#!/usr/bin/env python # -*- coding: UTF-8 -*- # # TabellioOOo - SCGI server providing preview of ODF files # Copyright (C) 2007-2010 Parlement de la Communauté française de Belgique # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import sys import os import resource from optparse import OptionParser from scgi.scgi_server import SCGIServer, SCGIHandler import time import syslog import socket import tempfile class PreviewHandler(SCGIHandler): debug = False daemon = False def handle_connection(self, conn): input = conn.makefile('r') output = conn.makefile('w') env = self.read_env(input) bodysize = int(env.get('CONTENT_LENGTH', 0)) try: self.produce(env, bodysize, input, output) finally: output.close() input.close() conn.close() def produce(self, env, bodysize, input, output): tmp_work_dir = os.path.join(tempfile.gettempdir(), 'tabellio') if not os.path.exists(tmp_work_dir): os.makedirs(tmp_work_dir) if self.debug: print 'Request received at', time.strftime('[%Y-%m-%d %H:%M]') print ' - body size:', bodysize if bodysize == 0: return self.error_page(output, 'this server only supports POST') input_file = input.read(bodysize) if not os.path.exists('../legi2pdf/script/db2pdf.py'): pdf_file = file('unconfigured.pdf').read() print >> output, 'Content-type: application/pdf' print >> output, 'Content-length: %s' % len(pdf_file) print >> output, '' print >> output, pdf_file return if env.get('REQUEST_URI').endswith('/odt'): # legi file as input, odt file as output legi_filename = tempfile.mkstemp(suffix='.legi', prefix='l2o-', dir=tmp_work_dir)[1] fd = file(legi_filename, 'w') fd.write(input_file) fd.close() os.system('python ../legi2odf/legi2odf.py %s' % legi_filename) odt_file = file(legi_filename.replace('.legi', '.odt')).read() print >> output, 'Content-type: application/octet-stream' print >> output, 'Content-Disposition: attachment' print >> output, 'Content-length: %s' % len(odt_file) print >> output, '' output.write(odt_file) return odf_file = input_file odf_filename = tempfile.mkstemp(suffix='.odt', prefix='o2l-', dir=tmp_work_dir)[1] if self.debug: print ' - storing ODT file as', odf_filename legi_filename = odf_filename.replace('.odt', '.legi') pdf_filename = odf_filename.replace('.odt', '.pdf') fd = file(odf_filename, 'w') fd.write(odf_file) fd.close() if os.system('python ../odf2legi/odf2legi.py %s' % odf_filename): if self.daemon: syslog.syslog(syslog.LOG_ERR, 'error in odf2legi') else: print ' E: error in odf2legi' return self.error_page(output, 'Error in odf2legi') else: if env.get('REQUEST_URI').endswith('/legi'): legi_file = file(legi_filename).read() if self.debug: print 'Serving result as a legi file (%s)' % legi_filename print ' - body size:', len(legi_file) print >> output, 'Content-type: application/octet-stream' print >> output, 'Content-Disposition: attachment' print >> output, 'Content-length: %s' % len(legi_file) print >> output, '' output.write(legi_file) return if os.system('python ../legi2pdf/script/db2pdf.py --debug --latex --input=%s' % legi_filename): if self.daemon: syslog.syslog(syslog.LOG_ERR, 'error in legi2pdf') else: print ' E: error in legi2pdf' return self.error_page(output, 'Error in legi2pdf') if os.path.exists(pdf_filename): pdf_file = file(pdf_filename).read() else: pdf_file = file('error.pdf').read() print >> output, 'Content-type: application/pdf' print >> output, 'Content-length: %s' % len(pdf_file) print >> output, '' output.write(pdf_file) def error_page(self, output, message): print >> output, 'Content-type: text/plain' print >> output, '' print >> output, message def main(): parser = OptionParser() parser.add_option('-p', '--port', dest = 'port', type='int', default = 2151) parser.add_option('--debug', action = 'store_true', dest = 'debug') parser.add_option('-f', '--foreground', dest='foreground', action='store_true') parser.add_option('--pid', dest='pid') options, args = parser.parse_args() # force current directory to match the script, to make sure it finds the # various tools (legi2pdf & odf2legi) os.chdir(os.path.abspath(os.path.dirname(__file__))) if not os.path.exists('../legi2pdf/script/db2pdf.py'): print >> sys.stderr, 'W: legi2pdf not found' if not os.path.exists('/tmp/tabellio'): os.mkdir('/tmp/tabellio') if not options.foreground: PreviewHandler.daemon = True if os.fork(): os._exit(0) os.setsid() maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1] if maxfd == resource.RLIM_INFINITY: maxfd = 1024 for fd in range(maxfd): try: os.close(fd) except OSError: pass os.open('/dev/null', os.O_RDWR) os.dup2(0, 1) os.dup2(0, 2) if os.fork(): os._exit(0) if options.pid: file(options.pid, 'w').write(str(os.getpid())) syslog.openlog('tabellio-preview') PreviewHandler.debug = options.debug try: SCGIServer(handler_class = PreviewHandler, port = options.port).serve() except socket.error: if PreviewHandler.daemon: syslog.syslog(syslog.LOG_CRIT, 'socket error (another instance is running?)') print >> sys.stderr, 'E: socket error (another instance is running?)' sys.exit(1) if __name__ == '__main__': main()