From 2549b610a84a5e17aad9d8dbc8422f0719709436 Mon Sep 17 00:00:00 2001
From: James Meyer <james.meyer@operamail.com>
Date: Thu, 27 Sep 2012 00:04:37 -0500
Subject: LinHES-system: enhance msg_client.py and msg_deamon.py to support :
 msg_client.py --clear --tag    to clear the queue, with the --tag then the
 whole queue is cleared --msg  --tag  to add messages to que --kill   kill
 whatever is currently being displayed

---
 abs/core/LinHES-system/msg_client.py |  31 ++-
 abs/core/LinHES-system/msg_daemon.py | 375 +++++++++++++++++++++++++++++++----
 2 files changed, 364 insertions(+), 42 deletions(-)

diff --git a/abs/core/LinHES-system/msg_client.py b/abs/core/LinHES-system/msg_client.py
index 3c53857..175933f 100755
--- a/abs/core/LinHES-system/msg_client.py
+++ b/abs/core/LinHES-system/msg_client.py
@@ -3,6 +3,8 @@
 
 import socket
 import sys
+import argparse
+import pickle
 
 # Create a UDS socket
 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
@@ -33,10 +35,25 @@ def send_message(message):
 
 
 if __name__ == "__main__":
-    if len(sys.argv) == 2:
-        send_message(sys.argv[1])
-    else:
-        print "Unknown command"
-        print "usage: %s msg to display" % sys.argv[0]
-        sys.exit(2)
-    sys.exit(0)
+    parser = argparse.ArgumentParser()
+
+    parser.add_argument('--tag', action='store', dest='tag',help='message tag')
+    parser.add_argument('--timeout', action='store', dest='timeout',help='time to display message')
+    action = parser.add_mutually_exclusive_group(required=True)
+    action.add_argument('--msg', action='store', dest='msg', help='Add message to the queue')
+    action.add_argument('--clear', action='store_true', help='Remove message from queue that match tag')
+    action.add_argument('--kill', action='store_true', help='Kill current msg thats displayed')
+
+    results = parser.parse_args()
+    resultsdict = vars(results)
+
+    if results.msg :
+        cmd = "msg"
+    elif results.clear:
+        cmd = "clear"
+    elif results.kill:
+        cmd = "kill"
+
+    arg_dict = {'cmd':cmd , 'msg':resultsdict['msg'] , 'tag':resultsdict['tag'] , 'timeout':resultsdict['timeout']}
+    send_message(pickle.dumps(arg_dict))
+    #sys.exit(0)
diff --git a/abs/core/LinHES-system/msg_daemon.py b/abs/core/LinHES-system/msg_daemon.py
index 5ca5b09..b766aae 100755
--- a/abs/core/LinHES-system/msg_daemon.py
+++ b/abs/core/LinHES-system/msg_daemon.py
@@ -4,43 +4,348 @@
 import socket
 import sys
 import os
-from subprocess import call
+import pickle
+import operator
+import threading
+import time
+import aosd
+import ConfigParser
+import multiprocessing
+import subprocess,signal
+
+sys.path.append('/etc')
 
 server_address = '/run/msg_socket'
+class msg_aosd():
+    def scroll(self,osd, width, height, display_time,position):
+        pos = position
+        step = 1
 
