OSDN Git Service

list_updatedイベントにとりあえず対応
[opentween/open-tween.git] / Tween / MyCommon.vb
1 ' Tween - 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 ' All rights reserved.
8
9 ' This file is part of Tween.
10
11 ' This program is free software; you can redistribute it and/or modify it
12 ' under the terms of the GNU General Public License as published by the Free
13 ' Software Foundation; either version 3 of the License, or (at your option)
14 ' any later version.
15
16 ' This program is distributed in the hope that it will be useful, but
17 ' WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 ' or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 ' for more details. 
20
21 ' You should have received a copy of the GNU General Public License along
22 ' with this program. If not, see <http://www.gnu.org/licenses/>, or write to
23 ' the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
24 ' Boston, MA 02110-1301, USA.
25
26 Imports System.Text
27 Imports System.Globalization
28 Imports System.Security.Principal
29 Imports System.Reflection
30 Imports System.Web
31 Imports System.IO
32 Imports System.Runtime.Serialization.Json
33
34 Public Module MyCommon
35     Private ReadOnly LockObj As New Object
36     Public _endingFlag As Boolean        '終了フラグ
37     Public cultureStr As String = Nothing
38
39     Public Enum IconSizes
40         IconNone = 0
41         Icon16 = 1
42         Icon24 = 2
43         Icon48 = 3
44         Icon48_2 = 4
45     End Enum
46
47     Public Enum NameBalloonEnum
48         None
49         UserID
50         NickName
51     End Enum
52
53     Public Enum DispTitleEnum
54         None
55         Ver
56         Post
57         UnreadRepCount
58         UnreadAllCount
59         UnreadAllRepCount
60         UnreadCountAllCount
61         OwnStatus
62     End Enum
63
64     Public Enum LogUnitEnum
65         Minute
66         Hour
67         Day
68     End Enum
69
70     Public Enum UploadFileType
71         Invalid
72         Picture
73         MultiMedia
74     End Enum
75
76     Public Enum UrlConverter
77         TinyUrl
78         Isgd
79         Twurl
80         Bitly
81         Jmp
82         Uxnu
83         '特殊
84         Nicoms
85         '廃止
86         Unu = -1
87     End Enum
88
89     Public Enum OutputzUrlmode
90         twittercom
91         twittercomWithUsername
92     End Enum
93
94     Public Enum HITRESULT
95         None
96         Copy
97         CopyAndMark
98         Move
99         Exclude
100     End Enum
101
102     Public Enum HttpTimeOut
103         MinValue = 10
104         MaxValue = 120
105         DefaultValue = 20
106     End Enum
107
108     'Backgroundworkerへ処理種別を通知するための引数用Enum
109     Public Enum WORKERTYPE
110         Timeline                'タイムライン取得
111         Reply                   '返信取得
112         DirectMessegeRcv        '受信DM取得
113         DirectMessegeSnt        '送信DM取得
114         PostMessage             '発言POST
115         FavAdd                  'Fav追加
116         FavRemove               'Fav削除
117         Follower                'Followerリスト取得
118         OpenUri                 'Uri開く
119         Favorites               'Fav取得
120         Retweet                 'Retweetする
121         PublicSearch            '公式検索
122         List                    'Lists
123         Related                 '関連発言
124         UserStream              'UserStream
125         UserTimeline            'UserTimeline
126         BlockIds                'Blocking/ids
127         '''
128         ErrorState              'エラー表示のみで後処理終了(認証エラー時など)
129     End Enum
130
131     Public Structure DEFAULTTAB
132         Const RECENT As String = "Recent"
133         Const REPLY As String = "Reply"
134         Const DM As String = "Direct"
135         Const FAV As String = "Favorites"
136
137         Private dummy As String
138
139         Private Shadows Function ReferenceEquals() As Object
140             Return New Object
141         End Function
142         Private Shadows Function Equals() As Object
143             Return New Object
144         End Function
145     End Structure
146
147     Public Const Block As Object = Nothing
148     Public TraceFlag As Boolean = False
149
150 #If DEBUG Then
151     Public DebugBuild As Boolean = True
152 #Else
153     Public DebugBuild As Boolean = False
154 #End If
155
156     Public Enum ACCOUNT_STATE
157         Valid
158         Invalid
159         Validating
160     End Enum
161
162     Public Enum REPLY_ICONSTATE
163         None
164         StaticIcon
165         BlinkIcon
166     End Enum
167
168     <FlagsAttribute()> _
169     Public Enum EVENTTYPE
170         None = 0
171         Favorite = 1
172         Unfavorite = 2
173         Follow = 4
174         ListMemberAdded = 8
175         ListMemberRemoved = 16
176         Block = 32
177         Unblock = 64
178         UserUpdate = 128
179         Deleted = 256
180         ListCreated = 512
181         ListUpdated = 1024
182
183         All = (None Or Favorite Or Unfavorite Or Follow Or ListMemberAdded Or ListMemberRemoved Or _
184                Block Or Unblock Or UserUpdate Or Deleted Or ListCreated Or ListUpdated)
185     End Enum
186
187     Public Sub TraceOut(ByVal ex As Exception, ByVal Message As String)
188         Dim buf As String = ExceptionOutMessage(ex)
189         TraceOut(TraceFlag, Message + Environment.NewLine + buf)
190     End Sub
191
192     Public Sub TraceOut(ByVal Message As String)
193         TraceOut(TraceFlag, Message)
194     End Sub
195
196     Public Sub TraceOut(ByVal OutputFlag As Boolean, ByVal Message As String)
197         SyncLock LockObj
198             If Not OutputFlag Then Exit Sub
199             Dim now As DateTime = DateTime.Now
200             Dim fileName As String = String.Format("TweenTrace-{0:0000}{1:00}{2:00}-{3:00}{4:00}{5:00}.log", now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second)
201
202             Using writer As IO.StreamWriter = New IO.StreamWriter(fileName)
203                 writer.WriteLine("**** TraceOut: {0} ****", DateTime.Now.ToString())
204                 writer.WriteLine(My.Resources.TraceOutText1)
205                 writer.WriteLine(My.Resources.TraceOutText2)
206                 writer.WriteLine()
207                 writer.WriteLine(My.Resources.TraceOutText3)
208                 writer.WriteLine(My.Resources.TraceOutText4, Environment.OSVersion.VersionString)
209                 writer.WriteLine(My.Resources.TraceOutText5, Environment.Version.ToString())
210                 writer.WriteLine(My.Resources.TraceOutText6, fileVersion)
211                 writer.WriteLine(Message)
212                 writer.WriteLine()
213             End Using
214         End SyncLock
215     End Sub
216
217     ' エラー内容をバッファに書き出し
218     ' 注意:最終的にファイル出力されるエラーログに記録されるため次の情報は書き出さない
219     ' 文頭メッセージ、権限、動作環境
220     ' Dataプロパティにある終了許可フラグのパースもここで行う
221
222     Public Function ExceptionOutMessage(ByVal ex As Exception, _
223                                  Optional ByRef IsTerminatePermission As Boolean = True) As String
224         If ex Is Nothing Then Return ""
225
226         Dim buf As New StringBuilder
227
228         buf.AppendFormat(My.Resources.UnhandledExceptionText8, ex.GetType().FullName, ex.Message)
229         buf.AppendLine()
230         If ex.Data IsNot Nothing Then
231             Dim needHeader As Boolean = True
232             For Each dt As DictionaryEntry In ex.Data
233                 If needHeader Then
234                     buf.AppendLine()
235                     buf.AppendLine("-------Extra Information-------")
236                     needHeader = False
237                 End If
238                 buf.AppendFormat("{0}  :  {1}", dt.Key, dt.Value)
239                 buf.AppendLine()
240                 If dt.Key.Equals("IsTerminatePermission") Then
241                     IsTerminatePermission = CBool(dt.Value)
242                 End If
243             Next
244             If Not needHeader Then
245                 buf.AppendLine("-----End Extra Information-----")
246             End If
247         End If
248         buf.AppendLine(ex.StackTrace)
249         buf.AppendLine()
250
251         'InnerExceptionが存在する場合書き出す
252         Dim _ex As Exception = ex.InnerException
253         Dim nesting As Integer = 0
254         While _ex IsNot Nothing
255             buf.AppendFormat("-----InnerException[{0}]-----" + vbCrLf, nesting)
256             buf.AppendLine()
257             buf.AppendFormat(My.Resources.UnhandledExceptionText8, _ex.GetType().FullName, _ex.Message)
258             buf.AppendLine()
259             If _ex.Data IsNot Nothing Then
260                 Dim needHeader As Boolean = True
261
262                 For Each dt As DictionaryEntry In _ex.Data
263                     If needHeader Then
264                         buf.AppendLine()
265                         buf.AppendLine("-------Extra Information-------")
266                         needHeader = False
267                     End If
268                     buf.AppendFormat("{0}  :  {1}", dt.Key, dt.Value)
269                     If dt.Key.Equals("IsTerminatePermission") Then
270                         IsTerminatePermission = CBool(dt.Value)
271                     End If
272                 Next
273                 If Not needHeader Then
274                     buf.AppendLine("-----End Extra Information-----")
275                 End If
276             End If
277             buf.AppendLine(_ex.StackTrace)
278             buf.AppendLine()
279             nesting += 1
280             _ex = _ex.InnerException
281         End While
282         Return buf.ToString()
283     End Function
284
285     Public Function ExceptionOut(ByVal ex As Exception) As Boolean
286         SyncLock LockObj
287             Dim IsTerminatePermission As Boolean = True
288             Dim now As DateTime = DateTime.Now
289             Dim fileName As String = String.Format("Tween-{0:0000}{1:00}{2:00}-{3:00}{4:00}{5:00}.log", now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second)
290
291             Using writer As IO.StreamWriter = New IO.StreamWriter(fileName)
292                 Dim ident As WindowsIdentity = WindowsIdentity.GetCurrent()
293                 Dim princ As New WindowsPrincipal(ident)
294
295                 writer.WriteLine(My.Resources.UnhandledExceptionText1, DateTime.Now.ToString())
296                 writer.WriteLine(My.Resources.UnhandledExceptionText2)
297                 writer.WriteLine(My.Resources.UnhandledExceptionText3)
298                 ' 権限書き出し
299                 writer.WriteLine(My.Resources.UnhandledExceptionText11 + princ.IsInRole(WindowsBuiltInRole.Administrator).ToString)
300                 writer.WriteLine(My.Resources.UnhandledExceptionText12 + princ.IsInRole(WindowsBuiltInRole.User).ToString)
301                 writer.WriteLine()
302                 ' OSVersion,AppVersion書き出し
303                 writer.WriteLine(My.Resources.UnhandledExceptionText4)
304                 writer.WriteLine(My.Resources.UnhandledExceptionText5, Environment.OSVersion.VersionString)
305                 writer.WriteLine(My.Resources.UnhandledExceptionText6, Environment.Version.ToString())
306                 writer.WriteLine(My.Resources.UnhandledExceptionText7, fileVersion)
307
308                 writer.Write(ExceptionOutMessage(ex, IsTerminatePermission))
309                 writer.Flush()
310             End Using
311
312             Select Case MessageBox.Show(String.Format(My.Resources.UnhandledExceptionText9, fileName, Environment.NewLine), _
313                                My.Resources.UnhandledExceptionText10, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Error)
314                 Case DialogResult.Yes
315                     Diagnostics.Process.Start(fileName)
316                     Return False
317                 Case DialogResult.No
318                     Return False
319                 Case DialogResult.Cancel
320                     Return IsTerminatePermission
321             End Select
322         End SyncLock
323     End Function
324
325     ''' <summary>
326     ''' URLに含まれているマルチバイト文字列を%xx形式でエンコードします。
327     ''' <newpara>
328     ''' マルチバイト文字のコードはUTF-8またはUnicodeで自動的に判断します。
329     ''' </newpara>
330     ''' </summary>
331     ''' <param name = input>エンコード対象のURL</param>
332     ''' <returns>マルチバイト文字の部分をUTF-8/%xx形式でエンコードした文字列を返します。</returns>
333
334     Public Function urlEncodeMultibyteChar(ByVal _input As String) As String
335         Dim uri As Uri = Nothing
336         Dim sb As StringBuilder = New StringBuilder(256)
337         Dim result As String = ""
338         Dim c As Char = "d"c
339         For Each c In _input
340             If Convert.ToInt32(c) > 127 Then Exit For
341         Next
342         If Convert.ToInt32(c) <= 127 Then Return _input
343
344         Dim input As String = HttpUtility.UrlDecode(_input)
345 retry:
346         For Each c In input
347             If Convert.ToInt32(c) > 255 Then
348                 ' Unicodeの場合(1charが複数のバイトで構成されている)
349                 ' UriクラスをNewして再構成し、入力をPathAndQueryのみとしてやり直す
350                 If uri Is Nothing Then
351                     uri = New Uri(input)
352                     input = uri.PathAndQuery
353                     sb.Length = 0
354                     GoTo retry
355                 End If
356             ElseIf Convert.ToInt32(c) > 127 Then
357                 ' UTF-8の場合
358                 ' UriクラスをNewして再構成し、入力をinputからAuthority部分を除去してやり直す
359                 If uri Is Nothing Then
360                     uri = New Uri(input)
361                     input = input.Remove(0, uri.GetLeftPart(UriPartial.Authority).Length)
362                     sb.Length = 0
363                     GoTo retry
364                 Else
365                     sb.Append("%" + Convert.ToInt16(c).ToString("X2").ToUpper())
366                 End If
367             Else
368                 sb.Append(c)
369             End If
370         Next
371
372         If uri Is Nothing Then
373             result = sb.ToString()
374         Else
375             result = uri.GetLeftPart(UriPartial.Authority) + sb.ToString()
376         End If
377
378         Return result
379     End Function
380
381     ''' <summary>
382     ''' URLのドメイン名をPunycode展開します。
383     ''' <para>
384     ''' ドメイン名がIDNでない場合はそのまま返します。
385     ''' ドメインラベルの区切り文字はFULLSTOP(.、U002E)に置き換えられます。
386     ''' </para>
387     ''' </summary>
388     ''' <param name="input">展開対象のURL</param>
389     ''' <returns>IDNが含まれていた場合はPunycodeに展開したURLをを返します。Punycode展開時にエラーが発生した場合はNothingを返します。</returns>
390
391     Public Function IDNDecode(ByVal input As String) As String
392         Dim result As String = ""
393         Dim IDNConverter As New IdnMapping
394
395         If Not input.Contains("://") Then Return Nothing
396
397         ' ドメイン名をPunycode展開
398         Dim Domain As String
399         Dim AsciiDomain As String
400
401         Try
402             Domain = input.Split("/"c)(2)
403             AsciiDomain = IDNConverter.GetAscii(Domain)
404         Catch ex As Exception
405             Return Nothing
406         End Try
407
408         Return input.Replace("://" + Domain, "://" + AsciiDomain)
409     End Function
410
411     Public Sub MoveArrayItem(ByVal values() As Integer, ByVal idx_fr As Integer, ByVal idx_to As Integer)
412         Dim moved_value As Integer = values(idx_fr)
413         Dim num_moved As Integer = Math.Abs(idx_fr - idx_to)
414
415         If idx_to < idx_fr Then
416             Array.Copy(values, idx_to, values, _
417                 idx_to + 1, num_moved)
418         Else
419             Array.Copy(values, idx_fr + 1, values, _
420                 idx_fr, num_moved)
421         End If
422
423         values(idx_to) = moved_value
424     End Sub
425
426     Public Function EncryptString(ByVal str As String) As String
427         If String.IsNullOrEmpty(str) Then Return ""
428
429         '文字列をバイト型配列にする
430         Dim bytesIn As Byte() = System.Text.Encoding.UTF8.GetBytes(str)
431
432         'DESCryptoServiceProviderオブジェクトの作成
433         Using des As New System.Security.Cryptography.DESCryptoServiceProvider
434
435             '共有キーと初期化ベクタを決定
436             'パスワードをバイト配列にする
437             Dim bytesKey As Byte() = System.Text.Encoding.UTF8.GetBytes("_tween_encrypt_key_")
438             '共有キーと初期化ベクタを設定
439             des.Key = ResizeBytesArray(bytesKey, des.Key.Length)
440             des.IV = ResizeBytesArray(bytesKey, des.IV.Length)
441
442             '暗号化されたデータを書き出すためのMemoryStream
443             Using msOut As New System.IO.MemoryStream
444                 'DES暗号化オブジェクトの作成
445                 Using desdecrypt As System.Security.Cryptography.ICryptoTransform = _
446                     des.CreateEncryptor()
447
448                     '書き込むためのCryptoStreamの作成
449                     Using cryptStream As New System.Security.Cryptography.CryptoStream( _
450                         msOut, desdecrypt, _
451                         System.Security.Cryptography.CryptoStreamMode.Write)
452                         '書き込む
453                         cryptStream.Write(bytesIn, 0, bytesIn.Length)
454                         cryptStream.FlushFinalBlock()
455                         '暗号化されたデータを取得
456                         Dim bytesOut As Byte() = msOut.ToArray()
457
458                         '閉じる
459                         cryptStream.Close()
460                         msOut.Close()
461
462                         'Base64で文字列に変更して結果を返す
463                         Return System.Convert.ToBase64String(bytesOut)
464                     End Using
465                 End Using
466             End Using
467         End Using
468     End Function
469
470     Public Function DecryptString(ByVal str As String) As String
471         If String.IsNullOrEmpty(str) Then Return ""
472
473         'DESCryptoServiceProviderオブジェクトの作成
474         Using des As New System.Security.Cryptography.DESCryptoServiceProvider
475
476             '共有キーと初期化ベクタを決定
477             'パスワードをバイト配列にする
478             Dim bytesKey As Byte() = System.Text.Encoding.UTF8.GetBytes("_tween_encrypt_key_")
479             '共有キーと初期化ベクタを設定
480             des.Key = ResizeBytesArray(bytesKey, des.Key.Length)
481             des.IV = ResizeBytesArray(bytesKey, des.IV.Length)
482
483             'Base64で文字列をバイト配列に戻す
484             Dim bytesIn As Byte() = System.Convert.FromBase64String(str)
485             '暗号化されたデータを読み込むためのMemoryStream
486             Using msIn As New System.IO.MemoryStream(bytesIn)
487                 'DES復号化オブジェクトの作成
488                 Using desdecrypt As System.Security.Cryptography.ICryptoTransform = _
489                     des.CreateDecryptor()
490                     '読み込むためのCryptoStreamの作成
491                     Using cryptStreem As New System.Security.Cryptography.CryptoStream( _
492                         msIn, desdecrypt, _
493                         System.Security.Cryptography.CryptoStreamMode.Read)
494
495                         '復号化されたデータを取得するためのStreamReader
496                         Using srOut As New System.IO.StreamReader( _
497                             cryptStreem, System.Text.Encoding.UTF8)
498                             '復号化されたデータを取得する
499                             Dim result As String = srOut.ReadToEnd()
500
501                             '閉じる
502                             srOut.Close()
503                             cryptStreem.Close()
504                             msIn.Close()
505
506                             Return result
507                         End Using
508                     End Using
509                 End Using
510             End Using
511         End Using
512     End Function
513
514     Public Function ResizeBytesArray(ByVal bytes() As Byte, _
515                                 ByVal newSize As Integer) As Byte()
516         Dim newBytes(newSize - 1) As Byte
517         If bytes.Length <= newSize Then
518             Dim i As Integer
519             For i = 0 To bytes.Length - 1
520                 newBytes(i) = bytes(i)
521             Next i
522         Else
523             Dim pos As Integer = 0
524             Dim i As Integer
525             For i = 0 To bytes.Length - 1
526                 newBytes(pos) = newBytes(pos) Xor bytes(i)
527                 pos += 1
528                 If pos >= newBytes.Length Then
529                     pos = 0
530                 End If
531             Next i
532         End If
533         Return newBytes
534     End Function
535
536     Public Function IsNT6() As Boolean
537         'NT6 kernelかどうか検査
538         Return Environment.OSVersion.Platform = PlatformID.Win32NT AndAlso Environment.OSVersion.Version.Major = 6
539     End Function
540
541     <FlagsAttribute()> _
542     Public Enum TabUsageType
543         Undefined = 0
544         Home = 1      'Unique
545         Mentions = 2     'Unique
546         DirectMessage = 4   'Unique
547         Favorites = 8       'Unique
548         UserDefined = 16
549         LocalQuery = 32      'Pin(no save/no save query/distribute/no update(normal update))
550         Profile = 64         'Pin(save/no distribute/manual update)
551         PublicSearch = 128    'Pin(save/no distribute/auto update)
552         Lists = 256
553         Related = 512
554         UserTimeline = 1024
555         'RTMyTweet
556         'RTByOthers
557         'RTByMe
558     End Enum
559
560     Public fileVersion As String = ""
561
562     Public Function GetUserAgentString() As String
563         If String.IsNullOrEmpty(fileVersion) Then
564             Throw New Exception("fileversion is not Initialized.")
565         End If
566         Return "Tween/" + fileVersion
567     End Function
568
569     Public WithEvents TwitterApiInfo As New ApiInformation
570
571     Public Function IsAnimatedGif(ByVal filename As String) As Boolean
572         Dim img As Image = Nothing
573         Try
574             img = Image.FromFile(filename)
575             If img Is Nothing Then Return False
576             If img.RawFormat.Guid = Imaging.ImageFormat.Gif.Guid Then
577                 Dim fd As New System.Drawing.Imaging.FrameDimension(img.FrameDimensionsList(0))
578                 Dim fd_count As Integer = img.GetFrameCount(fd)
579                 If fd_count > 1 Then
580                     Return True
581                 Else
582                     Return False
583                 End If
584             Else
585                 Return False
586             End If
587         Catch ex As Exception
588             Return False
589         Finally
590             If img IsNot Nothing Then img.Dispose()
591         End Try
592     End Function
593
594     Public Function DateTimeParse(ByVal input As String) As Date
595         Dim rslt As Date
596         Dim format() As String = {
597             "ddd MMM dd HH:mm:ss zzzz yyyy"
598         }
599         For Each fmt As String In format
600             If DateTime.TryParseExact(input, _
601                                       fmt, _
602                                       System.Globalization.DateTimeFormatInfo.InvariantInfo, _
603                                       System.Globalization.DateTimeStyles.None, _
604                                       rslt) Then
605                 Return rslt
606             Else
607                 Continue For
608             End If
609         Next
610         TraceOut("Parse Error(DateTimeFormat) : " + input)
611         Return New Date
612     End Function
613
614     Public Function CreateDataFromJson(Of T)(ByVal content As String) As T
615         Dim data As T
616         Using stream As New MemoryStream()
617             Dim buf As Byte() = Encoding.Unicode.GetBytes(content)
618             stream.Write(Encoding.Unicode.GetBytes(content), offset:=0, count:=buf.Length)
619             stream.Seek(offset:=0, loc:=SeekOrigin.Begin)
620             data = DirectCast((New DataContractJsonSerializer(GetType(T))).ReadObject(stream), T)
621         End Using
622         Return data
623     End Function
624 End Module