OSDN Git Service

更新チェック先の変更
[opentween/open-tween.git] / Tween / Twitter.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.Web
27 Imports System.Xml
28 Imports System.Text
29 Imports System.Threading
30 Imports System.IO
31 Imports System.Text.RegularExpressions
32 Imports System.Diagnostics
33 Imports System.Net
34 Imports System.Reflection.MethodBase
35 Imports System.Runtime.Serialization.Json
36 Imports System.Linq
37 Imports System.Xml.Linq
38 Imports System.Runtime.Serialization
39 Imports System.Net.NetworkInformation
40
41 Public Class Twitter
42     Implements IDisposable
43
44     Delegate Sub GetIconImageDelegate(ByVal post As PostClass)
45     Private ReadOnly LockObj As New Object
46     Private followerId As New List(Of Long)
47     Private _GetFollowerResult As Boolean = False
48
49     Private _followersCount As Integer = 0
50     Private _friendsCount As Integer = 0
51     Private _statusesCount As Integer = 0
52     Private _location As String = ""
53     Private _bio As String = ""
54     Private _protocol As String = "https://"
55
56     'プロパティからアクセスされる共通情報
57     Private _uid As String
58     Private _iconSz As Integer
59     Private _getIcon As Boolean
60     Private _dIcon As IDictionary(Of String, Image)
61
62     Private _tinyUrlResolve As Boolean
63     Private _restrictFavCheck As Boolean
64
65     Private _hubServer As String
66     Private _readOwnPost As Boolean
67     Private _hashList As New List(Of String)
68
69     '共通で使用する状態
70     Private _remainCountApi As Integer = -1
71
72     Private op As New Outputz
73     'max_idで古い発言を取得するために保持(lists分は個別タブで管理)
74     Private minHomeTimeline As Long = Long.MaxValue
75     Private minMentions As Long = Long.MaxValue
76     Private minDirectmessage As Long = Long.MaxValue
77     Private minDirectmessageSent As Long = Long.MaxValue
78
79     Private twCon As New HttpTwitter
80
81     'Private _deletemessages As New List(Of PostClass)
82
83     Public Function Authenticate(ByVal username As String, ByVal password As String) As String
84
85         Dim res As HttpStatusCode
86         Dim content As String = ""
87
88         TwitterApiInfo.Initialize()
89         Try
90             res = twCon.AuthUserAndPass(username, password, content)
91         Catch ex As Exception
92             Return "Err:" + ex.Message
93         End Try
94
95         Select Case res
96             Case HttpStatusCode.OK
97                 Twitter.AccountState = ACCOUNT_STATE.Valid
98                 _uid = username.ToLower
99                 Me.ReconnectUserStream()
100                 Return ""
101             Case HttpStatusCode.Unauthorized
102                 Twitter.AccountState = ACCOUNT_STATE.Invalid
103                 Dim errMsg As String = GetErrorMessageJson(content)
104                 If String.IsNullOrEmpty(errMsg) Then
105                     Return "Check your Username/Password." + Environment.NewLine + content
106                 Else
107                     Return "Auth error:" + errMsg
108                 End If
109             Case HttpStatusCode.Forbidden
110                 Dim errMsg As String = GetErrorMessageJson(content)
111                 If String.IsNullOrEmpty(errMsg) Then
112                     Return "Err:Forbidden"
113                 Else
114                     Return "Err:" + errMsg
115                 End If
116             Case Else
117                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
118         End Select
119
120     End Function
121
122     Public Sub ClearAuthInfo()
123         Twitter.AccountState = ACCOUNT_STATE.Invalid
124         TwitterApiInfo.Initialize()
125         twCon.ClearAuthInfo()
126         _UserIdNo = ""
127     End Sub
128
129     Private Function GetErrorMessageJson(ByVal content As String) As String
130         Try
131             If Not String.IsNullOrEmpty(content) Then
132                 Using jsonReader As XmlDictionaryReader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(content), XmlDictionaryReaderQuotas.Max)
133                     Dim xElm As XElement = XElement.Load(jsonReader)
134                     If xElm.Element("error") IsNot Nothing Then
135                         Return xElm.Element("error").Value
136                     Else
137                         Return ""
138                     End If
139                 End Using
140             Else
141                 Return ""
142             End If
143         Catch ex As Exception
144             Return ""
145         End Try
146     End Function
147
148     Public Sub Initialize(ByVal token As String, ByVal tokenSecret As String, ByVal username As String)
149         'xAuth認証
150         If String.IsNullOrEmpty(token) OrElse String.IsNullOrEmpty(tokenSecret) OrElse String.IsNullOrEmpty(username) Then
151             Twitter.AccountState = ACCOUNT_STATE.Invalid
152         End If
153         TwitterApiInfo.Initialize()
154         twCon.Initialize(token, tokenSecret, username)
155         _uid = username.ToLower
156         _UserIdNo = ""
157     End Sub
158
159     Public Sub Initialize(ByVal username As String, ByVal password As String)
160         'BASIC認証
161         If String.IsNullOrEmpty(username) OrElse String.IsNullOrEmpty(password) Then
162             Twitter.AccountState = ACCOUNT_STATE.Invalid
163         End If
164         TwitterApiInfo.Initialize()
165         twCon.Initialize(username, password)
166         _uid = username.ToLower
167         _UserIdNo = ""
168     End Sub
169
170     Public Function PreProcessUrl(ByVal orgData As String) As String
171         Dim posl1 As Integer
172         Dim posl2 As Integer = 0
173         'Dim IDNConveter As IdnMapping = New IdnMapping()
174         Dim href As String = "<a href="""
175
176         Do While True
177             If orgData.IndexOf(href, posl2, StringComparison.Ordinal) > -1 Then
178                 Dim urlStr As String = ""
179                 ' IDN展開
180                 posl1 = orgData.IndexOf(href, posl2, StringComparison.Ordinal)
181                 posl1 += href.Length
182                 posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
183                 urlStr = orgData.Substring(posl1, posl2 - posl1)
184
185                 If Not urlStr.StartsWith("http://") AndAlso Not urlStr.StartsWith("https://") AndAlso Not urlStr.StartsWith("ftp://") Then
186                     Continue Do
187                 End If
188
189                 Dim replacedUrl As String = IDNDecode(urlStr)
190                 If replacedUrl Is Nothing Then Continue Do
191                 If replacedUrl = urlStr Then Continue Do
192
193                 orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + replacedUrl)
194                 posl2 = 0
195             Else
196                 Exit Do
197             End If
198         Loop
199         Return orgData
200     End Function
201
202     Private Function GetPlainText(ByVal orgData As String) As String
203         Return HttpUtility.HtmlDecode(Regex.Replace(orgData, "(?<tagStart><a [^>]+>)(?<text>[^<]+)(?<tagEnd></a>)", "${text}"))
204     End Function
205
206     ' htmlの簡易サニタイズ(詳細表示に不要なタグの除去)
207
208     Private Function SanitizeHtml(ByVal orgdata As String) As String
209         Dim retdata As String = orgdata
210
211         retdata = Regex.Replace(retdata, "<(script|object|applet|image|frameset|fieldset|legend|style).*" & _
212             "</(script|object|applet|image|frameset|fieldset|legend|style)>", "", RegexOptions.IgnoreCase)
213
214         retdata = Regex.Replace(retdata, "<(frame|link|iframe|img)>", "", RegexOptions.IgnoreCase)
215
216         Return retdata
217     End Function
218
219     Private Function AdjustHtml(ByVal orgData As String) As String
220         Dim retStr As String = orgData
221         Dim m As Match = Regex.Match(retStr, "<a [^>]+>[#|#](?<1>[a-zA-Z0-9_]+)</a>")
222         While m.Success
223             SyncLock LockObj
224                 _hashList.Add("#" + m.Groups(1).Value)
225             End SyncLock
226             m = m.NextMatch
227         End While
228         retStr = Regex.Replace(retStr, "<a [^>]*href=""/", "<a href=""" + _protocol + "twitter.com/")
229         retStr = retStr.Replace("<a href=", "<a target=""_self"" href=")
230         retStr = retStr.Replace(vbLf, "<br>")
231
232         '半角スペースを置換(Thanks @anis774)
233         Dim ret As Boolean = False
234         Do
235             ret = EscapeSpace(retStr)
236         Loop While Not ret
237
238         Return SanitizeHtml(retStr)
239     End Function
240
241     Private Function EscapeSpace(ByRef html As String) As Boolean
242         '半角スペースを置換(Thanks @anis774)
243         Dim isTag As Boolean = False
244         For i As Integer = 0 To html.Length - 1
245             If html(i) = "<"c Then
246                 isTag = True
247             End If
248             If html(i) = ">"c Then
249                 isTag = False
250             End If
251
252             If (Not isTag) AndAlso (html(i) = " "c) Then
253                 html = html.Remove(i, 1)
254                 html = html.Insert(i, "&nbsp;")
255                 Return False
256             End If
257         Next
258         Return True
259     End Function
260
261     'Private Sub GetIconImage(ByVal post As PostClass)
262     '    Dim img As Image
263
264     '    Try
265     '        If Not _getIcon Then
266     '            post.ImageUrl = Nothing
267     '            TabInformations.GetInstance.AddPost(post)
268     '            Exit Sub
269     '        End If
270
271     '        If _dIcon.ContainsKey(post.ImageUrl) AndAlso _dIcon(post.ImageUrl) IsNot Nothing Then
272     '            TabInformations.GetInstance.AddPost(post)
273     '            Exit Sub
274     '        End If
275
276     '        Dim httpVar As New HttpVarious
277     '        img = httpVar.GetImage(post.ImageUrl, 10000)
278     '        If img Is Nothing Then
279     '            _dIcon.Add(post.ImageUrl, Nothing)
280     '            TabInformations.GetInstance.AddPost(post)
281     '            Exit Sub
282     '        End If
283
284     '        If _endingFlag Then Exit Sub
285
286     '        SyncLock LockObj
287     '            If Not _dIcon.ContainsKey(post.ImageUrl) Then
288     '                Try
289     '                    _dIcon.Add(post.ImageUrl, img)
290     '                Catch ex As InvalidOperationException
291     '                    'タイミングにより追加できない場合がある?(キー重複ではない)
292     '                    post.ImageUrl = Nothing
293     '                Catch ex As System.OverflowException
294     '                    '不正なアイコン?DrawImageに失敗する場合あり
295     '                    post.ImageUrl = Nothing
296     '                Catch ex As OutOfMemoryException
297     '                    'DrawImageで発生
298     '                    post.ImageUrl = Nothing
299     '                End Try
300     '            End If
301     '        End SyncLock
302     '        TabInformations.GetInstance.AddPost(post)
303     '    Catch ex As ArgumentException
304     '        'タイミングによってはキー重複
305     '    Finally
306     '        img = Nothing
307     '        post = Nothing
308     '    End Try
309     'End Sub
310
311     Private Structure PostInfo
312         Public CreatedAt As String
313         Public Id As String
314         Public Text As String
315         Public UserId As String
316         Public Sub New(ByVal Created As String, ByVal IdStr As String, ByVal txt As String, ByVal uid As String)
317             CreatedAt = Created
318             Id = IdStr
319             Text = txt
320             UserId = uid
321         End Sub
322         Public Shadows Function Equals(ByVal dst As PostInfo) As Boolean
323             If Me.CreatedAt = dst.CreatedAt AndAlso Me.Id = dst.Id AndAlso Me.Text = dst.Text AndAlso Me.UserId = dst.UserId Then
324                 Return True
325             Else
326                 Return False
327             End If
328         End Function
329     End Structure
330
331     Private Function IsPostRestricted(ByVal status As TwitterDataModel.Status) As Boolean
332         Static _prev As New PostInfo("", "", "", "")
333         Dim _current As New PostInfo("", "", "", "")
334
335         _current.CreatedAt = status.CreatedAt
336         _current.Id = status.IdStr
337         If status.Text Is Nothing Then
338             _current.Text = ""
339         Else
340             _current.Text = status.Text
341         End If
342         _current.UserId = status.User.IdStr
343
344         If _current.Equals(_prev) Then
345             Return True
346         End If
347         _prev.CreatedAt = _current.CreatedAt
348         _prev.Id = _current.Id
349         _prev.Text = _current.Text
350         _prev.UserId = _current.UserId
351
352         Return False
353     End Function
354
355     Public Function PostStatus(ByVal postStr As String, ByVal reply_to As Long) As String
356
357         If _endingFlag Then Return ""
358
359         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
360
361         postStr = postStr.Trim()
362
363         If Regex.Match(postStr, "^DM? +(?<id>[a-zA-Z0-9_]+) +(?<body>.+)", RegexOptions.IgnoreCase Or RegexOptions.Singleline).Success Then
364             Return SendDirectMessage(postStr)
365         End If
366
367         Dim res As HttpStatusCode
368         Dim content As String = ""
369         Try
370             res = twCon.UpdateStatus(postStr, reply_to, content)
371         Catch ex As Exception
372             Return "Err:" + ex.Message
373         End Try
374
375         Select Case res
376             Case HttpStatusCode.OK
377                 Twitter.AccountState = ACCOUNT_STATE.Valid
378                 Dim status As TwitterDataModel.Status
379                 Try
380                     status = CreateDataFromJson(Of TwitterDataModel.Status)(content)
381                 Catch ex As SerializationException
382                     TraceOut(ex.Message + Environment.NewLine + content)
383                     Return "Err:Json Parse Error(DataContractJsonSerializer)"
384                 Catch ex As Exception
385                     TraceOut(content)
386                     Return "Err:Invalid Json!"
387                 End Try
388                 _followersCount = status.User.FollowersCount
389                 _friendsCount = status.User.FriendsCount
390                 _statusesCount = status.User.StatusesCount
391                 _location = status.User.Location
392                 _bio = status.User.Description
393                 _UserIdNo = status.User.IdStr
394
395                 If IsPostRestricted(status) Then
396                     Return "OK:Delaying?"
397                 End If
398                 If op.Post(postStr.Length) Then
399                     Return ""
400                 Else
401                     Return "Outputz:Failed"
402                 End If
403             Case HttpStatusCode.Forbidden, HttpStatusCode.BadRequest
404                 Dim errMsg As String = GetErrorMessageJson(content)
405                 If String.IsNullOrEmpty(errMsg) Then
406                     Return "Warn:" + res.ToString
407                 Else
408                     Return "Warn:" + errMsg
409                 End If
410             Case HttpStatusCode.Conflict, _
411                 HttpStatusCode.ExpectationFailed, _
412                 HttpStatusCode.Gone, _
413                 HttpStatusCode.LengthRequired, _
414                 HttpStatusCode.MethodNotAllowed, _
415                 HttpStatusCode.NotAcceptable, _
416                 HttpStatusCode.NotFound, _
417                 HttpStatusCode.PaymentRequired, _
418                 HttpStatusCode.PreconditionFailed, _
419                 HttpStatusCode.RequestedRangeNotSatisfiable, _
420                 HttpStatusCode.RequestEntityTooLarge, _
421                 HttpStatusCode.RequestTimeout, _
422                 HttpStatusCode.RequestUriTooLong
423                 '仕様書にない400系エラー。サーバまでは到達しているのでリトライしない
424                 Return "Warn:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
425             Case HttpStatusCode.Unauthorized
426                 Twitter.AccountState = ACCOUNT_STATE.Invalid
427                 Dim errMsg As String = GetErrorMessageJson(content)
428                 If String.IsNullOrEmpty(errMsg) Then
429                     Return "Check your Username/Password."
430                 Else
431                     Return "Auth err:" + errMsg
432                 End If
433             Case Else
434                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
435         End Select
436     End Function
437
438     Public Function SendDirectMessage(ByVal postStr As String) As String
439
440         If _endingFlag Then Return ""
441
442         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
443
444         postStr = postStr.Trim()
445
446         Dim res As HttpStatusCode
447         Dim content As String = ""
448
449         Dim mc As Match = Regex.Match(postStr, "^DM? +(?<id>[a-zA-Z0-9_]+) +(?<body>.+)", RegexOptions.IgnoreCase Or RegexOptions.Singleline)
450
451         Try
452             res = twCon.SendDirectMessage(mc.Groups("body").Value, mc.Groups("id").Value, content)
453         Catch ex As Exception
454             Return "Err:" + ex.Message
455         End Try
456
457         Select Case res
458             Case HttpStatusCode.OK
459                 Twitter.AccountState = ACCOUNT_STATE.Valid
460                 Dim status As TwitterDataModel.Directmessage
461                 Try
462                     status = CreateDataFromJson(Of TwitterDataModel.Directmessage)(content)
463                 Catch ex As SerializationException
464                     TraceOut(ex.Message + Environment.NewLine + content)
465                     Return "Err:Json Parse Error(DataContractJsonSerializer)"
466                 Catch ex As Exception
467                     TraceOut(content)
468                     Return "Err:Invalid Json!"
469                 End Try
470                 _followersCount = status.Sender.FollowersCount
471                 _friendsCount = status.Sender.FriendsCount
472                 _statusesCount = status.Sender.StatusesCount
473                 _location = status.Sender.Location
474                 _bio = status.Sender.Description
475                 _UserIdNo = status.Sender.IdStr
476
477                 If op.Post(postStr.Length) Then
478                     Return ""
479                 Else
480                     Return "Outputz:Failed"
481                 End If
482             Case HttpStatusCode.Forbidden, HttpStatusCode.BadRequest
483                 Dim errMsg As String = GetErrorMessageJson(content)
484                 If String.IsNullOrEmpty(errMsg) Then
485                     Return "Warn:" + res.ToString
486                 Else
487                     Return "Warn:" + errMsg
488                 End If
489             Case HttpStatusCode.Conflict, _
490                 HttpStatusCode.ExpectationFailed, _
491                 HttpStatusCode.Gone, _
492                 HttpStatusCode.LengthRequired, _
493                 HttpStatusCode.MethodNotAllowed, _
494                 HttpStatusCode.NotAcceptable, _
495                 HttpStatusCode.NotFound, _
496                 HttpStatusCode.PaymentRequired, _
497                 HttpStatusCode.PreconditionFailed, _
498                 HttpStatusCode.RequestedRangeNotSatisfiable, _
499                 HttpStatusCode.RequestEntityTooLarge, _
500                 HttpStatusCode.RequestTimeout, _
501                 HttpStatusCode.RequestUriTooLong
502                 '仕様書にない400系エラー。サーバまでは到達しているのでリトライしない
503                 Return "Warn:" + res.ToString
504             Case HttpStatusCode.Unauthorized
505                 Twitter.AccountState = ACCOUNT_STATE.Invalid
506                 Dim errMsg As String = GetErrorMessageJson(content)
507                 If String.IsNullOrEmpty(errMsg) Then
508                     Return "Check your Username/Password."
509                 Else
510                     Return "Auth err:" + errMsg
511                 End If
512             Case Else
513                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
514         End Select
515     End Function
516
517     Public Function RemoveStatus(ByVal id As Long) As String
518         If _endingFlag Then Return ""
519
520         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
521
522         Dim res As HttpStatusCode
523
524         Try
525             res = twCon.DestroyStatus(id)
526         Catch ex As Exception
527             Return "Err:" + ex.Message
528         End Try
529
530         Select Case res
531             Case HttpStatusCode.OK
532                 Twitter.AccountState = ACCOUNT_STATE.Valid
533                 Return ""
534             Case HttpStatusCode.Unauthorized
535                 Twitter.AccountState = ACCOUNT_STATE.Invalid
536                 Return "Check your Username/Password."
537             Case HttpStatusCode.NotFound
538                 Return ""
539             Case Else
540                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
541         End Select
542
543     End Function
544
545     Public Function PostRetweet(ByVal id As Long, ByVal read As Boolean) As String
546         If _endingFlag Then Return ""
547         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
548
549         'データ部分の生成
550         Dim target As Long = id
551         If TabInformations.GetInstance.Item(id).RetweetedId > 0 Then
552             target = TabInformations.GetInstance.Item(id).RetweetedId '再RTの場合は元発言をRT
553         End If
554
555         Dim res As HttpStatusCode
556         Dim content As String = ""
557         Try
558             res = twCon.RetweetStatus(target, content)
559         Catch ex As Exception
560             Return "Err:" + ex.Message
561         End Try
562
563         Select Case res
564             Case HttpStatusCode.Unauthorized
565                 Twitter.AccountState = ACCOUNT_STATE.Invalid
566                 Return "Check your Username/Password."
567             Case Is <> HttpStatusCode.OK
568                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
569         End Select
570
571         Twitter.AccountState = ACCOUNT_STATE.Valid
572
573         Dim status As TwitterDataModel.Status
574         Try
575             status = CreateDataFromJson(Of TwitterDataModel.Status)(content)
576         Catch ex As SerializationException
577             TraceOut(ex.Message + Environment.NewLine + content)
578             Return "Err:Json Parse Error(DataContractJsonSerializer)"
579         Catch ex As Exception
580             TraceOut(content)
581             Return "Err:Invalid Json!"
582         End Try
583
584         'ReTweetしたものをTLに追加
585         Dim post As PostClass = CreatePostsFromStatusData(status)
586
587         '二重取得回避
588         SyncLock LockObj
589             If TabInformations.GetInstance.ContainsKey(post.StatusId) Then Return ""
590         End SyncLock
591         'Retweet判定
592         If post.RetweetedId = 0 Then Return "Invalid Json!"
593         'ユーザー情報
594         post.IsMe = True
595
596         post.IsRead = read
597         post.IsOwl = False
598         If _readOwnPost Then post.IsRead = True
599         post.IsDm = False
600
601         TabInformations.GetInstance.AddPost(post)
602
603         Return ""
604     End Function
605
606     Public Function RemoveDirectMessage(ByVal id As Long, ByVal post As PostClass) As String
607         If _endingFlag Then Return ""
608
609         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
610
611         Dim res As HttpStatusCode
612
613         'If post.IsMe Then
614         '    _deletemessages.Add(post)
615         'End If
616         Try
617             res = twCon.DestroyDirectMessage(id)
618         Catch ex As Exception
619             Return "Err:" + ex.Message
620         End Try
621
622         Select Case res
623             Case HttpStatusCode.OK
624                 Twitter.AccountState = ACCOUNT_STATE.Valid
625                 Return ""
626             Case HttpStatusCode.Unauthorized
627                 Twitter.AccountState = ACCOUNT_STATE.Invalid
628                 Return "Check your Username/Password."
629             Case HttpStatusCode.NotFound
630                 Return ""
631             Case Else
632                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
633         End Select
634     End Function
635
636     Public Function PostFollowCommand(ByVal screenName As String) As String
637
638         If _endingFlag Then Return ""
639
640         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
641
642         Dim res As HttpStatusCode
643         Dim content As String = ""
644
645         Try
646             res = twCon.CreateFriendships(screenName, content)
647         Catch ex As Exception
648             Return "Err:" + ex.Message
649         End Try
650
651         Select Case res
652             Case HttpStatusCode.OK
653                 Twitter.AccountState = ACCOUNT_STATE.Valid
654                 Return ""
655             Case HttpStatusCode.Unauthorized
656                 Twitter.AccountState = ACCOUNT_STATE.Invalid
657                 Return "Check your Username/Password."
658             Case HttpStatusCode.Forbidden
659                 Dim errMsg As String = GetErrorMessageJson(content)
660                 If String.IsNullOrEmpty(errMsg) Then
661                     Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
662                 Else
663                     Return "Err:" + errMsg
664                 End If
665             Case Else
666                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
667         End Select
668     End Function
669
670     Public Function PostRemoveCommand(ByVal screenName As String) As String
671
672         If _endingFlag Then Return ""
673
674         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
675
676         Dim res As HttpStatusCode
677         Dim content As String = ""
678
679         Try
680             res = twCon.DestroyFriendships(screenName, content)
681         Catch ex As Exception
682             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
683         End Try
684
685         Select Case res
686             Case HttpStatusCode.OK
687                 Twitter.AccountState = ACCOUNT_STATE.Valid
688                 Return ""
689             Case HttpStatusCode.Unauthorized
690                 Twitter.AccountState = ACCOUNT_STATE.Invalid
691                 Return "Check your Username/Password."
692             Case HttpStatusCode.Forbidden
693                 Dim errMsg As String = GetErrorMessageJson(content)
694                 If String.IsNullOrEmpty(errMsg) Then
695                     Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
696                 Else
697                     Return "Err:" + errMsg
698                 End If
699             Case Else
700                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
701         End Select
702     End Function
703
704     Public Function PostCreateBlock(ByVal screenName As String) As String
705
706         If _endingFlag Then Return ""
707
708         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
709
710         Dim res As HttpStatusCode
711         Dim content As String = ""
712
713         Try
714             res = twCon.CreateBlock(screenName, content)
715         Catch ex As Exception
716             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
717         End Try
718
719         Select Case res
720             Case HttpStatusCode.OK
721                 Twitter.AccountState = ACCOUNT_STATE.Valid
722                 Return ""
723             Case HttpStatusCode.Unauthorized
724                 Twitter.AccountState = ACCOUNT_STATE.Invalid
725                 Return "Check your Username/Password."
726             Case HttpStatusCode.Forbidden
727                 Dim errMsg As String = GetErrorMessageJson(content)
728                 If String.IsNullOrEmpty(errMsg) Then
729                     Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
730                 Else
731                     Return "Err:" + errMsg
732                 End If
733             Case Else
734                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
735         End Select
736     End Function
737
738     Public Function PostDestroyBlock(ByVal screenName As String) As String
739
740         If _endingFlag Then Return ""
741
742         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
743
744         Dim res As HttpStatusCode
745         Dim content As String = ""
746
747         Try
748             res = twCon.DestroyBlock(screenName, content)
749         Catch ex As Exception
750             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
751         End Try
752
753         Select Case res
754             Case HttpStatusCode.OK
755                 Twitter.AccountState = ACCOUNT_STATE.Valid
756                 Return ""
757             Case HttpStatusCode.Unauthorized
758                 Twitter.AccountState = ACCOUNT_STATE.Invalid
759                 Return "Check your Username/Password."
760             Case HttpStatusCode.Forbidden
761                 Dim errMsg As String = GetErrorMessageJson(content)
762                 If String.IsNullOrEmpty(errMsg) Then
763                     Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
764                 Else
765                     Return "Err:" + errMsg
766                 End If
767             Case Else
768                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
769         End Select
770     End Function
771
772     Public Function PostReportSpam(ByVal screenName As String) As String
773
774         If _endingFlag Then Return ""
775
776         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
777
778         Dim res As HttpStatusCode
779         Dim content As String = ""
780
781         Try
782             res = twCon.ReportSpam(screenName, content)
783         Catch ex As Exception
784             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
785         End Try
786
787         Select Case res
788             Case HttpStatusCode.OK
789                 Twitter.AccountState = ACCOUNT_STATE.Valid
790                 Return ""
791             Case HttpStatusCode.Unauthorized
792                 Twitter.AccountState = ACCOUNT_STATE.Invalid
793                 Return "Check your Username/Password."
794             Case HttpStatusCode.Forbidden
795                 Dim errMsg As String = GetErrorMessageJson(content)
796                 If String.IsNullOrEmpty(errMsg) Then
797                     Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
798                 Else
799                     Return "Err:" + errMsg
800                 End If
801             Case Else
802                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
803         End Select
804     End Function
805
806     Public Function GetFriendshipInfo(ByVal screenName As String, ByRef isFollowing As Boolean, ByRef isFollowed As Boolean) As String
807
808         If _endingFlag Then Return ""
809
810         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
811
812         Dim res As HttpStatusCode
813         Dim content As String = ""
814         Try
815             res = twCon.ShowFriendships(_uid, screenName, content)
816         Catch ex As Exception
817             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
818         End Try
819
820         Select Case res
821             Case HttpStatusCode.OK
822                 Try
823                     Dim relation = CreateDataFromJson(Of TwitterDataModel.Relationship)(content)
824                     isFollowing = relation.Relationship.Source.Following
825                     isFollowed = relation.Relationship.Source.FollowedBy
826                     Return ""
827                 Catch ex As SerializationException
828                     TraceOut(ex.Message + Environment.NewLine + content)
829                     Return "Err:Json Parse Error(DataContractJsonSerializer)"
830                 Catch ex As Exception
831                     TraceOut(content)
832                     Return "Err:Invalid Json!"
833                 End Try
834             Case HttpStatusCode.BadRequest
835                 Return "Err:API Limits?"
836             Case HttpStatusCode.Unauthorized
837                 Twitter.AccountState = ACCOUNT_STATE.Invalid
838                 Return "Check your Username/Password."
839             Case Else
840                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
841         End Select
842     End Function
843
844     Public Function GetUserInfo(ByVal screenName As String, ByRef user As TwitterDataModel.User) As String
845
846         If _endingFlag Then Return ""
847
848         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
849
850         Dim res As HttpStatusCode
851         Dim content As String = ""
852         user = Nothing
853         Try
854             res = twCon.ShowUserInfo(screenName, content)
855         Catch ex As Exception
856             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
857         End Try
858
859         Select Case res
860             Case HttpStatusCode.OK
861                 Twitter.AccountState = ACCOUNT_STATE.Valid
862                 Try
863                     user = CreateDataFromJson(Of TwitterDataModel.User)(content)
864                 Catch ex As SerializationException
865                     TraceOut(ex.Message + Environment.NewLine + content)
866                     Return "Err:Json Parse Error(DataContractJsonSerializer)"
867                 Catch ex As Exception
868                     TraceOut(content)
869                     Return "Err:Invalid Json!"
870                 End Try
871                 Return ""
872             Case HttpStatusCode.BadRequest
873                 Return "Err:API Limits?"
874             Case HttpStatusCode.Unauthorized
875                 Twitter.AccountState = ACCOUNT_STATE.Invalid
876                 Dim errMsg As String = GetErrorMessageJson(content)
877                 If String.IsNullOrEmpty(errMsg) Then
878                     Return "Check your Username/Password."
879                 Else
880                     Return "Auth err:" + errMsg
881                 End If
882             Case Else
883                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
884         End Select
885     End Function
886
887     Public Function GetStatus_Retweeted_Count(ByVal StatusId As Long, ByRef retweeted_count As Integer) As String
888
889         If _endingFlag Then Return ""
890
891         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
892
893         Dim res As HttpStatusCode
894         Dim content As String = ""
895         Dim xmlBuf As String = ""
896
897         retweeted_count = 0
898
899         ' 注:dev.twitter.comに記述されているcountパラメータは間違い。100が正しい
900         For i As Integer = 1 To 100
901
902             Try
903                 res = twCon.Statusid_retweeted_by_ids(StatusId, 100, i, content)
904             Catch ex As Exception
905                 Return "Err:" + ex.Message
906             End Try
907
908             Select Case res
909                 Case HttpStatusCode.OK
910                     Try
911                         Dim ids As Int64() = CreateDataFromJson(Of Int64())(content)
912                         retweeted_count += ids.Length
913                         If ids.Length < 100 Then Exit For
914                     Catch ex As SerializationException
915                         retweeted_count = -1
916                         TraceOut(ex.Message + Environment.NewLine + content)
917                         Return "Err:Json Parse Error(DataContractJsonSerializer)"
918                     Catch ex As Exception
919                         retweeted_count = -1
920                         TraceOut(content)
921                         Return "Err:Invalid Json!"
922                     End Try
923                 Case HttpStatusCode.BadRequest
924                     retweeted_count = -1
925                     Return "Err:API Limits?"
926                 Case HttpStatusCode.Unauthorized
927                     retweeted_count = -1
928                     Twitter.AccountState = ACCOUNT_STATE.Invalid
929                     Return "Check your Username/Password."
930                 Case Else
931                     retweeted_count = -1
932                     Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
933             End Select
934         Next
935         Return ""
936     End Function
937
938     Public Function PostFavAdd(ByVal id As Long) As String
939         If _endingFlag Then Return ""
940
941         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
942
943         Dim res As HttpStatusCode
944         Dim content As String = ""
945         Try
946             res = twCon.CreateFavorites(id, content)
947         Catch ex As Exception
948             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
949         End Try
950
951         Select Case res
952             Case HttpStatusCode.OK
953                 Twitter.AccountState = ACCOUNT_STATE.Valid
954                 If Not _restrictFavCheck Then Return ""
955             Case HttpStatusCode.Unauthorized
956                 Twitter.AccountState = ACCOUNT_STATE.Invalid
957                 Return "Check your Username/Password."
958             Case HttpStatusCode.Forbidden
959                 Dim errMsg As String = GetErrorMessageJson(content)
960                 If String.IsNullOrEmpty(errMsg) Then
961                     Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
962                 Else
963                     Return "Err:" + errMsg
964                 End If
965             Case Else
966                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
967         End Select
968
969         'http://twitter.com/statuses/show/id.xml APIを発行して本文を取得
970
971         'Dim content As String = ""
972         content = ""
973         Try
974             res = twCon.ShowStatuses(id, content)
975         Catch ex As Exception
976             Return "Err:" + ex.Message
977         End Try
978
979         Select Case res
980             Case HttpStatusCode.OK
981                 Twitter.AccountState = ACCOUNT_STATE.Valid
982                 Dim status As TwitterDataModel.Status
983                 Try
984                     status = CreateDataFromJson(Of TwitterDataModel.Status)(content)
985                 Catch ex As SerializationException
986                     TraceOut(ex.Message + Environment.NewLine + content)
987                     Return "Err:Json Parse Error(DataContractJsonSerializer)"
988                 Catch ex As Exception
989                     TraceOut(content)
990                     Return "Err:Invalid Json!"
991                 End Try
992                 If status.Favorited Then
993                     Return ""
994                 Else
995                     Return "NG(Restricted?)"
996                 End If
997             Case HttpStatusCode.Unauthorized
998                 Twitter.AccountState = ACCOUNT_STATE.Invalid
999                 Return "Check your Username/Password."
1000             Case HttpStatusCode.BadRequest
1001                 Return "Err:API Limits?"
1002             Case Else
1003                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
1004         End Select
1005
1006     End Function
1007
1008     Public Function PostFavRemove(ByVal id As Long) As String
1009         If _endingFlag Then Return ""
1010
1011         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1012
1013         Dim res As HttpStatusCode
1014         Dim content As String = ""
1015         Try
1016             res = twCon.DestroyFavorites(id, content)
1017         Catch ex As Exception
1018             Return "Err:" + ex.Message
1019         End Try
1020
1021         Select Case res
1022             Case HttpStatusCode.OK
1023                 Twitter.AccountState = ACCOUNT_STATE.Valid
1024                 Return ""
1025             Case HttpStatusCode.Unauthorized
1026                 Twitter.AccountState = ACCOUNT_STATE.Invalid
1027                 Return "Check your Username/Password."
1028             Case HttpStatusCode.Forbidden
1029                 Dim errMsg As String = GetErrorMessageJson(content)
1030                 If String.IsNullOrEmpty(errMsg) Then
1031                     Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
1032                 Else
1033                     Return "Err:" + errMsg
1034                 End If
1035             Case Else
1036                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
1037         End Select
1038     End Function
1039
1040     Public Function PostUpdateProfile(ByVal name As String, ByVal url As String, ByVal location As String, ByVal description As String) As String
1041         If _endingFlag Then Return ""
1042
1043         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1044
1045         Dim res As HttpStatusCode
1046         Dim content As String = ""
1047         Try
1048             res = twCon.UpdateProfile(name, url, location, description, content)
1049         Catch ex As Exception
1050             Return "Err:" + ex.Message
1051         End Try
1052
1053         Select Case res
1054             Case HttpStatusCode.OK
1055                 Twitter.AccountState = ACCOUNT_STATE.Valid
1056                 Return ""
1057             Case HttpStatusCode.Unauthorized
1058                 Twitter.AccountState = ACCOUNT_STATE.Invalid
1059                 Return "Check your Username/Password."
1060             Case HttpStatusCode.Forbidden
1061                 Dim errMsg As String = GetErrorMessageJson(content)
1062                 If String.IsNullOrEmpty(errMsg) Then
1063                     Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
1064                 Else
1065                     Return "Err:" + errMsg
1066                 End If
1067             Case Else
1068                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
1069         End Select
1070     End Function
1071
1072     Public Function PostUpdateProfileImage(ByVal filename As String) As String
1073         If _endingFlag Then Return ""
1074
1075         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1076
1077         Dim res As HttpStatusCode
1078         Dim content As String = ""
1079         Try
1080             res = twCon.UpdateProfileImage(New FileInfo(filename), content)
1081         Catch ex As Exception
1082             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
1083         End Try
1084
1085         Select Case res
1086             Case HttpStatusCode.OK
1087                 Twitter.AccountState = ACCOUNT_STATE.Valid
1088                 Return ""
1089             Case HttpStatusCode.Unauthorized
1090                 Twitter.AccountState = ACCOUNT_STATE.Invalid
1091                 Return "Check your Username/Password."
1092             Case HttpStatusCode.Forbidden
1093                 Dim errMsg As String = GetErrorMessageJson(content)
1094                 If String.IsNullOrEmpty(errMsg) Then
1095                     Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
1096                 Else
1097                     Return "Err:" + errMsg
1098                 End If
1099             Case Else
1100                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
1101         End Select
1102     End Function
1103
1104     Public ReadOnly Property Username() As String
1105         Get
1106             Return twCon.AuthenticatedUsername
1107         End Get
1108     End Property
1109
1110     Public ReadOnly Property Password() As String
1111         Get
1112             Return twCon.Password
1113         End Get
1114     End Property
1115
1116     Private Shared _accountState As ACCOUNT_STATE = ACCOUNT_STATE.Valid
1117     Public Shared Property AccountState() As ACCOUNT_STATE
1118         Get
1119             Return _accountState
1120         End Get
1121         Set(ByVal value As ACCOUNT_STATE)
1122             _accountState = value
1123         End Set
1124     End Property
1125
1126     Public WriteOnly Property GetIcon() As Boolean
1127         Set(ByVal value As Boolean)
1128             _getIcon = value
1129         End Set
1130     End Property
1131
1132     Public WriteOnly Property TinyUrlResolve() As Boolean
1133         Set(ByVal value As Boolean)
1134             _tinyUrlResolve = value
1135         End Set
1136     End Property
1137
1138     Public WriteOnly Property RestrictFavCheck() As Boolean
1139         Set(ByVal value As Boolean)
1140             _restrictFavCheck = value
1141         End Set
1142     End Property
1143
1144     Public WriteOnly Property IconSize() As Integer
1145         Set(ByVal value As Integer)
1146             _iconSz = value
1147         End Set
1148     End Property
1149
1150 #Region "バージョンアップ"
1151     Public Function GetVersionInfo() As String
1152         Dim content As String = ""
1153         If Not (New HttpVarious).GetData("http://tween.sourceforge.jp/version.txt?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), Nothing, content) Then
1154             Throw New Exception("GetVersionInfo Failed")
1155         End If
1156         Return content
1157     End Function
1158
1159     Public Function GetTweenBinary(ByVal strVer As String) As String
1160         Try
1161             If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/Tween" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
1162                                                 Path.Combine(Application.StartupPath(), "TweenNew.exe")) Then
1163                 Return "Err:Download failed"
1164             End If
1165             If Directory.Exists(Path.Combine(Application.StartupPath(), "en")) = False Then
1166                 Directory.CreateDirectory(Path.Combine(Application.StartupPath(), "en"))
1167             End If
1168             If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenRes" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
1169                                                 Path.Combine(Application.StartupPath(), "en\Tween.resourcesNew.dll")) Then
1170                 Return "Err:Download failed"
1171             End If
1172             If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenUp.gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
1173                                                 Path.Combine(Application.StartupPath(), "TweenUp.exe")) Then
1174                 Return "Err:Download failed"
1175             End If
1176             If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenDll" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
1177                                                 Path.Combine(Application.StartupPath(), "TweenNew.XmlSerializers.dll")) Then
1178                 Return "Err:Download failed"
1179             End If
1180             Return ""
1181         Catch ex As Exception
1182             Return "Err:Download failed"
1183         End Try
1184     End Function
1185 #End Region
1186
1187     Public Property DetailIcon() As IDictionary(Of String, Image)
1188         Get
1189             Return _dIcon
1190         End Get
1191         Set(ByVal value As IDictionary(Of String, Image))
1192             _dIcon = value
1193         End Set
1194     End Property
1195
1196     Public Property ReadOwnPost() As Boolean
1197         Get
1198             Return _readOwnPost
1199         End Get
1200         Set(ByVal value As Boolean)
1201             _readOwnPost = value
1202         End Set
1203     End Property
1204
1205     Public ReadOnly Property FollowersCount() As Integer
1206         Get
1207             Return _followersCount
1208         End Get
1209     End Property
1210
1211     Public ReadOnly Property FriendsCount() As Integer
1212         Get
1213             Return _friendsCount
1214         End Get
1215     End Property
1216
1217     Public ReadOnly Property StatusesCount() As Integer
1218         Get
1219             Return _statusesCount
1220         End Get
1221     End Property
1222
1223     Public ReadOnly Property Location() As String
1224         Get
1225             Return _location
1226         End Get
1227     End Property
1228
1229     Public ReadOnly Property Bio() As String
1230         Get
1231             Return _bio
1232         End Get
1233     End Property
1234
1235     Public WriteOnly Property UseSsl() As Boolean
1236         Set(ByVal value As Boolean)
1237             HttpTwitter.UseSsl = value
1238             If value Then
1239                 _protocol = "https://"
1240             Else
1241                 _protocol = "http://"
1242             End If
1243         End Set
1244     End Property
1245
1246     Public Function GetTimelineApi(ByVal read As Boolean, _
1247                             ByVal gType As WORKERTYPE, _
1248                             ByVal more As Boolean, _
1249                             ByVal startup As Boolean) As String
1250
1251         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1252
1253         If _endingFlag Then Return ""
1254
1255         Dim res As HttpStatusCode
1256         Dim content As String = ""
1257         Dim count As Integer = AppendSettingDialog.Instance.CountApi
1258         If gType = WORKERTYPE.Reply Then count = AppendSettingDialog.Instance.CountApiReply()
1259         If AppendSettingDialog.Instance.UseAdditionalCount Then
1260             If more AndAlso AppendSettingDialog.Instance.MoreCountApi <> 0 Then
1261                 count = AppendSettingDialog.Instance.MoreCountApi
1262             ElseIf startup AndAlso AppendSettingDialog.Instance.FirstCountApi <> 0 AndAlso gType = WORKERTYPE.Timeline Then
1263                 count = AppendSettingDialog.Instance.FirstCountApi
1264             End If
1265         End If
1266         Try
1267             If gType = WORKERTYPE.Timeline Then
1268                 If more Then
1269                     res = twCon.HomeTimeline(count, Me.minHomeTimeline, 0, content)
1270                 Else
1271                     res = twCon.HomeTimeline(count, 0, 0, content)
1272                 End If
1273             Else
1274                 If more Then
1275                     res = twCon.Mentions(count, Me.minMentions, 0, content)
1276                 Else
1277                     res = twCon.Mentions(count, 0, 0, content)
1278                 End If
1279             End If
1280         Catch ex As Exception
1281             Return "Err:" + ex.Message
1282         End Try
1283         Select Case res
1284             Case HttpStatusCode.OK
1285                 Twitter.AccountState = ACCOUNT_STATE.Valid
1286             Case HttpStatusCode.Unauthorized
1287                 Twitter.AccountState = ACCOUNT_STATE.Invalid
1288                 Return "Check your Username/Password."
1289             Case HttpStatusCode.BadRequest
1290                 Return "Err:API Limits?"
1291             Case Else
1292                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
1293         End Select
1294
1295         If gType = WORKERTYPE.Timeline Then
1296             Return CreatePostsFromJson(content, gType, Nothing, read, count, Me.minHomeTimeline)
1297         Else
1298             Return CreatePostsFromJson(content, gType, Nothing, read, count, Me.minMentions)
1299         End If
1300     End Function
1301
1302     Public Function GetUserTimelineApi(ByVal read As Boolean,
1303                                        ByVal count As Integer,
1304                                        ByVal userName As String,
1305                                        ByVal tab As TabClass,
1306                                        ByVal more As Boolean) As String
1307
1308         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1309
1310         If _endingFlag Then Return ""
1311
1312         Dim res As HttpStatusCode
1313         Dim content As String = ""
1314
1315         If count = 0 Then count = 20
1316         Try
1317             If String.IsNullOrEmpty(userName) Then
1318                 Dim target As String = tab.User
1319                 If target Is Nothing Then Return ""
1320                 res = twCon.UserTimeline(0, target, count, 0, 0, content)
1321             Else
1322                 If more Then
1323                     res = twCon.UserTimeline(0, userName, count, tab.OldestId, 0, content)
1324                 Else
1325                     res = twCon.UserTimeline(0, userName, count, 0, 0, content)
1326                 End If
1327             End If
1328         Catch ex As Exception
1329             Return "Err:" + ex.Message
1330         End Try
1331         Select Case res
1332             Case HttpStatusCode.OK
1333                 Twitter.AccountState = ACCOUNT_STATE.Valid
1334             Case HttpStatusCode.Unauthorized
1335                 Twitter.AccountState = ACCOUNT_STATE.Valid
1336                 Return "Err:@" + userName + "'s Tweets are protected."
1337             Case HttpStatusCode.BadRequest
1338                 Return "Err:API Limits?"
1339             Case Else
1340                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
1341         End Select
1342
1343         Dim items As List(Of TwitterDataModel.Status)
1344         Try
1345             items = CreateDataFromJson(Of List(Of TwitterDataModel.Status))(content)
1346         Catch ex As SerializationException
1347             TraceOut(ex.Message + Environment.NewLine + content)
1348             Return "Json Parse Error(DataContractJsonSerializer)"
1349         Catch ex As Exception
1350             TraceOut(content)
1351             Return "Invalid Json!"
1352         End Try
1353
1354         For Each status As TwitterDataModel.Status In items
1355             Dim item As PostClass = CreatePostsFromStatusData(status)
1356             If item Is Nothing Then Continue For
1357             If item.StatusId < tab.OldestId Then tab.OldestId = item.StatusId
1358             item.IsRead = read
1359             If item.IsMe AndAlso Not read AndAlso _readOwnPost Then item.IsRead = True
1360             If tab IsNot Nothing Then item.RelTabName = tab.TabName
1361             '非同期アイコン取得&StatusDictionaryに追加
1362             TabInformations.GetInstance.AddPost(item)
1363         Next
1364
1365         Return ""
1366     End Function
1367
1368     Public Function GetStatusApi(ByVal read As Boolean,
1369                                        ByVal id As Int64,
1370                                        ByRef post As PostClass) As String
1371         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1372
1373         If _endingFlag Then Return ""
1374
1375         Dim res As HttpStatusCode
1376         Dim content As String = ""
1377
1378         Try
1379             res = twCon.ShowStatuses(id, content)
1380         Catch ex As Exception
1381             Return "Err:" + ex.Message
1382         End Try
1383         Select Case res
1384             Case HttpStatusCode.OK
1385                 Twitter.AccountState = ACCOUNT_STATE.Valid
1386             Case HttpStatusCode.Unauthorized
1387                 Twitter.AccountState = ACCOUNT_STATE.Invalid
1388                 Return "Check your Username/Password."
1389             Case HttpStatusCode.BadRequest
1390                 Return "Err:API Limits?"
1391             Case HttpStatusCode.Forbidden
1392                 Return "Err:You are not authorized to see this status"
1393             Case Else
1394                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
1395         End Select
1396
1397         Dim status As TwitterDataModel.Status
1398         Try
1399             status = CreateDataFromJson(Of TwitterDataModel.Status)(content)
1400         Catch ex As SerializationException
1401             TraceOut(ex.Message + Environment.NewLine + content)
1402             Return "Json Parse Error(DataContractJsonSerializer)"
1403         Catch ex As Exception
1404             TraceOut(content)
1405             Return "Invalid Json!"
1406         End Try
1407
1408         Dim item As PostClass = CreatePostsFromStatusData(status)
1409         If item Is Nothing Then Return "Err:Can't create post"
1410         item.IsRead = read
1411         If item.IsMe AndAlso Not read AndAlso _readOwnPost Then item.IsRead = True
1412
1413         post = item
1414         Return ""
1415     End Function
1416
1417     Public Function GetStatusApi(ByVal read As Boolean,
1418                                        ByVal id As Int64,
1419                                        ByVal tab As TabClass) As String
1420         Dim post As PostClass = Nothing
1421         Dim r As String = Me.GetStatusApi(read, id, post)
1422
1423         If r = "" Then
1424             If tab IsNot Nothing Then post.RelTabName = tab.TabName
1425             '非同期アイコン取得&StatusDictionaryに追加
1426             TabInformations.GetInstance.AddPost(post)
1427         End If
1428
1429         Return r
1430     End Function
1431
1432     Private Function CreatePostsFromStatusData(ByVal status As TwitterDataModel.Status) As PostClass
1433         Dim post As New PostClass
1434
1435         post.StatusId = status.Id
1436         If status.RetweetedStatus IsNot Nothing Then
1437             Dim retweeted As TwitterDataModel.RetweetedStatus = status.RetweetedStatus
1438
1439             post.CreatedAt = DateTimeParse(retweeted.CreatedAt)
1440
1441             'Id
1442             post.RetweetedId = retweeted.Id
1443             '本文
1444             post.TextFromApi = retweeted.Text
1445             'Source取得(htmlの場合は、中身を取り出し)
1446             post.Source = retweeted.Source
1447             'Reply先
1448             Long.TryParse(retweeted.InReplyToStatusId, post.InReplyToStatusId)
1449             post.InReplyToUser = retweeted.InReplyToScreenName
1450             Long.TryParse(status.InReplyToUserId, post.InReplyToUserId)
1451             post.IsFav = TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Contains(post.RetweetedId)
1452
1453             '以下、ユーザー情報
1454             Dim user As TwitterDataModel.User = retweeted.User
1455
1456             post.UserId = user.Id
1457             post.ScreenName = user.ScreenName
1458             post.Nickname = user.Name.Trim()
1459             post.ImageUrl = user.ProfileImageUrl
1460             post.IsProtect = user.Protected
1461             post.Language = user.Lang
1462
1463             'Retweetした人
1464             post.RetweetedBy = status.User.ScreenName
1465             post.IsMe = post.RetweetedBy.ToLower.Equals(_uid)
1466         Else
1467             post.CreatedAt = DateTimeParse(status.CreatedAt)
1468             '本文
1469             post.TextFromApi = status.Text
1470             'Source取得(htmlの場合は、中身を取り出し)
1471             post.Source = status.Source
1472             Long.TryParse(status.InReplyToStatusId, post.InReplyToStatusId)
1473             post.InReplyToUser = status.InReplyToScreenName
1474             Long.TryParse(status.InReplyToUserId, post.InReplyToUserId)
1475
1476             post.IsFav = status.Favorited
1477
1478             '以下、ユーザー情報
1479             Dim user As TwitterDataModel.User = status.User
1480
1481             post.UserId = user.Id
1482             post.ScreenName = user.ScreenName
1483             post.Nickname = user.Name.Trim()
1484             post.ImageUrl = user.ProfileImageUrl
1485             post.IsProtect = user.Protected
1486             post.Language = user.Lang
1487             post.IsMe = post.ScreenName.ToLower.Equals(_uid)
1488             If post.IsMe Then _UserIdNo = post.UserId.ToString
1489         End If
1490         'HTMLに整形
1491         post.Text = CreateHtmlAnchor(post.TextFromApi, post.ReplyToList)
1492         post.TextFromApi = HttpUtility.HtmlDecode(post.TextFromApi)
1493         post.TextFromApi = post.TextFromApi.Replace("<3", "♡")
1494         'Source整形
1495         CreateSource(post)
1496
1497         post.IsReply = post.ReplyToList.Contains(_uid)
1498         post.IsExcludeReply = False
1499
1500         If post.IsMe Then
1501             post.IsOwl = False
1502         Else
1503             If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.UserId)
1504         End If
1505
1506         post.IsDm = False
1507         Return post
1508     End Function
1509
1510     Private Function CreatePostsFromJson(ByVal content As String, ByVal gType As WORKERTYPE, ByVal tab As TabClass, ByVal read As Boolean, ByVal count As Integer, ByRef minimumId As Long) As String
1511         Dim items As List(Of TwitterDataModel.Status)
1512         Try
1513             items = CreateDataFromJson(Of List(Of TwitterDataModel.Status))(content)
1514         Catch ex As SerializationException
1515             TraceOut(ex.Message + Environment.NewLine + content)
1516             Return "Json Parse Error(DataContractJsonSerializer)"
1517         Catch ex As Exception
1518             TraceOut(content)
1519             Return "Invalid Json!"
1520         End Try
1521
1522         For Each status As TwitterDataModel.Status In items
1523             Dim post As PostClass = Nothing
1524             post = CreatePostsFromStatusData(status)
1525
1526             If minimumId > post.StatusId Then minimumId = post.StatusId
1527             '二重取得回避
1528             SyncLock LockObj
1529                 If tab Is Nothing Then
1530                     If TabInformations.GetInstance.ContainsKey(post.StatusId) Then Continue For
1531                 Else
1532                     If TabInformations.GetInstance.ContainsKey(post.StatusId, tab.TabName) Then Continue For
1533                 End If
1534             End SyncLock
1535
1536             post.IsRead = read
1537             If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
1538
1539             If tab IsNot Nothing Then post.RelTabName = tab.TabName
1540             '非同期アイコン取得&StatusDictionaryに追加
1541             TabInformations.GetInstance.AddPost(post)
1542         Next
1543
1544         Return ""
1545     End Function
1546
1547     Public Overloads Function GetListStatus(ByVal read As Boolean, _
1548                             ByVal tab As TabClass, _
1549                             ByVal more As Boolean, _
1550                             ByVal startup As Boolean) As String
1551
1552         If _endingFlag Then Return ""
1553
1554         Dim res As HttpStatusCode
1555         Dim content As String = ""
1556         Dim page As Integer = 0
1557         Dim count As Integer
1558         If AppendSettingDialog.Instance.UseAdditionalCount Then
1559             count = AppendSettingDialog.Instance.ListCountApi
1560             If count = 0 Then
1561                 If more AndAlso AppendSettingDialog.Instance.MoreCountApi <> 0 Then
1562                     count = AppendSettingDialog.Instance.MoreCountApi
1563                 ElseIf startup AndAlso AppendSettingDialog.Instance.FirstCountApi <> 0 Then
1564                     count = AppendSettingDialog.Instance.FirstCountApi
1565                 Else
1566                     count = AppendSettingDialog.Instance.CountApi
1567                 End If
1568             End If
1569         Else
1570             count = AppendSettingDialog.Instance.CountApi
1571         End If
1572         Try
1573             If more Then
1574                 res = twCon.GetListsStatuses(tab.ListInfo.UserId.ToString, tab.ListInfo.Id.ToString, count, tab.OldestId, 0, content)
1575             Else
1576                 res = twCon.GetListsStatuses(tab.ListInfo.UserId.ToString, tab.ListInfo.Id.ToString, count, 0, 0, content)
1577             End If
1578         Catch ex As Exception
1579             Return "Err:" + ex.Message
1580         End Try
1581         Select Case res
1582             Case HttpStatusCode.OK
1583                 Twitter.AccountState = ACCOUNT_STATE.Valid
1584             Case HttpStatusCode.Unauthorized
1585                 Twitter.AccountState = ACCOUNT_STATE.Invalid
1586                 Return "Check your Username/Password."
1587             Case HttpStatusCode.BadRequest
1588                 Return "Err:API Limits?"
1589             Case Else
1590                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
1591         End Select
1592
1593         Return CreatePostsFromJson(content, WORKERTYPE.List, tab, read, count, tab.OldestId)
1594     End Function
1595
1596
1597     Private Function CheckReplyToPost(ByVal relPosts As List(Of PostClass)) As PostClass
1598         Dim tmpPost As PostClass = relPosts(0)
1599         Dim lastPost As PostClass = Nothing
1600         Do While tmpPost IsNot Nothing
1601             If tmpPost.InReplyToStatusId = 0 Then Return Nothing
1602             lastPost = tmpPost
1603             Dim replyToPost = From p In relPosts
1604                              Where p.StatusId = tmpPost.InReplyToStatusId
1605                              Select p
1606             tmpPost = replyToPost.FirstOrDefault()
1607         Loop
1608         Return lastPost
1609     End Function
1610
1611     Public Function GetRelatedResult(ByVal read As Boolean, ByVal tab As TabClass) As String
1612         Dim rslt As String = ""
1613         Dim relPosts As New List(Of PostClass)
1614         If tab.RelationTargetPost.TextFromApi.Contains("@") AndAlso tab.RelationTargetPost.InReplyToStatusId = 0 Then
1615             '検索結果対応
1616             Dim p As PostClass = TabInformations.GetInstance.Item(tab.RelationTargetPost.StatusId)
1617             If p IsNot Nothing AndAlso p.InReplyToStatusId > 0 Then
1618                 tab.RelationTargetPost = p
1619             Else
1620                 rslt = Me.GetStatusApi(read, tab.RelationTargetPost.StatusId, p)
1621                 If Not String.IsNullOrEmpty(rslt) Then Return rslt
1622                 tab.RelationTargetPost = p
1623             End If
1624         End If
1625         relPosts.Add(tab.RelationTargetPost.Copy)
1626         Dim tmpPost As PostClass = relPosts(0)
1627         Do
1628             rslt = Me.GetRelatedResultsApi(read, tmpPost, tab, relPosts)
1629             If Not String.IsNullOrEmpty(rslt) Then Exit Do
1630             tmpPost = CheckReplyToPost(relPosts)
1631         Loop While tmpPost IsNot Nothing
1632         relPosts.ForEach(New Action(Of PostClass)(Sub(p) TabInformations.GetInstance.AddPost(p)))
1633         Return rslt
1634     End Function
1635
1636     Public Function GetRelatedResultsApi(ByVal read As Boolean,
1637                                          ByVal post As PostClass,
1638                                          ByVal tab As TabClass,
1639                                          ByVal relatedPosts As List(Of PostClass)) As String
1640
1641         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1642
1643         If _endingFlag Then Return ""
1644
1645         Dim res As HttpStatusCode
1646         Dim content As String = ""
1647         Try
1648             res = twCon.GetRelatedResults(post.StatusId, content)
1649         Catch ex As Exception
1650             Return "Err:" + ex.Message
1651         End Try
1652         Select Case res
1653             Case HttpStatusCode.OK
1654                 Twitter.AccountState = ACCOUNT_STATE.Valid
1655             Case HttpStatusCode.Unauthorized
1656                 Twitter.AccountState = ACCOUNT_STATE.Invalid
1657                 Return "Check your Username/Password."
1658             Case HttpStatusCode.BadRequest
1659                 Return "Err:API Limits?"
1660             Case Else
1661                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
1662         End Select
1663
1664         Dim items As List(Of TwitterDataModel.RelatedResult)
1665         Try
1666             items = CreateDataFromJson(Of List(Of TwitterDataModel.RelatedResult))(content)
1667         Catch ex As SerializationException
1668             TraceOut(ex.Message + Environment.NewLine + content)
1669             Return "Json Parse Error(DataContractJsonSerializer)"
1670         Catch ex As Exception
1671             TraceOut(content)
1672             Return "Invalid Json!"
1673         End Try
1674
1675         Dim targetItem As PostClass = post
1676         If targetItem Is Nothing Then
1677             Return ""
1678         Else
1679             targetItem = targetItem.Copy()
1680         End If
1681         targetItem.RelTabName = tab.TabName
1682         TabInformations.GetInstance.AddPost(targetItem)
1683
1684         Dim replyToItem As PostClass = Nothing
1685         Dim replyToUserName As String = targetItem.InReplyToUser
1686         If targetItem.InReplyToStatusId > 0 AndAlso TabInformations.GetInstance.Item(targetItem.InReplyToStatusId) IsNot Nothing Then
1687             replyToItem = TabInformations.GetInstance.Item(targetItem.InReplyToStatusId).Copy
1688             replyToItem.IsRead = read
1689             If replyToItem.IsMe AndAlso Not read AndAlso _readOwnPost Then replyToItem.IsRead = True
1690             replyToItem.RelTabName = tab.TabName
1691         End If
1692
1693         Dim replyAdded As Boolean = False
1694         For Each relatedData As TwitterDataModel.RelatedResult In items
1695             For Each result As TwitterDataModel.RelatedTweet In relatedData.Results
1696                 Dim item As PostClass = CreatePostsFromStatusData(result.Status)
1697                 If item Is Nothing Then Continue For
1698                 If targetItem.InReplyToStatusId = item.StatusId Then
1699                     replyToItem = Nothing
1700                     replyAdded = True
1701                 End If
1702                 item.IsRead = read
1703                 If item.IsMe AndAlso Not read AndAlso _readOwnPost Then item.IsRead = True
1704                 If tab IsNot Nothing Then item.RelTabName = tab.TabName
1705                 '非同期アイコン取得&StatusDictionaryに追加
1706                 relatedPosts.Add(item)
1707             Next
1708         Next
1709         If replyToItem IsNot Nothing Then
1710             relatedPosts.Add(replyToItem)
1711         ElseIf targetItem.InReplyToStatusId > 0 AndAlso Not replyAdded Then
1712             Dim p As PostClass = Nothing
1713             Dim rslt As String = ""
1714             rslt = GetStatusApi(read, targetItem.InReplyToStatusId, p)
1715             If String.IsNullOrEmpty(rslt) Then
1716                 p.IsRead = read
1717                 p.RelTabName = tab.TabName
1718                 relatedPosts.Add(p)
1719             End If
1720             Return rslt
1721         End If
1722
1723         '発言者・返信先ユーザーの直近10発言取得
1724         'Dim rslt As String = Me.GetUserTimelineApi(read, 10, "", tab)
1725         'If Not String.IsNullOrEmpty(rslt) Then Return rslt
1726         'If Not String.IsNullOrEmpty(replyToUserName) Then
1727         '    rslt = Me.GetUserTimelineApi(read, 10, replyToUserName, tab)
1728         'End If
1729         'Return rslt
1730         Return ""
1731     End Function
1732
1733     Public Function GetSearch(ByVal read As Boolean, _
1734                             ByVal tab As TabClass, _
1735                             ByVal more As Boolean) As String
1736
1737         If _endingFlag Then Return ""
1738
1739         Dim res As HttpStatusCode
1740         Dim content As String = ""
1741         Dim page As Integer = 0
1742         Dim sinceId As Long = 0
1743         Dim count As Integer = 100
1744         If AppendSettingDialog.Instance.UseAdditionalCount AndAlso
1745             AppendSettingDialog.Instance.SearchCountApi <> 0 Then
1746             count = AppendSettingDialog.Instance.SearchCountApi
1747         End If
1748         If more Then
1749             page = tab.GetSearchPage(count)
1750         Else
1751             sinceId = tab.SinceId
1752         End If
1753
1754         Try
1755             ' TODO:一時的に40>100件に 件数変更UI作成の必要あり
1756             res = twCon.Search(tab.SearchWords, tab.SearchLang, count, page, sinceId, content)
1757         Catch ex As Exception
1758             Return "Err:" + ex.Message
1759         End Try
1760         Select Case res
1761             Case HttpStatusCode.BadRequest
1762                 Return "Invalid query"
1763             Case HttpStatusCode.NotFound
1764                 Return "Invalid query"
1765             Case HttpStatusCode.PaymentRequired 'API Documentには420と書いてあるが、該当コードがないので402にしてある
1766                 Return "Search API Limit?"
1767             Case HttpStatusCode.OK
1768             Case Else
1769                 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
1770         End Select
1771
1772         If Not TabInformations.GetInstance.ContainsTab(tab) Then Return ""
1773
1774         Dim xdoc As New XmlDocument
1775         Try
1776             xdoc.LoadXml(content)
1777         Catch ex As Exception
1778             TraceOut(content)
1779             Return "Invalid ATOM!"
1780         End Try
1781         Dim nsmgr As New XmlNamespaceManager(xdoc.NameTable)
1782         nsmgr.AddNamespace("search", "http://www.w3.org/2005/Atom")
1783         nsmgr.AddNamespace("twitter", "http://api.twitter.com/")
1784         For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/search:feed/search:entry", nsmgr)
1785             Dim xentry As XmlElement = CType(xentryNode, XmlElement)
1786             Dim post As New PostClass
1787             Try
1788                 post.StatusId = Long.Parse(xentry.Item("id").InnerText.Split(":"c)(2))
1789                 If TabInformations.GetInstance.ContainsKey(post.StatusId, tab.TabName) Then Continue For
1790                 post.CreatedAt = DateTime.Parse(xentry.Item("published").InnerText)
1791                 '本文
1792                 post.TextFromApi = xentry.Item("title").InnerText
1793                 'Source取得(htmlの場合は、中身を取り出し)
1794                 post.Source = xentry.Item("twitter:source").InnerText
1795                 post.InReplyToStatusId = 0
1796                 post.InReplyToUser = ""
1797                 post.InReplyToUserId = 0
1798                 post.IsFav = False
1799
1800                 '以下、ユーザー情報
1801                 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./search:author", nsmgr), XmlElement)
1802                 post.UserId = 0
1803                 post.ScreenName = xUentry.Item("name").InnerText.Split(" "c)(0).Trim
1804                 post.Nickname = xUentry.Item("name").InnerText.Substring(post.ScreenName.Length).Trim
1805                 If post.Nickname.Length > 2 Then
1806                     post.Nickname = post.Nickname.Substring(1, post.Nickname.Length - 2)
1807                 Else
1808                     post.Nickname = post.ScreenName
1809                 End If
1810                 post.ImageUrl = CType(xentry.SelectSingleNode("./search:link[@type='image/png']", nsmgr), XmlElement).GetAttribute("href")
1811                 post.IsProtect = False
1812                 post.IsMe = post.ScreenName.ToLower.Equals(_uid)
1813
1814                 'HTMLに整形
1815                 post.Text = CreateHtmlAnchor(HttpUtility.HtmlEncode(post.TextFromApi), post.ReplyToList)
1816                 post.TextFromApi = HttpUtility.HtmlDecode(post.TextFromApi)
1817                 'Source整形
1818                 CreateSource(post)
1819
1820                 post.IsRead = read
1821                 post.IsReply = post.ReplyToList.Contains(_uid)
1822                 post.IsExcludeReply = False
1823                 post.Language = xentryNode.Item("twitter:lang").InnerText
1824
1825                 post.IsOwl = False
1826                 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
1827                 post.IsDm = False
1828                 post.RelTabName = tab.TabName
1829                 If Not more AndAlso post.StatusId > tab.SinceId Then tab.SinceId = post.StatusId
1830             Catch ex As Exception
1831                 TraceOut(content)
1832                 Continue For
1833             End Try
1834
1835             'Me._dIcon.Add(post.ImageUrl, Nothing)
1836             TabInformations.GetInstance.AddPost(post)
1837
1838         Next
1839
1840         '' TODO
1841         '' 遡るための情報max_idやnext_pageの情報を保持する
1842
1843 #If 0 Then
1844         Dim xNode As XmlNode = xdoc.DocumentElement.SelectSingleNode("/search:feed/twitter:warning", nsmgr)
1845
1846         If xNode IsNot Nothing Then
1847             Return "Warn:" + xNode.InnerText + "(" + GetCurrentMethod.Name + ")"
1848         End If
1849 #End If
1850
1851         Return ""
1852     End Function
1853
1854     Private Function CreateDirectMessagesFromJson(ByVal content As String, ByVal gType As WORKERTYPE, ByVal read As Boolean) As String
1855         Dim item As List(Of TwitterDataModel.Directmessage)
1856         Try
1857             If gType = WORKERTYPE.UserStream Then
1858                 Dim itm As List(Of TwitterDataModel.DirectmessageEvent) = CreateDataFromJson(Of List(Of TwitterDataModel.DirectmessageEvent))(content)
1859                 item = New List(Of TwitterDataModel.Directmessage)
1860                 For Each dat As TwitterDataModel.DirectmessageEvent In itm
1861                     item.Add(dat.Directmessage)
1862                 Next
1863             Else
1864                 item = CreateDataFromJson(Of List(Of TwitterDataModel.Directmessage))(content)
1865             End If
1866         Catch ex As SerializationException
1867             TraceOut(ex.Message + Environment.NewLine + content)
1868             Return "Json Parse Error(DataContractJsonSerializer)"
1869         Catch ex As Exception
1870             TraceOut(content)
1871             Return "Invalid Json!"
1872         End Try
1873
1874         For Each message As TwitterDataModel.Directmessage In item
1875             Dim post As New PostClass
1876             Try
1877                 post.StatusId = message.Id
1878                 If gType <> WORKERTYPE.UserStream Then
1879                     If gType = WORKERTYPE.DirectMessegeRcv Then
1880                         If minDirectmessage > post.StatusId Then minDirectmessage = post.StatusId
1881                     Else
1882                         If minDirectmessageSent > post.StatusId Then minDirectmessageSent = post.StatusId
1883                     End If
1884                 End If
1885
1886                 '二重取得回避
1887                 SyncLock LockObj
1888                     If TabInformations.GetInstance.GetTabByType(TabUsageType.DirectMessage).Contains(post.StatusId) Then Continue For
1889                 End SyncLock
1890                 'sender_id
1891                 'recipient_id
1892                 post.CreatedAt = DateTimeParse(message.CreatedAt)
1893                 '本文
1894                 post.TextFromApi = message.Text
1895                 'HTMLに整形
1896                 post.Text = CreateHtmlAnchor(post.TextFromApi, post.ReplyToList)
1897                 post.TextFromApi = HttpUtility.HtmlDecode(post.TextFromApi)
1898                 post.TextFromApi = post.TextFromApi.Replace("<3", "♡")
1899                 post.IsFav = False
1900
1901                 '以下、ユーザー情報
1902                 Dim user As TwitterDataModel.User
1903                 If gType = WORKERTYPE.UserStream Then
1904                     If twCon.AuthenticatedUsername.Equals(message.Recipient.ScreenName, StringComparison.CurrentCultureIgnoreCase) Then
1905                         user = message.Sender
1906                         post.IsMe = False
1907                         post.IsOwl = True
1908                     Else
1909                         user = message.Recipient
1910                         post.IsMe = True
1911                         post.IsOwl = False
1912                     End If
1913                 Else
1914                     If gType = WORKERTYPE.DirectMessegeRcv Then
1915                         user = message.Sender
1916                         post.IsMe = False
1917                         post.IsOwl = True
1918                     Else
1919                         user = message.Recipient
1920                         post.IsMe = True
1921                         post.IsOwl = False
1922                     End If
1923                 End If
1924
1925                 post.UserId = user.Id
1926                 post.ScreenName = user.ScreenName
1927                 post.Nickname = user.Name.Trim()
1928                 post.ImageUrl = user.ProfileImageUrl
1929                 post.IsProtect = user.Protected
1930                 post.Language = user.Lang
1931             Catch ex As Exception
1932                 TraceOut(content)
1933                 MessageBox.Show("Parse Error(CreateDirectMessagesFromJson)")
1934                 Continue For
1935             End Try
1936
1937             post.IsRead = read
1938             If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
1939             post.IsReply = False
1940             post.IsExcludeReply = False
1941             post.IsDm = True
1942
1943             TabInformations.GetInstance.AddPost(post)
1944         Next
1945
1946         Return ""
1947
1948     End Function
1949
1950     Public Function GetDirectMessageApi(ByVal read As Boolean, _
1951                             ByVal gType As WORKERTYPE, _
1952                             ByVal more As Boolean) As String
1953         If _endingFlag Then Return ""
1954
1955         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1956
1957         Dim res As HttpStatusCode
1958         Dim content As String = ""
1959
1960         Try
1961             If gType = WORKERTYPE.DirectMessegeRcv Then
1962                 If more Then
1963                     res = twCon.DirectMessages(20, minDirectmessage, 0, content)
1964                 Else
1965                     res = twCon.DirectMessages(20, 0, 0, content)
1966                 End If
1967             Else
1968                 If more Then
1969                     res = twCon.DirectMessagesSent(20, minDirectmessageSent, 0, content)
1970                 Else
1971                     res = twCon.DirectMessagesSent(20, 0, 0, content)
1972                 End If
1973             End If
1974         Catch ex As Exception
1975             Return "Err:" + ex.Message
1976         End Try
1977
1978         Select Case res
1979             Case HttpStatusCode.OK
1980                 Twitter.AccountState = ACCOUNT_STATE.Valid
1981             Case HttpStatusCode.Unauthorized
1982                 Twitter.AccountState = ACCOUNT_STATE.Invalid
1983                 Return "Check your Username/Password."
1984             Case HttpStatusCode.BadRequest
1985                 Return "Err:API Limits?"
1986             Case Else
1987                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
1988         End Select
1989
1990         Return CreateDirectMessagesFromJson(content, gType, read)
1991     End Function
1992
1993     Public Function GetFavoritesApi(ByVal read As Boolean, _
1994                         ByVal gType As WORKERTYPE) As String
1995
1996         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1997
1998         If _endingFlag Then Return ""
1999
2000         Dim res As HttpStatusCode
2001         Dim content As String = ""
2002         Dim count As Integer = AppendSettingDialog.Instance.CountApi
2003         If AppendSettingDialog.Instance.UseAdditionalCount AndAlso
2004             AppendSettingDialog.Instance.FavoritesCountApi <> 0 Then
2005             count = AppendSettingDialog.Instance.FavoritesCountApi
2006         End If
2007         Try
2008             res = twCon.Favorites(count, content)
2009         Catch ex As Exception
2010             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2011         End Try
2012
2013         Select Case res
2014             Case HttpStatusCode.OK
2015                 Twitter.AccountState = ACCOUNT_STATE.Valid
2016             Case HttpStatusCode.Unauthorized
2017                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2018                 Return "Check your Username/Password."
2019             Case HttpStatusCode.BadRequest
2020                 Return "Err:API Limits?"
2021             Case Else
2022                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2023         End Select
2024
2025         Dim serializer As New DataContractJsonSerializer(GetType(List(Of TwitterDataModel.Status)))
2026         Dim item As List(Of TwitterDataModel.Status)
2027
2028         Try
2029             item = CreateDataFromJson(Of List(Of TwitterDataModel.Status))(content)
2030         Catch ex As SerializationException
2031             TraceOut(ex.Message + Environment.NewLine + content)
2032             Return "Json Parse Error(DataContractJsonSerializer)"
2033         Catch ex As Exception
2034             TraceOut(content)
2035             Return "Invalid Json!"
2036         End Try
2037
2038         For Each status As TwitterDataModel.Status In item
2039             Dim post As New PostClass
2040             Try
2041                 post.StatusId = status.Id
2042                 '二重取得回避
2043                 SyncLock LockObj
2044                     If TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Contains(post.StatusId) Then Continue For
2045                 End SyncLock
2046                 'Retweet判定
2047                 If status.RetweetedStatus IsNot Nothing Then
2048                     Dim retweeted As TwitterDataModel.RetweetedStatus = status.RetweetedStatus
2049                     post.CreatedAt = DateTimeParse(retweeted.CreatedAt)
2050
2051                     'Id
2052                     post.RetweetedId = post.StatusId
2053                     '本文
2054                     post.TextFromApi = retweeted.Text
2055                     'Source取得(htmlの場合は、中身を取り出し)
2056                     post.Source = retweeted.Source
2057                     'Reply先
2058                     Long.TryParse(retweeted.InReplyToStatusId, post.InReplyToStatusId)
2059                     post.InReplyToUser = retweeted.InReplyToScreenName
2060                     Long.TryParse(retweeted.InReplyToUserId, post.InReplyToUserId)
2061                     post.IsFav = retweeted.Favorited
2062
2063                     '以下、ユーザー情報
2064                     Dim user As TwitterDataModel.User = retweeted.User
2065                     post.UserId = user.Id
2066                     post.ScreenName = user.ScreenName
2067                     post.Nickname = user.Name.Trim()
2068                     post.ImageUrl = user.ProfileImageUrl
2069                     post.IsProtect = user.Protected
2070                     post.Language = user.Lang
2071
2072                     'Retweetした人
2073                     post.RetweetedBy = status.User.ScreenName
2074                     post.IsMe = post.RetweetedBy.ToLower.Equals(_uid)
2075                     If post.IsMe Then _UserIdNo = post.UserId.ToString()
2076                 Else
2077                     post.CreatedAt = DateTimeParse(status.CreatedAt)
2078
2079                     '本文
2080                     post.TextFromApi = status.Text
2081                     'Source取得(htmlの場合は、中身を取り出し)
2082                     post.Source = status.Source
2083                     Long.TryParse(status.InReplyToStatusId, post.InReplyToStatusId)
2084                     post.InReplyToUser = status.InReplyToScreenName
2085                     Long.TryParse(status.InReplyToUserId, post.InReplyToUserId)
2086
2087                     post.IsFav = status.Favorited
2088
2089                     '以下、ユーザー情報
2090                     Dim user As TwitterDataModel.User = status.User
2091                     post.UserId = user.Id
2092                     post.ScreenName = user.ScreenName
2093                     post.Nickname = user.Name.Trim()
2094                     post.ImageUrl = user.ProfileImageUrl
2095                     post.IsProtect = user.Protected
2096                     post.Language = user.Lang
2097                     post.IsMe = post.ScreenName.ToLower.Equals(_uid)
2098                     If post.IsMe Then _UserIdNo = post.UserId.ToString
2099                 End If
2100                 'HTMLに整形
2101                 post.Text = CreateHtmlAnchor(post.TextFromApi, post.ReplyToList)
2102                 post.TextFromApi = HttpUtility.HtmlDecode(post.TextFromApi)
2103                 post.TextFromApi = post.TextFromApi.Replace("<3", "♡")
2104                 'Source整形
2105                 CreateSource(post)
2106
2107                 post.IsRead = read
2108                 post.IsReply = post.ReplyToList.Contains(_uid)
2109                 post.IsExcludeReply = False
2110
2111                 If post.IsMe Then
2112                     post.IsOwl = False
2113                 Else
2114                     If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.UserId)
2115                 End If
2116
2117                 post.IsDm = False
2118             Catch ex As Exception
2119                 TraceOut(content)
2120                 Continue For
2121             End Try
2122
2123             TabInformations.GetInstance.AddPost(post)
2124
2125         Next
2126
2127         Return ""
2128     End Function
2129
2130     Public Function GetFollowersApi() As String
2131         If _endingFlag Then Return ""
2132         Dim cursor As Long = -1
2133         Dim tmpFollower As New List(Of Long)(followerId)
2134
2135         followerId.Clear()
2136         Do
2137             Dim ret As String = FollowerApi(cursor)
2138             If Not String.IsNullOrEmpty(ret) Then
2139                 followerId.Clear()
2140                 followerId.AddRange(tmpFollower)
2141                 _GetFollowerResult = False
2142                 Return ret
2143             End If
2144         Loop While cursor > 0
2145
2146         TabInformations.GetInstance.RefreshOwl(followerId)
2147
2148         _GetFollowerResult = True
2149         Return ""
2150     End Function
2151
2152     Public ReadOnly Property GetFollowersSuccess() As Boolean
2153         Get
2154             Return _GetFollowerResult
2155         End Get
2156     End Property
2157
2158     Private Function FollowerApi(ByRef cursor As Long) As String
2159         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2160
2161         Dim res As HttpStatusCode
2162         Dim content As String = ""
2163         Try
2164             res = twCon.FollowerIds(cursor, content)
2165         Catch ex As Exception
2166             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2167         End Try
2168
2169         Select Case res
2170             Case HttpStatusCode.OK
2171                 Twitter.AccountState = ACCOUNT_STATE.Valid
2172             Case HttpStatusCode.Unauthorized
2173                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2174                 Return "Check your Username/Password."
2175             Case HttpStatusCode.BadRequest
2176                 Return "Err:API Limits?"
2177             Case Else
2178                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2179         End Select
2180
2181         Try
2182             Dim followers = CreateDataFromJson(Of TwitterDataModel.Followers)(content)
2183             followerId.AddRange(followers.Id)
2184             cursor = followers.NextCursor
2185             Return ""
2186         Catch ex As SerializationException
2187             TraceOut(ex.Message + Environment.NewLine + content)
2188             Return "Err:Json Parse Error(DataContractJsonSerializer)"
2189         Catch ex As Exception
2190             TraceOut(content)
2191             Return "Err:Invalid Json!"
2192         End Try
2193     End Function
2194
2195     Public Function GetListsApi() As String
2196         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2197
2198         Dim res As HttpStatusCode
2199         Dim content As String = ""
2200         Dim cursor As Long = -1
2201
2202         Dim lists As New List(Of ListElement)
2203         Do
2204             Try
2205                 res = twCon.GetLists(Me.Username, cursor, content)
2206             Catch ex As Exception
2207                 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2208             End Try
2209
2210             Select Case res
2211                 Case HttpStatusCode.OK
2212                     Twitter.AccountState = ACCOUNT_STATE.Valid
2213                 Case HttpStatusCode.Unauthorized
2214                     Twitter.AccountState = ACCOUNT_STATE.Invalid
2215                     Return "Check your Username/Password."
2216                 Case HttpStatusCode.BadRequest
2217                     Return "Err:API Limits?"
2218                 Case Else
2219                     Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2220             End Select
2221
2222             Try
2223                 Dim lst = CreateDataFromJson(Of TwitterDataModel.Lists)(content)
2224                 For Each le In lst.Lists
2225                     lists.Add(New ListElement(le, Me))
2226                 Next
2227                 cursor = lst.NextCursor
2228             Catch ex As SerializationException
2229                 TraceOut(ex.Message + Environment.NewLine + content)
2230                 Return "Err:Json Parse Error(DataContractJsonSerializer)"
2231             Catch ex As Exception
2232                 TraceOut(content)
2233                 Return "Err:Invalid Json!"
2234             End Try
2235         Loop While cursor <> 0
2236
2237         cursor = -1
2238         content = ""
2239         Do
2240             Try
2241                 res = twCon.GetListsSubscriptions(Me.Username, cursor, content)
2242             Catch ex As Exception
2243                 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2244             End Try
2245
2246             Select Case res
2247                 Case HttpStatusCode.OK
2248                     Twitter.AccountState = ACCOUNT_STATE.Valid
2249                 Case HttpStatusCode.Unauthorized
2250                     Twitter.AccountState = ACCOUNT_STATE.Invalid
2251                     Return "Check your Username/Password."
2252                 Case HttpStatusCode.BadRequest
2253                     Return "Err:API Limits?"
2254                 Case Else
2255                     Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2256             End Select
2257
2258             Try
2259                 Dim lst = CreateDataFromJson(Of TwitterDataModel.Lists)(content)
2260                 For Each le In lst.Lists
2261                     lists.Add(New ListElement(le, Me))
2262                 Next
2263                 cursor = lst.NextCursor
2264             Catch ex As SerializationException
2265                 TraceOut(ex.Message + Environment.NewLine + content)
2266                 Return "Err:Json Parse Error(DataContractJsonSerializer)"
2267             Catch ex As Exception
2268                 TraceOut(content)
2269                 Return "Err:Invalid Json!"
2270             End Try
2271         Loop While cursor <> 0
2272
2273         TabInformations.GetInstance.SubscribableLists = lists
2274         Return ""
2275     End Function
2276
2277     Public Function DeleteList(ByVal list_id As String) As String
2278         Dim res As HttpStatusCode
2279         Dim content As String = ""
2280
2281         Try
2282             res = twCon.DeleteListID(Me.Username, list_id, content)
2283         Catch ex As Exception
2284             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2285         End Try
2286
2287         Select Case res
2288             Case HttpStatusCode.OK
2289                 Twitter.AccountState = ACCOUNT_STATE.Valid
2290             Case HttpStatusCode.Unauthorized
2291                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2292                 Return "Check your Username/Password."
2293             Case HttpStatusCode.BadRequest
2294                 Return "Err:API Limits?"
2295             Case Else
2296                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2297         End Select
2298
2299         Return ""
2300     End Function
2301
2302     Public Function EditList(ByVal list_id As String, ByVal new_name As String, ByVal isPrivate As Boolean, ByVal description As String, ByRef list As ListElement) As String
2303         Dim res As HttpStatusCode
2304         Dim content As String = ""
2305         Dim modeString As String = "public"
2306         If isPrivate Then
2307             modeString = "private"
2308         End If
2309
2310         Try
2311             res = twCon.PostListID(Me.Username, list_id, new_name, modeString, description, content)
2312         Catch ex As Exception
2313             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2314         End Try
2315
2316         Select Case res
2317             Case HttpStatusCode.OK
2318                 Twitter.AccountState = ACCOUNT_STATE.Valid
2319             Case HttpStatusCode.Unauthorized
2320                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2321                 Return "Check your Username/Password."
2322             Case HttpStatusCode.BadRequest
2323                 Return "Err:API Limits?"
2324             Case Else
2325                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2326         End Select
2327
2328         Try
2329             Dim le = CreateDataFromJson(Of TwitterDataModel.ListElementData)(content)
2330             Dim newList As New ListElement(le, Me)
2331             list.Description = newList.Description
2332             list.Id = newList.Id
2333             list.IsPublic = newList.IsPublic
2334             list.MemberCount = newList.MemberCount
2335             list.Name = newList.Name
2336             list.SubscriberCount = newList.SubscriberCount
2337             list.Slug = newList.Slug
2338             list.Nickname = newList.Nickname
2339             list.Username = newList.Username
2340             list.UserId = newList.UserId
2341             Return ""
2342         Catch ex As SerializationException
2343             TraceOut(ex.Message + Environment.NewLine + content)
2344             Return "Err:Json Parse Error(DataContractJsonSerializer)"
2345         Catch ex As Exception
2346             TraceOut(content)
2347             Return "Err:Invalid Json!"
2348         End Try
2349
2350     End Function
2351
2352     Public Function GetListMembers(ByVal list_id As String, ByVal lists As List(Of UserInfo), ByRef cursor As Long) As String
2353         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2354
2355         Dim res As HttpStatusCode
2356         Dim content As String = ""
2357
2358         'Do
2359         Try
2360             res = twCon.GetListMembers(Me.Username, list_id, cursor, content)
2361         Catch ex As Exception
2362             Return "Err:" + ex.Message
2363         End Try
2364
2365         Select Case res
2366             Case HttpStatusCode.OK
2367                 Twitter.AccountState = ACCOUNT_STATE.Valid
2368             Case HttpStatusCode.Unauthorized
2369                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2370                 Return "Check your Username/Password."
2371             Case HttpStatusCode.BadRequest
2372                 Return "Err:API Limits?"
2373             Case Else
2374                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2375         End Select
2376
2377         Try
2378             Dim users = CreateDataFromJson(Of TwitterDataModel.Users)(content)
2379             Array.ForEach(Of TwitterDataModel.User)(
2380                 users.users,
2381                 New Action(Of TwitterDataModel.User)(Sub(u)
2382                                                          lists.Add(New UserInfo(u))
2383                                                      End Sub))
2384             cursor = users.NextCursor
2385             Return ""
2386         Catch ex As SerializationException
2387             TraceOut(ex.Message + Environment.NewLine + content)
2388             Return "Err:Json Parse Error(DataContractJsonSerializer)"
2389         Catch ex As Exception
2390             TraceOut(content)
2391             Return "Err:Invalid Json!"
2392         End Try
2393
2394         Return ""
2395     End Function
2396
2397     Public Function CreateListApi(ByVal listName As String, ByVal isPrivate As Boolean, ByVal description As String) As String
2398         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2399
2400         Dim res As HttpStatusCode
2401         Dim content As String = ""
2402
2403         Try
2404             res = twCon.PostLists(Me.Username, listName, isPrivate, description, content)
2405         Catch ex As Exception
2406             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2407         End Try
2408
2409         Select Case res
2410             Case HttpStatusCode.OK
2411                 Twitter.AccountState = ACCOUNT_STATE.Valid
2412             Case HttpStatusCode.Unauthorized
2413                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2414                 Return "Check your Username/Password."
2415             Case HttpStatusCode.BadRequest
2416                 Return "Err:API Limits?"
2417             Case Else
2418                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2419         End Select
2420
2421         Try
2422             Dim le = CreateDataFromJson(Of TwitterDataModel.ListElementData)(content)
2423             TabInformations.GetInstance().SubscribableLists.Add(New ListElement(le, Me))
2424             Return ""
2425         Catch ex As SerializationException
2426             TraceOut(ex.Message + Environment.NewLine + content)
2427             Return "Err:Json Parse Error(DataContractJsonSerializer)"
2428         Catch ex As Exception
2429             TraceOut(content)
2430             Return "Err:Invalid Json!"
2431         End Try
2432     End Function
2433
2434     Public Function ContainsUserAtList(ByVal list_name As String, ByVal user As String, ByRef value As Boolean) As String
2435         value = False
2436
2437         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2438
2439         Dim res As HttpStatusCode
2440         Dim content As String = ""
2441
2442         Try
2443             res = Me.twCon.GetListMembersID(Me.Username, list_name, user, content)
2444         Catch ex As Exception
2445             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2446         End Try
2447
2448         Select Case res
2449             Case HttpStatusCode.OK
2450                 Twitter.AccountState = ACCOUNT_STATE.Valid
2451             Case HttpStatusCode.Unauthorized
2452                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2453                 Return "Check your Username/Password."
2454             Case HttpStatusCode.BadRequest
2455                 Return "Err:API Limits?"
2456             Case HttpStatusCode.NotFound
2457                 value = False
2458                 Return ""
2459             Case Else
2460                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2461         End Select
2462
2463         Try
2464             Dim u = CreateDataFromJson(Of TwitterDataModel.User)(content)
2465             value = True
2466             Return ""
2467         Catch ex As Exception
2468             value = False
2469             Return ""
2470         End Try
2471     End Function
2472
2473     Public Function AddUserToList(ByVal list_name As String, ByVal user As String) As String
2474         Dim content As String = ""
2475         Dim res As HttpStatusCode
2476
2477         Try
2478             res = twCon.PostListMembers(Me.Username, list_name, user, content)
2479         Catch ex As Exception
2480             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2481         End Try
2482
2483         Select Case res
2484             Case HttpStatusCode.OK
2485                 Twitter.AccountState = ACCOUNT_STATE.Valid
2486             Case HttpStatusCode.Unauthorized
2487                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2488                 Return "Check your Username/Password."
2489             Case HttpStatusCode.BadRequest
2490                 Return "Err:" + GetErrorMessageJson(content)
2491             Case Else
2492                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2493         End Select
2494
2495         Return ""
2496     End Function
2497
2498     Public Function RemoveUserToList(ByVal list_name As String, ByVal user As String) As String
2499         Dim content As String = ""
2500         Dim res As HttpStatusCode
2501
2502         Try
2503             res = twCon.DeleteListMembers(Me.Username, list_name, user, content)
2504         Catch ex As Exception
2505             Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2506         End Try
2507
2508         Select Case res
2509             Case HttpStatusCode.OK
2510                 Twitter.AccountState = ACCOUNT_STATE.Valid
2511             Case HttpStatusCode.Unauthorized
2512                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2513                 Return "Check your Username/Password."
2514             Case HttpStatusCode.BadRequest
2515                 Return "Err:" + GetErrorMessageJson(content)
2516             Case Else
2517                 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2518         End Select
2519
2520         Return ""
2521     End Function
2522
2523     Private Class range
2524         Public Property fromIndex As Integer
2525         Public Property toIndex As Integer
2526         Public Sub New(ByVal fromIndex As Integer, ByVal toIndex As Integer)
2527             Me.fromIndex = fromIndex
2528             Me.toIndex = toIndex
2529         End Sub
2530     End Class
2531     Public Function CreateHtmlAnchor(ByVal Text As String, ByVal AtList As List(Of String)) As String
2532         If Text Is Nothing Then Return Nothing
2533         Dim retStr As String = Text.Replace("&gt;", "<<<<<tweenだいなり>>>>>").Replace("&lt;", "<<<<<tweenしょうなり>>>>>")
2534         'uriの正規表現
2535         Const url_valid_general_path_chars As String = "[a-z0-9!*';:=+$/%#\[\]\-_,~]"
2536         Const url_valid_url_path_ending_chars As String = "[a-z0-9=#/]"
2537         Const pth As String = "(?<path>/(?:(?:\(" + url_valid_general_path_chars + "+\))" +
2538             "|@" + url_valid_general_path_chars + "+/" +
2539             "|[.,]?" + url_valid_general_path_chars +
2540             ")*" +
2541             url_valid_url_path_ending_chars + "?)?"
2542         Const qry As String = "(?<query>\?[a-z0-9!*'();:&=+$/%#\[\]\-_.,~]*[a-z0-9_&=#])?"
2543         Const rgUrl As String = "(?<before>(?:[^\""':!=]|^|\:))" +
2544                                     "(?<url>(?<protocol>https?://|www\.)" +
2545                                     "(?<domain>(?:[\.-]|[^\p{P}\s])+\.[a-z]{2,}(?::[0-9]+)?)" +
2546                                     pth +
2547                                     qry +
2548                                     ")"
2549         '絶対パス表現のUriをリンクに置換
2550         retStr = Regex.Replace(retStr,
2551                                rgUrl,
2552                                New MatchEvaluator(Function(mu As Match)
2553                                                       Dim sb As New StringBuilder(mu.Result("${before}<a href="""))
2554                                                       If mu.Result("${protocol}").StartsWith("w", StringComparison.OrdinalIgnoreCase) Then
2555                                                           sb.Append("http://")
2556                                                       End If
2557                                                       sb.Append(mu.Result("${url}"">")).Append(mu.Result("${url}")).Append("</a>")
2558                                                       Return sb.ToString
2559                                                   End Function),
2560                                RegexOptions.IgnoreCase)
2561
2562         '@先をリンクに置換(リスト)
2563         retStr = Regex.Replace(retStr,
2564                                "(^|[^a-zA-Z0-9_/])([@@]+)([a-zA-Z0-9_]{1,20}/[a-zA-Z][a-zA-Z0-9\p{IsLatin-1Supplement}\-]{0,79})",
2565                                "$1$2<a href=""/$3"">$3</a>")
2566
2567         Dim m As Match = Regex.Match(retStr, "(^|[^a-zA-Z0-9_])[@@]([a-zA-Z0-9_]{1,20})")
2568         While m.Success
2569             If Not AtList.Contains(m.Result("$2").ToLower) Then AtList.Add(m.Result("$2").ToLower)
2570             m = m.NextMatch
2571         End While
2572         '@先をリンクに置換
2573         retStr = Regex.Replace(retStr,
2574                                "(^|[^a-zA-Z0-9_/])([@@])([a-zA-Z0-9_]{1,20})",
2575                                "$1$2<a href=""/$3"">$3</a>")
2576
2577         'ハッシュタグを抽出し、リンクに置換
2578         Dim anchorRange As New List(Of range)
2579         For i As Integer = 0 To retStr.Length - 1
2580             Dim index As Integer = retStr.IndexOf("<a ", i)
2581             If index > -1 AndAlso index < retStr.Length Then
2582                 i = index
2583                 Dim toIndex As Integer = retStr.IndexOf("</a>", index)
2584                 If toIndex > -1 Then
2585                     anchorRange.Add(New range(index, toIndex + 3))
2586                     i = toIndex
2587                 End If
2588             End If
2589         Next
2590         retStr = Regex.Replace(retStr,
2591                                "(^|[^a-zA-Z0-9/&])([##])([0-9a-zA-Z_]*[a-zA-Z_]+[a-zA-Z0-9_\xc0-\xd6\xd8-\xf6\xf8-\xff]*)",
2592                                New MatchEvaluator(Function(mh As Match)
2593                                                       For Each rng As range In anchorRange
2594                                                           If mh.Index >= rng.fromIndex AndAlso
2595                                                            mh.Index <= rng.toIndex Then Return mh.Result("$0")
2596                                                       Next
2597                                                       If IsNumeric(mh.Result("$3")) Then Return mh.Result("$0")
2598                                                       SyncLock LockObj
2599                                                           _hashList.Add("#" + mh.Result("$3"))
2600                                                       End SyncLock
2601                                                       Return mh.Result("$1") + "<a href=""" & _protocol & "twitter.com/search?q=%23" + mh.Result("$3") + """>" + mh.Result("$2$3") + "</a>"
2602                                                   End Function),
2603                                               RegexOptions.IgnoreCase)
2604
2605
2606         retStr = Regex.Replace(retStr, "(^|[^a-zA-Z0-9_/&##@@>=.])(sm|nm)([0-9]{1,10})", "$1<a href=""http://www.nicovideo.jp/watch/$2$3"">$2$3</a>")
2607
2608         retStr = retStr.Replace("<<<<<tweenだいなり>>>>>", "&gt;").Replace("<<<<<tweenしょうなり>>>>>", "&lt;")
2609
2610         retStr = AdjustHtml(ShortUrl.Resolve(PreProcessUrl(retStr))) 'IDN置換、短縮Uri解決、@リンクを相対→絶対にしてtarget属性付与
2611         Return retStr
2612     End Function
2613
2614     'Source整形
2615     Private Sub CreateSource(ByRef post As PostClass)
2616         If post.Source.StartsWith("<") Then
2617             If Not post.Source.Contains("</a>") Then
2618                 post.Source += "</a>"
2619             End If
2620             Dim mS As Match = Regex.Match(post.Source, ">(?<source>.+)<")
2621             If mS.Success Then
2622                 post.SourceHtml = String.Copy(ShortUrl.Resolve(PreProcessUrl(post.Source)))
2623                 post.Source = HttpUtility.HtmlDecode(mS.Result("${source}"))
2624             Else
2625                 post.Source = ""
2626                 post.SourceHtml = ""
2627             End If
2628         Else
2629             If post.Source = "web" Then
2630                 post.SourceHtml = My.Resources.WebSourceString
2631             ElseIf post.Source = "Keitai Mail" Then
2632                 post.SourceHtml = My.Resources.KeitaiMailSourceString
2633             Else
2634                 post.SourceHtml = String.Copy(post.Source)
2635             End If
2636         End If
2637     End Sub
2638
2639     Public Function GetInfoApi(ByVal info As ApiInfo) As Boolean
2640         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return True
2641
2642         If _endingFlag Then Return True
2643
2644         Dim res As HttpStatusCode
2645         Dim content As String = ""
2646         Try
2647             res = twCon.RateLimitStatus(content)
2648         Catch ex As Exception
2649             TwitterApiInfo.Initialize()
2650             Return False
2651         End Try
2652
2653         If res <> HttpStatusCode.OK Then Return False
2654
2655         Try
2656             Dim limit = CreateDataFromJson(Of TwitterDataModel.RateLimitStatus)(content)
2657             Dim arg As New ApiInformationChangedEventArgs
2658             arg.ApiInfo.MaxCount = limit.HourlyLimit
2659             arg.ApiInfo.RemainCount = limit.RemainingHits
2660             arg.ApiInfo.ResetTime = DateTimeParse(limit.RestTime)
2661             arg.ApiInfo.ResetTimeInSeconds = limit.RestTimeInSeconds
2662             If info IsNot Nothing Then
2663                 arg.ApiInfo.UsingCount = info.UsingCount
2664
2665                 info.MaxCount = arg.ApiInfo.MaxCount
2666                 info.RemainCount = arg.ApiInfo.RemainCount
2667                 info.ResetTime = arg.ApiInfo.ResetTime
2668                 info.ResetTimeInSeconds = arg.ApiInfo.ResetTimeInSeconds
2669             End If
2670
2671             RaiseEvent ApiInformationChanged(Me, arg)
2672             TwitterApiInfo.WriteBackEventArgs(arg)
2673             Return True
2674         Catch ex As Exception
2675             TraceOut(content)
2676             TwitterApiInfo.Initialize()
2677             Return False
2678         End Try
2679     End Function
2680
2681     Public Function GetHashList() As String()
2682         Dim hashArray As String()
2683         SyncLock LockObj
2684             hashArray = _hashList.ToArray
2685             _hashList.Clear()
2686         End SyncLock
2687         Return hashArray
2688     End Function
2689
2690     Public ReadOnly Property AccessToken() As String
2691         Get
2692             Return twCon.AccessToken
2693         End Get
2694     End Property
2695
2696     Public ReadOnly Property AccessTokenSecret() As String
2697         Get
2698             Return twCon.AccessTokenSecret
2699         End Get
2700     End Property
2701
2702     Public Property UserIdNo As String
2703
2704     Public Event ApiInformationChanged(ByVal sender As Object, ByVal e As ApiInformationChangedEventArgs)
2705
2706     Private Sub Twitter_ApiInformationChanged(ByVal sender As Object, ByVal e As ApiInformationChangedEventArgs) Handles Me.ApiInformationChanged
2707     End Sub
2708
2709 #Region "UserStream"
2710     Public Property TrackWord As String = ""
2711     Public Property AllAtReply As Boolean = False
2712
2713     Public Event NewPostFromStream()
2714     Public Event UserStreamStarted()
2715     Public Event UserStreamStopped()
2716     Public Event UserStreamGetFriendsList()
2717     Public Event PostDeleted(ByVal id As Long, ByRef post As PostClass)
2718     Public Event UserStreamEventReceived(ByVal eventType As FormattedEvent)
2719     Private _lastUserstreamDataReceived As DateTime
2720     Private WithEvents userStream As TwitterUserstream
2721
2722     Public Class FormattedEvent
2723         Public Property Eventtype As EVENTTYPE
2724         Public Property CreatedAt As DateTime
2725         Public Property [Event] As String
2726         Public Property Username As String
2727         Public Property Target As String
2728         Public Property Id As Int64
2729         Public Property IsMe As Boolean
2730     End Class
2731
2732     Public Property StoredEvent As New List(Of FormattedEvent)
2733
2734     Private Class EventTypeTableElement
2735         Public Name As String
2736         Public Type As EVENTTYPE
2737
2738         Public Sub New(ByVal name As String, ByVal type As EVENTTYPE)
2739             Me.Name = name
2740             Me.Type = type
2741         End Sub
2742     End Class
2743
2744     Private EventTable As EventTypeTableElement() = {
2745         New EventTypeTableElement("favorite", EVENTTYPE.Favorite), _
2746         New EventTypeTableElement("unfavorite", EVENTTYPE.Unfavorite), _
2747         New EventTypeTableElement("follow", EVENTTYPE.Follow), _
2748         New EventTypeTableElement("list_member_added", EVENTTYPE.ListMemberAdded), _
2749         New EventTypeTableElement("list_member_removed", EVENTTYPE.ListMemberRemoved), _
2750         New EventTypeTableElement("block", EVENTTYPE.Block), _
2751         New EventTypeTableElement("unblock", EVENTTYPE.Unblock), _
2752         New EventTypeTableElement("user_update", EVENTTYPE.UserUpdate), _
2753         New EventTypeTableElement("deleted", EVENTTYPE.Deleted), _
2754         New EventTypeTableElement("list_created", EVENTTYPE.ListCreated)
2755     }
2756
2757     Public Function EventNameToEventType(ByVal EventName As String) As EVENTTYPE
2758         Return (From tbl In EventTable Where tbl.Name.Equals(EventName) Select tbl.Type).FirstOrDefault()
2759     End Function
2760
2761     Public ReadOnly Property IsUserstreamDataReceived As Boolean
2762         Get
2763             Return Now.Subtract(Me._lastUserstreamDataReceived).Seconds < 31
2764         End Get
2765     End Property
2766
2767     Private Sub userStream_StatusArrived(ByVal line As String) Handles userStream.StatusArrived
2768         Me._lastUserstreamDataReceived = Now
2769         If String.IsNullOrEmpty(line) Then Exit Sub
2770
2771         Dim isDm As Boolean = False
2772
2773         Try
2774             Using jsonReader As XmlDictionaryReader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(line), XmlDictionaryReaderQuotas.Max)
2775                 Dim xElm As XElement = XElement.Load(jsonReader)
2776                 If xElm.Element("friends") IsNot Nothing Then
2777                     Debug.Print("friends")
2778                     Exit Sub
2779                 ElseIf xElm.Element("delete") IsNot Nothing Then
2780                     Debug.Print("delete")
2781                     Dim post As PostClass = Nothing
2782                     Dim id As Int64
2783                     If xElm.Element("delete").Element("direct_message") IsNot Nothing AndAlso
2784                         xElm.Element("delete").Element("direct_message").Element("id") IsNot Nothing Then
2785                         id = CLng(xElm.Element("delete").Element("direct_message").Element("id").Value)
2786                         RaiseEvent PostDeleted(id, post)
2787                     ElseIf xElm.Element("delete").Element("status") IsNot Nothing AndAlso
2788                         xElm.Element("delete").Element("status").Element("id") IsNot Nothing Then
2789                         id = CLng(xElm.Element("delete").Element("status").Element("id").Value)
2790                         RaiseEvent PostDeleted(id, post)
2791                     Else
2792                         TraceOut("delete:" + line)
2793                         Exit Sub
2794                     End If
2795                     For i As Integer = Me.StoredEvent.Count - 1 To 0 Step -1
2796                         Dim sEvt As FormattedEvent = Me.StoredEvent(i)
2797                         If sEvt.Id = id AndAlso (sEvt.Event = "favorite" OrElse sEvt.Event = "unfavorite") Then
2798                             Me.StoredEvent.RemoveAt(i)
2799                         End If
2800                     Next
2801                     'CreateDeleteEvent(DateTime.Now, id, post)
2802                     Exit Sub
2803                 ElseIf xElm.Element("limit") IsNot Nothing Then
2804                     Debug.Print(line)
2805                     Exit Sub
2806                 ElseIf xElm.Element("event") IsNot Nothing Then
2807                     Debug.Print("event: " + xElm.Element("event").Value)
2808                     CreateEventFromJson(line)
2809                     Exit Sub
2810                 ElseIf xElm.Element("direct_message") IsNot Nothing Then
2811                     Debug.Print("direct_message")
2812                     isDm = True
2813                 ElseIf xElm.Element("scrub_geo") IsNot Nothing Then
2814                     Try
2815                         Debug.Print("scrub_geo: user_id=" + xElm.Element("user_id").Value.ToString + " up_to_status_id=" + xElm.Element("up_to_status_id").Value.ToString)
2816                     Catch ex As Exception
2817                         TraceOut("scrub_geo:" + line)
2818                     End Try
2819                     Exit Sub
2820                 End If
2821             End Using
2822
2823             Dim res As New StringBuilder
2824             res.Length = 0
2825             res.Append("[")
2826             res.Append(line)
2827             res.Append("]")
2828
2829             If isDm Then
2830                 CreateDirectMessagesFromJson(res.ToString, WORKERTYPE.UserStream, False)
2831             Else
2832                 CreatePostsFromJson(res.ToString, WORKERTYPE.Timeline, Nothing, False, Nothing, Nothing)
2833             End If
2834         Catch ex As NullReferenceException
2835             TraceOut("NullRef StatusArrived: " + line)
2836         End Try
2837
2838         RaiseEvent NewPostFromStream()
2839     End Sub
2840
2841     'Private Sub CreateDeleteEvent(ByVal createdat As DateTime, ByVal id As Int64, ByVal post As PostClass)
2842     '    Dim evt As New FormattedEvent
2843     '    evt.CreatedAt = createdat
2844     '    evt.Id = id
2845     '    evt.Eventtype = EventNameToEventType("deleted")
2846     '    If post Is Nothing Then
2847     '        Dim tmp As PostClass = (From p In _deletemessages Where p.Id = id).FirstOrDefault
2848     '        If tmp IsNot Nothing Then
2849     '            post = tmp
2850     '            _deletemessages.Remove(post)
2851     '        End If
2852     '    End If
2853     '    If post Is Nothing Then
2854     '        'evt.Event = "DELETE(UNKNOWN)"
2855     '        'evt.Username = "--UNKNOWN--"
2856     '        'evt.Target = "--UNKNOWN--"
2857     '        '保持していない発言に対しての削除イベントは無視
2858     '        Exit Sub
2859     '    Else
2860     '        If post.IsDm Then
2861     '            evt.Event = "DELETE(DM)"
2862     '        ElseIf post.RetweetedId > 0 Then
2863     '            evt.Event = "DELETE(RT)"
2864     '        Else
2865     '            evt.Event = "DELETE(Post)"
2866     '        End If
2867     '        evt.Username = post.ScreenName
2868     '        evt.Target = If(post.TextFromApi.Length > 10, post.TextFromApi.Substring(0, 10) + "...", post.TextFromApi) + " [" + post.CreatedAt.ToString + "]"
2869     '    End If
2870     '    For i As Integer = Me.StoredEvent.Count - 1 To 0 Step -1
2871     '        Dim sEvt As FormattedEvent = Me.StoredEvent(i)
2872     '        If sEvt.Id = id AndAlso (sEvt.Event = "favorite" OrElse sEvt.Event = "unfavorite") Then
2873     '            Me.StoredEvent.RemoveAt(i)
2874     '        End If
2875     '    Next
2876     '    'Me.StoredEvent.Insert(0, evt)
2877     '    RaiseEvent UserStreamEventReceived(evt)
2878     'End Sub
2879
2880     Private Sub CreateEventFromJson(ByVal content As String)
2881         Dim eventData As TwitterDataModel.EventData = Nothing
2882         Try
2883             eventData = CreateDataFromJson(Of TwitterDataModel.EventData)(content)
2884         Catch ex As SerializationException
2885             TraceOut(ex, "Event Serialize Exception!" + Environment.NewLine + content)
2886         Catch ex As Exception
2887             TraceOut(ex, "Event Exception!" + Environment.NewLine + content)
2888         End Try
2889
2890         Dim evt As New FormattedEvent
2891         evt.CreatedAt = DateTimeParse(eventData.CreatedAt)
2892         evt.Event = eventData.Event
2893         evt.Username = eventData.Source.ScreenName
2894         evt.IsMe = evt.Username.ToLower().Equals(Me.Username.ToLower())
2895         evt.Eventtype = EventNameToEventType(evt.Event)
2896         Select Case eventData.Event
2897             Case "follow"
2898                 If eventData.Target.ScreenName.ToLower.Equals(_uid) Then
2899                     If Not Me.followerId.Contains(eventData.Source.Id) Then Me.followerId.Add(eventData.Source.Id)
2900                 Else
2901                     Exit Sub    'Block後のUndoをすると、SourceとTargetが逆転したfollowイベントが帰ってくるため。
2902                 End If
2903                 evt.Target = ""
2904             Case "favorite", "unfavorite"
2905                 evt.Target = "@" + eventData.TargetObject.User.ScreenName + ":" + HttpUtility.HtmlDecode(eventData.TargetObject.Text)
2906                 evt.Id = eventData.TargetObject.Id
2907                 If TabInformations.GetInstance.ContainsKey(eventData.TargetObject.Id) Then
2908                     Dim post As PostClass = TabInformations.GetInstance.Item(eventData.TargetObject.Id)
2909                     If eventData.Event = "favorite" Then
2910                         If evt.Username.ToLower.Equals(_uid) Then
2911                             post.IsFav = True
2912                             TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Add(post.StatusId, post.IsRead, False)
2913                         Else
2914                             post.FavoritedCount += 1
2915                             If Not TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Contains(post.StatusId) Then
2916                                 If TweenMain.GetInstance().FavEventChangeUnread AndAlso post.IsRead Then
2917                                     post.IsRead = False
2918                                 End If
2919                                 TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Add(post.StatusId, post.IsRead, False)
2920                             Else
2921                                 If TweenMain.GetInstance().FavEventChangeUnread Then
2922                                     TabInformations.GetInstance.SetRead(False, TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).TabName, TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).IndexOf(post.StatusId))
2923                                 End If
2924                             End If
2925                         End If
2926                     Else
2927                         If evt.Username.ToLower.Equals(_uid) Then
2928                             post.IsFav = False
2929                         Else
2930                             post.FavoritedCount -= 1
2931                             If post.FavoritedCount < 0 Then post.FavoritedCount = 0
2932                         End If
2933                     End If
2934                 End If
2935             Case "list_member_added", "list_member_removed"
2936                 evt.Target = eventData.TargetObject.FullName
2937             Case "block"
2938                 evt.Target = ""
2939             Case "unblock"
2940                 evt.Target = ""
2941             Case "user_update"
2942                 evt.Target = ""
2943             Case "list_created"
2944                 evt.Target = ""
2945             Case Else
2946                 TraceOut("Unknown Event:" + evt.Event + Environment.NewLine + content)
2947         End Select
2948         Me.StoredEvent.Insert(0, evt)
2949         RaiseEvent UserStreamEventReceived(evt)
2950     End Sub
2951
2952     Private Sub userStream_Started() Handles userStream.Started
2953         RaiseEvent UserStreamStarted()
2954     End Sub
2955
2956     Private Sub userStream_Stopped() Handles userStream.Stopped
2957         RaiseEvent UserStreamStopped()
2958     End Sub
2959
2960     Public ReadOnly Property UserStreamEnabled As Boolean
2961         Get
2962             Return If(userStream Is Nothing, False, userStream.Enabled)
2963         End Get
2964     End Property
2965
2966     Public Sub StartUserStream()
2967         If userStream IsNot Nothing Then
2968             StopUserStream()
2969         End If
2970         userStream = New TwitterUserstream(twCon)
2971         userStream.Start(Me.AllAtReply, Me.TrackWord)
2972     End Sub
2973
2974     Public Sub StopUserStream()
2975         If userStream IsNot Nothing Then userStream.Dispose()
2976         userStream = Nothing
2977         If Not _endingFlag Then RaiseEvent UserStreamStopped()
2978     End Sub
2979
2980     Public Sub ReconnectUserStream()
2981         If userStream IsNot Nothing Then
2982             Me.StartUserStream()
2983         End If
2984     End Sub
2985
2986     Private Class TwitterUserstream
2987         Implements IDisposable
2988
2989         Public Event StatusArrived(ByVal status As String)
2990         Public Event Stopped()
2991         Public Event Started()
2992         Private twCon As HttpTwitter
2993
2994         Private _streamThread As Thread
2995         Private _streamActive As Boolean
2996
2997         Private _allAtreplies As Boolean = False
2998         Private _trackwords As String = ""
2999
3000         Public Sub New(ByVal twitterConnection As HttpTwitter)
3001             twCon = DirectCast(twitterConnection.Clone(), HttpTwitter)
3002         End Sub
3003
3004         Public Sub Start(ByVal allAtReplies As Boolean, ByVal trackwords As String)
3005             Me.AllAtReplies = allAtReplies
3006             Me.TrackWords = trackwords
3007             _streamActive = True
3008             If _streamThread IsNot Nothing AndAlso _streamThread.IsAlive Then Exit Sub
3009             _streamThread = New Thread(AddressOf UserStreamLoop)
3010             _streamThread.Name = "UserStreamReceiver"
3011             _streamThread.IsBackground = True
3012             _streamThread.Start()
3013         End Sub
3014
3015         Public ReadOnly Property Enabled() As Boolean
3016             Get
3017                 Return _streamActive
3018             End Get
3019         End Property
3020
3021         Public Property AllAtReplies As Boolean
3022             Get
3023                 Return _allAtreplies
3024             End Get
3025             Set(ByVal value As Boolean)
3026                 _allAtreplies = value
3027             End Set
3028         End Property
3029
3030         Public Property TrackWords As String
3031             Get
3032                 Return _trackwords
3033             End Get
3034             Set(ByVal value As String)
3035                 _trackwords = value
3036             End Set
3037         End Property
3038
3039         Private Sub UserStreamLoop()
3040             Dim st As Stream = Nothing
3041             Dim sr As StreamReader = Nothing
3042             Do
3043                 Try
3044                     If Not NetworkInterface.GetIsNetworkAvailable Then
3045                         Thread.Sleep(30 * 1000)
3046                         Continue Do
3047                     End If
3048
3049                     RaiseEvent Started()
3050
3051                     twCon.UserStream(st, _allAtreplies, _trackwords, My.Application.Info.ProductName + " v" + fileVersion)
3052                     sr = New StreamReader(st)
3053
3054                     Do While _streamActive AndAlso Not sr.EndOfStream
3055                         RaiseEvent StatusArrived(sr.ReadLine())
3056                         'Me.LastTime = Now
3057                     Loop
3058
3059                     If sr.EndOfStream Then
3060                         RaiseEvent Stopped()
3061                         'TraceOut("Stop:EndOfStream")
3062                         Thread.Sleep(10 * 1000)
3063                         Continue Do
3064                     End If
3065                     Exit Do
3066                 Catch ex As WebException
3067                     If Not Me._streamActive Then
3068                         Exit Do
3069                     ElseIf ex.Status = WebExceptionStatus.Timeout Then
3070                         RaiseEvent Stopped()
3071                         'TraceOut("Stop:Timeout")
3072                         Thread.Sleep(10 * 1000)
3073                     ElseIf ex.Response IsNot Nothing AndAlso CType(ex.Response, HttpWebResponse).StatusCode = 420 Then
3074                         'TraceOut("Stop:Connection Limit")
3075                         Exit Do
3076                     Else
3077                         RaiseEvent Stopped()
3078                         'TraceOut("Stop:WebException " & ex.Status.ToString)
3079                         Thread.Sleep(10 * 1000)
3080                     End If
3081                 Catch ex As ThreadAbortException
3082                     Exit Do
3083                 Catch ex As IOException
3084                     If Not Me._streamActive Then
3085                         Exit Do
3086                     Else
3087                         RaiseEvent Stopped()
3088                         'TraceOut("Stop:IOException with Active." + Environment.NewLine + ex.Message)
3089                         Thread.Sleep(10 * 1000)
3090                     End If
3091                 Catch ex As ArgumentException
3092                     'System.ArgumentException: ストリームを読み取れませんでした。
3093                     'サーバー側もしくは通信経路上で切断された場合?タイムアウト頻発後発生
3094                     RaiseEvent Stopped()
3095                     TraceOut(ex, "Stop:ArgumentException")
3096                     Thread.Sleep(10 * 1000)
3097                 Catch ex As Exception
3098                     TraceOut("Stop:Exception." + Environment.NewLine + ex.Message)
3099                     ExceptionOut(ex)
3100                 Finally
3101                     If sr IsNot Nothing Then
3102                         twCon.RequestAbort()
3103                         sr.BaseStream.Close()
3104                     End If
3105                 End Try
3106             Loop While True
3107
3108             If _streamActive Then RaiseEvent Stopped()
3109             TraceOut("Stop:EndLoop")
3110         End Sub
3111
3112 #Region "IDisposable Support"
3113         Private disposedValue As Boolean ' 重複する呼び出しを検出するには
3114
3115         ' IDisposable
3116         Protected Overridable Sub Dispose(ByVal disposing As Boolean)
3117             If Not Me.disposedValue Then
3118                 If disposing Then
3119                     ' TODO: マネージ状態を破棄します (マネージ オブジェクト)。
3120                     _streamActive = False
3121                     If _streamThread IsNot Nothing AndAlso _streamThread.IsAlive Then
3122                         _streamThread.Abort()
3123                         _streamThread.Join(1000)
3124                     End If
3125                 End If
3126
3127                 ' TODO: アンマネージ リソース (アンマネージ オブジェクト) を解放し、下の Finalize() をオーバーライドします。
3128                 ' TODO: 大きなフィールドを null に設定します。
3129             End If
3130             Me.disposedValue = True
3131         End Sub
3132
3133         ' TODO: 上の Dispose(ByVal disposing As Boolean) にアンマネージ リソースを解放するコードがある場合にのみ、Finalize() をオーバーライドします。
3134         'Protected Overrides Sub Finalize()
3135         '    ' このコードを変更しないでください。クリーンアップ コードを上の Dispose(ByVal disposing As Boolean) に記述します。
3136         '    Dispose(False)
3137         '    MyBase.Finalize()
3138         'End Sub
3139
3140         ' このコードは、破棄可能なパターンを正しく実装できるように Visual Basic によって追加されました。
3141         Public Sub Dispose() Implements IDisposable.Dispose
3142             ' このコードを変更しないでください。クリーンアップ コードを上の Dispose(ByVal disposing As Boolean) に記述します。
3143             Dispose(True)
3144             GC.SuppressFinalize(Me)
3145         End Sub
3146 #End Region
3147
3148     End Class
3149 #End Region
3150
3151 #Region "IDisposable Support"
3152     Private disposedValue As Boolean ' 重複する呼び出しを検出するには
3153
3154     ' IDisposable
3155     Protected Overridable Sub Dispose(ByVal disposing As Boolean)
3156         If Not Me.disposedValue Then
3157             If disposing Then
3158                 ' TODO: マネージ状態を破棄します (マネージ オブジェクト)。
3159                 Me.StopUserStream()
3160             End If
3161
3162             ' TODO: アンマネージ リソース (アンマネージ オブジェクト) を解放し、下の Finalize() をオーバーライドします。
3163             ' TODO: 大きなフィールドを null に設定します。
3164         End If
3165         Me.disposedValue = True
3166     End Sub
3167
3168     ' TODO: 上の Dispose(ByVal disposing As Boolean) にアンマネージ リソースを解放するコードがある場合にのみ、Finalize() をオーバーライドします。
3169     'Protected Overrides Sub Finalize()
3170     '    ' このコードを変更しないでください。クリーンアップ コードを上の Dispose(ByVal disposing As Boolean) に記述します。
3171     '    Dispose(False)
3172     '    MyBase.Finalize()
3173     'End Sub
3174
3175     ' このコードは、破棄可能なパターンを正しく実装できるように Visual Basic によって追加されました。
3176     Public Sub Dispose() Implements IDisposable.Dispose
3177         ' このコードを変更しないでください。クリーンアップ コードを上の Dispose(ByVal disposing As Boolean) に記述します。
3178         Dispose(True)
3179         GC.SuppressFinalize(Me)
3180     End Sub
3181 #End Region
3182
3183 End Class