-# Make sure the socket does not already exist
-try:
-    os.unlink(server_address)
-except OSError:
-    if os.path.exists(server_address):
-        raise
-# Create a UDS socket
-sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-# Bind the socket to the port
-print >>sys.stderr, 'starting up on %s' % server_address
-sock.bind(server_address)
-#change permissions of socket
-os.chmod(server_address,0777)
-
-# Listen for incoming connections
-sock.listen(1)
-
-while True:
-    # Wait for a connection
-    connection, client_address = sock.accept()
-    try:
-        #print >>sys.stderr, 'connection from', client_address
-        msg=""
-        # Receive the data in small chunks and retransmit it
-        while True:
-            data = connection.recv(16)
-            msg+=data
-            if data:
-                continue
+        osd.set_position(pos, width, height)
+        (x, y, _, _) = osd.get_geometry()
+        osd.set_position_offset(width, height)
+        osd.show()
+
+        x -= 1
+        y += height - 1;
+        for i in range(1, height + 1, step):
+            osd.loop_for(5)
+            y -= step
+            osd.set_geometry(x, y, width, i)
+
+        osd.set_position(pos, width, height)
+        osd.set_position_offset(-1, -1)
+        (x, y, _, _) = osd.get_geometry()
+    #time to display
+        osd.loop_for(display_time)
+        for i in range(height, 0, -step):
+            y += step
+            osd.set_geometry(x, y, width, i);
+            osd.loop_for(1);
+
+        osd.hide();
+
+    def setup(self,font_color,font_type):
+        osd = aosd.AosdText()
+        osd.set_transparency(aosd.TRANSPARENCY_COMPOSITE)
+        if osd.get_transparency() != aosd.TRANSPARENCY_COMPOSITE:
+            osd.set_transparency(aosd.TRANSPARENCY_NONE)
+
+        osd.geom_x_offset = 10
+        osd.geom_y_offset = 0
+
+        osd.back_color = "white"
+        osd.back_opacity = 50
+
+        osd.shadow_color = "black"
+        osd.shadow_opacity = 127
+        osd.shadow_x_offset = 2
+        osd.shadow_y_offset = 2
+
+        osd.fore_color = font_color
+        osd.fore_opacity = 255
+
+        osd.set_font(font_type)
+        osd.wrap = aosd.PANGO_WRAP_WORD_CHAR
+        osd.alignment = aosd.PANGO_ALIGN_LEFT
+        osd.set_layout_width(osd.get_screen_wrap_width())
+        return osd
+
+    def set_string(self, osd, text):
+        osd.set_text(text)
+        return osd.get_text_size()
+
+    def setup_config(self):
+        module_config = ConfigParser.RawConfigParser()
+        try:
+            module_config.read('/usr/MythVantage/etc/msg.cfg')
+        except:
+            pass
+        return module_config
+
+
+
+    def display (self,flags,display_time=-1):
+        """
+        parse the msg for display.
+        """
+        try:
+            text,config_section=flags.split("|")
+            if config_section == '':
+                config_section="default"
+        except:
+            text=flags
+            config_section="default"
+
+        module_config = self.setup_config()
+
+        position=6
+        font_color="green"
+        font_type="Times New Roman Italic 36"
+
+        if display_time <=  0 :
+            try:
+                display_time =  int(module_config.get(config_section,"display_time"))
+            except:
+                display_time = 5000
+                pass
+        try:
+            position =  int(module_config.get(config_section,"position"))
+        except:
+            pass
+        try:
+            font_color = module_config.get(config_section,"font_color")
+        except:
+            pass
+        try:
+            font_type =  module_config.get(config_section,"font_type")
+        except:
+            pass
+
+        #this bit of code converts a \n to EOL/BREAK
+        textline=text.split('\\n')
+        try:
+            textline.remove(' ')
+        except:
+            pass
+        text=chr(10).join(textline)
+
+        #cmd = sub_process.Popen("/usr/bin/wall %s" % text,stdout=sub_process.PIPE,shell=True)
+        #data = cmd.communicate()[0]
+        osd = self.setup(font_color, font_type)
+        width, height = self.set_string(osd, text)
+        self.scroll(osd, width, height, display_time, position)
+
+        return ("Message delivered")
+
+
+class msg_xosd():
+    """Crude wrapper for xosd_cat"""
+    def __init__ (self):
+        pass
+
+    def set_default_values(self):
+        self.color="yellow"
+        self.outline="2"
+        self.outlinecolour="black"
+        self.shadow="0"
+        self.shadowcolour="black"
+        self.font="-adobe-helvetica-bold-*-*-*-34-*-*-*-*-*-*-*"
+        return
+
+    def set_parameters(self):
+        xosd_cfg={}
+        file_name = "/etc/osd_cat.cfg"
+        try:
+            config_file = open(file_name)
+        except:
+            set_default_values()
+            return
+
+        for line in config_file:
+            line = line.strip()
+            if line and line[0] is not "#" and line[-1] is not "=":
+                var, val = line.rsplit("=", 1)
+                val = val.split("#")[0]
+                val = val.strip('"')
+                xosd_cfg[var.strip()] = val.strip()
+        self.color   = xosd_cfg['color']
+        self.outline = xosd_cfg['outline']
+        self.outlinecolour = xosd_cfg['outlinecolour']
+        self.shadow = xosd_cfg['shadow']
+        self.shadowcolour = xosd_cfg['shadowcolour']
+        self.font = xosd_cfg['font']
+
+    def display(self,msg,display_time):
+        self.set_parameters()
+        cmd = "echo -e \"%s\" | DISPLAY=127.0.0.1:0 osd_cat --pos=middle --align=center --offset=200 --delay=%s --color=%s --outline=%s --outlinecolour=%s --shadow=%s --shadowcolour=%s  --font=\"%s\"" %(msg,display_time,self.color,self.outline,self.outlinecolour,self.shadow,self.shadowcolour,self.font)
+        #set a process group on the OS, so that the kill gets them all.  No one survives or becomes a zombie
+        self.p = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,preexec_fn=os.setsid)
+        self.processID = self.p.pid
+        stdout,stderr = self.p.communicate()
+
+    def kill(self):
+        try:
+            os.killpg(self.processID,signal.SIGTERM)
+        except:
+            pass
+
+class Msg_Queue():
+    def __init__(self):
+        self.msglist=[]
+        self.msg_slot = 0
+
+    def get_msg(self):
+        return self.msglist.pop(0)
+        pass
+
+    def add_msg(self,cmddict):
+        #print "Adding msg to msg queue"
+        self.inc_last_msg_slot()
+        cmddict['slot'] = self.msg_slot
+        self.msglist.append(cmddict)
+
+
+    def clear_msg(self,msg_tag):
+        #print "Clearing out list of %s" %msg_tag
+        #loop over list in reverse
+        for i in xrange(len(self.msglist) - 1, -1, -1):
+            #access list by index, look at the key tag
+            if self.msglist[i]['tag'] == msg_tag:
+                del self.msglist[i]
+
+    def clear(self):
+        #print "Clearing out entire queue"
+        del self.msglist[:]
+
+    def sort(self,keyvalue):
+        self.msglist.sort(key=operator.itemgetter(keyvalue))
+
+    def search(self,key,value):
+        pass
+
+    def print_queue(self):
+        print "############################"
+        for i in self.msglist:
+            for key, value in i.iteritems():
+                print key,":", value
+            print "-----"
+
+    def get_last_msg_slot(self):
+        return self.msg_slot
+
+    def inc_last_msg_slot(self):
+        self.msg_slot  = self.msg_slot + 1
+
+
+class msg_queue_runner(threading.Thread):
+  """Threaded Queue runner for testing things"""
+  def __init__(self, msg_queue):
+      threading.Thread.__init__(self)
+      self.msg_queue = msg_queue
+      self.out_msg = msg_aosd()
+      self.out_xosd = msg_xosd()
+
+  def get_current_style(self):
+    style = "default"
+    if  os.path.exists('/etc/X11/WINDOWMANAGER'):
+        command = ['bash', '-c', 'source /etc/X11/WINDOWMANAGER && echo $STARTUP_STYLE']
+        proc = subprocess.Popen(command, stdout = subprocess.PIPE)
+
+        for line in proc.stdout:
+            if line.strip() == "":
+                style = "default"
             else:
