OSDN Git Service

URLをWebブラウザで開く時にスキームが正しいか検証する
[opentween/open-tween.git] / OpenTween / MyCommon.cs
index 2f1461e..04b7d93 100644 (file)
 #nullable enable
 
 using System;
+using System.Collections;
 using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.IO;
-using System.Windows.Forms;
-using System.Web;
-using System.Globalization;
-using System.Security.Cryptography;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
 using System.Drawing;
 using System.Drawing.Imaging;
-using System.Collections;
-using System.Security.Principal;
-using System.Runtime.Serialization.Json;
-using System.Reflection;
-using System.Diagnostics;
-using System.Text.RegularExpressions;
+using System.Globalization;
+using System.IO;
+using System.Linq;
 using System.Net;
 using System.Net.Http;
 using System.Net.NetworkInformation;
+using System.Reflection;
 using System.Runtime.InteropServices;
+using System.Runtime.Serialization.Json;
+using System.Security.Cryptography;
+using System.Security.Principal;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using System.Web;
+using System.Windows.Forms;
 using OpenTween.Api;
 using OpenTween.Models;
 using OpenTween.Setting;
-using System.Diagnostics.CodeAnalysis;
-using System.Threading.Tasks;
-using System.ComponentModel;
 
 namespace OpenTween
 {
     public static class MyCommon
     {
-        private static readonly object LockObj = new object();
-        public static bool _endingFlag;        // 終了フラグ
-        public static string settingPath = null!;
+        private static readonly object LockObj = new();
+
+        public static bool EndingFlag { get; set; } // 終了フラグ
 
         public enum IconSizes
         {
@@ -119,6 +119,20 @@ namespace OpenTween
             Twurl = -1,
         }
 
+        public enum ListItemDoubleClickActionType
+        {
+            // 設定ファイルの互換性を保つため新規の項目は途中に追加しないこと
+            Reply,
+            Favorite,
+            ShowProfile,
+            ShowTimeline,
+            ShowRelated,
+            OpenHomeInBrowser,
+            OpenStatusInBrowser,
+            None,
+            ReplyAll,
+        }
+
         public enum HITRESULT
         {
             None,
@@ -191,6 +205,7 @@ namespace OpenTween
         }
 
         public static _Assembly EntryAssembly { get; internal set; }
+
         public static string FileVersion { get; internal set; }
 
         static MyCommon()
@@ -215,20 +230,20 @@ namespace OpenTween
             TraceOut(TraceFlag, message);
         }
 
-        public static void TraceOut(Exception ex, string Message)
+        public static void TraceOut(Exception ex, string message)
         {
             var buf = ExceptionOutMessage(ex);
-            TraceOut(TraceFlag, Message + Environment.NewLine + buf);
+            TraceOut(TraceFlag, message + Environment.NewLine + buf);
         }
 
-        public static void TraceOut(string Message)
-            => TraceOut(TraceFlag, Message);
+        public static void TraceOut(string message)
+            => TraceOut(TraceFlag, message);
 
-        public static void TraceOut(bool OutputFlag, string Message)
+        public static void TraceOut(bool outputFlag, string message)
         {
             lock (LockObj)
             {
-                if (!OutputFlag) return;
+                if (!outputFlag) return;
 
                 var logPath = MyCommon.GetErrorLogPath();
                 if (!Directory.Exists(logPath))
@@ -248,7 +263,7 @@ namespace OpenTween
                 writer.WriteLine(Properties.Resources.TraceOutText4, Environment.OSVersion.VersionString);
                 writer.WriteLine(Properties.Resources.TraceOutText5, Environment.Version);
                 writer.WriteLine(Properties.Resources.TraceOutText6, ApplicationSettings.AssemblyName, FileVersion);
-                writer.WriteLine(Message);
+                writer.WriteLine(message);
                 writer.WriteLine();
             }
         }
@@ -260,11 +275,11 @@ namespace OpenTween
 
         public static string ExceptionOutMessage(Exception ex)
         {
-            var IsTerminatePermission = true;
-            return ExceptionOutMessage(ex, ref IsTerminatePermission);
+            var isTerminatePermission = true;
+            return ExceptionOutMessage(ex, ref isTerminatePermission);
         }
 
-        public static string ExceptionOutMessage(Exception ex, ref bool IsTerminatePermission)
+        public static string ExceptionOutMessage(Exception ex, ref bool isTerminatePermission)
         {
             if (ex == null) return "";
 
@@ -287,7 +302,7 @@ namespace OpenTween
                     buf.AppendLine();
                     if (dt.Key.Equals("IsTerminatePermission"))
                     {
-                        IsTerminatePermission = (bool)dt.Value;
+                        isTerminatePermission = (bool)dt.Value;
                     }
                 }
                 if (!needHeader)
@@ -299,19 +314,19 @@ namespace OpenTween
             buf.AppendLine();
 
             // InnerExceptionが存在する場合書き出す
-            var _ex = ex.InnerException;
+            var innerException = ex.InnerException;
             var nesting = 0;
-            while (_ex != null)
+            while (innerException != null)
             {
                 buf.AppendFormat("-----InnerException[{0}]-----\r\n", nesting);
                 buf.AppendLine();
-                buf.AppendFormat(Properties.Resources.UnhandledExceptionText8, _ex.GetType().FullName, _ex.Message);
+                buf.AppendFormat(Properties.Resources.UnhandledExceptionText8, innerException.GetType().FullName, innerException.Message);
                 buf.AppendLine();
-                if (_ex.Data != null)
+                if (innerException.Data != null)
                 {
                     var needHeader = true;
 
-                    foreach (DictionaryEntry dt in _ex.Data)
+                    foreach (DictionaryEntry dt in innerException.Data)
                     {
                         if (needHeader)
                         {
@@ -322,7 +337,7 @@ namespace OpenTween
                         buf.AppendFormat("{0}  :  {1}", dt.Key, dt.Value);
                         if (dt.Key.Equals("IsTerminatePermission"))
                         {
-                            IsTerminatePermission = (bool)dt.Value;
+                            isTerminatePermission = (bool)dt.Value;
                         }
                     }
                     if (!needHeader)
@@ -330,10 +345,10 @@ namespace OpenTween
                         buf.AppendLine("-----End Extra Information-----");
                     }
                 }
-                buf.AppendLine(_ex.StackTrace);
+                buf.AppendLine(innerException.StackTrace);
                 buf.AppendLine();
                 nesting++;
-                _ex = _ex.InnerException;
+                innerException = innerException.InnerException;
             }
             return buf.ToString();
         }
