/** * MailArchiver is an application that provides services for storing and managing e-mail messages through a Web Services SOAP interface. * Copyright (C) 2012 Marcio Andre Scholl Levien and Fernando Alberto Reuter Wendt and Jose Ronaldo Nogueira Fonseca Junior * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ /******************************************************************************\ * * This product was developed by * * SERVIÇO FEDERAL DE PROCESSAMENTO DE DADOS (SERPRO), * * a government company established under Brazilian law (5.615/70), * at Department of Development of Porto Alegre. * \******************************************************************************/ package serpro.mailarchiver.util; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.FileVisitResult; import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; import java.util.Map; import java.util.TreeMap; import static com.google.common.base.Strings.isNullOrEmpty; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import de.schlichtherle.truezip.file.TFile; import de.schlichtherle.truezip.nio.file.TPath; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Configurable; import serpro.mailarchiver.service.dto.TFolder; import serpro.mailarchiver.service.web.ArchiveServices; import serpro.mailarchiver.service.web.ServiceFault; @Configurable public class ImportServlet extends HttpServlet { private static final Logger log = Logger.getLocalLogger(); private Integer _filescounter = 0; private Integer _filesok = 0; private Integer _filesnok = 0; @Autowired private ArchiveServices archiveServices; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp){ try { log.info("ImportServlet inicializado: carregando mensagens de arquivo ZIP para o meta arquivamento..."); String foldername = "fid"; String sessname = "sid"; String protocol = "prt"; String port = "por"; String lang = "lng"; String base_folder = ""; String foldervalue = req.getParameter(foldername); String sessvalue = req.getParameter(sessname); String protocolvalue = req.getParameter(protocol); String portvalue = req.getParameter(port); String langvalue = req.getParameter(lang); //validates folder import destination. Defaults will be "inbox" if(foldervalue == null) { // The request parameter 'folder id' was not present in the query string. So, default import dir will be setted to 'inbox' folder log.debug("ImportServlet -> pasta de destino nula. Utilizando o padrão \"inbox\" (caixa de entrada) para destino da importação."); base_folder = "inbox"; } else if(foldervalue.isEmpty()) { // The request parameter 'param' was present in the query string but has no value. Same policy. log.debug("ImportServlet -> pasta de destino vazia. Utilizando o padrão \"inbox\" (caixa de entrada) para destino da importação."); base_folder = "inbox"; } else { //OK, user has passed a folder name. log.debug("ImportServlet -> pasta de destino da importação é \"" + foldervalue + "\"."); base_folder = foldervalue; } //validates the session id string handler if(isNullOrEmpty(sessvalue)) { //todo -> sess handler log.debug("ImportServlet -> identificador da sessão nulo ou inválido. Utilizando \"fakesessid\" para a importação."); sessvalue = "fakesessid"; } //validates protocol entry: defaults, points to HTTPS if(isNullOrEmpty(protocolvalue) || (!"http".equals(protocolvalue) && (!"https".equals(protocolvalue)))) { protocolvalue = "https"; } log.debug("ImportServlet -> protocolo em uso é \"" + protocolvalue + "\"."); //validates port entry: defaults, points to HTTPS default port (4334) if(isNullOrEmpty(portvalue)) { portvalue = "4334"; } log.debug("ImportServlet -> porta em uso é \"" + portvalue + "\"."); //validates lang entry: defaults PT-BR if(isNullOrEmpty(langvalue)) { langvalue = "pt-BR"; } log.debug("ImportServlet -> idioma em uso é \"" + langvalue + "\"."); resp.setContentType("text/html"); PrintWriter out = resp.getWriter(); StringBuilder htmlpage = new StringBuilder(); htmlpage.append( "\n" + " \n" + " Import local messages package\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ""); out.println(htmlpage.toString()); log.debug("ImportServlet -> página web estática repassada ao cliente com a seguinte URL: \"" + protocolvalue + "://127.0.0.1:" + portvalue + "/arcservutil/form_upload.html?basevalue=" + base_folder + "&sessvalue=" + sessvalue + "&serprotocol=" + protocolvalue + "&serport=" + portvalue + "&langvalue=" + langvalue + "\"."); } catch(IOException ex) { resp.setContentType("text/html"); PrintWriter out = null; try { out = resp.getWriter(); } catch(IOException ex1) { log.error(ex1); } StringBuilder htmlpage = new StringBuilder(""); htmlpage.append( "\n" + " \n" + " \n" + " \n" + "

MailArchiver

\n" + " \n" + ""); out.println(htmlpage.toString()); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) { try { log.debug("ImportServlet -> processamento de HTTP POST data inicializado."); _doPost(req, resp); String lang = req.getParameter("lang"); resp.setContentType("text/html"); PrintWriter out = resp.getWriter(); StringBuilder htmlpage = new StringBuilder(""); htmlpage.append( "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "

"); if((_filescounter == _filesok) && (_filescounter > 0 )) htmlpage.append(LocalizedString.ImportSuccessful.get(lang)); else if((_filescounter == _filesnok) && (_filescounter > 0)) htmlpage.append(LocalizedString.ImportFailure.get(lang)); else if((_filescounter != _filesok) && (_filesnok > 0)) htmlpage.append(LocalizedString.ImportPartialSucess.get(lang)); htmlpage.append("

\n" + "
\n" + "
Resumo do processamento:
\n" + "
").append(LocalizedString.TotalCounterData.get(lang)).append(_filescounter).append("
\n" + "
").append(LocalizedString.CounterDataOK.get(lang)).append(_filesok).append("
\n" + "
").append(LocalizedString.CounterDataNOK.get(lang)).append(_filesnok).append("
\n" + "
\n" + " \n" + ""); out.println(htmlpage.toString()); } catch(ServletException ex) { resp.setContentType("text/html"); PrintWriter out = null; try { out = resp.getWriter(); } catch(IOException ex1) { log.error(ex1); } StringBuilder htmlpage = new StringBuilder(""); htmlpage.append( "\n" + " \n" + " \n" + " \n" + " \n" + "

") .append(ex.getMessage()).append("

\n" + " \n" + ""); out.println(htmlpage.toString()); } catch(IOException ex) { resp.setContentType("text/html"); PrintWriter out = null; try { out = resp.getWriter(); } catch(IOException ex1) { log.error(ex1); } StringBuilder htmlpage = new StringBuilder(""); htmlpage.append( "\n" + " \n" + " \n" + " \n" + " \n" + "

") .append(ex.getMessage()).append("

\n" + " \n" + ""); out.println(htmlpage.toString()); } } private void _doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { final String _sessionId = req.getParameter("sessionId"); final String _base = req.getParameter("base"); final String _flat = req.getParameter("flat"); final String _mailarc = req.getParameter("file_1"); final String _lang = req.getParameter("lang"); log.info("ImportServlet -> doPost data dumping ---\n\tsessionId: %s\n\tbase: %s\n\tflat: %s\n\tfile_1: %s", _sessionId, _base, _flat, _mailarc); log.debug("ImportServlet: reinicializando contador de files"); _filescounter = 0; _filesok = 0; _filesnok = 0; //TODO: validar sessão Path base0 = Paths.get(""); if(_base != null) { String[] names = _base.split("/|\\\\"); for(String name : names) { if(name.isEmpty()) { continue; } base0 = base0.resolve(name); } } final TPath base = new TPath(base0); final Map folderMap = new TreeMap(); if(base.toString().isEmpty()) { folderMap.put(base, null); } else { try { TFolder folderDto = archiveServices.createAbsoluteFolder(_sessionId, base.toString()); String folderId = folderDto.getId(); folderMap.put(base, folderId); } catch(ServiceFault e) { //log.error(e); } } final boolean flat = "true".equalsIgnoreCase(_flat); if((!_mailarc.endsWith(".zip")) && (!_mailarc.endsWith(".jar")) && (!_mailarc.endsWith(".tar")) && (!_mailarc.endsWith(".tar.gz")) && (!_mailarc.endsWith(".tgz")) && (!_mailarc.endsWith(".tar.bz2")) && (!_mailarc.endsWith(".tb2")) && (!_mailarc.endsWith(".tbz"))) { log.warn("ImportServlet: unsupported package file format at import event [" + _mailarc + "]"); throw new IOException(LocalizedString.InvalidPackageFormat.get(_lang)); } log.debug("ImportServlet: seguindo com pacote postado: \"" +_mailarc + "\""); Path tmpPath0 = ((File) req.getAttribute("file_1")).toPath(); log.debug("ImportServlet: tmp file path: \"" +tmpPath0.toString() + "\""); Path tmpPath = Files.move(tmpPath0, tmpPath0.resolveSibling(_mailarc), StandardCopyOption.REPLACE_EXISTING); log.debug("ImportServlet: path temporário após o files.move: \""+ tmpPath.toString() + "\""); final TPath zip = new TPath(tmpPath); Files.walkFileTree(zip, new FileVisitor() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { log.debug("ImportServlet: acessando diretório de destino da importação"); Path rel = zip.relativize(dir); if(flat) { return FileVisitResult.CONTINUE; } Path folderPath = base.resolve(rel); if(folderPath.getNameCount() > base.getNameCount()) { try { log.debug("ImportServlet: invocando o serviço \"createAbsoluteFolder\" com o folder \"" + folderPath.toString() + "\""); TFolder folderDto = archiveServices.createAbsoluteFolder(_sessionId, folderPath.toString()); String folderId = folderDto.getId(); log.debug("ImportServlet: folderId \"" + folderId + "\""); folderMap.put(folderPath, folderId); } catch(ServiceFault e) { log.error("ImportServlet: falha ao invocar o serviço \"createAbsoluteFolder\". StackTrace:\n" + e.getStackTrace()+ "\""); } } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { _filescounter++; Path rel = zip.relativize(file); Path folderPath = (flat) ? base : base.resolve(rel).getParent(); String folderId = folderMap.get(folderPath); log.debug("ImportServlet: navegando pelo conteúdo do pacote EML -> \"" + file.toString() + "\"."); //just "eml" files visitor if(file.toString().endsWith(".eml")) { String message = new String(Files.readAllBytes(file), Charsets.Windows_1252); try { log.info("ImportServlet: invocando serviço de arquivamento para \"" + file.toString() + "\""); archiveServices.archive(_sessionId, folderId, message); _filesok++; } catch(ServiceFault e) { log.error("ImportServlet: falha ao invocar serviço de arquivamento para \"" + file.toString() + "\" \n\t ---> " + e.getStackTrace()); _filesnok++; } } else { log.warn("ImportServlet: desconsiderando arquivo presente no pacote que não é EML[" + file.toString() + "]"); _filesnok++; } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { //Path rel = zip.relativize(file); log.debug("ImportServlet: falha ao visitar o arquivo [" + file.toString() + "]:\n\t" + exc.getStackTrace()); _filesnok++; return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { //Path rel = zip.relativize(dir); return FileVisitResult.CONTINUE; } }); log.info("ImportServlet: contabilização de processamento\n\t ---> total de arquivos no pacote: " + _filescounter + "\n\t ---> total de arquivos importados: " + _filesok + "\n\t ---> total de arquivos falhos/inválidos: " + _filesnok); TFile.umount(zip.toFile(), true); log.debug("ImportServlet: servlet de importação encerrado"); } enum LocalizedString { InvalidPackageFormat( "Falha na importação:
O formato do pacote enviado é inválido.", "Import failure:
File format from sent package is invalid.", "La importaciõn ha fallado:
El formato del paquete enviado no es válido." ), InvalidMessageFormat( "Falha na importação:
Somente arquivos no formato "eml" são suportados.", "Import failure:
Only "eml" files are supported.", "La importaciõn ha fallado:
Sõlo archivos "eml" son compatibles." ), ImportFailure( "A importação local não carregou mensagens
Verifique o conteúdo dos dados do pacote: somente arquivos "eml" são suportados.", "The import data is not loaded:
Take a look at the package data: only "eml" files are supported.", "La importaciõn de datos no está cargado:
Revise el contenido del paquete: "eml" sólo son compatibles." ), ImportPartialSucess( "A importação local carregou algumas mensagens
É possível que outros arquivos de outros formatos estejam presentes no pacote.", "Import succed partially:
It is possible the package contains others files format plus messages data.", "La importaciõn fue parcial:
Puede haber otros formatos de archivo en el paquete." ), ImportSuccessful( "Importação local realizada com sucesso!
Lembre-se de atualizar a sua visualização do navegador para conferir o resultado.", "Local import gracefull finished!
Remember to refresh your page view in order to get the operation result.", "La importación se completó con éxito!
Recuerde actualizar su pantalla para ver los resultados." ), LoadingData( "Aguarde", "Loading", "Esperar" ), TotalCounterData( "Total de arquivos no pacote: ", "Total files in the package: ", "Total de archivos en el paquete: " ), CounterDataOK( "Carregados com êxito: ", "Successfully loaded: ", "Se ha cargado satisfactoriamente: " ), CounterDataNOK( "Não carregados: ", "Uncharged: ", "Sin carga: " ); private final String pt_BR; private final String en_US; private final String es_ES; LocalizedString(String pt_BR, String en_US, String es_ES) { this.pt_BR = pt_BR; this.en_US = en_US; this.es_ES = es_ES; } public String get(String lang) { if("en-US".equals(lang) || "en_US".equals(lang)) { return en_US; } else if("es-ES".equals(lang) || "es_ES".equals(lang)) { return es_ES; } else { return pt_BR; } } } }