-                call(["/usr/LH/bin/lh_message.sh", msg])
-                break
+                style = line.strip()
+            break
+        proc.communicate()
+    else:
+        style = "default"
+    return style
+
+
+  def kill_current(self):
+      style = self.get_current_style()
+      #print "Killing current display"
+      if style == "enhanced":
+        self.p.terminate()
+      elif style == "default":
+        #self.p.terminate()
+        self.out_xosd.kill()
+
+  def run(self):
+    while True:
+        try:
+            msgdict = self.msg_queue.get_msg()
+            style = self.get_current_style()
+            if msgdict['timeout'] == None:
+                display_time = 3
+
+            # display message here
+            msgtext = msgdict['msg']
+            if style == "enhanced":
+                display_time = display_time * 1000
+                self.p = multiprocessing.Process(target=self.out_msg.display, args=(msgtext,display_time))
+                self.p.start()
+                self.p.join()
+            elif style == "default":
+                display_time = int(msgdict['timeout'])
+                self.out_xosd.display(msgtext,display_time)
+
+        except:
+            time.sleep(1)
+            continue
+
+
+msg_queue = Msg_Queue()
+
+
+if __name__ == "__main__":
+    # Make sure the socket does not already exist
+    try:
+        os.unlink(server_address)
+    except OSError:
+        if os.path.exists(server_address):
+            raise
+    # Create a UDS socket
+    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+    # Bind the socket to the port
+    print >>sys.stderr, 'starting up on %s' % server_address
+    sock.bind(server_address)
+    #change permissions of socket
+    os.chmod(server_address,0777)
+
+    # Listen for incoming connections
+    sock.listen(1)
+    #start msg display thread
+    msgthread = msg_queue_runner(msg_queue)
+    msgthread.setDaemon(True)
+    msgthread.start()
+
+
+    #main loop that reads in the cmddict, never exits
+    while True:
+        # Wait for a connection
+        connection, client_address = sock.accept()
+        try:
+            sf = connection.makefile("r+b", bufsize=0)
+            data = sf.read()
+            cmddict = (pickle.loads(data))
+
+            if cmddict['cmd'] == "msg":
+                #add to msg_queue
+                msg_queue.add_msg(cmddict)
+            elif cmddict['cmd'] == 'clear':
+                if cmddict['tag'] == '' or cmddict['tag'] == None :
+                    msg_queue.clear()
+                else:
+                    msg_queue.clear_msg(cmddict['tag'])
+            elif cmddict['cmd'] == 'kill':
+                    msgthread.kill_current()
+                ##    call(["/usr/LH/bin/lh_message.sh", msg])
+                #break
+        finally:
+            # Clean up the connection
+            connection.close()
+
 
-    finally:
-        # Clean up the connection
-        connection.close()
-- 
cgit v0.12

