OSDN Git Service

HttpTwitter.SendDirectMessageメソッドをTwitterApiクラスに置き換え
[opentween/open-tween.git] / OpenTween / Connection / HttpTwitter.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2007-2011 kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
3 //           (c) 2008-2011 Moz (@syo68k)
4 //           (c) 2008-2011 takeshik (@takeshik) <http://www.takeshik.org/>
5 //           (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
6 //           (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
7 //           (c) 2011      kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
8 // All rights reserved.
9 // 
10 // This file is part of OpenTween.
11 // 
12 // This program is free software; you can redistribute it and/or modify it
13 // under the terms of the GNU General public License as published by the Free
14 // Software Foundation; either version 3 of the License, or (at your option)
15 // any later version.
16 // 
17 // This program is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General public License
20 // for more details. 
21 // 
22 // You should have received a copy of the GNU General public License along
23 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
24 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
25 // Boston, MA 02110-1301, USA.
26
27 using System;
28 using System.Collections.Generic;
29 using System.Linq;
30 using System.Text;
31 using System.Net;
32 using System.IO;
33
34 namespace OpenTween
35 {
36     public class HttpTwitter : ICloneable
37     {
38         //OAuth関連
39         ///<summary>
40         ///OAuthのアクセストークン取得先URI
41         ///</summary>
42         private const string AccessTokenUrlXAuth = "https://api.twitter.com/oauth/access_token";
43         private const string RequestTokenUrl = "https://api.twitter.com/oauth/request_token";
44         private const string AuthorizeUrl = "https://api.twitter.com/oauth/authorize";
45         private const string AccessTokenUrl = "https://api.twitter.com/oauth/access_token";
46
47         private const string PostMethod = "POST";
48         private const string GetMethod = "GET";
49
50         private IHttpConnection httpCon; //HttpConnectionApi or HttpConnectionOAuth
51
52         private enum AuthMethod
53         {
54             OAuth,
55             Basic,
56         }
57         private AuthMethod connectionType = AuthMethod.Basic;
58
59         private string requestToken;
60
61         private static string tk = "";
62         private static string tks = "";
63         private static string un = "";
64
65         public void Initialize(string accessToken,
66                                         string accessTokenSecret,
67                                         string username,
68                                         long userId)
69         {
70             //for OAuth
71             HttpOAuthApiProxy con = new HttpOAuthApiProxy();
72             if (tk != accessToken || tks != accessTokenSecret ||
73                     un != username || connectionType != AuthMethod.OAuth)
74             {
75                 // 以前の認証状態よりひとつでも変化があったらhttpヘッダより読み取ったカウントは初期化
76                 tk = accessToken;
77                 tks = accessTokenSecret;
78                 un = username;
79             }
80             con.Initialize(ApplicationSettings.TwitterConsumerKey, ApplicationSettings.TwitterConsumerSecret, accessToken, accessTokenSecret, username, userId, "screen_name", "user_id");
81             con.CacheEnabled = false;
82             httpCon = con;
83             connectionType = AuthMethod.OAuth;
84             requestToken = "";
85         }
86
87         public string AccessToken
88         {
89             get
90             {
91                 return ((HttpConnectionOAuth)httpCon)?.AccessToken ?? "";
92             }
93         }
94
95         public string AccessTokenSecret
96         {
97             get
98             {
99                 return ((HttpConnectionOAuth)httpCon)?.AccessTokenSecret ?? "";
100             }
101         }
102
103         public string AuthenticatedUsername
104         {
105             get
106             {
107                 return httpCon?.AuthUsername ?? "";
108             }
109         }
110
111         public long AuthenticatedUserId
112         {
113             get
114             {
115                 return httpCon?.AuthUserId ?? 0;
116             }
117             set
118             {
119                 if (httpCon != null)
120                     httpCon.AuthUserId = value;
121             }
122         }
123
124         public string Password
125         {
126             get
127             {
128                 return "";
129             }
130         }
131
132         public bool AuthGetRequestToken(ref string content)
133         {
134             Uri authUri = null;
135             bool result = ((HttpOAuthApiProxy)httpCon).AuthenticatePinFlowRequest(RequestTokenUrl, AuthorizeUrl, ref requestToken, ref authUri);
136             content = authUri.AbsoluteUri;
137             return result;
138         }
139
140         public HttpStatusCode AuthGetAccessToken(string pin)
141         {
142             return ((HttpOAuthApiProxy)httpCon).AuthenticatePinFlow(AccessTokenUrl, requestToken, pin);
143         }
144
145         public HttpStatusCode AuthUserAndPass(string username, string password, ref string content)
146         {
147             return httpCon.Authenticate(new Uri(AccessTokenUrlXAuth), username, password, ref content);
148         }
149
150         public void ClearAuthInfo()
151         {
152             this.Initialize("", "", "", 0);
153         }
154
155         public HttpStatusCode UploadMedia(IMediaItem item, ref string content)
156         {
157             //画像投稿専用エンドポイント
158             var binary = new List<KeyValuePair<string, IMediaItem>>();
159             binary.Add(new KeyValuePair<string, IMediaItem>("media", item));
160
161             return httpCon.GetContent(PostMethod,
162                 this.CreateTwitterUploadUri("/1.1/media/upload.json"),
163                 null,
164                 binary,
165                 ref content,
166                 null,
167                 null);
168         }
169
170         public HttpStatusCode RetweetStatus(long id, ref string content)
171         {
172             Dictionary<string, string> param = new Dictionary<string, string>();
173             param.Add("include_entities", "true");
174             param.Add("include_ext_alt_text", "true");
175
176             return httpCon.GetContent(PostMethod,
177                 this.CreateTwitterUri("/1.1/statuses/retweet/" + id + ".json"),
178                 param,
179                 ref content,
180                 null,
181                 null);
182         }
183
184         public HttpStatusCode ShowStatuses(long id, ref string content)
185         {
186             Dictionary<string, string> param = new Dictionary<string, string>();
187             param.Add("include_entities", "true");
188             param.Add("include_ext_alt_text", "true");
189             return httpCon.GetContent(GetMethod,
190                 this.CreateTwitterUri("/1.1/statuses/show/" + id + ".json"),
191                 param,
192                 ref content,
193                 this.CreateRatelimitHeadersDict(),
194                 this.CreateApiCalllback("/statuses/show/:id"));
195         }
196
197         public HttpStatusCode HomeTimeline(int? count, long? max_id, long? since_id, ref string content)
198         {
199             Dictionary<string, string> param = new Dictionary<string, string>();
200             if (count != null)
201                 param.Add("count", count.ToString());
202             if (max_id != null)
203                 param.Add("max_id", max_id.ToString());
204             if (since_id != null)
205                 param.Add("since_id", since_id.ToString());
206
207             param.Add("include_entities", "true");
208             param.Add("include_ext_alt_text", "true");
209
210             return httpCon.GetContent(GetMethod,
211                 this.CreateTwitterUri("/1.1/statuses/home_timeline.json"),
212                 param,
213                 ref content,
214                 this.CreateRatelimitHeadersDict(),
215                 this.CreateApiCalllback("/statuses/home_timeline"));
216         }
217
218         public HttpStatusCode UserTimeline(long? user_id, string screen_name, int? count, long? max_id, long? since_id, ref string content)
219         {
220             Dictionary<string, string> param = new Dictionary<string, string>();
221
222             if ((user_id == null && string.IsNullOrEmpty(screen_name)) ||
223                 (user_id != null && !string.IsNullOrEmpty(screen_name))) return HttpStatusCode.BadRequest;
224
225             if (user_id != null)
226                 param.Add("user_id", user_id.ToString());
227             if (!string.IsNullOrEmpty(screen_name))
228                 param.Add("screen_name", screen_name);
229             if (count != null)
230                 param.Add("count", count.ToString());
231             if (max_id != null)
232                 param.Add("max_id", max_id.ToString());
233             if (since_id != null)
234                 param.Add("since_id", since_id.ToString());
235
236             param.Add("include_rts", "true");
237             param.Add("include_entities", "true");
238             param.Add("include_ext_alt_text", "true");
239
240             return httpCon.GetContent(GetMethod,
241                 this.CreateTwitterUri("/1.1/statuses/user_timeline.json"),
242                 param,
243                 ref content,
244                 this.CreateRatelimitHeadersDict(),
245                 this.CreateApiCalllback("/statuses/user_timeline"));
246         }
247
248         public HttpStatusCode Mentions(int? count, long? max_id, long? since_id, ref string content)
249         {
250             Dictionary<string, string> param = new Dictionary<string, string>();
251             if (count != null)
252                 param.Add("count", count.ToString());
253             if (max_id != null)
254                 param.Add("max_id", max_id.ToString());
255             if (since_id != null)
256                 param.Add("since_id", since_id.ToString());
257
258             param.Add("include_entities", "true");
259             param.Add("include_ext_alt_text", "true");
260
261             return httpCon.GetContent(GetMethod,
262                 this.CreateTwitterUri("/1.1/statuses/mentions_timeline.json"),
263                 param,
264                 ref content,
265                 this.CreateRatelimitHeadersDict(),
266                 this.CreateApiCalllback("/statuses/mentions_timeline"));
267         }
268
269         public HttpStatusCode DirectMessages(int? count, long? max_id, long? since_id, ref string content)
270         {
271             Dictionary<string, string> param = new Dictionary<string, string>();
272             if (count != null)
273                 param.Add("count", count.ToString());
274             if (max_id != null)
275                 param.Add("max_id", max_id.ToString());
276             if (since_id != null)
277                 param.Add("since_id", since_id.ToString());
278             param.Add("full_text", "true");
279             param.Add("include_entities", "true");
280             param.Add("include_ext_alt_text", "true");
281
282             return httpCon.GetContent(GetMethod,
283                 this.CreateTwitterUri("/1.1/direct_messages.json"),
284                 param,
285                 ref content,
286                 this.CreateRatelimitHeadersDict(),
287                 this.CreateApiCalllback("/direct_messages"));
288         }
289
290         public HttpStatusCode DirectMessagesSent(int? count, long? max_id, long? since_id, ref string content)
291         {
292             Dictionary<string, string> param = new Dictionary<string, string>();
293             if (count != null)
294                 param.Add("count", count.ToString());
295             if (max_id != null)
296                 param.Add("max_id", max_id.ToString());
297             if (since_id != null)
298                 param.Add("since_id", since_id.ToString());
299             param.Add("full_text", "true");
300             param.Add("include_entities", "true");
301             param.Add("include_ext_alt_text", "true");
302
303             return httpCon.GetContent(GetMethod,
304                 this.CreateTwitterUri("/1.1/direct_messages/sent.json"),
305                 param,
306                 ref content,
307                 this.CreateRatelimitHeadersDict(),
308                 this.CreateApiCalllback("/direct_messages/sent"));
309         }
310
311         public HttpStatusCode Favorites(int? count, ref string content)
312         {
313             Dictionary<string, string> param = new Dictionary<string, string>();
314             if (count != null)
315                 param.Add("count", count.ToString());
316             param.Add("include_entities", "true");
317             param.Add("include_ext_alt_text", "true");
318
319             return httpCon.GetContent(GetMethod,
320                 this.CreateTwitterUri("/1.1/favorites/list.json"),
321                 param,
322                 ref content,
323                 this.CreateRatelimitHeadersDict(),
324                 this.CreateApiCalllback("/favorites/list"));
325         }
326
327         public HttpStatusCode Search(string words, string lang, int? count, long? maxId, long? sinceId, ref string content)
328         {
329             Dictionary<string, string> param = new Dictionary<string, string>();
330             if (!string.IsNullOrEmpty(words)) param.Add("q", words);
331             if (!string.IsNullOrEmpty(lang)) param.Add("lang", lang);
332             if (count != null) param.Add("count", count.ToString());
333             if (maxId != null) param.Add("max_id", maxId.ToString());
334             if (sinceId != null) param.Add("since_id", sinceId.ToString());
335
336             if (param.Count == 0) return HttpStatusCode.BadRequest;
337
338             param.Add("result_type", "recent");
339             param.Add("include_entities", "true");
340             param.Add("include_ext_alt_text", "true");
341             return httpCon.GetContent(GetMethod,
342                 this.CreateTwitterUri("/1.1/search/tweets.json"),
343                 param,
344                 ref content,
345                 this.CreateRatelimitHeadersDict(),
346                 this.CreateApiCalllback("/search/tweets"));
347         }
348
349         public HttpStatusCode SavedSearches(ref string content)
350         {
351             return httpCon.GetContent(GetMethod,
352                 this.CreateTwitterUri("/1.1/saved_searches/list.json"),
353                 null,
354                 ref content,
355                 this.CreateRatelimitHeadersDict(),
356                 this.CreateApiCalllback("/saved_searches/list"));
357         }
358
359         public HttpStatusCode FollowerIds(long cursor, ref string content)
360         {
361             Dictionary<string, string> param = new Dictionary<string, string>();
362             param.Add("cursor", cursor.ToString());
363
364             return httpCon.GetContent(GetMethod,
365                 this.CreateTwitterUri("/1.1/followers/ids.json"),
366                 param,
367                 ref content,
368                 this.CreateRatelimitHeadersDict(),
369                 this.CreateApiCalllback("/followers/ids"));
370         }
371
372         public HttpStatusCode NoRetweetIds(ref string content)
373         {
374             return httpCon.GetContent(GetMethod,
375                 this.CreateTwitterUri("/1.1/friendships/no_retweets/ids.json"),
376                 null,
377                 ref content,
378                 this.CreateRatelimitHeadersDict(),
379                 this.CreateApiCalllback("/friendships/no_retweets/ids"));
380         }
381
382         public HttpStatusCode RateLimitStatus(ref string content)
383         {
384             return httpCon.GetContent(GetMethod,
385                 this.CreateTwitterUri("/1.1/application/rate_limit_status.json"),
386                 null,
387                 ref content,
388                 this.CreateRatelimitHeadersDict(),
389                 this.CreateApiCalllback("/application/rate_limit_status"));
390         }
391
392         #region Lists
393         public HttpStatusCode GetLists(string user, ref string content)
394         {
395             Dictionary<string, string> param = new Dictionary<string, string>();
396             param.Add("screen_name", user);
397
398             return httpCon.GetContent(GetMethod,
399                 this.CreateTwitterUri("/1.1/lists/list.json"),
400                 param,
401                 ref content,
402                 this.CreateRatelimitHeadersDict(),
403                 this.CreateApiCalllback("/lists/list"));
404         }
405
406         public HttpStatusCode UpdateListID(string user, string list_id, string name, Boolean isPrivate, string description, ref string content)
407         {
408             string mode = "public";
409             if (isPrivate)
410                 mode = "private";
411
412             Dictionary<string, string> param = new Dictionary<string, string>();
413             param.Add("screen_name", user);
414             param.Add("list_id", list_id);
415             if (name != null) param.Add("name", name);
416             if (mode != null) param.Add("mode", mode);
417             if (description != null) param.Add("description", description);
418
419             return httpCon.GetContent(PostMethod,
420                 this.CreateTwitterUri("/1.1/lists/update.json"),
421                 param,
422                 ref content,
423                 null,
424                 null);
425         }
426
427         public HttpStatusCode DeleteListID(string user, string list_id, ref string content)
428         {
429             Dictionary<string, string> param = new Dictionary<string, string>();
430             param.Add("screen_name", user);
431             param.Add("list_id", list_id);
432
433             return httpCon.GetContent(PostMethod,
434                 this.CreateTwitterUri("/1.1/lists/destroy.json"),
435                 param,
436                 ref content,
437                 null,
438                 null);
439         }
440
441         public HttpStatusCode GetListsSubscriptions(string user, ref string content)
442         {
443             Dictionary<string, string> param = new Dictionary<string, string>();
444             param.Add("screen_name", user);
445
446             return httpCon.GetContent(GetMethod,
447                 this.CreateTwitterUri("/1.1/lists/subscriptions.json"),
448                 param,
449                 ref content,
450                 this.CreateRatelimitHeadersDict(),
451                 this.CreateApiCalllback("/lists/subscriptions"));
452         }
453
454         public HttpStatusCode GetListsStatuses(long userId, long list_id, int? per_page, long? max_id, long? since_id, Boolean isRTinclude, ref string content)
455         {
456             //認証なくても取得できるが、protectedユーザー分が抜ける
457             Dictionary<string, string> param = new Dictionary<string, string>();
458             param.Add("user_id", userId.ToString());
459             param.Add("list_id", list_id.ToString());
460             param.Add("include_rts", isRTinclude ? "true" : "false");
461             if (per_page != null)
462                 param.Add("count", per_page.ToString());
463             if (max_id != null)
464                 param.Add("max_id", max_id.ToString());
465             if (since_id != null)
466                 param.Add("since_id", since_id.ToString());
467             param.Add("include_entities", "true");
468             param.Add("include_ext_alt_text", "true");
469
470             return httpCon.GetContent(GetMethod,
471                 this.CreateTwitterUri("/1.1/lists/statuses.json"),
472                 param,
473                 ref content,
474                 this.CreateRatelimitHeadersDict(),
475                 this.CreateApiCalllback("/lists/statuses"));
476         }
477
478         public HttpStatusCode CreateLists(string listname, Boolean isPrivate, string description, ref string content)
479         {
480             string mode = "public";
481             if (isPrivate)
482                 mode = "private";
483
484             Dictionary<string, string> param = new Dictionary<string, string>();
485             param.Add("name", listname);
486             param.Add("mode", mode);
487             if (!string.IsNullOrEmpty(description))
488                 param.Add("description", description);
489
490             return httpCon.GetContent(PostMethod,
491                 this.CreateTwitterUri("/1.1/lists/create.json"),
492                 param,
493                 ref content,
494                 null,
495                 null);
496         }
497
498         public HttpStatusCode GetListMembers(string user, string list_id, long cursor, ref string content)
499         {
500             Dictionary<string, string> param = new Dictionary<string, string>();
501             param.Add("screen_name", user);
502             param.Add("list_id", list_id);
503             param.Add("cursor", cursor.ToString());
504             return httpCon.GetContent(GetMethod,
505                 this.CreateTwitterUri("/1.1/lists/members.json"),
506                 param,
507                 ref content,
508                 this.CreateRatelimitHeadersDict(),
509                 this.CreateApiCalllback("/lists/members"));
510         }
511
512         public HttpStatusCode CreateListMembers(string list_id, string memberName, ref string content)
513         {
514             Dictionary<string, string> param = new Dictionary<string, string>();
515             param.Add("list_id", list_id);
516             param.Add("screen_name", memberName);
517             return httpCon.GetContent(PostMethod,
518                 this.CreateTwitterUri("/1.1/lists/members/create.json"),
519                 param,
520                 ref content,
521                 null,
522                 null);
523         }
524
525         public HttpStatusCode DeleteListMembers(string list_id, string memberName, ref string content)
526         {
527             Dictionary<string, string> param = new Dictionary<string, string>();
528             param.Add("screen_name", memberName);
529             param.Add("list_id", list_id);
530             return httpCon.GetContent(PostMethod,
531                 this.CreateTwitterUri("/1.1/lists/members/destroy.json"),
532                 param,
533                 ref content,
534                 null,
535                 null);
536         }
537
538         public HttpStatusCode ShowListMember(string list_id, string memberName, ref string content)
539         {
540             Dictionary<string, string> param = new Dictionary<string, string>();
541             param.Add("screen_name", memberName);
542             param.Add("list_id", list_id);
543             return httpCon.GetContent(GetMethod,
544                 this.CreateTwitterUri("/1.1/lists/members/show.json"),
545                 param,
546                 ref content,
547                 this.CreateRatelimitHeadersDict(),
548                 this.CreateApiCalllback("/lists/members/show"));
549         }
550         #endregion
551
552         public HttpStatusCode Statusid_retweeted_by_ids(long statusid, int? count, int? page, ref string content)
553         {
554             Dictionary<string, string> param = new Dictionary<string, string>();
555             if (count != null)
556                 param.Add("count", count.ToString());
557             if (page != null)
558                 param.Add("page", page.ToString());
559
560             param.Add("id", statusid.ToString());
561
562             return httpCon.GetContent(GetMethod,
563                 this.CreateTwitterUri("/1.1/statuses/retweeters/ids.json"),
564                 param,
565                 ref content,
566                 this.CreateRatelimitHeadersDict(),
567                 this.CreateApiCalllback("/statuses/retweeters/ids"));
568         }
569
570         public HttpStatusCode GetBlockUserIds(ref string content, long? cursor)
571         {
572             var param = new Dictionary<string, string>();
573
574             if (cursor != null)
575                 param.Add("cursor", cursor.ToString());
576
577             return httpCon.GetContent(GetMethod,
578                 this.CreateTwitterUri("/1.1/blocks/ids.json"),
579                 param,
580                 ref content,
581                 this.CreateRatelimitHeadersDict(),
582                 this.CreateApiCalllback("/blocks/ids"));
583         }
584
585         public HttpStatusCode GetMuteUserIds(ref string content, long? cursor)
586         {
587             var param = new Dictionary<string, string>();
588
589             if (cursor != null)
590                 param.Add("cursor", cursor.ToString());
591
592             return httpCon.GetContent(GetMethod,
593                 this.CreateTwitterUri("/1.1/mutes/users/ids.json"),
594                 param,
595                 ref content,
596                 this.CreateRatelimitHeadersDict(),
597                 this.CreateApiCalllback("/mutes/users/ids"));
598         }
599
600         public HttpStatusCode GetConfiguration(ref string content)
601         {
602             return httpCon.GetContent(GetMethod,
603                 this.CreateTwitterUri("/1.1/help/configuration.json"),
604                 null,
605                 ref content,
606                 this.CreateRatelimitHeadersDict(),
607                 this.CreateApiCalllback("/help/configuration"));
608         }
609
610         public HttpStatusCode VerifyCredentials(ref string content)
611         {
612             return httpCon.GetContent(GetMethod,
613                 this.CreateTwitterUri("/1.1/account/verify_credentials.json"),
614                 null,
615                 ref content,
616                 this.CreateRatelimitHeadersDict(),
617                 this.CreateApiCalllback("/account/verify_credentials"));
618         }
619
620         #region Proxy API
621         private static string _twitterUrl = "api.twitter.com";
622         private static string _twitterUserStreamUrl = "userstream.twitter.com";
623         private static string _twitterStreamUrl = "stream.twitter.com";
624         private static string _twitterUploadUrl = "upload.twitter.com";
625
626         private Uri CreateTwitterUri(string path)
627         {
628             return new Uri(string.Format("{0}{1}{2}", "https://", _twitterUrl, path));
629         }
630
631         private Uri CreateTwitterUserStreamUri(string path)
632         {
633             return new Uri(string.Format("{0}{1}{2}", "https://", _twitterUserStreamUrl, path));
634         }
635
636         private Uri CreateTwitterStreamUri(string path)
637         {
638             return new Uri(string.Format("{0}{1}{2}", "http://", _twitterStreamUrl, path));
639         }
640
641         private Uri CreateTwitterUploadUri(string path)
642         {
643             return new Uri(string.Format("{0}{1}{2}", "https://", _twitterUploadUrl, path));
644         }
645
646         public static string TwitterUrl
647         {
648             get { return _twitterUrl; }
649             set
650             {
651                 _twitterUrl = value;
652                 HttpOAuthApiProxy.ProxyHost = value;
653             }
654         }
655         #endregion
656
657         private Dictionary<string, string> CreateRatelimitHeadersDict()
658         {
659             return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
660             {
661                 ["X-Access-Level"] = "",
662                 ["X-RateLimit-Limit"] = "",
663                 ["X-RateLimit-Remaining"] = "",
664                 ["X-RateLimit-Reset"] = "",
665                 ["X-Rate-Limit-Limit"] = "",
666                 ["X-Rate-Limit-Remaining"] = "",
667                 ["X-Rate-Limit-Reset"] = "",
668                 ["X-MediaRateLimit-Limit"] = "",
669                 ["X-MediaRateLimit-Remaining"] = "",
670                 ["X-MediaRateLimit-Reset"] = "",
671             };
672         }
673
674         private CallbackDelegate CreateApiCalllback(string endpointName)
675         {
676             return (sender, code, headerInfo, content) =>
677             {
678                 if (code < HttpStatusCode.InternalServerError)
679                     MyCommon.TwitterApiInfo.UpdateFromHeader(headerInfo, endpointName);
680             };
681         }
682
683         public HttpStatusCode UserStream(ref Stream content,
684                                          bool allAtReplies,
685                                          string trackwords,
686                                          string userAgent)
687         {
688             Dictionary<string, string> param = new Dictionary<string, string>();
689
690             if (allAtReplies)
691                 param.Add("replies", "all");
692
693             if (!string.IsNullOrEmpty(trackwords))
694                 param.Add("track", trackwords);
695
696             return httpCon.GetContent(GetMethod,
697                 this.CreateTwitterUserStreamUri("/1.1/user.json"),
698                 param,
699                 ref content,
700                 userAgent);
701         }
702
703         public HttpStatusCode FilterStream(ref Stream content,
704                                            string trackwords,
705                                            string userAgent)
706         {
707             //文中の日本語キーワードに反応せず、使えない(スペースで分かち書きしてないと反応しない)
708             Dictionary<string, string> param = new Dictionary<string, string>();
709
710             if (!string.IsNullOrEmpty(trackwords))
711                 param.Add("track", string.Join(",", trackwords.Split(" ".ToCharArray())));
712
713             return httpCon.GetContent(PostMethod,
714                 this.CreateTwitterStreamUri("/1.1/statuses/filter.json"),
715                 param,
716                 ref content,
717                 userAgent);
718         }
719
720         public void RequestAbort()
721         {
722             httpCon.RequestAbort();
723         }
724
725         public object Clone()
726         {
727             HttpTwitter myCopy = new HttpTwitter();
728             myCopy.Initialize(this.AccessToken, this.AccessTokenSecret, this.AuthenticatedUsername, this.AuthenticatedUserId);
729             return myCopy;
730         }
731     }
732 }