From eab086303d3f8255488f3e9dc099f0f0b17614c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=9D=E7=91=AA=E8=B2=93?= Date: Wed, 21 Dec 2016 00:09:00 +0800 Subject: [PATCH] First commit. --- bin/mpresent | 270 +++++++++++++++++++++++++++++++++++++++++++++++++++ setup.py | 22 +++++ 2 files changed, 292 insertions(+) create mode 100755 bin/mpresent create mode 100755 setup.py diff --git a/bin/mpresent b/bin/mpresent new file mode 100755 index 0000000..cb5d170 --- /dev/null +++ b/bin/mpresent @@ -0,0 +1,270 @@ +#! /opt/openoffice4/program/python +# -*- coding: utf-8 -*- +# OpenOffice mobile presentation constroller, as Python +# by imacat , 2014-02-28 + +# Python imports +import os +import os.path +import sys +import ssl +import time +import random +import BaseHTTPServer + + +def append_uno_path(): + """ Appends the path of the uno module to the import path. """ + + is_found_uno = False + for p in sys.path: + if os.path.exists(os.path.join(p, "uno.py")): + return + # For uno.py on MacOS + cand = "/Applications/OpenOffice.app/Contents/MacOS" + if os.path.exists(os.path.join(cand, "uno.py")): + sys.path.append(cand) + return + # Finds uno.py for MS-Windows + cand = sys.executable + while cand != os.path.dirname(cand): + cand = os.path.dirname(cand) + if os.path.exists(os.path.join(cand, "uno.py")): + sys.path.append(cand) + return + +append_uno_path() +import uno +from com.sun.star.beans import PropertyValue +from com.sun.star.lang import DisposedException +from com.sun.star.connection import NoConnectException + + +class PresentationController: + """The OpenOffice mobile presentation controller.""" + + def __init__(self, docfile): + """Initializes the object.""" + self.file = docfile + self.bootstrap_context = None + self.service_manager = None + self.desktop = None + self.doc = None + + def check_valid(self): + """Check the validity of the connection and the opened document.""" + try: + presentation = self.doc.getPresentation() + except (AttributeError, DisposedException): + try: + self.bootstrap_context.getServiceManager() + except (AttributeError, DisposedException): + self.connect() + self.open() + presentation = self.doc.getPresentation() + if not presentation.isRunning(): + presentation.start() + + def connect(self): + """Connects to the running OpenOffice process.""" + # Obtains the local context + local_context = uno.getComponentContext() + # Obtains the local service manager + local_service_manager = local_context.getServiceManager() + # Obtains the URL resolver + url_resolver = local_service_manager.createInstanceWithContext( + "com.sun.star.bridge.UnoUrlResolver", local_context) + # Obtains the context + url = ("uno:socket,host=localhost,port=2002;" + "urp;StarOffice.ComponentContext") + try: + self.bootstrap_context = url_resolver.resolve(url) + except NoConnectException: + self.start_oo() + self.bootstrap_context = url_resolver.resolve(url) + # Obtains the service manager + self.service_manager = self.bootstrap_context.getServiceManager() + # Obtains the desktop service + self.desktop = self.service_manager.createInstanceWithContext( + "com.sun.star.frame.Desktop", self.bootstrap_context) + + def start_oo(self): + """Starts the OpenOffice in server listening mode""" + # For MS-Windows, which does not have fork() + if os.name == "nt": + from subprocess import Popen + ooexec = os.path.join(os.path.dirname(uno.__file__), "soffice.exe") + DETACHED_PROCESS = 0x00000008 + Popen([ooexec, "-accept=socket,host=localhost,port=2002;urp;"], + close_fds=True, creationflags=DETACHED_PROCESS) + time.sleep(2) + return + + # For POSIX systems, including Linux + try: + pid = os.fork() + except OSError: + sys.stderr.write("failed to fork().\n") + sys.exit(1) + if pid != 0: + time.sleep(2) + return + os.setsid() + ooexec = os.path.join(os.path.dirname(uno.__file__), "soffice.bin") + try: + os.execl( + ooexec, ooexec, + "-accept=socket,host=localhost,port=2002;urp;") + except OSError: + sys.stderr.write( + ooexec + ": Failed to run the OpenOffice server.\n") + sys.exit(1) + + def open(self): + """Opens an office document.""" + file_content_provider = self.service_manager.createInstance( + "com.sun.star.ucb.FileContentProvider") + url = file_content_provider.getFileURLFromSystemPath("", self.file) + enum = self.desktop.getComponents().createEnumeration() + while enum.hasMoreElements(): + component = enum.nextElement() + if component.supportsService( + "com.sun.star.presentation.PresentationDocument"): + if component.getURL() == url: + self.doc = component + return + prop1 = PropertyValue() + prop1.Name = "ReadOnly" + prop1.Value = True + prop2 = PropertyValue() + prop2.Name = "MacroExecutionMode" + # com.sun.star.document.MacroExecMode.ALWAYS_EXECUTE + prop2.Value = 2 + self.doc = self.desktop.loadComponentFromURL( + url, "_default", 0, (prop2,)) + if not self.doc.supportsService( + "com.sun.star.presentation.PresentationDocument"): + sys.stderr.write(self.file + ": not a presentation document.\n") + sys.exit(1) + return + + def goto_next_slide(self): + """Goes to the next slide.""" + self.doc.getPresentation().getController().gotoNextSlide() + return + + def goto_prev_slide(self): + """Goes to the previous slide.""" + self.doc.getPresentation().getController().gotoPreviousSlide() + return + + +class MyHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): + """The local HTTP request handler.""" + def do_GET(self): + """Handles the GET requests.""" + oo.check_valid() + html = """ + + + + + + +OpenOffice Presentation Controller + + + +
+
+ +
+
+ +
+
+ +
+
+ +""" + self.send_response(200) + self.send_header("Content-Type", "text/html; charset=UTF-8") + self.send_header("Content-Length", len(html)) + self.end_headers() + self.wfile.write(html) + + def do_POST(self): + """Handles the POST requests.""" + oo.check_valid() + if self.path == "/next": + oo.goto_next_slide() + elif self.path == "/prev": + oo.goto_prev_slide() + html = """ + + + + + +303 See Others + + +

