/* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot * * 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 1 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, see . */ using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Threading; using Greenshot.IniFile; using Greenshot.Plugin; using GreenshotPlugin.Core; using System.ComponentModel; using System.Text.RegularExpressions; namespace ExternalCommand { /// /// Description of OCRDestination. /// public class ExternalCommandDestination : AbstractDestination { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ExternalCommandDestination)); private static readonly Regex URI_REGEXP = new Regex(@"((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)"); private static readonly ExternalCommandConfiguration config = IniConfig.GetIniSection(); private readonly string _presetCommand; public ExternalCommandDestination(string commando) { _presetCommand = commando; } public override string Designation { get { return "External " + _presetCommand.Replace(',','_'); } } public override string Description { get { return _presetCommand; } } public override IEnumerable DynamicDestinations() { yield break; } public override Image DisplayIcon { get { return IconCache.IconForCommand(_presetCommand); } } public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { ExportInformation exportInformation = new ExportInformation(Designation, Description); SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(); if (_presetCommand != null) { if (!config.runInbackground.ContainsKey(_presetCommand)) { config.runInbackground.Add(_presetCommand, true); } bool runInBackground = config.runInbackground[_presetCommand]; string fullPath = captureDetails.Filename; if (fullPath == null) { fullPath = ImageOutput.SaveNamedTmpFile(surface, captureDetails, outputSettings); } string output; string error; if (runInBackground) { Thread commandThread = new Thread(delegate() { CallExternalCommand(exportInformation, fullPath, out output, out error); ProcessExport(exportInformation, surface); }) { Name = "Running " + _presetCommand, IsBackground = true }; commandThread.SetApartmentState(ApartmentState.STA); commandThread.Start(); exportInformation.ExportMade = true; } else { CallExternalCommand(exportInformation, fullPath, out output, out error); ProcessExport(exportInformation, surface); } } return exportInformation; } /// /// Wrapper method for the background and normal call, this does all the logic: /// Call the external command, parse for URI, place to clipboard and set the export information /// /// /// /// /// private void CallExternalCommand(ExportInformation exportInformation, string fullPath, out string output, out string error) { output = null; error = null; try { if (CallExternalCommand(_presetCommand, fullPath, out output, out error) == 0) { exportInformation.ExportMade = true; if (!string.IsNullOrEmpty(output)) { MatchCollection uriMatches = URI_REGEXP.Matches(output); // Place output on the clipboard before the URI, so if one is found this overwrites if (config.OutputToClipboard) { ClipboardHelper.SetClipboardData(output); } if (uriMatches.Count > 0) { exportInformation.Uri = uriMatches[0].Groups[1].Value; LOG.InfoFormat("Got URI : {0} ", exportInformation.Uri); if (config.UriToClipboard) { ClipboardHelper.SetClipboardData(exportInformation.Uri); } } } } else { LOG.WarnFormat("Error calling external command: {0} ", output); exportInformation.ExportMade = false; exportInformation.ErrorMessage = error; } } catch (Exception ex) { exportInformation.ExportMade = false; exportInformation.ErrorMessage = ex.Message; LOG.WarnFormat("Error calling external command: {0} ", exportInformation.ErrorMessage); } } /// /// Wrapper to retry with a runas /// /// /// /// /// /// private int CallExternalCommand(string commando, string fullPath, out string output, out string error) { try { return CallExternalCommand(commando, fullPath, null, out output, out error); } catch (Win32Exception w32ex) { try { return CallExternalCommand(commando, fullPath, "runas", out output, out error); } catch { w32ex.Data.Add("commandline", config.commandlines[_presetCommand]); w32ex.Data.Add("arguments", config.arguments[_presetCommand]); throw; } } catch (Exception ex) { ex.Data.Add("commandline", config.commandlines[_presetCommand]); ex.Data.Add("arguments", config.arguments[_presetCommand]); throw; } } /// /// The actual executing code for the external command /// /// /// /// /// /// /// private int CallExternalCommand(string commando, string fullPath, string verb, out string output, out string error) { string commandline = config.commandlines[commando]; string arguments = config.arguments[commando]; output = null; error = null; if (!string.IsNullOrEmpty(commandline)) { using (Process process = new Process()) { // Fix variables commandline = FilenameHelper.FillVariables(commandline, true); commandline = FilenameHelper.FillCmdVariables(commandline, true); arguments = FilenameHelper.FillVariables(arguments, false); arguments = FilenameHelper.FillCmdVariables(arguments, false); process.StartInfo.FileName = FilenameHelper.FillCmdVariables(commandline, true); process.StartInfo.Arguments = FormatArguments(arguments, fullPath); process.StartInfo.UseShellExecute = false; if (config.RedirectStandardOutput) { process.StartInfo.RedirectStandardOutput = true; } if (config.RedirectStandardError) { process.StartInfo.RedirectStandardError = true; } if (verb != null) { process.StartInfo.Verb = verb; } LOG.InfoFormat("Starting : {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); process.Start(); process.WaitForExit(); if (config.RedirectStandardOutput) { output = process.StandardOutput.ReadToEnd(); if (config.ShowStandardOutputInLog && output.Trim().Length > 0) { LOG.InfoFormat("Output:\n{0}", output); } } if (config.RedirectStandardError) { error = process.StandardError.ReadToEnd(); if (error.Trim().Length > 0) { LOG.WarnFormat("Error:\n{0}", error); } } LOG.InfoFormat("Finished : {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); return process.ExitCode; } } return -1; } public static string FormatArguments(string arguments, string fullpath) { return string.Format(arguments, fullpath); } } }