diff options
Diffstat (limited to 'linhes')
46 files changed, 2329 insertions, 0 deletions
diff --git a/linhes/linhes-web/.gitignore b/linhes/linhes-web/.gitignore new file mode 100644 index 0000000..073b364 --- /dev/null +++ b/linhes/linhes-web/.gitignore @@ -0,0 +1 @@ +website.tar.gz diff --git a/linhes/linhes-web/PKGBUILD b/linhes/linhes-web/PKGBUILD new file mode 100644 index 0000000..7cde68f --- /dev/null +++ b/linhes/linhes-web/PKGBUILD @@ -0,0 +1,17 @@ +pkgname=linhes-web +pkgver=9.0.0 +pkgrel=1 +conflicts=() +pkgdesc="LinHES local website" +depends=() +makedepends=() +arch=('x86_64') +license=('GPL') +source=(website.tar.gz) +sha256sums=('6ff99589d225826d86bd1911aa0223f3c9668c02ff15e7bc607e52d90cca20ae') + +package() { + mkdir -p $pkgdir/data/srv/httpd/htdocs/ + cp -rp $srcdir/website/contents/* $pkgdir/data/srv/httpd/htdocs + chmod -R 755 $pkgdir/data/srv/httpd/htdocs +} diff --git a/linhes/linhes-web/mp_preflight b/linhes/linhes-web/mp_preflight new file mode 100755 index 0000000..037054f --- /dev/null +++ b/linhes/linhes-web/mp_preflight @@ -0,0 +1,3 @@ +#!/usr/bin/bash +echo " Starting mp_preflight" +tar -czvf website.tar.gz ./website diff --git a/linhes/linhes-web/website/contents/ajaxloader.min.js b/linhes/linhes-web/website/contents/ajaxloader.min.js new file mode 100755 index 0000000..11c14ba --- /dev/null +++ b/linhes/linhes-web/website/contents/ajaxloader.min.js @@ -0,0 +1 @@ +function AjaxLoader(e,t){function n(e){var t=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;e=e.replace(t,function(e,t,n,r){return t+t+n+n+r+r});var n=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return n?{r:parseInt(n[1],16),g:parseInt(n[2],16),b:parseInt(n[3],16)}:null}function r(e,t,n){return"#"+((1<<24)+(e<<16)+(t<<8)+n).toString(16).slice(1)}function b(){p=s>=32?s>=128?72:36:18,d=.5*s*o,v=2*Math.PI/p;h=a/m;if(f){h=-h}g.width=s;g.height=s}function w(e){var t=2*Math.PI*e;var n=Math.cos(t),r=Math.sin(t),i=.5*s*(1+n),o=.5*s*(1-r),a=i-d*n,l=o+d*r;y.clearRect(0,0,s,s);for(var c=0;c<p;c++){y.beginPath();if(f){y.fillStyle="rgba("+u.r+","+u.g+","+u.b+","+(p-1-c)/(p-1)+")"}else{y.fillStyle="rgba("+u.r+","+u.g+","+u.b+","+c/(p-1)+")"}y.moveTo(i,o);y.lineTo(a,l);t+=v,n=Math.cos(t);r=Math.sin(t);i=.5*s*(1+n);o=.5*s*(1-r);a=i-d*n;l=o+d*r;y.lineTo(a,l);y.lineTo(i,o);y.closePath();y.fill()}}var i={size:32,factor:.25,speed:1,color:"#000",clockwise:true};var s,o,u,a,f,l,c=0,h,p,d,v,m=30;if(t!=null){s="size"in t?t.size:i.size;o="factor"in t?t.factor:i.factor;u=n("color"in t?t.color:i.color);a="speed"in t?t.speed:i.speed;f="clockwise"in t?t.clockwise:i.clockwise}else{s=i.size;o=i.factor;u=n(i.color);a=i.speed;f=i.clockwise}var g=document.getElementById(e);if(g==null){console.log("AjaxLoader Error! Cannot find canvas element by id '"+e+"'");return null}var y=g.getContext("2d");b();this.show=function(){g.removeAttribute("style");clearInterval(l);l=setInterval(function(){w(c);c+=h;c=c-Math.floor(c)},1e3/m)};this.hide=function(){clearInterval(l);g.style.display="none"};this.getSize=function(){return s};this.setSize=function(e){s=e;b()};this.getFactor=function(){return o};this.setFactor=function(e){o=e;b()};this.getSpeed=function(){return a};this.setSpeed=function(e){a=e;b()};this.getColor=function(){return r(u.r,u.g,u.b)};this.setColor=function(e){u=n(e)};this.getClockwise=function(){return f};this.setClockwise=function(e){f=e;b()}}
\ No newline at end of file diff --git a/linhes/linhes-web/website/contents/back.png b/linhes/linhes-web/website/contents/back.png Binary files differnew file mode 100644 index 0000000..6b5da48 --- /dev/null +++ b/linhes/linhes-web/website/contents/back.png diff --git a/linhes/linhes-web/website/contents/calllog.py b/linhes/linhes-web/website/contents/calllog.py new file mode 100644 index 0000000..0b2fb22 --- /dev/null +++ b/linhes/linhes-web/website/contents/calllog.py @@ -0,0 +1,66 @@ +#!/usr/bin/python2 +# import MySQL module + +import MySQLdb +import sys +import getopt +import socket + + +def main(argv): + grandtotal=0 + grandtotal_current=0 + db = MySQLdb.connect(host="localhost", user="mythtv", passwd="mythtv", db="ncid") + # create a cursor + cursor = db.cursor() + # execute SQL statement + # cursor.execute("select name,number,count(number) as '# calls' from cid group by number,name order by '# calls' DESC limit 20;") + # result = cursor.fetchall() + + + #Top 20 callers + #print '<div id="content"> <p></p>' + print '<div> <p></p>' + print '<table class="calllog">' + print "Top 20 callers" + searchstring='''<td> <a href="http://www.google.com/search?q=%s" target="_blank" > %s </a> </td> ''' + cursor.execute("select name,number,count(number) from cid group by number,name order by count(number) DESC limit 20;") + result = cursor.fetchall() + for row in result: + print " <tr>" + #print " <td>",row[0],"</td>" + print searchstring % (row[0], row [0]) + print " <td>",row[2],"</td>" + #print " <td>",row[1],"</td>" + print searchstring % (row[1], row [1]) + print " </tr>" + #print "%40s %26s %10s" %(row[0],row[2],row[1]) + print "</table>" + print "</div>" + + + #last 20 calls + print '<br>' + print '<br>' + #print '<div id="content"> <p></p>' + print '<div> <p></p>' + print '<table class="calllog">' + print "Last 20 calls" + print '<br>' + cursor.execute("select date,time,name,number from cid order by date(ts) DESC ,time DESC limit 20 ;" ) + result = cursor.fetchall() + for row in result: + print " <tr>" + print " <td> %s </td>" %(row[0]) + print " <td>",row[1],"</td>" + #print " <td>",row[2],"</td>" + print searchstring % (row[2], row [2]) + #print " <td>",row[3],"</td>" + print searchstring % (row[3], row [3]) + print " </tr>" +# print "%26s %26s %26s %26s " %(row[0],row[1],row[2],row[3]) + print "</table>" + print "</div>" + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/linhes/linhes-web/website/contents/calllog.shtml b/linhes/linhes-web/website/contents/calllog.shtml new file mode 100644 index 0000000..5b64dc3 --- /dev/null +++ b/linhes/linhes-web/website/contents/calllog.shtml @@ -0,0 +1,19 @@ +<html> +<head> +<style type="text/css">@import "/frame.css";</style> +</head> + +<body> + <div id="header"> + <h1>Phone Call Log</h1> + <br> + </div> + + <!--#exec cmd="/data/srv/httpd/htdocs/calllog.py" --> + +</br> +</br> + +</body> +</html> + diff --git a/linhes/linhes-web/website/contents/cardmap.shtml b/linhes/linhes-web/website/contents/cardmap.shtml new file mode 100755 index 0000000..d98a4e9 --- /dev/null +++ b/linhes/linhes-web/website/contents/cardmap.shtml @@ -0,0 +1,13 @@ +<html> + <head> + <style type="text/css">@import "/frame.css";</style> + </head> + <body> + <div id="header"> + <h1>Tuners</h1> + <h2>Detected Cards and Static Device Paths</h2> + </div> + <!--#exec cmd=" MYTHCONFDIR=/usr/share/mythtv /data/srv/httpd/htdocs/list_cardmap.py" --> + </body> +</html> + diff --git a/linhes/linhes-web/website/contents/count.py b/linhes/linhes-web/website/contents/count.py new file mode 100644 index 0000000..76d18e8 --- /dev/null +++ b/linhes/linhes-web/website/contents/count.py @@ -0,0 +1,100 @@ +#!/usr/bin/python2 +# import MySQL module + +import MySQLdb +import sys +import getopt +import socket + + +def main(argv): + #get LinHES version + verfile = open('/etc/LinHES-release', 'r') + verLH = verfile.read() + verfile.close() + + grandtotal=0 + grandtotal_current=0 + db = MySQLdb.connect(host="localhost", user="mythtv", passwd="mythtv", db="mythconverg") + # create a cursor + cursor = db.cursor() + # execute SQL statement + cursor.execute("SELECT unix_timestamp(starttime),unix_timestamp(endtime),title FROM oldrecorded where oldrecorded.recstatus = -3 ORDER by starttime;") + result = cursor.fetchall() + + for row in result: + # print row[0], row[1] ,row [2] + start=row[0] + end=row[1] + if ( end > start ): + total = (end - start) /60 + grandtotal+=total + hours = grandtotal / 60.0 + days = hours / 24.0 + + cursor.execute("SELECT unix_timestamp(starttime),unix_timestamp(endtime),title FROM recorded where not (recgroup=(%s)) ORDER by starttime",("LiveTV")) + result_current = cursor.fetchall() + for row in result_current: + start=row[0] + end=row[1] + if ( end > start ): + total = (end - start) /60 + grandtotal_current+=total + hours_current = grandtotal_current / 60.0 + days_current = hours_current / 24.0 + + print '<div id="header">' + print "<h3>Welcome to</h3>" + print "<h1>" , verLH , "</h1>" + print "<h3>on " , socket.gethostname() , "</h3>" + print "</br>" + print "<table>" + print " <tr>" + print " <td>Currently there are " , len(result_current) , " recorded programs, with a viewing time of %.2f days or %.2f hours.</td>" %(days_current,hours_current) + print " </tr>" + print "</table>" + print "</br> " + + print "<table>" + print " <tr>" + print " <td>Overall there have been " , len(result) , "shows recorded, with a viewing time of %.2f days or %.2f hours.</td>"%(days,hours) + print " </tr>" + print "</table>" + print '</div>' + print "</br> </br> " +#Top shows + print '<div id="content"> <p></p>' + print '<table class="sample">' + print "Top 20 Shows" + cursor.execute("select title,count(title),category as numtitle from oldrecorded where oldrecorded.recstatus = -3 group by title having (COUNT(title) > 0 ) order by (COUNT(title)) DESC limit 20;" ) + result = cursor.fetchall() + for row in result: + print " <tr>" + print " <td>",row[0],"</td>" + print " <td>",row[2],"</td>" + print " <td>",row[1],"</td>" + print " </tr>" + # print "%40s %26s %10s" %(row[0],row[2],row[1]) + print "</table>" + print "</div>" +#Top categories + + print '<div id="column">' + print '<table class="sample">' + print "Top 20 Categories" + cursor.execute("select category,count(category) as numtitle from oldrecorded where oldrecorded.recstatus = -3 group by category having (COUNT(category) > 0 ) order by (COUNT(category)) DESC limit 20; " ) + result = cursor.fetchall() + for row in result: + category = row[0] + if category == "": + category = "Unknown" + print " <tr>" + print " <td>",category,"</td>" + print " <td>",row[1],"</td>" + print " </tr>" + #print "%16s %16s" %(row[0],row[1]) + print "</table>" + print "</div>" + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/linhes/linhes-web/website/contents/docs.html b/linhes/linhes-web/website/contents/docs.html new file mode 100644 index 0000000..dc3a936 --- /dev/null +++ b/linhes/linhes-web/website/contents/docs.html @@ -0,0 +1,58 @@ +<html> +<head> +<style type="text/css">@import "frame.css";</style> +</head> + +<body> +<div id="header"> +<h1>Documentation</h1> +<br> +</div> + +<h3>Package Management</h3> +<div id="navcontainer"> +<ul id="navlist"> + <li>pacman -Sy = to refresh pkg database</li> + <li>pacman -Ss $keyword = to search pkg database</li> + <li>pacman -Su = to update all install packages</li> + <li>pacman -S $pkg = to update one pkg</li> + <li>pacman -h = for a list of pacman operations</li> + <li>pacman -S --help = for a full list of options associated with the -S command</li> +</ul> +</div> +<br> + +<h3>Starting and Stopping Services</h3> +<div id="navcontainer"> +<ul id="navlist"> + <li>sv {stop,start,restart} frontend = This will start/stop the entire X proccess that runs mythfrontend</li> + <li>sv {stop,start,restart} mysql</li> + <li>sv {stop,start,restart} mythbackend</li> + <li>sv {stop,start,restart} remotes</li> +</ul> +<br> +</div> + +<h3>Other Notes</h3> +<div id="navcontainer"> +<ul id="navlist"> + <li>To keep a host from showing up in the network map, add it to: + /home/xymon/server/ext/ignoreclient.py + </li> + <li>To stop xymon from running a check on a function remove "func" from bb-hosts</li> + <li>remove "func" from bb-hosts to stop hobbit from running a func check on it </li> + <li>If /tmp/nomfe is present then mythfrontend will not restart</li> + <li>Adding pkg names to /etc/pkgname.blacklist will stop MythVantage from auto installing a package</li> +</div> +<br> + +<h3>MythFrontend Menu Navigation</h3> +<div id="navcontainer"> +<ul id="navlist"> + <li> <A HREF="images/classic-menugraph.png">Classic Menu</A> </li> + <li> <A HREF="images/menu_diagram_color.png">Standard Menu</A> </li> + <li> <A HREF="images/dvr_menugraph.png">DVR Menu</A> </li> + +</body> +</html> + diff --git a/linhes/linhes-web/website/contents/error-handler.html b/linhes/linhes-web/website/contents/error-handler.html new file mode 100644 index 0000000..49e406f --- /dev/null +++ b/linhes/linhes-web/website/contents/error-handler.html @@ -0,0 +1,9 @@ +<html> +<head> +<style type="text/css">@import "/frame.css";</style> +</head> + +<body> +Module or page not found +</body> +</html>
\ No newline at end of file diff --git a/linhes/linhes-web/website/contents/error/call_log.html b/linhes/linhes-web/website/contents/error/call_log.html new file mode 100644 index 0000000..d4d6333 --- /dev/null +++ b/linhes/linhes-web/website/contents/error/call_log.html @@ -0,0 +1,11 @@ +<html> +<head> +<style type="text/css">@import "/frame.css";</style> +</head> + +<body> +Call logging is not enabled, or no calls logs +</br> +To enable logging of incoming phone calls please visit the advanced section of the service menu +</body> +</html> diff --git a/linhes/linhes-web/website/contents/error/hobbit.html b/linhes/linhes-web/website/contents/error/hobbit.html new file mode 100644 index 0000000..4c65716 --- /dev/null +++ b/linhes/linhes-web/website/contents/error/hobbit.html @@ -0,0 +1,11 @@ +<html> +<head> +<style type="text/css">@import "/frame.css";</style> +</head> + +<body> +Xymon does not appear to be installed. +</br> +If Xymon was just installed/started it will take a few minutes before this page populates. +</body> +</html> diff --git a/linhes/linhes-web/website/contents/error/mythbackend.html b/linhes/linhes-web/website/contents/error/mythbackend.html new file mode 100644 index 0000000..9c3a362 --- /dev/null +++ b/linhes/linhes-web/website/contents/error/mythbackend.html @@ -0,0 +1,11 @@ +<html> +<head> +<style type="text/css">@import "/frame.css";</style> +</head> + +<body> +MythBackend status is currently unavailable. +</br> + +</body> +</html> diff --git a/linhes/linhes-web/website/contents/error/mythexport.html b/linhes/linhes-web/website/contents/error/mythexport.html new file mode 100644 index 0000000..f0d6b9d --- /dev/null +++ b/linhes/linhes-web/website/contents/error/mythexport.html @@ -0,0 +1,22 @@ +<html> +<head> +<style type="text/css">@import "/frame.css";</style> +</head> + +<body> +<h2>MythExport does not appear to be installed</h2> +</br> +</br> +<h4>Export MythTV recordings to portable media players.</h4> +</br> +<div id="navcontainer"> + <ul id="navlist"> +To enable MythExport run these commands in a terminal: + </br> + <li> pacman -Syyu mythexport </li> + <li> add_service.sh mythexport </li> +</ul> + +</body> +</html> + diff --git a/linhes/linhes-web/website/contents/error/mythexpress.html b/linhes/linhes-web/website/contents/error/mythexpress.html new file mode 100644 index 0000000..0525dfc --- /dev/null +++ b/linhes/linhes-web/website/contents/error/mythexpress.html @@ -0,0 +1,20 @@ +<html> +<head> +<style type="text/css">@import "/frame.css";</style> +</head> + +<body> +<h2>MythExpress is not enabled or installed</h2> +</br> +</br> +<h4>MythExpress is a browser-based interface to MythTV's HTTP streaming capability.</h4> +</br> +<div id="navcontainer"> + <ul id="navlist"> +To enable MythExpress run these commands in a terminal: + </br> + <li> pacman -Syyu mythexpress </li> + <li> add_service.sh mythexpress </li> +</ul> +</body> +</html> diff --git a/linhes/linhes-web/website/contents/error/mythweb.html b/linhes/linhes-web/website/contents/error/mythweb.html new file mode 100644 index 0000000..fe76a9a --- /dev/null +++ b/linhes/linhes-web/website/contents/error/mythweb.html @@ -0,0 +1,16 @@ +<html> +<head> +<style type="text/css">@import "/frame.css";</style> +</head> + +<body> +MythWeb does not appear to be installed. +</br> +To install MythWeb either +</br> +1) Visit the MythVantage advanced screen to enable mythweb. </br> +2) type "pacman -S mythweb-release-fixes" at the console. + + +</body> +</html> diff --git a/linhes/linhes-web/website/contents/error/phpadmin.html b/linhes/linhes-web/website/contents/error/phpadmin.html new file mode 100644 index 0000000..39b2f48 --- /dev/null +++ b/linhes/linhes-web/website/contents/error/phpadmin.html @@ -0,0 +1,26 @@ +<html> +<head> +<style type="text/css">@import "/frame.css";</style> +</head> + +<body> +phpMyAdmin is a tool written in PHP intended to handle the administration of MySQL over the Web. +</br> +Currently it's not installed,but if you wish to install phpmyadmin, type the following at a command prompt +</br> +</br> + +pacman -S phpmyadmin + +</br> +</br> +PHP must be enabled for phpMyAdmin. +</br> +</br> +</br> + +Please be carefull, phpMyAdmin is a powerful tool and can easily mess with your settings. + + +</body> +</html> diff --git a/linhes/linhes-web/website/contents/error/remyth.html b/linhes/linhes-web/website/contents/error/remyth.html new file mode 100644 index 0000000..36661d2 --- /dev/null +++ b/linhes/linhes-web/website/contents/error/remyth.html @@ -0,0 +1,22 @@ +<html> +<head> +<style type="text/css">@import "/frame.css";</style> +</head> + +<body> +<h2>ReMyth is not enabled or installed</h2> +</br> +</br> +<h4>ReMyth provides a nice remote for your MythTV Frontends.</h4> +<h4>You will be able to view your recordings, as well as send actions to a frontend of your choosing.</h4> +</br> + +<div id="navcontainer"> + <ul id="navlist"> +To enable ReMyth run these commands in a terminal: + </br> + <li> pacman -Syyu remyth </li> + <li> add_service.sh remyth </li> +</ul> +</body> +</html> diff --git a/linhes/linhes-web/website/contents/error/status-404.html b/linhes/linhes-web/website/contents/error/status-404.html new file mode 100644 index 0000000..49e406f --- /dev/null +++ b/linhes/linhes-web/website/contents/error/status-404.html @@ -0,0 +1,9 @@ +<html> +<head> +<style type="text/css">@import "/frame.css";</style> +</head> + +<body> +Module or page not found +</body> +</html>
\ No newline at end of file diff --git a/linhes/linhes-web/website/contents/error/zoneminder.html b/linhes/linhes-web/website/contents/error/zoneminder.html new file mode 100644 index 0000000..25ecc9b --- /dev/null +++ b/linhes/linhes-web/website/contents/error/zoneminder.html @@ -0,0 +1,20 @@ +<html> +<head> +<style type="text/css">@import "/frame.css";</style> +</head> + +<body> +Zoneminder is not enabled or installed. +</br> +</br> +</br> +<div id="navcontainer"> + <ul id="navlist"> + +To enable zoneminder run these commands in a terminal: + </br> + <li> pacman -Syyu zoneminder </li> + <li> add_service.sh zoneminder </li> +</ul> +</body> +</html> diff --git a/linhes/linhes-web/website/contents/exports.shtml b/linhes/linhes-web/website/contents/exports.shtml new file mode 100755 index 0000000..12e079c --- /dev/null +++ b/linhes/linhes-web/website/contents/exports.shtml @@ -0,0 +1,14 @@ +<html> + <head> + <style type="text/css">@import "/frame.css";</style> + </head> + <body> + <div id="header"> + <h1>File Shares</h1> + </div> + <div id="navcontainer"> + <!--#exec cmd="/data/srv/httpd/htdocs/list_exports.py" --> + </div> + </body> +</html> + diff --git a/linhes/linhes-web/website/contents/favicon.ico b/linhes/linhes-web/website/contents/favicon.ico Binary files differnew file mode 100644 index 0000000..6a99443 --- /dev/null +++ b/linhes/linhes-web/website/contents/favicon.ico diff --git a/linhes/linhes-web/website/contents/fe_status.py b/linhes/linhes-web/website/contents/fe_status.py new file mode 100644 index 0000000..c66d8f9 --- /dev/null +++ b/linhes/linhes-web/website/contents/fe_status.py @@ -0,0 +1,144 @@ +#!/usr/bin/python2 + +import urllib2 +import xml.etree.ElementTree as ET +import socket +from MythTV import Frontend +import sys +#socket.setdefaulttimeout(1) +#socket.setdefaulttimeout(.00001) + +def msg(msg): + #if cmdargs.silent is False: + print "%s" %msg + + +def parse_xml(frontend): + temp_dict = {'state':" --- ", + 'title':" --- ", + 'subtitle':" --- ", + 'location':" --- "} + url = "http://%s:6547/Frontend/GetStatus" %frontend + try: + request = urllib2.Request(url) + xml = urllib2.urlopen(request,timeout=1) + tree = ET.parse(xml) + root = tree.getroot() + except: + #msg(" Couldn't connect to %s" %frontend) + temp_dict['state'] = "offline" + return temp_dict + + lst = root.find("State") + for item in lst: + try: + keyitem = (item.find('Key').text).strip() + valueitem = (item.find('Value').text).strip() + except: + continue + if keyitem == "state": + temp_dict['state'] = valueitem + + elif keyitem == "title": + temp_dict['title'] = valueitem + + elif keyitem == "subtitle": + temp_dict['subtitle'] = valueitem + + elif keyitem == "currentlocation": + temp_dict['location'] = valueitem + + return temp_dict + + +def mythfe_status(cursor,mythDB): + status_dict={} + try: + #frontends = mythDB.getFrontends() #use cursor instead so it doesn't test connection + cursor.execute("select distinct hostname from settings where hostname is not null;") + frontends=cursor.fetchall() + except: + #msg("Exceptions") + return + + for i in frontends: + i=''.join(i) + try: + fe_hostname = socket.gethostbyaddr(i)[0] + except: + #print "DNS lookup failed for %s" %i + fe_hostname = i + try: + ip_addr = socket.gethostbyname(i) + fe_hostname = "%s (%s)" %(fe_hostname,ip_addr) + status_dict[fe_hostname] = parse_xml(ip_addr) + except: + fe_hostname = "%s" %fe_hostname + status_dict[fe_hostname] = parse_xml(fe_hostname) + return status_dict + + +def print_html(status_dict): + print '<div> <p></p>' + print '</br> </br> ' + print '<table class="calllog">' + + #print "Current state of all online frontends" + #print '</br> </br> ' + + #print status_dict + row = ''' +<tr> + <td> %s </td> + <td> %s </td> + <td> %s </td> + <td> %s </td> + <td> %s </td> +</tr> +''' + print row %(" MythFrontend Host "," State "," Title "," Subtitle "," MythFrontend Location ") + for fe in status_dict.keys(): + temp_dict = status_dict[fe] + print row %(fe, + temp_dict['state'], + temp_dict['title'], + temp_dict['subtitle'], + temp_dict['location']) + + print "</table>" + print '</div>' + +# print ''' +# <div id="footer"> +# </br> +# <p>Offline systems are not listed</p> +# </div> +#''' + + +def main(): + try: + from MythTV import MythDB + mythDB = MythDB() + cursor = mythDB.cursor() + db_conn=True + except: + msg("Couldn't connect to MythTV database.") + db_conn=False + + try: + from MythTV import MythBE + mythBE = MythBE() + be_conn=True + except: + msg("Couldn't connect to MythTV backend.") + be_conn=False + + if (db_conn): + status_dict = mythfe_status(cursor,mythDB) + print_html(status_dict) + + + +if __name__ == "__main__": + main() diff --git a/linhes/linhes-web/website/contents/fe_status.shtml b/linhes/linhes-web/website/contents/fe_status.shtml new file mode 100644 index 0000000..8fda3df --- /dev/null +++ b/linhes/linhes-web/website/contents/fe_status.shtml @@ -0,0 +1,18 @@ +<html> + <head> + <style type="text/css">@import "/frame.css";</style> + <meta http-equiv="cache-control" content="max-age=0" /> + <meta http-equiv="cache-control" content="no-cache" /> + <meta http-equiv="expires" content="0" /> + <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" /> + <meta http-equiv="pragma" content="no-cache" /> + <meta http-equiv="refresh" content="30"> + </head> + + <body> + <div id="header"> + <h1>MythFrontend Status</h1> + </div> + <!--#exec cmd="MYTHCONFDIR=/usr/share/mythtv /data/srv/httpd/htdocs/fe_status.py" --> + </body> +</html> diff --git a/linhes/linhes-web/website/contents/fe_status_load.shtml b/linhes/linhes-web/website/contents/fe_status_load.shtml new file mode 100755 index 0000000..b83c13f --- /dev/null +++ b/linhes/linhes-web/website/contents/fe_status_load.shtml @@ -0,0 +1,41 @@ +<html> + <head> + <style type="text/css">@import "/frame.css";</style> + <script src="/ajaxloader.min.js"></script> + <meta http-equiv="cache-control" content="max-age=0"> + <meta http-equiv="cache-control" content="no-cache"> + <meta http-equiv="expires" content="0"> + <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT"> + <meta http-equiv="pragma" content="no-cache"> + <meta http-equiv="refresh" content="0; url=/fe_status.shtml"> + <script language="javascript"> + function redirect() { + window.location.replace("/fe_status.shtml");} + </script> + </head> + + <body onload="redirect()"> + <div id="header"> + <h1>MythFrontend Status</h1> + </div> + <br> <br> + <h3>Querying MythFrontends...</h3> + <br> + <div id="container"> + <div> + <canvas id="spinner"></canvas> + </div> + </div> + <script type="text/javascript"> + var opts = { + size: 72, // Width and height of the spinner + factor: 0.25, // Factor of thickness, density, etc. + color: "#ebb81c", // Color #rgb or #rrggbb + speed: 1.0, // Number of turns per second + clockwise: true // Direction of rotation + }; + var ajaxLoader = new AjaxLoader("spinner", opts); + ajaxLoader.show(); + </script> + </body> +</html> diff --git a/linhes/linhes-web/website/contents/frame.css b/linhes/linhes-web/website/contents/frame.css new file mode 100644 index 0000000..0008aec --- /dev/null +++ b/linhes/linhes-web/website/contents/frame.css @@ -0,0 +1,229 @@ +* /* Our "universal rule" */ +{ + padding: 0px; + margin: 0px; + border: 0px; +} +body { +/* background: url("page_background.jpg") repeat-y #9FA9B3; */ + background-color: #191c26; + +//background-color: #ebb81c; +//background-image: -webkit-gradient(linear, left top, left bottom, from(#ebb81c), to(#0072bc)); /* Saf4+, Chrome */ +//background-image: -webkit-linear-gradient(top, #ebb81c, #0072bc); /* Chrome 10+, Saf5.1+, iOS 5+ */ +//background-image: -moz-linear-gradient(top, #ebb81c, #0072bc) ; /* FF3.6 */ +//background-image: -moz-linear-gradient(top, #0072bc,#ebb81c) ; /* FF3.6 */ +//background-image: -ms-linear-gradient(top, #ebb81c, #0072bc); /* IE10 */ +//background-image: -o-linear-gradient(top, #ebb81c, #0072bc); /* Opera 11.10+ */ +//background-image: linear-gradient(top, #ebb81c, #0072bc); +/filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#ebb81c', EndColorStr='#0072bc'); /* IE6-IE9 */ + + +//background-size: 1000px 1000px, 500px 500px; +//-o-background-size: 1000px 10000px; +//-moz-background-size: 1000px 10000px, 500px, 500px; +//-webkit-background-size: 1000px 10000px, 500px 500px; + + margin: 10px; + padding: 10px; + border: 10px; + min-width: 770px; + font-family: Arial, Tahoma, Helvetica, sans-serif; + font-size: 11px; + color: #FFFFFF; + text-align: center; + font-size: 18px; + font-family: tahoma, verdana, geneva, arial, helvetica, sans-serif; +} + +#mainContainer { + clear: both; + width: 770px; + margin: 10px auto; + text-align: left; /* Since we used text-align: center in the body to be sure some older IE versions are going to center our design, we now align the text left */ + display: block; +} +#header { + color: #fff; + text-align: center; +} +#content { + float: left; /* Our content is going to be left aligned */ + width: 320px; /* And it's going to have a 320px width */ + /*background: #D9D9D9;*/ + margin-left:60px; +} + +#column { + float: right; /* Our column is going to be right aligned */ + width: 320px; /* And it's going to have a 320px width */ + /*background: #8A8AE6;*/ + margin-right:60px; +} + +#resultbox { + width: 700px ; + margin-left: auto ; + margin-right: auto ; + border-width: .2em; + border-style: dotted; + border-color: #900; + text-align: left; + padding-left: 30; + padding-right: 30; + padding-top: 10; + padding-bottom: 10; + +} + +#netContainer { + clear: both; + width: 770px; + margin: 10px auto; + display: block; +} + +img.center { + display: block; + padding-top: 10px; + padding-bottom: 10px; + margin-left: auto; + margin-right: auto; + max-width: 100%; +} + +#footer { + clear: both; /* We have to clear our floats */ + width: 770px; /* We need to set the width on the footer since it's outside the mainContainer, and therefor isn't controlled by it */ + margin: 0px auto; /* We need to center the footer also */ + color: gold; + text-align: center; + font-size: 10px; +} + +#navlist { + clear: both; + width: 770px; + margin: 10px auto; + display: block; + text-align: left; + list-style-type: square; +} + +#navlist li { + +} +#navlist a:link +{ + color: #fff; +# background-color: #FDB14F; + text-decoration: underline; + + +} + +#navlist a:visited +{ +# color: #FDB14F; + color: gold; + text-decoration: underline; +} + +table.sample { + border-width: 4px; + border-spacing: 2px; + border-style: outset; + border-color: #808080; + border-collapse: separate; + width:300px; +} + +table.sample td { + border-width: 1px; + padding: 1px; + border-style: inset; + border-color: #808080; + /*width:300px;*/ + -moz-border-radius: ; +} + + +table.calllog { + border-width: 4px; + border-spacing: 2px; + border-style: outset; + border-color: #808080; + border-collapse: separate; + width:85%; + margin-left:auto; + margin-right:auto; + body {text-align:center;} +} + +table.calllog td { + border-width: 1px; + padding: 1px; + border-style: inset; + border-color: #808080; + /*width:300px;*/ + -moz-border-radius: ; +} + + +.n { + font-weight: normal; + text-align: left; + width: 250px; + color: white; +} + +.s { + font-weight: normal; + text-align: left; + width: 150px; + color: white; + text-decoration: none; +} + +.m { + font-weight: normal; + text-align: left; + width: 350px; + color: white; + text-decoration: none; +} + +.t { + font-weight: normal; + text-align: left; + width: 350px; + color: white; + text-decoration: none; + visibility:hidden +} + + +a:link +{ + color: #fff; +# background-color: #FDB14F; + text-decoration: underline; + +# margin-left:10px; + +} + +a:visited +{ +# color: #FDB14F; + color: gold; + text-decoration: underline; + margin-left:10px; +} + +#submitbutton { + background-color: #010101; + font-size: 100%; + color: gold; + text-decoration: underline;margin-left:150px; + padding: 10px; font-weight: bold; } diff --git a/linhes/linhes-web/website/contents/go.png b/linhes/linhes-web/website/contents/go.png Binary files differnew file mode 100644 index 0000000..c70bf2a --- /dev/null +++ b/linhes/linhes-web/website/contents/go.png diff --git a/linhes/linhes-web/website/contents/header.html b/linhes/linhes-web/website/contents/header.html new file mode 100644 index 0000000..831a9d5 --- /dev/null +++ b/linhes/linhes-web/website/contents/header.html @@ -0,0 +1,97 @@ +<html>
+<!--<style type="text/css">@import "mv.css";</style>-->
+<link rel="stylesheet" type="text/css" href="skeleton.css" />
+<head>
+
+<script type="text/javascript">
+function r()
+{
+ current_hostname=parent.location.hostname
+ top.frames["content"].location.href = ( "http://" + current_hostname + ":6544" ) ;
+}
+
+function express()
+{
+ current_hostname=parent.location.hostname
+ top.frames["content"].location.href = ( "http://" + current_hostname + ":6565" ) ;
+}
+
+function remyth()
+{
+ current_hostname=parent.location.hostname
+ top.frames["content"].location.href = ( "http://" + current_hostname + ":8088" ) ;
+}
+
+function beStatus()
+{
+ document.getElementById('modify-me').href = "http://" + window.location.hostname + ":6544";
+}
+
+</script>
+</head>
+
+<BODY BGCOLOR=#ebb81c onload="beStatus()">
+
+<div id='header'></div>
+<img id='header_img' src="linhes_header.png" alt="LinHES" title="LinHES"/>
+
+<base target="content" />
+<ul id="nav">
+<li><a href="home.shtml" TARGET="content" id="current">Home</a></li>
+
+<li><a href="mythweb/">MythWeb »</a>
+ <ul>
+ <li><a href="mythweb/tv/list" >Listings</a></li>
+ <li><a href="mythweb/tv/recorded" >Recorded</a></li>
+ <li><a href="mythweb/tv/schedules" >Schedules</a></li>
+ <li><a href="mythweb/tv/searches" >Searches</a></li>
+ <li><a href="mythweb/status" >Status</a></li>
+ <li><a href="mythweb/tv/upcoming" >Upcoming</a></li>
+ <li><a href="mythweb/music" >Music</a></li>
+ <li><a href="mythweb/video" >Video</a></li>
+ </ul>
+</li>
+
+<li><a href="fe_status_load.shtml">MythFrontend Status</a></li>
+
+<li><a href="" id="modify-me" target="_blank">MythTV WebFrontend</a></li>
+
+<li><a href="xymon/">Health & Maintenance</a></li>
+
+<li><a href="/logs/" >System »</a>
+ <ul>
+ <!-- <li><a href="/xymon" >Health</a></li>-->
+ <li><a href="/logs/" >Logs</a></li>
+ <li><a href="/exports.shtml" >File Shares</a></li>
+ <li><a href="/cardmap.shtml" >Tuners</a></li>
+ <li><a href="/shell/" >Terminal</a></li>
+ </ul>
+</li>
+
+<li><a href="calllog.shtml">Utilities »</a>
+ <ul>
+<!-- <li><a onClick=r() >MythBackend Status</a></li> -->
+ <li><a href="calllog.shtml">Call Log</a></li>
+ <li><a href="mythexport/setup.cgi">MythExport</a></li>
+ <li><a href="mythexpress.html" target="_blank">MythExpress</a></li>
+<!-- <li><a href="remyth.html" >ReMyth</a></li> -->
+ <li><a href="zm">ZoneMinder</a></li>
+ </ul>
+</li>
+
+<li><a href="docs.html" >Documentation</a></li>
+
+<li><a href="links.html" >Links »</a>
+ <ul>
+ <li><a href="http://linhes.org/wiki" >LinHES Wiki</a></li>
+ <li><a href="http://forums.linhes.org" >LinHES Forums</a></li>
+ <li><a href="http://linhes.org/projects/linhes/issues" >LinHES Bug Tracker </a></li>
+ <li><a href="http://linhes.org/projects/linhes/wiki/Official_and_3rd_party_add-ons" >LinHES Add-Ons</a></li>
+ <li><a href="http://www.mythtv.org" >MythTV</a></li>
+ <li><a href="http://smolt.mythtv.org" >MythTV Smolt Server</a></li>
+ <li><a href="http://www.schedulesdirect.org" >Schedules Direct</a></li>
+ </ul>
+</li>
+
+</body>
+</html>
diff --git a/linhes/linhes-web/website/contents/home.shtml b/linhes/linhes-web/website/contents/home.shtml new file mode 100644 index 0000000..a2c817e --- /dev/null +++ b/linhes/linhes-web/website/contents/home.shtml @@ -0,0 +1,17 @@ +<html> + <head> + <style type="text/css">@import "frame.css";</style> + </head> + <body> + <div id="mainContainer"> + <!--#exec cmd="/data/srv/httpd/htdocs/count.py" --> + </div> + <div id="netContainer"> + <img src="/xymon/gifs/network.png" class="center"> + </div> + <div id="footer"> + <p>Thank you for choosing LinHES</p> + </div> + </body> +</html> + diff --git a/linhes/linhes-web/website/contents/images/classic-menugraph.png b/linhes/linhes-web/website/contents/images/classic-menugraph.png Binary files differnew file mode 100644 index 0000000..bedbd93 --- /dev/null +++ b/linhes/linhes-web/website/contents/images/classic-menugraph.png diff --git a/linhes/linhes-web/website/contents/images/dvr_menugraph.png b/linhes/linhes-web/website/contents/images/dvr_menugraph.png Binary files differnew file mode 100644 index 0000000..712ab36 --- /dev/null +++ b/linhes/linhes-web/website/contents/images/dvr_menugraph.png diff --git a/linhes/linhes-web/website/contents/images/menu_diagram_color.png b/linhes/linhes-web/website/contents/images/menu_diagram_color.png Binary files differnew file mode 100644 index 0000000..d364d94 --- /dev/null +++ b/linhes/linhes-web/website/contents/images/menu_diagram_color.png diff --git a/linhes/linhes-web/website/contents/index.html b/linhes/linhes-web/website/contents/index.html new file mode 100644 index 0000000..1168c4a --- /dev/null +++ b/linhes/linhes-web/website/contents/index.html @@ -0,0 +1,16 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"> +<html> + <head> + <link rel="shortcut icon" href="/favicon.ico"> + <title>LinHES: The Linux Home Entertainment System</title> + </head> + <frameset cols="205, 100%" frameborder="no" border="0" bordercolor="#000000"> + <frame src="header.html" scrolling=no name="menuframe" /> + <frame src="home.shtml" name="content" /> + <noframes> + <body> + There is no frame support on your browser. + </body> + </noframes> + </frameset> + </html> diff --git a/linhes/linhes-web/website/contents/linhes_header.png b/linhes/linhes-web/website/contents/linhes_header.png Binary files differnew file mode 100644 index 0000000..fd50187 --- /dev/null +++ b/linhes/linhes-web/website/contents/linhes_header.png diff --git a/linhes/linhes-web/website/contents/links.html b/linhes/linhes-web/website/contents/links.html new file mode 100644 index 0000000..65b5231 --- /dev/null +++ b/linhes/linhes-web/website/contents/links.html @@ -0,0 +1,27 @@ +<html> +<head> +<style type="text/css">@import "frame.css";</style> +</head> + +<body> +<h1>Links</h1> +</br> + +<div id="navcontainer"> +<ul id="navlist"> + <!-- <li><a href="/mvpmc.shtml" >Media MVP setup</a> (dhcp server must be enabled) </li> --> + <li><a href="http://linhes.org/wiki" >LinHES Wiki</a></li> + <li><a href="http://forums.linhes.org" >LinHES Forums</a></li> + <li><a href="http://linhes.org/projects/linhes/issues" >LinHES Bug Tracker </a></li> + <li><a href="http://linhes.org/projects/linhes/wiki/Official_and_3rd_party_add-ons" >LinHES Add-Ons</a></li> + <li><a href="http://www.mythtv.org" >MythTV</a></li> + <li><a href="http://smolt.mythtv.org" >MythTV Smolt Server</a></li> + <li><a href="http://www.schedulesdirect.org" >Schedules Direct</a></li> + + + +</ul> +</div> + +</body> +</html> diff --git a/linhes/linhes-web/website/contents/list_cardmap.py b/linhes/linhes-web/website/contents/list_cardmap.py new file mode 100755 index 0000000..c77ed83 --- /dev/null +++ b/linhes/linhes-web/website/contents/list_cardmap.py @@ -0,0 +1,156 @@ +#!/usr/bin/python2 +import subprocess +import socket,sys +import urllib2 +from MythTV import MythBE,MythDB,MythLog + +def find_slave_hosts(): + slave_hosts=[] + try: + be=MythBE() + db = MythDB() + cursor = db.cursor() + except: + return slave_hosts + + try: + cmd="select hostname from settings where data='Slave_backend';" + cursor.execute(cmd) + results=cursor.fetchall() + for i in results: + slave_hosts.append(i[0]) + except: + return slave_hosts + return slave_hosts + +def read_local_tuner(): + tuner_list = [] + exportfile = '/etc/udev/mv-persistent-video.description' + try: + f = open(exportfile,"r") + for line in f.readlines(): + if line.startswith("#"): + continue + item = line.split(":") + if len(item) <= 1 : + continue + tuner_list.append(item) + except : + tuner_list.append(["notfound","notfound","notfound"]) + return tuner_list + +def parse_remote_tuners(the_page): + tuner_list=[] + the_page = the_page.split("\n") + try: + for line in the_page: + if line.startswith("#"): + continue + item = line.split(":") + if len(item) <= 1 : + continue + tuner_list.append(item) + except : + tuner_list.append(["notfound","notfound","notfound"]) + return tuner_list + + +def remote_tuners(slave_host): + default_timeout = 3 + socket.setdefaulttimeout(default_timeout) + slaveurl="http://%s:1337/cardlist.cgi" %slave_host + req = urllib2.Request(slaveurl) + response = urllib2.urlopen(req) + the_page = response.read() + #the_page="abc\nadef\na" + if the_page : + tuner_list = parse_remote_tuners(the_page) + print "</br>" + for statictuner in tuner_list: + if statictuner[1].find("notfound") > -1 : + print "Couldn't open tuner map" + print "</br>" + else: + print "<li> %s  %s" %(statictuner[1] ,statictuner[0]) + print "</br>" + print " static device node: %s" %statictuner[2] + print "</br>" + print "</br>" + else: + print "<li> no tuners found  " + + return + + + +mbelist = read_local_tuner() +slave_hosts = find_slave_hosts() + +#--------------MBE------------- +hostname = socket.gethostname() +print "</br>" +print "<h2>" +print "__________ %s __________" %(hostname) +print "</h2>" +print "</br>" +print ''' +<div id="navcontainer"> +<ul id="navlist"> +''' + +for statictuner in mbelist: + hdhr_url = None + if statictuner[1].find("notfound") > -1 : + print "Couldn't open tuner map" + print "</br>" + else: + ceton_url = None + hdhr_url = None + if statictuner[0] == "hdhr": + hdhr_url = statictuner[1].split("-")[-1] + elif statictuner[0] == "infinitv": + ceton_port = statictuner[3].strip() + #Services/1/Status.html + #print statictuner + ceton_tuner=statictuner[2].strip()[-1] + ceton_tuner = int(ceton_tuner) + 1 + ceton_url = "http://%s:%s/Services/%s/Status.html" %(hostname, + ceton_port, + ceton_tuner) + + #print "<li> %s  %s" %(statictuner[1] ,statictuner[0]) + print "<li> %s  " %(statictuner[1]) + print "</br>" + print " static device node: %s" %statictuner[2] + + if hdhr_url: + print "</br>" + print ' device webpage: <a href="http://%s">http://%s</a> ' %(hdhr_url.strip(),hdhr_url.strip()) + if ceton_url: + print "</br>" + print ' device webpage: <a href="%s">%s</a> ' %(ceton_url.strip(),ceton_url.strip()) + print "</br>" + print "</br>" + +print '''</ul> </div>''' + +#---------Slave tuners +for i in slave_hosts: + print "<h2>" + print "__________ %s __________" %(i) + print "</h2>" + print "</br>" + print ''' + <div id="navcontainer"> + <ul id="navlist" ''' + #remote_tuners(i) + try: + remote_tuners(i) + pass + except: + print "</br>" + print "<li> Problem reading list from %s" %i + pass + print ''' </ul> </div>''' + + diff --git a/linhes/linhes-web/website/contents/list_exports.py b/linhes/linhes-web/website/contents/list_exports.py new file mode 100755 index 0000000..79c2c38 --- /dev/null +++ b/linhes/linhes-web/website/contents/list_exports.py @@ -0,0 +1,85 @@ +#!/usr/bin/python2 +import subprocess + +def nfs_export_list(): + nfslist = [] + exportfile = "/etc/exports" + proc = subprocess.Popen(["showmount", "-a"] , stdout=subprocess.PIPE,stderr=subprocess.PIPE) + stdout,stderr = proc.communicate() + rc = proc.returncode + if rc == 0: + try: + f = open(exportfile,"r") + for line in f.readlines(): + if line.startswith("#"): + continue + item = line.split() + if len(item) <= 1 : + continue + nfslist.append(item) + except : + pass + else: + nfslist.append(["NFS server is not running",'NFS server is not running']) + return nfslist + + +def smb_share_list(): + smblist=[] + + proc = subprocess.Popen(["smbclient", "-L", "\\localhost" , "-N"], stdout=subprocess.PIPE,stderr=subprocess.PIPE) + stdout,stderr = proc.communicate() + outstuff = stderr.split("\n") + for line in outstuff: + try: + heading1 = line.split()[0] + except: + continue + #print heading1 + #print heading1.find("Domain") + if heading1.find("Domain") > -1 : + #smblist.append('') + smblist.append(heading1) + break + + outstuff = stdout.split("\n") + for line in outstuff: + try: + heading1,heading2 = line.split() + except: + continue + if heading1 == "Server" and heading2 == "Comment": + break + smblist.append(line) + + return smblist + + +nfslist = nfs_export_list() +smblist = smb_share_list() + + +print "</br>" +print "<h2>__________ NFS Shares __________</h2>" +print "</br>" +print '<ul id="navlist">' +for sharename in nfslist: + if sharename[1].find("noaccess") > -1 : + print "<h3>%s \t no access</h3>" %sharename[0] + else: + print "<li>%s</li>" %sharename[0] + +print '</ul>' + +print "</br>" +print "<h2>__________ SMB Shares __________</h2>" +print "</br>" +print '<ul id="navlist">' +if len(smblist) == 0: + print "<h3>Samba is not running or no shares are listed</h3>" + print "</br>" +else: + for sharename in smblist: + print "<li>%s</li>" %(sharename.split()[0]) + +print '</ul>' diff --git a/linhes/linhes-web/website/contents/mv.css b/linhes/linhes-web/website/contents/mv.css new file mode 100644 index 0000000..54e70b0 --- /dev/null +++ b/linhes/linhes-web/website/contents/mv.css @@ -0,0 +1,100 @@ +#header { + // width: 820px; + position: relative; + height: 182px; + #background: #000011 url(linhes_header.png) no-repeat center top; + background: #ebb81c url(linhes_header.png) no-repeat center bottom ; + padding: 0; + padding-top: 1px; + font-size: 14px; + color: #FFF; +} + +#header h1#logo-text { + // position: absolute; + margin: 0; padding: 0; + font: bolder 3.3em 'Trebuchet MS', Arial, Sans-serif; + letter-spacing: -2px; + color: #FFFFFF; + text-transform: none; + text-align: center; + /* change the values of top and left to adjust the position of the logo*/ + top: 0px; left: 150px; +} + +#content +{ + color: #FFFFFF; + text-transform: none; + text-align: center; +} + +#navcontainer +{ + width: 100%; + float: left; + background-color:#0072bc; +} + +#navcontainer ul { padding: 0; } +#navcontainer ul li { display: inline; } + +#navcontainer ul +{ + margin: 0; + padding: 0 0 0 7%; + color: #FFFFFF; + font-family: tahoma, verdana, geneva, arial, helvetica, sans-serif; + //font-size: .65em; + letter-spacing: 2px; + font-weight: bold; + float: right; + //background:#ebb81c; + background-color: #0072bc; + +} + + +#navcontainer ul li a +{ + padding: 0.2em 12px;// background-color: #ebb81c; + background-color: #0072bc; + color: #FFFFFF; + text-decoration: none; + float: left; + //border-right: 1px solid #94B473; + + border-top-right-radius: 15px; + -moz-border-top-right-radius: 15px; + + border-top-left-radius: 15px; + -moz-border-top-left-radius: 15px; +} + + +#navcontainer a:active +{ + background-color: #ECECEC; + color: #333; + border-top-right-radius: 25px; + -moz-border-top-right-radius: 25px; + border-top-left-radius: 25px; + -moz-border-top-left-radius: 22px; +} + +#navcontainer ul li a:hover +{ + background-color: #ECECEC; + color: #333; +} + +#navlist li a:hover, #navlist li a:active li:active +{ + color: #FFFFFF; + text-decoration: none; + background:black; + text-align: right; + font-family: tahoma, verdana, geneva, arial, helvetica, sans-serif; +} + + diff --git a/linhes/linhes-web/website/contents/mvp_process.py b/linhes/linhes-web/website/contents/mvp_process.py new file mode 100644 index 0000000..b01ed8b --- /dev/null +++ b/linhes/linhes-web/website/contents/mvp_process.py @@ -0,0 +1,195 @@ +#!/usr/bin/python +import sys +import cgi +import os +import socket +import time +import shutil +try: + import cgitb + cgitb.enable() +except ImportError: + sys.stderr = sys.stdout +def cgiprint(inline=''): + sys.stdout.write(inline) + sys.stdout.write('\r\n') + sys.stdout.flush() +contentheader = 'Content-Type: text/html' + +thepage = '''<html><head> +<title>%s</title> +</head><body> +%s +</body></html> +''' +h1 = '<h1>%s</h1>' + +def getform(theform, valuelist, notpresent='', nolist=False): + """ + This function, given a CGI form as a + FieldStorage instance, extracts the + data from it, based on valuelist + passed in. Any non-present values are + set to '' - although this can be + changed. (e.g. to return None so you + can test for missing keywords - where + '' is a valid answer but to have the + field missing isn't.) It also takes a + keyword argument 'nolist'. If this is + True list values only return their + first value. + """ + data = {} + for field in valuelist: + + + if not theform.has_key(field): + # if the field is not present (or was empty) + data[field] = notpresent + else: + # the field is present + data[field] = theform.getlist(field) + +# print type(theform[field]) + return data + +def getall(theform, nolist=False): + """ + Passed a form (cgi.FieldStorage + instance) return *all* the values. + This doesn't take into account + multipart form data (file uploads). + It also takes a keyword argument + 'nolist'. If this is True list values + only return their first value. + """ + data = {} + for field in theform.keys(): + # we can't just iterate over it, but must use the keys() method + if type(theform[field]) == type([]): + if not nolist: + data[field] = theform.getlist(field) + + else: + data[field] = theform.getfirst(field) + else: + data[field] = theform[field].value + + + return data + +def isblank(indict): + """ + Passed an indict of values it checks + if any of the values are set. Returns + True if the indict is empty, else + returns False. I use it on the a form + processed with getform to tell if my + CGI has been activated without any + form values. + """ + for key in indict.keys(): + if indict[key]: + return False + return True + + +def update_mvp_list(maclist): + outfile = open("/etc/dnsmasq.mvpmc.conf","w") + mvpline="dhcp-boot=net:mvp,dongle.bin" + mvpmacline='dhcp-host=net:mvp,%s' + results="The following media mvp devices have been added:" + results+='</br>' + havemvp = "false" + #print maclist + for i in range(len(maclist)): + if maclist[i] != '': +# print mvpmacline % maclist[i] + outfile.write(mvpmacline % maclist[i] + '\n' ) + havemvp="true" + results+=maclist[i] + results+='</br>' + if havemvp == "true": +# print mvpline + outfile.write(mvpline + '\n' ) + outfile.flush + outfile.close + #time.sleep(5) + + else: + outfile.close + return results + + +mainpage = ''' + <html><head> + <style type="text/css">@import "/frame.css";</style> + <!--<meta http-equiv="refresh" content="6">--> + <title>Receiving a Form</title> + </head><body>%s</body></html>''' + +error = ''' + + <h2>Removed all media mvp devices</h2>''' + +result = ''' + <h1>%s</h1> +''' +possible_parameters = ['activemvp', 'othermac','hiddenparam'] + +if __name__ == '__main__': + cgiprint(contentheader) # content header + cgiprint() # finish headers with blank line + + theform = cgi.FieldStorage() + #print theform + formdict = getform(theform, possible_parameters) + #print possible_parameters + #print formdict + oldurl = '/mvpmc.shtml' + if isblank(formdict): + body = error + all_active=[] + else: + all_active=[] + activemac_checkbox = formdict['activemvp'] + for i in range(len(activemac_checkbox)): + active_string=activemac_checkbox[i] + active_string=active_string.strip() + all_active.append(active_string) + body = result % ("MVP mac address") + + + + print mainpage % body + # mylogfile=update_mvp_list(all_active) + + + box=''' + <div style="border: 1px solid #aaa; width:600px; height:500px; overflow:auto; color:#FFF;text-align:left;"> + <code id="box" style="display: block; height: 500px; width: 600px; overflow: auto;"> + ''' + + endbox=''' + </code> + </div> + ''' + javascript=''' + <script type="text/javascript"> + var objDiv = document.getElementById("box"); + objDiv.scrollTop = objDiv.scrollHeight; + </script> + ''' + if all_active != []: + mylogfile=update_mvp_list(all_active) + command="sudo /sbin/sv stop dnsmasq" + os.system(command) + command="sudo /sbin/sv start dnsmasq" + os.system(command) + print box + print mylogfile + print endbox + print '<a href=', oldurl, ' > Back </a> ' + #print oldurl + print javascript + diff --git a/linhes/linhes-web/website/contents/mvp_select.py b/linhes/linhes-web/website/contents/mvp_select.py new file mode 100644 index 0000000..8283d68 --- /dev/null +++ b/linhes/linhes-web/website/contents/mvp_select.py @@ -0,0 +1,146 @@ +#!/usr/bin/python +# + +import urllib2 +import string +import sys +import time +import datetime +import socket + +def read_accepted(): + + global dhcp_accepted + dhcp_accepted = [] + try: + infile = open('/tmp/dhcp.leases', 'r') + except(IOError), e: + print "couldn't open accepted" + else: + filelist = infile.readlines() + infile.close() + for item in filelist: + item=item.strip() + macaddress=item.split(" ")[1] + if macaddress not in dhcp_accepted: + dhcp_accepted.append(macaddress) + #print macaddress + +def read_offered(): + global dhcp_offered + dhcp_offered = [] + try: + today = datetime.date.today() + + host = socket.gethostname() + filename='/var/log/' + filename+=str(today) + filename+='/' + filename+=host + filename+='/dnsmasq' + infile = open(filename, 'r') + except(IOError), e: + print "couldn't open offered" + else: + filelist = infile.readlines() + infile.close() + for item in filelist: + item=item.strip() + if item.find("DHCPOFFER") != -1 : + macaddress=item.rpartition(" ")[2] + if macaddress not in dhcp_offered: + dhcp_offered.append(macaddress) + #print macaddress + + + +def read_current(): + global dhcp_current + dhcp_current = [] + try: + infile = open('/etc/dnsmasq.mvpmc.conf', 'r') + except(IOError), e: + print "couldn't open current" + else: + filelist = infile.readlines() + infile.close() + for item in filelist: + item=item.strip() + if item.find("dhcp-host") != -1 : + macaddress=item.partition(",")[2] + + if macaddress not in dhcp_current : + dhcp_current.append(macaddress) + # print macaddress + + + + + + + +def make_html(): + global dhcp_accepted + global dhcp_offered + buttonform_top=''' + <div class="content" style="solid #aaa; width:500px; height:300px; overflow:auto; color:#FFF;text-align:left;"> + <form action="/mvp_process.py" method="get"> + ''' + + + buttonform_bottom=''' + Mac Address: + <input type="text" name="activemvp"> + + </br> + <input id="submitbutton" type="submit" /> + </form> + </div> + ''' + checkboxline = ''' + <input type="checkbox" name="activemvp" value="%s" %s /> %s <br /> + ''' + print '<br />' + da = set(dhcp_accepted) + dof = set(dhcp_offered) + dc = set(dhcp_current) + possible_mac= dof -dc + #possible_mac= dof -da - dc + + print buttonform_top + for mac in dhcp_current: + print checkboxline % (mac ,' checked="yes"' , mac) + for mac in possible_mac: + print checkboxline % (mac , " " ,mac) + print buttonform_bottom + + +#------------------- +global dhcp_accepted +global dhcp_offered +global dhcp_current + + + + +read_offered() +#print "--" +#print '</br>' +read_accepted() +#print "--" +#print '</br>' +read_current() +#print "--" +#print '</br>' + + + +#possible_mac= (dof - da) +#possible_mac = dof +#print "should be unchecked:" +#print possible_mac + + +make_html() + + diff --git a/linhes/linhes-web/website/contents/mvpmc.shtml b/linhes/linhes-web/website/contents/mvpmc.shtml new file mode 100644 index 0000000..edc27d4 --- /dev/null +++ b/linhes/linhes-web/website/contents/mvpmc.shtml @@ -0,0 +1,21 @@ +<html> +<head> +<style type="text/css">@import "/frame.css";</style> +</head> +<h1>Media MVP page</h1> +<body> +<div id="mainContainer"> +<!-- <div id="header"><p></p></div> + <div id="content"> + <p></p>--> + + <!--#exec cmd="/data/srv/httpd/htdocs/mvp_select.py" --> + + +</br> +</br> +<div id="footer"><p>Thank you for choosing MythVantage</p></div> + +</body> +</html> + diff --git a/linhes/linhes-web/website/contents/mythweb.html b/linhes/linhes-web/website/contents/mythweb.html new file mode 100644 index 0000000..fe76a9a --- /dev/null +++ b/linhes/linhes-web/website/contents/mythweb.html @@ -0,0 +1,16 @@ +<html> +<head> +<style type="text/css">@import "/frame.css";</style> +</head> + +<body> +MythWeb does not appear to be installed. +</br> +To install MythWeb either +</br> +1) Visit the MythVantage advanced screen to enable mythweb. </br> +2) type "pacman -S mythweb-release-fixes" at the console. + + +</body> +</html> diff --git a/linhes/linhes-web/website/contents/page_background.jpg b/linhes/linhes-web/website/contents/page_background.jpg Binary files differnew file mode 100644 index 0000000..4819c9a --- /dev/null +++ b/linhes/linhes-web/website/contents/page_background.jpg diff --git a/linhes/linhes-web/website/contents/process.py b/linhes/linhes-web/website/contents/process.py new file mode 100755 index 0000000..60714ee --- /dev/null +++ b/linhes/linhes-web/website/contents/process.py @@ -0,0 +1,447 @@ +#!/usr/bin/python2 +import sys +import cgi +import os +import socket +import time +import StringIO + +try: + import cgitb + cgitb.enable() +except ImportError: + sys.stderr = sys.stdout +def cgiprint(inline=''): + sys.stdout.write(inline) + sys.stdout.write('\r\n') + sys.stdout.flush() +contentheader = 'Content-Type: text/html' + +def getform(theform, valuelist, notpresent='', nolist=False): + """ + This function, given a CGI form as a + FieldStorage instance, extracts the + data from it, based on valuelist + passed in. Any non-present values are + set to '' - although this can be + changed. (e.g. to return None so you + can test for missing keywords - where + '' is a valid answer but to have the + field missing isn't.) It also takes a + keyword argument 'nolist'. If this is + True list values only return their + first value. + """ + data = {} + for field in valuelist: + if not theform.has_key(field): + # if the field is not present (or was empty) + data[field] = notpresent + else: + # the field is present + #print type(theform[field]) + if type(theform[field]) != type([]): + # is it a list or a single item + #print type(theform[field]) + data[field] = theform[field].value + else: + if not nolist: + # do we want a list ? + data[field] = theform.getlist(field) + else: + data[field] = theform.getfirst(field) + # just fetch the first item + return data + +def getall(theform, nolist=False): + """ + Passed a form (cgi.FieldStorage + instance) return *all* the values. + This doesn't take into account + multipart form data (file uploads). + It also takes a keyword argument + 'nolist'. If this is True list values + only return their first value. + """ + data = {} + for field in theform.keys(): + # we can't just iterate over it, but must use the keys() method + if type(theform[field]) == type([]): + if not nolist: + data[field] = theform.getlist(field) + else: + data[field] = theform.getfirst(field) + else: + data[field] = theform[field].value + return data + +def isblank(indict): + """ + Passed an indict of values it checks + if any of the values are set. Returns + True if the indict is empty, else + returns False. I use it on the a form + processed with getform to tell if my + CGI has been activated without any + form values. + """ + for key in indict.keys(): + if indict[key]: + return False + return True + +def go_backup(myhost): + myhostname = socket.gethostname() + results="Nothing happened" + command= "sudo /usr/LH/bin/lh_system_backup_job" + #print command + + command2="sleep 1; sudo -u nobody /home/xymon/server/ext/hbnotes.py" + results=os.popen(command,'r') + os.popen(command2,'r') + + return results + +def go_download_backup(dl_file): + # Actual File Content will go hear. + dlf = "/data/storage/disk0/backup/system_backups/%s" %dl_file + fo = open(dlf, "rb") + + str = fo.read() + fo.close() + + # HTTP Header + print "Content-Type:application/octet-stream; name=\"%s\"\r\n;" %(dl_file) + print "Content-Disposition: attachment; filename=\"%s\"\r\n;" %(dl_file) + print "Content-Length: %d" % len(str) + print "" + + print str + return results + +def go_restore(restorefile,myhost,prestore): + myhostname = socket.gethostname() + psc = '' + if prestore == "on": + psc = "partial" + + if myhostname.strip() == myhost.strip(): + command="sudo /usr/LH/bin/lh_system_restore_job %s %s" %(restorefile , psc) + else: + #this should never execute + sshcmd="ssh -o StrictHostKeyChecking=no -o ConnectTimeout=1 -i /data/srv/.nobody_ssh/id_dsa mythtv@" + sshcmd+=myhost.strip() + cmd=' "sudo /usr/bin/restore_job.sh " ' + command=sshcmd + cmd + restorefile + " 2>&1 " + #print command + results=os.popen(command,'r') + return results + +def go_upload(up_file): + saveDir = "/data/storage/disk0/backup/system_backups/" + fPath = "%s/%s" % (saveDir, up_file.filename) + buf = up_file.file.read() + bytes = len(buf) + sFile = open(fPath, 'wb') + sFile.write(buf) + sFile.close() + results=["<b>%s</b> uploaded (%d bytes)." %(up_file.filename, bytes)] + line = '''The backup has been uploaded and is now available for restore. + To restore from the file, check "Restore database" then select the file from the drop down menu''' + + results.append(line) + + command2="sleep 1; sudo -u nobody /home/xymon/server/ext/hbnotes.py" + os.popen(command2,'r') + + return results + +def go_optimize(myhost): + #myhostname = socket.gethostname() + #if myhostname.strip() == myhost.strip(): + command="/usr/LH/bin/optimize_mythdb.py" + #print command + results=os.popen(command,'r') + #else: + #results='This host does not run a database' + return results + +def go_update(myhost,update_type): + cmd=" call pacman update_system " + cmd+=update_type + command="/usr/bin/func \"" + myhost.strip() + "*\" " + cmd + #print command + results=os.popen(command,'r') + return results + +def go_updateall(allupdate_type): + cmd=" sudo /usr/bin/update_system_all " + cmd+=allupdate_type + command= cmd + " 2>&1 " + results=os.popen(command,'r') + return results + +def go_shutdown(myhost): + myhostname = socket.gethostname() + message="Shutdown from MBE" + command="/usr/bin/func \"" + myhost.strip() + "*\" call msg display \"%s\" " %message + results=os.popen(command,'r') + time.sleep(3) + command="/usr/bin/func \"" + myhost.strip() + "*\" call power poweroff " + results=os.popen(command,'r') + return results + +def go_shutdownall(): + import MySQLdb + #import mysql + #find all hosts(minus myself) + #loop through results shutdown as we go. + db = MySQLdb.connect(host="localhost", user="mythtv", passwd="mythtv", db="mythconverg") + # create a cursor + cursor = db.cursor() + # execute SQL statement + myhostname = socket.gethostname() + results=["Sent shutdown command to: \n "] + cursor.execute("SELECT distinct(hostname) from settings where not hostname = %s ; ",(myhostname)) + result = cursor.fetchall() + + for row in result: + go_shutdown(row[0]) + results.append(row[0]) + + #shutdown myself. + #go_shutdown(myhostname) + #results.append(myhostname) + return results + +def go_reboot(myhost): + myhostname = socket.gethostname() + message="Reboot from MBE" + command="/usr/bin/func \"" + myhost.strip() + "*\" call msg display \"%s\" " %message + results=os.popen(command,'r') + time.sleep(3) + + command="/usr/bin/func \"" + myhost.strip() + "*\" call power reboot " + results=os.popen(command,'r') + return results + +def go_wake(myhost): + command="/usr/MythVantage/bin/wakeonlan.sh " + myhost.strip() + results=os.popen(command,'r') + return results + +def go_kill(myhost,kill_type): + myhostname = socket.gethostname() + cmd=" call fe_restart " + cmd+=kill_type + command="/usr/bin/func \"" + myhost.strip() + "*\" " + cmd + + results=os.popen(command,'r') + return results + +def go_restart_mbe_local(): + cmd = "/usr/LH/bin/lh_backend_control.sh restart &" + #results=os.popen(cmd,'r') + os.popen(cmd,'r') + results = ["Attempting restart of backend service"] + return results + + +mainpage = ''' +<html> + <head> + <style type="text/css">@import "/frame.css";</style> + <meta http-equiv="cache-control" content="max-age=0"> + <meta http-equiv="cache-control" content="no-cache"> + <meta http-equiv="expires" content="0"> + <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT"> + <meta http-equiv="pragma" content="no-cache"> + <title>LinHES</title> + </head> + <body> + %s + </body> +</html> +''' + + +loadingpage = ''' +<html> + <head> + <style type="text/css">@import "/frame.css";</style> + <script src="/ajaxloader.min.js"></script> + <meta http-equiv="cache-control" content="max-age=0"> + <meta http-equiv="cache-control" content="no-cache"> + <meta http-equiv="expires" content="0"> + <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT"> + <meta http-equiv="pragma" content="no-cache"> + <title>LinHES</title> + </head> + <body> + <div id="header"> + %s + </div> + <div id="container"> + <br><br> + <h3>Working. Please Wait...</h3> + <br><br> + <div> + <canvas id="spinner"></canvas> + </div> + </div> + <script type="text/javascript"> + var opts = { + size: 72, // Width and height of the spinner + factor: 0.25, // Factor of thickness, density, etc. + color: "#ebb81c", // Color #rgb or #rrggbb + speed: 1.0, // Number of turns per second + clockwise: true // Direction of rotation + }; + var ajaxLoader = new AjaxLoader("spinner", opts); + ajaxLoader.show(); + </script> +''' + + +error = ''' + <h1>Error</h1> + <h2>No Form Submission Was Received</h2>''' + + +result = ''' + <h1>%s of %s</h1> +''' + +possible_parameters = ['param1', 'param2', 'param3', 'param4','hiddenparam','param5','param6','param7','uFile','param8'] + +if __name__ == '__main__': + + theform = cgi.FieldStorage() + #print theform + formdict = getform(theform, possible_parameters) + #print possible_parameters + + if isblank(formdict): + body = error + else: + name = formdict['param1'] + radio = formdict['param2'] # should be 'this' or 'that' + if radio != 'Restore' : + name = "" + update_type = formdict['param3'] + oldurl = formdict['param4'] + hidden = formdict['hiddenparam'] + all_update_type=formdict['param5'] + kill_type = formdict['param6'] + dl_file = formdict['param7'] + try: + up_file = theform['uFile'] + except: + pass + try: + prestore = theform['param8'].value + except: + prestore = "off" + body = result % (radio, hidden) + + selection=radio + myhost=hidden.lower() + + if selection == "Restore": + mylogfile=go_restore(name,myhost,prestore) + cgiprint(contentheader) # content header + cgiprint() # finish headers with blank line + print mainpage % body + elif selection == "Backup": + cgiprint(contentheader) # content header + cgiprint() # finish headers with blank line + print loadingpage % body + mylogfile=go_backup(myhost) + elif selection == "Dbackup": + mylogfile=go_download_backup(dl_file) + cgiprint(contentheader) # content header + cgiprint() # finish headers with blank line + print mainpage % body + elif selection == "Update": + cgiprint(contentheader) # content header + cgiprint() # finish headers with blank line + print loadingpage % body + mylogfile=go_update(myhost,update_type) + elif selection == "Shutdown": + mylogfile=go_shutdown(myhost) + cgiprint(contentheader) # content header + cgiprint() # finish headers with blank line + print mainpage % body + elif selection == "Reboot": + mylogfile=go_reboot(myhost) + cgiprint(contentheader) # content header + cgiprint() # finish headers with blank line + print mainpage % body + elif selection == "Optimize": + cgiprint(contentheader) # content header + cgiprint() # finish headers with blank line + print loadingpage % body + mylogfile=go_optimize(myhost) + elif selection == "WOL": + cgiprint(contentheader) # content header + cgiprint() # finish headers with blank line + print loadingpage % body + mylogfile=go_wake(myhost) + elif selection == "UpdateAll": + mylogfile=go_updateall(all_update_type) + cgiprint(contentheader) # content header + cgiprint() # finish headers with blank line + print mainpage % body + elif selection == "ShutdownAll": + mylogfile=go_shutdownall() + cgiprint(contentheader) # content header + cgiprint() # finish headers with blank line + print mainpage % body + elif selection == "Kill": + mylogfile=go_kill(myhost,kill_type) + cgiprint(contentheader) # content header + cgiprint() # finish headers with blank line + print mainpage % body + elif selection == "Upload": + mylogfile = go_upload(up_file) + cgiprint(contentheader) # content header + cgiprint() # finish headers with blank line + print mainpage % body + elif selection == "RestartMBE": + mylogfile = go_restart_mbe_local() + cgiprint(contentheader) # content header + cgiprint() # finish headers with blank line + print mainpage % body + + cgiprint() # finish headers with blank line + + box='''<br><br> + <div id="resultbox" > + + ''' + + endbox=''' + + </div> + ''' + javascript=''' + <script type="text/javascript"> + document.getElementById("container").style.display = 'none'; + ajaxLoader.hide(); + var objDiv = document.getElementById("resultbox"); + objDiv.scrollTop = objDiv.scrollHeight; + </script> + ''' + + print box + for line in mylogfile: + print line + '<br> \r\n' + + print endbox + print "<br><br>" + #print '<a href=', oldurl, ' > Back </a> ' + s='<a href="%s"><img src="back.png"></a>' %oldurl + print s + #<a href="myfile.htm"><img src="rainbow.gif"></a> + #print oldurl + print javascript diff --git a/linhes/linhes-web/website/contents/skeleton.css b/linhes/linhes-web/website/contents/skeleton.css new file mode 100644 index 0000000..6a6b107 --- /dev/null +++ b/linhes/linhes-web/website/contents/skeleton.css @@ -0,0 +1,105 @@ +/* ================================================================
+This copyright notice must be untouched at all times.
+
+The original version of this stylesheet and the associated (x)html
+is available at http://www.stunicholls.com/menu/skeleton_up.html
+Copyright (c) 2005-2007 Stu Nicholls. All rights reserved.
+This stylesheet and the associated (x)html may be modified in any
+way to fit your requirements.
+=================================================================== */
+#header_img {margin:5px auto;display:block;width:100%}
+
+#nav,
+#nav ul {padding:0 0 5px 0; margin:0; list-style:none;
+ font: 14px helvetica, sans-serif;
+ /*font: 14px verdana, sans-serif;*/
+ border:1px solid #000;
+ border-color:#ace #79b #68a #bde;
+ border-width:1px 2px 2px 1px; background:#fff;
+ position:relative; z-index:200;}
+
+#nav {height:auto; width:calc(100% - 2px);
+ padding:0; background-color:#0072bc;
+ display: inline-block;}
+
+#nav li {float:left; width:100%;}
+#nav li li {float:none; background:#fff;}
+/* a hack for IE5.x and IE6 */
+* html #nav li li {float:left;}
+
+
+
+
+#nav li a {display:block; float:left;
+ color:#FFFFFF; margin:0 25px 0 10px;
+ height:auto; line-height:25px;
+ text-decoration:none; white-space:normal;
+}
+
+/*item in white box*/
+#nav li li a {height:auto; line-height:20px; float:none;
+ background-color:#0072bc;
+ margin:0 0 0 0;
+ border:1px solid #000;
+ /*border-color:#ace #79b #68a #bde;*/
+ border-color:#0072bc;
+ border-width:3px 3px 3px 3px; background:#0072bc;
+ }
+
+#nav li:hover {position:relative; z-index:300; }
+
+/*white box*/
+#nav li:hover ul {left:4em; top:0px; right:-10px; background-color:#0072bc;}
+
+/* another hack for IE5.5 and IE6 */
+* html #nav li:hover ul {left:10px;}
+
+
+#nav ul {position:absolute;
+ left:-9999px;
+ top:-9999px;
+}
+/* yet another hack for IE5.x and IE6 */
+* html #nav ul {width:1px;}
+
+/* it could have been this simple if all browsers understood */
+/* show next level */
+#nav li:hover li:hover > ul {left:-15px; margin-left:100%; bottom:-7px; top:auto;}
+/* keep further levels hidden */
+#nav li:hover > ul ul {position:absolute; left:-9999px; top:-9999px; width:auto;}
+/* show path followed */
+
+#nav li:hover > a {text-decoration:underline; }
+
+
+/* but IE5.x and IE6 need this lot to style the flyouts and path followed */
+/* show next level */
+#nav li:hover li:hover ul,
+#nav li:hover li:hover li:hover ul,
+#nav li:hover li:hover li:hover li:hover ul,
+#nav li:hover li:hover li:hover li:hover li:hover ul
+{left:-15px; margin-left:100%; bottom:-7px; top:auto;}
+
+/* keep further levels hidden */
+#nav li:hover ul ul,
+#nav li:hover li:hover ul ul,
+#nav li:hover li:hover li:hover ul ul,
+#nav li:hover li:hover li:hover li:hover ul ul
+{position:absolute; left:-9999px; top:-9999px;}
+
+/* show path followed */
+#nav li:hover a,
+#nav li:hover li:hover a,
+#nav li:hover li:hover li:hover a,
+#nav li:hover li:hover li:hover li:hover a,
+#nav li:hover li:hover li:hover li:hover li:hover a,
+#nav li:hover li:hover li:hover li:hover li:hover li:hover a
+{text-decoration:underline; color:#ebb81c;}
+
+/* hide futher possible paths */
+#nav li:hover li a,
+#nav li:hover li:hover li a,
+#nav li:hover li:hover li:hover li a,
+#nav li:hover li:hover li:hover li:hover li a,
+#nav li:hover li:hover li:hover li:hover li:hover li a
+{text-decoration:none; color:#FFFFFF;}
|