@@ -342,7 +357,7 @@ namespace OpenTween
         {
             lock (LockObj)
             {
-                var IsTerminatePermission = true;
+                var isTerminatePermission = true;
 
                 var ident = WindowsIdentity.GetCurrent();
                 var princ = new WindowsPrincipal(ident);
@@ -362,7 +377,7 @@ namespace OpenTween
                     string.Format(Properties.Resources.UnhandledExceptionText6, Environment.Version),
                     string.Format(Properties.Resources.UnhandledExceptionText7, ApplicationSettings.AssemblyName, FileVersion),
 
-                    ExceptionOutMessage(ex, ref IsTerminatePermission));
+                    ExceptionOutMessage(ex, ref isTerminatePermission));
 
                 var logPath = MyCommon.GetErrorLogPath();
                 if (!Directory.Exists(logPath))
@@ -374,7 +389,7 @@ namespace OpenTween
                     writer.Write(errorReport);
                 }
 
-                var settings = SettingManager.Common;
+                var settings = SettingManager.Instance;
                 var mainForm = Application.OpenForms.OfType<TweenMain>().FirstOrDefault();
 
                 ErrorReport report;
@@ -383,15 +398,15 @@ namespace OpenTween
                 else
                     report = new ErrorReport(errorReport);
 
-                report.AnonymousReport = settings.ErrorReportAnonymous;
+                report.AnonymousReport = settings.Common.ErrorReportAnonymous;
 
                 OpenErrorReportDialog(mainForm, report);
 
                 // ダイアログ内で設定が変更されていれば保存する
-                if (settings.ErrorReportAnonymous != report.AnonymousReport)
+                if (settings.Common.ErrorReportAnonymous != report.AnonymousReport)
                 {
-                    settings.ErrorReportAnonymous = report.AnonymousReport;
-                    settings.Save();
+                    settings.Common.ErrorReportAnonymous = report.AnonymousReport;
+                    settings.SaveCommon();
                 }
 
                 return false;
@@ -653,7 +668,7 @@ namespace OpenTween
             SearchResults = 4096,
         }
 
