OSDN Git Service

HttpConnectionでcontentlengthが不正な場合があるので参照しないように変更。
[opentween/open-tween.git] / Tween / Twitter.vb
1 ' Tween - Client of Twitter
2 ' Copyright (c) 2007-2010 kiri_feather (@kiri_feather) <kiri_feather@gmail.com>
3 '           (c) 2008-2010 Moz (@syo68k) <http://iddy.jp/profile/moz/>
4 '           (c) 2008-2010 takeshik (@takeshik) <http://www.takeshik.org/>
5 ' All rights reserved.
6
7 ' This file is part of Tween.
8
9 ' This program is free software; you can redistribute it and/or modify it
10 ' under the terms of the GNU General Public License as published by the Free
11 ' Software Foundation; either version 3 of the License, or (at your option)
12 ' any later version.
13
14 ' This program is distributed in the hope that it will be useful, but
15 ' WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 ' or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 ' for more details. 
18
19 ' You should have received a copy of the GNU General Public License along
20 ' with this program. If not, see <http://www.gnu.org/licenses/>, or write to
21 ' the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
22 ' Boston, MA 02110-1301, USA.
23
24 Imports System.Web
25 Imports System.Xml
26 Imports System.Text
27 Imports System.Threading
28 Imports System.IO
29 Imports System.Text.RegularExpressions
30 Imports System.Globalization
31 Imports System.Diagnostics
32 Imports System.Net
33
34 Public Class Twitter
35     Delegate Sub GetIconImageDelegate(ByVal post As PostClass)
36     'Delegate Function GetTimelineDelegate(ByVal page As Integer, _
37     '                            ByVal read As Boolean, _
38     '                            ByRef endPage As Integer, _
39     '                            ByVal gType As WORKERTYPE, _
40     '                            ByRef getDM As Boolean) As String
41     'Delegate Function GetDirectMessageDelegate(ByVal page As Integer, _
42     '                                ByVal read As Boolean, _
43     '                                ByVal endPage As Integer, _
44     '                                ByVal gType As WORKERTYPE) As String
45     Private ReadOnly LockObj As New Object
46     'Private GetTmSemaphore As New Threading.Semaphore(8, 8)
47
48     'Private follower As New List(Of String)
49     Private followerId As New List(Of Long)
50     'Private tmpFollower As New List(Of String)
51
52     Private _followersCount As Integer = 0
53     Private _friendsCount As Integer = 0
54     Private _statusesCount As Integer = 0
55     Private _location As String = ""
56     Private _bio As String = ""
57     'Private _useSsl As Boolean = True
58     Private _protocol As String = "https://"
59     Private _bitlyId As String = ""
60     Private _bitlyKey As String = ""
61
62     'プロパティからアクセスされる共通情報
63     Private _uid As String
64     'Private _pwd As String
65     'Private _proxyType As ProxyType
66     'Private _proxyAddress As String
67     'Private _proxyPort As Integer
68     'Private _proxyUser As String
69     'Private _proxyPassword As String
70
71     'Private _nextThreshold As Integer
72     'Private _nextPages As Integer
73
74     Private _iconSz As Integer
75     Private _getIcon As Boolean
76     Private _lIcon As ImageList
77     Private _dIcon As Dictionary(Of String, Image)
78
79     Private _tinyUrlResolve As Boolean
80     Private _restrictFavCheck As Boolean
81     'Private _useAPI As Boolean
82
83     Private _hubServer As String
84     'Private _defaultTimeOut As Integer      ' MySocketクラスへ渡すタイムアウト待ち時間(秒単位 ミリ秒への換算はMySocketクラス側で行う)
85     Private _countApi As Integer
86     Private _countApiReply As Integer
87     'Private _usePostMethod As Boolean
88     'Private _ApiMethod As MySocket.REQ_TYPE
89     Private _readOwnPost As Boolean
90     Private _hashList As New List(Of String)
91
92     '共通で使用する状態
93     'Private _authKey As String              'StatusUpdate、発言削除で使用
94     'Private _authKeyDM As String              'DM送信、DM削除で使用
95     Private _infoTwitter As String = ""
96     'Private _dmCount As Integer
97     'Private _getDm As Boolean
98     Private _remainCountApi As Integer = -1
99
100     Private _ShortUrlService() As String = { _
101             "http://tinyurl.com/", _
102             "http://is.gd/", _
103             "http://snipurl.com/", _
104             "http://snurl.com/", _
105             "http://nsfw.in/", _
106             "http://qurlyq.com/", _
107             "http://dwarfurl.com/", _
108             "http://icanhaz.com/", _
109             "http://tiny.cc/", _
110             "http://urlenco.de/", _
111             "http://bit.ly/", _
112             "http://piurl.com/", _
113             "http://linkbee.com/", _
114             "http://traceurl.com/", _
115             "http://twurl.nl/", _
116             "http://cli.gs/", _
117             "http://rubyurl.com/", _
118             "http://budurl.com/", _
119             "http://ff.im/", _
120             "http://twitthis.com/", _
121             "http://blip.fm/", _
122             "http://tumblr.com/", _
123             "http://www.qurl.com/", _
124             "http://digg.com/", _
125             "http://u.nu/", _
126             "http://ustre.am/", _
127             "http://pic.gd/", _
128             "http://airme.us/", _
129             "http://qurl.com/", _
130             "http://bctiny.com/", _
131             "http://j.mp/", _
132             "http://goo.gl/", _
133             "http://ow.ly/", _
134             "http://bkite.com/" _
135         }
136
137     Private Const _apiHost As String = "api."
138     Private Const _baseUrlStr As String = "twitter.com"
139     'Private Const _loginPath As String = "/sessions"
140     'Private Const _homePath As String = "/home"
141     'Private Const _replyPath As String = "/replies"
142     'Private Const _DMPathRcv As String = "/inbox"
143     'Private Const _DMPathSnt As String = "/sent"
144     Private Const _DMDestroyPath As String = "/1/direct_messages/destroy/"
145     Private Const _StDestroyPath As String = "/1/statuses/destroy/"
146     Private Const _postRetweetPath As String = "/1/statuses/retweet/"
147     Private Const _uidHeader As String = "session[username_or_email]="
148     Private Const _pwdHeader As String = "session[password]="
149     Private Const _pageQry As String = "?page="
150     Private Const _cursorQry As String = "?cursor="
151     Private Const _statusHeader As String = "status="
152     Private Const _statusUpdatePathAPI As String = "/1/statuses/update.xml"
153     'Private Const _linkToOld As String = "class=""section_links"" rel=""prev"""
154     Private Const _postFavAddPath As String = "/1/favorites/create/"
155     Private Const _postFavRemovePath As String = "/1/favorites/destroy/"
156     'Private Const _authKeyHeader As String = "authenticity_token="
157     'Private Const _parseLink1 As String = "<a href="""
158     'Private Const _parseLink2 As String = """>"
159     'Private Const _parseLink3 As String = "</a>"
160     Private Const _GetFollowers As String = "/1/statuses/followers.xml"
161     Private Const _ShowStatus As String = "/1/statuses/show/"
162     Private Const _rateLimitStatus As String = "/1/account/rate_limit_status.xml"
163     Private Const FOLLOWER_PATH As String = "/1/followers/ids.xml"
164     Private Const RECEIVE_PATH As String = "/1/direct_messages.xml"
165     Private Const SENT_PATH As String = "/1/direct_messages/sent.xml"
166     Private Const COUNT_QUERY As String = "count="
167     Private Const FAV_PATH As String = "/1/favorites.xml"
168     Private Const PATH_FRIENDSHIP As String = "/1/friendships/show.xml?source_screen_name="
169     Private Const QUERY_TARGET As String = "&target_screen_name="
170     Private Const FRIEND_PATH As String = "/1/statuses/home_timeline.xml"
171     Private Const REPLY_PATH As String = "/1/statuses/mentions.xml"
172     Private Const PATH_FOLLOW As String = "/1/friendships/create.xml?screen_name="
173     Private Const PATH_REMOVE As String = "/1/friendships/destroy.xml?screen_name="
174
175
176
177     '''<summary>
178     '''OAuthのアクセストークン取得先URI
179     '''</summary>
180     Private Const AccessTokenUrl As String = "http://twitter.com/oauth/access_token"
181
182     '''<summary>
183     '''OAuthのリクエストトークン取得先URI
184     '''</summary>
185     Private Const RequestTokenUrl As String = "http://twitter.com/oauth/request_token"
186
187     '''<summary>
188     '''OAuthのユーザー認証用ページURI
189     '''</summary>
190     '''<remarks>
191     '''クエリ「oauth_token=リクエストトークン」を付加して、このURIをブラウザで開く。ユーザーが承認操作を行うとPINコードが表示される。
192     '''</remarks>
193     Private Const AuthorizeUrl As String = "http://twitter.com/oauth/authorize"
194
195     ''''Wedata対応
196     'Private Const wedataUrl As String = "http://wedata.net/databases/Tween/items.json"
197
198     Private op As New Outputz
199     'max_idで古い発言を取得するために保持(lists分は個別タブで管理)
200     Private minHomeTimeline As Long = Long.MaxValue
201     Private minMentions As Long = Long.MaxValue
202     Private minDirectmessage As Long = Long.MaxValue
203     Private minDirectmessageSent As Long = Long.MaxValue
204     Private minFavorites As Long = Long.MaxValue
205
206     Private twCon As New HttpTwitter
207
208     Public Function Authenticate(ByVal username As String, ByVal password As String) As Boolean
209         Dim rslt As Boolean = twCon.AuthUserAndPass(username, password)
210         If rslt Then
211             _uid = twCon.AuthenticatedUsername.ToLower
212         End If
213         Return rslt
214     End Function
215
216     Public Sub ClearAuthInfo()
217         twCon.ClearAuthInfo()
218     End Sub
219
220     Public Sub Initialize(ByVal token As String, ByVal tokenSecret As String, ByVal username As String)
221         'xAuth認証
222         twCon.Initialize(token, tokenSecret, username)
223         _uid = username.ToLower
224     End Sub
225
226     Public Sub Initialize(ByVal username As String, ByVal password As String)
227         'BASIC認証
228         twCon.Initialize(username, password)
229         _uid = username.ToLower
230     End Sub
231
232     'Private Function SignIn() As String
233     '    If _endingFlag Then Return ""
234
235     '    'ユーザー情報からデータ部分の生成
236     '    Dim account As String = ""
237     '    Static skipCount As Integer = 0
238
239     '    SyncLock LockObj
240     '        If _signed Then Return ""
241     '        If Twitter.AccountState <> ACCOUNT_STATE.Valid AndAlso skipCount < 10 Then
242     '            skipCount += 1
243     '            Return "SignIn -> Check Username/Password in setting."
244     '        End If
245     '        skipCount = 0
246
247     '        '未認証
248     '        _signed = False
249
250     '        MySocket.ResetCookie()
251
252     '        Dim resStatus As String = ""
253     '        Dim resMsg As String = ""
254
255     '        '設定によらずログイン処理はhttps固定
256     '        resMsg = DirectCast(CreateSocket.GetWebResponse("https://" + _hubServer + "/login", resStatus, MySocket.REQ_TYPE.ReqGET), String)
257     '        If resMsg.Length = 0 Then
258     '            'Twitter.AccountState = ACCOUNT_STATE.Invalid
259     '            Return "SignIn -> " + resStatus
260     '        End If
261     '        Dim authToken As String = ""
262     '        Dim rg As New Regex("authenticity_token"" type=""hidden"" value=""(?<auth>[a-z0-9]+)""")
263     '        Dim m As Match = rg.Match(resMsg)
264     '        If m.Success Then
265     '            authToken = m.Result("${auth}")
266     '        Else
267     '            Return "SignIn -> Can't get token."
268     '        End If
269
270     '        account = _authKeyHeader + authToken + "&" + _uidHeader + _uid + "&" + _pwdHeader + HttpUtility.UrlEncode(_pwd) + "&" + "remember_me=1"
271
272     '        'https固定
273     '        resMsg = DirectCast(CreateSocket.GetWebResponse("https://" + _hubServer + _loginPath, resStatus, MySocket.REQ_TYPE.ReqPOST, account), String)
274     '        If resStatus.StartsWith("OK") Then
275     '            'OK (username/passwordが合致しない)
276     '            Dim msg As String = resStatus
277     '            If resMsg.Contains("Wrong Username/Email and password combination.") Then
278     '                msg = "Wrong Username or password."
279     '            Else
280     '                '未知の応答(May be required Chapta)
281     '                msg = "Wrong Username or password. Try from web."
282     '            End If
283     '            Twitter.AccountState = ACCOUNT_STATE.Invalid
284     '            Return "SignIn Failed -> " + msg
285     '        ElseIf resMsg.Contains("https://twitter.com/account/locked") Then   '302 FOUND
286     '            Dim msg As String = "You account is Locked Out."
287     '            Twitter.AccountState = ACCOUNT_STATE.Invalid
288     '            Return "SignIn Failed -> " + msg
289     '        ElseIf resMsg.Contains("https://twitter.com:443/") Then '302 FOUND
290     '            'OK
291     '        ElseIf resMsg.Contains("https://twitter.com/") OrElse _
292     '               resMsg.Contains("http://twitter.com/") Then '302 FOUND
293     '            'OK
294     '        ElseIf resStatus.StartsWith("Err:") Then
295     '            ' その他プロトコルエラー
296     '            Return "SignIn Failed"
297     '        Else
298     '            '応答がOK でありサインインできていない場合の未知の応答
299     '            'TraceOut(True, "SignIn Failed." + vbCrLf + "resStatus:" + resStatus + vbCrLf + "resMsg:" + vbCrLf + resMsg)
300     '            Twitter.AccountState = ACCOUNT_STATE.Invalid
301     '            Return "SignIn Failed -> " + "Unknown problems."
302     '        End If
303     '        Twitter.AccountState = ACCOUNT_STATE.Valid
304     '        _signed = True
305     '        Return ""
306     '    End SyncLock
307     'End Function
308
309     'Public Function GetTimeline(ByVal page As Integer, _
310     '                            ByVal read As Boolean, _
311     '                            ByRef endPage As Integer, _
312     '                            ByVal gType As WORKERTYPE, _
313     '                            ByRef getDM As Boolean) As String
314
315     '    If endPage = 0 Then
316     '        '通常モード
317     '        Dim epage As Integer = page
318     '        GetTmSemaphore.WaitOne()
319     '        Dim trslt As String = ""
320     '        trslt = GetTimelineThread(page, read, epage, gType, getDM)
321     '        If trslt.Length > 0 Then Return trslt
322     '        page += 1
323     '        If epage < page OrElse gType = WORKERTYPE.Reply Then Return ""
324     '        endPage = epage
325     '    End If
326     '    '起動時モード or 通常モードの読み込み継続 -> 複数ページ同時取得
327     '    Dim num As Integer = endPage - page
328     '    Dim ar(num) As IAsyncResult
329     '    Dim dlgt(num) As GetTimelineDelegate
330
331     '    For idx As Integer = 0 To num
332     '        dlgt(idx) = New GetTimelineDelegate(AddressOf GetTimelineThread)
333     '        GetTmSemaphore.WaitOne()
334     '        ar(idx) = dlgt(idx).BeginInvoke(page + idx, read, endPage + idx, gType, getDM, Nothing, Nothing)
335     '    Next
336     '    Dim rslt As String = ""
337     '    For idx As Integer = 0 To num
338     '        Dim epage As Integer = 0
339     '        Dim dm As Boolean = False
340     '        Dim trslt As String = ""
341     '        Try
342     '            trslt = dlgt(idx).EndInvoke(epage, dm, ar(idx))
343     '        Catch ex As Exception
344     '            '最後までendinvoke回す(ゾンビ化回避)
345     '            ex.Data("IsTerminatePermission") = False
346     '            Throw
347     '            rslt = "GetTimelineErr"
348     '        End Try
349     '        If trslt.Length > 0 AndAlso rslt.Length = 0 Then rslt = trslt
350     '        If dm Then getDM = True
351     '    Next
352     '    Return rslt
353     'End Function
354
355     '    Private Function GetTimelineThread(ByVal page As Integer, _
356     '                                ByVal read As Boolean, _
357     '                                ByRef endPage As Integer, _
358     '                                ByVal gType As WORKERTYPE, _
359     '                                ByRef getDM As Boolean) As String
360     '        Try
361     '            If _endingFlag Then Return ""
362
363     '            Dim retMsg As String = ""
364     '            Dim resStatus As String = ""
365
366     '            Static redirectToTimeline As String = ""
367     '            Static redirectToReply As String = ""
368
369     '            If _signed = False Then
370     '                retMsg = SignIn()
371     '                If retMsg.Length > 0 Then
372     '                    Return retMsg
373     '                End If
374     '            End If
375
376     '            If _endingFlag Then Return ""
377
378     '            'リクエストメッセージを作成する
379     '            Dim pageQuery As String
380
381     '            If page = 1 Then
382     '                pageQuery = ""
383     '            Else
384     '                pageQuery = _pageQry + page.ToString
385     '            End If
386
387     '            If gType = WORKERTYPE.Timeline Then
388     '                retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _homePath + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
389     '            Else
390     '                retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _replyPath + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
391     '            End If
392
393     '            If retMsg.Length = 0 Then
394     '                _signed = False
395     '                Return resStatus
396     '            End If
397
398     '            ' tr 要素の class 属性を消去
399     '            retMsg = Regex.Replace(retMsg, "(?<tagStart><li)(?<cls>\s+class=""[^""]+""\s+)", "${tagStart} ")
400     '            'Do
401     '            '    Try
402     '            '        Dim idx As Integer = retMsg.IndexOf(_removeClass, StringComparison.Ordinal)
403     '            '        If idx = -1 Then Exit Do
404     '            '        Dim idx2 As Integer = retMsg.IndexOf("""", idx + _removeClass.Length, StringComparison.Ordinal) - idx + 1 - 3
405     '            '        If idx2 > 0 Then retMsg = retMsg.Remove(idx + 3, idx2)
406     '            '    Catch ex As Exception
407     '            '        _signed = False
408     '            '        TraceOut("TM-Remove: " + retMsg)
409     '            '        Return "GetTimeline -> Err: Can't parse data."
410     '            '    End Try
411     '            'Loop
412
413     '            If _endingFlag Then Return ""
414
415     '            '各メッセージに分割可能か?
416     '            Dim strSepTmp As String
417     '            If gType = WORKERTYPE.Timeline Then
418     '                strSepTmp = _splitPostRecent
419     '            Else
420     '                strSepTmp = _splitPost
421     '            End If
422
423     '            Dim pos1 As Integer
424     '            Dim pos2 As Integer
425
426     '            pos1 = retMsg.IndexOf(strSepTmp, StringComparison.Ordinal)
427     '            If pos1 = -1 Then
428     '                '0件 or 取得失敗
429     '                _signed = False
430     '                Return "GetTimeline -> Err: tweets count is 0."
431     '            End If
432
433     '            Dim strSep() As String = {strSepTmp}
434     '            Dim posts() As String = retMsg.Split(strSep, StringSplitOptions.RemoveEmptyEntries)
435     '            Dim intCnt As Integer = 0
436     '            Dim listCnt As Integer = 0
437     '            SyncLock LockObj
438     '                listCnt = TabInformations.GetInstance.ItemCount
439     '            End SyncLock
440     '            Dim dlgt(20) As GetIconImageDelegate
441     '            Dim ar(20) As IAsyncResult
442     '            Dim arIdx As Integer = -1
443     '            Dim rg As Regex
444     '            Dim m As Match
445
446     '            For Each strPost As String In posts
447     '                intCnt += 1
448
449     '                If intCnt = 1 Then
450     '                    If page = 1 And gType = WORKERTYPE.Timeline Then
451     '                        ''siv取得
452     '                        'pos1 = strPost.IndexOf(_getSiv, 0)
453     '                        'If pos1 > 0 Then
454     '                        '    pos2 = strPost.IndexOf(_getSivTo, pos1 + _getSiv.Length)
455     '                        '    If pos2 > -1 Then
456     '                        '        _authSiv = strPost.Substring(pos1 + _getSiv.Length, pos2 - pos1 - _getSiv.Length)
457     '                        '    Else
458     '                        '        '取得失敗
459     '                        '        _signed = False
460     '                        '        Return "GetTimeline -> Err: Can't get Siv."
461     '                        '    End If
462     '                        'Else
463     '                        '    '取得失敗
464     '                        '    _signed = False
465     '                        '    Return "GetTimeline -> Err: Can't get Siv."
466     '                        'End If
467
468     '                        'AuthKeyの取得
469     '                        If GetAuthKey(retMsg) < 0 Then
470     '                            _signed = False
471     '                            Return "GetTimeline -> Err: Can't get auth token."
472     '                        End If
473
474     '                        'TwitterInfoの取得
475     '                        pos1 = retMsg.IndexOf(_getInfoTwitter, StringComparison.Ordinal)
476     '                        If pos1 > -1 Then
477     '                            pos2 = retMsg.IndexOf(_getInfoTwitterTo, pos1, StringComparison.Ordinal)
478     '                            If pos2 > -1 Then
479     '                                _infoTwitter = retMsg.Substring(pos1 + _getInfoTwitter.Length, pos2 - pos1 - _getInfoTwitter.Length)
480     '                            Else
481     '                                _infoTwitter = ""
482     '                            End If
483     '                        Else
484     '                            _infoTwitter = ""
485     '                        End If
486     '                    End If
487     '                Else
488
489     '                    Dim post As New PostClass
490
491     '                    pos1 = strPost.IndexOf("</ol>")
492     '                    If pos1 > -1 Then
493     '                        strPost = strPost.Substring(0, pos1)
494     '                    End If
495
496     '                    Try
497     '                        'Get ID
498     '                        pos1 = 0
499     '                        pos2 = strPost.IndexOf(_statusIdTo, 0, StringComparison.Ordinal)
500     '                        post.Id = Long.Parse(HttpUtility.HtmlDecode(strPost.Substring(0, pos2)))
501     '                    Catch ex As Exception
502     '                        _signed = False
503     '                        TraceOut("TM-ID:" + strPost)
504     '                        Return "GetTimeline -> Err: Can't get ID."
505     '                    End Try
506     '                    'Get Name
507     '                    Try
508     '                        pos1 = strPost.IndexOf(_parseName, pos2, StringComparison.Ordinal)
509     '                        pos2 = strPost.IndexOf(_parseNameTo, pos1, StringComparison.Ordinal)
510     '                        post.Name = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseName.Length, pos2 - pos1 - _parseName.Length))
511     '                    Catch ex As Exception
512     '                        _signed = False
513     '                        TraceOut("TM-Name:" + strPost)
514     '                        Return "GetTimeline -> Err: Can't get Name."
515     '                    End Try
516     '                    'Get Nick
517     '                    '''バレンタイン対応
518     '                    If strPost.IndexOf("twitter.com/images/heart.png", pos2, StringComparison.Ordinal) > -1 Then
519     '                        post.Nickname = post.Name
520     '                    Else
521     '                        Try
522     '                            pos1 = strPost.IndexOf(_parseNick, pos2, StringComparison.Ordinal)
523     '                            pos2 = strPost.IndexOf(_parseNickTo, pos1 + _parseNick.Length, StringComparison.Ordinal)
524     '                            post.Nickname = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseNick.Length, pos2 - pos1 - _parseNick.Length))
525     '                        Catch ex As Exception
526     '                            _signed = False
527     '                            TraceOut("TM-Nick:" + strPost)
528     '                            Return "GetTimeline -> Err: Can't get Nick."
529     '                        End Try
530     '                    End If
531
532     '                    '二重取得回避
533     '                    SyncLock LockObj
534     '                        If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
535     '                    End SyncLock
536
537     '                    Dim orgData As String = ""
538     '                    'バレンタイン
539     '                    If strPost.IndexOf("<form action=""/status/update"" id=""heartForm", 0, StringComparison.Ordinal) > -1 Then
540     '                        Try
541     '                            pos1 = strPost.IndexOf("<strong>", 0, StringComparison.Ordinal)
542     '                            pos2 = strPost.IndexOf("</strong>", pos1, StringComparison.Ordinal)
543     '                            orgData = strPost.Substring(pos1 + 8, pos2 - pos1 - 8)
544     '                        Catch ex As Exception
545     '                            _signed = False
546     '                            TraceOut("TM-VBody:" + strPost)
547     '                            Return "GetTimeline -> Err: Can't get Valentine body."
548     '                        End Try
549     '                    End If
550
551
552     '                    'Get ImagePath
553     '                    Try
554     '                        pos1 = strPost.IndexOf(_parseImg, pos2, StringComparison.Ordinal)
555     '                        pos2 = strPost.IndexOf(_parseImgTo, pos1 + _parseImg.Length, StringComparison.Ordinal)
556     '                        post.ImageUrl = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseImg.Length, pos2 - pos1 - _parseImg.Length))
557     '                    Catch ex As Exception
558     '                        _signed = False
559     '                        TraceOut("TM-Img:" + strPost)
560     '                        Return "GetTimeline -> Err: Can't get ImagePath."
561     '                    End Try
562
563     '                    'Protect
564     '                    If strPost.IndexOf(_isProtect, pos2, StringComparison.Ordinal) > -1 Then
565     '                        post.IsProtect = True
566     '                    End If
567
568     '                    'RetweetedBy
569     '                    If strPost.IndexOf("class=""big-retweet-icon""") > -1 Then
570     '                        rg = New Regex("class=""shared-content"".+<a href=""/(?<name>[a-zA-Z0-9_]+)""")
571     '                        m = rg.Match(strPost)
572     '                        If m.Success Then
573     '                            post.RetweetedBy = m.Result("${name}")
574     '                        Else
575     '                            post.RetweetedBy = ""
576     '                        End If
577     '                        rg = New Regex("&in_reply_to_status_id=(?<id>[0-9]+)&in_reply_to=")
578     '                        m = rg.Match(strPost)
579     '                        If m.Success Then
580     '                            post.RetweetedId = Long.Parse(m.Result("${id}"))
581     '                        Else
582     '                            post.RetweetedId = 0
583     '                        End If
584     '                    End If
585
586     '                    'Get Message
587     '                    pos1 = strPost.IndexOf(_parseMsg1, pos2, StringComparison.Ordinal)
588     '                    If pos1 < 0 Then
589     '                        'Valentine対応その2
590     '                        Try
591     '                            If strPost.IndexOf("<div id=""doyouheart", pos2, StringComparison.Ordinal) > -1 Then
592     '                                'バレンタイン
593     '                                orgData += " <3 you! Do you <3 "
594     '                                pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
595     '                                pos2 = strPost.IndexOf("?", pos1, StringComparison.Ordinal)
596     '                                orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
597     '                            Else
598     '                                pos1 = strPost.IndexOf(_parseProtectMsg1, pos2, StringComparison.Ordinal)
599     '                                If pos1 = -1 Then
600     '                                    'バレンタイン
601     '                                    orgData += " <3 's "
602     '                                    pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
603     '                                    If pos1 > -1 Then
604     '                                        pos2 = strPost.IndexOf("!", pos1, StringComparison.Ordinal)
605     '                                        orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
606     '                                    End If
607     '                                Else
608     '                                    'プロテクトメッセージ
609     '                                    pos2 = strPost.IndexOf(_parseProtectMsg2, pos1, StringComparison.Ordinal)
610     '                                    orgData = strPost.Substring(pos1 + _parseProtectMsg1.Length, pos2 - pos1 - _parseProtectMsg1.Length).Trim()
611     '                                End If
612     '                            End If
613     '                        Catch ex As Exception
614     '                            _signed = False
615     '                            TraceOut("TM-VBody2:" + strPost)
616     '                            Return "GetTimeline -> Err: Can't get Valentine body2."
617     '                        End Try
618     '                    Else
619     '                        '通常メッセージ
620     '                        Try
621     '                            pos2 = strPost.IndexOf(_parseMsg2, pos1, StringComparison.Ordinal)
622     '                            orgData = strPost.Substring(pos1 + _parseMsg1.Length, pos2 - pos1 - _parseMsg1.Length).Trim()
623     '                        Catch ex As Exception
624     '                            _signed = False
625     '                            TraceOut("TM-Body:" + strPost)
626     '                            Return "GetTimeline -> Err: Can't get body."
627     '                        End Try
628     '                        '#If 0 Then
629     '                        '                        '原文リンク削除
630     '                        '                        orgData = Regex.Replace(orgData, "<a href=""https://twitter\.com/" + post.Name + "/status/[0-9]+"">\.\.\.</a>$", "")
631     '                        '#End If
632     '                        'ハート変換
633     '                        orgData = orgData.Replace("&lt;3", "♡")
634     '                    End If
635
636     '                    'URL前処理(IDNデコードなど)
637     '                    orgData = PreProcessUrl(orgData)
638
639     '                    '短縮URL解決処理(orgData書き換え)
640     '                    orgData = ShortUrlResolve(orgData)
641
642     '                    '表示用にhtml整形
643     '                    post.OriginalData = AdjustHtml(orgData)
644
645     '                    '単純テキストの取り出し(リンクタグ除去)
646     '                    Try
647     '                        post.Data = GetPlainText(orgData)
648     '                    Catch ex As Exception
649     '                        _signed = False
650     '                        TraceOut("TM-Link:" + strPost)
651     '                        Return "GetTimeline -> Err: Can't parse links."
652     '                    End Try
653
654     '                    ' Imageタグ除去(ハロウィン)
655     '                    Dim ImgTag As New Regex("<img src=.*?/>", RegexOptions.IgnoreCase)
656     '                    If ImgTag.IsMatch(post.Data) Then post.Data = ImgTag.Replace(post.Data, "<img>")
657
658     '                    'Get Date
659     '#If 1 Then
660     '                    Try
661     '                        pos1 = strPost.IndexOf(_parseDate, pos2, StringComparison.Ordinal)
662     '                        If pos1 > -1 Then
663     '                            pos2 = strPost.IndexOf(_parseDateTo, pos1 + _parseDate.Length, StringComparison.Ordinal)
664     '                            post.PDate = DateTime.ParseExact(strPost.Substring(pos1 + _parseDate.Length, pos2 - pos1 - _parseDate.Length), "ddd MMM dd HH':'mm':'ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, Globalization.DateTimeStyles.None)
665     '                        Else
666     '                            post.PDate = Now()
667     '                        End If
668     '                    Catch ex As Exception
669     '                        _signed = False
670     '                        TraceOut("TM-Date:" + strPost)
671     '                        Return "GetTimeline -> Err: Can't get date."
672     '                    End Try
673     '#Else
674     '                    '取得できなくなったため暫定対応(2/26)
675     '                    post.PDate = Now()
676     '#End If
677
678
679     '                    'from Sourceの取得
680     '                    'ToDo: _parseSourceFromを正規表現へ。wedataからの取得へ変更(次版より)
681     '                    rg = New Regex("<span>.+>(?<name>.+)</a>.*</span>")
682     '                    m = rg.Match(strPost)
683     '                    If m.Success Then
684     '                        post.Source = m.Result("${name}")
685     '                    Else
686     '                        post.Source = "Web"
687     '                    End If
688     '                    'Try
689     '                    '    pos1 = strPost.IndexOf(_parseSourceFrom, pos2, StringComparison.Ordinal)
690     '                    '    If pos1 = -1 Then pos1 = strPost.IndexOf(_parseSourceFrom2, pos2, StringComparison.Ordinal)
691     '                    '    If pos1 > -1 Then
692     '                    '        pos1 = strPost.IndexOf(_parseSource2, pos1 + 19, StringComparison.Ordinal)
693     '                    '        pos2 = strPost.IndexOf(_parseSourceTo, pos1 + 2, StringComparison.Ordinal)
694     '                    '        post.Source = HttpUtility.HtmlDecode(strPost.Substring(pos1 + 2, pos2 - pos1 - 2))
695     '                    '    Else
696     '                    '        post.Source = "Web"
697     '                    '    End If
698     '                    'Catch ex As Exception
699     '                    '    _signed = False
700     '                    '    TraceOut("TM-Src:" + strPost)
701     '                    '    Return "GetTimeline -> Err: Can't get src."
702     '                    'End Try
703
704     '                    'Get Reply(in_reply_to_user/id)
705     '                    'ToDo: _isReplyEngを正規表現へ。wedataからの取得へ変更(次版より)
706     '                    rg = New Regex("<a href=""https?:\/\/twitter\.com\/(?<name>[a-zA-Z0-9_]+)\/status\/(?<id>[0-9]+)"">(in reply to )*\k<name>")
707     '                    m = rg.Match(strPost)
708     '                    If m.Success Then
709     '                        post.InReplyToUser = m.Result("${name}")
710     '                        post.InReplyToId = Long.Parse(m.Result("${id}"))
711     '                        post.IsReply = post.InReplyToUser.Equals(_uid, StringComparison.OrdinalIgnoreCase)
712     '                    End If
713
714     '                    '@先リスト作成
715     '                    rg = New Regex("@<a [^>]*href=""\/(?<1>[a-zA-Z0-9_]+)[^a-zA-Z0-9_]")
716     '                    m = rg.Match(orgData)
717     '                    While m.Success
718     '                        post.ReplyToList.Add(m.Groups(1).Value.ToLower())
719     '                        m = m.NextMatch
720     '                    End While
721     '                    If Not post.IsReply Then post.IsReply = post.ReplyToList.Contains(_uid)
722
723     '                    If gType = WORKERTYPE.Reply Then post.IsReply = True
724
725     '                    'Get Fav
726     '                    If strPost.IndexOf("class=""fav-action fav""") > -1 Then
727     '                        post.IsFav = True
728     '                    Else
729     '                        post.IsFav = False
730     '                    End If
731     '                    'pos1 = strPost.IndexOf(_parseStar, pos2, StringComparison.Ordinal)
732     '                    'If pos1 > -1 Then
733     '                    '    Try
734     '                    '        pos2 = strPost.IndexOf(_parseStarTo, pos1 + _parseStar.Length, StringComparison.Ordinal)
735     '                    '        If strPost.Substring(pos1 + _parseStar.Length, pos2 - pos1 - _parseStar.Length) = _parseStarEmpty Then
736     '                    '            post.IsFav = False
737     '                    '        Else
738     '                    '            post.IsFav = True
739     '                    '        End If
740     '                    '    Catch ex As Exception
741     '                    '        _signed = False
742     '                    '        TraceOut("TM-Fav:" + strPost)
743     '                    '        Return "GetTimeline -> Err: Can't get fav status."
744     '                    '    End Try
745     '                    'Else
746     '                    '    post.IsFav = False
747     '                    'End If
748
749     '                    If _endingFlag Then Return ""
750
751     '                    post.IsMe = post.Name.Equals(_uid, StringComparison.OrdinalIgnoreCase)
752     '                    SyncLock LockObj
753     '                        If follower.Count > 1 Then
754     '                            post.IsOwl = Not follower.Contains(post.Name.ToLower())
755     '                        Else
756     '                            post.IsOwl = False
757     '                        End If
758     '                    End SyncLock
759     '                    post.IsRead = read
760     '                    If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
761
762     '                    arIdx += 1
763     '                    dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
764     '                    ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
765
766     '                End If
767
768     '                'テスト実装:DMカウント取得
769     '                If intCnt = posts.Length AndAlso gType = WORKERTYPE.Timeline AndAlso page = 1 Then
770     '                    pos1 = strPost.IndexOf(_parseDMcountFrom, pos2, StringComparison.Ordinal)
771     '                    If pos1 > -1 Then
772     '                        Try
773     '                            pos2 = strPost.IndexOf(_parseDMcountTo, pos1 + _parseDMcountFrom.Length, StringComparison.Ordinal)
774     '                            Dim dmCnt As Integer = Integer.Parse(strPost.Substring(pos1 + _parseDMcountFrom.Length, pos2 - pos1 - _parseDMcountFrom.Length))
775     '                            If dmCnt > _dmCount Then
776     '                                _dmCount = dmCnt
777     '                                _getDm = True
778     '                            End If
779     '                        Catch ex As Exception
780     '                            Return "GetTimeline -> Err: Can't get DM count."
781     '                        End Try
782     '                    End If
783     '                End If
784     '                getDM = _getDm
785     '            Next
786
787     '            For i As Integer = 0 To arIdx
788     '                Try
789     '                    dlgt(i).EndInvoke(ar(i))
790     '                Catch ex As Exception
791     '                    '最後までendinvoke回す(ゾンビ化回避)
792     '                    ex.Data("IsTerminatePermission") = False
793     '                    Throw
794     '                End Try
795     '            Next
796
797     '            SyncLock LockObj
798     '                If page = 1 AndAlso (TabInformations.GetInstance.ItemCount - listCnt) >= _nextThreshold Then
799     '                    '新着が閾値の件数以上なら、次のページも念のため読み込み
800     '                    endPage = _nextPages + 1
801     '                End If
802     '            End SyncLock
803
804     '            Return ""
805     '        Finally
806     '            GetTmSemaphore.Release()
807     '        End Try
808     '    End Function
809
810     '    Public Function GetDirectMessage(ByVal page As Integer, _
811     '                                    ByVal read As Boolean, _
812     '                                    ByVal endPage As Integer, _
813     '                                    ByVal gType As WORKERTYPE) As String
814
815     '        If endPage = 0 Then
816     '            '通常モード(DMはモード関係なし)
817     '            endPage = 1
818     '        End If
819     '        '起動時モード 
820     '        Dim num As Integer = endPage - page
821     '        Dim ar(num) As IAsyncResult
822     '        Dim dlgt(num) As GetDirectMessageDelegate
823
824     '        For idx As Integer = 0 To num
825     '            gType = WORKERTYPE.DirectMessegeRcv
826     '            dlgt(idx) = New GetDirectMessageDelegate(AddressOf GetDirectMessageThread)
827     '            GetTmSemaphore.WaitOne()
828     '            ar(idx) = dlgt(idx).BeginInvoke(page + idx, read, endPage + idx, gType, Nothing, Nothing)
829     '        Next
830     '        Dim rslt As String = ""
831     '        For idx As Integer = 0 To num
832     '            Dim trslt As String = ""
833     '            Try
834     '                trslt = dlgt(idx).EndInvoke(ar(idx))
835     '            Catch ex As Exception
836     '                '最後までendinvoke回す(ゾンビ化回避)
837     '                ex.Data("IsTerminatePermission") = False
838     '                Throw
839     '                rslt = "GetDirectMessageErr"
840     '            End Try
841     '            If trslt.Length > 0 AndAlso rslt.Length = 0 Then rslt = trslt
842     '        Next
843     '        For idx As Integer = 0 To num
844     '            gType = WORKERTYPE.DirectMessegeSnt
845     '            dlgt(idx) = New GetDirectMessageDelegate(AddressOf GetDirectMessageThread)
846     '            GetTmSemaphore.WaitOne()
847     '            ar(idx) = dlgt(idx).BeginInvoke(page + idx, read, endPage + idx, gType, Nothing, Nothing)
848     '        Next
849     '        For idx As Integer = 0 To num
850     '            Dim trslt As String = ""
851     '            Try
852     '                trslt = dlgt(idx).EndInvoke(ar(idx))
853     '            Catch ex As Exception
854     '                '最後までendinvoke回す(ゾンビ化回避)
855     '                ex.Data("IsTerminatePermission") = False
856     '                Throw
857     '                rslt = "GetDirectMessageErr"
858     '            End Try
859     '            If trslt.Length > 0 AndAlso rslt.Length = 0 Then rslt = trslt
860     '        Next
861     '        Return rslt
862     '    End Function
863
864     '    Private Function GetDirectMessageThread(ByVal page As Integer, _
865     '                                    ByVal read As Boolean, _
866     '                                    ByVal endPage As Integer, _
867     '                                    ByVal gType As WORKERTYPE) As String
868     '        Try
869     '            If _endingFlag Then Return ""
870
871     '            Dim retMsg As String = ""
872     '            Dim resStatus As String = ""
873
874     '            Static redirectToDmRcv As String = ""
875     '            Static redirectToDmSnd As String = ""
876
877     '            _getDm = False
878
879     '            If _signed = False Then
880     '                retMsg = SignIn()
881     '                If retMsg.Length > 0 Then
882     '                    Return retMsg
883     '                End If
884     '            End If
885
886     '            If _endingFlag Then Return ""
887
888     '            'リクエストメッセージを作成する
889     '            Dim pageQuery As String = _pageQry + page.ToString
890     '            If gType = WORKERTYPE.DirectMessegeRcv Then
891     '                retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _DMPathRcv + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
892     '            Else
893     '                retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _DMPathSnt + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
894     '            End If
895
896     '            If retMsg.Length = 0 Then
897     '                _signed = False
898     '                Return resStatus
899     '            End If
900
901     '            ' tr 要素の class 属性を消去
902     '            retMsg = Regex.Replace(retMsg, "(?<tagStart><li)(?<cls>\s+class=""[^""]+""\s+)", "${tagStart} ")
903     '            'Do
904     '            '    Try
905     '            '        Dim idx As Integer = retMsg.IndexOf(_removeClass, StringComparison.Ordinal)
906     '            '        If idx = -1 Then Exit Do
907     '            '        Dim idx2 As Integer = retMsg.IndexOf("""", idx + _removeClass.Length, StringComparison.Ordinal) - idx + 1 - 3
908     '            '        If idx2 > 0 Then retMsg = retMsg.Remove(idx + 3, idx2)
909     '            '    Catch ex As Exception
910     '            '        _signed = False
911     '            '        TraceOut("DM-Remove: " + retMsg)
912     '            '        Return "GetDm -> Err: Can't parse data."
913     '            '    End Try
914     '            'Loop
915
916     '            If _endingFlag Then Return ""
917
918     '            ''AuthKeyの取得
919     '            'If GetAuthKeyDM(retMsg) < 0 Then
920     '            '    _signed = False
921     '            '    Return "GetDirectMessage -> Err: Busy(1)"
922     '            'End If
923
924     '            Dim pos1 As Integer
925     '            Dim pos2 As Integer
926
927     '            '各メッセージに分割可能か?
928     '            pos1 = retMsg.IndexOf(_splitDM, StringComparison.Ordinal)
929     '            If pos1 = -1 Then
930     '                '0件(メッセージなし。エラーの場合もありうるが判別できないので正常として戻す)
931     '                Return ""
932     '            End If
933
934     '            Dim strSep() As String = {_splitDM}
935     '            Dim posts() As String = retMsg.Split(strSep, StringSplitOptions.RemoveEmptyEntries)
936     '            Dim intCnt As Integer = 0   'カウンタ
937     '            'Dim listCnt As Integer = 0
938     '            'SyncLock LockObj
939     '            '    listCnt = TabInformations.GetInstance.ItemCount
940     '            'End SyncLock
941     '            Dim dlgt(20) As GetIconImageDelegate
942     '            Dim ar(20) As IAsyncResult
943     '            Dim arIdx As Integer = -1
944
945     '            For Each strPost As String In posts
946     '                intCnt += 1
947
948     '                If intCnt > 1 Then  '1件目はヘッダなので無視
949     '                    'Dim lItem As New MyListItem
950     '                    Dim post As New PostClass()
951
952     '                    pos1 = strPost.IndexOf("</ol>")
953     '                    If pos1 > -1 Then
954     '                        strPost = strPost.Substring(0, pos1)
955     '                    End If
956
957     '                    'Get ID
958     '                    Try
959     '                        pos1 = 0
960     '                        pos2 = strPost.IndexOf("""", 0, StringComparison.Ordinal)
961     '                        post.Id = Long.Parse(HttpUtility.HtmlDecode(strPost.Substring(0, pos2)))
962     '                    Catch ex As Exception
963     '                        _signed = False
964     '                        TraceOut("DM-ID:" + strPost)
965     '                        Return "GetDirectMessage -> Err: Can't get ID"
966     '                    End Try
967
968     '                    'Get Name
969     '                    Try
970     '                        pos1 = strPost.IndexOf(_parseName, pos2, StringComparison.Ordinal)
971     '                        pos2 = strPost.IndexOf(_parseNameTo, pos1, StringComparison.Ordinal)
972     '                        post.Name = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseName.Length, pos2 - pos1 - _parseName.Length))
973     '                    Catch ex As Exception
974     '                        _signed = False
975     '                        TraceOut("DM-Name:" + strPost)
976     '                        Return "GetDirectMessage -> Err: Can't get Name"
977     '                    End Try
978
979     '                    'Get Nick
980     '                    Try
981     '                        pos1 = strPost.IndexOf(_parseNick, pos2, StringComparison.Ordinal)
982     '                        pos2 = strPost.IndexOf(_parseNickTo, pos1 + _parseNick.Length, StringComparison.Ordinal)
983     '                        post.Nickname = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseNick.Length, pos2 - pos1 - _parseNick.Length))
984     '                    Catch ex As Exception
985     '                        _signed = False
986     '                        TraceOut("DM-Nick:" + strPost)
987     '                        Return "GetDirectMessage -> Err: Can't get Nick."
988     '                    End Try
989
990     '                    SyncLock LockObj
991     '                        If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
992     '                    End SyncLock
993
994     '                    'Get ImagePath
995     '                    Try
996     '                        pos1 = strPost.IndexOf(_parseImg, pos2, StringComparison.Ordinal)
997     '                        pos2 = strPost.IndexOf(_parseImgTo, pos1 + _parseImg.Length, StringComparison.Ordinal)
998     '                        post.ImageUrl = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseImg.Length, pos2 - pos1 - _parseImg.Length))
999     '                    Catch ex As Exception
1000     '                        _signed = False
1001     '                        TraceOut("DM-Img:" + strPost)
1002     '                        Return "GetDirectMessage -> Err: Can't get ImagePath"
1003     '                    End Try
1004
1005     '                    'Get Protect 
1006     '                    Try
1007     '                        pos1 = strPost.IndexOf(_isProtect, pos2, StringComparison.Ordinal)
1008     '                        If pos1 > -1 Then post.IsProtect = True
1009     '                    Catch ex As Exception
1010     '                        _signed = False
1011     '                        TraceOut("DM-Protect:" + strPost)
1012     '                        Return "GetDirectMessage -> Err: Can't get Protect"
1013     '                    End Try
1014
1015     '                    Dim orgData As String = ""
1016
1017     '                    'Get Message
1018     '                    Try
1019     '                        pos1 = strPost.IndexOf(_parseDM1, pos2, StringComparison.Ordinal)
1020     '                        If pos1 > -1 Then
1021     '                            pos2 = strPost.IndexOf(_parseDM2, pos1, StringComparison.Ordinal)
1022     '                            orgData = strPost.Substring(pos1 + _parseDM1.Length, pos2 - pos1 - _parseDM1.Length).Trim()
1023     '                        Else
1024     '                            pos1 = strPost.IndexOf(_parseDM11, pos2, StringComparison.Ordinal)
1025     '                            pos2 = strPost.IndexOf(_parseDM2, pos1, StringComparison.Ordinal)
1026     '                            orgData = strPost.Substring(pos1 + _parseDM11.Length, pos2 - pos1 - _parseDM11.Length).Trim()
1027     '                        End If
1028     '                        'orgData = Regex.Replace(orgData, "<a href=""https://twitter\.com/" + post.Name + "/status/[0-9]+"">\.\.\.</a>$", "")
1029     '                        orgData = orgData.Replace("&lt;3", "♡")
1030     '                    Catch ex As Exception
1031     '                        _signed = False
1032     '                        TraceOut("DM-Body:" + strPost)
1033     '                        Return "GetDirectMessage -> Err: Can't get body"
1034     '                    End Try
1035
1036     '                    'URL前処理(IDNデコードなど)
1037     '                    orgData = PreProcessUrl(orgData)
1038
1039     '                    '短縮URL解決処理(orgData書き換え)
1040     '                    orgData = ShortUrlResolve(orgData)
1041
1042     '                    '表示用にhtml整形
1043     '                    post.OriginalData = AdjustHtml(orgData)
1044
1045     '                    '単純テキストの取り出し(リンクタグ除去)
1046     '                    Try
1047     '                        post.Data = GetPlainText(orgData)
1048     '                    Catch ex As Exception
1049     '                        _signed = False
1050     '                        TraceOut("DM-Link:" + strPost)
1051     '                        Return "GetDirectMessage -> Err: Can't parse links"
1052     '                    End Try
1053
1054     '#If 1 Then
1055     '                    'Get Date
1056     '                    Try
1057     '                        pos1 = strPost.IndexOf(_parseDate, pos2, StringComparison.Ordinal)
1058     '                        If pos1 > -1 Then
1059     '                            pos2 = strPost.IndexOf(_parseDateTo, pos1 + _parseDate.Length, StringComparison.Ordinal)
1060     '                            post.PDate = DateTime.ParseExact(strPost.Substring(pos1 + _parseDate.Length, pos2 - pos1 - _parseDate.Length), "ddd MMM dd HH':'mm':'ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, Globalization.DateTimeStyles.None)
1061     '                        Else
1062     '                            post.PDate = Now()
1063     '                        End If
1064     '                    Catch ex As Exception
1065     '                        _signed = False
1066     '                        TraceOut("DM-Date:" + strPost)
1067     '                        Return "GetDirectMessage -> Err: Can't get date."
1068     '                    End Try
1069     '#Else
1070     '                    '取得できなくなったため暫定対応(2/26)
1071     '                    post.PDate = Now()
1072     '#End If
1073
1074     '                    'Get Fav
1075     '                    'pos1 = strPost.IndexOf(_parseStar, pos2)
1076     '                    'pos2 = strPost.IndexOf("""", pos1 + _parseStar.Length)
1077     '                    'If strPost.Substring(pos1 + _parseStar.Length, pos2 - pos1 - _parseStar.Length) = "empty" Then
1078     '                    '    lItem.Fav = False
1079     '                    'Else
1080     '                    '    lItem.Fav = True
1081     '                    'End If
1082     '                    post.IsFav = False
1083
1084
1085     '                    If _endingFlag Then Return ""
1086
1087     '                    '受信DMかの判定で使用
1088     '                    If gType = WORKERTYPE.DirectMessegeRcv Then
1089     '                        post.IsOwl = False
1090     '                    Else
1091     '                        post.IsOwl = True
1092     '                    End If
1093
1094     '                    post.IsRead = read
1095     '                    post.IsDm = True
1096
1097     '                    'Imageの取得
1098     '                    arIdx += 1
1099     '                    dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
1100     '                    ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
1101     '                End If
1102     '            Next
1103
1104     '            For i As Integer = 0 To arIdx
1105     '                Try
1106     '                    dlgt(i).EndInvoke(ar(i))
1107     '                Catch ex As Exception
1108     '                    ex.Data("IsTerminatePermission") = False
1109     '                    Throw
1110     '                End Try
1111     '            Next
1112
1113     '            Return ""
1114
1115     '        Finally
1116     '            GetTmSemaphore.Release()
1117     '        End Try
1118     '    End Function
1119
1120     '    Public Function GetFavorites(ByVal page As Integer, _
1121     '                                ByVal read As Boolean, _
1122     '                                ByRef endPage As Integer, _
1123     '                                ByVal gType As WORKERTYPE, _
1124     '                                ByRef getDM As Boolean) As String
1125
1126     '        GetTmSemaphore.WaitOne()
1127     '        Try
1128     '            If _endingFlag Then Return ""
1129
1130     '            Dim retMsg As String = ""
1131     '            Dim resStatus As String = ""
1132
1133     '            Static redirectToFav As String = ""
1134     '            Const FAV_PATH As String = "/favorites"
1135
1136     '            If _signed = False Then
1137     '                retMsg = SignIn()
1138     '                If retMsg.Length > 0 Then
1139     '                    Return retMsg
1140     '                End If
1141     '            End If
1142
1143     '            If _endingFlag Then Return ""
1144
1145     '            'リクエストメッセージを作成する
1146     '            Dim pageQuery As String
1147
1148     '            If page = 1 Then
1149     '                pageQuery = ""
1150     '            Else
1151     '                pageQuery = _pageQry + page.ToString
1152     '            End If
1153
1154     '            retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + FAV_PATH + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
1155
1156     '            If retMsg.Length = 0 Then
1157     '                _signed = False
1158     '                Return resStatus
1159     '            End If
1160
1161     '            ' tr 要素の class 属性を消去
1162     '            retMsg = Regex.Replace(retMsg, "(?<tagStart><li)(?<cls>\s+class=""[^""]+""\s+)", "${tagStart} ")
1163     '            'Do
1164     '            '    Try
1165     '            '        Dim idx As Integer = retMsg.IndexOf(_removeClass, StringComparison.Ordinal)
1166     '            '        If idx = -1 Then Exit Do
1167     '            '        Dim idx2 As Integer = retMsg.IndexOf("""", idx + _removeClass.Length, StringComparison.Ordinal) - idx + 1 - 3
1168     '            '        If idx2 > 0 Then retMsg = retMsg.Remove(idx + 3, idx2)
1169     '            '    Catch ex As Exception
1170     '            '        _signed = False
1171     '            '        TraceOut("GetFav-Remove: " + retMsg)
1172     '            '        Return "GetFav -> Err: Can't parse data."
1173     '            '    End Try
1174     '            'Loop
1175
1176     '            If _endingFlag Then Return ""
1177
1178     '            '各メッセージに分割可能か?
1179     '            Dim strSepTmp As String
1180     '            strSepTmp = _splitPostRecent
1181
1182     '            Dim pos1 As Integer
1183     '            Dim pos2 As Integer
1184
1185     '            pos1 = retMsg.IndexOf(strSepTmp, StringComparison.Ordinal)
1186     '            If pos1 = -1 Then
1187     '                '0件 or 取得失敗
1188     '                _signed = False
1189     '                Return "GetTimeline -> Err: tweets count is 0."
1190     '            End If
1191
1192     '            Dim strSep() As String = {strSepTmp}
1193     '            Dim posts() As String = retMsg.Split(strSep, StringSplitOptions.RemoveEmptyEntries)
1194     '            Dim intCnt As Integer = 0
1195     '            'Dim listCnt As Integer = 0
1196     '            'SyncLock LockObj
1197     '            '    listCnt = TabInformations.GetInstance.ItemCount
1198     '            'End SyncLock
1199     '            Dim dlgt(20) As GetIconImageDelegate
1200     '            Dim ar(20) As IAsyncResult
1201     '            Dim arIdx As Integer = -1
1202     '            Dim rg As Regex
1203     '            Dim m As Match
1204
1205     '            For Each strPost As String In posts
1206     '                intCnt += 1
1207
1208     '                If intCnt = 1 Then
1209     '                    Continue For
1210     '                Else
1211
1212     '                    Dim post As New PostClass
1213
1214     '                    pos1 = strPost.IndexOf("</ol>")
1215     '                    If pos1 > -1 Then
1216     '                        strPost = strPost.Substring(0, pos1)
1217     '                    End If
1218
1219     '                    Try
1220     '                        'Get ID
1221     '                        pos1 = 0
1222     '                        pos2 = strPost.IndexOf(_statusIdTo, 0, StringComparison.Ordinal)
1223     '                        post.Id = Long.Parse(HttpUtility.HtmlDecode(strPost.Substring(0, pos2)))
1224     '                    Catch ex As Exception
1225     '                        _signed = False
1226     '                        TraceOut("TM-ID:" + strPost)
1227     '                        Return "GetTimeline -> Err: Can't get ID."
1228     '                    End Try
1229     '                    'Get Name
1230     '                    Try
1231     '                        pos1 = strPost.IndexOf(_parseName, pos2, StringComparison.Ordinal)
1232     '                        pos2 = strPost.IndexOf(_parseNameTo, pos1, StringComparison.Ordinal)
1233     '                        post.Name = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseName.Length, pos2 - pos1 - _parseName.Length))
1234     '                    Catch ex As Exception
1235     '                        _signed = False
1236     '                        TraceOut("TM-Name:" + strPost)
1237     '                        Return "GetTimeline -> Err: Can't get Name."
1238     '                    End Try
1239     '                    'Get Nick
1240     '                    '''バレンタイン対応
1241     '                    If strPost.IndexOf("twitter.com/images/heart.png", pos2, StringComparison.Ordinal) > -1 Then
1242     '                        post.Nickname = post.Name
1243     '                    Else
1244     '                        Try
1245     '                            pos1 = strPost.IndexOf(_parseNick, pos2, StringComparison.Ordinal)
1246     '                            pos2 = strPost.IndexOf(_parseNickTo, pos1 + _parseNick.Length, StringComparison.Ordinal)
1247     '                            post.Nickname = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseNick.Length, pos2 - pos1 - _parseNick.Length))
1248     '                        Catch ex As Exception
1249     '                            _signed = False
1250     '                            TraceOut("TM-Nick:" + strPost)
1251     '                            Return "GetTimeline -> Err: Can't get Nick."
1252     '                        End Try
1253     '                    End If
1254
1255     '                    ''二重取得回避
1256     '                    'SyncLock LockObj
1257     '                    '    If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
1258     '                    'End SyncLock
1259
1260     '                    Dim orgData As String = ""
1261     '                    'バレンタイン
1262     '                    If strPost.IndexOf("<form action=""/status/update"" id=""heartForm", 0, StringComparison.Ordinal) > -1 Then
1263     '                        Try
1264     '                            pos1 = strPost.IndexOf("<strong>", 0, StringComparison.Ordinal)
1265     '                            pos2 = strPost.IndexOf("</strong>", pos1, StringComparison.Ordinal)
1266     '                            orgData = strPost.Substring(pos1 + 8, pos2 - pos1 - 8)
1267     '                        Catch ex As Exception
1268     '                            _signed = False
1269     '                            TraceOut("TM-VBody:" + strPost)
1270     '                            Return "GetTimeline -> Err: Can't get Valentine body."
1271     '                        End Try
1272     '                    End If
1273
1274
1275     '                    'Get ImagePath
1276     '                    Try
1277     '                        pos1 = strPost.IndexOf(_parseImg, pos2, StringComparison.Ordinal)
1278     '                        pos2 = strPost.IndexOf(_parseImgTo, pos1 + _parseImg.Length, StringComparison.Ordinal)
1279     '                        post.ImageUrl = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseImg.Length, pos2 - pos1 - _parseImg.Length))
1280     '                    Catch ex As Exception
1281     '                        _signed = False
1282     '                        TraceOut("TM-Img:" + strPost)
1283     '                        Return "GetTimeline -> Err: Can't get ImagePath."
1284     '                    End Try
1285
1286     '                    'Protect
1287     '                    If strPost.IndexOf(_isProtect, pos2, StringComparison.Ordinal) > -1 Then
1288     '                        post.IsProtect = True
1289     '                    End If
1290
1291     '                    'RetweetedBy
1292     '                    If strPost.IndexOf("class=""big-retweet-icon""") > -1 Then
1293     '                        rg = New Regex("class=""shared-content"".+<a href=""/(?<name>[a-zA-Z0-9_]+)""")
1294     '                        m = rg.Match(strPost)
1295     '                        If m.Success Then
1296     '                            post.RetweetedBy = m.Result("${name}")
1297     '                        Else
1298     '                            post.RetweetedBy = ""
1299     '                        End If
1300     '                        rg = New Regex("&in_reply_to_status_id=(?<id>[0-9]+)&in_reply_to=")
1301     '                        m = rg.Match(strPost)
1302     '                        If m.Success Then
1303     '                            post.RetweetedId = Long.Parse(m.Result("${id}"))
1304     '                        Else
1305     '                            post.RetweetedId = 0
1306     '                        End If
1307     '                    End If
1308
1309     '                    'Get Message
1310     '                    pos1 = strPost.IndexOf(_parseMsg1, pos2, StringComparison.Ordinal)
1311     '                    If pos1 < 0 Then
1312     '                        'Valentine対応その2
1313     '                        Try
1314     '                            If strPost.IndexOf("<div id=""doyouheart", pos2, StringComparison.Ordinal) > -1 Then
1315     '                                'バレンタイン
1316     '                                orgData += " <3 you! Do you <3 "
1317     '                                pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
1318     '                                pos2 = strPost.IndexOf("?", pos1, StringComparison.Ordinal)
1319     '                                orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
1320     '                            Else
1321     '                                pos1 = strPost.IndexOf(_parseProtectMsg1, pos2, StringComparison.Ordinal)
1322     '                                If pos1 = -1 Then
1323     '                                    'バレンタイン
1324     '                                    orgData += " <3 's "
1325     '                                    pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
1326     '                                    If pos1 > -1 Then
1327     '                                        pos2 = strPost.IndexOf("!", pos1, StringComparison.Ordinal)
1328     '                                        orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
1329     '                                    End If
1330     '                                Else
1331     '                                    'プロテクトメッセージ
1332     '                                    pos2 = strPost.IndexOf(_parseProtectMsg2, pos1, StringComparison.Ordinal)
1333     '                                    orgData = strPost.Substring(pos1 + _parseProtectMsg1.Length, pos2 - pos1 - _parseProtectMsg1.Length).Trim()
1334     '                                End If
1335     '                            End If
1336     '                        Catch ex As Exception
1337     '                            _signed = False
1338     '                            TraceOut("TM-VBody2:" + strPost)
1339     '                            Return "GetTimeline -> Err: Can't get Valentine body2."
1340     '                        End Try
1341     '                    Else
1342     '                        '通常メッセージ
1343     '                        Try
1344     '                            pos2 = strPost.IndexOf(_parseMsg2, pos1, StringComparison.Ordinal)
1345     '                            orgData = strPost.Substring(pos1 + _parseMsg1.Length, pos2 - pos1 - _parseMsg1.Length).Trim()
1346     '                        Catch ex As Exception
1347     '                            _signed = False
1348     '                            TraceOut("TM-Body:" + strPost)
1349     '                            Return "GetTimeline -> Err: Can't get body."
1350     '                        End Try
1351     '                        '#If 0 Then
1352     '                        '                        '原文リンク削除
1353     '                        '                        orgData = Regex.Replace(orgData, "<a href=""https://twitter\.com/" + post.Name + "/status/[0-9]+"">\.\.\.</a>$", "")
1354     '                        '#End If
1355     '                        'ハート変換
1356     '                        orgData = orgData.Replace("&lt;3", "♡")
1357     '                    End If
1358
1359     '                    'URL前処理(IDNデコードなど)
1360     '                    orgData = PreProcessUrl(orgData)
1361
1362     '                    '短縮URL解決処理(orgData書き換え)
1363     '                    orgData = ShortUrlResolve(orgData)
1364
1365     '                    '表示用にhtml整形
1366     '                    post.OriginalData = AdjustHtml(orgData)
1367
1368     '                    '単純テキストの取り出し(リンクタグ除去)
1369     '                    Try
1370     '                        post.Data = GetPlainText(orgData)
1371     '                    Catch ex As Exception
1372     '                        _signed = False
1373     '                        TraceOut("TM-Link:" + strPost)
1374     '                        Return "GetTimeline -> Err: Can't parse links."
1375     '                    End Try
1376
1377     '                    ' Imageタグ除去(ハロウィン)
1378     '                    Dim ImgTag As New Regex("<img src=.*?/>", RegexOptions.IgnoreCase)
1379     '                    If ImgTag.IsMatch(post.Data) Then post.Data = ImgTag.Replace(post.Data, "<img>")
1380
1381     '                    'Get Date
1382     '#If 1 Then
1383     '                    Try
1384     '                        pos1 = strPost.IndexOf(_parseDate, pos2, StringComparison.Ordinal)
1385     '                        If pos1 > -1 Then
1386     '                            pos2 = strPost.IndexOf(_parseDateTo, pos1 + _parseDate.Length, StringComparison.Ordinal)
1387     '                            post.PDate = DateTime.ParseExact(strPost.Substring(pos1 + _parseDate.Length, pos2 - pos1 - _parseDate.Length), "ddd MMM dd HH':'mm':'ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, Globalization.DateTimeStyles.None)
1388     '                        Else
1389     '                            post.PDate = Now()
1390     '                        End If
1391     '                    Catch ex As Exception
1392     '                        _signed = False
1393     '                        TraceOut("TM-Date:" + strPost)
1394     '                        Return "GetTimeline -> Err: Can't get date."
1395     '                    End Try
1396     '#Else
1397     '                    '取得できなくなったため暫定対応(2/26)
1398     '                    post.PDate = Now()
1399     '#End If
1400
1401
1402     '                    'from Sourceの取得
1403     '                    'ToDo: _parseSourceFromを正規表現へ。wedataからの取得へ変更(次版より)
1404     '                    rg = New Regex("<span>.+>(?<name>.+)</a>.*</span>")
1405     '                    m = rg.Match(strPost)
1406     '                    If m.Success Then
1407     '                        post.Source = m.Result("${name}")
1408     '                    Else
1409     '                        post.Source = "Web"
1410     '                    End If
1411     '                    'Try
1412     '                    '    pos1 = strPost.IndexOf(_parseSourceFrom, pos2, StringComparison.Ordinal)
1413     '                    '    If pos1 = -1 Then pos1 = strPost.IndexOf(_parseSourceFrom2, pos2, StringComparison.Ordinal)
1414     '                    '    If pos1 > -1 Then
1415     '                    '        pos1 = strPost.IndexOf(_parseSource2, pos1 + 19, StringComparison.Ordinal)
1416     '                    '        pos2 = strPost.IndexOf(_parseSourceTo, pos1 + 2, StringComparison.Ordinal)
1417     '                    '        post.Source = HttpUtility.HtmlDecode(strPost.Substring(pos1 + 2, pos2 - pos1 - 2))
1418     '                    '    Else
1419     '                    '        post.Source = "Web"
1420     '                    '    End If
1421     '                    'Catch ex As Exception
1422     '                    '    _signed = False
1423     '                    '    TraceOut("TM-Src:" + strPost)
1424     '                    '    Return "GetTimeline -> Err: Can't get src."
1425     '                    'End Try
1426
1427     '                    'Get Reply(in_reply_to_user/id)
1428     '                    'ToDo: _isReplyEngを正規表現へ。wedataからの取得へ変更(次版より)
1429     '                    rg = New Regex("<a href=""https?:\/\/twitter\.com\/(?<name>[a-zA-Z0-9_]+)\/status\/(?<id>[0-9]+)"">(in reply to )*\k<name>")
1430     '                    m = rg.Match(strPost)
1431     '                    If m.Success Then
1432     '                        post.InReplyToUser = m.Result("${name}")
1433     '                        post.InReplyToId = Long.Parse(m.Result("${id}"))
1434     '                        post.IsReply = post.InReplyToUser.Equals(_uid, StringComparison.OrdinalIgnoreCase)
1435     '                    End If
1436
1437     '                    '@先リスト作成
1438     '                    rg = New Regex("@<a [^>]*href=""\/(?<1>[a-zA-Z0-9_]+)[^a-zA-Z0-9_]")
1439     '                    m = rg.Match(orgData)
1440     '                    While m.Success
1441     '                        post.ReplyToList.Add(m.Groups(1).Value.ToLower())
1442     '                        m = m.NextMatch
1443     '                    End While
1444     '                    If Not post.IsReply Then post.IsReply = post.ReplyToList.Contains(_uid)
1445
1446     '                    'Get Fav
1447     '                    post.IsFav = True
1448
1449     '                    If _endingFlag Then Return ""
1450
1451     '                    post.IsMe = post.Name.Equals(_uid, StringComparison.OrdinalIgnoreCase)
1452     '                    SyncLock LockObj
1453     '                        If follower.Count > 1 Then
1454     '                            post.IsOwl = Not follower.Contains(post.Name.ToLower())
1455     '                        Else
1456     '                            post.IsOwl = False
1457     '                        End If
1458     '                    End SyncLock
1459     '                    post.IsRead = read
1460
1461     '                    arIdx += 1
1462     '                    dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
1463     '                    ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
1464
1465     '                End If
1466
1467     '            Next
1468
1469     '            For i As Integer = 0 To arIdx
1470     '                Try
1471     '                    dlgt(i).EndInvoke(ar(i))
1472     '                Catch ex As Exception
1473     '                    '最後までendinvoke回す(ゾンビ化回避)
1474     '                    ex.Data("IsTerminatePermission") = False
1475     '                    Throw
1476     '                End Try
1477     '            Next
1478
1479     '            Return ""
1480     '        Finally
1481     '            GetTmSemaphore.Release()
1482     '        End Try
1483     '    End Function
1484
1485     Private Function PreProcessUrl(ByVal orgData As String) As String
1486         Dim posl1 As Integer
1487         Dim posl2 As Integer = 0
1488         Dim IDNConveter As IdnMapping = New IdnMapping()
1489         Dim href As String = "<a href="""
1490
1491         Do While True
1492             If orgData.IndexOf(href, posl2, StringComparison.Ordinal) > -1 Then
1493                 Dim urlStr As String = ""
1494                 ' IDN展開
1495                 posl1 = orgData.IndexOf(href, posl2, StringComparison.Ordinal)
1496                 posl1 += href.Length
1497                 posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
1498                 urlStr = orgData.Substring(posl1, posl2 - posl1)
1499
1500                 If Not urlStr.StartsWith("http://") AndAlso Not urlStr.StartsWith("https://") AndAlso Not urlStr.StartsWith("ftp://") Then
1501                     Continue Do
1502                 End If
1503
1504                 Dim replacedUrl As String = IDNDecode(urlStr)
1505                 If replacedUrl Is Nothing Then Continue Do
1506                 If replacedUrl = urlStr Then Continue Do
1507
1508                 orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + replacedUrl)
1509                 posl2 = 0
1510             Else
1511                 Exit Do
1512             End If
1513         Loop
1514         Return orgData
1515     End Function
1516     '#If 0 Then
1517     '    Private Function doShortUrlResolve(ByRef orgData As String) As Boolean
1518     '        Dim replaced As Boolean = False
1519     '        For Each _svc As String In _ShortUrlService
1520     '            Dim svc As String = _svc
1521     '            Dim posl1 As Integer
1522     '            Dim posl2 As Integer = 0
1523
1524     '            Do While True
1525     '                If orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal) > -1 Then
1526     '                    Dim urlStr As String = ""
1527     '                    Try
1528     '                        posl1 = orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal)
1529     '                        posl1 = orgData.IndexOf(svc, posl1, StringComparison.Ordinal)
1530     '                        posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
1531     '                        urlStr = New Uri(urlEncodeMultibyteChar(orgData.Substring(posl1, posl2 - posl1))).GetLeftPart(UriPartial.Path)
1532     '                        Dim Response As String = ""
1533     '                        Dim retUrlStr As String = ""
1534     '                        Dim tmpurlStr As String = urlStr
1535     '                        Dim SchemeAndDomain As Regex = New Regex("http://.+?/+?")
1536     '                        Dim tmpSchemeAndDomain As String = ""
1537     '                        For i As Integer = 0 To 4   'とりあえず5回試す
1538     '                            retUrlStr = urlEncodeMultibyteChar(DirectCast(CreateSocket.GetWebResponse(tmpurlStr, Response, MySocket.REQ_TYPE.ReqGETForwardTo), String))
1539     '                            If retUrlStr.Length > 0 Then
1540     '                                ' 転送先URLが返された (まだ転送されるかもしれないので返値を引数にしてもう一度)
1541     '                                ' 取得試行回数オーバーの場合は取得結果を転送先とする
1542     '                                Dim scd As Match = SchemeAndDomain.Match(retUrlStr)
1543     '                                If scd.Success AndAlso scd.Value <> svc Then
1544     '                                    svc = scd.Value()
1545     '                                End If
1546     '                                tmpurlStr = retUrlStr
1547     '                                Continue For
1548     '                            Else
1549     '                                ' 転送先URLが返されなかった
1550     '                                If tmpurlStr <> urlStr Then
1551     '                                    '少なくとも一度以上転送されている (前回の結果を転送先とする)
1552     '                                    retUrlStr = tmpurlStr
1553     '                                Else
1554     '                                    ' 一度も転送されていない
1555     '                                    retUrlStr = ""
1556     '                                End If
1557     '                                Exit For
1558     '                            End If
1559     '                        Next
1560     '                        If retUrlStr.Length > 0 Then
1561     '                            If Not retUrlStr.StartsWith("http") Then
1562     '                                If retUrlStr.StartsWith("/") Then
1563     '                                    retUrlStr = urlEncodeMultibyteChar(svc + retUrlStr.Substring(1))
1564     '                                ElseIf retUrlStr.StartsWith("data:") Then
1565     '                                    '
1566     '                                Else
1567     '                                    retUrlStr = urlEncodeMultibyteChar(retUrlStr.Insert(0, svc))
1568     '                                End If
1569     '                            Else
1570     '                                retUrlStr = urlEncodeMultibyteChar(retUrlStr)
1571     '                            End If
1572     '                            orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + retUrlStr)
1573     '                            posl2 = 0   '置換した場合は頭から再探索(複数同時置換での例外対応)
1574     '                            replaced = True
1575     '                        End If
1576     '                    Catch ex As Exception
1577     '                        '_signed = False
1578     '                        'Return "GetTimeline -> Err: Can't get tinyurl."
1579     '                    End Try
1580     '                Else
1581     '                    Exit Do
1582     '                End If
1583     '            Loop
1584     '        Next
1585     '        Return replaced
1586     '    End Function
1587     '#Else
1588
1589     '    Private Sub doShortUrlResolve(ByRef orgData As String)
1590     '        'Dim replaced As Boolean = False
1591     '        'Dim svc As String
1592     '        'Dim posl1 As Integer
1593     '        'Dim posl2 As Integer = 0
1594     '        Static urlCache As New Specialized.StringDictionary()
1595     '        If urlCache.Count > 500 Then urlCache.Clear() '定期的にリセット
1596
1597     '        Dim rx As New Regex("<a href=""(?<svc>http://.+?/)(?<path>[^""]+)""", RegexOptions.IgnoreCase)
1598     '        Dim m As MatchCollection = rx.Matches(orgData)
1599     '        Dim urlList As New List(Of String)
1600     '        For Each orgUrlMatch As Match In m
1601     '            Dim orgUrl As String = orgUrlMatch.Result("${svc}")
1602     '            Dim orgUrlPath As String = orgUrlMatch.Result("${path}")
1603     '            If Array.IndexOf(_ShortUrlService, orgUrl) > -1 AndAlso _
1604     '               Not urlList.Contains(orgUrl + orgUrlPath) Then
1605     '                urlList.Add(orgUrl + orgUrlPath)
1606     '            End If
1607     '        Next
1608     '        For Each orgUrl As String In urlList
1609     '            If urlCache.ContainsKey(orgUrl) Then
1610     '                Try
1611     '                    orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + urlCache(orgUrl) + """")
1612     '                Catch ex As Exception
1613     '                    'Through
1614     '                End Try
1615     '            Else
1616     '                Try
1617     '                    'urlとして生成できない場合があるらしい
1618     '                    'Dim urlstr As String = New Uri(urlEncodeMultibyteChar(orgUrl)).GetLeftPart(UriPartial.Path)
1619     '                    Dim retUrlStr As String = ""
1620     '                    Dim tmpurlStr As String = New Uri(urlEncodeMultibyteChar(orgUrl)).GetLeftPart(UriPartial.Path)
1621     '                    Dim httpVar As New HttpVarious
1622     '                    retUrlStr = urlEncodeMultibyteChar(httpVar.GetRedirectTo(tmpurlStr))
1623     '                    If retUrlStr.StartsWith("http") Then
1624     '                        retUrlStr = retUrlStr.Replace("""", "%22")  'ダブルコーテーションがあるとURL終端と判断されるため、これだけ再エンコード
1625     '                        orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + retUrlStr + """")
1626     '                        urlCache.Add(orgUrl, retUrlStr)
1627     '                    End If
1628     '                Catch ex As Exception
1629     '                    'Through
1630     '                End Try
1631     '            End If
1632     '        Next
1633
1634     '        'For Each ma As Match In m
1635     '        '    svc = ma.Result("${svc}")
1636     '        '    posl1 = ma.Index
1637     '        '    If orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal) > -1 Then
1638     '        '        Dim urlStr As String = ""
1639     '        '        Try
1640     '        '            posl1 = orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal)
1641     '        '            posl1 = orgData.IndexOf(svc, posl1, StringComparison.Ordinal)
1642     '        '            posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
1643     '        '            urlStr = New Uri(urlEncodeMultibyteChar(orgData.Substring(posl1, posl2 - posl1))).GetLeftPart(UriPartial.Path)
1644     '        '            Dim Response As String = ""
1645     '        '            Dim retUrlStr As String = ""
1646     '        '            Dim tmpurlStr As String = urlStr
1647     '        '            Dim SchemeAndDomain As Regex = New Regex("http://.+?/+?")
1648     '        '            Dim tmpSchemeAndDomain As String = ""
1649     '        '            For i As Integer = 0 To 4   'とりあえず5回試す
1650     '        '                retUrlStr = urlEncodeMultibyteChar(DirectCast(CreateSocket.GetWebResponse(tmpurlStr, Response, MySocket.REQ_TYPE.ReqGETForwardTo, timeOut:=2000), String))
1651     '        '                If retUrlStr.Length > 0 Then
1652     '        '                    ' 転送先URLが返された (まだ転送されるかもしれないので返値を引数にしてもう一度)
1653     '        '                    ' 取得試行回数オーバーの場合は取得結果を転送先とする
1654     '        '                    Dim scd As Match = SchemeAndDomain.Match(retUrlStr)
1655     '        '                    If scd.Success AndAlso scd.Value <> svc Then
1656     '        '                        svc = scd.Value()
1657     '        '                    End If
1658     '        '                    tmpurlStr = retUrlStr
1659     '        '                    Continue For
1660     '        '                Else
1661     '        '                    ' 転送先URLが返されなかった
1662     '        '                    If tmpurlStr <> urlStr Then
1663     '        '                        '少なくとも一度以上転送されている (前回の結果を転送先とする)
1664     '        '                        retUrlStr = tmpurlStr
1665     '        '                    Else
1666     '        '                        ' 一度も転送されていない
1667     '        '                        retUrlStr = ""
1668     '        '                    End If
1669     '        '                    Exit For
1670     '        '                End If
1671     '        '            Next
1672     '        '            If retUrlStr.Length > 0 Then
1673     '        '                If Not retUrlStr.StartsWith("http") Then
1674     '        '                    If retUrlStr.StartsWith("/") Then
1675     '        '                        retUrlStr = urlEncodeMultibyteChar(svc + retUrlStr.Substring(1))
1676     '        '                    ElseIf retUrlStr.StartsWith("data:") Then
1677     '        '                        '
1678     '        '                    Else
1679     '        '                        retUrlStr = urlEncodeMultibyteChar(retUrlStr.Insert(0, svc))
1680     '        '                    End If
1681     '        '                Else
1682     '        '                    retUrlStr = urlEncodeMultibyteChar(retUrlStr)
1683     '        '                End If
1684     '        '                orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + retUrlStr)
1685     '        '                posl2 = 0   '置換した場合は頭から再探索(複数同時置換での例外対応)
1686     '        '                replaced = True
1687     '        '            End If
1688     '        '        Catch ex As Exception
1689     '        '            '_signed = False
1690     '        '            'Return "GetTimeline -> Err: Can't get tinyurl."
1691     '        '        End Try
1692     '        '    Else
1693     '        '        Exit For
1694     '        '    End If
1695     '        'Next
1696     '        'Return replaced
1697     '    End Sub
1698     '#End If
1699
1700     Private Function ShortUrlResolve(ByVal orgData As String) As String
1701         If _tinyUrlResolve Then
1702             Static urlCache As New Specialized.StringDictionary()
1703             If urlCache.Count > 500 Then urlCache.Clear() '定期的にリセット
1704
1705             Dim rx As New Regex("<a href=""(?<svc>http://.+?/)(?<path>[^""]+)""", RegexOptions.IgnoreCase)
1706             Dim m As MatchCollection = rx.Matches(orgData)
1707             Dim urlList As New List(Of String)
1708             For Each orgUrlMatch As Match In m
1709                 Dim orgUrl As String = orgUrlMatch.Result("${svc}")
1710                 Dim orgUrlPath As String = orgUrlMatch.Result("${path}")
1711                 If Array.IndexOf(_ShortUrlService, orgUrl) > -1 AndAlso _
1712                    Not urlList.Contains(orgUrl + orgUrlPath) Then
1713                     urlList.Add(orgUrl + orgUrlPath)
1714                 End If
1715             Next
1716             For Each orgUrl As String In urlList
1717                 If urlCache.ContainsKey(orgUrl) Then
1718                     Try
1719                         orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + urlCache(orgUrl) + """")
1720                     Catch ex As Exception
1721                         'Through
1722                     End Try
1723                 Else
1724                     Try
1725                         'urlとして生成できない場合があるらしい
1726                         'Dim urlstr As String = New Uri(urlEncodeMultibyteChar(orgUrl)).GetLeftPart(UriPartial.Path)
1727                         Dim retUrlStr As String = ""
1728                         Dim tmpurlStr As String = New Uri(urlEncodeMultibyteChar(orgUrl)).GetLeftPart(UriPartial.Path)
1729                         Dim httpVar As New HttpVarious
1730                         retUrlStr = urlEncodeMultibyteChar(httpVar.GetRedirectTo(tmpurlStr))
1731                         If retUrlStr.StartsWith("http") Then
1732                             retUrlStr = retUrlStr.Replace("""", "%22")  'ダブルコーテーションがあるとURL終端と判断されるため、これだけ再エンコード
1733                             orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + retUrlStr + """")
1734                             urlCache.Add(orgUrl, retUrlStr)
1735                         End If
1736                     Catch ex As Exception
1737                         'Through
1738                     End Try
1739                 End If
1740             Next
1741         End If
1742         Return orgData
1743     End Function
1744
1745     Private Function GetPlainText(ByVal orgData As String) As String
1746         Return HttpUtility.HtmlDecode(Regex.Replace(orgData, "(?<tagStart><a [^>]+>)(?<text>[^<]+)(?<tagEnd></a>)", "${text}"))
1747         '不具合緊急対応で上記へ変更
1748         ''単純テキストの取り出し(リンクタグ除去)
1749         'If orgData.IndexOf(_parseLink1, StringComparison.Ordinal) = -1 Then
1750         '    retStr = HttpUtility.HtmlDecode(orgData)
1751         'Else
1752         '    Dim posl1 As Integer
1753         '    Dim posl2 As Integer
1754         '    Dim posl3 As Integer = 0
1755
1756         '    retStr = ""
1757
1758         '    posl3 = 0
1759         '    Do While True
1760         '        posl1 = orgData.IndexOf(_parseLink1, posl3, StringComparison.Ordinal)
1761         '        If posl1 = -1 Then Exit Do
1762
1763         '        If (posl3 + _parseLink3.Length <> posl1) Or posl3 = 0 Then
1764         '            If posl3 <> 0 Then
1765         '                retStr += HttpUtility.HtmlDecode(orgData.Substring(posl3 + _parseLink3.Length, posl1 - posl3 - _parseLink3.Length))
1766         '            Else
1767         '                retStr += HttpUtility.HtmlDecode(orgData.Substring(0, posl1))
1768         '            End If
1769         '        End If
1770         '        posl2 = orgData.IndexOf(_parseLink2, posl1, StringComparison.Ordinal)
1771         '        posl3 = orgData.IndexOf(_parseLink3, posl2, StringComparison.Ordinal)
1772         '        retStr += HttpUtility.HtmlDecode(orgData.Substring(posl2 + _parseLink2.Length, posl3 - posl2 - _parseLink2.Length))
1773         '    Loop
1774         '    retStr += HttpUtility.HtmlDecode(orgData.Substring(posl3 + _parseLink3.Length))
1775         'End If
1776
1777         'Return retStr
1778     End Function
1779
1780     ' htmlの簡易サニタイズ(詳細表示に不要なタグの除去)
1781
1782     Private Function SanitizeHtml(ByVal orgdata As String) As String
1783         Dim retdata As String = orgdata
1784
1785         '  <script ~ </script>
1786         Dim rx As Regex = New Regex( _
1787             "<(script|object|applet|image|frameset|fieldset|legend|style).*" & _
1788             "</(script|object|applet|image|frameset|fieldset|legend|style)>", RegexOptions.IgnoreCase)
1789         retdata = rx.Replace(retdata, "")
1790
1791         ' <frame src="...">
1792         rx = New Regex("<(frame|link|iframe|img)>", RegexOptions.IgnoreCase)
1793         retdata = rx.Replace(retdata, "")
1794
1795         Return retdata
1796     End Function
1797
1798     Private Function AdjustHtml(ByVal orgData As String) As String
1799         Dim retStr As String = orgData
1800         Dim hash As New Regex("<a [^>]+>[#|#](?<1>[a-zA-Z0-9_]+)</a>")
1801         Dim m As Match = hash.Match(retStr)
1802         While m.Success
1803             SyncLock LockObj
1804                 _hashList.Add("#" + m.Groups(1).Value)
1805             End SyncLock
1806             m = m.NextMatch
1807         End While
1808         retStr = Regex.Replace(retStr, "<a [^>]*href=""/", "<a href=""" + _protocol + "twitter.com/")
1809         retStr = retStr.Replace("<a href=", "<a target=""_self"" href=")
1810         retStr = retStr.Replace(vbLf, "<br>")
1811
1812         '半角スペースを置換(Thanks @anis774)
1813         Dim ret As Boolean = False
1814         Do
1815             ret = EscapeSpace(retStr)
1816         Loop While Not ret
1817         'Dim isTag As Boolean = False
1818         'For i As Integer = 0 To retStr.Length - 1
1819         '    If retStr(i) = "<"c Then
1820         '        isTag = True
1821         '    End If
1822         '    If retStr(i) = ">"c Then
1823         '        isTag = False
1824         '    End If
1825
1826         '    If (Not isTag) AndAlso (retStr(i) = " "c) Then
1827         '        retStr = retStr.Remove(i, 1)
1828         '        retStr = retStr.Insert(i, "&nbsp;")
1829         '    End If
1830         'Next
1831
1832         Return SanitizeHtml(retStr)
1833     End Function
1834
1835     Private Function EscapeSpace(ByRef html As String) As Boolean
1836         '半角スペースを置換(Thanks @anis774)
1837         Dim isTag As Boolean = False
1838         For i As Integer = 0 To html.Length - 1
1839             If html(i) = "<"c Then
1840                 isTag = True
1841             End If
1842             If html(i) = ">"c Then
1843                 isTag = False
1844             End If
1845
1846             If (Not isTag) AndAlso (html(i) = " "c) Then
1847                 html = html.Remove(i, 1)
1848                 html = html.Insert(i, "&nbsp;")
1849                 Return False
1850             End If
1851         Next
1852         Return True
1853     End Function
1854
1855     Private Sub GetIconImage(ByVal post As PostClass)
1856         Dim img As Image
1857         Dim bmp2 As Bitmap
1858
1859         Try
1860             If Not _getIcon Then
1861                 post.ImageIndex = -1
1862                 TabInformations.GetInstance.AddPost(post)
1863                 Exit Sub
1864             End If
1865
1866             SyncLock LockObj
1867                 post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1868             End SyncLock
1869
1870             If post.ImageIndex > -1 Then
1871                 TabInformations.GetInstance.AddPost(post)
1872                 Exit Sub
1873             End If
1874
1875             Dim httpVar As New HttpVarious
1876             img = httpVar.GetImage(post.ImageUrl)
1877             If img Is Nothing Then
1878                 post.ImageIndex = -1
1879                 TabInformations.GetInstance.AddPost(post)
1880                 Exit Sub
1881             End If
1882
1883             If _endingFlag Then Exit Sub
1884
1885             bmp2 = New Bitmap(_iconSz, _iconSz)
1886             Using g As Graphics = Graphics.FromImage(bmp2)
1887                 g.InterpolationMode = Drawing2D.InterpolationMode.High
1888                 g.DrawImage(img, 0, 0, _iconSz, _iconSz)
1889                 g.Dispose()
1890             End Using
1891
1892             SyncLock LockObj
1893                 post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1894                 If post.ImageIndex = -1 Then
1895                     Try
1896                         Dim fd As New System.Drawing.Imaging.FrameDimension(img.FrameDimensionsList(0))
1897                         Dim fd_count As Integer = img.GetFrameCount(fd)
1898                         If fd_count > 1 Then
1899                             Try
1900                                 img.SelectActiveFrame(fd, 1)
1901                                 _dIcon.Add(post.ImageUrl, img)  '詳細表示用ディクショナリに追加
1902                             Catch ex As Exception
1903                                 Dim bmp As New Bitmap(img)
1904                                 _dIcon.Add(post.ImageUrl, bmp)  '詳細表示用ディクショナリに追加
1905                                 img.Dispose()
1906                             End Try
1907                         Else
1908                             _dIcon.Add(post.ImageUrl, img)  '詳細表示用ディクショナリに追加
1909                         End If
1910                         _lIcon.Images.Add(post.ImageUrl, bmp2)
1911                         post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1912                     Catch ex As InvalidOperationException
1913                         'タイミングにより追加できない場合がある?(キー重複ではない)
1914                         post.ImageIndex = -1
1915                     End Try
1916                 End If
1917             End SyncLock
1918             TabInformations.GetInstance.AddPost(post)
1919         Catch ex As ArgumentException
1920             'タイミングによってはキー重複
1921         Finally
1922             img = Nothing
1923             bmp2 = Nothing
1924             post = Nothing
1925         End Try
1926     End Sub
1927
1928     'Private Function GetAuthKey(ByVal resMsg As String) As Integer
1929     '    Dim pos1 As Integer
1930     '    Dim pos2 As Integer
1931
1932     '    pos1 = resMsg.IndexOf(_getAuthKey, StringComparison.Ordinal)
1933     '    If pos1 < 0 Then
1934     '        'データ不正?
1935     '        Return -7
1936     '    End If
1937     '    pos2 = resMsg.IndexOf(_getAuthKeyTo, pos1 + _getAuthKey.Length, StringComparison.Ordinal)
1938     '    If pos2 > -1 Then
1939     '        _authKey = resMsg.Substring(pos1 + _getAuthKey.Length, pos2 - pos1 - _getAuthKey.Length)
1940     '    Else
1941     '        Return -7
1942     '    End If
1943
1944     '    Return 0
1945     'End Function
1946
1947     'Private Function GetAuthKeyDM(ByVal resMsg As String) As Integer
1948     '    Dim pos1 As Integer
1949     '    Dim pos2 As Integer
1950
1951     '    pos1 = resMsg.IndexOf(_getAuthKey, StringComparison.Ordinal)
1952     '    If pos1 < 0 Then
1953     '        'データ不正?
1954     '        Return -7
1955     '    End If
1956     '    pos2 = resMsg.IndexOf("""", pos1 + _getAuthKey.Length, StringComparison.Ordinal)
1957     '    _authKeyDM = resMsg.Substring(pos1 + _getAuthKey.Length, pos2 - pos1 - _getAuthKey.Length)
1958
1959     '    Return 0
1960     'End Function
1961
1962     Private Structure PostInfo
1963         Public CreatedAt As String
1964         Public Id As String
1965         Public Text As String
1966         Public UserId As String
1967         Public Sub New(ByVal Created As String, ByVal IdStr As String, ByVal txt As String, ByVal uid As String)
1968             CreatedAt = Created
1969             Id = IdStr
1970             Text = txt
1971             UserId = uid
1972         End Sub
1973         Public Shadows Function Equals(ByVal dst As PostInfo) As Boolean
1974             If Me.CreatedAt = dst.CreatedAt AndAlso Me.Id = dst.Id AndAlso Me.Text = dst.Text AndAlso Me.UserId = dst.UserId Then
1975                 Return True
1976             Else
1977                 Return False
1978             End If
1979         End Function
1980     End Structure
1981
1982     Private Function IsPostRestricted(ByRef resMsg As String) As Boolean
1983         Static _prev As New PostInfo("", "", "", "")
1984         Dim _current As New PostInfo("", "", "", "")
1985
1986
1987         Dim xd As XmlDocument = New XmlDocument()
1988         Try
1989             xd.LoadXml(resMsg)
1990             _current.CreatedAt = xd.SelectSingleNode("/status/created_at/text()").Value
1991             _current.Id = xd.SelectSingleNode("/status/id/text()").Value
1992             _current.Text = xd.SelectSingleNode("/status/text/text()").Value
1993             _current.UserId = xd.SelectSingleNode("/status/user/id/text()").Value
1994
1995             If _current.Equals(_prev) Then
1996                 Return True
1997             End If
1998             _prev.CreatedAt = _current.CreatedAt
1999             _prev.Id = _current.Id
2000             _prev.Text = _current.Text
2001             _prev.UserId = _current.UserId
2002         Catch ex As XmlException
2003             Return False
2004         End Try
2005
2006         Return False
2007     End Function
2008
2009     Public Function PostStatus(ByVal postStr As String, ByVal reply_to As Long) As String
2010
2011         If _endingFlag Then Return ""
2012
2013         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2014
2015         postStr = postStr.Trim()
2016
2017         Dim res As HttpStatusCode
2018         Dim content As String = ""
2019         Try
2020             res = twCon.UpdateStatus(postStr, reply_to, content)
2021         Catch ex As Exception
2022             Return "Err:" + ex.Message
2023         End Try
2024
2025         Select Case res
2026             Case HttpStatusCode.OK
2027                 Dim xd As XmlDocument = New XmlDocument()
2028                 Try
2029                     xd.LoadXml(content)
2030                     Dim xNode As XmlNode = Nothing
2031                     xNode = xd.SelectSingleNode("/status/user/followers_count/text()")
2032                     If xNode IsNot Nothing Then _followersCount = Integer.Parse(xNode.Value)
2033                     xNode = xd.SelectSingleNode("/status/user/friends_count/text()")
2034                     If xNode IsNot Nothing Then _friendsCount = Integer.Parse(xNode.Value)
2035                     xNode = xd.SelectSingleNode("/status/user/statuses_count/text()")
2036                     If xNode IsNot Nothing Then _statusesCount = Integer.Parse(xNode.Value)
2037                     xNode = xd.SelectSingleNode("/status/user/location/text()")
2038                     If xNode IsNot Nothing Then _location = xNode.Value
2039                     xNode = xd.SelectSingleNode("/status/user/description/text()")
2040                     If xNode IsNot Nothing Then _bio = xNode.Value
2041                 Catch ex As Exception
2042                     Return ""
2043                 End Try
2044
2045                 If Not postStr.StartsWith("D ", StringComparison.OrdinalIgnoreCase) AndAlso _
2046                         Not postStr.StartsWith("DM ", StringComparison.OrdinalIgnoreCase) AndAlso _
2047                         IsPostRestricted(content) Then
2048                     Return "OK:Delaying?"
2049                 End If
2050                 If op.Post(postStr.Length) Then
2051                     Return ""
2052                 Else
2053                     Return "Outputz:Failed"
2054                 End If
2055             Case HttpStatusCode.Forbidden
2056                 Return "Err:Update Limits?"
2057             Case HttpStatusCode.Unauthorized
2058                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2059                 Return "Check your Username/Password."
2060             Case Else
2061                 Return "Err:" + res.ToString
2062         End Select
2063     End Function
2064
2065     Public Function RemoveStatus(ByVal id As Long) As String
2066         If _endingFlag Then Return ""
2067
2068         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2069
2070         Dim res As HttpStatusCode
2071
2072         Try
2073             res = twCon.DestroyStatus(id)
2074         Catch ex As Exception
2075             Return "Err:" + ex.Message
2076         End Try
2077
2078         Select Case res
2079             Case HttpStatusCode.OK
2080                 Return ""
2081             Case HttpStatusCode.Unauthorized
2082                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2083                 Return "Check your Username/Password."
2084             Case HttpStatusCode.NotFound
2085                 Return ""
2086             Case Else
2087                 Return "Err:" + res.ToString
2088         End Select
2089
2090     End Function
2091
2092     Public Function PostRetweet(ByVal id As Long, ByVal read As Boolean) As String
2093         If _endingFlag Then Return ""
2094         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2095
2096         'データ部分の生成
2097         Dim target As Long = id
2098         If TabInformations.GetInstance.Item(id).RetweetedId > 0 Then
2099             target = TabInformations.GetInstance.Item(id).RetweetedId '再RTの場合は元発言をRT
2100         End If
2101
2102         Dim res As HttpStatusCode
2103         Dim content As String = ""
2104         Try
2105             res = twCon.RetweetStatus(target, content)
2106         Catch ex As Exception
2107             Return "Err:" + ex.Message
2108         End Try
2109
2110         Select Case res
2111             Case HttpStatusCode.Unauthorized
2112                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2113                 Return "Check your Username/Password."
2114             Case Is <> HttpStatusCode.OK
2115                 Return "Err:" + res.ToString()
2116         End Select
2117
2118         Dim dlgt As GetIconImageDelegate    'countQueryに合わせる
2119         Dim ar As IAsyncResult              'countQueryに合わせる
2120         Dim xdoc As New XmlDocument
2121         Try
2122             xdoc.LoadXml(content)
2123         Catch ex As Exception
2124             TraceOut(content)
2125             'MessageBox.Show("不正なXMLです。(TL-LoadXml)")
2126             Return "Invalid XML!"
2127         End Try
2128
2129         'ReTweetしたものをTLに追加
2130         Dim xentryNode As XmlNode = xdoc.DocumentElement.SelectSingleNode("/status")
2131         If xentryNode Is Nothing Then Return "Invalid XML!"
2132         Dim xentry As XmlElement = CType(xentryNode, XmlElement)
2133         Dim post As New PostClass
2134         Try
2135             post.Id = Long.Parse(xentry.Item("id").InnerText)
2136             '二重取得回避
2137             SyncLock LockObj
2138                 If TabInformations.GetInstance.ContainsKey(post.Id) Then Return ""
2139             End SyncLock
2140             'Retweet判定
2141             Dim xRnode As XmlNode = xentry.SelectSingleNode("./retweeted_status")
2142             If xRnode Is Nothing Then Return "Invalid XML!"
2143
2144             Dim xRentry As XmlElement = CType(xRnode, XmlElement)
2145             post.PDate = DateTime.ParseExact(xRentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
2146             'Id
2147             post.RetweetedId = Long.Parse(xRentry.Item("id").InnerText)
2148             '本文
2149             post.Data = xRentry.Item("text").InnerText
2150             'Source取得(htmlの場合は、中身を取り出し)
2151             post.Source = xRentry.Item("source").InnerText
2152             'Reply先
2153             Long.TryParse(xRentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
2154             post.InReplyToUser = xRentry.Item("in_reply_to_screen_name").InnerText
2155             post.IsFav = TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Contains(post.RetweetedId)
2156
2157             '以下、ユーザー情報
2158             Dim xRUentry As XmlElement = CType(xRentry.SelectSingleNode("./user"), XmlElement)
2159             post.Uid = Long.Parse(xRUentry.Item("id").InnerText)
2160             post.Name = xRUentry.Item("screen_name").InnerText
2161             post.Nickname = xRUentry.Item("name").InnerText
2162             post.ImageUrl = xRUentry.Item("profile_image_url").InnerText
2163             post.IsProtect = Boolean.Parse(xRUentry.Item("protected").InnerText)
2164             'post.IsMe = post.Name.ToLower.Equals(_uid)
2165             post.IsMe = True
2166
2167             'Retweetした人(自分のはず)
2168             Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
2169             post.RetweetedBy = xUentry.Item("screen_name").InnerText
2170
2171             'HTMLに整形
2172             post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
2173             post.Data = HttpUtility.HtmlDecode(post.Data)
2174             post.Data = post.Data.Replace("<3", "♡")
2175             'Source整形
2176             If post.Source.StartsWith("<") Then
2177                 Dim rgS As New Regex(">(?<source>.+)<")
2178                 Dim mS As Match = rgS.Match(post.Source)
2179                 If mS.Success Then
2180                     post.Source = mS.Result("${source}")
2181                 End If
2182             End If
2183
2184             post.IsRead = read
2185             post.IsReply = post.ReplyToList.Contains(_uid)
2186
2187             If post.IsMe Then
2188                 post.IsOwl = False
2189             Else
2190                 If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.Uid)
2191             End If
2192             If post.IsMe AndAlso _readOwnPost Then post.IsRead = True
2193
2194             post.IsDm = False
2195         Catch ex As Exception
2196             TraceOut(content)
2197             'MessageBox.Show("不正なXMLです。(TL-Parse)")
2198             Return "Invalid XML!"
2199         End Try
2200
2201         '非同期アイコン取得&StatusDictionaryに追加
2202         dlgt = New GetIconImageDelegate(AddressOf GetIconImage)
2203         ar = dlgt.BeginInvoke(post, Nothing, Nothing)
2204
2205         'アイコン取得完了待ち
2206         Try
2207             dlgt.EndInvoke(ar)
2208         Catch ex As Exception
2209             '最後までendinvoke回す(ゾンビ化回避)
2210             ex.Data("IsTerminatePermission") = False
2211             Throw
2212         End Try
2213
2214         Return ""
2215     End Function
2216
2217     Public Function RemoveDirectMessage(ByVal id As Long) As String
2218         If _endingFlag Then Return ""
2219
2220         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2221
2222         Dim res As HttpStatusCode
2223
2224         Try
2225             res = twCon.DestroyDirectMessage(id)
2226         Catch ex As Exception
2227             Return "Err:" + ex.Message
2228         End Try
2229
2230         Select Case res
2231             Case HttpStatusCode.OK
2232                 Return ""
2233             Case HttpStatusCode.Unauthorized
2234                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2235                 Return "Check your Username/Password."
2236             Case HttpStatusCode.NotFound
2237                 Return ""
2238             Case Else
2239                 Return "Err:" + res.ToString
2240         End Select
2241     End Function
2242
2243     Public Function PostFollowCommand(ByVal screenName As String) As String
2244
2245         If _endingFlag Then Return ""
2246
2247         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2248
2249         Dim res As HttpStatusCode
2250
2251         Try
2252             res = twCon.CreateFriendships(screenName)
2253         Catch ex As Exception
2254             Return "Err:" + ex.Message
2255         End Try
2256
2257         Select Case res
2258             Case HttpStatusCode.OK
2259                 Return ""
2260             Case HttpStatusCode.Unauthorized
2261                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2262                 Return "Check your Username/Password."
2263             Case HttpStatusCode.Forbidden
2264                 Return "Err:Update Limits?"
2265             Case Else
2266                 Return "Err:" + res.ToString
2267         End Select
2268     End Function
2269
2270     Public Function PostRemoveCommand(ByVal screenName As String) As String
2271
2272         If _endingFlag Then Return ""
2273
2274         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2275
2276         Dim res As HttpStatusCode
2277
2278         Try
2279             res = twCon.DestroyFriendships(screenName)
2280         Catch ex As Exception
2281             Return "Err:" + ex.Message
2282         End Try
2283
2284         Select Case res
2285             Case HttpStatusCode.OK
2286                 Return ""
2287             Case HttpStatusCode.Unauthorized
2288                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2289                 Return "Check your Username/Password."
2290             Case Else
2291                 Return "Err:" + res.ToString
2292         End Select
2293     End Function
2294
2295     Public Function GetFriendshipInfo(ByVal screenName As String, ByRef isFollowing As Boolean, ByRef isFollowed As Boolean) As String
2296
2297         If _endingFlag Then Return ""
2298
2299         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2300
2301         Dim res As HttpStatusCode
2302         Dim content As String = ""
2303         Try
2304             res = twCon.ShowFriendships(_uid, screenName, content)
2305         Catch ex As Exception
2306             Return "Err:" + ex.Message
2307         End Try
2308
2309         Select Case res
2310             Case HttpStatusCode.OK
2311                 Dim xdoc As New XmlDocument
2312                 Dim result As String = ""
2313                 Try
2314                     xdoc.LoadXml(content)
2315                     isFollowing = Boolean.Parse(xdoc.SelectSingleNode("/relationship/source/following").InnerText)
2316                     isFollowed = Boolean.Parse(xdoc.SelectSingleNode("/relationship/source/followed_by").InnerText)
2317                 Catch ex As Exception
2318                     result = "Err:Invalid XML."
2319                 End Try
2320                 Return result
2321             Case HttpStatusCode.BadRequest
2322                 Return "Err:API Limits?"
2323             Case HttpStatusCode.Unauthorized
2324                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2325                 Return "Check your Username/Password."
2326             Case Else
2327                 Return "Err:" + res.ToString
2328         End Select
2329     End Function
2330
2331     Public Function PostFavAdd(ByVal id As Long) As String
2332         If _endingFlag Then Return ""
2333
2334         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2335
2336         Dim res As HttpStatusCode
2337
2338         Try
2339             res = twCon.CreateFavorites(id)
2340         Catch ex As Exception
2341             Return "Err:" + ex.Message
2342         End Try
2343
2344         Select Case res
2345             Case HttpStatusCode.OK
2346                 If Not _restrictFavCheck Then Return ""
2347             Case HttpStatusCode.Unauthorized
2348                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2349                 Return "Check your Username/Password."
2350             Case HttpStatusCode.Forbidden
2351                 Return "Err:Update Limits?"
2352             Case Else
2353                 Return "Err:" + res.ToString
2354         End Select
2355
2356         'http://twitter.com/statuses/show/id.xml APIを発行して本文を取得
2357
2358         Dim content As String = ""
2359         Try
2360             res = twCon.ShowStatuses(id, content)
2361         Catch ex As Exception
2362             Return "Err:" + ex.Message
2363         End Try
2364
2365         Select Case res
2366             Case HttpStatusCode.OK
2367                 Try
2368                     Using rd As Xml.XmlTextReader = New Xml.XmlTextReader(New System.IO.StringReader(content))
2369                         rd.Read()
2370                         While rd.EOF = False
2371                             If rd.IsStartElement("favorited") Then
2372                                 If rd.ReadElementContentAsBoolean() = True Then
2373                                     Return ""  '正常にふぁぼれている
2374                                 Else
2375                                     Return "NG(Restricted?)"  '正常応答なのにふぁぼれてないので制限っぽい
2376                                 End If
2377                             Else
2378                                 rd.Read()
2379                             End If
2380                         End While
2381                         rd.Close()
2382                         Return "Err:Invalid XML!"
2383                     End Using
2384                 Catch ex As XmlException
2385                     Return ""
2386                 End Try
2387             Case HttpStatusCode.Unauthorized
2388                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2389                 Return "Check your Username/Password."
2390             Case HttpStatusCode.BadRequest
2391                 Return "Err:API Limits?"
2392             Case Else
2393                 Return "Err:" + res.ToString
2394         End Select
2395
2396     End Function
2397
2398     Public Function PostFavRemove(ByVal id As Long) As String
2399         If _endingFlag Then Return ""
2400
2401         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2402
2403         Dim res As HttpStatusCode
2404
2405         Try
2406             res = twCon.DestroyFavorites(id)
2407         Catch ex As Exception
2408             Return "Err:" + ex.Message
2409         End Try
2410
2411         Select Case res
2412             Case HttpStatusCode.OK
2413                 Return ""
2414             Case HttpStatusCode.Unauthorized
2415                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2416                 Return "Check your Username/Password."
2417             Case HttpStatusCode.Forbidden
2418                 Return "Err:Update Limits?"
2419             Case Else
2420                 Return "Err:" + res.ToString
2421         End Select
2422     End Function
2423
2424     '#Region "follower取得"
2425     '    'Delegate Function GetFollowersDelegate(ByVal Query As Integer) As String
2426     '    'Private semaphore As Threading.Semaphore = Nothing
2427     '    'Private threadNum As Integer = 0
2428     '    Private _threadErr As Boolean = False
2429
2430     '    Private Function GetFollowersMethod() As String
2431     '        Dim resStatus As String = ""
2432     '        Dim resMsg As String = ""
2433     '        Dim lineCount As Integer = 0
2434     '        Dim page As Long = -1
2435
2436     '        Do
2437     '            If _endingFlag Then Exit Do
2438     '            resMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _apiHost + _hubServer + _GetFollowers + _cursorQry + page.ToString, resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
2439     '            If resStatus.StartsWith("OK") = False Then
2440     '                Debug.WriteLine(page.ToString)
2441     '                _threadErr = True
2442     '                Return resStatus
2443     '            End If
2444     '            Try
2445     '                Using rd As Xml.XmlTextReader = New Xml.XmlTextReader(New System.IO.StringReader(resMsg))
2446     '                    lineCount = 0
2447     '                    rd.Read()
2448     '                    While rd.EOF = False
2449     '                        If rd.IsStartElement("screen_name") Then
2450     '                            Dim tmp As String = rd.ReadElementString("screen_name").ToLower()
2451     '                            SyncLock LockObj
2452     '                                If Not tmpFollower.Contains(tmp) Then
2453     '                                    tmpFollower.Add(tmp)
2454     '                                End If
2455     '                            End SyncLock
2456     '                            lineCount += 1
2457     '                        ElseIf rd.IsStartElement("next_cursor") Then
2458     '                            page = Long.Parse(rd.ReadElementString("next_cursor"))
2459     '                            If page = 0 Then Exit Do
2460     '                            Exit While
2461     '                        Else
2462     '                            rd.Read()
2463     '                        End If
2464     '                    End While
2465     '                End Using
2466     '            Catch ex As Exception
2467     '                _threadErr = True
2468     '                TraceOut("NG(XmlException)")
2469     '                Return "NG(XmlException)"
2470     '            End Try
2471     '        Loop While lineCount > 0
2472
2473     '        Return ""
2474     '    End Function
2475
2476     'Private Sub GetFollowersCallback(ByVal ar As IAsyncResult)
2477     '    Dim dlgt As GetFollowersDelegate = DirectCast(ar.AsyncState, GetFollowersDelegate)
2478
2479     '    Try
2480     '        Dim ret As String = dlgt.EndInvoke(ar)
2481     '        If Not ret.Equals("") AndAlso Not _threadErr Then
2482     '            TraceOut(ret)
2483     '            _threadErr = True
2484     '        End If
2485     '    Catch ex As Exception
2486     '        _threadErr = True
2487     '        ex.Data("IsTerminatePermission") = False
2488     '        Throw
2489     '    Finally
2490     '        GetTmSemaphore.Release()                     ' セマフォから出る
2491     '        Interlocked.Decrement(threadNum)        ' スレッド数カウンタを-1
2492     '    End Try
2493
2494     'End Sub
2495
2496     '' キャッシュの検証と読み込み -1を渡した場合は読み込みのみ行う(APIエラーでFollowersCountが取得できなかったとき)
2497     'Private Function ValidateCache() As Integer
2498
2499     '    follower.Clear()
2500     '    Try
2501     '        Dim setting As SettingFollower = SettingFollower.Load()
2502     '        follower = setting.Follower
2503     '        If follower.Count = 0 OrElse Not follower(0).Equals(_uid.ToLower()) Then
2504     '            ' 別IDの場合はキャッシュ破棄して読み直し
2505     '            Return -1
2506     '        End If
2507     '    Catch ex As XmlException
2508     '        ' 不正なxmlの場合は読み直し
2509     '        Return -1
2510     '    Catch ex As InvalidOperationException
2511     '        'XMLが壊れている場合
2512     '        Return -1
2513     '    End Try
2514
2515     '    'If _FollowersCount = -1 Then Return tmpFollower.Count
2516     '    Return follower.Count
2517
2518     '    'If (_FollowersCount + 1) = tmpFollower.Count Then
2519     '    '    '変動がないので読み込みの必要なし
2520     '    '    Return 0
2521     '    'ElseIf (_FollowersCount + 1) < tmpFollower.Count Then
2522     '    '    '減っている場合はどこが抜けているのかわからないので全部破棄して読み直し
2523     '    '    tmpFollower.Clear()
2524     '    '    tmpFollower.Add(_uid.ToLower())
2525     '    '    Return _FollowersCount
2526     '    'End If
2527
2528     '    '' 増えた場合は差分だけ読む
2529
2530     '    'Return _FollowersCount - tmpFollower.Count
2531
2532     'End Function
2533
2534     'Private Sub UpdateCache()
2535     '    Dim setting As New SettingFollower(follower)
2536     '    setting.Save()
2537     'End Sub
2538
2539     '    Public Function GetFollowers(ByVal CacheInvalidate As Boolean) As String
2540     '#If DEBUG Then
2541     '        Dim sw As New System.Diagnostics.Stopwatch
2542     '        sw.Start()
2543     '#End If
2544
2545     '        If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2546
2547     '        'Dim resStatus As String = ""
2548     '        'Dim resMsg As String = ""
2549     '        'Dim i As Integer = 0
2550     '        'Dim DelegateInstance As GetFollowersDelegate = New GetFollowersDelegate(AddressOf GetFollowersMethod)
2551     '        'Dim threadMax As Integer = 4            ' 最大スレッド数
2552     '        'Dim followersCount As Integer = 0
2553
2554     '        'Interlocked.Exchange(threadNum, 0)      ' スレッド数カウンタ初期化
2555     '        _threadErr = False
2556     '        'follower.Clear()
2557     '        tmpFollower.Clear()
2558     '        'follower.Add(_uid.ToLower())
2559     '        tmpFollower.Add(_uid.ToLower())
2560
2561     '        'resMsg = DirectCast(CreateSocket.GetWebResponse("https://twitter.com/users/show/" + _uid + ".xml", resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
2562     '        'If resMsg = "" Then
2563     '        '    If resStatus.StartsWith("Err: BadRequest") Then
2564     '        '        Return "Maybe, the requests reached API limit."
2565     '        '    ElseIf resStatus.StartsWith("Err: Unauthorized") Then
2566     '        '        Twitter.AccountState = ACCOUNT_STATE.Invalid
2567     '        '        Return "Check your Username/Password."
2568     '        '    Else
2569     '        '        Return resStatus
2570     '        '    End If
2571     '        'End If
2572
2573     '        'Dim xd As XmlDocument = New XmlDocument()
2574     '        'Try
2575     '        '    xd.LoadXml(resMsg)
2576     '        '    followersCount = Integer.Parse(xd.SelectSingleNode("/user/followers_count/text()").Value)
2577     '        'Catch ex As Exception
2578     '        '    'If CacheInvalidate OrElse ValidateCache(-1) < 0 Then
2579     '        '    If ValidateCache(-1) < 0 Then
2580     '        '        ' FollowersカウントがAPIで取得できず、なおかつキャッシュから読めなかった
2581     '        '        SyncLock LockObj
2582     '        '            follower.Clear()
2583     '        '            follower.Add(_uid.ToLower())
2584     '        '        End SyncLock
2585     '        '        Return "Can't get followers_count and invalid cache."
2586     '        '    Else
2587     '        '        'キャッシュを読み出せたのでキャッシュを使う
2588     '        '        SyncLock LockObj
2589     '        '            follower = tmpFollower
2590     '        '        End SyncLock
2591     '        '        Return ""
2592     '        '    End If
2593     '        'End Try
2594
2595     '        'Dim tmp As Integer
2596
2597     '        ''If CacheInvalidate Then
2598     '        'tmp = followersCount
2599     '        ''Else
2600     '        ''tmp = ValidateCache(followersCount)
2601     '        ''End If
2602
2603
2604     '        'If tmp <> 0 Then
2605     '        '    i = (tmp + 100) \ 100  ' Followersカウント取得しページ単位に切り上げる。1ページ余分に読む
2606     '        'Else
2607     '        '    '            ' キャッシュの件数に変化がなかった
2608     '        '    '#If DEBUG Then
2609     '        '    '            sw.Stop()
2610     '        '    '            Console.WriteLine(sw.ElapsedMilliseconds)
2611     '        '    '#End If
2612     '        '    '            SyncLock LockObj
2613     '        '    '                follower = tmpFollower
2614     '        '    '            End SyncLock
2615     '        '    'Return ""
2616     '        '    Return ""   'ユーザー情報のフォロワー数が0
2617     '        'End If
2618
2619
2620     '        ''semaphore = New System.Threading.Semaphore(threadMax, threadMax) 'スレッド最大数
2621
2622     '        'For cnt As Integer = 0 To i
2623     '        '    If _endingFlag Then Exit For
2624     '        '    'semaphore.WaitOne()                     'セマフォ取得 threadMax以上ならここでブロックされる
2625     '        '    GetTmSemaphore.WaitOne()
2626     '        '    'Interlocked.Increment(threadNum)        'スレッド数カウンタを+1
2627     '        '    'DelegateInstance.BeginInvoke(cnt + 1, New System.AsyncCallback(AddressOf GetFollowersCallback), DelegateInstance)
2628     '        '    Dim ret As String = GetFollowersMethod(cnt + 1)
2629     '        '    'Interlocked.Decrement(threadNum)        'スレッド数カウンタを-1
2630     '        '    GetTmSemaphore.Release()
2631     '        '    If _threadErr Then Exit For
2632     '        'Next
2633
2634     '        '''全てのスレッドの終了を待つ(スレッド数カウンタが0になるまで待機)
2635     '        ''Do
2636     '        ''    Thread.Sleep(50)
2637     '        ''Loop Until Interlocked.Add(threadNum, 0) = 0
2638
2639     '        ''semaphore.Close()
2640
2641     '        Dim ret As String = GetFollowersMethod()
2642     '        If _endingFlag Then Return ""
2643
2644     '        If _threadErr Then
2645     '            If ValidateCache() > 0 Then
2646     '                SyncLock LockObj
2647     '                    For Each name As String In tmpFollower
2648     '                        If Not follower.Contains(name) Then follower.Add(name)
2649     '                    Next
2650     '                End SyncLock
2651     '                If Not _endingFlag AndAlso follower.Count > 1 Then UpdateCache()
2652     '                ret = "Can't get followers. Use cache."
2653     '            Else
2654     '                ' エラーが発生しているならFollowersリストクリア
2655     '                SyncLock LockObj
2656     '                    follower.Clear()
2657     '                    follower.Add(_uid.ToLower())
2658     '                End SyncLock
2659     '                ret = "Can't get followers."
2660     '            End If
2661     '        Else
2662     '            SyncLock LockObj
2663     '                follower = tmpFollower
2664     '            End SyncLock
2665     '            ret = ""
2666     '        End If
2667
2668     '        If Not _endingFlag AndAlso follower.Count > 1 Then UpdateCache()
2669
2670     '#If DEBUG Then
2671     '        sw.Stop()
2672     '        'Console.WriteLine(sw.ElapsedMilliseconds)
2673     '#End If
2674
2675     '        TabInformations.GetInstance.RefreshOwl(follower)
2676     '        Return ret
2677     '    End Function
2678
2679     '#End Region
2680
2681     'Public Sub RefreshOwl()
2682     '    TabInformations.GetInstance.RefreshOwl(follower)
2683     'End Sub
2684
2685     'Public Sub RefreshOwlApi()
2686     '    TabInformations.GetInstance.RefreshOwl(followerId)
2687     'End Sub
2688
2689     Public ReadOnly Property Username() As String
2690         Get
2691             Return twCon.AuthenticatedUsername
2692         End Get
2693     End Property
2694
2695     Public ReadOnly Property Password() As String
2696         Get
2697             Return twCon.Password
2698         End Get
2699     End Property
2700
2701     Private Shared _accountState As ACCOUNT_STATE = ACCOUNT_STATE.Valid
2702     Public Shared Property AccountState() As ACCOUNT_STATE
2703         Get
2704             Return _accountState
2705         End Get
2706         Set(ByVal value As ACCOUNT_STATE)
2707             _accountState = value
2708         End Set
2709     End Property
2710
2711     'Public Property NextThreshold() As Integer
2712     '    Get
2713     '        Return _nextThreshold
2714     '    End Get
2715     '    Set(ByVal value As Integer)
2716     '        _nextThreshold = value
2717     '    End Set
2718     'End Property
2719
2720     'Public Property NextPages() As Integer
2721     '    Get
2722     '        Return _nextPages
2723     '    End Get
2724     '    Set(ByVal value As Integer)
2725     '        _nextPages = value
2726     '    End Set
2727     'End Property
2728
2729     Public ReadOnly Property InfoTwitter() As String
2730         Get
2731             Return _infoTwitter
2732         End Get
2733     End Property
2734
2735     'Public Property UseAPI() As Boolean
2736     '    Get
2737     '        Return _useAPI
2738     '    End Get
2739     '    Set(ByVal value As Boolean)
2740     '        _useAPI = value
2741     '    End Set
2742     'End Property
2743
2744     '    Public Sub GetWedata()
2745     '        Dim resStatus As String = ""
2746     '        Dim resMsg As String = ""
2747
2748     '        resMsg = DirectCast(CreateSocket.GetWebResponse(wedataUrl, resStatus, timeOut:=10 * 1000), String) 'タイムアウト時間を10秒に設定
2749     '        If resMsg.Length = 0 Then Exit Sub
2750
2751     '        Dim rs As New System.IO.StringReader(resMsg)
2752
2753     '        Dim mode As Integer = 0 '0:search name 1:search data 2:read data
2754     '        Dim name As String = ""
2755
2756     '        'ストリームの末端まで繰り返す
2757     '        Dim ln As String
2758     '        While rs.Peek() > -1
2759     '            ln = rs.ReadLine
2760
2761     '            Select Case mode
2762     '                Case 0
2763     '                    If ln.StartsWith("    ""name"": ") Then
2764     '                        name = ln.Substring(13, ln.Length - 2 - 13)
2765     '                        mode += 1
2766     '                    End If
2767     '                Case 1
2768     '                    If ln = "    ""data"": {" Then
2769     '                        mode += 1
2770     '                    End If
2771     '                Case 2
2772     '                    If ln = "    }," Then
2773     '                        mode = 0
2774     '                    Else
2775     '                        If ln.EndsWith(",") Then ln = ln.Substring(0, ln.Length - 1)
2776     '                        Select Case name
2777     '                            Case "SplitPostReply"
2778     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2779     '                                    _splitPost = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2780     '                                End If
2781     '                            Case "SplitPostRecent"
2782     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2783     '                                    _splitPostRecent = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2784     '                                End If
2785     '                            Case "StatusID"
2786     '                                If ln.StartsWith("      ""tagto"": """) Then
2787     '                                    _statusIdTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2788     '                                End If
2789     '                            Case "IsProtect"
2790     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2791     '                                    _isProtect = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2792     '                                End If
2793     '                            Case "IsReply"
2794     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2795     '                                    _isReplyEng = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2796     '                                End If
2797     '                                If ln.StartsWith("      ""tagfrom2"": """) Then
2798     '                                    _isReplyJpn = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2799     '                                End If
2800     '                                If ln.StartsWith("      ""tagto"": """) Then
2801     '                                    _isReplyTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2802     '                                End If
2803     '                                'Case "GetStar"
2804     '                                '    If ln.StartsWith("      ""tagfrom"": """) Then
2805     '                                '        _parseStar = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2806     '                                '    End If
2807     '                                '    If ln.StartsWith("      ""tagfrom2"": """) Then
2808     '                                '        _parseStarEmpty = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2809     '                                '    End If
2810     '                                '    If ln.StartsWith("      ""tagto"": """) Then
2811     '                                '        _parseStarTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2812     '                                '    End If
2813     '                            Case "Follower"
2814     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2815     '                                    _followerList = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2816     '                                End If
2817     '                                If ln.StartsWith("      ""tagfrom2"": """) Then
2818     '                                    _followerMbr1 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2819     '                                End If
2820     '                                If ln.StartsWith("      ""tagfrom3"": """) Then
2821     '                                    _followerMbr2 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2822     '                                End If
2823     '                                If ln.StartsWith("      ""tagto"": """) Then
2824     '                                    _followerMbr3 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2825     '                                End If
2826     '                            Case "SplitDM"
2827     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2828     '                                    _splitDM = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2829     '                                End If
2830     '                            Case "GetMsgDM"
2831     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2832     '                                    _parseDM1 = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2833     '                                End If
2834     '                                If ln.StartsWith("      ""tagfrom2"": """) Then
2835     '                                    _parseDM11 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2836     '                                End If
2837     '                                If ln.StartsWith("      ""tagto"": """) Then
2838     '                                    _parseDM2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2839     '                                End If
2840     '                            Case "GetDate"
2841     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2842     '                                    _parseDate = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2843     '                                End If
2844     '                                If ln.StartsWith("      ""tagto"": """) Then
2845     '                                    _parseDateTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2846     '                                End If
2847     '                            Case "GetMsg"
2848     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2849     '                                    _parseMsg1 = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2850     '                                End If
2851     '                                If ln.StartsWith("      ""tagto"": """) Then
2852     '                                    _parseMsg2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2853     '                                End If
2854     '                            Case "GetImagePath"
2855     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2856     '                                    _parseImg = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2857     '                                End If
2858     '                                If ln.StartsWith("      ""tagto"": """) Then
2859     '                                    _parseImgTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2860     '                                End If
2861     '                            Case "GetNick"
2862     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2863     '                                    _parseNick = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2864     '                                End If
2865     '                                If ln.StartsWith("      ""tagto"": """) Then
2866     '                                    _parseNickTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2867     '                                End If
2868     '                            Case "GetName"
2869     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2870     '                                    _parseName = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2871     '                                End If
2872     '                                If ln.StartsWith("      ""tagto"": """) Then
2873     '                                    _parseNameTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2874     '                                End If
2875     '                                'Case "GetSiv"
2876     '                                '    If ln.StartsWith("      ""tagfrom"": """) Then
2877     '                                '        _getSiv = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2878     '                                '    End If
2879     '                                '    If ln.StartsWith("      ""tagto"": """) Then
2880     '                                '        _getSivTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2881     '                                '    End If
2882     '                            Case "AuthKey"
2883     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2884     '                                    _getAuthKey = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2885     '                                End If
2886     '                                If ln.StartsWith("      ""tagto"": """) Then
2887     '                                    _getAuthKeyTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2888     '                                End If
2889     '                            Case "InfoTwitter"
2890     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2891     '                                    _getInfoTwitter = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2892     '                                End If
2893     '                                If ln.StartsWith("      ""tagto"": """) Then
2894     '                                    _getInfoTwitterTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2895     '                                End If
2896     '                            Case "GetProtectMsg"
2897     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2898     '                                    _parseProtectMsg1 = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2899     '                                End If
2900     '                                If ln.StartsWith("      ""tagto"": """) Then
2901     '                                    _parseProtectMsg2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2902     '                                End If
2903     '                            Case "GetDMCount"
2904     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2905     '                                    _parseDMcountFrom = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2906     '                                End If
2907     '                                If ln.StartsWith("      ""tagto"": """) Then
2908     '                                    _parseDMcountTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2909     '                                End If
2910     '                            Case "GetSource"
2911     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2912     '                                    _parseSourceFrom = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2913     '                                End If
2914     '                                If ln.StartsWith("      ""tagfrom2"": """) Then
2915     '                                    _parseSource2 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2916     '                                End If
2917     '                                If ln.StartsWith("      ""tagto"": """) Then
2918     '                                    _parseSource2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2919     '                                End If
2920     '                            Case "RemoveClass"
2921     '                                If ln.StartsWith("      ""tagfrom"": """) Then
2922     '                                    _removeClass = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2923     '                                End If
2924     '                        End Select
2925     '                    End If
2926     '            End Select
2927     '        End While
2928
2929     '        rs.Close()
2930
2931     '#If DEBUG Then
2932     '        GenerateAnalyzeKey()
2933     '#End If
2934     '    End Sub
2935
2936     Public WriteOnly Property GetIcon() As Boolean
2937         Set(ByVal value As Boolean)
2938             _getIcon = value
2939         End Set
2940     End Property
2941
2942     Public WriteOnly Property TinyUrlResolve() As Boolean
2943         Set(ByVal value As Boolean)
2944             _tinyUrlResolve = value
2945         End Set
2946     End Property
2947
2948     'Public WriteOnly Property SelectedProxyType() As ProxyType
2949     '    Set(ByVal value As ProxyType)
2950     '        _proxyType = value
2951     '    End Set
2952     'End Property
2953
2954     'Public WriteOnly Property ProxyAddress() As String
2955     '    Set(ByVal value As String)
2956     '        _proxyAddress = value
2957     '    End Set
2958     'End Property
2959
2960     'Public WriteOnly Property ProxyPort() As Integer
2961     '    Set(ByVal value As Integer)
2962     '        _proxyPort = value
2963     '    End Set
2964     'End Property
2965
2966     'Public WriteOnly Property ProxyUser() As String
2967     '    Set(ByVal value As String)
2968     '        _proxyUser = value
2969     '    End Set
2970     'End Property
2971
2972     'Public WriteOnly Property ProxyPassword() As String
2973     '    Set(ByVal value As String)
2974     '        _proxyPassword = value
2975     '    End Set
2976     'End Property
2977
2978     Public WriteOnly Property RestrictFavCheck() As Boolean
2979         Set(ByVal value As Boolean)
2980             _restrictFavCheck = value
2981         End Set
2982     End Property
2983
2984     Public WriteOnly Property IconSize() As Integer
2985         Set(ByVal value As Integer)
2986             _iconSz = value
2987         End Set
2988     End Property
2989
2990     Public Function MakeShortUrl(ByVal ConverterType As UrlConverter, ByVal SrcUrl As String) As String
2991         Dim src As String = urlEncodeMultibyteChar(SrcUrl)
2992         Dim param As New Dictionary(Of String, String)
2993         Dim content As String = ""
2994
2995         For Each svc As String In _ShortUrlService
2996             If SrcUrl.StartsWith(svc) Then
2997                 Return "Can't convert"
2998             End If
2999         Next
3000
3001         'nico.msは短縮しない
3002         If SrcUrl.StartsWith("http://nico.ms/") Then Return "Can't convert"
3003
3004         SrcUrl = HttpUtility.UrlEncode(SrcUrl)
3005
3006         Select Case ConverterType
3007             Case UrlConverter.TinyUrl       'tinyurl
3008                 If SrcUrl.StartsWith("http") Then
3009                     If "http://tinyurl.com/xxxxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
3010                         ' 明らかに長くなると推測できる場合は圧縮しない
3011                         content = src
3012                         Exit Select
3013                     End If
3014                     If Not (New HttpVarious).PostData("http://tinyurl.com/api-create.php?url=" + SrcUrl, Nothing, content) Then
3015                         Return "Can't convert"
3016                     End If
3017                 End If
3018                 If Not content.StartsWith("http://tinyurl.com/") Then
3019                     Return "Can't convert"
3020                 End If
3021             Case UrlConverter.Isgd
3022                 If SrcUrl.StartsWith("http") Then
3023                     If "http://is.gd/xxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
3024                         ' 明らかに長くなると推測できる場合は圧縮しない
3025                         content = src
3026                         Exit Select
3027                     End If
3028                     If Not (New HttpVarious).PostData("http://is.gd/api.php?longurl=" + SrcUrl, Nothing, content) Then
3029                         Return "Can't convert"
3030                     End If
3031                 End If
3032                 If Not content.StartsWith("http://is.gd/") Then
3033                     Return "Can't convert"
3034                 End If
3035             Case UrlConverter.Twurl
3036                 If SrcUrl.StartsWith("http") Then
3037                     If "http://twurl.nl/xxxxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
3038                         ' 明らかに長くなると推測できる場合は圧縮しない
3039                         content = src
3040                         Exit Select
3041                     End If
3042                     param.Add("link[url]", SrcUrl)
3043                     If Not (New HttpVarious).PostData("http://tweetburner.com/links", param, content) Then
3044                         Return "Can't convert"
3045                     End If
3046                 End If
3047                 If Not content.StartsWith("http://twurl.nl/") Then
3048                     Return "Can't convert"
3049                 End If
3050             Case UrlConverter.Unu
3051                 If SrcUrl.StartsWith("http") Then
3052                     If "http://u.nu/xxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
3053                         ' 明らかに長くなると推測できる場合は圧縮しない
3054                         content = src
3055                         Exit Select
3056                     End If
3057                     If Not (New HttpVarious).PostData("http://u.nu/unu-api-simple?url=" + SrcUrl, Nothing, content) Then
3058                         Return "Can't convert"
3059                     End If
3060                 End If
3061                 If Not content.StartsWith("http://u.nu") Then
3062                     Return "Can't convert"
3063                 End If
3064             Case UrlConverter.Bitly, UrlConverter.Jmp
3065                 Dim BitlyLogin As String = "tweenapi"
3066                 Dim BitlyApiKey As String = "R_c5ee0e30bdfff88723c4457cc331886b"
3067                 If _bitlyId <> "" Then
3068                     BitlyLogin = _bitlyId
3069                     BitlyApiKey = _bitlyKey
3070                 End If
3071                 Const BitlyApiVersion As String = "2.0.1"
3072                 If SrcUrl.StartsWith("http") Then
3073                     If "http://bit.ly/xxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
3074                         ' 明らかに長くなると推測できる場合は圧縮しない
3075                         content = src
3076                         Exit Select
3077                     End If
3078                     Dim req As String = ""
3079                     If ConverterType = UrlConverter.Bitly Then
3080                         req = "http://api.bit.ly/shorten?version="
3081                     Else
3082                         req = "http://api.j.mp/shorten?version="
3083                     End If
3084                     req += BitlyApiVersion + _
3085                         "&login=" + BitlyLogin + _
3086                         "&apiKey=" + BitlyApiKey + _
3087                         "&longUrl=" + SrcUrl
3088                     If BitlyLogin <> "tweenapi" Then req += "&history=1"
3089                     If Not (New HttpVarious).PostData(req, Nothing, content) Then
3090                         Return "Can't convert"
3091                     Else
3092                         Dim rx As Regex = New Regex("""shortUrl"": ""(?<ShortUrl>.*?)""")
3093                         If rx.Match(content).Success Then
3094                             content = rx.Match(content).Groups("ShortUrl").Value
3095                         End If
3096                     End If
3097                 End If
3098                 If Not content.StartsWith("http://bit.ly") AndAlso Not content.StartsWith("http://j.mp") Then
3099                     Return "Can't convert"
3100                 End If
3101         End Select
3102         '変換結果から改行を除去
3103         Dim ch As Char() = {ControlChars.Cr, ControlChars.Lf}
3104         content = content.TrimEnd(ch)
3105         If src.Length < content.Length Then content = src ' 圧縮の結果逆に長くなった場合は圧縮前のURLを返す
3106         Return content
3107     End Function
3108
3109     'Public Function MakeShortNicoms(ByVal SrcUrl As String) As String
3110     '    Dim content As String = ""
3111
3112     '    If Not (New HttpVarious).GetData("http://nico.ms/q/" + SrcUrl, Nothing, content) Then
3113     '        Return "Can't convert"
3114     '    End If
3115
3116     '    If content.StartsWith("http") Then
3117     '        Return content
3118     '    Else
3119     '        Return "Can't convert"
3120     '    End If
3121
3122     'End Function
3123
3124 #Region "バージョンアップ"
3125     Public Function GetVersionInfo() As String
3126         Dim content As String = ""
3127         If Not (New HttpVarious).GetData("http://tween.sourceforge.jp/version2.txt?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), Nothing, content) Then
3128             Throw New Exception("GetVersionInfo Failed")
3129         End If
3130         Return content
3131     End Function
3132
3133     Public Function GetTweenBinary(ByVal strVer As String) As String
3134         Try
3135             If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/Tween" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
3136                                                 Path.Combine(Application.StartupPath(), "TweenNew.exe")) Then
3137                 Return "Err:Download failed"
3138             End If
3139             If Directory.Exists(Path.Combine(Application.StartupPath(), "en")) = False Then
3140                 Directory.CreateDirectory(Path.Combine(Application.StartupPath(), "en"))
3141             End If
3142             If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenRes" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
3143                                                 Path.Combine(Application.StartupPath(), "en\Tween.resourcesNew.dll")) Then
3144                 Return "Err:Download failed"
3145             End If
3146             If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenUp.gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
3147                                                 Path.Combine(Application.StartupPath(), "TweenUp.exe")) Then
3148                 Return "Err:Download failed"
3149             End If
3150             If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenDll" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
3151                                                 Path.Combine(Application.StartupPath(), "TweenNew.XmlSerializers.dll")) Then
3152                 Return "Err:Download failed"
3153             End If
3154             Return ""
3155         Catch ex As Exception
3156             Return "Err:Download failed"
3157         End Try
3158     End Function
3159 #End Region
3160
3161     Public WriteOnly Property ListIcon() As ImageList
3162         Set(ByVal value As ImageList)
3163             _lIcon = value
3164         End Set
3165     End Property
3166
3167     Public WriteOnly Property DetailIcon() As Dictionary(Of String, Image)
3168         Set(ByVal value As Dictionary(Of String, Image))
3169             _dIcon = value
3170         End Set
3171     End Property
3172
3173     'Public Property DefaultTimeOut() As Integer
3174     '    Get
3175     '        Return _defaultTimeOut
3176     '    End Get
3177     '    Set(ByVal value As Integer)
3178     '        _defaultTimeOut = value
3179     '    End Set
3180     'End Property
3181
3182     Public WriteOnly Property CountApi() As Integer
3183         'API時の取得件数
3184         Set(ByVal value As Integer)
3185             _countApi = value
3186         End Set
3187     End Property
3188
3189     Public WriteOnly Property CountApiReply() As Integer
3190         'API時のMentions取得件数
3191         Set(ByVal value As Integer)
3192             _countApiReply = value
3193         End Set
3194     End Property
3195
3196     '    Public WriteOnly Property UsePostMethod() As Boolean
3197     '        Set(ByVal value As Boolean)
3198     '            _usePostMethod = False
3199     '#If 0 Then
3200     '            'POSTメソッドが弾かれるためGETに固定(2009/4/9)
3201     '            If value Then
3202     '                _ApiMethod = MySocket.REQ_TYPE.ReqPOSTAPI
3203     '            Else
3204     '                _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI
3205     '            End If
3206     '#Else
3207     '            _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI
3208     '#End If
3209     '        End Set
3210     '    End Property
3211
3212     Public Property ReadOwnPost() As Boolean
3213         Get
3214             Return _readOwnPost
3215         End Get
3216         Set(ByVal value As Boolean)
3217             _readOwnPost = value
3218         End Set
3219     End Property
3220
3221     Public ReadOnly Property FollowersCount() As Integer
3222         Get
3223             Return _followersCount
3224         End Get
3225     End Property
3226
3227     Public ReadOnly Property FriendsCount() As Integer
3228         Get
3229             Return _friendsCount
3230         End Get
3231     End Property
3232
3233     Public ReadOnly Property StatusesCount() As Integer
3234         Get
3235             Return _statusesCount
3236         End Get
3237     End Property
3238
3239     Public ReadOnly Property Location() As String
3240         Get
3241             Return _location
3242         End Get
3243     End Property
3244
3245     Public ReadOnly Property Bio() As String
3246         Get
3247             Return _bio
3248         End Get
3249     End Property
3250
3251     Public WriteOnly Property UseSsl() As Boolean
3252         Set(ByVal value As Boolean)
3253             HttpTwitter.UseSsl = value
3254             If value Then
3255                 _protocol = "https://"
3256             Else
3257                 _protocol = "http://"
3258             End If
3259         End Set
3260     End Property
3261
3262     Public WriteOnly Property BitlyId() As String
3263         Set(ByVal value As String)
3264             _bitlyId = value
3265         End Set
3266     End Property
3267
3268     Public WriteOnly Property BitlyKey() As String
3269         Set(ByVal value As String)
3270             _bitlyKey = value
3271         End Set
3272     End Property
3273
3274     Public Function GetTimelineApi(ByVal read As Boolean, _
3275                             ByVal gType As WORKERTYPE, _
3276                             ByVal more As Boolean) As String
3277
3278         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3279
3280         If _endingFlag Then Return ""
3281
3282         Dim countQuery As Integer
3283         Dim res As HttpStatusCode
3284         Dim content As String = ""
3285         Try
3286             If gType = WORKERTYPE.Timeline Then
3287                 If more Then
3288                     res = twCon.HomeTimeline(_countApi, minHomeTimeline, 0, content)
3289                 Else
3290                     res = twCon.HomeTimeline(_countApi, 0, 0, content)
3291                 End If
3292                 countQuery = _countApi
3293             Else
3294                 If more Then
3295                     res = twCon.Mentions(_countApiReply, minMentions, 0, content)
3296                 Else
3297                     res = twCon.Mentions(_countApiReply, 0, 0, content)
3298                 End If
3299                 countQuery = _countApiReply
3300             End If
3301         Catch ex As Exception
3302             Return "Err:" + ex.Message
3303         End Try
3304         Select Case res
3305             Case HttpStatusCode.OK
3306             Case HttpStatusCode.Unauthorized
3307                 Twitter.AccountState = ACCOUNT_STATE.Invalid
3308                 Return "Check your Username/Password."
3309             Case HttpStatusCode.BadRequest
3310                 Return "Err:API Limits?"
3311             Case Else
3312                 Return "Err:" + res.ToString()
3313         End Select
3314
3315         Dim arIdx As Integer = -1
3316         Dim dlgt(countQuery) As GetIconImageDelegate    'countQueryに合わせる
3317         Dim ar(countQuery) As IAsyncResult              'countQueryに合わせる
3318         Dim xdoc As New XmlDocument
3319         Try
3320             xdoc.LoadXml(content)
3321         Catch ex As Exception
3322             TraceOut(content)
3323             'MessageBox.Show("不正なXMLです。(TL-LoadXml)")
3324             Return "Invalid XML!"
3325         End Try
3326
3327         For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("./status")
3328             Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3329             Dim post As New PostClass
3330             Try
3331                 post.Id = Long.Parse(xentry.Item("id").InnerText)
3332                 If gType = WORKERTYPE.Timeline Then
3333                     If minHomeTimeline > post.Id Then minHomeTimeline = post.Id
3334                 Else
3335                     If minMentions > post.Id Then minMentions = post.Id
3336                 End If
3337                 '二重取得回避
3338                 SyncLock LockObj
3339                     If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
3340                 End SyncLock
3341                 'Retweet判定
3342                 Dim xRnode As XmlNode = xentry.SelectSingleNode("./retweeted_status")
3343                 If xRnode IsNot Nothing Then
3344                     Dim xRentry As XmlElement = CType(xRnode, XmlElement)
3345                     post.PDate = DateTime.ParseExact(xRentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
3346                     'Id
3347                     post.RetweetedId = Long.Parse(xRentry.Item("id").InnerText)
3348                     '本文
3349                     post.Data = xRentry.Item("text").InnerText
3350                     'Source取得(htmlの場合は、中身を取り出し)
3351                     post.Source = xRentry.Item("source").InnerText
3352                     'Reply先
3353                     Long.TryParse(xRentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3354                     post.InReplyToUser = xRentry.Item("in_reply_to_screen_name").InnerText
3355                     'post.IsFav = TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Contains(post.RetweetedId)
3356                     post.IsFav = Boolean.Parse(xentry.Item("favorited").InnerText)
3357
3358                     '以下、ユーザー情報
3359                     Dim xRUentry As XmlElement = CType(xRentry.SelectSingleNode("./user"), XmlElement)
3360                     post.Uid = Long.Parse(xRUentry.Item("id").InnerText)
3361                     post.Name = xRUentry.Item("screen_name").InnerText
3362                     post.Nickname = xRUentry.Item("name").InnerText
3363                     post.ImageUrl = xRUentry.Item("profile_image_url").InnerText
3364                     post.IsProtect = Boolean.Parse(xRUentry.Item("protected").InnerText)
3365                     post.IsMe = post.Name.ToLower.Equals(_uid)
3366
3367                     'Retweetした人
3368                     Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3369                     post.RetweetedBy = xUentry.Item("screen_name").InnerText
3370                 Else
3371                     post.PDate = DateTime.ParseExact(xentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
3372                     '本文
3373                     post.Data = xentry.Item("text").InnerText
3374                     'Source取得(htmlの場合は、中身を取り出し)
3375                     post.Source = xentry.Item("source").InnerText
3376                     Long.TryParse(xentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3377                     post.InReplyToUser = xentry.Item("in_reply_to_screen_name").InnerText
3378                     'in_reply_to_user_idを使うか?
3379                     post.IsFav = Boolean.Parse(xentry.Item("favorited").InnerText)
3380
3381                     '以下、ユーザー情報
3382                     Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3383                     post.Uid = Long.Parse(xUentry.Item("id").InnerText)
3384                     post.Name = xUentry.Item("screen_name").InnerText
3385                     post.Nickname = xUentry.Item("name").InnerText
3386                     post.ImageUrl = xUentry.Item("profile_image_url").InnerText
3387                     post.IsProtect = Boolean.Parse(xUentry.Item("protected").InnerText)
3388                     post.IsMe = post.Name.ToLower.Equals(_uid)
3389                 End If
3390                 'HTMLに整形
3391                 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3392                 post.Data = HttpUtility.HtmlDecode(post.Data)
3393                 post.Data = post.Data.Replace("<3", "♡")
3394                 'Source整形
3395                 If post.Source.StartsWith("<") Then
3396                     Dim rgS As New Regex(">(?<source>.+)<")
3397                     Dim mS As Match = rgS.Match(post.Source)
3398                     If mS.Success Then
3399                         post.Source = mS.Result("${source}")
3400                     End If
3401                 End If
3402
3403                 post.IsRead = read
3404                 If gType = WORKERTYPE.Timeline Then
3405                     post.IsReply = post.ReplyToList.Contains(_uid)
3406                 Else
3407                     post.IsReply = True
3408                 End If
3409
3410                 If post.IsMe Then
3411                     post.IsOwl = False
3412                 Else
3413                     If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.Uid)
3414                 End If
3415                 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
3416
3417                 post.IsDm = False
3418             Catch ex As Exception
3419                 TraceOut(content)
3420                 'MessageBox.Show("不正なXMLです。(TL-Parse)")
3421                 Continue For
3422             End Try
3423
3424             '非同期アイコン取得&StatusDictionaryに追加
3425             arIdx += 1
3426             dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3427             ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3428         Next
3429
3430         'アイコン取得完了待ち
3431         For i As Integer = 0 To arIdx
3432             Try
3433                 dlgt(i).EndInvoke(ar(i))
3434             Catch ex As Exception
3435                 '最後までendinvoke回す(ゾンビ化回避)
3436                 ex.Data("IsTerminatePermission") = False
3437                 Throw
3438             End Try
3439         Next
3440
3441         'If _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI Then _remainCountApi = sck.RemainCountApi
3442
3443         Return ""
3444     End Function
3445
3446     Public Function GetSearch(ByVal read As Boolean, _
3447                             ByVal tab As TabClass, _
3448                             ByVal more As Boolean) As String
3449
3450         If _endingFlag Then Return ""
3451
3452         Dim res As HttpStatusCode
3453         Dim content As String = ""
3454         Dim page As Integer = 0
3455         If more Then page = tab.SearchPage
3456         Try
3457             res = twCon.Search(tab.SearchWords, tab.SearchLang, 40, page, content)
3458         Catch ex As Exception
3459             Return "Err:" + ex.Message
3460         End Try
3461         Select Case res
3462             Case HttpStatusCode.BadRequest
3463                 Return "Invalid query"
3464             Case HttpStatusCode.NotFound
3465                 Return "Invalid query"
3466             Case HttpStatusCode.PaymentRequired 'API Documentには420と書いてあるが、該当コードがないので402にしてある
3467                 Return "Search API Limit?"
3468             Case HttpStatusCode.OK
3469             Case Else
3470                 Return "Err:" + res.ToString
3471         End Select
3472
3473         If Not TabInformations.GetInstance.ContainsTab(tab) Then Return ""
3474
3475         Dim arIdx As Integer = -1
3476         Dim dlgt(40) As GetIconImageDelegate    'countQueryに合わせる
3477         Dim ar(40) As IAsyncResult              'countQueryに合わせる
3478         Dim xdoc As New XmlDocument
3479         Try
3480             xdoc.LoadXml(content)
3481         Catch ex As Exception
3482             TraceOut(content)
3483             Return "Invalid ATOM!"
3484         End Try
3485         Dim nsmgr As New XmlNamespaceManager(xdoc.NameTable)
3486         nsmgr.AddNamespace("search", "http://www.w3.org/2005/Atom")
3487         For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/search:feed/search:entry", nsmgr)
3488             Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3489             Dim post As New PostClass
3490             Try
3491                 post.Id = Long.Parse(xentry.Item("id").InnerText.Split(":"c)(2))
3492                 If TabInformations.GetInstance.ContainsKey(post.Id, tab.TabName) Then Continue For
3493                 post.PDate = DateTime.Parse(xentry.Item("published").InnerText)
3494                 '本文
3495                 post.Data = xentry.Item("title").InnerText
3496                 'Source取得(htmlの場合は、中身を取り出し)
3497                 post.Source = xentry.Item("twitter:source").InnerText
3498                 post.InReplyToId = 0
3499                 post.InReplyToUser = ""
3500                 post.IsFav = False
3501
3502                 '以下、ユーザー情報
3503                 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./search:author", nsmgr), XmlElement)
3504                 post.Uid = 0
3505                 post.Name = xUentry.Item("name").InnerText.Split(" "c)(0).Trim
3506                 post.Nickname = xUentry.Item("name").InnerText.Substring(post.Name.Length).Trim
3507                 If post.Nickname.Length > 2 Then
3508                     post.Nickname = post.Nickname.Substring(1, post.Nickname.Length - 2)
3509                 Else
3510                     post.Nickname = post.Name
3511                 End If
3512                 post.ImageUrl = CType(xentry.SelectSingleNode("./search:link[@type='image/png']", nsmgr), XmlElement).GetAttribute("href")
3513                 post.IsProtect = False
3514                 post.IsMe = post.Name.ToLower.Equals(_uid)
3515
3516                 'HTMLに整形
3517                 post.OriginalData = CreateHtmlAnchor(HttpUtility.HtmlEncode(post.Data), post.ReplyToList)
3518                 post.Data = HttpUtility.HtmlDecode(post.Data)
3519                 'Source整形
3520                 If post.Source.StartsWith("<") Then
3521                     Dim rgS As New Regex(">(?<source>.+)<")
3522                     Dim mS As Match = rgS.Match(post.Source)
3523                     If mS.Success Then
3524                         post.Source = mS.Result("${source}")
3525                     End If
3526                 End If
3527
3528                 post.IsRead = read
3529                 post.IsReply = post.ReplyToList.Contains(_uid)
3530
3531                 post.IsOwl = False
3532                 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
3533                 post.IsDm = False
3534                 post.SearchTabName = tab.TabName
3535             Catch ex As Exception
3536                 TraceOut(content)
3537                 Continue For
3538             End Try
3539
3540             '非同期アイコン取得&StatusDictionaryに追加
3541             arIdx += 1
3542             dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3543             ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3544         Next
3545
3546         '' TODO
3547         '' 遡るための情報max_idやnext_pageの情報を保持する
3548
3549         'アイコン取得完了待ち
3550         For i As Integer = 0 To arIdx
3551             Try
3552                 dlgt(i).EndInvoke(ar(i))
3553             Catch ex As Exception
3554                 '最後までendinvoke回す(ゾンビ化回避)
3555                 ex.Data("IsTerminatePermission") = False
3556                 Throw
3557             End Try
3558         Next
3559
3560         Return ""
3561     End Function
3562
3563     Public Function GetDirectMessageApi(ByVal read As Boolean, _
3564                             ByVal gType As WORKERTYPE, _
3565                             ByVal more As Boolean) As String
3566         If _endingFlag Then Return ""
3567
3568         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3569
3570         Dim res As HttpStatusCode
3571         Dim content As String = ""
3572
3573         Try
3574             If gType = WORKERTYPE.DirectMessegeRcv Then
3575                 If more Then
3576                     res = twCon.DirectMessages(20, minDirectmessage, 0, content)
3577                 Else
3578                     res = twCon.DirectMessages(20, 0, 0, content)
3579                 End If
3580             Else
3581                 If more Then
3582                     res = twCon.DirectMessagesSent(20, minDirectmessageSent, 0, content)
3583                 Else
3584                     res = twCon.DirectMessagesSent(20, 0, 0, content)
3585                 End If
3586             End If
3587         Catch ex As Exception
3588             Return "Err:" + ex.Message
3589         End Try
3590
3591         Select Case res
3592             Case HttpStatusCode.OK
3593             Case HttpStatusCode.Unauthorized
3594                 Twitter.AccountState = ACCOUNT_STATE.Invalid
3595                 Return "Check your Username/Password."
3596             Case HttpStatusCode.BadRequest
3597                 Return "Err:API Limits?"
3598             Case Else
3599                 Return "Err:" + res.ToString()
3600         End Select
3601
3602         Dim arIdx As Integer = -1
3603         Dim dlgt(20) As GetIconImageDelegate    'countQueryに合わせる
3604         Dim ar(20) As IAsyncResult              'countQueryに合わせる
3605         Dim xdoc As New XmlDocument
3606         Try
3607             xdoc.LoadXml(content)
3608         Catch ex As Exception
3609             TraceOut(content)
3610             'MessageBox.Show("不正なXMLです。(DM-LoadXml)")
3611             Return "Invalid XML!"
3612         End Try
3613
3614         For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("./direct_message")
3615             Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3616             Dim post As New PostClass
3617             Try
3618                 post.Id = Long.Parse(xentry.Item("id").InnerText)
3619                 If gType = WORKERTYPE.DirectMessegeRcv Then
3620                     If minDirectmessage > post.Id Then minDirectmessage = post.Id
3621                 Else
3622                     If minDirectmessageSent > post.Id Then minDirectmessageSent = post.Id
3623                 End If
3624                 '二重取得回避
3625                 SyncLock LockObj
3626                     If TabInformations.GetInstance.GetTabByType(TabUsageType.DirectMessage).Contains(post.Id) Then Continue For
3627                 End SyncLock
3628                 'sender_id
3629                 'recipient_id
3630                 post.PDate = DateTime.ParseExact(xentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
3631                 '本文
3632                 post.Data = xentry.Item("text").InnerText
3633                 'HTMLに整形
3634                 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3635                 post.Data = HttpUtility.HtmlDecode(post.Data)
3636                 post.Data = post.Data.Replace("<3", "♡")
3637                 post.IsFav = False
3638                 '受信DMかの判定で使用
3639                 If gType = WORKERTYPE.DirectMessegeRcv Then
3640                     post.IsOwl = False
3641                 Else
3642                     post.IsOwl = True
3643                 End If
3644
3645                 '以下、ユーザー情報
3646                 Dim xUentry As XmlElement
3647                 If gType = WORKERTYPE.DirectMessegeRcv Then
3648                     xUentry = CType(xentry.SelectSingleNode("./sender"), XmlElement)
3649                     post.IsMe = False
3650                 Else
3651                     xUentry = CType(xentry.SelectSingleNode("./recipient"), XmlElement)
3652                     post.IsMe = True
3653                 End If
3654                 post.Uid = Long.Parse(xUentry.Item("id").InnerText)
3655                 post.Name = xUentry.Item("screen_name").InnerText
3656                 post.Nickname = xUentry.Item("name").InnerText
3657                 post.ImageUrl = xUentry.Item("profile_image_url").InnerText
3658                 post.IsProtect = Boolean.Parse(xUentry.Item("protected").InnerText)
3659             Catch ex As Exception
3660                 TraceOut(content)
3661                 'MessageBox.Show("不正なXMLです。(DM-Parse)")
3662                 Continue For
3663             End Try
3664
3665             post.IsRead = read
3666             post.IsReply = False
3667             post.IsDm = True
3668
3669             '非同期アイコン取得&StatusDictionaryに追加
3670             arIdx += 1
3671             dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3672             ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3673         Next
3674
3675         'アイコン取得完了待ち
3676         For i As Integer = 0 To arIdx
3677             Try
3678                 dlgt(i).EndInvoke(ar(i))
3679             Catch ex As Exception
3680                 '最後までendinvoke回す(ゾンビ化回避)
3681                 ex.Data("IsTerminatePermission") = False
3682                 Throw
3683             End Try
3684         Next
3685
3686         '_remainCountApi = sck.RemainCountApi
3687         'If _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI Then _remainCountApi = sck.RemainCountApi
3688
3689         Return ""
3690     End Function
3691
3692     Public Function GetFavoritesApi(ByVal read As Boolean, _
3693                         ByVal gType As WORKERTYPE) As String
3694
3695         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3696
3697         If _endingFlag Then Return ""
3698
3699         Dim res As HttpStatusCode
3700         Dim content As String = ""
3701         Try
3702             res = twCon.Favorites(_countApi, content)
3703         Catch ex As Exception
3704             Return "Err:" + ex.Message
3705         End Try
3706
3707         Select Case res
3708             Case HttpStatusCode.OK
3709             Case HttpStatusCode.Unauthorized
3710                 Twitter.AccountState = ACCOUNT_STATE.Invalid
3711                 Return "Check your Username/Password."
3712             Case HttpStatusCode.BadRequest
3713                 Return "Err:API Limits?"
3714             Case Else
3715                 Return "Err:" + res.ToString()
3716         End Select
3717
3718         Dim arIdx As Integer = -1
3719         Dim dlgt(_countApi) As GetIconImageDelegate    'countQueryに合わせる
3720         Dim ar(_countApi) As IAsyncResult              'countQueryに合わせる
3721         Dim xdoc As New XmlDocument
3722         Try
3723             xdoc.LoadXml(content)
3724         Catch ex As Exception
3725             TraceOut(content)
3726             'MessageBox.Show("不正なXMLです。(TL-LoadXml)")
3727             Return "Invalid XML!"
3728         End Try
3729
3730         For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("./status")
3731             Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3732             Dim post As New PostClass
3733             Try
3734                 post.Id = Long.Parse(xentry.Item("id").InnerText)
3735                 If minFavorites > post.Id Then minFavorites = post.Id
3736                 '二重取得回避
3737                 SyncLock LockObj
3738                     If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
3739                 End SyncLock
3740                 'Retweet判定
3741                 Dim xRnode As XmlNode = xentry.SelectSingleNode("./retweeted_status")
3742                 If xRnode IsNot Nothing Then
3743                     Dim xRentry As XmlElement = CType(xRnode, XmlElement)
3744                     post.PDate = DateTime.ParseExact(xRentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
3745                     'Id
3746                     post.RetweetedId = Long.Parse(xRentry.Item("id").InnerText)
3747                     '本文
3748                     post.Data = xRentry.Item("text").InnerText
3749                     'Source取得(htmlの場合は、中身を取り出し)
3750                     post.Source = xRentry.Item("source").InnerText
3751                     'Reply先
3752                     Long.TryParse(xRentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3753                     post.InReplyToUser = xRentry.Item("in_reply_to_screen_name").InnerText
3754                     'in_reply_to_user_idを使うか?
3755                     post.IsFav = Boolean.Parse(xRentry.Item("favorited").InnerText)
3756
3757                     '以下、ユーザー情報
3758                     Dim xRUentry As XmlElement = CType(xRentry.SelectSingleNode("./user"), XmlElement)
3759                     post.Uid = Long.Parse(xRUentry.Item("id").InnerText)
3760                     post.Name = xRUentry.Item("screen_name").InnerText
3761                     post.Nickname = xRUentry.Item("name").InnerText
3762                     post.ImageUrl = xRUentry.Item("profile_image_url").InnerText
3763                     post.IsProtect = Boolean.Parse(xRUentry.Item("protected").InnerText)
3764                     post.IsMe = post.Name.ToLower.Equals(_uid)
3765
3766                     'Retweetした人
3767                     Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3768                     post.RetweetedBy = xUentry.Item("screen_name").InnerText
3769                 Else
3770                     post.PDate = DateTime.ParseExact(xentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
3771                     '本文
3772                     post.Data = xentry.Item("text").InnerText
3773                     'Source取得(htmlの場合は、中身を取り出し)
3774                     post.Source = xentry.Item("source").InnerText
3775                     Long.TryParse(xentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3776                     post.InReplyToUser = xentry.Item("in_reply_to_screen_name").InnerText
3777                     'in_reply_to_user_idを使うか?
3778                     post.IsFav = Boolean.Parse(xentry.Item("favorited").InnerText)
3779
3780                     '以下、ユーザー情報
3781                     Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3782                     post.Uid = Long.Parse(xUentry.Item("id").InnerText)
3783                     post.Name = xUentry.Item("screen_name").InnerText
3784                     post.Nickname = xUentry.Item("name").InnerText
3785                     post.ImageUrl = xUentry.Item("profile_image_url").InnerText
3786                     post.IsProtect = Boolean.Parse(xUentry.Item("protected").InnerText)
3787                     post.IsMe = post.Name.ToLower.Equals(_uid)
3788                 End If
3789                 'HTMLに整形
3790                 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3791                 post.Data = HttpUtility.HtmlDecode(post.Data)
3792                 post.Data = post.Data.Replace("<3", "♡")
3793                 'Source整形
3794                 If post.Source.StartsWith("<") Then
3795                     Dim rgS As New Regex(">(?<source>.+)<")
3796                     Dim mS As Match = rgS.Match(post.Source)
3797                     If mS.Success Then
3798                         post.Source = mS.Result("${source}")
3799                     End If
3800                 End If
3801
3802                 post.IsRead = read
3803                 post.IsReply = post.ReplyToList.Contains(_uid)
3804
3805                 If post.IsMe Then
3806                     post.IsOwl = False
3807                 Else
3808                     If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.Uid)
3809                 End If
3810
3811                 post.IsDm = False
3812             Catch ex As Exception
3813                 TraceOut(content)
3814                 'MessageBox.Show("不正なXMLです。(TL-Parse)")
3815                 Continue For
3816             End Try
3817
3818             '非同期アイコン取得&StatusDictionaryに追加
3819             arIdx += 1
3820             dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3821             ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3822         Next
3823
3824         'アイコン取得完了待ち
3825         For i As Integer = 0 To arIdx
3826             Try
3827                 dlgt(i).EndInvoke(ar(i))
3828             Catch ex As Exception
3829                 '最後までendinvoke回す(ゾンビ化回避)
3830                 ex.Data("IsTerminatePermission") = False
3831                 Throw
3832             End Try
3833         Next
3834
3835         '_remainCountApi = sck.RemainCountApi
3836         'If _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI Then _remainCountApi = sck.RemainCountApi
3837
3838         Return ""
3839     End Function
3840
3841     Public Function GetFollowersApi() As String
3842         If _endingFlag Then Return ""
3843         Dim cursor As Long = -1
3844         Dim tmpFollower As New List(Of Long)(followerId)
3845
3846         followerId.Clear()
3847         Do
3848             Dim ret As String = FollowerApi(cursor)
3849             If ret <> "" Then
3850                 followerId.Clear()
3851                 followerId.AddRange(tmpFollower)
3852                 Return ret
3853             End If
3854         Loop While cursor > 0
3855
3856         TabInformations.GetInstance.RefreshOwl(followerId)
3857
3858         Return ""
3859     End Function
3860
3861     Private Function FollowerApi(ByRef cursor As Long) As String
3862         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3863
3864         Dim res As HttpStatusCode
3865         Dim content As String = ""
3866         Try
3867             res = twCon.FollowerIds(cursor, content)
3868         Catch ex As Exception
3869             Return "Err:" + ex.Message
3870         End Try
3871
3872         Select Case res
3873             Case HttpStatusCode.OK
3874             Case HttpStatusCode.Unauthorized
3875                 Twitter.AccountState = ACCOUNT_STATE.Invalid
3876                 Return "Check your Username/Password."
3877             Case HttpStatusCode.BadRequest
3878                 Return "Err:API Limits?"
3879             Case Else
3880                 Return "Err:" + res.ToString()
3881         End Select
3882
3883         Dim xdoc As New XmlDocument
3884         Try
3885             xdoc.LoadXml(content)
3886         Catch ex As Exception
3887             TraceOut(content)
3888             Return "Invalid XML!"
3889         End Try
3890
3891         Try
3892             For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/id_list/ids/id")
3893                 followerId.Add(Long.Parse(xentryNode.InnerText))
3894             Next
3895             cursor = Long.Parse(xdoc.DocumentElement.SelectSingleNode("/id_list/next_cursor").InnerText)
3896         Catch ex As Exception
3897             TraceOut(content)
3898             Return "Invalid XML!"
3899         End Try
3900
3901         Return ""
3902
3903     End Function
3904
3905     Private Function CreateHtmlAnchor(ByVal Text As String, ByVal AtList As List(Of String)) As String
3906         'Dim retStr As String = HttpUtility.HtmlEncode(Text)     '要検証(デコードされて取得されるので再エンコード)
3907         'Dim retStr As String = HttpUtility.HtmlDecode(Text)
3908         Dim retStr As String = ""
3909         'uriの正規表現
3910         'Dim rgUrl As Regex = New Regex("(?<![0-9A-Za-z=])(?:https?|shttp|ftps?)://(?:(?:[-_.!~*'()a-zA-Z0-9;:&=+$,]|%[0-9A-Fa-f" + _
3911         '                 "][0-9A-Fa-f])*@)?(?:(?:[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?\.)" + _
3912         '                 "*[a-zA-Z](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?\.?|[0-9]+\.[0-9]+\.[0-9]+\." + _
3913         '                 "[0-9]+)(?::[0-9]*)?(?:/(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f]" + _
3914         '                 "[0-9A-Fa-f])*(?:;(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f][0-9A-" + _
3915         '                 "Fa-f])*)*(?:/(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f" + _
3916         '                 "])*(?:;(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f])*)*)" + _
3917         '                 "*)?(?:\?(?:[-_.!~*'()a-zA-Z0-9;/?:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f])" + _
3918         '                 "*)?(?:#(?:[-_.!~*'()a-zA-Z0-9;/?:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f])*)?")
3919         Dim rgUrl As Regex = New Regex("(?<before>(?:[^\/""':!=]|^|\:))" + _
3920                                     "(?<url>(?<protocol>https?://|www\.)" + _
3921                                     "(?<domain>(?:[\.-]|[^\p{P}])+\.[a-z]{2,}(?::[0-9]+)?)" + _
3922                                     "(?<path>/[a-z0-9!*'();:&=+$/%#\[\]\-_.,~]*[a-z0-9)=#/]?)?" + _
3923                                     "(?<query>\?[a-z0-9!*'();:&=+$/%#\[\]\-_.,~]*[a-z0-9_&=#])?)", RegexOptions.IgnoreCase Or RegexOptions.Compiled)
3924         '絶対パス表現のUriをリンクに置換
3925         retStr = rgUrl.Replace(Text, New MatchEvaluator(AddressOf AutoLinkUrl))
3926
3927         '@返信を抽出し、@先リスト作成
3928         'Dim rg As New Regex("(^|[ -/:-@[-^`{-~])@([a-zA-Z0-9_]{1,20}/[a-zA-Z0-9_\-]{1,24}[a-zA-Z0-9_])")
3929         Dim rg As New Regex("(^|[^a-zA-Z0-9_])[@@]([a-zA-Z0-9_]{1,20}/[a-zA-Z0-9_\-]{1,79}[a-zA-Z0-9_])", RegexOptions.Compiled)
3930         Dim m As Match = rg.Match(retStr)
3931         '@先をリンクに置換
3932         retStr = rg.Replace(retStr, "$1@<a href=""/$2"">$2</a>")
3933
3934         'rg = New Regex("(^|[ -/:-@[-^`{-~])@([a-zA-Z0-9_]{1,20})")
3935         rg = New Regex("(^|[^a-zA-Z0-9_])[@@]([a-zA-Z0-9_]{1,20})", RegexOptions.Compiled)
3936         m = rg.Match(retStr)
3937         While m.Success
3938             AtList.Add(m.Result("$2").ToLower)
3939             m = m.NextMatch
3940         End While
3941         '@先をリンクに置換
3942         retStr = rg.Replace(retStr, "$1@<a href=""/$2"">$2</a>")
3943
3944         'ハッシュタグを抽出し、リンクに置換
3945         'Dim rgh As New Regex("(^|[ .!,\-:;<>?])#([^] !""#$%&'()*+,.:;<=>?@\-[\^`{|}~\r\n]+)")
3946         Dim rgh As New Regex("(^|[^a-zA-Z0-9_/&])[##]([a-zA-Z0-9_]+)", RegexOptions.Compiled)
3947         Dim mhs As MatchCollection = rgh.Matches(retStr)
3948         For Each mt As Match In mhs
3949             If Not IsNumeric(mt.Result("$2")) Then
3950                 'retStr = retStr.Replace(mt.Result("$1") + mt.Result("$2"), "<a href=""" + _protocol + "twitter.com/search?q=%23" + mt.Result("$2") + """>#" + mt.Result("$2") + "</a>")
3951                 SyncLock LockObj
3952                     _hashList.Add("#" + mt.Result("$2"))
3953                 End SyncLock
3954             End If
3955         Next
3956         retStr = rgh.Replace(retStr, New MatchEvaluator(AddressOf AutoLinkHashtag))
3957
3958         retStr = AdjustHtml(ShortUrlResolve(PreProcessUrl(retStr))) 'IDN置換、短縮Uri解決、@リンクを相対→絶対にしてtarget属性付与
3959         Return retStr
3960     End Function
3961
3962     Private Function AutoLinkUrl(ByVal m As Match) As String
3963         Dim sb As New StringBuilder(m.Result("${before}<a href="""))
3964         If m.Result("${protocol}").StartsWith("w", StringComparison.OrdinalIgnoreCase) Then
3965             sb.Append("http://")
3966         End If
3967         sb.Append(m.Result("${url}"">")).Append(m.Result("${url}")).Append("</a>")
3968         Return sb.ToString
3969     End Function
3970
3971     Private Function AutoLinkHashtag(ByVal m As Match) As String
3972         If IsNumeric(m.Result("$2")) Then Return m.Result("$1#$2")
3973         Dim sb As New StringBuilder(m.Result("$1<a href="""))
3974         Return sb.Append(_protocol).Append("twitter.com/search?q=%23").Append(m.Result("$2"">#$2</a>")).ToString
3975     End Function
3976
3977     Public ReadOnly Property RemainCountApi() As Integer
3978         Get
3979             Return twCon.RemainCountApi
3980         End Get
3981     End Property
3982
3983     Public Function GetInfoApi(ByRef info As ApiInfo) As Boolean
3984         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return True
3985
3986         If _endingFlag Then Return True
3987
3988         'info.MaxCount = twCon.UpperCountApi
3989         'info.RemainCount = twCon.RemainCountApi
3990         'info.ResetTime = twCon.ResetTimeApi
3991         'Return True
3992         Dim res As HttpStatusCode
3993         Dim content As String = ""
3994         Try
3995             res = twCon.RateLimitStatus(content)
3996         Catch ex As Exception
3997             Return False
3998         End Try
3999
4000         If res <> HttpStatusCode.OK Then Return False
4001
4002         Dim xdoc As New XmlDocument
4003         Try
4004             xdoc.LoadXml(content)
4005             info.MaxCount = Integer.Parse(xdoc.SelectSingleNode("/hash/hourly-limit").InnerText)
4006             info.RemainCount = Integer.Parse(xdoc.SelectSingleNode("/hash/remaining-hits").InnerText)
4007             info.ResetTime = DateTime.Parse(xdoc.SelectSingleNode("/hash/reset-time").InnerText)
4008             'info.ResetTimeInSeconds = Integer.Parse(xdoc.SelectSingleNode("/hash/reset-time-in-seconds").InnerText)
4009             Return True
4010         Catch ex As Exception
4011             Return False
4012         End Try
4013     End Function
4014
4015     Public Function GetHashList() As String()
4016         Dim hashArray As String()
4017         SyncLock LockObj
4018             hashArray = _hashList.ToArray
4019             _hashList.Clear()
4020         End SyncLock
4021         Return hashArray
4022     End Function
4023
4024     '#Region "デバッグモード解析キー自動生成"
4025     '#If DEBUG Then
4026     '    Public Sub GenerateAnalyzeKey()
4027     '        '解析キー情報部分のソースをwedataから作成する
4028     '        '生成したソースはプロジェクトのディレクトリにコピーする
4029     '        Dim sw As New System.IO.StreamWriter(".\AnalyzeKey.vb", _
4030     '            False, _
4031     '            System.Text.Encoding.UTF8)
4032
4033     '        sw.WriteLine("Public Module AnalyzeKey")
4034     '        sw.WriteLine("'    このファイルはデバッグビルドのTweenにより自動作成されました   作成日時  " + DateAndTime.Now.ToString())
4035     '        sw.WriteLine("")
4036
4037     '        sw.WriteLine("    Public _splitPost As String = " + Chr(34) + _splitPost.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4038     '        sw.WriteLine("    Public _splitPostRecent As String = " + Chr(34) + _splitPostRecent.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4039     '        sw.WriteLine("    Public _statusIdTo As String = " + Chr(34) + _statusIdTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4040     '        sw.WriteLine("    Public _splitDM As String = " + Chr(34) + _splitDM.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4041     '        sw.WriteLine("    Public _parseName As String = " + Chr(34) + _parseName.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4042     '        sw.WriteLine("    Public _parseNameTo As String = " + Chr(34) + _parseNameTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4043     '        sw.WriteLine("    Public _parseNick As String = " + Chr(34) + _parseNick.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4044     '        sw.WriteLine("    Public _parseNickTo As String = " + Chr(34) + _parseNickTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4045     '        sw.WriteLine("    Public _parseImg As String = " + Chr(34) + _parseImg.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4046     '        sw.WriteLine("    Public _parseImgTo As String = " + Chr(34) + _parseImgTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4047     '        sw.WriteLine("    Public _parseMsg1 As String = " + Chr(34) + _parseMsg1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4048     '        sw.WriteLine("    Public _parseMsg2 As String = " + Chr(34) + _parseMsg2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4049     '        sw.WriteLine("    Public _parseDM1 As String = " + Chr(34) + _parseDM1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4050     '        sw.WriteLine("    Public _parseDM11 As String = " + Chr(34) + _parseDM11.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4051     '        sw.WriteLine("    Public _parseDM2 As String = " + Chr(34) + _parseDM2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4052     '        sw.WriteLine("    Public _parseDate As String = " + Chr(34) + _parseDate.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4053     '        sw.WriteLine("    Public _parseDateTo As String = " + Chr(34) + _parseDateTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4054     '        sw.WriteLine("    Public _getAuthKey As String = " + Chr(34) + _getAuthKey.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4055     '        sw.WriteLine("    Public _getAuthKeyTo As String = " + Chr(34) + _getAuthKeyTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4056     '        'sw.WriteLine("    Public _parseStar As String = " + Chr(34) + _parseStar.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4057     '        'sw.WriteLine("    Public _parseStarTo As String = " + Chr(34) + _parseStarTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4058     '        'sw.WriteLine("    Public _parseStarEmpty As String = " + Chr(34) + _parseStarEmpty.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4059     '        sw.WriteLine("    Public _followerList As String = " + Chr(34) + _followerList.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4060     '        sw.WriteLine("    Public _followerMbr1 As String = " + Chr(34) + _followerMbr1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4061     '        sw.WriteLine("    Public _followerMbr2 As String = " + Chr(34) + _followerMbr2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4062     '        sw.WriteLine("    Public _followerMbr3 As String = " + Chr(34) + _followerMbr3.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4063     '        sw.WriteLine("    Public _getInfoTwitter As String = " + Chr(34) + _getInfoTwitter.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4064     '        sw.WriteLine("    Public _getInfoTwitterTo As String = " + Chr(34) + _getInfoTwitterTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4065     '        sw.WriteLine("    Public _isProtect As String = " + Chr(34) + _isProtect.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4066     '        sw.WriteLine("    Public _isReplyEng As String = " + Chr(34) + _isReplyEng.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4067     '        sw.WriteLine("    Public _isReplyJpn As String = " + Chr(34) + _isReplyJpn.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4068     '        sw.WriteLine("    Public _isReplyTo As String = " + Chr(34) + _isReplyTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4069     '        sw.WriteLine("    Public _parseProtectMsg1 As String = " + Chr(34) + _parseProtectMsg1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4070     '        sw.WriteLine("    Public _parseProtectMsg2 As String = " + Chr(34) + _parseProtectMsg2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4071     '        sw.WriteLine("    Public _parseDMcountFrom As String = " + Chr(34) + _parseDMcountFrom.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4072     '        sw.WriteLine("    Public _parseDMcountTo As String = " + Chr(34) + _parseDMcountTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4073     '        sw.WriteLine("    Public _parseSourceFrom As String = " + Chr(34) + _parseSourceFrom.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4074     '        sw.WriteLine("    Public _parseSource2 As String = " + Chr(34) + _parseSource2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4075     '        sw.WriteLine("    Public _parseSourceTo As String = " + Chr(34) + _parseSourceTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4076     '        sw.WriteLine("    Public _removeClass As String = " + Chr(34) + _removeClass.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4077     '        sw.WriteLine("End Module")
4078
4079     '        sw.Close()
4080     '        'MessageBox.Show("解析キー情報定義ファイル AnalyzeKey.vbを生成しました")
4081
4082     '    End Sub
4083     '#End If
4084     '#End Region
4085
4086     Public ReadOnly Property AccessToken() As String
4087         Get
4088             Return twCon.AccessToken
4089         End Get
4090     End Property
4091
4092     Public ReadOnly Property AccessTokenSecret() As String
4093         Get
4094             Return twCon.AccessTokenSecret
4095         End Get
4096     End Property
4097
4098 End Class