/******************************************************************************* * Copyright (c) 2008, 2017 Alphonse Van Assche and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Alphonse Van Assche - initial API and implementation *******************************************************************************/ package org.eclipse.linuxtools.internal.rpm.ui.editor.hyperlink; import java.net.MalformedURLException; import java.net.URL; import java.text.MessageFormat; import java.util.StringTokenizer; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector; import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.jface.viewers.ISelection; import org.eclipse.linuxtools.internal.rpm.ui.editor.SpecfileEditor; import org.eclipse.linuxtools.rpm.ui.editor.parser.Specfile; /** * Mail hyperlink detector. Largely inspired of {@link org.eclipse.jface.text.hyperlink.URLHyperlinkDetector} */ public class MailHyperlinkDetector extends AbstractHyperlinkDetector { private SpecfileEditor editor; @Override public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) { if (region == null || textViewer == null) { return null; } if (editor == null) { editor = this.getAdapter(SpecfileEditor.class); if (editor == null) { return null; } } IDocument document= textViewer.getDocument(); int offset= region.getOffset(); String urlString= null; if (document == null) { return null; } IRegion lineInfo; String line; String mail; int mailLength = 0; int mailOffsetInLine; try { lineInfo= document.getLineInformationOfOffset(offset); line= document.get(lineInfo.getOffset(), lineInfo.getLength()); } catch (BadLocationException ex) { ex.printStackTrace(); return null; } int startSeparator= line.indexOf('<'); mailOffsetInLine = startSeparator + 1; if (startSeparator != -1) { int endSeparator= line.indexOf('>'); if (endSeparator < 5) { return null; } mail= line.substring(startSeparator + 1, endSeparator).trim(); mailLength= mail.length(); // Some cleanups, maybe we can add more. mail= mail.replaceAll("(?i) at ", "@"); //$NON-NLS-1$ //$NON-NLS-2$ mail= mail.replaceAll("(?i) dot ", "."); //$NON-NLS-1$ //$NON-NLS-2$ mail= mail.replaceAll("(?i)_at_", "@"); //$NON-NLS-1$ //$NON-NLS-2$ mail= mail.replaceAll("(?i)_dot_", "."); //$NON-NLS-1$ //$NON-NLS-2$ mail= mail.replaceAll(" +", " "); //$NON-NLS-1$ //$NON-NLS-2$ if (mail.split(" ").length == 3) { //$NON-NLS-1$ if (mail.indexOf('@') == -1) { mail = mail.replaceFirst(" ", "@").replaceFirst(" ", "."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } } mail= mail.replaceAll(" ", ""); //$NON-NLS-1$ //$NON-NLS-2$ } else { int offsetInLine= offset - lineInfo.getOffset(); boolean startDoubleQuote= false; mailOffsetInLine= 0; int mailSeparatorOffset= line.indexOf('@'); while (mailSeparatorOffset >= 0) { // (left to "@") mailOffsetInLine= mailSeparatorOffset; char ch; do { mailOffsetInLine--; ch= ' '; if (mailOffsetInLine > -1) { ch= line.charAt(mailOffsetInLine); } startDoubleQuote= ch == '"'; } while (Character.isLetterOrDigit(ch) || ch == '.' || ch == '_' || ch == '-'); mailOffsetInLine++; // a valid mail contain a left part. if (mailOffsetInLine == mailSeparatorOffset) { return null; } // Right to "@" StringTokenizer tokenizer= new StringTokenizer(line.substring(mailSeparatorOffset + 3), " \t\n\r\f<>", false); //$NON-NLS-1$ if (!tokenizer.hasMoreTokens()) { return null; } mailLength= tokenizer.nextToken().length() + 3 + mailSeparatorOffset - mailOffsetInLine; if (offsetInLine >= mailOffsetInLine && offsetInLine <= mailOffsetInLine + mailLength) { break; } mailSeparatorOffset= line.indexOf('@', mailSeparatorOffset + 1); } if (mailSeparatorOffset < 0) { return null; } if (startDoubleQuote) { int endOffset= -1; int nextDoubleQuote= line.indexOf('"', mailOffsetInLine); int nextWhitespace= line.indexOf(' ', mailOffsetInLine); if (nextDoubleQuote != -1 && nextWhitespace != -1) { endOffset= Math.min(nextDoubleQuote, nextWhitespace); } else if (nextDoubleQuote != -1) { endOffset= nextDoubleQuote; } else if (nextWhitespace != -1) { endOffset= nextWhitespace; } if (endOffset != -1) { mailLength= endOffset - mailOffsetInLine; } } if (mailLength == 0) { return null; } mail= line.substring(mailOffsetInLine, mailOffsetInLine + mailLength); } try { // mail address contain at less one '@' and one '.' character. if (!mail.contains("@") || !mail.contains(".")) { //$NON-NLS-1$ //$NON-NLS-2$ return null; } urlString= "mailto:" + mail; //$NON-NLS-1$ char separator= '?'; String subject= getSubject(); if (subject != null) { urlString+= separator + "subject=" + subject; //$NON-NLS-1$ separator= '&'; } String body= getBody(); if (body != null) { urlString+= separator + "body=" + body; //$NON-NLS-1$ } // url don't like % urlString= urlString.replaceAll("\\%", "\\%25"); //$NON-NLS-1$ //$NON-NLS-2$ new URL(urlString); } catch (MalformedURLException ex) { ex.printStackTrace(); urlString= null; return null; } IRegion urlRegion= new Region(lineInfo.getOffset() + mailOffsetInLine, mailLength); return new IHyperlink[] {new MailHyperlink(urlRegion, urlString)}; } private String getSubject() { Specfile specfile= editor.getSpecfile(); return MessageFormat.format("[{0}.spec - {1}-{2}]", specfile.getName(), specfile.getVersion(), //$NON-NLS-1$ specfile.getRelease()); } private String getBody() { String body = null; // Get current selection IDocument document= editor.getAdapter(IDocument.class); ISelection currentSelection= editor.getSpecfileSourceViewer().getSelection(); if (currentSelection instanceof ITextSelection) { ITextSelection selection= (ITextSelection) currentSelection; try { String txt= selection.getText(); if (txt.trim().length() > 0) { int begin= document.getLineOffset(selection.getStartLine()); body= document.get().substring(begin, selection.getOffset() + selection.getLength()); // replace left spaces or tabs and add a space at the begin of each line. body= body.replaceAll("(?m)^[ \\t]+|[ \\t]+$|^", " "); //$NON-NLS-1$ //$NON-NLS-2$ } } catch (BadLocationException e) { } } return body; } public void setEditor(SpecfileEditor editor) { this.editor = editor; } }