303 See Others

+

Please follow this location.

+ +""" + self.send_response(303) + self.send_header("Location", "/") + self.send_header("Content-Type", "text/html; charset=US-ASCII") + self.send_header("Content-Length", len(html)) + self.end_headers() + self.wfile.write(html) + + +def run(): + """Runs the local HTTP server and starts the presentation.""" + oo.check_valid() + server_address = ("", 53177) + httpd = BaseHTTPServer.HTTPServer(server_address, MyHTTPRequestHandler) + # TODO: Changed to an option or find the certificates automatically + if usessl is not False: + httpd.socket = ssl.wrap_socket( + httpd.socket, + keyfile=usessl[0], + certfile=usessl[1], + server_side=True) + httpd.serve_forever() + +if __name__ == "__main__": + if len(sys.argv) != 2: + sys.stderr.write("Please specify the presentation document.\n") + sys.exit(1) + docfile = os.path.abspath(sys.argv[1]) + s = docfile.lower() + if not (s.endswith(".odp") + or s.endswith(".sxi") + or s.endswith(".ppt") + or s.endswith(".pptx")): + sys.stderr.write(docfile + ": not a presentation document.\n") + sys.exit(1) + if not os.path.exists(docfile): + sys.stderr.write(docfile + ": file does not exist.\n") + sys.exit(1) + if not os.path.isfile(docfile): + sys.stderr.write(docfile + ": file does not exist.\n") + sys.exit(1) + mydir = os.path.dirname(os.path.abspath(sys.argv[0])) + keyfile = os.path.join(mydir, "server.key.pem") + crtfile = os.path.join(mydir, "server.crt.pem") + usessl = False + if os.path.isfile(keyfile) and os.path.isfile(crtfile): + usessl = (keyfile, crtfile) + oo = PresentationController(docfile) + run() diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..a14a5e9 --- /dev/null +++ b/setup.py @@ -0,0 +1,22 @@ +import os +import sys +from setuptools import setup + +# For Python shipped with OpenOffice, python is a wrapper +# for python.bin that fixes the import and library path. We should +# call python instead of python.bin. """ +import os +import sys +if os.path.basename(sys.executable) == "python.bin": + sys.executable = os.path.join( + os.path.dirname(sys.executable), "python") + +setup(name="mpresent", + version="0.1", + description="Office mobile presentation constroller", + url="https://github.com/imacat/mpresent", + author="imacat", + author_email="imacat@mail.imacat.idv.tw", + license="Apache License, Version 2.0", + zip_safe=False, + scripts=["bin/mpresent"])