OSDN Git Service

488d926b29fe89b629b9b8d81417d4920a0fb955
[opentween/open-tween.git] / OpenTween / Setting / SettingCommon.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2007-2011 kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
3 //           (c) 2008-2011 Moz (@syo68k)
4 //           (c) 2008-2011 takeshik (@takeshik) <http://www.takeshik.org/>
5 //           (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
6 //           (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
7 //           (c) 2011      kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
8 // All rights reserved.
9 //
10 // This file is part of OpenTween.
11 //
12 // This program is free software; you can redistribute it and/or modify it
13 // under the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 3 of the License, or (at your option)
15 // any later version.
16 //
17 // This program is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
24 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
25 // Boston, MA 02110-1301, USA.
26
27 #nullable enable
28
29 using System;
30 using System.Collections.Generic;
31 using System.Windows.Forms;
32 using System.Xml.Serialization;
33 using OpenTween.Connection;
34 using OpenTween.Thumbnail;
35
36 namespace OpenTween
37 {
38     [XmlSerializerAssembly(null, null)] // OpenTween アセンブリ内の XmlSerializerContract を使用させる
39     public class SettingCommon : SettingBase<SettingCommon>
40     {
41         #region "Settingクラス基本"
42         public static SettingCommon Load(string settingsPath)
43             => LoadSettings(settingsPath);
44
45         public void Save(string settingsPath)
46             => SaveSettings(this, settingsPath);
47         #endregion
48
49         public List<UserAccount> UserAccounts = new();
50
51         public Guid? SelectedAccountKey { get; set; } = null;
52
53         [XmlIgnore]
54         public UserAccount? SelectedAccount
55             => this.UserAccounts.Find(x => x.UniqueKey == this.SelectedAccountKey);
56
57         public string UserName = "";
58
59         [XmlIgnore]
60         public string Password = "";
61
62         public string EncryptPassword
63         {
64             get => this.Encrypt(this.Password);
65             set => this.Password = this.Decrypt(value);
66         }
67
68         public string Token = "";
69         [XmlIgnore]
70         public string TokenSecret = "";
71
72         public string EncryptTokenSecret
73         {
74             get => this.Encrypt(this.TokenSecret);
75             set => this.TokenSecret = this.Decrypt(value);
76         }
77
78         private string Encrypt(string password)
79         {
80             if (MyCommon.IsNullOrEmpty(password)) password = "";
81             if (password.Length > 0)
82             {
83                 try
84                 {
85                     return MyCommon.EncryptString(password);
86                 }
87                 catch (Exception)
88                 {
89                     return "";
90                 }
91             }
92             else
93             {
94                 return "";
95             }
96         }
97
98         private string Decrypt(string password)
99         {
100             if (MyCommon.IsNullOrEmpty(password)) password = "";
101             if (password.Length > 0)
102             {
103                 try
104                 {
105                     password = MyCommon.DecryptString(password);
106                 }
107                 catch (Exception)
108                 {
109                     password = "";
110                 }
111             }
112             return password;
113         }
114
115         public long UserId = 0;
116         public List<string> TabList = new();
117         public int TimelinePeriod = 90;
118         public int ReplyPeriod = 180;
119         public int DMPeriod = 600;
120         public int PubSearchPeriod = 180;
121         public int ListsPeriod = 180;
122
123         /// <summary>
124         /// 起動時読み込み分を既読にするか。trueなら既読として処理
125         /// </summary>
126         public bool Read = true;
127
128         public bool ListLock = false;
129         public MyCommon.IconSizes IconSize = MyCommon.IconSizes.Icon16;
130         public bool NewAllPop = true;
131         public string TranslateLanguage = Properties.Resources.TranslateDefaultLanguage;
132
133         /// <summary>
134         /// サウンド再生(タブ別設定より優先)
135         /// </summary>
136         public bool PlaySound = false;
137
138         /// <summary>
139         /// 未読管理。trueなら未読管理する
140         /// </summary>
141         public bool UnreadManage = true;
142
143         /// <summary>
144         /// 片思い表示。trueなら片思い表示する
145         /// </summary>
146         public bool OneWayLove = true;
147
148         public MyCommon.NameBalloonEnum NameBalloon = MyCommon.NameBalloonEnum.NickName;
149         public bool PostCtrlEnter = true;
150         public bool PostShiftEnter = false;
151         public int CountApi = 60;
152         public int CountApiReply = 40;
153         public bool PostAndGet = true;
154         public bool DispUsername = false;
155         public bool MinimizeToTray = false;
156         public bool CloseToExit = false;
157         public MyCommon.DispTitleEnum DispLatestPost = MyCommon.DispTitleEnum.Post;
158         public bool SortOrderLock = false;
159
160         /// <summary>
161         /// タブを下部に表示するかどうか
162         /// </summary>
163         public bool ViewTabBottom = true;
164
165         public bool TinyUrlResolve = true;
166         public bool StartupVersion = true;
167         public bool StartupFollowers = true;
168
169         /// <summary>
170         /// Twitter API v2 の使用を有効にする
171         /// </summary>
172         [XmlIgnore]
173         public bool EnableTwitterV2Api => false;
174
175         public bool RestrictFavCheck = false;
176         public bool AlwaysTop = false;
177         public string CultureCode = "";
178         public bool UrlConvertAuto = false;
179         public int SortColumn = 3;
180         public int SortOrder = 1;
181         public bool IsMonospace = false;
182         public bool ReadOldPosts = false;
183         public string Language = "OS";
184         public bool Nicoms = false;
185         public List<string> HashTags = new();
186         public string HashSelected = "";
187         public bool HashIsPermanent = false;
188         public bool HashIsHead = false;
189         public bool HashIsNotAddToAtReply = true;
190         public bool PreviewEnable = true;
191         public bool StatusAreaAtBottom = true;
192
193         public MyCommon.UrlConverter AutoShortUrlFirst = MyCommon.UrlConverter.Uxnu;
194         public bool UseUnreadStyle = true;
195         public string DateTimeFormat = "yyyy/MM/dd H:mm:ss";
196         public int DefaultTimeOut = 20;
197
198         /// <summary>画像アップロードのタイムアウト設定 (秒)</summary>
199         public int UploadImageTimeout { get; set; } = 60;
200
201         public bool RetweetNoConfirm = false;
202         public bool LimitBalloon = false;
203         public bool TabIconDisp = true;
204         public MyCommon.REPLY_ICONSTATE ReplyIconState = MyCommon.REPLY_ICONSTATE.StaticIcon;
205         public bool WideSpaceConvert = true;
206         public bool ReadOwnPost = false;
207         public bool GetFav = true;
208         public string BilyUser = "";
209         public string BitlyPwd = "";
210
211         /// <summary>Bitly API アクセストークン</summary>
212         public string BitlyAccessToken { get; set; } = "";
213
214         public bool ShowGrid = false;
215         public bool UseAtIdSupplement = true;
216         public bool UseHashSupplement = true;
217
218         [XmlElement(ElementName = "TwitterUrl")]
219         public string TwitterApiHost = "api.twitter.com";
220
221         public bool HotkeyEnabled = false;
222         public Keys HotkeyModifier = Keys.None;
223         public Keys HotkeyKey = Keys.None;
224         public int HotkeyValue = 0;
225         public bool BlinkNewMentions = false;
226         public bool FocusLockToStatusText = false;
227         public bool UseAdditionalCount = false;
228         public int MoreCountApi = 200;
229         public int FirstCountApi = 100;
230         public int SearchCountApi = 100;
231         public int FavoritesCountApi = 40;
232         public int UserTimelineCountApi = 20;
233         public int UserTimelinePeriod = 600;
234         public bool OpenUserTimeline = true;
235         public int ListCountApi = 100;
236         public int UseImageService = 0;
237         public string UseImageServiceName = "";
238
239         [XmlIgnore]
240         public MyCommon.ListItemDoubleClickActionType ListDoubleClickAction { get; set; } = MyCommon.ListItemDoubleClickActionType.Reply;
241
242         [XmlElement(ElementName = nameof(ListDoubleClickAction))]
243         public int ListDoubleClickActionNumeric
244         {
245             get => (int)this.ListDoubleClickAction;
246             set => this.ListDoubleClickAction = (MyCommon.ListItemDoubleClickActionType)value;
247         }
248
249         public string UserAppointUrl = "";
250         public bool HideDuplicatedRetweets = false;
251         public bool EnableImgAzyobuziNet = true;
252         public bool ImgAzyobuziNetDisabledInDM = true;
253         public int MapThumbnailHeight = 200;
254         public int MapThumbnailWidth = 200;
255         public int MapThumbnailZoom = 15;
256         public MapProvider MapThumbnailProvider = MapProvider.OpenStreetMap;
257
258         /// <summary>Listの発言取得に公式RTを含める</summary>
259         public bool IsListsIncludeRts = true;
260
261         public bool TabMouseLock = false;
262         public bool IsUseNotifyGrowl = false;
263         public bool ForceIPv4 = false;
264         public bool ErrorReportAnonymous = true;
265
266         /// <summary>pic.twitter.com への画像アップロード時に JPEG への変換を回避する</summary>
267         public bool AlphaPNGWorkaround { get; set; } = false;
268
269         /// <summary>アップデート通知を無視するバージョン番号</summary>
270         [XmlIgnore]
271         public Version? SkipUpdateVersion
272         {
273             get => MyCommon.IsNullOrEmpty(this.SkipUpdateVersionStr) ? null : Version.Parse(this.SkipUpdateVersionStr);
274             set => this.SkipUpdateVersionStr = value == null ? "" : value.ToString();
275         }
276
277         [XmlElement(ElementName = nameof(SkipUpdateVersion))]
278         public string SkipUpdateVersionStr { get; set; } = "";
279
280         public void Validate()
281         {
282             if (this.TimelinePeriod < 0)
283                 this.TimelinePeriod = 15;
284
285             if (this.ReplyPeriod < 0)
286                 this.ReplyPeriod = 15;
287
288             if (this.DMPeriod < 0)
289                 this.DMPeriod = 15;
290
291             if (this.PubSearchPeriod < 0)
292                 this.PubSearchPeriod = 30;
293
294             if (this.UserTimelinePeriod < 0)
295                 this.UserTimelinePeriod = 15;
296
297             if (this.ListsPeriod < 0)
298                 this.ListsPeriod = 15;
299
300             if (!Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.Timeline, this.CountApi))
301                 this.CountApi = 60;
302
303             if (!Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.Reply, this.CountApiReply))
304                 this.CountApiReply = 40;
305
306             if (this.MoreCountApi != 0 && !Twitter.VerifyMoreApiResultCount(this.MoreCountApi))
307                 this.MoreCountApi = 200;
308
309             if (this.FirstCountApi != 0 && !Twitter.VerifyFirstApiResultCount(this.FirstCountApi))
310                 this.FirstCountApi = 100;
311
312             if (this.FavoritesCountApi != 0 && !Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.Favorites, this.FavoritesCountApi))
313                 this.FavoritesCountApi = 40;
314
315             if (this.ListCountApi != 0 && !Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.List, this.ListCountApi))
316                 this.ListCountApi = 100;
317
318             if (this.SearchCountApi != 0 && !Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.PublicSearch, this.SearchCountApi))
319                 this.SearchCountApi = 100;
320
321             if (this.UserTimelineCountApi != 0 && !Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.UserTimeline, this.UserTimelineCountApi))
322                 this.UserTimelineCountApi = 20;
323
324             // 廃止サービスが選択されていた場合ux.nuへ読み替え
325             if (this.AutoShortUrlFirst < 0)
326                 this.AutoShortUrlFirst = MyCommon.UrlConverter.Uxnu;
327
328             UserAccount? selectedAccount;
329             if (this.SelectedAccountKey != null)
330             {
331                 selectedAccount = this.SelectedAccount;
332             }
333             else
334             {
335                 selectedAccount = this.UserAccounts.Find(
336                     x => string.Equals(x.Username, this.UserName, StringComparison.InvariantCultureIgnoreCase)
337                 );
338             }
339
340             this.SelectedAccountKey = selectedAccount?.UniqueKey;
341
342             if (selectedAccount?.UserId == 0)
343                 selectedAccount.UserId = this.UserId;
344
345             if (MyCommon.IsNullOrEmpty(this.Token))
346                 this.UserName = "";
347         }
348     }
349
350     public class UserAccount
351     {
352         public Guid UniqueKey { get; set; } = Guid.NewGuid();
353
354         public string Username = "";
355         public long UserId = 0;
356
357         public APIAuthType TwitterAuthType { get; set; }
358
359         public string TwitterOAuth1ConsumerKey { get; set; } = "";
360
361         [XmlIgnore]
362         public string TwitterOAuth1ConsumerSecret { get; set; } = "";
363
364         public string TwitterOAuth1ConsumerSecretEncrypted
365         {
366             get => this.Encrypt(this.TwitterOAuth1ConsumerSecret);
367             set => this.TwitterOAuth1ConsumerSecret = this.Decrypt(value);
368         }
369
370         [XmlIgnore]
371         public string TwitterComCookie { get; set; } = "";
372
373         public string TwitterComCookieEncrypted
374         {
375             get => this.Encrypt(this.TwitterComCookie);
376             set => this.TwitterComCookie = this.Decrypt(value);
377         }
378
379         public string Token = "";
380
381         [XmlIgnore]
382         public string TokenSecret = "";
383
384         public string EncryptTokenSecret
385         {
386             get => this.Encrypt(this.TokenSecret);
387             set => this.TokenSecret = this.Decrypt(value);
388         }
389
390         public TwitterAppToken GetTwitterAppToken()
391         {
392             return new()
393             {
394                 AuthType = this.TwitterAuthType,
395                 OAuth1CustomConsumerKey = MyCommon.IsNullOrEmpty(this.TwitterOAuth1ConsumerKey) ? null : ApiKey.Create(this.TwitterOAuth1ConsumerKey),
396                 OAuth1CustomConsumerSecret = MyCommon.IsNullOrEmpty(this.TwitterOAuth1ConsumerSecret) ? null : ApiKey.Create(this.TwitterOAuth1ConsumerSecret),
397                 TwitterComCookie = this.TwitterComCookie,
398             };
399         }
400
401         public ITwitterCredential GetTwitterCredential()
402         {
403             var appToken = this.GetTwitterAppToken();
404
405             return appToken.AuthType switch
406             {
407                 APIAuthType.OAuth1
408                     => new TwitterCredentialOAuth1(appToken, this.TwitterOAuth1ConsumerKey, this.TwitterOAuth1ConsumerSecret),
409                 APIAuthType.TwitterComCookie
410                     => new TwitterCredentialCookie(appToken),
411                 _ => new TwitterCredentialNone(),
412             };
413         }
414
415         private string Encrypt(string password)
416         {
417             if (MyCommon.IsNullOrEmpty(password)) password = "";
418             if (password.Length > 0)
419             {
420                 try
421                 {
422                     return MyCommon.EncryptString(password);
423                 }
424                 catch (Exception)
425                 {
426                     return "";
427                 }
428             }
429             else
430             {
431                 return "";
432             }
433         }
434
435         private string Decrypt(string password)
436         {
437             if (MyCommon.IsNullOrEmpty(password)) password = "";
438             if (password.Length > 0)
439             {
440                 try
441                 {
442                     password = MyCommon.DecryptString(password);
443                 }
444                 catch (Exception)
445                 {
446                     password = "";
447                 }
448             }
449             return password;
450         }
451
452         public override string ToString()
453             => this.Username;
454     }
455
456     public enum APIAuthType
457     {
458         None,
459         OAuth1,
460         TwitterComCookie,
461     }
462 }