/** * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS-IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ jimport("java.io.File"); jimport("java.io.FileOutputStream"); jimport("java.lang.System.out.println"); jimport("java.io.ByteArrayInputStream"); jimport("java.io.ByteArrayOutputStream"); jimport("java.io.DataInputStream"); jimport("java.io.DataOutputStream"); jimport("net.appjet.common.sars.SarsClient"); jimport("com.etherpad.openofficeservice.OpenOfficeService"); jimport("com.etherpad.openofficeservice.UnsupportedFormatException"); jimport("com.etherpad.openofficeservice.TemporaryFailure"); import("etherpad.log"); import("etherpad.utils"); import("sync"); import("execution"); import("varz"); import("exceptionutils"); function _log(obj) { log.custom("import-export", obj); } function onStartup() { execution.initTaskThreadPool("importexport", 1); } var formats = { pdf: 'application/pdf', doc: 'application/msword', html: 'text/html; charset=utf-8', odt: 'application/vnd.oasis.opendocument.text', txt: 'text/plain; charset=utf-8' } function _createTempFile(bytes, type) { var f = File.createTempFile("ooconvert-", (type === null ? null : (type == "" ? "" : "."+type))); if (bytes) { var fos = new FileOutputStream(f); fos.write(bytes); } return f; } function _initConverterClient(convertServer) { if (convertServer) { var convertHost = convertServer.split(":")[0]; var convertPort = Number(convertServer.split(":")[1]); if (! appjet.scopeCache.converter) { var converter = new SarsClient("ooffice-password", convertHost, convertPort); appjet.scopeCache.converter = converter; converter.setConnectTimeout(5000); converter.setReadTimeout(40000); appjet.scopeCache.converter.connect(); } return appjet.scopeCache.converter; } else { return null; } } function _conversionSarsFailure() { delete appjet.scopeCache.converter; } function errorUnsupported(from) { return "Unsupported file type"+(from ? ": "+from+"." : ".")+" Etherpad can only import txt, html, rtf, doc, and docx files."; } var errorTemporary = "A temporary failure occurred; please try again later."; function doSlowFileConversion(from, to, bytes, continuation) { var bytes = convertFileSlowly(from, to, bytes); continuation.resume(); return bytes; } function _convertOverNetwork(convertServer, from, to, bytes) { var c = _initConverterClient(convertServer); var reqBytes = new ByteArrayOutputStream(); var req = new DataOutputStream(reqBytes); req.writeUTF(from); req.writeUTF(to); req.writeInt(bytes.length); req.write(bytes, 0, bytes.length); var retBtyes; try { retBytes = c.message(reqBytes.toByteArray()); } catch (e) { if (e.javaException) { net.appjet.oui.exceptionlog.apply(e.javaException) } _conversionSarsFailure(); return "A communications failure occurred; please try again later."; } if (retBytes.length == 0) { return "An unknown failure occurred; please try again later. (#5)"; } var res = new DataInputStream(new ByteArrayInputStream(retBytes)); var status = res.readInt(); if (status == 0) { // success var len = res.readInt(); var resBytes = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, len); res.readFully(resBytes); return resBytes; } else if (status == 1) { return errorTemporary; } else if (status == 2) { var permFailureCode = res.readInt(); if (permFailureCode == 0) { return "An unknown failure occurred. (#1)"; } else if (permFailureCode == 1) { return errorUnsupported(from); } } else { return "An unknown failure occurred. (#2)"; } } function convertFileSlowly(from, to, bytes) { var convertServer = appjet.config["etherpad.sofficeConversionServer"]; if (convertServer) { return _convertOverNetwork(convertServer, from, to, bytes); } if (! utils.hasOffice()) { return "EtherPad is not configured to import or export formats other than txt and html. Please contact your system administrator for details."; } OpenOfficeService.setExecutable(appjet.config["etherpad.soffice"]); try { return OpenOfficeService.convertFile(from, to, bytes); } catch (e) { if (e.javaException instanceof TemporaryFailure) { return errorTemporary; } else if (e.javaException instanceof UnsupportedFormatException) { return errorUnsupported(from); } else { return "An unknown failure occurred. (#3)"; } } } function _noteConversionAttempt() { varz.incrementInt("importexport-conversions-attempted"); } function _noteConversionSuccess() { varz.incrementInt("importexport-conversions-successful"); } function _noteConversionFailure() { varz.incrementInt("importexport-conversions-failed"); } function _noteConversionTimeout() { varz.incrementInt("importexport-conversions-timeout"); } function _noteConversionImpossible() { varz.incrementInt("importexport-conversions-impossible"); } function precomputedConversionResult(from, to, bytes) { try { var retBytes = request.cache.conversionCallable.get(500, java.util.concurrent.TimeUnit.MILLISECONDS); var delay = Date.now() - request.cache.startTime; _log({type: "conversion-latency", from: from, to: to, numBytes: request.cache.conversionByteLength, delay: delay}); varz.addToInt("importexport-total-conversion-millis", delay); if (typeof(retBytes) == 'string') { _log({type: "error", error: "conversion-failed", from: from, to: to, numBytes: request.cache.conversionByteLength, delay: delay}); _noteConversionFailure(); } else { _noteConversionSuccess(); } return retBytes; } catch (e) { if (e.javaException instanceof java.util.concurrent.TimeoutException) { _noteConversionTimeout(); request.cache.conversionCallable.cancel(false); _log({type: "error", error: "conversion-failed", from: from, to: to, numBytes: request.cache.conversionByteLength, delay: -1}); return "Conversion timed out. Please try again later."; } _log({type: "error", error: "conversion-failed", from: from, to: to, numBytes: request.cache.conversionByteLength, trace: exceptionutils.getStackTracePlain(e)}); _noteConversionFailure(); return "An unknown failure occurred. (#4)"; } } function convertFile(from, to, bytes) { if (request.cache.conversionCallable) { return precomputedConversionResult(from, to, bytes); } _noteConversionAttempt(); if (from == to) { _noteConversionSuccess(); return bytes; } if (from == "txt" && to == "html") { _noteConversionSuccess(); return (new java.lang.String(utils.renderTemplateAsString('pad/exporthtml.ejs', { content: String(new java.lang.String(bytes, "UTF-8")).replace(/&/g, "&").replace(/