-        public static TwitterApiStatus TwitterApiInfo = new TwitterApiStatus();
+        public static TwitterApiStatus TwitterApiInfo = new();
 
         public static bool IsAnimatedGif(string filename)
         {
@@ -689,7 +704,8 @@ namespace OpenTween
 
         public static DateTimeUtc DateTimeParse(string input)
         {
-            var formats = new[] {
+            var formats = new[]
+            {
                 "ddd MMM dd HH:mm:ss zzzz yyyy",
                 "ddd, d MMM yyyy HH:mm:ss zzzz",
             };
@@ -710,7 +726,7 @@ namespace OpenTween
             {
                 UseSimpleDictionaryFormat = true,
             };
-            return (T)((new DataContractJsonSerializer(typeof(T), settings)).ReadObject(stream));
+            return (T)new DataContractJsonSerializer(typeof(T), settings).ReadObject(stream);
         }
 
         public static bool IsNetworkAvailable()
@@ -740,9 +756,9 @@ namespace OpenTween
         /// <param name="keys">状態を調べるキー</param>
         /// <returns><paramref name="keys"/> で指定された修飾キーがすべて押されている状態であれば true。それ以外であれば false。</returns>
         public static bool IsKeyDown(params Keys[] keys)
-            => MyCommon._IsKeyDown(Control.ModifierKeys, keys);
+            => MyCommon.IsKeyDownInternal(Control.ModifierKeys, keys);
 
-        internal static bool _IsKeyDown(Keys modifierKeys, Keys[] targetKeys)
+        internal static bool IsKeyDownInternal(Keys modifierKeys, Keys[] targetKeys)
         {
             foreach (var key in targetKeys)
             {
@@ -856,7 +872,7 @@ namespace OpenTween
 
         // .NET 4.5+: Reserved characters のうち、Uriクラスによってエスケープ強制解除されてしまうものも最初から Unreserved として扱う
         private static readonly HashSet<char> UnreservedChars =
-            new HashSet<char>("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~!'()*:");
+            new("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~!'()*:");
 
         /// <summary>
         /// 2バイト文字も考慮したクエリ用エンコード
@@ -968,24 +984,43 @@ namespace OpenTween
         public static bool IsNullOrEmpty([NotNullWhen(false)] string? value)
             => string.IsNullOrEmpty(value);
 
-        public static Task OpenInBrowserAsync(IWin32Window? owner, string url)
-            => MyCommon.OpenInBrowserAsync(owner, SettingManager.Local.BrowserPath, url);
+        public static Task OpenInBrowserAsync(IWin32Window? owner, string urlStr)
+            => MyCommon.OpenInBrowserAsync(owner, SettingManager.Instance.Local.BrowserPath, urlStr);
+
+        public static Task OpenInBrowserAsync(IWin32Window? owner, Uri uri)
+            => MyCommon.OpenInBrowserAsync(owner, SettingManager.Instance.Local.BrowserPath, uri);
+
+        public static async Task OpenInBrowserAsync(IWin32Window? owner, string? browserPath, string urlStr)
+        {
+            if (!Uri.TryCreate(urlStr, UriKind.Absolute, out var uri))
+            {
+                var message = string.Format(Properties.Resources.CannotOpenUriText, urlStr);
+                MessageBox.Show(owner, message, ApplicationSettings.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
+            }
+            await MyCommon.OpenInBrowserAsync(owner, browserPath, uri);
+        }
 
-        public static Task OpenInBrowserAsync(IWin32Window? owner, string? browserPath, string url)
+        public static async Task OpenInBrowserAsync(IWin32Window? owner, string? browserPath, Uri uri)
         {
-            return Task.Run(() =>
+            if (uri.Scheme != "http" && uri.Scheme != "https")
             {
-                try
+                var message = string.Format(Properties.Resources.CannotOpenUriText, uri.OriginalString);
+                MessageBox.Show(owner, message, ApplicationSettings.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
+            }
+
+            try
+            {
+                await Task.Run(() =>
                 {
                     var startInfo = MyCommon.CreateBrowserProcessStartInfo(browserPath, url);
                     Process.Start(startInfo);
-                }
-                catch (Win32Exception ex)
-                {
-                    var message = string.Format(Properties.Resources.BrowserStartFailed, ex.ErrorCode);
-                    MessageBox.Show(owner, message, ApplicationSettings.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
-                }
-            });
+                });
+            }
+            catch (Win32Exception ex)
+            {
+                var message = string.Format(Properties.Resources.BrowserStartFailed, ex.Message);
+                MessageBox.Show(owner, message, ApplicationSettings.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
+            }
         }
 
         public static ProcessStartInfo CreateBrowserProcessStartInfo(string? browserPathWithArgs, string url)
@@ -999,7 +1034,7 @@ namespace OpenTween
                 };
             }
 
-            int quoteEnd = -1;
+            var quoteEnd = -1;
             if (browserPathWithArgs.StartsWith("\"", StringComparison.Ordinal))
                 quoteEnd = browserPathWithArgs.IndexOf("\"", 1, StringComparison.Ordinal);
 
@@ -1026,5 +1061,36 @@ namespace OpenTween
                 UseShellExecute = false,
             };
         }
+
+        public static IEnumerable<(int Start, int End)> ToRangeChunk(IEnumerable<int> values)
+        {
+            var start = -1;
+            var end = -1;
+
+            foreach (var value in values.OrderBy(x => x))
+            {
+                if (start == -1)
+                {
+                    start = value;
+                    end = value;
+                }
+                else
+                {
+                    if (value == end + 1)
+                    {
+                        end = value;
+                    }
+                    else
+                    {
+                        yield return (start, end);
+                        start = value;
+                        end = value;
+                    }
+                }
+            }
+
+            if (start != -1)
+                yield return (start, end);
+        }
     }
 }