OSDN Git Service

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