mirror of
https://github.com/greenshot/greenshot
synced 2025-07-16 10:03:44 -07:00
Get rid of embedded browser (#255)
This change makes it possible to use Box, DropBox and Imgur with the default browser, instead of the embedded which causes many issues. Other plugins need to follow.
This commit is contained in:
parent
ecb1b91ae7
commit
19fb98ae55
71 changed files with 4037 additions and 3542 deletions
|
@ -65,17 +65,17 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Tokens Include="Box_ClientId">
|
||||
<ReplacementValue>$(Box_ClientId)</ReplacementValue>
|
||||
<Tokens Include="Box13_ClientId">
|
||||
<ReplacementValue>$(Box13_ClientId)</ReplacementValue>
|
||||
</Tokens>
|
||||
<Tokens Include="Box_ClientSecret">
|
||||
<ReplacementValue>$(Box_ClientSecret)</ReplacementValue>
|
||||
<Tokens Include="Box13_ClientSecret">
|
||||
<ReplacementValue>$(Box13_ClientSecret)</ReplacementValue>
|
||||
</Tokens>
|
||||
<Tokens Include="DropBox_ClientId">
|
||||
<ReplacementValue>$(DropBox_ClientId)</ReplacementValue>
|
||||
<Tokens Include="DropBox13_ClientId">
|
||||
<ReplacementValue>$(DropBox13_ClientId)</ReplacementValue>
|
||||
</Tokens>
|
||||
<Tokens Include="DropBox_ClientSecret">
|
||||
<ReplacementValue>$(DropBox_ClientSecret)</ReplacementValue>
|
||||
<Tokens Include="DropBox13_ClientSecret">
|
||||
<ReplacementValue>$(DropBox13_ClientSecret)</ReplacementValue>
|
||||
</Tokens>
|
||||
<Tokens Include="Flickr_ClientId">
|
||||
<ReplacementValue>$(Flickr_ClientId)</ReplacementValue>
|
||||
|
@ -83,11 +83,11 @@
|
|||
<Tokens Include="Flickr_ClientSecret">
|
||||
<ReplacementValue>$(Flickr_ClientSecret)</ReplacementValue>
|
||||
</Tokens>
|
||||
<Tokens Include="Imgur_ClientId">
|
||||
<ReplacementValue>$(Imgur_ClientId)</ReplacementValue>
|
||||
<Tokens Include="Imgur13_ClientId">
|
||||
<ReplacementValue>$(Imgur13_ClientId)</ReplacementValue>
|
||||
</Tokens>
|
||||
<Tokens Include="Imgur_ClientSecret">
|
||||
<ReplacementValue>$(Imgur_ClientSecret)</ReplacementValue>
|
||||
<Tokens Include="Imgur13_ClientSecret">
|
||||
<ReplacementValue>$(Imgur13_ClientSecret)</ReplacementValue>
|
||||
</Tokens>
|
||||
<Tokens Include="Photobucket_ClientId">
|
||||
<ReplacementValue>$(Photobucket_ClientId)</ReplacementValue>
|
||||
|
|
|
@ -34,7 +34,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotDropboxPlugin", "G
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotFlickrPlugin", "GreenshotFlickrPlugin\GreenshotFlickrPlugin.csproj", "{7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotPicasaPlugin", "GreenshotPicasaPlugin\GreenshotPicasaPlugin.csproj", "{1893A2E4-A78A-4713-A8E7-E70058DABEE0}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotGooglePhotosPlugin", "GreenshotGooglePhotosPlugin\GreenshotGooglePhotosPlugin.csproj", "{1893A2E4-A78A-4713-A8E7-E70058DABEE0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotOfficePlugin", "GreenshotOfficePlugin\GreenshotOfficePlugin.csproj", "{92599C09-FF29-4ABD-B6E6-C48ECD781BAB}"
|
||||
EndProject
|
||||
|
|
|
@ -105,10 +105,6 @@ namespace Greenshot.Drawing {
|
|||
cursor.DrawStretched(graphics, Bounds);
|
||||
}
|
||||
|
||||
public override Size DefaultSize {
|
||||
get {
|
||||
return cursor.Size;
|
||||
}
|
||||
}
|
||||
public override Size DefaultSize => cursor?.Size ?? new Size(16, 16);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -548,23 +548,11 @@ namespace Greenshot.Drawing
|
|||
return ScaleHelper.ShapeAngleRoundBehavior.Instance;
|
||||
}
|
||||
|
||||
public virtual bool HasContextMenu {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public virtual bool HasContextMenu => true;
|
||||
|
||||
public virtual bool HasDefaultSize {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public virtual bool HasDefaultSize => false;
|
||||
|
||||
public virtual Size DefaultSize {
|
||||
get {
|
||||
throw new NotSupportedException("Object doesn't have a default size");
|
||||
}
|
||||
}
|
||||
public virtual Size DefaultSize => throw new NotSupportedException("Object doesn't have a default size");
|
||||
|
||||
/// <summary>
|
||||
/// Allows to override the initializing of the fields, so we can actually have our own defaults
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace Greenshot.Drawing {
|
|||
Width = value.Width;
|
||||
Height = value.Height;
|
||||
}
|
||||
get { return icon; }
|
||||
get => icon;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,27 +78,32 @@ namespace Greenshot.Drawing {
|
|||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public void Load(string filename) {
|
||||
if (File.Exists(filename))
|
||||
{
|
||||
using Icon fileIcon = new Icon(filename);
|
||||
Icon = fileIcon;
|
||||
Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width);
|
||||
}
|
||||
public void Load(string filename)
|
||||
{
|
||||
if (!File.Exists(filename))
|
||||
{
|
||||
return;
|
||||
}
|
||||
using Icon fileIcon = new Icon(filename);
|
||||
Icon = fileIcon;
|
||||
Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width);
|
||||
}
|
||||
|
||||
public override void Draw(Graphics graphics, RenderMode rm) {
|
||||
if (icon != null) {
|
||||
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
|
||||
graphics.CompositingQuality = CompositingQuality.Default;
|
||||
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
graphics.DrawIcon(icon, Bounds);
|
||||
public override void Draw(Graphics graphics, RenderMode rm)
|
||||
{
|
||||
if (icon == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
|
||||
graphics.CompositingQuality = CompositingQuality.Default;
|
||||
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
graphics.DrawIcon(icon, Bounds);
|
||||
}
|
||||
|
||||
public override bool HasDefaultSize => true;
|
||||
|
||||
public override Size DefaultSize => icon.Size;
|
||||
public override Size DefaultSize => icon?.Size ?? new Size(16,16);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,11 +77,14 @@ namespace Greenshot.Drawing {
|
|||
AddField(GetType(), FieldType.SHADOW, false);
|
||||
}
|
||||
|
||||
protected void BitmapContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) {
|
||||
if (sender.Equals(this)) {
|
||||
if (FieldType.SHADOW.Equals(e.Field.FieldType)) {
|
||||
ChangeShadowField();
|
||||
}
|
||||
protected void BitmapContainer_OnFieldChanged(object sender, FieldChangedEventArgs e)
|
||||
{
|
||||
if (!sender.Equals(this))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (FieldType.SHADOW.Equals(e.Field.FieldType)) {
|
||||
ChangeShadowField();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,12 +192,14 @@ namespace Greenshot.Drawing {
|
|||
/// This checks if a shadow is already generated
|
||||
/// </summary>
|
||||
/// <param name="shadow"></param>
|
||||
private void CheckShadow(bool shadow) {
|
||||
if (shadow && _shadowBitmap == null)
|
||||
{
|
||||
using var matrix = new Matrix();
|
||||
_shadowBitmap = ImageHelper.ApplyEffect(image, new DropShadowEffect(), matrix);
|
||||
}
|
||||
private void CheckShadow(bool shadow)
|
||||
{
|
||||
if (!shadow || _shadowBitmap != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
using var matrix = new Matrix();
|
||||
_shadowBitmap = ImageHelper.ApplyEffect(image, new DropShadowEffect(), matrix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -202,25 +207,28 @@ namespace Greenshot.Drawing {
|
|||
/// </summary>
|
||||
/// <param name="graphics"></param>
|
||||
/// <param name="rm"></param>
|
||||
public override void Draw(Graphics graphics, RenderMode rm) {
|
||||
if (image != null) {
|
||||
bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
|
||||
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
graphics.CompositingQuality = CompositingQuality.HighQuality;
|
||||
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
public override void Draw(Graphics graphics, RenderMode rm)
|
||||
{
|
||||
if (image == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
|
||||
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
graphics.CompositingQuality = CompositingQuality.HighQuality;
|
||||
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
|
||||
if (shadow) {
|
||||
CheckShadow(true);
|
||||
graphics.DrawImage(_shadowBitmap, Bounds);
|
||||
} else {
|
||||
graphics.DrawImage(image, Bounds);
|
||||
}
|
||||
if (shadow) {
|
||||
CheckShadow(true);
|
||||
graphics.DrawImage(_shadowBitmap, Bounds);
|
||||
} else {
|
||||
graphics.DrawImage(image, Bounds);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool HasDefaultSize => true;
|
||||
|
||||
public override Size DefaultSize => image.Size;
|
||||
public override Size DefaultSize => image?.Size ?? new Size(32, 32);
|
||||
}
|
||||
}
|
||||
|
|
1
Greenshot/Forms/AboutForm.Designer.cs
generated
1
Greenshot/Forms/AboutForm.Designer.cs
generated
|
@ -21,6 +21,7 @@
|
|||
|
||||
using System.Windows.Forms;
|
||||
using Greenshot.Helpers;
|
||||
using GreenshotPlugin.Core;
|
||||
|
||||
namespace Greenshot.Forms {
|
||||
partial class AboutForm {
|
||||
|
|
|
@ -1,786 +0,0 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using GreenshotPlugin.Core;
|
||||
using GreenshotPlugin.IniFile;
|
||||
using GreenshotPlugin.UnmanagedHelpers;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Greenshot.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of EnvironmentInfo.
|
||||
/// </summary>
|
||||
public static class EnvironmentInfo
|
||||
{
|
||||
private static bool? _isWindows;
|
||||
|
||||
public static bool IsWindows
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_isWindows.HasValue)
|
||||
{
|
||||
return _isWindows.Value;
|
||||
}
|
||||
_isWindows = Environment.OSVersion.Platform.ToString().StartsWith("Win");
|
||||
return _isWindows.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsNet45OrNewer()
|
||||
{
|
||||
// Class "ReflectionContext" exists from .NET 4.5 onwards.
|
||||
return Type.GetType("System.Reflection.ReflectionContext", false) != null;
|
||||
}
|
||||
|
||||
public static string GetGreenshotVersion(bool shortVersion = false)
|
||||
{
|
||||
var executingAssembly = Assembly.GetExecutingAssembly();
|
||||
|
||||
// Use assembly version
|
||||
string greenshotVersion = executingAssembly.GetName().Version.ToString();
|
||||
|
||||
// Use AssemblyFileVersion if available
|
||||
var assemblyFileVersionAttribute = executingAssembly.GetCustomAttribute<AssemblyFileVersionAttribute>();
|
||||
if (!string.IsNullOrEmpty(assemblyFileVersionAttribute?.Version))
|
||||
{
|
||||
var assemblyFileVersion = new Version(assemblyFileVersionAttribute.Version);
|
||||
greenshotVersion = assemblyFileVersion.ToString(3);
|
||||
}
|
||||
|
||||
if (!shortVersion)
|
||||
{
|
||||
// Use AssemblyInformationalVersion if available
|
||||
var informationalVersionAttribute = executingAssembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
|
||||
if (!string.IsNullOrEmpty(informationalVersionAttribute?.InformationalVersion))
|
||||
{
|
||||
greenshotVersion = informationalVersionAttribute.InformationalVersion;
|
||||
}
|
||||
}
|
||||
|
||||
return greenshotVersion.Replace("+", " - ");
|
||||
}
|
||||
|
||||
public static string EnvironmentToString(bool newline)
|
||||
{
|
||||
StringBuilder environment = new StringBuilder();
|
||||
environment.Append("Software version: " + GetGreenshotVersion());
|
||||
if (IniConfig.IsPortable) {
|
||||
environment.Append(" Portable");
|
||||
}
|
||||
environment.Append(" (" + OsInfo.Bits + " bit)");
|
||||
|
||||
if (newline)
|
||||
{
|
||||
environment.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
environment.Append(", ");
|
||||
}
|
||||
environment.Append(".NET runtime version: " + Environment.Version);
|
||||
if (IsNet45OrNewer())
|
||||
{
|
||||
environment.Append("+");
|
||||
|
||||
}
|
||||
if (newline)
|
||||
{
|
||||
environment.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
environment.Append(", ");
|
||||
}
|
||||
environment.Append("Time: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss zzz"));
|
||||
|
||||
if (IsWindows)
|
||||
{
|
||||
if (newline)
|
||||
{
|
||||
environment.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
environment.Append(", ");
|
||||
}
|
||||
|
||||
environment.Append($"OS: {OsInfo.Name}");
|
||||
if (!string.IsNullOrEmpty(OsInfo.Edition))
|
||||
{
|
||||
environment.Append($" {OsInfo.Edition}");
|
||||
|
||||
}
|
||||
if (!string.IsNullOrEmpty(OsInfo.ServicePack))
|
||||
{
|
||||
environment.Append($" {OsInfo.ServicePack}");
|
||||
|
||||
}
|
||||
environment.Append($" x{OsInfo.Bits}");
|
||||
environment.Append($" {OsInfo.VersionString}");
|
||||
if (newline)
|
||||
{
|
||||
environment.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
environment.Append(", ");
|
||||
}
|
||||
// Get some important information for fixing GDI related Problems
|
||||
environment.AppendFormat("GDI object count: {0}", User32.GetGuiResourcesGDICount());
|
||||
if (newline)
|
||||
{
|
||||
environment.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
environment.Append(", ");
|
||||
}
|
||||
environment.AppendFormat("User object count: {0}", User32.GetGuiResourcesUserCount());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newline)
|
||||
{
|
||||
environment.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
environment.Append(", ");
|
||||
}
|
||||
environment.AppendFormat("OS: {0}", Environment.OSVersion.Platform);
|
||||
}
|
||||
if (newline)
|
||||
{
|
||||
environment.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
environment.Append(", ");
|
||||
}
|
||||
// TODO: Is this needed?
|
||||
// environment.AppendFormat("Surface count: {0}", Surface.Count);
|
||||
|
||||
return environment.ToString();
|
||||
}
|
||||
|
||||
public static string ExceptionToString(Exception ex)
|
||||
{
|
||||
if (ex == null)
|
||||
return "null\r\n";
|
||||
|
||||
StringBuilder report = new StringBuilder();
|
||||
|
||||
report.AppendLine("Exception: " + ex.GetType());
|
||||
report.AppendLine("Message: " + ex.Message);
|
||||
if (ex.Data.Count > 0)
|
||||
{
|
||||
report.AppendLine();
|
||||
report.AppendLine("Additional Information:");
|
||||
foreach (object key in ex.Data.Keys)
|
||||
{
|
||||
object data = ex.Data[key];
|
||||
if (data != null)
|
||||
{
|
||||
report.AppendLine(key + " : " + data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ex is ExternalException externalException)
|
||||
{
|
||||
// e.g. COMException
|
||||
report.AppendLine().AppendLine("ErrorCode: 0x" + externalException.ErrorCode.ToString("X"));
|
||||
}
|
||||
|
||||
report.AppendLine().AppendLine("Stack:").AppendLine(ex.StackTrace);
|
||||
|
||||
if (ex is ReflectionTypeLoadException reflectionTypeLoadException)
|
||||
{
|
||||
report.AppendLine().AppendLine("LoaderExceptions: ");
|
||||
foreach (Exception cbE in reflectionTypeLoadException.LoaderExceptions)
|
||||
{
|
||||
report.AppendLine(cbE.Message);
|
||||
}
|
||||
}
|
||||
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
report.AppendLine("--- InnerException: ---");
|
||||
report.AppendLine(ExceptionToString(ex.InnerException));
|
||||
}
|
||||
return report.ToString();
|
||||
}
|
||||
|
||||
public static string BuildReport(Exception exception)
|
||||
{
|
||||
StringBuilder exceptionText = new StringBuilder();
|
||||
exceptionText.AppendLine(EnvironmentToString(true));
|
||||
exceptionText.AppendLine(ExceptionToString(exception));
|
||||
exceptionText.AppendLine("Configuration dump:");
|
||||
|
||||
return exceptionText.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides detailed information about the host operating system.
|
||||
/// Code is available at: http://www.csharp411.com/determine-windows-version-and-edition-with-c/
|
||||
/// </summary>
|
||||
public static class OsInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines if the current application is 32 or 64-bit.
|
||||
/// </summary>
|
||||
public static int Bits => IntPtr.Size * 8;
|
||||
|
||||
private static string _sEdition;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the edition of the operating system running on this computer.
|
||||
/// </summary>
|
||||
public static string Edition
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_sEdition != null)
|
||||
{
|
||||
return _sEdition; //***** RETURN *****//
|
||||
}
|
||||
|
||||
string edition = string.Empty;
|
||||
|
||||
OperatingSystem osVersion = Environment.OSVersion;
|
||||
OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create();
|
||||
|
||||
if (GetVersionEx(ref osVersionInfo))
|
||||
{
|
||||
int majorVersion = osVersion.Version.Major;
|
||||
int minorVersion = osVersion.Version.Minor;
|
||||
byte productType = osVersionInfo.ProductType;
|
||||
ushort suiteMask = osVersionInfo.SuiteMask;
|
||||
|
||||
if (majorVersion == 4)
|
||||
{
|
||||
if (productType == VER_NT_WORKSTATION)
|
||||
{
|
||||
// Windows NT 4.0 Workstation
|
||||
edition = "Workstation";
|
||||
}
|
||||
else if (productType == VER_NT_SERVER)
|
||||
{
|
||||
edition = (suiteMask & VER_SUITE_ENTERPRISE) != 0 ? "Enterprise Server" : "Standard Server";
|
||||
}
|
||||
}
|
||||
|
||||
else if (majorVersion == 5)
|
||||
{
|
||||
if (productType == VER_NT_WORKSTATION)
|
||||
{
|
||||
if ((suiteMask & VER_SUITE_PERSONAL) != 0)
|
||||
{
|
||||
// Windows XP Home Edition
|
||||
edition = "Home";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Windows XP / Windows 2000 Professional
|
||||
edition = "Professional";
|
||||
}
|
||||
}
|
||||
else if (productType == VER_NT_SERVER)
|
||||
{
|
||||
if (minorVersion == 0)
|
||||
{
|
||||
if ((suiteMask & VER_SUITE_DATACENTER) != 0)
|
||||
{
|
||||
// Windows 2000 Datacenter Server
|
||||
edition = "Datacenter Server";
|
||||
}
|
||||
else if ((suiteMask & VER_SUITE_ENTERPRISE) != 0)
|
||||
{
|
||||
// Windows 2000 Advanced Server
|
||||
edition = "Advanced Server";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Windows 2000 Server
|
||||
edition = "Server";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((suiteMask & VER_SUITE_DATACENTER) != 0)
|
||||
{
|
||||
// Windows Server 2003 Datacenter Edition
|
||||
edition = "Datacenter";
|
||||
}
|
||||
else if ((suiteMask & VER_SUITE_ENTERPRISE) != 0)
|
||||
{
|
||||
// Windows Server 2003 Enterprise Edition
|
||||
edition = "Enterprise";
|
||||
}
|
||||
else if ((suiteMask & VER_SUITE_BLADE) != 0)
|
||||
{
|
||||
// Windows Server 2003 Web Edition
|
||||
edition = "Web Edition";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Windows Server 2003 Standard Edition
|
||||
edition = "Standard";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (majorVersion == 6)
|
||||
{
|
||||
if (GetProductInfo(majorVersion, minorVersion, osVersionInfo.ServicePackMajor, osVersionInfo.ServicePackMinor, out var ed))
|
||||
{
|
||||
switch (ed)
|
||||
{
|
||||
case PRODUCT_BUSINESS:
|
||||
edition = "Business";
|
||||
break;
|
||||
case PRODUCT_BUSINESS_N:
|
||||
edition = "Business N";
|
||||
break;
|
||||
case PRODUCT_CLUSTER_SERVER:
|
||||
edition = "HPC Edition";
|
||||
break;
|
||||
case PRODUCT_DATACENTER_SERVER:
|
||||
edition = "Datacenter Server";
|
||||
break;
|
||||
case PRODUCT_DATACENTER_SERVER_CORE:
|
||||
edition = "Datacenter Server (core installation)";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE:
|
||||
edition = "Enterprise";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_N:
|
||||
edition = "Enterprise N";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER:
|
||||
edition = "Enterprise Server";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_CORE:
|
||||
edition = "Enterprise Server (core installation)";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_CORE_V:
|
||||
edition = "Enterprise Server without Hyper-V (core installation)";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_IA64:
|
||||
edition = "Enterprise Server for Itanium-based Systems";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_V:
|
||||
edition = "Enterprise Server without Hyper-V";
|
||||
break;
|
||||
case PRODUCT_HOME_BASIC:
|
||||
edition = "Home Basic";
|
||||
break;
|
||||
case PRODUCT_HOME_BASIC_N:
|
||||
edition = "Home Basic N";
|
||||
break;
|
||||
case PRODUCT_HOME_PREMIUM:
|
||||
edition = "Home Premium";
|
||||
break;
|
||||
case PRODUCT_HOME_PREMIUM_N:
|
||||
edition = "Home Premium N";
|
||||
break;
|
||||
case PRODUCT_HYPERV:
|
||||
edition = "Microsoft Hyper-V Server";
|
||||
break;
|
||||
case PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT:
|
||||
edition = "Windows Essential Business Management Server";
|
||||
break;
|
||||
case PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING:
|
||||
edition = "Windows Essential Business Messaging Server";
|
||||
break;
|
||||
case PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY:
|
||||
edition = "Windows Essential Business Security Server";
|
||||
break;
|
||||
case PRODUCT_SERVER_FOR_SMALLBUSINESS:
|
||||
edition = "Windows Essential Server Solutions";
|
||||
break;
|
||||
case PRODUCT_SERVER_FOR_SMALLBUSINESS_V:
|
||||
edition = "Windows Essential Server Solutions without Hyper-V";
|
||||
break;
|
||||
case PRODUCT_SMALLBUSINESS_SERVER:
|
||||
edition = "Windows Small Business Server";
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER:
|
||||
edition = "Standard Server";
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER_CORE:
|
||||
edition = "Standard Server (core installation)";
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER_CORE_V:
|
||||
edition = "Standard Server without Hyper-V (core installation)";
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER_V:
|
||||
edition = "Standard Server without Hyper-V";
|
||||
break;
|
||||
case PRODUCT_STARTER:
|
||||
edition = "Starter";
|
||||
break;
|
||||
case PRODUCT_STORAGE_ENTERPRISE_SERVER:
|
||||
edition = "Enterprise Storage Server";
|
||||
break;
|
||||
case PRODUCT_STORAGE_EXPRESS_SERVER:
|
||||
edition = "Express Storage Server";
|
||||
break;
|
||||
case PRODUCT_STORAGE_STANDARD_SERVER:
|
||||
edition = "Standard Storage Server";
|
||||
break;
|
||||
case PRODUCT_STORAGE_WORKGROUP_SERVER:
|
||||
edition = "Workgroup Storage Server";
|
||||
break;
|
||||
case PRODUCT_UNDEFINED:
|
||||
edition = "Unknown product";
|
||||
break;
|
||||
case PRODUCT_ULTIMATE:
|
||||
edition = "Ultimate";
|
||||
break;
|
||||
case PRODUCT_ULTIMATE_N:
|
||||
edition = "Ultimate N";
|
||||
break;
|
||||
case PRODUCT_WEB_SERVER:
|
||||
edition = "Web Server";
|
||||
break;
|
||||
case PRODUCT_WEB_SERVER_CORE:
|
||||
edition = "Web Server (core installation)";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_sEdition = edition;
|
||||
return edition;
|
||||
}
|
||||
}
|
||||
|
||||
private static string _name;
|
||||
/// <summary>
|
||||
/// Gets the name of the operating system running on this computer.
|
||||
/// </summary>
|
||||
public static string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_name != null)
|
||||
{
|
||||
return _name; //***** RETURN *****//
|
||||
}
|
||||
|
||||
string name = "unknown";
|
||||
|
||||
OperatingSystem osVersion = Environment.OSVersion;
|
||||
OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create();
|
||||
if (GetVersionEx(ref osVersionInfo))
|
||||
{
|
||||
int majorVersion = osVersion.Version.Major;
|
||||
int minorVersion = osVersion.Version.Minor;
|
||||
byte productType = osVersionInfo.ProductType;
|
||||
ushort suiteMask = osVersionInfo.SuiteMask;
|
||||
switch (osVersion.Platform)
|
||||
{
|
||||
case PlatformID.Win32Windows:
|
||||
if (majorVersion == 4)
|
||||
{
|
||||
string csdVersion = osVersionInfo.ServicePackVersion;
|
||||
switch (minorVersion)
|
||||
{
|
||||
case 0:
|
||||
if (csdVersion == "B" || csdVersion == "C")
|
||||
{
|
||||
name = "Windows 95 OSR2";
|
||||
}
|
||||
else
|
||||
{
|
||||
name = "Windows 95";
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
name = csdVersion == "A" ? "Windows 98 Second Edition" : "Windows 98";
|
||||
break;
|
||||
case 90:
|
||||
name = "Windows Me";
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PlatformID.Win32NT:
|
||||
switch (majorVersion)
|
||||
{
|
||||
case 3:
|
||||
name = "Windows NT 3.51";
|
||||
break;
|
||||
case 4:
|
||||
switch (productType)
|
||||
{
|
||||
case 1:
|
||||
name = "Windows NT 4.0";
|
||||
break;
|
||||
case 3:
|
||||
name = "Windows NT 4.0 Server";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
switch (minorVersion)
|
||||
{
|
||||
case 0:
|
||||
name = "Windows 2000";
|
||||
break;
|
||||
case 1:
|
||||
name = suiteMask switch
|
||||
{
|
||||
0x0200 => "Windows XP Professional",
|
||||
_ => "Windows XP"
|
||||
};
|
||||
break;
|
||||
case 2:
|
||||
name = suiteMask switch
|
||||
{
|
||||
0x0200 => "Windows XP Professional x64",
|
||||
0x0002 => "Windows Server 2003 Enterprise",
|
||||
0x0080 => "Windows Server 2003 Data Center",
|
||||
0x0400 => "Windows Server 2003 Web Edition",
|
||||
0x8000 => "Windows Home Server",
|
||||
_ => "Windows Server 2003"
|
||||
};
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
switch (minorVersion)
|
||||
{
|
||||
case 0:
|
||||
name = productType switch
|
||||
{
|
||||
3 => "Windows Server 2008",
|
||||
_ => "Windows Vista"
|
||||
};
|
||||
break;
|
||||
case 1:
|
||||
name = productType switch
|
||||
{
|
||||
3 => "Windows Server 2008 R2",
|
||||
_ => "Windows 7"
|
||||
};
|
||||
break;
|
||||
case 2:
|
||||
name = "Windows 8";
|
||||
break;
|
||||
case 3:
|
||||
name = "Windows 8.1";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
string releaseId = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ReleaseId", "").ToString();
|
||||
name = $"Windows 10 {releaseId}";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_name = name;
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("Kernel32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool GetProductInfo(
|
||||
int osMajorVersion,
|
||||
int osMinorVersion,
|
||||
int spMajorVersion,
|
||||
int spMinorVersion,
|
||||
out int edition);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool GetVersionEx(ref OSVERSIONINFOEX osVersionInfo);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
private unsafe struct OSVERSIONINFOEX
|
||||
{
|
||||
/// <summary>
|
||||
/// The size of this data structure, in bytes. Set this member to sizeof(OSVERSIONINFOEX).
|
||||
/// </summary>
|
||||
private int _dwOSVersionInfoSize;
|
||||
|
||||
private readonly int _dwMajorVersion;
|
||||
private readonly int _dwMinorVersion;
|
||||
private readonly int _dwBuildNumber;
|
||||
private readonly int _dwPlatformId;
|
||||
private fixed char _szCSDVersion[128];
|
||||
private readonly short _wServicePackMajor;
|
||||
private readonly short _wServicePackMinor;
|
||||
private readonly ushort _wSuiteMask;
|
||||
private readonly byte _wProductType;
|
||||
private readonly byte _wReserved;
|
||||
|
||||
/// <summary>
|
||||
/// A null-terminated string, such as "Service Pack 3", that indicates the latest Service Pack installed on the system.
|
||||
/// If no Service Pack has been installed, the string is empty.
|
||||
/// </summary>
|
||||
public string ServicePackVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (char* servicePackVersion = _szCSDVersion)
|
||||
{
|
||||
return new string(servicePackVersion);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The major version number of the latest Service Pack installed on the system. For example, for Service Pack 3, the
|
||||
/// major version number is 3.
|
||||
/// If no Service Pack has been installed, the value is zero.
|
||||
/// </summary>
|
||||
public short ServicePackMajor => _wServicePackMajor;
|
||||
|
||||
/// <summary>
|
||||
/// The minor version number of the latest Service Pack installed on the system. For example, for Service Pack 3, the
|
||||
/// minor version number is 0.
|
||||
/// </summary>
|
||||
public short ServicePackMinor => _wServicePackMinor;
|
||||
|
||||
/// <summary>
|
||||
/// A bit mask that identifies the product suites available on the system. This member can be a combination of the
|
||||
/// following values.
|
||||
/// </summary>
|
||||
public ushort SuiteMask => _wSuiteMask;
|
||||
|
||||
/// <summary>
|
||||
/// Any additional information about the system.
|
||||
/// </summary>
|
||||
public byte ProductType => _wProductType;
|
||||
|
||||
/// <summary>
|
||||
/// Factory for an empty OsVersionInfoEx
|
||||
/// </summary>
|
||||
/// <returns>OSVERSIONINFOEX</returns>
|
||||
public static OSVERSIONINFOEX Create()
|
||||
{
|
||||
return new OSVERSIONINFOEX
|
||||
{
|
||||
_dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEX))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private const int PRODUCT_UNDEFINED = 0x00000000;
|
||||
private const int PRODUCT_ULTIMATE = 0x00000001;
|
||||
private const int PRODUCT_HOME_BASIC = 0x00000002;
|
||||
private const int PRODUCT_HOME_PREMIUM = 0x00000003;
|
||||
private const int PRODUCT_ENTERPRISE = 0x00000004;
|
||||
private const int PRODUCT_HOME_BASIC_N = 0x00000005;
|
||||
private const int PRODUCT_BUSINESS = 0x00000006;
|
||||
private const int PRODUCT_STANDARD_SERVER = 0x00000007;
|
||||
private const int PRODUCT_DATACENTER_SERVER = 0x00000008;
|
||||
private const int PRODUCT_SMALLBUSINESS_SERVER = 0x00000009;
|
||||
private const int PRODUCT_ENTERPRISE_SERVER = 0x0000000A;
|
||||
private const int PRODUCT_STARTER = 0x0000000B;
|
||||
private const int PRODUCT_DATACENTER_SERVER_CORE = 0x0000000C;
|
||||
private const int PRODUCT_STANDARD_SERVER_CORE = 0x0000000D;
|
||||
private const int PRODUCT_ENTERPRISE_SERVER_CORE = 0x0000000E;
|
||||
private const int PRODUCT_ENTERPRISE_SERVER_IA64 = 0x0000000F;
|
||||
private const int PRODUCT_BUSINESS_N = 0x00000010;
|
||||
private const int PRODUCT_WEB_SERVER = 0x00000011;
|
||||
private const int PRODUCT_CLUSTER_SERVER = 0x00000012;
|
||||
private const int PRODUCT_STORAGE_EXPRESS_SERVER = 0x00000014;
|
||||
private const int PRODUCT_STORAGE_STANDARD_SERVER = 0x00000015;
|
||||
private const int PRODUCT_STORAGE_WORKGROUP_SERVER = 0x00000016;
|
||||
private const int PRODUCT_STORAGE_ENTERPRISE_SERVER = 0x00000017;
|
||||
private const int PRODUCT_SERVER_FOR_SMALLBUSINESS = 0x00000018;
|
||||
private const int PRODUCT_HOME_PREMIUM_N = 0x0000001A;
|
||||
private const int PRODUCT_ENTERPRISE_N = 0x0000001B;
|
||||
private const int PRODUCT_ULTIMATE_N = 0x0000001C;
|
||||
private const int PRODUCT_WEB_SERVER_CORE = 0x0000001D;
|
||||
private const int PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E;
|
||||
private const int PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F;
|
||||
private const int PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020;
|
||||
private const int PRODUCT_SERVER_FOR_SMALLBUSINESS_V = 0x00000023;
|
||||
private const int PRODUCT_STANDARD_SERVER_V = 0x00000024;
|
||||
private const int PRODUCT_ENTERPRISE_SERVER_V = 0x00000026;
|
||||
private const int PRODUCT_STANDARD_SERVER_CORE_V = 0x00000028;
|
||||
private const int PRODUCT_ENTERPRISE_SERVER_CORE_V = 0x00000029;
|
||||
private const int PRODUCT_HYPERV = 0x0000002A;
|
||||
|
||||
private const int VER_NT_WORKSTATION = 1;
|
||||
private const int VER_NT_SERVER = 3;
|
||||
private const int VER_SUITE_ENTERPRISE = 2;
|
||||
private const int VER_SUITE_DATACENTER = 128;
|
||||
private const int VER_SUITE_PERSONAL = 512;
|
||||
private const int VER_SUITE_BLADE = 1024;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the service pack information of the operating system running on this computer.
|
||||
/// </summary>
|
||||
public static string ServicePack
|
||||
{
|
||||
get
|
||||
{
|
||||
string servicePack = string.Empty;
|
||||
OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create();
|
||||
|
||||
if (GetVersionEx(ref osVersionInfo))
|
||||
{
|
||||
servicePack = osVersionInfo.ServicePackVersion;
|
||||
}
|
||||
|
||||
return servicePack;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full version string of the operating system running on this computer.
|
||||
/// </summary>
|
||||
public static string VersionString
|
||||
{
|
||||
get
|
||||
{
|
||||
if (WindowsVersion.IsWindows10OrLater)
|
||||
{
|
||||
return $"build {Environment.OSVersion.Version.Build}";
|
||||
}
|
||||
if (Environment.OSVersion.Version.Revision != 0)
|
||||
{
|
||||
return $"{Environment.OSVersion.Version.Major}.{Environment.OSVersion.Version.Minor} build {Environment.OSVersion.Version.Build} revision {Environment.OSVersion.Version.Revision:X}";
|
||||
}
|
||||
return $"{Environment.OSVersion.Version.Major}.{Environment.OSVersion.Version.Minor} build {Environment.OSVersion.Version.Build}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -99,8 +99,8 @@ Source: {#BaseDir}\GreenshotFlickrPlugin\Languages\language_flickr*.xml; DestDir
|
|||
Source: {#BaseDir}\GreenshotPhotobucketPlugin\{#BinDir}\GreenshotPhotobucketPlugin.dll; DestDir: {app}\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#BaseDir}\GreenshotPhotobucketPlugin\Languages\language_photo*.xml; DestDir: {app}\Languages\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly ignoreversion replacesameversion;
|
||||
;Picasa Plugin
|
||||
Source: {#BaseDir}\GreenshotPicasaPlugin\{#BinDir}\GreenshotPicasaPlugin.dll; DestDir: {app}\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#BaseDir}\GreenshotPicasaPlugin\Languages\language_picasa*.xml; DestDir: {app}\Languages\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly ignoreversion replacesameversion;
|
||||
;Source: {#BaseDir}\GreenshotPicasaPlugin\{#BinDir}\GreenshotPicasaPlugin.dll; DestDir: {app}\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
;Source: {#BaseDir}\GreenshotPicasaPlugin\Languages\language_picasa*.xml; DestDir: {app}\Languages\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly ignoreversion replacesameversion;
|
||||
;Confluence Plugin
|
||||
Source: {#BaseDir}\GreenshotConfluencePlugin\{#BinDir}\GreenshotConfluencePlugin.dll; DestDir: {app}\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#BaseDir}\GreenshotConfluencePlugin\Languages\language_confluence*.xml; DestDir: {app}\Languages\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly ignoreversion replacesameversion;
|
||||
|
@ -491,7 +491,7 @@ Name: "plugins\imgur"; Description: {cm:imgur}; Types: default full custom; Flag
|
|||
Name: "plugins\jira"; Description: {cm:jira}; Types: full custom; Flags: disablenouninstallwarning
|
||||
Name: "plugins\office"; Description: {cm:office}; Types: default full custom; Flags: disablenouninstallwarning
|
||||
Name: "plugins\photobucket"; Description: {cm:photobucket}; Types: full custom; Flags: disablenouninstallwarning
|
||||
Name: "plugins\picasa"; Description: {cm:picasa}; Types: full custom; Flags: disablenouninstallwarning
|
||||
;Name: "plugins\picasa"; Description: {cm:picasa}; Types: full custom; Flags: disablenouninstallwarning
|
||||
Name: "plugins\win10"; Description: {cm:win10}; Types: default full custom; Flags: disablenouninstallwarning; Check: IsWindows10OrNewer()
|
||||
Name: "languages"; Description: {cm:language}; Types: full custom; Flags: disablenouninstallwarning
|
||||
Name: "languages\arSY"; Description: {cm:arSY}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d')
|
||||
|
|
|
@ -30,17 +30,9 @@ namespace GreenshotBoxPlugin {
|
|||
_plugin = plugin;
|
||||
}
|
||||
|
||||
public override string Designation {
|
||||
get {
|
||||
return "Box";
|
||||
}
|
||||
}
|
||||
public override string Designation => "Box";
|
||||
|
||||
public override string Description {
|
||||
get {
|
||||
return Language.GetString("box", LangKey.upload_menu_item);
|
||||
}
|
||||
}
|
||||
public override string Description => Language.GetString("box", LangKey.upload_menu_item);
|
||||
|
||||
public override Image DisplayIcon {
|
||||
get {
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
|
||||
using GreenshotPlugin.Core;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization.Json;
|
||||
using System.Text;
|
||||
using GreenshotPlugin.Core.OAuth;
|
||||
using GreenshotPlugin.IniFile;
|
||||
|
||||
namespace GreenshotBoxPlugin {
|
||||
|
@ -73,9 +73,8 @@ namespace GreenshotBoxPlugin {
|
|||
CloudServiceName = "Box",
|
||||
ClientId = BoxCredentials.ClientId,
|
||||
ClientSecret = BoxCredentials.ClientSecret,
|
||||
RedirectUrl = "https://www.box.com/home/",
|
||||
BrowserSize = new Size(1060, 600),
|
||||
AuthorizeMode = OAuth2AuthorizeMode.EmbeddedBrowser,
|
||||
RedirectUrl = "https://getgreenshot.org/authorize/box",
|
||||
AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver,
|
||||
RefreshToken = Config.RefreshToken,
|
||||
AccessToken = Config.AccessToken,
|
||||
AccessTokenExpires = Config.AccessTokenExpires
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace GreenshotBoxPlugin {
|
|||
/// You can set your own values here
|
||||
/// </summary>
|
||||
public static class BoxCredentials {
|
||||
public static string ClientId = "${Box_ClientId}";
|
||||
public static string ClientSecret = "${Box_ClientSecret}";
|
||||
public static string ClientId = "${Box13_ClientId}";
|
||||
public static string ClientSecret = "${Box13_ClientSecret}";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* (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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
@ -32,7 +32,7 @@ namespace GreenshotDropboxPlugin {
|
|||
public DropboxDestination(DropboxPlugin plugin) {
|
||||
_plugin = plugin;
|
||||
}
|
||||
|
||||
|
||||
public override string Designation => "Dropbox";
|
||||
|
||||
public override string Description => Language.GetString("dropbox", LangKey.upload_menu_item);
|
||||
|
@ -43,10 +43,10 @@ namespace GreenshotDropboxPlugin {
|
|||
return (Image)resources.GetObject("Dropbox");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override ExportInformation ExportCapture(bool manually, ISurface surface, ICaptureDetails captureDetails) {
|
||||
ExportInformation exportInformation = new ExportInformation(Designation, Description);
|
||||
bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl);
|
||||
bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl);
|
||||
if (uploaded) {
|
||||
exportInformation.Uri = uploadUrl;
|
||||
exportInformation.ExportMade = true;
|
||||
|
|
|
@ -1,27 +1,26 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
|
||||
*
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using GreenshotPlugin.Controls;
|
||||
using GreenshotPlugin.Core;
|
||||
|
@ -45,13 +44,12 @@ namespace GreenshotDropboxPlugin {
|
|||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected void Dispose(bool disposing) {
|
||||
if (disposing) {
|
||||
if (_itemPlugInConfig != null) {
|
||||
_itemPlugInConfig.Dispose();
|
||||
_itemPlugInConfig = null;
|
||||
}
|
||||
}
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposing) return;
|
||||
if (_itemPlugInConfig == null) return;
|
||||
_itemPlugInConfig.Dispose();
|
||||
_itemPlugInConfig = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -102,20 +100,16 @@ namespace GreenshotDropboxPlugin {
|
|||
public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) {
|
||||
uploadUrl = null;
|
||||
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false);
|
||||
try {
|
||||
string dropboxUrl = null;
|
||||
new PleaseWaitForm().ShowAndWait("Dropbox", Language.GetString("dropbox", LangKey.communication_wait),
|
||||
try
|
||||
{
|
||||
bool result = false;
|
||||
new PleaseWaitForm().ShowAndWait("Dropbox", Language.GetString("dropbox", LangKey.communication_wait),
|
||||
delegate
|
||||
{
|
||||
string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails));
|
||||
dropboxUrl = DropboxUtils.UploadToDropbox(surfaceToUpload, outputSettings, filename);
|
||||
result = DropboxUtils.UploadToDropbox(surfaceToUpload, outputSettings, captureDetails);
|
||||
}
|
||||
);
|
||||
if (dropboxUrl == null) {
|
||||
return false;
|
||||
}
|
||||
uploadUrl = dropboxUrl;
|
||||
return true;
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
Log.Error(e);
|
||||
MessageBox.Show(Language.GetString("dropbox", LangKey.upload_failure) + " " + e.Message);
|
||||
|
|
|
@ -1,23 +1,25 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
|
||||
*
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using GreenshotDropboxPlugin.Forms;
|
||||
using GreenshotPlugin.Core;
|
||||
|
@ -39,10 +41,18 @@ namespace GreenshotDropboxPlugin {
|
|||
[IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send Dropbox link to clipboard.", DefaultValue = "true")]
|
||||
public bool AfterUploadLinkToClipBoard { get; set; }
|
||||
|
||||
[IniProperty("DropboxToken", Description = "The Dropbox token", Encrypted = true, ExcludeIfNull = true)]
|
||||
public string DropboxToken { get; set; }
|
||||
[IniProperty("DropboxTokenSecret", Description = "The Dropbox token secret", Encrypted = true, ExcludeIfNull = true)]
|
||||
public string DropboxTokenSecret { get; set; }
|
||||
[IniProperty("RefreshToken", Description = "Dropbox refresh Token", Encrypted = true, ExcludeIfNull = true)]
|
||||
public string RefreshToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// AccessToken, not stored
|
||||
/// </summary>
|
||||
public string AccessToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// AccessTokenExpires, not stored
|
||||
/// </summary>
|
||||
public DateTimeOffset AccessTokenExpires { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A form for token
|
||||
|
|
|
@ -1,30 +1,32 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
|
||||
*
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using GreenshotPlugin.Core;
|
||||
using GreenshotPlugin.Core.OAuth;
|
||||
using GreenshotPlugin.IniFile;
|
||||
using GreenshotPlugin.Interfaces;
|
||||
using GreenshotPlugin.Interfaces.Plugin;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GreenshotDropboxPlugin {
|
||||
/// <summary>
|
||||
|
@ -37,49 +39,54 @@ namespace GreenshotDropboxPlugin {
|
|||
private DropboxUtils() {
|
||||
}
|
||||
|
||||
public static string UploadToDropbox(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string filename) {
|
||||
var oAuth = new OAuthSession(DropBoxCredentials.CONSUMER_KEY, DropBoxCredentials.CONSUMER_SECRET)
|
||||
{
|
||||
BrowserSize = new Size(1080, 650),
|
||||
CheckVerifier = false,
|
||||
AccessTokenUrl = "https://api.dropbox.com/1/oauth/access_token",
|
||||
AuthorizeUrl = "https://api.dropbox.com/1/oauth/authorize",
|
||||
RequestTokenUrl = "https://api.dropbox.com/1/oauth/request_token",
|
||||
LoginTitle = "Dropbox authorization",
|
||||
Token = DropboxConfig.DropboxToken,
|
||||
TokenSecret = DropboxConfig.DropboxTokenSecret
|
||||
public static bool UploadToDropbox(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, ICaptureDetails captureDetails)
|
||||
{
|
||||
var oauth2Settings = new OAuth2Settings
|
||||
{
|
||||
AuthUrlPattern = "https://api.dropbox.com/oauth2/authorize?response_type=token&client_id={ClientId}&state={State}&redirect_uri={RedirectUrl}",
|
||||
TokenUrl = "https://api.dropbox.com/oauth2/token",
|
||||
RedirectUrl = "https://getgreenshot.org/authorize/dropbox",
|
||||
CloudServiceName = "Dropbox",
|
||||
ClientId = DropBoxCredentials.CONSUMER_KEY,
|
||||
ClientSecret = DropBoxCredentials.CONSUMER_SECRET,
|
||||
AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver,
|
||||
RefreshToken = DropboxConfig.RefreshToken,
|
||||
AccessToken = DropboxConfig.AccessToken,
|
||||
AccessTokenExpires = DropboxConfig.AccessTokenExpires
|
||||
};
|
||||
try
|
||||
{
|
||||
string filename = Path.GetFileName(FilenameHelper.GetFilename(DropboxConfig.UploadFormat, captureDetails));
|
||||
SurfaceContainer image = new SurfaceContainer(surfaceToUpload, outputSettings, filename);
|
||||
|
||||
try {
|
||||
SurfaceContainer imageToUpload = new SurfaceContainer(surfaceToUpload, outputSettings, filename);
|
||||
string uploadResponse = oAuth.MakeOAuthRequest(HTTPMethod.POST, "https://api-content.dropbox.com/1/files_put/sandbox/" + OAuthSession.UrlEncode3986(filename), null, null, imageToUpload);
|
||||
Log.DebugFormat("Upload response: {0}", uploadResponse);
|
||||
} catch (Exception ex) {
|
||||
IDictionary<string, object> arguments = new Dictionary<string, object>
|
||||
{
|
||||
{ "autorename", true },
|
||||
{ "mute", true },
|
||||
{ "path", "/" + filename.Replace(Path.DirectorySeparatorChar, '\\')}
|
||||
};
|
||||
IDictionary<string, object> headers = new Dictionary<string, object>
|
||||
{
|
||||
{ "Dropbox-API-Arg", JsonConvert.SerializeObject(arguments)}
|
||||
};
|
||||
var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, "https://content.dropboxapi.com/2/files/upload", oauth2Settings);
|
||||
|
||||
NetworkHelper.Post(webRequest, headers, image);
|
||||
var responseString = NetworkHelper.GetResponseAsString(webRequest);
|
||||
Log.DebugFormat("Upload response: {0}", responseString);
|
||||
var response = JsonConvert.DeserializeObject<IDictionary<string, string>>(responseString);
|
||||
return response.ContainsKey("id");
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.Error("Upload error: ", ex);
|
||||
throw;
|
||||
} finally {
|
||||
if (!string.IsNullOrEmpty(oAuth.Token)) {
|
||||
DropboxConfig.DropboxToken = oAuth.Token;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(oAuth.TokenSecret)) {
|
||||
DropboxConfig.DropboxTokenSecret = oAuth.TokenSecret;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to get a URL to the uploaded image
|
||||
try {
|
||||
string responseString = oAuth.MakeOAuthRequest(HTTPMethod.GET, "https://api.dropbox.com/1/shares/sandbox/" + OAuthSession.UrlEncode3986(filename), null, null, null);
|
||||
if (responseString != null) {
|
||||
Log.DebugFormat("Parsing output: {0}", responseString);
|
||||
IDictionary<string, object> returnValues = JSONHelper.JsonDecode(responseString);
|
||||
if (returnValues.ContainsKey("url")) {
|
||||
return returnValues["url"] as string;
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.Error("Can't parse response.", ex);
|
||||
}
|
||||
return null;
|
||||
DropboxConfig.RefreshToken = oauth2Settings.RefreshToken;
|
||||
DropboxConfig.AccessToken = oauth2Settings.AccessToken;
|
||||
DropboxConfig.AccessTokenExpires = oauth2Settings.AccessTokenExpires;
|
||||
DropboxConfig.IsDirty = true;
|
||||
IniConfig.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace GreenshotDropboxPlugin {
|
|||
/// You can set your own values here
|
||||
/// </summary>
|
||||
public static class DropBoxCredentials {
|
||||
public static string CONSUMER_KEY = "${DropBox_ClientId}";
|
||||
public static string CONSUMER_SECRET = "${DropBox_ClientSecret}";
|
||||
public static string CONSUMER_KEY = "${DropBox13_ClientId}";
|
||||
public static string CONSUMER_SECRET = "${DropBox13_ClientSecret}";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ using System.Collections.Generic;
|
|||
using System.Drawing;
|
||||
using System.Xml;
|
||||
using GreenshotPlugin.Core;
|
||||
using GreenshotPlugin.Core.OAuth;
|
||||
using GreenshotPlugin.IniFile;
|
||||
using GreenshotPlugin.Interfaces;
|
||||
using GreenshotPlugin.Interfaces.Plugin;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* A Picasa Plugin for Greenshot
|
||||
* A GooglePhotos Plugin for Greenshot
|
||||
* Copyright (C) 2011 Francis Noel
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
|
@ -20,7 +20,7 @@
|
|||
|
||||
using GreenshotPlugin.Controls;
|
||||
|
||||
namespace GreenshotPicasaPlugin.Forms {
|
||||
public class PicasaForm : GreenshotForm {
|
||||
namespace GreenshotGooglePhotosPlugin.Forms {
|
||||
public class GooglePhotosForm : GreenshotForm {
|
||||
}
|
||||
}
|
|
@ -1,147 +1,147 @@
|
|||
/*
|
||||
* A Picasa Plugin for Greenshot
|
||||
* Copyright (C) 2011 Francis Noel
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace GreenshotPicasaPlugin.Forms {
|
||||
partial class SettingsForm {
|
||||
/// <summary>
|
||||
/// Designer variable used to keep track of non-visual components.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Disposes resources used by the form.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing) {
|
||||
if (components != null) {
|
||||
components.Dispose();
|
||||
}
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is required for Windows Forms designer support.
|
||||
/// Do not change the method contents inside the source code editor. The Forms designer might
|
||||
/// not be able to load this method if it was changed manually.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton();
|
||||
this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton();
|
||||
this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox();
|
||||
this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel();
|
||||
this.label_AfterUpload = new GreenshotPlugin.Controls.GreenshotLabel();
|
||||
this.checkboxAfterUploadLinkToClipBoard = new GreenshotPlugin.Controls.GreenshotCheckBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// buttonOK
|
||||
//
|
||||
this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.buttonOK.LanguageKey = "OK";
|
||||
this.buttonOK.Location = new System.Drawing.Point(267, 78);
|
||||
this.buttonOK.Name = "buttonOK";
|
||||
this.buttonOK.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonOK.TabIndex = 10;
|
||||
this.buttonOK.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// buttonCancel
|
||||
//
|
||||
this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.buttonCancel.LanguageKey = "CANCEL";
|
||||
this.buttonCancel.Location = new System.Drawing.Point(348, 78);
|
||||
this.buttonCancel.Name = "buttonCancel";
|
||||
this.buttonCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonCancel.TabIndex = 11;
|
||||
this.buttonCancel.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// combobox_uploadimageformat
|
||||
//
|
||||
this.combobox_uploadimageformat.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.combobox_uploadimageformat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.combobox_uploadimageformat.FormattingEnabled = true;
|
||||
this.combobox_uploadimageformat.Location = new System.Drawing.Point(197, 12);
|
||||
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat";
|
||||
this.combobox_uploadimageformat.PropertyName = "UploadFormat";
|
||||
this.combobox_uploadimageformat.SectionName = "Picasa";
|
||||
this.combobox_uploadimageformat.Size = new System.Drawing.Size(225, 21);
|
||||
this.combobox_uploadimageformat.TabIndex = 1;
|
||||
//
|
||||
// label_upload_format
|
||||
//
|
||||
this.label_upload_format.LanguageKey = "picasa.label_upload_format";
|
||||
this.label_upload_format.Location = new System.Drawing.Point(10, 18);
|
||||
this.label_upload_format.Name = "label_upload_format";
|
||||
this.label_upload_format.Size = new System.Drawing.Size(181, 33);
|
||||
this.label_upload_format.TabIndex = 4;
|
||||
//
|
||||
// label_AfterUpload
|
||||
//
|
||||
this.label_AfterUpload.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.label_AfterUpload.LanguageKey = "picasa.label_AfterUpload";
|
||||
this.label_AfterUpload.Location = new System.Drawing.Point(10, 51);
|
||||
this.label_AfterUpload.Name = "label_AfterUpload";
|
||||
this.label_AfterUpload.Size = new System.Drawing.Size(181, 29);
|
||||
this.label_AfterUpload.TabIndex = 8;
|
||||
//
|
||||
// checkboxAfterUploadLinkToClipBoard
|
||||
//
|
||||
this.checkboxAfterUploadLinkToClipBoard.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "picasa.label_AfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(197, 50);
|
||||
this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.SectionName = "Picasa";
|
||||
this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17);
|
||||
this.checkboxAfterUploadLinkToClipBoard.TabIndex = 2;
|
||||
this.checkboxAfterUploadLinkToClipBoard.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// SettingsForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(432, 110);
|
||||
this.Controls.Add(this.checkboxAfterUploadLinkToClipBoard);
|
||||
this.Controls.Add(this.label_AfterUpload);
|
||||
this.Controls.Add(this.label_upload_format);
|
||||
this.Controls.Add(this.combobox_uploadimageformat);
|
||||
this.Controls.Add(this.buttonCancel);
|
||||
this.Controls.Add(this.buttonOK);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.LanguageKey = "picasa.settings_title";
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "SettingsForm";
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat;
|
||||
private GreenshotPlugin.Controls.GreenshotLabel label_upload_format;
|
||||
private GreenshotPlugin.Controls.GreenshotButton buttonCancel;
|
||||
private GreenshotPlugin.Controls.GreenshotButton buttonOK;
|
||||
private GreenshotPlugin.Controls.GreenshotLabel label_AfterUpload;
|
||||
private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAfterUploadLinkToClipBoard;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* A GooglePhotos Plugin for Greenshot
|
||||
* Copyright (C) 2011 Francis Noel
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace GreenshotGooglePhotosPlugin.Forms {
|
||||
partial class SettingsForm {
|
||||
/// <summary>
|
||||
/// Designer variable used to keep track of non-visual components.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Disposes resources used by the form.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing) {
|
||||
if (components != null) {
|
||||
components.Dispose();
|
||||
}
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is required for Windows Forms designer support.
|
||||
/// Do not change the method contents inside the source code editor. The Forms designer might
|
||||
/// not be able to load this method if it was changed manually.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton();
|
||||
this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton();
|
||||
this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox();
|
||||
this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel();
|
||||
this.label_AfterUpload = new GreenshotPlugin.Controls.GreenshotLabel();
|
||||
this.checkboxAfterUploadLinkToClipBoard = new GreenshotPlugin.Controls.GreenshotCheckBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// buttonOK
|
||||
//
|
||||
this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.buttonOK.LanguageKey = "OK";
|
||||
this.buttonOK.Location = new System.Drawing.Point(267, 78);
|
||||
this.buttonOK.Name = "buttonOK";
|
||||
this.buttonOK.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonOK.TabIndex = 10;
|
||||
this.buttonOK.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// buttonCancel
|
||||
//
|
||||
this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.buttonCancel.LanguageKey = "CANCEL";
|
||||
this.buttonCancel.Location = new System.Drawing.Point(348, 78);
|
||||
this.buttonCancel.Name = "buttonCancel";
|
||||
this.buttonCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonCancel.TabIndex = 11;
|
||||
this.buttonCancel.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// combobox_uploadimageformat
|
||||
//
|
||||
this.combobox_uploadimageformat.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.combobox_uploadimageformat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.combobox_uploadimageformat.FormattingEnabled = true;
|
||||
this.combobox_uploadimageformat.Location = new System.Drawing.Point(197, 12);
|
||||
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat";
|
||||
this.combobox_uploadimageformat.PropertyName = "UploadFormat";
|
||||
this.combobox_uploadimageformat.SectionName = "GooglePhotos";
|
||||
this.combobox_uploadimageformat.Size = new System.Drawing.Size(225, 21);
|
||||
this.combobox_uploadimageformat.TabIndex = 1;
|
||||
//
|
||||
// label_upload_format
|
||||
//
|
||||
this.label_upload_format.LanguageKey = "googlephotos.label_upload_format";
|
||||
this.label_upload_format.Location = new System.Drawing.Point(10, 18);
|
||||
this.label_upload_format.Name = "label_upload_format";
|
||||
this.label_upload_format.Size = new System.Drawing.Size(181, 33);
|
||||
this.label_upload_format.TabIndex = 4;
|
||||
//
|
||||
// label_AfterUpload
|
||||
//
|
||||
this.label_AfterUpload.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.label_AfterUpload.LanguageKey = "googlephotos.label_AfterUpload";
|
||||
this.label_AfterUpload.Location = new System.Drawing.Point(10, 51);
|
||||
this.label_AfterUpload.Name = "label_AfterUpload";
|
||||
this.label_AfterUpload.Size = new System.Drawing.Size(181, 29);
|
||||
this.label_AfterUpload.TabIndex = 8;
|
||||
//
|
||||
// checkboxAfterUploadLinkToClipBoard
|
||||
//
|
||||
this.checkboxAfterUploadLinkToClipBoard.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "googlephotos.label_AfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(197, 50);
|
||||
this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.SectionName = "GooglePhotos";
|
||||
this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17);
|
||||
this.checkboxAfterUploadLinkToClipBoard.TabIndex = 2;
|
||||
this.checkboxAfterUploadLinkToClipBoard.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// SettingsForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(432, 110);
|
||||
this.Controls.Add(this.checkboxAfterUploadLinkToClipBoard);
|
||||
this.Controls.Add(this.label_AfterUpload);
|
||||
this.Controls.Add(this.label_upload_format);
|
||||
this.Controls.Add(this.combobox_uploadimageformat);
|
||||
this.Controls.Add(this.buttonCancel);
|
||||
this.Controls.Add(this.buttonOK);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.LanguageKey = "googlephotos.settings_title";
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "SettingsForm";
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat;
|
||||
private GreenshotPlugin.Controls.GreenshotLabel label_upload_format;
|
||||
private GreenshotPlugin.Controls.GreenshotButton buttonCancel;
|
||||
private GreenshotPlugin.Controls.GreenshotButton buttonOK;
|
||||
private GreenshotPlugin.Controls.GreenshotLabel label_AfterUpload;
|
||||
private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAfterUploadLinkToClipBoard;
|
||||
}
|
||||
}
|
|
@ -1,38 +1,38 @@
|
|||
/*
|
||||
* A Picasa Plugin for Greenshot
|
||||
* Copyright (C) 2011 Francis Noel
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GreenshotPicasaPlugin.Forms {
|
||||
/// <summary>
|
||||
/// Description of PasswordRequestForm.
|
||||
/// </summary>
|
||||
public partial class SettingsForm : PicasaForm {
|
||||
|
||||
public SettingsForm()
|
||||
{
|
||||
//
|
||||
// The InitializeComponent() call is required for Windows Forms designer support.
|
||||
//
|
||||
InitializeComponent();
|
||||
CancelButton = buttonCancel;
|
||||
AcceptButton = buttonOK;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/*
|
||||
* A GooglePhotos Plugin for Greenshot
|
||||
* Copyright (C) 2011 Francis Noel
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GreenshotGooglePhotosPlugin.Forms {
|
||||
/// <summary>
|
||||
/// Description of PasswordRequestForm.
|
||||
/// </summary>
|
||||
public partial class SettingsForm : GooglePhotosForm {
|
||||
|
||||
public SettingsForm()
|
||||
{
|
||||
//
|
||||
// The InitializeComponent() call is required for Windows Forms designer support.
|
||||
//
|
||||
InitializeComponent();
|
||||
CancelButton = buttonCancel;
|
||||
AcceptButton = buttonOK;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
BIN
GreenshotGooglePhotosPlugin/GooglePhotos.png
Normal file
BIN
GreenshotGooglePhotosPlugin/GooglePhotos.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -1,93 +1,93 @@
|
|||
/*
|
||||
* A Picasa Plugin for Greenshot
|
||||
* Copyright (C) 2011 Francis Noel
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System.Windows.Forms;
|
||||
using GreenshotPlugin.Core;
|
||||
using System;
|
||||
using GreenshotPicasaPlugin.Forms;
|
||||
using GreenshotPlugin.IniFile;
|
||||
|
||||
namespace GreenshotPicasaPlugin {
|
||||
/// <summary>
|
||||
/// Description of PicasaConfiguration.
|
||||
/// </summary>
|
||||
[IniSection("Picasa", Description = "Greenshot Picasa Plugin configuration")]
|
||||
public class PicasaConfiguration : IniSection {
|
||||
[IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")]
|
||||
public OutputFormat UploadFormat { get; set; }
|
||||
|
||||
[IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")]
|
||||
public int UploadJpegQuality { get; set; }
|
||||
|
||||
[IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send Picasa link to clipboard.", DefaultValue = "true")]
|
||||
public bool AfterUploadLinkToClipBoard { get; set; }
|
||||
[IniProperty("AddFilename", Description = "Is the filename passed on to Picasa", DefaultValue = "False")]
|
||||
public bool AddFilename {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[IniProperty("UploadUser", Description = "The Picasa user to upload to", DefaultValue = "default")]
|
||||
public string UploadUser {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[IniProperty("UploadAlbum", Description = "The Picasa album to upload to", DefaultValue = "default")]
|
||||
public string UploadAlbum {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[IniProperty("RefreshToken", Description = "Picasa authorization refresh Token", Encrypted = true)]
|
||||
public string RefreshToken {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Not stored
|
||||
/// </summary>
|
||||
public string AccessToken {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Not stored
|
||||
/// </summary>
|
||||
public DateTimeOffset AccessTokenExpires {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A form for token
|
||||
/// </summary>
|
||||
/// <returns>bool true if OK was pressed, false if cancel</returns>
|
||||
public bool ShowConfigDialog() {
|
||||
DialogResult result = new SettingsForm().ShowDialog();
|
||||
if (result == DialogResult.OK) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/*
|
||||
* A GooglePhotos Plugin for Greenshot
|
||||
* Copyright (C) 2011 Francis Noel
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System.Windows.Forms;
|
||||
using GreenshotPlugin.Core;
|
||||
using System;
|
||||
using GreenshotGooglePhotosPlugin.Forms;
|
||||
using GreenshotPlugin.IniFile;
|
||||
|
||||
namespace GreenshotGooglePhotosPlugin {
|
||||
/// <summary>
|
||||
/// Description of GooglePhotosConfiguration.
|
||||
/// </summary>
|
||||
[IniSection("GooglePhotos", Description = "Greenshot GooglePhotos Plugin configuration")]
|
||||
public class GooglePhotosConfiguration : IniSection {
|
||||
[IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")]
|
||||
public OutputFormat UploadFormat { get; set; }
|
||||
|
||||
[IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")]
|
||||
public int UploadJpegQuality { get; set; }
|
||||
|
||||
[IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send GooglePhotos link to clipboard.", DefaultValue = "true")]
|
||||
public bool AfterUploadLinkToClipBoard { get; set; }
|
||||
[IniProperty("AddFilename", Description = "Is the filename passed on to GooglePhotos", DefaultValue = "False")]
|
||||
public bool AddFilename {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[IniProperty("UploadUser", Description = "The GooglePhotos user to upload to", DefaultValue = "default")]
|
||||
public string UploadUser {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[IniProperty("UploadAlbum", Description = "The GooglePhotos album to upload to", DefaultValue = "default")]
|
||||
public string UploadAlbum {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[IniProperty("RefreshToken", Description = "GooglePhotos authorization refresh Token", Encrypted = true)]
|
||||
public string RefreshToken {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Not stored
|
||||
/// </summary>
|
||||
public string AccessToken {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Not stored
|
||||
/// </summary>
|
||||
public DateTimeOffset AccessTokenExpires {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A form for token
|
||||
/// </summary>
|
||||
/// <returns>bool true if OK was pressed, false if cancel</returns>
|
||||
public bool ShowConfigDialog() {
|
||||
DialogResult result = new SettingsForm().ShowDialog();
|
||||
if (result == DialogResult.OK) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,54 +1,54 @@
|
|||
/*
|
||||
* A Picasa Plugin for Greenshot
|
||||
* Copyright (C) 2011 Francis Noel
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using GreenshotPlugin.Core;
|
||||
using GreenshotPlugin.Interfaces;
|
||||
|
||||
namespace GreenshotPicasaPlugin {
|
||||
public class PicasaDestination : AbstractDestination {
|
||||
private readonly PicasaPlugin _plugin;
|
||||
public PicasaDestination(PicasaPlugin plugin) {
|
||||
_plugin = plugin;
|
||||
}
|
||||
|
||||
public override string Designation => "Picasa";
|
||||
|
||||
public override string Description => Language.GetString("picasa", LangKey.upload_menu_item);
|
||||
|
||||
public override Image DisplayIcon {
|
||||
get {
|
||||
ComponentResourceManager resources = new ComponentResourceManager(typeof(PicasaPlugin));
|
||||
return (Image)resources.GetObject("Picasa");
|
||||
}
|
||||
}
|
||||
|
||||
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) {
|
||||
ExportInformation exportInformation = new ExportInformation(Designation, Description);
|
||||
bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl);
|
||||
if (uploaded) {
|
||||
exportInformation.ExportMade = true;
|
||||
exportInformation.Uri = uploadUrl;
|
||||
}
|
||||
ProcessExport(exportInformation, surface);
|
||||
return exportInformation;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* A GooglePhotos Plugin for Greenshot
|
||||
* Copyright (C) 2011 Francis Noel
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using GreenshotPlugin.Core;
|
||||
using GreenshotPlugin.Interfaces;
|
||||
|
||||
namespace GreenshotGooglePhotosPlugin {
|
||||
public class GooglePhotosDestination : AbstractDestination {
|
||||
private readonly GooglePhotosPlugin _plugin;
|
||||
public GooglePhotosDestination(GooglePhotosPlugin plugin) {
|
||||
_plugin = plugin;
|
||||
}
|
||||
|
||||
public override string Designation => "GooglePhotos";
|
||||
|
||||
public override string Description => Language.GetString("googlephotos", LangKey.upload_menu_item);
|
||||
|
||||
public override Image DisplayIcon {
|
||||
get {
|
||||
ComponentResourceManager resources = new ComponentResourceManager(typeof(GooglePhotosPlugin));
|
||||
return (Image)resources.GetObject("GooglePhotos");
|
||||
}
|
||||
}
|
||||
|
||||
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) {
|
||||
ExportInformation exportInformation = new ExportInformation(Designation, Description);
|
||||
bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl);
|
||||
if (uploaded) {
|
||||
exportInformation.ExportMade = true;
|
||||
exportInformation.Uri = uploadUrl;
|
||||
}
|
||||
ProcessExport(exportInformation, surface);
|
||||
return exportInformation;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,125 +1,124 @@
|
|||
/*
|
||||
* A Picasa Plugin for Greenshot
|
||||
* Copyright (C) 2011 Francis Noel
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using GreenshotPlugin.Controls;
|
||||
using GreenshotPlugin.Core;
|
||||
using GreenshotPlugin.IniFile;
|
||||
using GreenshotPlugin.Interfaces;
|
||||
using GreenshotPlugin.Interfaces.Plugin;
|
||||
|
||||
namespace GreenshotPicasaPlugin {
|
||||
/// <summary>
|
||||
/// This is the Picasa base code
|
||||
/// </summary>
|
||||
[Plugin("Picasa", true)]
|
||||
public class PicasaPlugin : IGreenshotPlugin {
|
||||
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PicasaPlugin));
|
||||
private static PicasaConfiguration _config;
|
||||
private ComponentResourceManager _resources;
|
||||
private ToolStripMenuItem _itemPlugInRoot;
|
||||
|
||||
public void Dispose() {
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected void Dispose(bool disposing) {
|
||||
if (disposing) {
|
||||
if (_itemPlugInRoot != null) {
|
||||
_itemPlugInRoot.Dispose();
|
||||
_itemPlugInRoot = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of the IGreenshotPlugin.Initialize
|
||||
/// </summary>
|
||||
public bool Initialize() {
|
||||
SimpleServiceProvider.Current.AddService<IDestination>(new PicasaDestination(this));
|
||||
|
||||
// Get configuration
|
||||
_config = IniConfig.GetIniSection<PicasaConfiguration>();
|
||||
_resources = new ComponentResourceManager(typeof(PicasaPlugin));
|
||||
|
||||
_itemPlugInRoot = new ToolStripMenuItem
|
||||
{
|
||||
Text = Language.GetString("picasa", LangKey.Configure),
|
||||
Image = (Image) _resources.GetObject("Picasa")
|
||||
};
|
||||
_itemPlugInRoot.Click += ConfigMenuClick;
|
||||
PluginUtils.AddToContextMenu(_itemPlugInRoot);
|
||||
Language.LanguageChanged += OnLanguageChanged;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnLanguageChanged(object sender, EventArgs e) {
|
||||
if (_itemPlugInRoot != null) {
|
||||
_itemPlugInRoot.Text = Language.GetString("picasa", LangKey.Configure);
|
||||
}
|
||||
}
|
||||
|
||||
public void Shutdown() {
|
||||
Log.Debug("Picasa Plugin shutdown.");
|
||||
Language.LanguageChanged -= OnLanguageChanged;
|
||||
//host.OnImageEditorOpen -= new OnImageEditorOpenHandler(ImageEditorOpened);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of the IPlugin.Configure
|
||||
/// </summary>
|
||||
public void Configure() {
|
||||
_config.ShowConfigDialog();
|
||||
}
|
||||
|
||||
public void ConfigMenuClick(object sender, EventArgs eventArgs) {
|
||||
Configure();
|
||||
}
|
||||
|
||||
public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) {
|
||||
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality);
|
||||
try {
|
||||
string url = null;
|
||||
new PleaseWaitForm().ShowAndWait("Picasa", Language.GetString("picasa", LangKey.communication_wait),
|
||||
delegate
|
||||
{
|
||||
string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails));
|
||||
url = PicasaUtils.UploadToPicasa(surfaceToUpload, outputSettings, captureDetails.Title, filename);
|
||||
}
|
||||
);
|
||||
uploadUrl = url;
|
||||
|
||||
if (uploadUrl != null && _config.AfterUploadLinkToClipBoard) {
|
||||
ClipboardHelper.SetClipboardData(uploadUrl);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
Log.Error("Error uploading.", e);
|
||||
MessageBox.Show(Language.GetString("picasa", LangKey.upload_failure) + " " + e.Message);
|
||||
}
|
||||
uploadUrl = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* A GooglePhotos Plugin for Greenshot
|
||||
* Copyright (C) 2011 Francis Noel
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using GreenshotPlugin.Controls;
|
||||
using GreenshotPlugin.Core;
|
||||
using GreenshotPlugin.IniFile;
|
||||
using GreenshotPlugin.Interfaces;
|
||||
using GreenshotPlugin.Interfaces.Plugin;
|
||||
|
||||
namespace GreenshotGooglePhotosPlugin {
|
||||
/// <summary>
|
||||
/// This is the GooglePhotos base code
|
||||
/// </summary>
|
||||
[Plugin("GooglePhotos", true)]
|
||||
public class GooglePhotosPlugin : IGreenshotPlugin {
|
||||
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosPlugin));
|
||||
private static GooglePhotosConfiguration _config;
|
||||
private ComponentResourceManager _resources;
|
||||
private ToolStripMenuItem _itemPlugInRoot;
|
||||
|
||||
public void Dispose() {
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposing) return;
|
||||
if (_itemPlugInRoot == null) return;
|
||||
_itemPlugInRoot.Dispose();
|
||||
_itemPlugInRoot = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of the IGreenshotPlugin.Initialize
|
||||
/// </summary>
|
||||
public bool Initialize() {
|
||||
SimpleServiceProvider.Current.AddService<IDestination>(new GooglePhotosDestination(this));
|
||||
|
||||
// Get configuration
|
||||
_config = IniConfig.GetIniSection<GooglePhotosConfiguration>();
|
||||
_resources = new ComponentResourceManager(typeof(GooglePhotosPlugin));
|
||||
|
||||
_itemPlugInRoot = new ToolStripMenuItem
|
||||
{
|
||||
Text = Language.GetString("googlephotos", LangKey.Configure),
|
||||
Image = (Image) _resources.GetObject("GooglePhotos")
|
||||
};
|
||||
_itemPlugInRoot.Click += ConfigMenuClick;
|
||||
PluginUtils.AddToContextMenu(_itemPlugInRoot);
|
||||
Language.LanguageChanged += OnLanguageChanged;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnLanguageChanged(object sender, EventArgs e) {
|
||||
if (_itemPlugInRoot != null) {
|
||||
_itemPlugInRoot.Text = Language.GetString("googlephotos", LangKey.Configure);
|
||||
}
|
||||
}
|
||||
|
||||
public void Shutdown() {
|
||||
Log.Debug("GooglePhotos Plugin shutdown.");
|
||||
Language.LanguageChanged -= OnLanguageChanged;
|
||||
//host.OnImageEditorOpen -= new OnImageEditorOpenHandler(ImageEditorOpened);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of the IPlugin.Configure
|
||||
/// </summary>
|
||||
public void Configure() {
|
||||
_config.ShowConfigDialog();
|
||||
}
|
||||
|
||||
public void ConfigMenuClick(object sender, EventArgs eventArgs) {
|
||||
Configure();
|
||||
}
|
||||
|
||||
public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) {
|
||||
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality);
|
||||
try {
|
||||
string url = null;
|
||||
new PleaseWaitForm().ShowAndWait("GooglePhotos", Language.GetString("googlephotos", LangKey.communication_wait),
|
||||
delegate
|
||||
{
|
||||
string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails));
|
||||
url = GooglePhotosUtils.UploadToGooglePhotos(surfaceToUpload, outputSettings, captureDetails.Title, filename);
|
||||
}
|
||||
);
|
||||
uploadUrl = url;
|
||||
|
||||
if (uploadUrl != null && _config.AfterUploadLinkToClipBoard) {
|
||||
ClipboardHelper.SetClipboardData(uploadUrl);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
Log.Error("Error uploading.", e);
|
||||
MessageBox.Show(Language.GetString("googlephotos", LangKey.upload_failure) + " " + e.Message);
|
||||
}
|
||||
uploadUrl = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -118,7 +118,7 @@
|
|||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="Picasa" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>picasa.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
<data name="GooglePhotos" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>GooglePhotos.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1,119 +1,120 @@
|
|||
/*
|
||||
* A Picasa Plugin for Greenshot
|
||||
* Copyright (C) 2011 Francis Noel
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using GreenshotPlugin.Core;
|
||||
using System;
|
||||
using System.Xml;
|
||||
using GreenshotPlugin.IniFile;
|
||||
using GreenshotPlugin.Interfaces;
|
||||
using GreenshotPlugin.Interfaces.Plugin;
|
||||
|
||||
namespace GreenshotPicasaPlugin {
|
||||
/// <summary>
|
||||
/// Description of PicasaUtils.
|
||||
/// </summary>
|
||||
public static class PicasaUtils {
|
||||
private const string PicasaScope = "https://picasaweb.google.com/data/";
|
||||
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PicasaUtils));
|
||||
private static readonly PicasaConfiguration Config = IniConfig.GetIniSection<PicasaConfiguration>();
|
||||
private const string AuthUrl = "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={ClientId}&redirect_uri={RedirectUrl}&state={State}&scope=" + PicasaScope;
|
||||
private const string TokenUrl = "https://www.googleapis.com/oauth2/v3/token";
|
||||
private const string UploadUrl = "https://picasaweb.google.com/data/feed/api/user/{0}/albumid/{1}";
|
||||
|
||||
/// <summary>
|
||||
/// Do the actual upload to Picasa
|
||||
/// </summary>
|
||||
/// <param name="surfaceToUpload">Image to upload</param>
|
||||
/// <param name="outputSettings"></param>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="filename"></param>
|
||||
/// <returns>PicasaResponse</returns>
|
||||
public static string UploadToPicasa(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) {
|
||||
// Fill the OAuth2Settings
|
||||
var settings = new OAuth2Settings
|
||||
{
|
||||
AuthUrlPattern = AuthUrl,
|
||||
TokenUrl = TokenUrl,
|
||||
CloudServiceName = "Picasa",
|
||||
ClientId = PicasaCredentials.ClientId,
|
||||
ClientSecret = PicasaCredentials.ClientSecret,
|
||||
AuthorizeMode = OAuth2AuthorizeMode.LocalServer,
|
||||
RefreshToken = Config.RefreshToken,
|
||||
AccessToken = Config.AccessToken,
|
||||
AccessTokenExpires = Config.AccessTokenExpires
|
||||
};
|
||||
|
||||
// Copy the settings from the config, which is kept in memory and on the disk
|
||||
|
||||
try {
|
||||
var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, string.Format(UploadUrl, Config.UploadUser, Config.UploadAlbum), settings);
|
||||
if (Config.AddFilename) {
|
||||
webRequest.Headers.Add("Slug", NetworkHelper.EscapeDataString(filename));
|
||||
}
|
||||
SurfaceContainer container = new SurfaceContainer(surfaceToUpload, outputSettings, filename);
|
||||
container.Upload(webRequest);
|
||||
|
||||
string response = NetworkHelper.GetResponseAsString(webRequest);
|
||||
|
||||
return ParseResponse(response);
|
||||
} finally {
|
||||
// Copy the settings back to the config, so they are stored.
|
||||
Config.RefreshToken = settings.RefreshToken;
|
||||
Config.AccessToken = settings.AccessToken;
|
||||
Config.AccessTokenExpires = settings.AccessTokenExpires;
|
||||
Config.IsDirty = true;
|
||||
IniConfig.Save();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse the upload URL from the response
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <returns></returns>
|
||||
public static string ParseResponse(string response) {
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.LoadXml(response);
|
||||
XmlNodeList nodes = doc.GetElementsByTagName("link", "*");
|
||||
if(nodes.Count > 0) {
|
||||
string url = null;
|
||||
foreach(XmlNode node in nodes) {
|
||||
if (node.Attributes != null) {
|
||||
url = node.Attributes["href"].Value;
|
||||
string rel = node.Attributes["rel"].Value;
|
||||
// Pictures with rel="http://schemas.google.com/photos/2007#canonical" are the direct link
|
||||
if (rel != null && rel.EndsWith("canonical")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
} catch(Exception e) {
|
||||
Log.ErrorFormat("Could not parse Picasa response due to error {0}, response was: {1}", e.Message, response);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* A GooglePhotos Plugin for Greenshot
|
||||
* Copyright (C) 2011 Francis Noel
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using GreenshotPlugin.Core;
|
||||
using System;
|
||||
using System.Xml;
|
||||
using GreenshotPlugin.Core.OAuth;
|
||||
using GreenshotPlugin.IniFile;
|
||||
using GreenshotPlugin.Interfaces;
|
||||
using GreenshotPlugin.Interfaces.Plugin;
|
||||
|
||||
namespace GreenshotGooglePhotosPlugin {
|
||||
/// <summary>
|
||||
/// Description of GooglePhotosUtils.
|
||||
/// </summary>
|
||||
public static class GooglePhotosUtils {
|
||||
private const string GooglePhotosScope = "https://picasaweb.google.com/data/";
|
||||
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosUtils));
|
||||
private static readonly GooglePhotosConfiguration Config = IniConfig.GetIniSection<GooglePhotosConfiguration>();
|
||||
private const string AuthUrl = "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={ClientId}&redirect_uri={RedirectUrl}&state={State}&scope=" + GooglePhotosScope;
|
||||
private const string TokenUrl = "https://www.googleapis.com/oauth2/v3/token";
|
||||
private const string UploadUrl = "https://picasaweb.google.com/data/feed/api/user/{0}/albumid/{1}";
|
||||
|
||||
/// <summary>
|
||||
/// Do the actual upload to GooglePhotos
|
||||
/// </summary>
|
||||
/// <param name="surfaceToUpload">Image to upload</param>
|
||||
/// <param name="outputSettings">SurfaceOutputSettings</param>
|
||||
/// <param name="title">string</param>
|
||||
/// <param name="filename">string</param>
|
||||
/// <returns>GooglePhotosResponse</returns>
|
||||
public static string UploadToGooglePhotos(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) {
|
||||
// Fill the OAuth2Settings
|
||||
var settings = new OAuth2Settings
|
||||
{
|
||||
AuthUrlPattern = AuthUrl,
|
||||
TokenUrl = TokenUrl,
|
||||
CloudServiceName = "GooglePhotos",
|
||||
ClientId = GooglePhotosCredentials.ClientId,
|
||||
ClientSecret = GooglePhotosCredentials.ClientSecret,
|
||||
AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver,
|
||||
RefreshToken = Config.RefreshToken,
|
||||
AccessToken = Config.AccessToken,
|
||||
AccessTokenExpires = Config.AccessTokenExpires
|
||||
};
|
||||
|
||||
// Copy the settings from the config, which is kept in memory and on the disk
|
||||
|
||||
try {
|
||||
var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, string.Format(UploadUrl, Config.UploadUser, Config.UploadAlbum), settings);
|
||||
if (Config.AddFilename) {
|
||||
webRequest.Headers.Add("Slug", NetworkHelper.EscapeDataString(filename));
|
||||
}
|
||||
SurfaceContainer container = new SurfaceContainer(surfaceToUpload, outputSettings, filename);
|
||||
container.Upload(webRequest);
|
||||
|
||||
string response = NetworkHelper.GetResponseAsString(webRequest);
|
||||
|
||||
return ParseResponse(response);
|
||||
} finally {
|
||||
// Copy the settings back to the config, so they are stored.
|
||||
Config.RefreshToken = settings.RefreshToken;
|
||||
Config.AccessToken = settings.AccessToken;
|
||||
Config.AccessTokenExpires = settings.AccessTokenExpires;
|
||||
Config.IsDirty = true;
|
||||
IniConfig.Save();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse the upload URL from the response
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <returns></returns>
|
||||
public static string ParseResponse(string response) {
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.LoadXml(response);
|
||||
XmlNodeList nodes = doc.GetElementsByTagName("link", "*");
|
||||
if(nodes.Count > 0) {
|
||||
string url = null;
|
||||
foreach(XmlNode node in nodes) {
|
||||
if (node.Attributes != null) {
|
||||
url = node.Attributes["href"].Value;
|
||||
string rel = node.Attributes["rel"].Value;
|
||||
// Pictures with rel="http://schemas.google.com/photos/2007#canonical" are the direct link
|
||||
if (rel != null && rel.EndsWith("canonical")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
} catch(Exception e) {
|
||||
Log.ErrorFormat("Could not parse GooglePhotos response due to error {0}, response was: {1}", e.Message, response);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,13 +19,13 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GreenshotPicasaPlugin {
|
||||
namespace GreenshotGooglePhotosPlugin {
|
||||
/// <summary>
|
||||
/// This class is merely a placeholder for the file keeping the API key and secret for dropbox integration.
|
||||
/// You can set your own values here
|
||||
/// </summary>
|
||||
public static class PicasaCredentials {
|
||||
public static string ClientId = "${Picasa_ClientId}";
|
||||
public static string ClientSecret = "${Picasa_ClientSecret}";
|
||||
public static class GooglePhotosCredentials {
|
||||
public static string ClientId = "${GooglePhotos_ClientId}";
|
||||
public static string ClientSecret = "${GooglePhotos_ClientSecret}";
|
||||
}
|
||||
}
|
|
@ -1,21 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<RootNamespace>GreenshotPicasaPlugin</RootNamespace>
|
||||
<AssemblyName>GreenshotPicasaPlugin</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Languages\language*.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Picasa.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GreenshotPlugin\GreenshotPlugin.csproj" />
|
||||
</ItemGroup>
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<ItemGroup>
|
||||
<None Include="Languages\language*.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="GooglePhotos.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GreenshotPlugin\GreenshotPlugin.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,29 +1,29 @@
|
|||
/*
|
||||
* A Picasa Plugin for Greenshot
|
||||
* Copyright (C) 2011 Francis Noel
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GreenshotPicasaPlugin {
|
||||
public enum LangKey
|
||||
{
|
||||
upload_menu_item,
|
||||
upload_failure,
|
||||
communication_wait,
|
||||
Configure
|
||||
}
|
||||
}
|
||||
/*
|
||||
* A GooglePhotos Plugin for Greenshot
|
||||
* Copyright (C) 2011 Francis Noel
|
||||
*
|
||||
* For more information see: http://getgreenshot.org/
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GreenshotGooglePhotosPlugin {
|
||||
public enum LangKey
|
||||
{
|
||||
upload_menu_item,
|
||||
upload_failure,
|
||||
communication_wait,
|
||||
Configure
|
||||
}
|
||||
}
|
|
@ -1,29 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Czech" ietf="cs-CZ" version="1.1.0.2411" languagegroup="">
|
||||
<resources>
|
||||
<resource name="CANCEL">Zrušit</resource>
|
||||
<resource name="communication_wait">Probíhá komunikace s Picasem. Prosím počkejte ...</resource>
|
||||
<resource name="Configure">Konfigurace</resource>
|
||||
<resource name="delete_question">Opravdu chcete odstranit obrázek {0} z Picasa?</resource>
|
||||
<resource name="delete_title">Odstranit Picasa {0}</resource>
|
||||
<resource name="History">Historie</resource>
|
||||
<resource name="InvalidCredentials">Neplatná oprávnění. Otevřít nastavení pro provedené změn.</resource>
|
||||
<resource name="label_AfterUpload">Po odeslání</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">Kopírovat odkaz do schránky</resource>
|
||||
<resource name="label_AfterUploadOpenHistory">Zobrazit historii</resource>
|
||||
<resource name="label_DefaultSize">Výchozí velikost</resource>
|
||||
<resource name="label_Password">Heslo</resource>
|
||||
<resource name="label_upload_format">Formát obrázku</resource>
|
||||
<resource name="label_Username">Jméno</resource>
|
||||
<resource name="OK">OK</resource>
|
||||
<resource name="PictureDisplaySize.OriginalUrl">Originál URL</resource>
|
||||
<resource name="PictureDisplaySize.SquareThumbnailUrl">Čtvercové náhledy URL ???</resource>
|
||||
<resource name="PictureDisplaySize.WebUrl">Webová adresa URL</resource>
|
||||
<resource name="settings_title">Nastavení Picasa</resource>
|
||||
<resource name="Upload">Nahrát</resource>
|
||||
<resource name="upload_failure">Nahrání obrázku do Picasa se nezdařilo:</resource>
|
||||
<resource name="upload_menu_item">Nahrát do Picasa</resource>
|
||||
<resource name="upload_success">Úspěšně odeslaný obrázek do Picasa!</resource>
|
||||
<resource name="UsernameNotSet">Prosím ověřit aplikaci Picasa. Otevřít nastavení obrazovky. ???</resource>
|
||||
</resources>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Czech" ietf="cs-CZ" version="1.1.0.2411" languagegroup="">
|
||||
<resources>
|
||||
<resource name="CANCEL">Zrušit</resource>
|
||||
<resource name="communication_wait">Probíhá komunikace s Picasem. Prosím počkejte ...</resource>
|
||||
<resource name="Configure">Konfigurace</resource>
|
||||
<resource name="delete_question">Opravdu chcete odstranit obrázek {0} z GooglePhotos?</resource>
|
||||
<resource name="delete_title">Odstranit GooglePhotos {0}</resource>
|
||||
<resource name="History">Historie</resource>
|
||||
<resource name="InvalidCredentials">Neplatná oprávnění. Otevřít nastavení pro provedené změn.</resource>
|
||||
<resource name="label_AfterUpload">Po odeslání</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">Kopírovat odkaz do schránky</resource>
|
||||
<resource name="label_AfterUploadOpenHistory">Zobrazit historii</resource>
|
||||
<resource name="label_DefaultSize">Výchozí velikost</resource>
|
||||
<resource name="label_Password">Heslo</resource>
|
||||
<resource name="label_upload_format">Formát obrázku</resource>
|
||||
<resource name="label_Username">Jméno</resource>
|
||||
<resource name="OK">OK</resource>
|
||||
<resource name="PictureDisplaySize.OriginalUrl">Originál URL</resource>
|
||||
<resource name="PictureDisplaySize.SquareThumbnailUrl">Čtvercové náhledy URL ???</resource>
|
||||
<resource name="PictureDisplaySize.WebUrl">Webová adresa URL</resource>
|
||||
<resource name="settings_title">Nastavení GooglePhotos</resource>
|
||||
<resource name="Upload">Nahrát</resource>
|
||||
<resource name="upload_failure">Nahrání obrázku do GooglePhotos se nezdařilo:</resource>
|
||||
<resource name="upload_menu_item">Nahrát do GooglePhotos</resource>
|
||||
<resource name="upload_success">Úspěšně odeslaný obrázek do GooglePhotos!</resource>
|
||||
<resource name="UsernameNotSet">Prosím ověřit aplikaci GooglePhotos. Otevřít nastavení obrazovky. ???</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -8,25 +8,25 @@
|
|||
Anschliessend
|
||||
</resource>
|
||||
<resource name="Configure">
|
||||
Picasa konfigurieren
|
||||
GooglePhotos konfigurieren
|
||||
</resource>
|
||||
<resource name="upload_menu_item">
|
||||
Hochladen zu Picasa
|
||||
Hochladen zu GooglePhotos
|
||||
</resource>
|
||||
<resource name="settings_title">
|
||||
Picasa Einstellungen
|
||||
GooglePhotos Einstellungen
|
||||
</resource>
|
||||
<resource name="upload_success">
|
||||
Hochladen zu Picasa war erfolgreich !
|
||||
Hochladen zu GooglePhotos war erfolgreich !
|
||||
</resource>
|
||||
<resource name="upload_failure">
|
||||
Fehler beim Hochladen zu Picasa:
|
||||
Fehler beim Hochladen zu GooglePhotos:
|
||||
</resource>
|
||||
<resource name="label_upload_format">
|
||||
Grafikformat
|
||||
</resource>
|
||||
<resource name="communication_wait">
|
||||
Übermittle Daten zu Picasa. Bitte warten...
|
||||
Übermittle Daten zu GooglePhotos. Bitte warten...
|
||||
</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -8,25 +8,25 @@
|
|||
After upload
|
||||
</resource>
|
||||
<resource name="Configure">
|
||||
Configure Picasa
|
||||
Configure GooglePhotos
|
||||
</resource>
|
||||
<resource name="upload_menu_item">
|
||||
Upload to Picasa
|
||||
Upload to GooglePhotos
|
||||
</resource>
|
||||
<resource name="settings_title">
|
||||
Picasa settings
|
||||
GooglePhotos settings
|
||||
</resource>
|
||||
<resource name="upload_success">
|
||||
Successfully uploaded image to Picasa!
|
||||
Successfully uploaded image to GooglePhotos!
|
||||
</resource>
|
||||
<resource name="upload_failure">
|
||||
An error occured while uploading to Picasa:
|
||||
An error occured while uploading to GooglePhotos:
|
||||
</resource>
|
||||
<resource name="label_upload_format">
|
||||
Image format
|
||||
</resource>
|
||||
<resource name="communication_wait">
|
||||
Communicating with Picasa. Please wait...
|
||||
Communicating with GooglePhotos. Please wait...
|
||||
</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -1,14 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Français" ietf="fr-FR" version="1.0.0" languagegroup="">
|
||||
<resources>
|
||||
<resource name="communication_wait">Communication en cours avec Picasa. Veuillez patientez...</resource>
|
||||
<resource name="Configure">Configurer Picasa</resource>
|
||||
<resource name="label_AfterUpload">Après téléversement</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">Copier le lien dans le presse-papier</resource>
|
||||
<resource name="label_upload_format">Format image</resource>
|
||||
<resource name="settings_title">Paramètres Picasa</resource>
|
||||
<resource name="upload_failure">Une erreur s'est produite lors du téléversement vers Picasa :</resource>
|
||||
<resource name="upload_menu_item">Téléverser vers Picasa</resource>
|
||||
<resource name="upload_success">Image téléversée avec succès vers Picasa !</resource>
|
||||
</resources>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Français" ietf="fr-FR" version="1.0.0" languagegroup="">
|
||||
<resources>
|
||||
<resource name="communication_wait">Communication en cours avec GooglePhotos. Veuillez patientez...</resource>
|
||||
<resource name="Configure">Configurer GooglePhotos</resource>
|
||||
<resource name="label_AfterUpload">Après téléversement</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">Copier le lien dans le presse-papier</resource>
|
||||
<resource name="label_upload_format">Format image</resource>
|
||||
<resource name="settings_title">Paramètres GooglePhotos</resource>
|
||||
<resource name="upload_failure">Une erreur s'est produite lors du téléversement vers GooglePhotos :</resource>
|
||||
<resource name="upload_menu_item">Téléverser vers GooglePhotos</resource>
|
||||
<resource name="upload_success">Image téléversée avec succès vers GooglePhotos !</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -1,14 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Bahasa Indonesia" ietf="id-ID" version="1.0.0.0" languagegroup="">
|
||||
<resources>
|
||||
<resource name="communication_wait">Menyambungkan ke Picasa. Tunggu sebentar...</resource>
|
||||
<resource name="Configure">Konfigurasi Picasa</resource>
|
||||
<resource name="label_AfterUpload">Sesudah mengunggah</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">Sambung ke papanklip</resource>
|
||||
<resource name="label_upload_format">Format gambar</resource>
|
||||
<resource name="settings_title">Pengaturan Picasa</resource>
|
||||
<resource name="upload_failure">Kesalahan terjadi ketika mengunggah ke Picasa:</resource>
|
||||
<resource name="upload_menu_item">Unggah ke Picasa</resource>
|
||||
<resource name="upload_success">Berhasil mengunggah gambar ke Picasa!</resource>
|
||||
</resources>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Bahasa Indonesia" ietf="id-ID" version="1.0.0.0" languagegroup="">
|
||||
<resources>
|
||||
<resource name="communication_wait">Menyambungkan ke GooglePhotos. Tunggu sebentar...</resource>
|
||||
<resource name="Configure">Konfigurasi GooglePhotos</resource>
|
||||
<resource name="label_AfterUpload">Sesudah mengunggah</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">Sambung ke papanklip</resource>
|
||||
<resource name="label_upload_format">Format gambar</resource>
|
||||
<resource name="settings_title">Pengaturan GooglePhotos</resource>
|
||||
<resource name="upload_failure">Kesalahan terjadi ketika mengunggah ke GooglePhotos:</resource>
|
||||
<resource name="upload_menu_item">Unggah ke GooglePhotos</resource>
|
||||
<resource name="upload_success">Berhasil mengunggah gambar ke GooglePhotos!</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -1,32 +1,32 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Italiano" ietf="it-IT" version="1.1.5">
|
||||
<resources>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">
|
||||
Collegamento agli Appunti
|
||||
</resource>
|
||||
<resource name="label_AfterUpload">
|
||||
Dopo il caricamento
|
||||
</resource>
|
||||
<resource name="Configure">
|
||||
Impostazioni Picasa
|
||||
</resource>
|
||||
<resource name="upload_menu_item">
|
||||
Carica su Picasa
|
||||
</resource>
|
||||
<resource name="settings_title">
|
||||
Impostazioni Picasa
|
||||
</resource>
|
||||
<resource name="upload_success">
|
||||
Caricamento immagine su Picasa completato!
|
||||
</resource>
|
||||
<resource name="upload_failure">
|
||||
Si è verificato un errore durante il caricamento su Picasa:
|
||||
</resource>
|
||||
<resource name="label_upload_format">
|
||||
Formato immagine
|
||||
</resource>
|
||||
<resource name="communication_wait">
|
||||
Comunicazione con Picasa...
|
||||
</resource>
|
||||
</resources>
|
||||
</language>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Italiano" ietf="it-IT" version="1.1.5">
|
||||
<resources>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">
|
||||
Collegamento agli Appunti
|
||||
</resource>
|
||||
<resource name="label_AfterUpload">
|
||||
Dopo il caricamento
|
||||
</resource>
|
||||
<resource name="Configure">
|
||||
Impostazioni GooglePhotos
|
||||
</resource>
|
||||
<resource name="upload_menu_item">
|
||||
Carica su GooglePhotos
|
||||
</resource>
|
||||
<resource name="settings_title">
|
||||
Impostazioni GooglePhotos
|
||||
</resource>
|
||||
<resource name="upload_success">
|
||||
Caricamento immagine su GooglePhotos completato!
|
||||
</resource>
|
||||
<resource name="upload_failure">
|
||||
Si è verificato un errore durante il caricamento su GooglePhotos:
|
||||
</resource>
|
||||
<resource name="label_upload_format">
|
||||
Formato immagine
|
||||
</resource>
|
||||
<resource name="communication_wait">
|
||||
Comunicazione con GooglePhotos...
|
||||
</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="日本語" ietf="ja-JP" version="1.0.0">
|
||||
<resources>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">リンクをクリップボードへコピー</resource>
|
||||
<resource name="label_AfterUpload">アップロード後</resource>
|
||||
<resource name="Configure">GooglePhotos の設定</resource>
|
||||
<resource name="upload_menu_item">GooglePhotos にアップロード</resource>
|
||||
<resource name="settings_title">GooglePhotos の設定</resource>
|
||||
<resource name="upload_success">GooglePhotos へのアップロードに成功しました!</resource>
|
||||
<resource name="upload_failure">GooglePhotos へのアップロード中にエラーが発生しました:</resource>
|
||||
<resource name="label_upload_format">画像フォーマット</resource>
|
||||
<resource name="communication_wait">GooglePhotos に接続中です。しばらくお待ち下さい...</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -1,14 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Taqbaylit" ietf="kab-DZ" version="1.0.0" languagegroup="">
|
||||
<resources>
|
||||
<resource name="communication_wait">S tidett tebɣiḍ ad tekkseḍ amazray adigan n Picasa ?...</resource>
|
||||
<resource name="Configure">Swel Picasa</resource>
|
||||
<resource name="communication_wait">S tidett tebɣiḍ ad tekkseḍ amazray adigan n GooglePhotos ?...</resource>
|
||||
<resource name="Configure">Swel GooglePhotos</resource>
|
||||
<resource name="label_AfterUpload">Ticki yemmed usali</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">Nɣel aseɣwen ɣef afus</resource>
|
||||
<resource name="label_upload_format">Amsal n tugna</resource>
|
||||
<resource name="settings_title">Iɣewwaṛen Picasa</resource>
|
||||
<resource name="upload_failure">Teḍra-d tuccḍa deg usali ɣer Picasa :</resource>
|
||||
<resource name="upload_menu_item">Sali ɣer Picasa</resource>
|
||||
<resource name="upload_success">Tugna tuli ɣer Picasa !</resource>
|
||||
<resource name="settings_title">Iɣewwaṛen GooglePhotos</resource>
|
||||
<resource name="upload_failure">Teḍra-d tuccḍa deg usali ɣer GooglePhotos :</resource>
|
||||
<resource name="upload_menu_item">Sali ɣer GooglePhotos</resource>
|
||||
<resource name="upload_success">Tugna tuli ɣer GooglePhotos !</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -8,25 +8,25 @@
|
|||
얼로드 후
|
||||
</resource>
|
||||
<resource name="Configure">
|
||||
Picasa 설정
|
||||
GooglePhotos 설정
|
||||
</resource>
|
||||
<resource name="upload_menu_item">
|
||||
Picasa로 업로드
|
||||
GooglePhotos로 업로드
|
||||
</resource>
|
||||
<resource name="settings_title">
|
||||
Picasa 설정
|
||||
GooglePhotos 설정
|
||||
</resource>
|
||||
<resource name="upload_success">
|
||||
Picasa로 이미지 업로드 성공!
|
||||
GooglePhotos로 이미지 업로드 성공!
|
||||
</resource>
|
||||
<resource name="upload_failure">
|
||||
Picasa로 업로드시 오류 발생:
|
||||
GooglePhotos로 업로드시 오류 발생:
|
||||
</resource>
|
||||
<resource name="label_upload_format">
|
||||
이미지 형식
|
||||
</resource>
|
||||
<resource name="communication_wait">
|
||||
Picasa와 연결 중 잠시 기다리세요...
|
||||
GooglePhotos와 연결 중 잠시 기다리세요...
|
||||
</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -9,25 +9,25 @@
|
|||
Pēc augšupielādes
|
||||
</resource>
|
||||
<resource name="Configure">
|
||||
Picasa iestatījumi
|
||||
GooglePhotos iestatījumi
|
||||
</resource>
|
||||
<resource name="upload_menu_item">
|
||||
Augšupieladēt uz Picasa
|
||||
Augšupieladēt uz GooglePhotos
|
||||
</resource>
|
||||
<resource name="settings_title">
|
||||
Picasa iestatījumi
|
||||
GooglePhotos iestatījumi
|
||||
</resource>
|
||||
<resource name="upload_success">
|
||||
Attēls veiksmīgi augšupielādēts uz Picasa!
|
||||
Attēls veiksmīgi augšupielādēts uz GooglePhotos!
|
||||
</resource>
|
||||
<resource name="upload_failure">
|
||||
Kļūda augšuplādējot uz Picasa:
|
||||
Kļūda augšuplādējot uz GooglePhotos:
|
||||
</resource>
|
||||
<resource name="label_upload_format">
|
||||
Attēla formāts
|
||||
</resource>
|
||||
<resource name="communication_wait">
|
||||
Savienojos ar Picasa. Lūdzu uzgaidiet...
|
||||
Savienojos ar GooglePhotos. Lūdzu uzgaidiet...
|
||||
</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Polski" ietf="pl-PL" version="1.1.4" languagegroup="2">
|
||||
<resources>
|
||||
<resource name="communication_wait">Trwa komunikacja z GooglePhotos. Proszę czekać...</resource>
|
||||
<resource name="Configure">Konfiguruj GooglePhotos</resource>
|
||||
<resource name="label_AfterUpload">Po wysłaniu</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">Link do schowka</resource>
|
||||
<resource name="label_upload_format">Format obrazów</resource>
|
||||
<resource name="settings_title">Ustawienia GooglePhotos</resource>
|
||||
<resource name="upload_failure">Wystąpił błąd przy wysyłaniu do GooglePhotos:</resource>
|
||||
<resource name="upload_menu_item">Wyślij do GooglePhotos</resource>
|
||||
<resource name="upload_success">Wysyłanie obrazu do GooglePhotos powiodło się!</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -8,25 +8,25 @@
|
|||
Após enviar
|
||||
</resource>
|
||||
<resource name="Configure">
|
||||
Configurar o Picasa
|
||||
Configurar o GooglePhotos
|
||||
</resource>
|
||||
<resource name="upload_menu_item">
|
||||
enviar para o Picasa
|
||||
enviar para o GooglePhotos
|
||||
</resource>
|
||||
<resource name="settings_title">
|
||||
Definições Picasa
|
||||
Definições GooglePhotos
|
||||
</resource>
|
||||
<resource name="upload_success">
|
||||
Imagem enviada com êxito para o Picasa!
|
||||
Imagem enviada com êxito para o GooglePhotos!
|
||||
</resource>
|
||||
<resource name="upload_failure">
|
||||
Ocorreu um erro ao enviar para o Picasa:
|
||||
Ocorreu um erro ao enviar para o GooglePhotos:
|
||||
</resource>
|
||||
<resource name="label_upload_format">
|
||||
Formato da imagem
|
||||
</resource>
|
||||
<resource name="communication_wait">
|
||||
A comunicar com o Picasa. Por favor aguarde...
|
||||
A comunicar com o GooglePhotos. Por favor aguarde...
|
||||
</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -1,14 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Русский" ietf="ru-RU" version="1.1.0.2515" languagegroup="5">
|
||||
<resources>
|
||||
<resource name="communication_wait">Обмен данными с Picasa. Подождите...</resource>
|
||||
<resource name="Configure">Настройка Picasa</resource>
|
||||
<resource name="label_AfterUpload">После загрузки</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">Ссылки в буфер обмена</resource>
|
||||
<resource name="label_upload_format">Формат изображения</resource>
|
||||
<resource name="settings_title">Настройки Picasa</resource>
|
||||
<resource name="upload_failure">Произошла ошибка при загрузке на Picasa:</resource>
|
||||
<resource name="upload_menu_item">Загрузить на Picasa</resource>
|
||||
<resource name="upload_success">Изображение успешно загружено на Picasa!</resource>
|
||||
</resources>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Русский" ietf="ru-RU" version="1.1.0.2515" languagegroup="5">
|
||||
<resources>
|
||||
<resource name="communication_wait">Обмен данными с GooglePhotos. Подождите...</resource>
|
||||
<resource name="Configure">Настройка GooglePhotos</resource>
|
||||
<resource name="label_AfterUpload">После загрузки</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">Ссылки в буфер обмена</resource>
|
||||
<resource name="label_upload_format">Формат изображения</resource>
|
||||
<resource name="settings_title">Настройки GooglePhotos</resource>
|
||||
<resource name="upload_failure">Произошла ошибка при загрузке на GooglePhotos:</resource>
|
||||
<resource name="upload_menu_item">Загрузить на GooglePhotos</resource>
|
||||
<resource name="upload_success">Изображение успешно загружено на GooglePhotos!</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -1,14 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Српски" ietf="sr-RS" version="1.0.5" languagegroup="">
|
||||
<resources>
|
||||
<resource name="communication_wait">Комуницирам с Пикасом. Сачекајте…</resource>
|
||||
<resource name="Configure">Поставке Пикасе</resource>
|
||||
<resource name="label_AfterUpload">Након отпремања:</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">Веза ка остави</resource>
|
||||
<resource name="label_upload_format">Формат слике:</resource>
|
||||
<resource name="settings_title">Поставке Пикасе</resource>
|
||||
<resource name="upload_failure">Дошло је до грешке при отпремању на Пикасу:</resource>
|
||||
<resource name="upload_menu_item">Отпреми на Пикасу</resource>
|
||||
<resource name="upload_success">Слика је успешно отпремљена на Пикасу.</resource>
|
||||
</resources>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Српски" ietf="sr-RS" version="1.0.5" languagegroup="">
|
||||
<resources>
|
||||
<resource name="communication_wait">Комуницирам с Пикасом. Сачекајте…</resource>
|
||||
<resource name="Configure">Поставке Пикасе</resource>
|
||||
<resource name="label_AfterUpload">Након отпремања:</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">Веза ка остави</resource>
|
||||
<resource name="label_upload_format">Формат слике:</resource>
|
||||
<resource name="settings_title">Поставке Пикасе</resource>
|
||||
<resource name="upload_failure">Дошло је до грешке при отпремању на Пикасу:</resource>
|
||||
<resource name="upload_menu_item">Отпреми на Пикасу</resource>
|
||||
<resource name="upload_success">Слика је успешно отпремљена на Пикасу.</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -8,25 +8,25 @@
|
|||
Vid uppladdning
|
||||
</resource>
|
||||
<resource name="Configure">
|
||||
Konfigurera Picasa
|
||||
Konfigurera GooglePhotos
|
||||
</resource>
|
||||
<resource name="upload_menu_item">
|
||||
Ladda upp till Picasa
|
||||
Ladda upp till GooglePhotos
|
||||
</resource>
|
||||
<resource name="settings_title">
|
||||
Picasa-inställningar
|
||||
GooglePhotos-inställningar
|
||||
</resource>
|
||||
<resource name="upload_success">
|
||||
Skärmdumpen laddades upp till Picasa!
|
||||
Skärmdumpen laddades upp till GooglePhotos!
|
||||
</resource>
|
||||
<resource name="upload_failure">
|
||||
Ett fel uppstod vid uppladdning till Picasa:
|
||||
Ett fel uppstod vid uppladdning till GooglePhotos:
|
||||
</resource>
|
||||
<resource name="label_upload_format">
|
||||
Bildformat
|
||||
</resource>
|
||||
<resource name="communication_wait">
|
||||
Kommunicerar med Picasa. Vänta...
|
||||
Kommunicerar med GooglePhotos. Vänta...
|
||||
</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -1,14 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Українська" ietf="uk-UA" version="1.0.0">
|
||||
<resources>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">Посилання в буфер обміну</resource>
|
||||
<resource name="label_AfterUpload">Після вивантаження</resource>
|
||||
<resource name="Configure">Налаштувати Picasa</resource>
|
||||
<resource name="upload_menu_item">Вивантажити на Picasa</resource>
|
||||
<resource name="settings_title">Параметри Picasa</resource>
|
||||
<resource name="upload_success">Зображення вдало вивантажено на Picasa!</resource>
|
||||
<resource name="upload_failure">Відбулась помилка під час вивантаження на Picasa:</resource>
|
||||
<resource name="label_upload_format">Формат зображення</resource>
|
||||
<resource name="communication_wait">З’єднання з Picasa. Будь ласка, зачекайте...</resource>
|
||||
</resources>
|
||||
</language>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Українська" ietf="uk-UA" version="1.0.0">
|
||||
<resources>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">Посилання в буфер обміну</resource>
|
||||
<resource name="label_AfterUpload">Після вивантаження</resource>
|
||||
<resource name="Configure">Налаштувати GooglePhotos</resource>
|
||||
<resource name="upload_menu_item">Вивантажити на GooglePhotos</resource>
|
||||
<resource name="settings_title">Параметри GooglePhotos</resource>
|
||||
<resource name="upload_success">Зображення вдало вивантажено на GooglePhotos!</resource>
|
||||
<resource name="upload_failure">Відбулась помилка під час вивантаження на GooglePhotos:</resource>
|
||||
<resource name="label_upload_format">Формат зображення</resource>
|
||||
<resource name="communication_wait">З’єднання з GooglePhotos. Будь ласка, зачекайте...</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="简体中文" ietf="zh-CN" version="1.0.3" languagegroup="a">
|
||||
<resources>
|
||||
<resource name="communication_wait">正在连接到GooglePhotos。请稍后...</resource>
|
||||
<resource name="Configure">配置 GooglePhotos</resource>
|
||||
<resource name="label_AfterUpload">上传之后</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">复制链接到剪贴板</resource>
|
||||
<resource name="label_upload_format">图片格式</resource>
|
||||
<resource name="settings_title">GooglePhotos设置</resource>
|
||||
<resource name="upload_failure">上传到GooglePhotos时发生错误:</resource>
|
||||
<resource name="upload_menu_item">上传到GooglePhotos</resource>
|
||||
<resource name="upload_success">图片已成功上传到了GooglePhotos!</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="正體中文" ietf="zh-TW" version="1.0.0" languagegroup="9">
|
||||
<resources>
|
||||
<resource name="communication_wait">正在與 GooglePhotos 通訊,請稍候...</resource>
|
||||
<resource name="Configure">組態 GooglePhotos</resource>
|
||||
<resource name="label_AfterUpload">上傳後</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">連結到剪貼簿</resource>
|
||||
<resource name="label_upload_format">圖片格式</resource>
|
||||
<resource name="settings_title">GooglePhotos 設定</resource>
|
||||
<resource name="upload_failure">上傳到 GooglePhotos 時發生錯誤:</resource>
|
||||
<resource name="upload_menu_item">上傳到 GooglePhotos</resource>
|
||||
<resource name="upload_success">上傳圖片到 GooglePhotos 成功!</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -25,7 +25,7 @@ using System.Runtime.InteropServices;
|
|||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyDescription("A plugin to upload images to Picasa")]
|
||||
[assembly: AssemblyDescription("A plugin to upload images to GooglePhotos")]
|
||||
|
||||
// This sets the default COM visibility of types in the assembly to invisible.
|
||||
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
|
|
@ -25,7 +25,7 @@ namespace GreenshotImgurPlugin {
|
|||
/// You can set your own values here
|
||||
/// </summary>
|
||||
public static class ImgurCredentials {
|
||||
public static string CONSUMER_KEY = "${Imgur_ClientId}";
|
||||
public static string CONSUMER_SECRET = "${Imgur_ClientSecret}";
|
||||
public static string CONSUMER_KEY = "${Imgur13_ClientId}";
|
||||
public static string CONSUMER_SECRET = "${Imgur13_ClientSecret}";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@
|
|||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using GreenshotPlugin.Core;
|
||||
using GreenshotPlugin.Core.OAuth;
|
||||
using GreenshotPlugin.IniFile;
|
||||
using GreenshotPlugin.Interfaces;
|
||||
using GreenshotPlugin.Interfaces.Plugin;
|
||||
|
@ -37,10 +37,8 @@ namespace GreenshotImgurPlugin {
|
|||
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurUtils));
|
||||
private const string SmallUrlPattern = "http://i.imgur.com/{0}s.jpg";
|
||||
private static readonly ImgurConfiguration Config = IniConfig.GetIniSection<ImgurConfiguration>();
|
||||
private const string AuthUrlPattern = "https://api.imgur.com/oauth2/authorize?response_type=token&client_id={ClientId}&state={State}";
|
||||
private const string TokenUrl = "https://api.imgur.com/oauth2/token";
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Check if we need to load the history
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
|
@ -162,20 +160,20 @@ namespace GreenshotImgurPlugin {
|
|||
responseString = reader.ReadToEnd();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.Error("Upload to imgur gave an exeption: ", ex);
|
||||
Log.Error("Upload to imgur gave an exception: ", ex);
|
||||
throw;
|
||||
}
|
||||
} else {
|
||||
|
||||
var oauth2Settings = new OAuth2Settings
|
||||
{
|
||||
AuthUrlPattern = AuthUrlPattern,
|
||||
TokenUrl = TokenUrl,
|
||||
RedirectUrl = "https://getgreenshot.org/oauth/imgur",
|
||||
AuthUrlPattern = "https://api.imgur.com/oauth2/authorize?response_type=token&client_id={ClientId}&state={State}",
|
||||
TokenUrl = "https://api.imgur.com/oauth2/token",
|
||||
RedirectUrl = "https://getgreenshot.org/authorize/imgur",
|
||||
CloudServiceName = "Imgur",
|
||||
ClientId = ImgurCredentials.CONSUMER_KEY,
|
||||
ClientSecret = ImgurCredentials.CONSUMER_SECRET,
|
||||
AuthorizeMode = OAuth2AuthorizeMode.OutOfBoundAuto,
|
||||
AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver,
|
||||
RefreshToken = Config.RefreshToken,
|
||||
AccessToken = Config.AccessToken,
|
||||
AccessTokenExpires = Config.AccessTokenExpires
|
||||
|
@ -221,7 +219,7 @@ namespace GreenshotImgurPlugin {
|
|||
Log.InfoFormat("Retrieving Imgur image for {0} with url {1}", imgurInfo.Hash, imgurInfo.SmallSquare);
|
||||
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(string.Format(SmallUrlPattern, imgurInfo.Hash), HTTPMethod.GET);
|
||||
webRequest.ServicePoint.Expect100Continue = false;
|
||||
// Not for getting the thumbnail, in anonymous modus
|
||||
// Not for getting the thumbnail, in anonymous mode
|
||||
//SetClientId(webRequest);
|
||||
using WebResponse response = webRequest.GetResponse();
|
||||
LogRateLimitInfo(response);
|
||||
|
@ -304,7 +302,7 @@ namespace GreenshotImgurPlugin {
|
|||
}
|
||||
}
|
||||
}
|
||||
// Make sure we remove it from the history, if no error occured
|
||||
// Make sure we remove it from the history, if no error occurred
|
||||
Config.runtimeImgurHistory.Remove(imgurInfo.Hash);
|
||||
Config.ImgurUploadHistory.Remove(imgurInfo.Hash);
|
||||
imgurInfo.Image = null;
|
||||
|
|
|
@ -24,6 +24,7 @@ using System.Collections.Generic;
|
|||
using System.Drawing;
|
||||
using System.Xml;
|
||||
using GreenshotPlugin.Core;
|
||||
using GreenshotPlugin.Core.OAuth;
|
||||
using GreenshotPlugin.IniFile;
|
||||
using GreenshotPlugin.Interfaces;
|
||||
using GreenshotPlugin.Interfaces.Plugin;
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="日本語" ietf="ja-JP" version="1.0.0">
|
||||
<resources>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">リンクをクリップボードへコピー</resource>
|
||||
<resource name="label_AfterUpload">アップロード後</resource>
|
||||
<resource name="Configure">Picasa の設定</resource>
|
||||
<resource name="upload_menu_item">Picasa にアップロード</resource>
|
||||
<resource name="settings_title">Picasa の設定</resource>
|
||||
<resource name="upload_success">Picasa へのアップロードに成功しました!</resource>
|
||||
<resource name="upload_failure">Picasa へのアップロード中にエラーが発生しました:</resource>
|
||||
<resource name="label_upload_format">画像フォーマット</resource>
|
||||
<resource name="communication_wait">Picasa に接続中です。しばらくお待ち下さい...</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="Polski" ietf="pl-PL" version="1.1.4" languagegroup="2">
|
||||
<resources>
|
||||
<resource name="communication_wait">Trwa komunikacja z Picasa. Proszę czekać...</resource>
|
||||
<resource name="Configure">Konfiguruj Picasa</resource>
|
||||
<resource name="label_AfterUpload">Po wysłaniu</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">Link do schowka</resource>
|
||||
<resource name="label_upload_format">Format obrazów</resource>
|
||||
<resource name="settings_title">Ustawienia Picasa</resource>
|
||||
<resource name="upload_failure">Wystąpił błąd przy wysyłaniu do Picasa:</resource>
|
||||
<resource name="upload_menu_item">Wyślij do Picasa</resource>
|
||||
<resource name="upload_success">Wysyłanie obrazu do Picasa powiodło się!</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="简体中文" ietf="zh-CN" version="1.0.3" languagegroup="a">
|
||||
<resources>
|
||||
<resource name="communication_wait">正在连接到Picasa。请稍后...</resource>
|
||||
<resource name="Configure">配置 Picasa</resource>
|
||||
<resource name="label_AfterUpload">上传之后</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">复制链接到剪贴板</resource>
|
||||
<resource name="label_upload_format">图片格式</resource>
|
||||
<resource name="settings_title">Picasa设置</resource>
|
||||
<resource name="upload_failure">上传到Picasa时发生错误:</resource>
|
||||
<resource name="upload_menu_item">上传到Picasa</resource>
|
||||
<resource name="upload_success">图片已成功上传到了Picasa!</resource>
|
||||
</resources>
|
||||
</language>
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<language description="正體中文" ietf="zh-TW" version="1.0.0" languagegroup="9">
|
||||
<resources>
|
||||
<resource name="communication_wait">正在與 Picasa 通訊,請稍候...</resource>
|
||||
<resource name="Configure">組態 Picasa</resource>
|
||||
<resource name="label_AfterUpload">上傳後</resource>
|
||||
<resource name="label_AfterUploadLinkToClipBoard">連結到剪貼簿</resource>
|
||||
<resource name="label_upload_format">圖片格式</resource>
|
||||
<resource name="settings_title">Picasa 設定</resource>
|
||||
<resource name="upload_failure">上傳到 Picasa 時發生錯誤:</resource>
|
||||
<resource name="upload_menu_item">上傳到 Picasa</resource>
|
||||
<resource name="upload_success">上傳圖片到 Picasa 成功!</resource>
|
||||
</resources>
|
||||
</language>
|
Binary file not shown.
Before Width: | Height: | Size: 4.8 KiB |
|
@ -1,20 +1,20 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
@ -32,9 +32,8 @@ namespace GreenshotPlugin.Controls {
|
|||
public sealed partial class OAuthLoginForm : Form {
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(OAuthLoginForm));
|
||||
private readonly string _callbackUrl;
|
||||
private IDictionary<string, string> _callbackParameters;
|
||||
|
||||
public IDictionary<string, string> CallbackParameters => _callbackParameters;
|
||||
|
||||
public IDictionary<string, string> CallbackParameters { get; private set; }
|
||||
|
||||
public bool IsOk => DialogResult == DialogResult.OK;
|
||||
|
||||
|
@ -94,7 +93,7 @@ namespace GreenshotPlugin.Controls {
|
|||
if (queryParams.Length > 0) {
|
||||
queryParams = NetworkHelper.UrlDecode(queryParams);
|
||||
//Store the Token and Token Secret
|
||||
_callbackParameters = NetworkHelper.ParseQueryString(queryParams);
|
||||
CallbackParameters = NetworkHelper.ParseQueryString(queryParams);
|
||||
}
|
||||
DialogResult = DialogResult.OK;
|
||||
}
|
||||
|
@ -102,7 +101,7 @@ namespace GreenshotPlugin.Controls {
|
|||
|
||||
private void AddressTextBox_KeyPress(object sender, KeyPressEventArgs e) {
|
||||
//Cancel the key press so the user can't enter a new url
|
||||
e.Handled = true;
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
793
GreenshotPlugin/Core/EnvironmentInfo.cs
Normal file
793
GreenshotPlugin/Core/EnvironmentInfo.cs
Normal file
|
@ -0,0 +1,793 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using GreenshotPlugin.IniFile;
|
||||
using GreenshotPlugin.UnmanagedHelpers;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace GreenshotPlugin.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of EnvironmentInfo.
|
||||
/// </summary>
|
||||
public static class EnvironmentInfo
|
||||
{
|
||||
private static bool? _isWindows;
|
||||
|
||||
public static bool IsWindows
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_isWindows.HasValue)
|
||||
{
|
||||
return _isWindows.Value;
|
||||
}
|
||||
_isWindows = Environment.OSVersion.Platform.ToString().StartsWith("Win");
|
||||
return _isWindows.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsNet45OrNewer()
|
||||
{
|
||||
// Class "ReflectionContext" exists from .NET 4.5 onwards.
|
||||
return Type.GetType("System.Reflection.ReflectionContext", false) != null;
|
||||
}
|
||||
|
||||
public static string GetGreenshotVersion(bool shortVersion = false)
|
||||
{
|
||||
var executingAssembly = Assembly.GetExecutingAssembly();
|
||||
|
||||
// Use assembly version
|
||||
string greenshotVersion = executingAssembly.GetName().Version.ToString();
|
||||
|
||||
// Use AssemblyFileVersion if available
|
||||
var assemblyFileVersionAttribute = executingAssembly.GetCustomAttribute<AssemblyFileVersionAttribute>();
|
||||
if (!string.IsNullOrEmpty(assemblyFileVersionAttribute?.Version))
|
||||
{
|
||||
var assemblyFileVersion = new Version(assemblyFileVersionAttribute.Version);
|
||||
greenshotVersion = assemblyFileVersion.ToString(3);
|
||||
}
|
||||
|
||||
if (!shortVersion)
|
||||
{
|
||||
// Use AssemblyInformationalVersion if available
|
||||
var informationalVersionAttribute = executingAssembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
|
||||
if (!string.IsNullOrEmpty(informationalVersionAttribute?.InformationalVersion))
|
||||
{
|
||||
greenshotVersion = informationalVersionAttribute.InformationalVersion;
|
||||
}
|
||||
}
|
||||
|
||||
return greenshotVersion.Replace("+", " - ");
|
||||
}
|
||||
|
||||
public static string EnvironmentToString(bool newline)
|
||||
{
|
||||
StringBuilder environment = new StringBuilder();
|
||||
environment.Append("Software version: " + GetGreenshotVersion());
|
||||
if (IniConfig.IsPortable) {
|
||||
environment.Append(" Portable");
|
||||
}
|
||||
environment.Append(" (" + OsInfo.Bits + " bit)");
|
||||
|
||||
if (newline)
|
||||
{
|
||||
environment.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
environment.Append(", ");
|
||||
}
|
||||
environment.Append(".NET runtime version: " + Environment.Version);
|
||||
if (IsNet45OrNewer())
|
||||
{
|
||||
environment.Append("+");
|
||||
|
||||
}
|
||||
if (newline)
|
||||
{
|
||||
environment.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
environment.Append(", ");
|
||||
}
|
||||
environment.Append("Time: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss zzz"));
|
||||
|
||||
if (IsWindows)
|
||||
{
|
||||
if (newline)
|
||||
{
|
||||
environment.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
environment.Append(", ");
|
||||
}
|
||||
|
||||
environment.Append($"OS: {OsInfo.Name}");
|
||||
if (!string.IsNullOrEmpty(OsInfo.Edition))
|
||||
{
|
||||
environment.Append($" {OsInfo.Edition}");
|
||||
|
||||
}
|
||||
if (!string.IsNullOrEmpty(OsInfo.ServicePack))
|
||||
{
|
||||
environment.Append($" {OsInfo.ServicePack}");
|
||||
|
||||
}
|
||||
environment.Append($" x{OsInfo.Bits}");
|
||||
environment.Append($" {OsInfo.VersionString}");
|
||||
if (newline)
|
||||
{
|
||||
environment.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
environment.Append(", ");
|
||||
}
|
||||
// Get some important information for fixing GDI related Problems
|
||||
environment.AppendFormat("GDI object count: {0}", User32.GetGuiResourcesGDICount());
|
||||
if (newline)
|
||||
{
|
||||
environment.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
environment.Append(", ");
|
||||
}
|
||||
environment.AppendFormat("User object count: {0}", User32.GetGuiResourcesUserCount());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newline)
|
||||
{
|
||||
environment.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
environment.Append(", ");
|
||||
}
|
||||
environment.AppendFormat("OS: {0}", Environment.OSVersion.Platform);
|
||||
}
|
||||
if (newline)
|
||||
{
|
||||
environment.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
environment.Append(", ");
|
||||
}
|
||||
// TODO: Is this needed?
|
||||
// environment.AppendFormat("Surface count: {0}", Surface.Count);
|
||||
|
||||
return environment.ToString();
|
||||
}
|
||||
|
||||
public static string ExceptionToString(Exception ex)
|
||||
{
|
||||
if (ex == null)
|
||||
return "null\r\n";
|
||||
|
||||
StringBuilder report = new StringBuilder();
|
||||
|
||||
report.AppendLine("Exception: " + ex.GetType());
|
||||
report.AppendLine("Message: " + ex.Message);
|
||||
if (ex.Data.Count > 0)
|
||||
{
|
||||
report.AppendLine();
|
||||
report.AppendLine("Additional Information:");
|
||||
foreach (object key in ex.Data.Keys)
|
||||
{
|
||||
object data = ex.Data[key];
|
||||
if (data != null)
|
||||
{
|
||||
report.AppendLine(key + " : " + data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ex is ExternalException externalException)
|
||||
{
|
||||
// e.g. COMException
|
||||
report.AppendLine().AppendLine("ErrorCode: 0x" + externalException.ErrorCode.ToString("X"));
|
||||
}
|
||||
|
||||
report.AppendLine().AppendLine("Stack:").AppendLine(ex.StackTrace);
|
||||
|
||||
if (ex is ReflectionTypeLoadException reflectionTypeLoadException)
|
||||
{
|
||||
report.AppendLine().AppendLine("LoaderExceptions: ");
|
||||
foreach (Exception cbE in reflectionTypeLoadException.LoaderExceptions)
|
||||
{
|
||||
report.AppendLine(cbE.Message);
|
||||
}
|
||||
}
|
||||
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
report.AppendLine("--- InnerException: ---");
|
||||
report.AppendLine(ExceptionToString(ex.InnerException));
|
||||
}
|
||||
return report.ToString();
|
||||
}
|
||||
|
||||
public static string BuildReport(Exception exception)
|
||||
{
|
||||
StringBuilder exceptionText = new StringBuilder();
|
||||
exceptionText.AppendLine(EnvironmentToString(true));
|
||||
exceptionText.AppendLine(ExceptionToString(exception));
|
||||
exceptionText.AppendLine("Configuration dump:");
|
||||
|
||||
return exceptionText.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides detailed information about the host operating system.
|
||||
/// Code is available at: http://www.csharp411.com/determine-windows-version-and-edition-with-c/
|
||||
/// </summary>
|
||||
public static class OsInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines if the current application is 32 or 64-bit.
|
||||
/// </summary>
|
||||
public static int Bits => IntPtr.Size * 8;
|
||||
|
||||
private static string _sEdition;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the edition of the operating system running on this computer.
|
||||
/// </summary>
|
||||
public static string Edition
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_sEdition != null)
|
||||
{
|
||||
return _sEdition; //***** RETURN *****//
|
||||
}
|
||||
|
||||
string edition = string.Empty;
|
||||
|
||||
OperatingSystem osVersion = Environment.OSVersion;
|
||||
OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create();
|
||||
|
||||
if (GetVersionEx(ref osVersionInfo))
|
||||
{
|
||||
int majorVersion = osVersion.Version.Major;
|
||||
int minorVersion = osVersion.Version.Minor;
|
||||
byte productType = osVersionInfo.ProductType;
|
||||
ushort suiteMask = osVersionInfo.SuiteMask;
|
||||
|
||||
if (majorVersion == 4)
|
||||
{
|
||||
if (productType == VER_NT_WORKSTATION)
|
||||
{
|
||||
// Windows NT 4.0 Workstation
|
||||
edition = "Workstation";
|
||||
}
|
||||
else if (productType == VER_NT_SERVER)
|
||||
{
|
||||
edition = (suiteMask & VER_SUITE_ENTERPRISE) != 0 ? "Enterprise Server" : "Standard Server";
|
||||
}
|
||||
}
|
||||
|
||||
else if (majorVersion == 5)
|
||||
{
|
||||
if (productType == VER_NT_WORKSTATION)
|
||||
{
|
||||
if ((suiteMask & VER_SUITE_PERSONAL) != 0)
|
||||
{
|
||||
// Windows XP Home Edition
|
||||
edition = "Home";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Windows XP / Windows 2000 Professional
|
||||
edition = "Professional";
|
||||
}
|
||||
}
|
||||
else if (productType == VER_NT_SERVER)
|
||||
{
|
||||
if (minorVersion == 0)
|
||||
{
|
||||
if ((suiteMask & VER_SUITE_DATACENTER) != 0)
|
||||
{
|
||||
// Windows 2000 Datacenter Server
|
||||
edition = "Datacenter Server";
|
||||
}
|
||||
else if ((suiteMask & VER_SUITE_ENTERPRISE) != 0)
|
||||
{
|
||||
// Windows 2000 Advanced Server
|
||||
edition = "Advanced Server";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Windows 2000 Server
|
||||
edition = "Server";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((suiteMask & VER_SUITE_DATACENTER) != 0)
|
||||
{
|
||||
// Windows Server 2003 Datacenter Edition
|
||||
edition = "Datacenter";
|
||||
}
|
||||
else if ((suiteMask & VER_SUITE_ENTERPRISE) != 0)
|
||||
{
|
||||
// Windows Server 2003 Enterprise Edition
|
||||
edition = "Enterprise";
|
||||
}
|
||||
else if ((suiteMask & VER_SUITE_BLADE) != 0)
|
||||
{
|
||||
// Windows Server 2003 Web Edition
|
||||
edition = "Web Edition";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Windows Server 2003 Standard Edition
|
||||
edition = "Standard";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (majorVersion == 6)
|
||||
{
|
||||
if (GetProductInfo(majorVersion, minorVersion, osVersionInfo.ServicePackMajor, osVersionInfo.ServicePackMinor, out var ed))
|
||||
{
|
||||
switch (ed)
|
||||
{
|
||||
case PRODUCT_BUSINESS:
|
||||
edition = "Business";
|
||||
break;
|
||||
case PRODUCT_BUSINESS_N:
|
||||
edition = "Business N";
|
||||
break;
|
||||
case PRODUCT_CLUSTER_SERVER:
|
||||
edition = "HPC Edition";
|
||||
break;
|
||||
case PRODUCT_DATACENTER_SERVER:
|
||||
edition = "Datacenter Server";
|
||||
break;
|
||||
case PRODUCT_DATACENTER_SERVER_CORE:
|
||||
edition = "Datacenter Server (core installation)";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE:
|
||||
edition = "Enterprise";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_N:
|
||||
edition = "Enterprise N";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER:
|
||||
edition = "Enterprise Server";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_CORE:
|
||||
edition = "Enterprise Server (core installation)";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_CORE_V:
|
||||
edition = "Enterprise Server without Hyper-V (core installation)";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_IA64:
|
||||
edition = "Enterprise Server for Itanium-based Systems";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_V:
|
||||
edition = "Enterprise Server without Hyper-V";
|
||||
break;
|
||||
case PRODUCT_HOME_BASIC:
|
||||
edition = "Home Basic";
|
||||
break;
|
||||
case PRODUCT_HOME_BASIC_N:
|
||||
edition = "Home Basic N";
|
||||
break;
|
||||
case PRODUCT_HOME_PREMIUM:
|
||||
edition = "Home Premium";
|
||||
break;
|
||||
case PRODUCT_HOME_PREMIUM_N:
|
||||
edition = "Home Premium N";
|
||||
break;
|
||||
case PRODUCT_HYPERV:
|
||||
edition = "Microsoft Hyper-V Server";
|
||||
break;
|
||||
case PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT:
|
||||
edition = "Windows Essential Business Management Server";
|
||||
break;
|
||||
case PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING:
|
||||
edition = "Windows Essential Business Messaging Server";
|
||||
break;
|
||||
case PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY:
|
||||
edition = "Windows Essential Business Security Server";
|
||||
break;
|
||||
case PRODUCT_SERVER_FOR_SMALLBUSINESS:
|
||||
edition = "Windows Essential Server Solutions";
|
||||
break;
|
||||
case PRODUCT_SERVER_FOR_SMALLBUSINESS_V:
|
||||
edition = "Windows Essential Server Solutions without Hyper-V";
|
||||
break;
|
||||
case PRODUCT_SMALLBUSINESS_SERVER:
|
||||
edition = "Windows Small Business Server";
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER:
|
||||
edition = "Standard Server";
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER_CORE:
|
||||
edition = "Standard Server (core installation)";
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER_CORE_V:
|
||||
edition = "Standard Server without Hyper-V (core installation)";
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER_V:
|
||||
edition = "Standard Server without Hyper-V";
|
||||
break;
|
||||
case PRODUCT_STARTER:
|
||||
edition = "Starter";
|
||||
break;
|
||||
case PRODUCT_STORAGE_ENTERPRISE_SERVER:
|
||||
edition = "Enterprise Storage Server";
|
||||
break;
|
||||
case PRODUCT_STORAGE_EXPRESS_SERVER:
|
||||
edition = "Express Storage Server";
|
||||
break;
|
||||
case PRODUCT_STORAGE_STANDARD_SERVER:
|
||||
edition = "Standard Storage Server";
|
||||
break;
|
||||
case PRODUCT_STORAGE_WORKGROUP_SERVER:
|
||||
edition = "Workgroup Storage Server";
|
||||
break;
|
||||
case PRODUCT_UNDEFINED:
|
||||
edition = "Unknown product";
|
||||
break;
|
||||
case PRODUCT_ULTIMATE:
|
||||
edition = "Ultimate";
|
||||
break;
|
||||
case PRODUCT_ULTIMATE_N:
|
||||
edition = "Ultimate N";
|
||||
break;
|
||||
case PRODUCT_WEB_SERVER:
|
||||
edition = "Web Server";
|
||||
break;
|
||||
case PRODUCT_WEB_SERVER_CORE:
|
||||
edition = "Web Server (core installation)";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_sEdition = edition;
|
||||
return edition;
|
||||
}
|
||||
}
|
||||
|
||||
private static string _name;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the operating system running on this computer.
|
||||
/// </summary>
|
||||
public static string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_name != null)
|
||||
{
|
||||
return _name; //***** RETURN *****//
|
||||
}
|
||||
|
||||
string name = "unknown";
|
||||
|
||||
OperatingSystem osVersion = Environment.OSVersion;
|
||||
OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create();
|
||||
if (GetVersionEx(ref osVersionInfo))
|
||||
{
|
||||
int majorVersion = osVersion.Version.Major;
|
||||
int minorVersion = osVersion.Version.Minor;
|
||||
byte productType = osVersionInfo.ProductType;
|
||||
ushort suiteMask = osVersionInfo.SuiteMask;
|
||||
switch (osVersion.Platform)
|
||||
{
|
||||
case PlatformID.Win32Windows:
|
||||
if (majorVersion == 4)
|
||||
{
|
||||
string csdVersion = osVersionInfo.ServicePackVersion;
|
||||
switch (minorVersion)
|
||||
{
|
||||
case 0:
|
||||
if (csdVersion == "B" || csdVersion == "C")
|
||||
{
|
||||
name = "Windows 95 OSR2";
|
||||
}
|
||||
else
|
||||
{
|
||||
name = "Windows 95";
|
||||
}
|
||||
|
||||
break;
|
||||
case 10:
|
||||
name = csdVersion == "A" ? "Windows 98 Second Edition" : "Windows 98";
|
||||
break;
|
||||
case 90:
|
||||
name = "Windows Me";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case PlatformID.Win32NT:
|
||||
switch (majorVersion)
|
||||
{
|
||||
case 3:
|
||||
name = "Windows NT 3.51";
|
||||
break;
|
||||
case 4:
|
||||
switch (productType)
|
||||
{
|
||||
case 1:
|
||||
name = "Windows NT 4.0";
|
||||
break;
|
||||
case 3:
|
||||
name = "Windows NT 4.0 Server";
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case 5:
|
||||
switch (minorVersion)
|
||||
{
|
||||
case 0:
|
||||
name = "Windows 2000";
|
||||
break;
|
||||
case 1:
|
||||
name = suiteMask switch
|
||||
{
|
||||
0x0200 => "Windows XP Professional",
|
||||
_ => "Windows XP"
|
||||
};
|
||||
break;
|
||||
case 2:
|
||||
name = suiteMask switch
|
||||
{
|
||||
0x0200 => "Windows XP Professional x64",
|
||||
0x0002 => "Windows Server 2003 Enterprise",
|
||||
0x0080 => "Windows Server 2003 Data Center",
|
||||
0x0400 => "Windows Server 2003 Web Edition",
|
||||
0x8000 => "Windows Home Server",
|
||||
_ => "Windows Server 2003"
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case 6:
|
||||
switch (minorVersion)
|
||||
{
|
||||
case 0:
|
||||
name = productType switch
|
||||
{
|
||||
3 => "Windows Server 2008",
|
||||
_ => "Windows Vista"
|
||||
};
|
||||
break;
|
||||
case 1:
|
||||
name = productType switch
|
||||
{
|
||||
3 => "Windows Server 2008 R2",
|
||||
_ => "Windows 7"
|
||||
};
|
||||
break;
|
||||
case 2:
|
||||
name = "Windows 8";
|
||||
break;
|
||||
case 3:
|
||||
name = "Windows 8.1";
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case 10:
|
||||
string releaseId = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ReleaseId", "").ToString();
|
||||
name = $"Windows 10 {releaseId}";
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_name = name;
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("Kernel32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool GetProductInfo(
|
||||
int osMajorVersion,
|
||||
int osMinorVersion,
|
||||
int spMajorVersion,
|
||||
int spMinorVersion,
|
||||
out int edition);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool GetVersionEx(ref OSVERSIONINFOEX osVersionInfo);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
private unsafe struct OSVERSIONINFOEX
|
||||
{
|
||||
/// <summary>
|
||||
/// The size of this data structure, in bytes. Set this member to sizeof(OSVERSIONINFOEX).
|
||||
/// </summary>
|
||||
private int _dwOSVersionInfoSize;
|
||||
|
||||
private readonly int _dwMajorVersion;
|
||||
private readonly int _dwMinorVersion;
|
||||
private readonly int _dwBuildNumber;
|
||||
private readonly int _dwPlatformId;
|
||||
private fixed char _szCSDVersion[128];
|
||||
private readonly short _wServicePackMajor;
|
||||
private readonly short _wServicePackMinor;
|
||||
private readonly ushort _wSuiteMask;
|
||||
private readonly byte _wProductType;
|
||||
private readonly byte _wReserved;
|
||||
|
||||
/// A null-terminated string, such as "Service Pack 3", that indicates the latest Service Pack installed on the system.
|
||||
/// If no Service Pack has been installed, the string is empty.
|
||||
/// </summary>
|
||||
public string ServicePackVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (char* servicePackVersion = _szCSDVersion)
|
||||
{
|
||||
return new string(servicePackVersion);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The major version number of the latest Service Pack installed on the system. For example, for Service Pack 3, the
|
||||
/// major version number is 3.
|
||||
/// If no Service Pack has been installed, the value is zero.
|
||||
/// </summary>
|
||||
public short ServicePackMajor => _wServicePackMajor;
|
||||
|
||||
/// <summary>
|
||||
/// The minor version number of the latest Service Pack installed on the system. For example, for Service Pack 3, the
|
||||
/// minor version number is 0.
|
||||
/// </summary>
|
||||
public short ServicePackMinor => _wServicePackMinor;
|
||||
|
||||
/// <summary>
|
||||
/// A bit mask that identifies the product suites available on the system. This member can be a combination of the
|
||||
/// following values.
|
||||
/// </summary>
|
||||
public ushort SuiteMask => _wSuiteMask;
|
||||
|
||||
/// <summary>
|
||||
/// Any additional information about the system.
|
||||
/// </summary>
|
||||
public byte ProductType => _wProductType;
|
||||
|
||||
/// <summary>
|
||||
/// Factory for an empty OsVersionInfoEx
|
||||
/// </summary>
|
||||
/// <returns>OSVERSIONINFOEX</returns>
|
||||
public static OSVERSIONINFOEX Create()
|
||||
{
|
||||
return new OSVERSIONINFOEX
|
||||
{
|
||||
_dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEX))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private const int PRODUCT_UNDEFINED = 0x00000000;
|
||||
private const int PRODUCT_ULTIMATE = 0x00000001;
|
||||
private const int PRODUCT_HOME_BASIC = 0x00000002;
|
||||
private const int PRODUCT_HOME_PREMIUM = 0x00000003;
|
||||
private const int PRODUCT_ENTERPRISE = 0x00000004;
|
||||
private const int PRODUCT_HOME_BASIC_N = 0x00000005;
|
||||
private const int PRODUCT_BUSINESS = 0x00000006;
|
||||
private const int PRODUCT_STANDARD_SERVER = 0x00000007;
|
||||
private const int PRODUCT_DATACENTER_SERVER = 0x00000008;
|
||||
private const int PRODUCT_SMALLBUSINESS_SERVER = 0x00000009;
|
||||
private const int PRODUCT_ENTERPRISE_SERVER = 0x0000000A;
|
||||
private const int PRODUCT_STARTER = 0x0000000B;
|
||||
private const int PRODUCT_DATACENTER_SERVER_CORE = 0x0000000C;
|
||||
private const int PRODUCT_STANDARD_SERVER_CORE = 0x0000000D;
|
||||
private const int PRODUCT_ENTERPRISE_SERVER_CORE = 0x0000000E;
|
||||
private const int PRODUCT_ENTERPRISE_SERVER_IA64 = 0x0000000F;
|
||||
private const int PRODUCT_BUSINESS_N = 0x00000010;
|
||||
private const int PRODUCT_WEB_SERVER = 0x00000011;
|
||||
private const int PRODUCT_CLUSTER_SERVER = 0x00000012;
|
||||
private const int PRODUCT_STORAGE_EXPRESS_SERVER = 0x00000014;
|
||||
private const int PRODUCT_STORAGE_STANDARD_SERVER = 0x00000015;
|
||||
private const int PRODUCT_STORAGE_WORKGROUP_SERVER = 0x00000016;
|
||||
private const int PRODUCT_STORAGE_ENTERPRISE_SERVER = 0x00000017;
|
||||
private const int PRODUCT_SERVER_FOR_SMALLBUSINESS = 0x00000018;
|
||||
private const int PRODUCT_HOME_PREMIUM_N = 0x0000001A;
|
||||
private const int PRODUCT_ENTERPRISE_N = 0x0000001B;
|
||||
private const int PRODUCT_ULTIMATE_N = 0x0000001C;
|
||||
private const int PRODUCT_WEB_SERVER_CORE = 0x0000001D;
|
||||
private const int PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E;
|
||||
private const int PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F;
|
||||
private const int PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020;
|
||||
private const int PRODUCT_SERVER_FOR_SMALLBUSINESS_V = 0x00000023;
|
||||
private const int PRODUCT_STANDARD_SERVER_V = 0x00000024;
|
||||
private const int PRODUCT_ENTERPRISE_SERVER_V = 0x00000026;
|
||||
private const int PRODUCT_STANDARD_SERVER_CORE_V = 0x00000028;
|
||||
private const int PRODUCT_ENTERPRISE_SERVER_CORE_V = 0x00000029;
|
||||
private const int PRODUCT_HYPERV = 0x0000002A;
|
||||
|
||||
private const int VER_NT_WORKSTATION = 1;
|
||||
private const int VER_NT_SERVER = 3;
|
||||
private const int VER_SUITE_ENTERPRISE = 2;
|
||||
private const int VER_SUITE_DATACENTER = 128;
|
||||
private const int VER_SUITE_PERSONAL = 512;
|
||||
private const int VER_SUITE_BLADE = 1024;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the service pack information of the operating system running on this computer.
|
||||
/// </summary>
|
||||
public static string ServicePack
|
||||
{
|
||||
get
|
||||
{
|
||||
string servicePack = string.Empty;
|
||||
OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create();
|
||||
|
||||
if (GetVersionEx(ref osVersionInfo))
|
||||
{
|
||||
servicePack = osVersionInfo.ServicePackVersion;
|
||||
}
|
||||
|
||||
return servicePack;
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the full version string of the operating system running on this computer.
|
||||
/// </summary>
|
||||
public static string VersionString
|
||||
{
|
||||
get
|
||||
{
|
||||
if (WindowsVersion.IsWindows10OrLater)
|
||||
{
|
||||
return $"build {Environment.OSVersion.Version.Build}";
|
||||
}
|
||||
|
||||
if (Environment.OSVersion.Version.Revision != 0)
|
||||
{
|
||||
return
|
||||
$"{Environment.OSVersion.Version.Major}.{Environment.OSVersion.Version.Minor} build {Environment.OSVersion.Version.Build} revision {Environment.OSVersion.Version.Revision:X}";
|
||||
}
|
||||
|
||||
return $"{Environment.OSVersion.Version.Major}.{Environment.OSVersion.Version.Minor} build {Environment.OSVersion.Version.Build}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
191
GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs
Normal file
191
GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs
Normal file
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GreenshotPlugin.Core.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// OAuth 2.0 verification code receiver that runs a local server on a free port
|
||||
/// and waits for a call with the authorization verification code.
|
||||
/// </summary>
|
||||
public class LocalJsonReceiver
|
||||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(LocalJsonReceiver));
|
||||
private readonly ManualResetEvent _ready = new ManualResetEvent(true);
|
||||
private IDictionary<string, string> _returnValues;
|
||||
|
||||
/// <summary>
|
||||
/// The url format for the website to post to. Expects one port parameter.
|
||||
/// Default: http://localhost:{0}/authorize/
|
||||
/// </summary>
|
||||
public string ListeningUrlFormat { get; set; } = "http://localhost:{0}/authorize/";
|
||||
|
||||
private string _listeningUri;
|
||||
/// <summary>
|
||||
/// The URL where the server is listening
|
||||
/// </summary>
|
||||
public string ListeningUri {
|
||||
get {
|
||||
if (string.IsNullOrEmpty(_listeningUri))
|
||||
{
|
||||
_listeningUri = string.Format(ListeningUrlFormat, GetRandomUnusedPort());
|
||||
}
|
||||
return _listeningUri;
|
||||
}
|
||||
set => _listeningUri = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This action is called when the URI must be opened, default is just to run Process.Start
|
||||
/// </summary>
|
||||
public Action<string> OpenUriAction
|
||||
{
|
||||
set;
|
||||
get;
|
||||
} = authorizationUrl =>
|
||||
{
|
||||
Log.DebugFormat("Open a browser with: {0}", authorizationUrl);
|
||||
using var process = Process.Start(authorizationUrl);
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Timeout for waiting for the website to respond
|
||||
/// </summary>
|
||||
public TimeSpan Timeout { get; set; } = TimeSpan.FromMinutes(4);
|
||||
|
||||
/// <summary>
|
||||
/// The OAuth code receiver
|
||||
/// </summary>
|
||||
/// <param name="oauth2Settings">OAuth2Settings</param>
|
||||
/// <returns>Dictionary with values</returns>
|
||||
public IDictionary<string, string> ReceiveCode(OAuth2Settings oauth2Settings) {
|
||||
using var listener = new HttpListener();
|
||||
// Make sure the port is stored in the state, so the website can process this.
|
||||
oauth2Settings.State = new Uri(ListeningUri).Port.ToString();
|
||||
listener.Prefixes.Add(ListeningUri);
|
||||
try {
|
||||
listener.Start();
|
||||
_ready.Reset();
|
||||
|
||||
listener.BeginGetContext(ListenerCallback, listener);
|
||||
OpenUriAction(oauth2Settings.FormattedAuthUrl);
|
||||
_ready.WaitOne(Timeout, true);
|
||||
} catch (Exception) {
|
||||
// Make sure we can clean up, also if the thead is aborted
|
||||
_ready.Set();
|
||||
throw;
|
||||
} finally {
|
||||
listener.Close();
|
||||
}
|
||||
|
||||
return _returnValues;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a connection async, this allows us to break the waiting
|
||||
/// </summary>
|
||||
/// <param name="result">IAsyncResult</param>
|
||||
private void ListenerCallback(IAsyncResult result) {
|
||||
HttpListener listener = (HttpListener)result.AsyncState;
|
||||
|
||||
//If not listening return immediately as this method is called one last time after Close()
|
||||
if (!listener.IsListening) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use EndGetContext to complete the asynchronous operation.
|
||||
HttpListenerContext context = listener.EndGetContext(result);
|
||||
|
||||
// Handle request
|
||||
HttpListenerRequest request = context.Request;
|
||||
|
||||
if (request.HasEntityBody)
|
||||
{
|
||||
// Process the body
|
||||
using var body = request.InputStream;
|
||||
using var reader = new StreamReader(body, request.ContentEncoding);
|
||||
using var jsonTextReader = new JsonTextReader(reader);
|
||||
var serializer = new JsonSerializer();
|
||||
_returnValues = serializer.Deserialize<Dictionary<string, string>>(jsonTextReader);
|
||||
}
|
||||
|
||||
// Create the response.
|
||||
using (HttpListenerResponse response = context.Response)
|
||||
{
|
||||
if (request.HttpMethod == "OPTIONS")
|
||||
{
|
||||
response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
|
||||
response.AddHeader("Access-Control-Allow-Methods", "POST");
|
||||
response.AddHeader("Access-Control-Max-Age", "1728000");
|
||||
}
|
||||
|
||||
response.AppendHeader("Access-Control-Allow-Origin", "*");
|
||||
if (request.HasEntityBody)
|
||||
{
|
||||
response.ContentType = "application/json";
|
||||
// currently only return the version, more can be added later
|
||||
string jsonContent = "{\"version\": \"" + EnvironmentInfo.GetGreenshotVersion(true) + "\"}";
|
||||
|
||||
// Write a "close" response.
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(jsonContent);
|
||||
// Write to response stream.
|
||||
response.ContentLength64 = buffer.Length;
|
||||
using var stream = response.OutputStream;
|
||||
stream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
}
|
||||
|
||||
if (_returnValues != null)
|
||||
{
|
||||
_ready.Set();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure the next request is processed
|
||||
listener.BeginGetContext(ListenerCallback, listener);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a random, unused port.
|
||||
/// </summary>
|
||||
/// <returns>port to use</returns>
|
||||
private static int GetRandomUnusedPort() {
|
||||
var listener = new TcpListener(IPAddress.Loopback, 0);
|
||||
try {
|
||||
listener.Start();
|
||||
return ((IPEndPoint)listener.LocalEndpoint).Port;
|
||||
} finally {
|
||||
listener.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
183
GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs
Normal file
183
GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs
Normal file
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
|
||||
namespace GreenshotPlugin.Core.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// OAuth 2.0 verification code receiver that runs a local server on a free port
|
||||
/// and waits for a call with the authorization verification code.
|
||||
/// </summary>
|
||||
public class LocalServerCodeReceiver {
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(LocalServerCodeReceiver));
|
||||
private readonly ManualResetEvent _ready = new ManualResetEvent(true);
|
||||
|
||||
/// <summary>
|
||||
/// The call back format. Expects one port parameter.
|
||||
/// Default: http://localhost:{0}/authorize/
|
||||
/// </summary>
|
||||
public string LoopbackCallbackUrl { get; set; } = "http://localhost:{0}/authorize/";
|
||||
|
||||
/// <summary>
|
||||
/// HTML code to to return the _browser, default it will try to close the _browser / tab, this won't always work.
|
||||
/// You can use CloudServiceName where you want to show the CloudServiceName from your OAuth2 settings
|
||||
/// </summary>
|
||||
public string ClosePageResponse { get; set; } = @"<html>
|
||||
<head><title>OAuth 2.0 Authentication CloudServiceName</title></head>
|
||||
<body>
|
||||
Greenshot received information from CloudServiceName. You can close this browser / tab if it is not closed itself...
|
||||
<script type='text/javascript'>
|
||||
window.setTimeout(function() {
|
||||
window.open('', '_self', '');
|
||||
window.close();
|
||||
}, 1000);
|
||||
if (window.opener) {
|
||||
window.opener.checkToken();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>";
|
||||
|
||||
private string _redirectUri;
|
||||
/// <summary>
|
||||
/// The URL to redirect to
|
||||
/// </summary>
|
||||
protected string RedirectUri {
|
||||
get {
|
||||
if (!string.IsNullOrEmpty(_redirectUri)) {
|
||||
return _redirectUri;
|
||||
}
|
||||
|
||||
return _redirectUri = string.Format(LoopbackCallbackUrl, GetRandomUnusedPort());
|
||||
}
|
||||
}
|
||||
|
||||
private string _cloudServiceName;
|
||||
|
||||
private readonly IDictionary<string, string> _returnValues = new Dictionary<string, string>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The OAuth code receiver
|
||||
/// </summary>
|
||||
/// <param name="oauth2Settings"></param>
|
||||
/// <returns>Dictionary with values</returns>
|
||||
public IDictionary<string, string> ReceiveCode(OAuth2Settings oauth2Settings) {
|
||||
// Set the redirect URL on the settings
|
||||
oauth2Settings.RedirectUrl = RedirectUri;
|
||||
_cloudServiceName = oauth2Settings.CloudServiceName;
|
||||
using (var listener = new HttpListener()) {
|
||||
listener.Prefixes.Add(oauth2Settings.RedirectUrl);
|
||||
try {
|
||||
listener.Start();
|
||||
|
||||
// Get the formatted FormattedAuthUrl
|
||||
string authorizationUrl = oauth2Settings.FormattedAuthUrl;
|
||||
Log.DebugFormat("Open a browser with: {0}", authorizationUrl);
|
||||
Process.Start(authorizationUrl);
|
||||
|
||||
// Wait to get the authorization code response.
|
||||
var context = listener.BeginGetContext(ListenerCallback, listener);
|
||||
_ready.Reset();
|
||||
|
||||
while (!context.AsyncWaitHandle.WaitOne(1000, true)) {
|
||||
Log.Debug("Waiting for response");
|
||||
}
|
||||
} catch (Exception) {
|
||||
// Make sure we can clean up, also if the thead is aborted
|
||||
_ready.Set();
|
||||
throw;
|
||||
} finally {
|
||||
_ready.WaitOne();
|
||||
listener.Close();
|
||||
}
|
||||
}
|
||||
return _returnValues;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a connection async, this allows us to break the waiting
|
||||
/// </summary>
|
||||
/// <param name="result">IAsyncResult</param>
|
||||
private void ListenerCallback(IAsyncResult result) {
|
||||
HttpListener listener = (HttpListener)result.AsyncState;
|
||||
|
||||
//If not listening return immediately as this method is called one last time after Close()
|
||||
if (!listener.IsListening) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use EndGetContext to complete the asynchronous operation.
|
||||
HttpListenerContext context = listener.EndGetContext(result);
|
||||
|
||||
|
||||
// Handle request
|
||||
HttpListenerRequest request = context.Request;
|
||||
try {
|
||||
NameValueCollection nameValueCollection = request.QueryString;
|
||||
|
||||
// Get response object.
|
||||
using (HttpListenerResponse response = context.Response) {
|
||||
// Write a "close" response.
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(ClosePageResponse.Replace("CloudServiceName", _cloudServiceName));
|
||||
// Write to response stream.
|
||||
response.ContentLength64 = buffer.Length;
|
||||
using var stream = response.OutputStream;
|
||||
stream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
// Create a new response URL with a dictionary that contains all the response query parameters.
|
||||
foreach (var name in nameValueCollection.AllKeys) {
|
||||
if (!_returnValues.ContainsKey(name)) {
|
||||
_returnValues.Add(name, nameValueCollection[name]);
|
||||
}
|
||||
}
|
||||
} catch (Exception) {
|
||||
context.Response.OutputStream.Close();
|
||||
throw;
|
||||
}
|
||||
_ready.Set();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a random, unused port.
|
||||
/// </summary>
|
||||
/// <returns>port to use</returns>
|
||||
private static int GetRandomUnusedPort() {
|
||||
var listener = new TcpListener(IPAddress.Loopback, 0);
|
||||
try {
|
||||
listener.Start();
|
||||
return ((IPEndPoint)listener.LocalEndpoint).Port;
|
||||
} finally {
|
||||
listener.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs
Normal file
33
GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GreenshotPlugin.Core.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Specify the authorize mode that is used to get the token from the cloud service.
|
||||
/// </summary>
|
||||
public enum OAuth2AuthorizeMode {
|
||||
Unknown, // Will give an exception, caller needs to specify another value
|
||||
LocalServer, // Will specify a redirect URL to http://localhost:port/authorize, while having a HttpListener
|
||||
JsonReceiver, // Will start a local HttpListener and wait for a Json post
|
||||
EmbeddedBrowser // Will open into an embedded _browser (OAuthLoginForm), and catch the redirect
|
||||
}
|
||||
}
|
372
GreenshotPlugin/Core/OAuth/OAuth2Helper.cs
Normal file
372
GreenshotPlugin/Core/OAuth/OAuth2Helper.cs
Normal file
|
@ -0,0 +1,372 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Net;
|
||||
using GreenshotPlugin.Controls;
|
||||
|
||||
namespace GreenshotPlugin.Core.OAuth {
|
||||
/// <summary>
|
||||
/// Code to simplify OAuth 2
|
||||
/// </summary>
|
||||
public static class OAuth2Helper {
|
||||
private const string RefreshToken = "refresh_token";
|
||||
private const string AccessToken = "access_token";
|
||||
private const string Code = "code";
|
||||
private const string Error = "error";
|
||||
private const string ClientId = "client_id";
|
||||
private const string ClientSecret = "client_secret";
|
||||
private const string GrantType = "grant_type";
|
||||
private const string AuthorizationCode = "authorization_code";
|
||||
private const string RedirectUri = "redirect_uri";
|
||||
private const string ExpiresIn = "expires_in";
|
||||
|
||||
/// <summary>
|
||||
/// Generate an OAuth 2 Token by using the supplied code
|
||||
/// </summary>
|
||||
/// <param name="settings">OAuth2Settings to update with the information that was retrieved</param>
|
||||
public static void GenerateRefreshToken(OAuth2Settings settings) {
|
||||
IDictionary<string, object> data = new Dictionary<string, object>
|
||||
{
|
||||
// Use the returned code to get a refresh code
|
||||
{ Code, settings.Code },
|
||||
{ ClientId, settings.ClientId },
|
||||
{ ClientSecret, settings.ClientSecret },
|
||||
{ GrantType, AuthorizationCode }
|
||||
};
|
||||
foreach (string key in settings.AdditionalAttributes.Keys) {
|
||||
data.Add(key, settings.AdditionalAttributes[key]);
|
||||
}
|
||||
|
||||
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.TokenUrl, HTTPMethod.POST);
|
||||
NetworkHelper.UploadFormUrlEncoded(webRequest, data);
|
||||
string accessTokenJsonResult = NetworkHelper.GetResponseAsString(webRequest, true);
|
||||
|
||||
IDictionary<string, object> refreshTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult);
|
||||
if (refreshTokenResult.ContainsKey("error"))
|
||||
{
|
||||
if (refreshTokenResult.ContainsKey("error_description")) {
|
||||
throw new Exception($"{refreshTokenResult["error"]} - {refreshTokenResult["error_description"]}");
|
||||
}
|
||||
throw new Exception((string)refreshTokenResult["error"]);
|
||||
}
|
||||
|
||||
// gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp
|
||||
// "access_token":"1/fFAGRNJru1FTz70BzhT3Zg",
|
||||
// "expires_in":3920,
|
||||
// "token_type":"Bearer",
|
||||
// "refresh_token":"1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
|
||||
if (refreshTokenResult.ContainsKey(AccessToken))
|
||||
{
|
||||
settings.AccessToken = (string)refreshTokenResult[AccessToken];
|
||||
}
|
||||
if (refreshTokenResult.ContainsKey(RefreshToken))
|
||||
{
|
||||
settings.RefreshToken = (string)refreshTokenResult[RefreshToken];
|
||||
}
|
||||
if (refreshTokenResult.ContainsKey(ExpiresIn))
|
||||
{
|
||||
object seconds = refreshTokenResult[ExpiresIn];
|
||||
if (seconds != null)
|
||||
{
|
||||
settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double)seconds);
|
||||
}
|
||||
}
|
||||
settings.Code = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to update the settings with the callback information
|
||||
/// </summary>
|
||||
/// <param name="settings">OAuth2Settings</param>
|
||||
/// <param name="callbackParameters">IDictionary</param>
|
||||
/// <returns>true if the access token is already in the callback</returns>
|
||||
private static bool UpdateFromCallback(OAuth2Settings settings, IDictionary<string, string> callbackParameters)
|
||||
{
|
||||
if (!callbackParameters.ContainsKey(AccessToken))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (callbackParameters.ContainsKey(RefreshToken))
|
||||
{
|
||||
// Refresh the refresh token :)
|
||||
settings.RefreshToken = callbackParameters[RefreshToken];
|
||||
}
|
||||
if (callbackParameters.ContainsKey(ExpiresIn))
|
||||
{
|
||||
var expiresIn = callbackParameters[ExpiresIn];
|
||||
settings.AccessTokenExpires = DateTimeOffset.MaxValue;
|
||||
if (expiresIn != null)
|
||||
{
|
||||
if (double.TryParse(expiresIn, out var seconds))
|
||||
{
|
||||
settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds(seconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
settings.AccessToken = callbackParameters[AccessToken];
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Go out and retrieve a new access token via refresh-token with the TokenUrl in the settings
|
||||
/// Will update the access token, refresh token, expire date
|
||||
/// </summary>
|
||||
/// <param name="settings"></param>
|
||||
public static void GenerateAccessToken(OAuth2Settings settings) {
|
||||
IDictionary<string, object> data = new Dictionary<string, object>
|
||||
{
|
||||
{ RefreshToken, settings.RefreshToken },
|
||||
{ ClientId, settings.ClientId },
|
||||
{ ClientSecret, settings.ClientSecret },
|
||||
{ GrantType, RefreshToken }
|
||||
};
|
||||
foreach (string key in settings.AdditionalAttributes.Keys) {
|
||||
data.Add(key, settings.AdditionalAttributes[key]);
|
||||
}
|
||||
|
||||
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.TokenUrl, HTTPMethod.POST);
|
||||
NetworkHelper.UploadFormUrlEncoded(webRequest, data);
|
||||
string accessTokenJsonResult = NetworkHelper.GetResponseAsString(webRequest, true);
|
||||
|
||||
// gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp
|
||||
// "access_token":"1/fFAGRNJru1FTz70BzhT3Zg",
|
||||
// "expires_in":3920,
|
||||
// "token_type":"Bearer",
|
||||
|
||||
IDictionary<string, object> accessTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult);
|
||||
if (accessTokenResult.ContainsKey("error"))
|
||||
{
|
||||
if ("invalid_grant" == (string)accessTokenResult["error"]) {
|
||||
// Refresh token has also expired, we need a new one!
|
||||
settings.RefreshToken = null;
|
||||
settings.AccessToken = null;
|
||||
settings.AccessTokenExpires = DateTimeOffset.MinValue;
|
||||
settings.Code = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (accessTokenResult.ContainsKey("error_description")) {
|
||||
throw new Exception($"{accessTokenResult["error"]} - {accessTokenResult["error_description"]}");
|
||||
}
|
||||
|
||||
throw new Exception((string)accessTokenResult["error"]);
|
||||
}
|
||||
|
||||
if (accessTokenResult.ContainsKey(AccessToken))
|
||||
{
|
||||
settings.AccessToken = (string) accessTokenResult[AccessToken];
|
||||
settings.AccessTokenExpires = DateTimeOffset.MaxValue;
|
||||
}
|
||||
if (accessTokenResult.ContainsKey(RefreshToken)) {
|
||||
// Refresh the refresh token :)
|
||||
settings.RefreshToken = (string)accessTokenResult[RefreshToken];
|
||||
}
|
||||
if (accessTokenResult.ContainsKey(ExpiresIn))
|
||||
{
|
||||
object seconds = accessTokenResult[ExpiresIn];
|
||||
if (seconds != null)
|
||||
{
|
||||
settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double) seconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authorize by using the mode specified in the settings
|
||||
/// </summary>
|
||||
/// <param name="settings">OAuth2Settings</param>
|
||||
/// <returns>false if it was canceled, true if it worked, exception if not</returns>
|
||||
public static bool Authorize(OAuth2Settings settings) {
|
||||
var completed = settings.AuthorizeMode switch
|
||||
{
|
||||
OAuth2AuthorizeMode.LocalServer => AuthorizeViaLocalServer(settings),
|
||||
OAuth2AuthorizeMode.EmbeddedBrowser => AuthorizeViaEmbeddedBrowser(settings),
|
||||
OAuth2AuthorizeMode.JsonReceiver => AuthorizeViaDefaultBrowser(settings),
|
||||
_ => throw new NotImplementedException($"Authorize mode '{settings.AuthorizeMode}' is not 'yet' implemented."),
|
||||
};
|
||||
return completed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authorize via the default browser, via the Greenshot website.
|
||||
/// It will wait for a Json post.
|
||||
/// If this works, return the code
|
||||
/// </summary>
|
||||
/// <param name="settings">OAuth2Settings with the Auth / Token url etc</param>
|
||||
/// <returns>true if completed, false if canceled</returns>
|
||||
private static bool AuthorizeViaDefaultBrowser(OAuth2Settings settings)
|
||||
{
|
||||
var codeReceiver = new LocalJsonReceiver();
|
||||
IDictionary<string, string> result = codeReceiver.ReceiveCode(settings);
|
||||
|
||||
if (result == null || result.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
foreach (var key in result.Keys)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case AccessToken:
|
||||
settings.AccessToken = result[key];
|
||||
break;
|
||||
case ExpiresIn:
|
||||
if (int.TryParse(result[key], out var seconds))
|
||||
{
|
||||
settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds(seconds);
|
||||
}
|
||||
break;
|
||||
case RefreshToken:
|
||||
settings.RefreshToken = result[key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.TryGetValue("error", out var error))
|
||||
{
|
||||
if (result.TryGetValue("error_description", out var errorDescription))
|
||||
{
|
||||
throw new Exception(errorDescription);
|
||||
}
|
||||
if ("access_denied" == error)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Access denied");
|
||||
}
|
||||
throw new Exception(error);
|
||||
}
|
||||
if (result.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code))
|
||||
{
|
||||
settings.Code = code;
|
||||
GenerateRefreshToken(settings);
|
||||
return !string.IsNullOrEmpty(settings.AccessToken);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authorize via an embedded browser
|
||||
/// If this works, return the code
|
||||
/// </summary>
|
||||
/// <param name="settings">OAuth2Settings with the Auth / Token url etc</param>
|
||||
/// <returns>true if completed, false if canceled</returns>
|
||||
private static bool AuthorizeViaEmbeddedBrowser(OAuth2Settings settings) {
|
||||
if (string.IsNullOrEmpty(settings.CloudServiceName)) {
|
||||
throw new ArgumentNullException(nameof(settings.CloudServiceName));
|
||||
}
|
||||
if (settings.BrowserSize == Size.Empty) {
|
||||
throw new ArgumentNullException(nameof(settings.BrowserSize));
|
||||
}
|
||||
OAuthLoginForm loginForm = new OAuthLoginForm($"Authorize {settings.CloudServiceName}", settings.BrowserSize, settings.FormattedAuthUrl, settings.RedirectUrl);
|
||||
loginForm.ShowDialog();
|
||||
if (!loginForm.IsOk) return false;
|
||||
if (loginForm.CallbackParameters.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) {
|
||||
settings.Code = code;
|
||||
GenerateRefreshToken(settings);
|
||||
return true;
|
||||
}
|
||||
return UpdateFromCallback(settings, loginForm.CallbackParameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authorize via a local server by using the LocalServerCodeReceiver
|
||||
/// If this works, return the code
|
||||
/// </summary>
|
||||
/// <param name="settings">OAuth2Settings with the Auth / Token url etc</param>
|
||||
/// <returns>true if completed</returns>
|
||||
private static bool AuthorizeViaLocalServer(OAuth2Settings settings) {
|
||||
var codeReceiver = new LocalServerCodeReceiver();
|
||||
IDictionary<string, string> result = codeReceiver.ReceiveCode(settings);
|
||||
|
||||
if (result.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) {
|
||||
settings.Code = code;
|
||||
GenerateRefreshToken(settings);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (result.TryGetValue("error", out var error)) {
|
||||
if (result.TryGetValue("error_description", out var errorDescription)) {
|
||||
throw new Exception(errorDescription);
|
||||
}
|
||||
if ("access_denied" == error) {
|
||||
throw new UnauthorizedAccessException("Access denied");
|
||||
}
|
||||
throw new Exception(error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple helper to add the Authorization Bearer header
|
||||
/// </summary>
|
||||
/// <param name="webRequest">WebRequest</param>
|
||||
/// <param name="settings">OAuth2Settings</param>
|
||||
public static void AddOAuth2Credentials(HttpWebRequest webRequest, OAuth2Settings settings) {
|
||||
if (!string.IsNullOrEmpty(settings.AccessToken)) {
|
||||
webRequest.Headers.Add("Authorization", "Bearer " + settings.AccessToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check and authenticate or refresh tokens
|
||||
/// </summary>
|
||||
/// <param name="settings">OAuth2Settings</param>
|
||||
public static void CheckAndAuthenticateOrRefresh(OAuth2Settings settings) {
|
||||
// Get Refresh / Access token
|
||||
if (string.IsNullOrEmpty(settings.RefreshToken)) {
|
||||
if (!Authorize(settings)) {
|
||||
throw new Exception("Authentication cancelled");
|
||||
}
|
||||
}
|
||||
if (settings.IsAccessTokenExpired) {
|
||||
GenerateAccessToken(settings);
|
||||
// Get Refresh / Access token
|
||||
if (string.IsNullOrEmpty(settings.RefreshToken)) {
|
||||
if (!Authorize(settings)) {
|
||||
throw new Exception("Authentication cancelled");
|
||||
}
|
||||
GenerateAccessToken(settings);
|
||||
}
|
||||
}
|
||||
if (settings.IsAccessTokenExpired) {
|
||||
throw new Exception("Authentication failed");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CreateWebRequest ready for OAuth 2 access
|
||||
/// </summary>
|
||||
/// <param name="method">HTTPMethod</param>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="settings">OAuth2Settings</param>
|
||||
/// <returns>HttpWebRequest</returns>
|
||||
public static HttpWebRequest CreateOAuth2WebRequest(HTTPMethod method, string url, OAuth2Settings settings) {
|
||||
CheckAndAuthenticateOrRefresh(settings);
|
||||
|
||||
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, method);
|
||||
AddOAuth2Credentials(webRequest, settings);
|
||||
return webRequest;
|
||||
}
|
||||
}
|
||||
}
|
181
GreenshotPlugin/Core/OAuth/OAuth2Settings.cs
Normal file
181
GreenshotPlugin/Core/OAuth/OAuth2Settings.cs
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
namespace GreenshotPlugin.Core.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Settings for the OAuth 2 protocol
|
||||
/// </summary>
|
||||
public class OAuth2Settings {
|
||||
public OAuth2Settings() {
|
||||
AdditionalAttributes = new Dictionary<string, string>();
|
||||
// Create a default state
|
||||
var state = Guid.NewGuid().ToString();
|
||||
// Only store a small part of the GUID
|
||||
State = state.Substring(0, state.IndexOf('-')-1);
|
||||
AuthorizeMode = OAuth2AuthorizeMode.Unknown;
|
||||
}
|
||||
|
||||
public OAuth2AuthorizeMode AuthorizeMode {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specify the name of the cloud service, so it can be used in window titles, logs etc
|
||||
/// </summary>
|
||||
public string CloudServiceName {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specify the size of the embedded Browser, if using this
|
||||
/// </summary>
|
||||
public Size BrowserSize {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The OAuth 2 client id
|
||||
/// </summary>
|
||||
public string ClientId {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The OAuth 2 client secret
|
||||
/// </summary>
|
||||
public string ClientSecret {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The OAuth 2 state, this is something that is passed to the server, is not processed but returned back to the client.
|
||||
/// e.g. a correlation ID
|
||||
/// Default this is filled with a new Guid
|
||||
/// </summary>
|
||||
public string State {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The authorization URL where the values of this class can be "injected"
|
||||
/// </summary>
|
||||
public string AuthUrlPattern {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get formatted Auth url (this will call a FormatWith(this) on the AuthUrlPattern
|
||||
/// </summary>
|
||||
public string FormattedAuthUrl => AuthUrlPattern.FormatWith(this);
|
||||
|
||||
/// <summary>
|
||||
/// The URL to get a Token
|
||||
/// </summary>
|
||||
public string TokenUrl {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is the redirect URL, in some implementations this is automatically set (LocalServerCodeReceiver)
|
||||
/// In some implementations this could be e.g. urn:ietf:wg:oauth:2.0:oob or urn:ietf:wg:oauth:2.0:oob:auto
|
||||
/// </summary>
|
||||
public string RedirectUrl {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bearer token for accessing OAuth 2 services
|
||||
/// </summary>
|
||||
public string AccessToken {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expire time for the AccessToken, this this time (-60 seconds) is passed a new AccessToken needs to be generated with the RefreshToken
|
||||
/// </summary>
|
||||
public DateTimeOffset AccessTokenExpires {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return true if the access token is expired.
|
||||
/// Important "side-effect": if true is returned the AccessToken will be set to null!
|
||||
/// </summary>
|
||||
public bool IsAccessTokenExpired {
|
||||
get {
|
||||
if (AccessTokenExpires == default)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool expired = true;
|
||||
if (!string.IsNullOrEmpty(AccessToken)) {
|
||||
expired = DateTimeOffset.Now.AddSeconds(60) > AccessTokenExpires;
|
||||
}
|
||||
// Make sure the token is not usable
|
||||
if (expired) {
|
||||
AccessToken = null;
|
||||
}
|
||||
return expired;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Token used to get a new Access Token
|
||||
/// </summary>
|
||||
public string RefreshToken {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Put anything in here which is needed for the OAuth 2 implementation of this specific service but isn't generic, e.g. for Google there is a "scope"
|
||||
/// </summary>
|
||||
public IDictionary<string, string> AdditionalAttributes {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This contains the code returned from the authorization, but only shortly after it was received.
|
||||
/// It will be cleared as soon as it was used.
|
||||
/// </summary>
|
||||
public string Code {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
629
GreenshotPlugin/Core/OAuth/OAuthSession.cs
Normal file
629
GreenshotPlugin/Core/OAuth/OAuthSession.cs
Normal file
|
@ -0,0 +1,629 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using GreenshotPlugin.Controls;
|
||||
using log4net;
|
||||
|
||||
namespace GreenshotPlugin.Core.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// An OAuth 1 session object
|
||||
/// </summary>
|
||||
public class OAuthSession {
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(OAuthSession));
|
||||
protected const string OAUTH_VERSION = "1.0";
|
||||
protected const string OAUTH_PARAMETER_PREFIX = "oauth_";
|
||||
|
||||
//
|
||||
// List of know and used oauth parameters' names
|
||||
//
|
||||
protected const string OAUTH_CONSUMER_KEY_KEY = "oauth_consumer_key";
|
||||
protected const string OAUTH_CALLBACK_KEY = "oauth_callback";
|
||||
protected const string OAUTH_VERSION_KEY = "oauth_version";
|
||||
protected const string OAUTH_SIGNATURE_METHOD_KEY = "oauth_signature_method";
|
||||
protected const string OAUTH_TIMESTAMP_KEY = "oauth_timestamp";
|
||||
protected const string OAUTH_NONCE_KEY = "oauth_nonce";
|
||||
protected const string OAUTH_TOKEN_KEY = "oauth_token";
|
||||
protected const string OAUTH_VERIFIER_KEY = "oauth_verifier";
|
||||
protected const string OAUTH_TOKEN_SECRET_KEY = "oauth_token_secret";
|
||||
protected const string OAUTH_SIGNATURE_KEY = "oauth_signature";
|
||||
|
||||
protected const string HMACSHA1SignatureType = "HMAC-SHA1";
|
||||
protected const string PlainTextSignatureType = "PLAINTEXT";
|
||||
|
||||
protected static Random random = new Random();
|
||||
|
||||
protected const string UnreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
|
||||
|
||||
private string _userAgent = "Greenshot";
|
||||
private IDictionary<string, string> _requestTokenResponseParameters;
|
||||
|
||||
public IDictionary<string, object> RequestTokenParameters { get; } = new Dictionary<string, object>();
|
||||
|
||||
/// <summary>
|
||||
/// Parameters of the last called getAccessToken
|
||||
/// </summary>
|
||||
public IDictionary<string, string> AccessTokenResponseParameters { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Parameters of the last called getRequestToken
|
||||
/// </summary>
|
||||
public IDictionary<string, string> RequestTokenResponseParameters => _requestTokenResponseParameters;
|
||||
|
||||
private readonly string _consumerKey;
|
||||
private readonly string _consumerSecret;
|
||||
|
||||
// default _browser size
|
||||
|
||||
public HTTPMethod RequestTokenMethod {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public HTTPMethod AccessTokenMethod {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public string RequestTokenUrl {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public string AuthorizeUrl {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public string AccessTokenUrl {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public string Token {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public string TokenSecret {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public string Verifier {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public OAuthSignatureTypes SignatureType {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool UseMultipartFormData { get; set; }
|
||||
public string UserAgent {
|
||||
get {
|
||||
return _userAgent;
|
||||
}
|
||||
set {
|
||||
_userAgent = value;
|
||||
}
|
||||
}
|
||||
public string CallbackUrl { get; set; } = "http://getgreenshot.org";
|
||||
|
||||
public bool CheckVerifier { get; set; } = true;
|
||||
|
||||
public Size BrowserSize { get; set; } = new Size(864, 587);
|
||||
|
||||
public string LoginTitle { get; set; } = "Authorize Greenshot access";
|
||||
|
||||
public bool UseHttpHeadersForAuthorization { get; set; } = true;
|
||||
|
||||
public bool AutoLogin {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an OAuthSession with the consumerKey / consumerSecret
|
||||
/// </summary>
|
||||
/// <param name="consumerKey">"Public" key for the encoding. When using RSASHA1 this is the path to the private key file</param>
|
||||
/// <param name="consumerSecret">"Private" key for the encoding. when usin RSASHA1 this is the password for the private key file</param>
|
||||
public OAuthSession(string consumerKey, string consumerSecret) {
|
||||
_consumerKey = consumerKey;
|
||||
_consumerSecret = consumerSecret;
|
||||
UseMultipartFormData = true;
|
||||
RequestTokenMethod = HTTPMethod.GET;
|
||||
AccessTokenMethod = HTTPMethod.GET;
|
||||
SignatureType = OAuthSignatureTypes.HMACSHA1;
|
||||
AutoLogin = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function to compute a hash value
|
||||
/// </summary>
|
||||
/// <param name="hashAlgorithm">The hashing algorithm used. If that algorithm needs some initialization, like HMAC and its derivatives, they should be initialized prior to passing it to this function</param>
|
||||
/// <param name="data">The data to hash</param>
|
||||
/// <returns>a Base64 string of the hash value</returns>
|
||||
private static string ComputeHash(HashAlgorithm hashAlgorithm, string data) {
|
||||
if (hashAlgorithm == null) {
|
||||
throw new ArgumentNullException(nameof(hashAlgorithm));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(data)) {
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
|
||||
byte[] dataBuffer = Encoding.UTF8.GetBytes(data);
|
||||
byte[] hashBytes = hashAlgorithm.ComputeHash(dataBuffer);
|
||||
|
||||
return Convert.ToBase64String(hashBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the normalized paramter string
|
||||
/// </summary>
|
||||
/// <param name="queryParameters">the list of query parameters</param>
|
||||
/// <returns>a string with the normalized query parameters</returns>
|
||||
private static string GenerateNormalizedParametersString(IDictionary<string, object> queryParameters) {
|
||||
if (queryParameters == null || queryParameters.Count == 0) {
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
queryParameters = new SortedDictionary<string, object>(queryParameters);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (string key in queryParameters.Keys) {
|
||||
if (queryParameters[key] is string) {
|
||||
sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode3986($"{queryParameters[key]}"));
|
||||
}
|
||||
}
|
||||
sb.Remove(sb.Length - 1, 1);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is a different Url Encode implementation since the default .NET one outputs the percent encoding in lower case.
|
||||
/// While this is not a problem with the percent encoding spec, it is used in upper case throughout OAuth
|
||||
/// The resulting string is for UTF-8 encoding!
|
||||
/// </summary>
|
||||
/// <param name="value">The value to Url encode</param>
|
||||
/// <returns>Returns a Url encoded string (unicode) with UTF-8 encoded % values</returns>
|
||||
public static string UrlEncode3986(string value) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
foreach (char symbol in value) {
|
||||
if (UnreservedChars.IndexOf(symbol) != -1) {
|
||||
result.Append(symbol);
|
||||
} else {
|
||||
byte[] utf8Bytes = Encoding.UTF8.GetBytes(symbol.ToString());
|
||||
foreach(byte utf8Byte in utf8Bytes) {
|
||||
result.AppendFormat("%{0:X2}", utf8Byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the timestamp for the signature
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GenerateTimeStamp() {
|
||||
// Default implementation of UNIX time of the current UTC time
|
||||
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
||||
return Convert.ToInt64(ts.TotalSeconds).ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a nonce
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GenerateNonce() {
|
||||
// Just a simple implementation of a random number between 123400 and 9999999
|
||||
return random.Next(123400, 9999999).ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the request token using the consumer key and secret. Also initializes tokensecret
|
||||
/// </summary>
|
||||
/// <returns>response, this doesn't need to be used!!</returns>
|
||||
private string GetRequestToken() {
|
||||
IDictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
foreach(var value in RequestTokenParameters) {
|
||||
parameters.Add(value);
|
||||
}
|
||||
Sign(RequestTokenMethod, RequestTokenUrl, parameters);
|
||||
string response = MakeRequest(RequestTokenMethod, RequestTokenUrl, null, parameters, null);
|
||||
if (!string.IsNullOrEmpty(response)) {
|
||||
response = NetworkHelper.UrlDecode(response);
|
||||
Log.DebugFormat("Request token response: {0}", response);
|
||||
_requestTokenResponseParameters = NetworkHelper.ParseQueryString(response);
|
||||
if (_requestTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out var value)) {
|
||||
Token = value;
|
||||
TokenSecret = _requestTokenResponseParameters[OAUTH_TOKEN_SECRET_KEY];
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authorize the token by showing the dialog
|
||||
/// </summary>
|
||||
/// <param name="requestTokenResponse">Pass the response from the server's request token, so if there is something wrong we can show it.</param>
|
||||
/// <returns>The request token.</returns>
|
||||
private string GetAuthorizeToken(string requestTokenResponse) {
|
||||
if (string.IsNullOrEmpty(Token)) {
|
||||
Exception e = new Exception("The request token is not set, service responded with: " + requestTokenResponse);
|
||||
throw e;
|
||||
}
|
||||
Log.DebugFormat("Opening AuthorizationLink: {0}", AuthorizationLink);
|
||||
OAuthLoginForm oAuthLoginForm = new OAuthLoginForm(LoginTitle, BrowserSize, AuthorizationLink, CallbackUrl);
|
||||
oAuthLoginForm.ShowDialog();
|
||||
if (oAuthLoginForm.IsOk) {
|
||||
if (oAuthLoginForm.CallbackParameters != null) {
|
||||
if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_TOKEN_KEY, out var tokenValue)) {
|
||||
Token = tokenValue;
|
||||
}
|
||||
|
||||
if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_VERIFIER_KEY, out var verifierValue)) {
|
||||
Verifier = verifierValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CheckVerifier) {
|
||||
if (!string.IsNullOrEmpty(Verifier)) {
|
||||
return Token;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return Token;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the access token
|
||||
/// </summary>
|
||||
/// <returns>The access token.</returns>
|
||||
private string GetAccessToken() {
|
||||
if (string.IsNullOrEmpty(Token) || (CheckVerifier && string.IsNullOrEmpty(Verifier))) {
|
||||
Exception e = new Exception("The request token and verifier were not set");
|
||||
throw e;
|
||||
}
|
||||
|
||||
IDictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
Sign(AccessTokenMethod, AccessTokenUrl, parameters);
|
||||
string response = MakeRequest(AccessTokenMethod, AccessTokenUrl, null, parameters, null);
|
||||
if (!string.IsNullOrEmpty(response)) {
|
||||
response = NetworkHelper.UrlDecode(response);
|
||||
Log.DebugFormat("Access token response: {0}", response);
|
||||
AccessTokenResponseParameters = NetworkHelper.ParseQueryString(response);
|
||||
if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out var tokenValue) && tokenValue != null) {
|
||||
Token = tokenValue;
|
||||
}
|
||||
|
||||
if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_SECRET_KEY, out var secretValue) && secretValue != null) {
|
||||
TokenSecret = secretValue;
|
||||
}
|
||||
}
|
||||
|
||||
return Token;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method goes through the whole authorize process, including a Authorization window.
|
||||
/// </summary>
|
||||
/// <returns>true if the process is completed</returns>
|
||||
public bool Authorize() {
|
||||
Token = null;
|
||||
TokenSecret = null;
|
||||
Verifier = null;
|
||||
Log.Debug("Creating Token");
|
||||
string requestTokenResponse;
|
||||
try {
|
||||
requestTokenResponse = GetRequestToken();
|
||||
} catch (Exception ex) {
|
||||
Log.Error(ex);
|
||||
throw new NotSupportedException("Service is not available: " + ex.Message);
|
||||
}
|
||||
if (string.IsNullOrEmpty(GetAuthorizeToken(requestTokenResponse))) {
|
||||
Log.Debug("User didn't authenticate!");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Thread.Sleep(1000);
|
||||
return GetAccessToken() != null;
|
||||
} catch (Exception ex) {
|
||||
Log.Error(ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the link to the authorization page for this application.
|
||||
/// </summary>
|
||||
/// <returns>The url with a valid request token, or a null string.</returns>
|
||||
private string AuthorizationLink => AuthorizeUrl + "?" + OAUTH_TOKEN_KEY + "=" + Token + "&" + OAUTH_CALLBACK_KEY + "=" + UrlEncode3986(CallbackUrl);
|
||||
|
||||
/// <summary>
|
||||
/// Submit a web request using oAuth.
|
||||
/// </summary>
|
||||
/// <param name="method">GET or POST</param>
|
||||
/// <param name="requestUrl">The full url, including the querystring for the signing/request</param>
|
||||
/// <param name="parametersToSign">Parameters for the request, which need to be signed</param>
|
||||
/// <param name="additionalParameters">Parameters for the request, which do not need to be signed</param>
|
||||
/// <param name="postData">Data to post (MemoryStream)</param>
|
||||
/// <returns>The web server response.</returns>
|
||||
public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary<string, object> parametersToSign, IDictionary<string, object> additionalParameters, IBinaryContainer postData) {
|
||||
return MakeOAuthRequest(method, requestUrl, requestUrl, null, parametersToSign, additionalParameters, postData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Submit a web request using oAuth.
|
||||
/// </summary>
|
||||
/// <param name="method">GET or POST</param>
|
||||
/// <param name="requestUrl">The full url, including the querystring for the signing/request</param>
|
||||
/// <param name="headers">Header values</param>
|
||||
/// <param name="parametersToSign">Parameters for the request, which need to be signed</param>
|
||||
/// <param name="additionalParameters">Parameters for the request, which do not need to be signed</param>
|
||||
/// <param name="postData">Data to post (MemoryStream)</param>
|
||||
/// <returns>The web server response.</returns>
|
||||
public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary<string, string> headers, IDictionary<string, object> parametersToSign, IDictionary<string, object> additionalParameters, IBinaryContainer postData) {
|
||||
return MakeOAuthRequest(method, requestUrl, requestUrl, headers, parametersToSign, additionalParameters, postData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Submit a web request using oAuth.
|
||||
/// </summary>
|
||||
/// <param name="method">GET or POST</param>
|
||||
/// <param name="signUrl">The full url, including the querystring for the signing</param>
|
||||
/// <param name="requestUrl">The full url, including the querystring for the request</param>
|
||||
/// <param name="parametersToSign">Parameters for the request, which need to be signed</param>
|
||||
/// <param name="additionalParameters">Parameters for the request, which do not need to be signed</param>
|
||||
/// <param name="postData">Data to post (MemoryStream)</param>
|
||||
/// <returns>The web server response.</returns>
|
||||
public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary<string, object> parametersToSign, IDictionary<string, object> additionalParameters, IBinaryContainer postData) {
|
||||
return MakeOAuthRequest(method, signUrl, requestUrl, null, parametersToSign, additionalParameters, postData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Submit a web request using oAuth.
|
||||
/// </summary>
|
||||
/// <param name="method">GET or POST</param>
|
||||
/// <param name="signUrl">The full url, including the querystring for the signing</param>
|
||||
/// <param name="requestUrl">The full url, including the querystring for the request</param>
|
||||
/// <param name="headers">Headers for the request</param>
|
||||
/// <param name="parametersToSign">Parameters for the request, which need to be signed</param>
|
||||
/// <param name="additionalParameters">Parameters for the request, which do not need to be signed</param>
|
||||
/// <param name="postData">Data to post (MemoryStream)</param>
|
||||
/// <returns>The web server response.</returns>
|
||||
public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary<string, string> headers, IDictionary<string, object> parametersToSign, IDictionary<string, object> additionalParameters, IBinaryContainer postData) {
|
||||
if (parametersToSign == null) {
|
||||
parametersToSign = new Dictionary<string, object>();
|
||||
}
|
||||
int retries = 2;
|
||||
Exception lastException = null;
|
||||
while (retries-- > 0) {
|
||||
// If we are not trying to get a Authorization or Accestoken, and we don't have a token, create one
|
||||
if (string.IsNullOrEmpty(Token)) {
|
||||
if (!AutoLogin || !Authorize()) {
|
||||
throw new Exception("Not authorized");
|
||||
}
|
||||
}
|
||||
try {
|
||||
Sign(method, signUrl, parametersToSign);
|
||||
|
||||
// Join all parameters
|
||||
IDictionary<string, object> newParameters = new Dictionary<string, object>();
|
||||
foreach (var parameter in parametersToSign) {
|
||||
newParameters.Add(parameter);
|
||||
}
|
||||
if (additionalParameters != null) {
|
||||
foreach (var parameter in additionalParameters) {
|
||||
newParameters.Add(parameter);
|
||||
}
|
||||
}
|
||||
return MakeRequest(method, requestUrl, headers, newParameters, postData);
|
||||
} catch (UnauthorizedAccessException uaEx) {
|
||||
lastException = uaEx;
|
||||
Token = null;
|
||||
TokenSecret = null;
|
||||
// Remove oauth keys, so they aren't added double
|
||||
List<string> keysToDelete = new List<string>();
|
||||
foreach (string parameterKey in parametersToSign.Keys)
|
||||
{
|
||||
if (parameterKey.StartsWith(OAUTH_PARAMETER_PREFIX))
|
||||
{
|
||||
keysToDelete.Add(parameterKey);
|
||||
}
|
||||
}
|
||||
foreach (string keyToDelete in keysToDelete)
|
||||
{
|
||||
parametersToSign.Remove(keyToDelete);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lastException != null) {
|
||||
throw lastException;
|
||||
}
|
||||
throw new Exception("Not authorized");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OAuth sign the parameters, meaning all oauth parameters are added to the supplied dictionary.
|
||||
/// And additionally a signature is added.
|
||||
/// </summary>
|
||||
/// <param name="method">Method (POST,PUT,GET)</param>
|
||||
/// <param name="requestUrl">Url to call</param>
|
||||
/// <param name="parameters">IDictionary of string and string</param>
|
||||
private void Sign(HTTPMethod method, string requestUrl, IDictionary<string, object> parameters) {
|
||||
if (parameters == null) {
|
||||
throw new ArgumentNullException(nameof(parameters));
|
||||
}
|
||||
// Build the signature base
|
||||
StringBuilder signatureBase = new StringBuilder();
|
||||
|
||||
// Add Method to signature base
|
||||
signatureBase.Append(method).Append("&");
|
||||
|
||||
// Add normalized URL
|
||||
Uri url = new Uri(requestUrl);
|
||||
string normalizedUrl = string.Format(CultureInfo.InvariantCulture, "{0}://{1}", url.Scheme, url.Host);
|
||||
if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443))) {
|
||||
normalizedUrl += ":" + url.Port;
|
||||
}
|
||||
normalizedUrl += url.AbsolutePath;
|
||||
signatureBase.Append(UrlEncode3986(normalizedUrl)).Append("&");
|
||||
|
||||
// Add normalized parameters
|
||||
parameters.Add(OAUTH_VERSION_KEY, OAUTH_VERSION);
|
||||
parameters.Add(OAUTH_NONCE_KEY, GenerateNonce());
|
||||
parameters.Add(OAUTH_TIMESTAMP_KEY, GenerateTimeStamp());
|
||||
switch(SignatureType) {
|
||||
case OAuthSignatureTypes.PLAINTEXT:
|
||||
parameters.Add(OAUTH_SIGNATURE_METHOD_KEY, PlainTextSignatureType);
|
||||
break;
|
||||
default:
|
||||
parameters.Add(OAUTH_SIGNATURE_METHOD_KEY, HMACSHA1SignatureType);
|
||||
break;
|
||||
}
|
||||
parameters.Add(OAUTH_CONSUMER_KEY_KEY, _consumerKey);
|
||||
if (CallbackUrl != null && RequestTokenUrl != null && requestUrl.StartsWith(RequestTokenUrl)) {
|
||||
parameters.Add(OAUTH_CALLBACK_KEY, CallbackUrl);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Verifier)) {
|
||||
parameters.Add(OAUTH_VERIFIER_KEY, Verifier);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Token)) {
|
||||
parameters.Add(OAUTH_TOKEN_KEY, Token);
|
||||
}
|
||||
signatureBase.Append(UrlEncode3986(GenerateNormalizedParametersString(parameters)));
|
||||
Log.DebugFormat("Signature base: {0}", signatureBase);
|
||||
string key = string.Format(CultureInfo.InvariantCulture, "{0}&{1}", UrlEncode3986(_consumerSecret), string.IsNullOrEmpty(TokenSecret) ? string.Empty : UrlEncode3986(TokenSecret));
|
||||
switch (SignatureType) {
|
||||
case OAuthSignatureTypes.PLAINTEXT:
|
||||
parameters.Add(OAUTH_SIGNATURE_KEY, key);
|
||||
break;
|
||||
default:
|
||||
// Generate Signature and add it to the parameters
|
||||
HMACSHA1 hmacsha1 = new HMACSHA1 {Key = Encoding.UTF8.GetBytes(key)};
|
||||
string signature = ComputeHash(hmacsha1, signatureBase.ToString());
|
||||
parameters.Add(OAUTH_SIGNATURE_KEY, signature);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make the actual OAuth request, all oauth parameters are passed as header (default) and the others are placed in the url or post data.
|
||||
/// Any additional parameters added after the Sign call are not in the signature, this could be by design!
|
||||
/// </summary>
|
||||
/// <param name="method"></param>
|
||||
/// <param name="requestUrl"></param>
|
||||
/// <param name="headers"></param>
|
||||
/// <param name="parameters"></param>
|
||||
/// <param name="postData">IBinaryParameter</param>
|
||||
/// <returns>Response from server</returns>
|
||||
private string MakeRequest(HTTPMethod method, string requestUrl, IDictionary<string, string> headers, IDictionary<string, object> parameters, IBinaryContainer postData) {
|
||||
if (parameters == null) {
|
||||
throw new ArgumentNullException(nameof(parameters));
|
||||
}
|
||||
IDictionary<string, object> requestParameters;
|
||||
// Add oAuth values as HTTP headers, if this is allowed
|
||||
StringBuilder authHeader = null;
|
||||
if (UseHttpHeadersForAuthorization) {
|
||||
authHeader = new StringBuilder();
|
||||
requestParameters = new Dictionary<string, object>();
|
||||
foreach (string parameterKey in parameters.Keys) {
|
||||
if (parameterKey.StartsWith(OAUTH_PARAMETER_PREFIX)) {
|
||||
authHeader.AppendFormat(CultureInfo.InvariantCulture, "{0}=\"{1}\", ", parameterKey, UrlEncode3986($"{parameters[parameterKey]}"));
|
||||
} else if (!requestParameters.ContainsKey(parameterKey)) {
|
||||
requestParameters.Add(parameterKey, parameters[parameterKey]);
|
||||
}
|
||||
}
|
||||
// Remove trailing comma and space and add it to the headers
|
||||
if (authHeader.Length > 0) {
|
||||
authHeader.Remove(authHeader.Length - 2, 2);
|
||||
}
|
||||
} else {
|
||||
requestParameters = parameters;
|
||||
}
|
||||
|
||||
if (HTTPMethod.GET == method || postData != null) {
|
||||
if (requestParameters.Count > 0) {
|
||||
// Add the parameters to the request
|
||||
requestUrl += "?" + NetworkHelper.GenerateQueryParameters(requestParameters);
|
||||
}
|
||||
}
|
||||
// Create webrequest
|
||||
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(requestUrl, method);
|
||||
webRequest.ServicePoint.Expect100Continue = false;
|
||||
webRequest.UserAgent = _userAgent;
|
||||
|
||||
if (UseHttpHeadersForAuthorization && authHeader != null) {
|
||||
Log.DebugFormat("Authorization: OAuth {0}", authHeader);
|
||||
webRequest.Headers.Add("Authorization: OAuth " + authHeader);
|
||||
}
|
||||
|
||||
if (headers != null) {
|
||||
foreach(string key in headers.Keys) {
|
||||
webRequest.Headers.Add(key, headers[key]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((HTTPMethod.POST == method || HTTPMethod.PUT == method) && postData == null && requestParameters.Count > 0) {
|
||||
if (UseMultipartFormData) {
|
||||
NetworkHelper.WriteMultipartFormData(webRequest, requestParameters);
|
||||
} else {
|
||||
StringBuilder form = new StringBuilder();
|
||||
foreach (string parameterKey in requestParameters.Keys)
|
||||
{
|
||||
var binaryParameter = parameters[parameterKey] as IBinaryContainer;
|
||||
form.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", UrlEncode3986(parameterKey), binaryParameter != null ? UrlEncode3986(binaryParameter.ToBase64String(Base64FormattingOptions.None)) : UrlEncode3986($"{parameters[parameterKey]}"));
|
||||
}
|
||||
// Remove trailing &
|
||||
if (form.Length > 0) {
|
||||
form.Remove(form.Length - 1, 1);
|
||||
}
|
||||
webRequest.ContentType = "application/x-www-form-urlencoded";
|
||||
byte[] data = Encoding.UTF8.GetBytes(form.ToString());
|
||||
using var requestStream = webRequest.GetRequestStream();
|
||||
requestStream.Write(data, 0, data.Length);
|
||||
}
|
||||
} else if (postData != null) {
|
||||
postData.Upload(webRequest);
|
||||
} else {
|
||||
webRequest.ContentLength = 0;
|
||||
}
|
||||
|
||||
string responseData;
|
||||
try {
|
||||
responseData = NetworkHelper.GetResponseAsString(webRequest);
|
||||
Log.DebugFormat("Response: {0}", responseData);
|
||||
} catch (Exception ex) {
|
||||
Log.Error("Couldn't retrieve response: ", ex);
|
||||
throw;
|
||||
}
|
||||
|
||||
return responseData;
|
||||
}
|
||||
}
|
||||
}
|
31
GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs
Normal file
31
GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GreenshotPlugin.Core.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a predefined set of algorithms that are supported officially by the OAuth 1.x protocol
|
||||
/// </summary>
|
||||
public enum OAuthSignatureTypes {
|
||||
HMACSHA1,
|
||||
PLAINTEXT,
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -266,33 +266,6 @@ namespace GreenshotPlugin.Core
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve all windows with a certain title or classname
|
||||
/// </summary>
|
||||
/// <param name="windows">IEnumerable</param>
|
||||
/// <param name="titlePattern">The regexp to look for in the title</param>
|
||||
/// <param name="classnamePattern">The regexp to look for in the classname</param>
|
||||
/// <returns>IEnumerable WindowDetails with all the found windows</returns>
|
||||
private static IEnumerable<WindowDetails> FindWindow(IEnumerable<WindowDetails> windows, string titlePattern, string classnamePattern) {
|
||||
Regex titleRegexp = null;
|
||||
Regex classnameRegexp = null;
|
||||
|
||||
if (titlePattern != null && titlePattern.Trim().Length > 0) {
|
||||
titleRegexp = new Regex(titlePattern);
|
||||
}
|
||||
if (classnamePattern != null && classnamePattern.Trim().Length > 0) {
|
||||
classnameRegexp = new Regex(classnamePattern);
|
||||
}
|
||||
|
||||
foreach(WindowDetails window in windows) {
|
||||
if (titleRegexp != null && titleRegexp.IsMatch(window.Text)) {
|
||||
yield return window;
|
||||
} else if (classnameRegexp != null && classnameRegexp.IsMatch(window.ClassName)) {
|
||||
yield return window;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the child with matching classname
|
||||
/// </summary>
|
||||
|
|
|
@ -43,14 +43,14 @@ stages:
|
|||
platform: $(buildPlatform)
|
||||
configuration: $(buildConfiguration)
|
||||
env:
|
||||
Box_ClientId: $(Box_ClientId)
|
||||
Box_ClientSecret: $(Box_ClientSecret)
|
||||
DropBox_ClientId: $(DropBox_ClientId)
|
||||
DropBox_ClientSecret: $(DropBox_ClientSecret)
|
||||
Box13_ClientId: $(Box13_ClientId)
|
||||
Box13_ClientSecret: $(Box13_ClientSecret)
|
||||
DropBox13_ClientId: $(DropBox13_ClientId)
|
||||
DropBox13_ClientSecret: $(DropBox13_ClientSecret)
|
||||
Flickr_ClientId: $(Flickr_ClientId)
|
||||
Flickr_ClientSecret: $(Flickr_ClientSecret)
|
||||
Imgur_ClientId: $(Imgur_ClientId)
|
||||
Imgur_ClientSecret: $(Imgur_ClientSecret)
|
||||
Imgur13_ClientId: $(Imgur13_ClientId)
|
||||
Imgur13_ClientSecret: $(Imgur13_ClientSecret)
|
||||
Photobucket_ClientId: $(Photobucket_ClientId)
|
||||
Photobucket_ClientSecret: $(Photobucket_ClientSecret)
|
||||
Picasa_ClientId: $(Picasa_ClientId)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue