OSDN Git Service

Merge branch 'api11'
[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         /// <summary>
39         /// API v1.1 を有効にする否か
40         /// </summary>
41         /// <remarks>
42         /// 旧APIが使用出来なくなったら消す予定。
43         /// 静的フィールドとしているのは TwitterUserstream クラスが Clone メソッドを使用しているため
44         /// </remarks>
45         public static bool API11Enabled { get; set; }
46
47         //OAuth関連
48         ///<summary>
49         ///OAuthのアクセストークン取得先URI
50         ///</summary>
51         private const string AccessTokenUrlXAuth = "https://api.twitter.com/oauth/access_token";
52         private const string RequestTokenUrl = "https://api.twitter.com/oauth/request_token";
53         private const string AuthorizeUrl = "https://api.twitter.com/oauth/authorize";
54         private const string AccessTokenUrl = "https://api.twitter.com/oauth/access_token";
55
56         private static string _protocol = "http://";
57
58         private const string PostMethod = "POST";
59         private const string GetMethod = "GET";
60
61         private IHttpConnection httpCon; //HttpConnectionApi or HttpConnectionOAuth
62         private HttpVarious httpConVar = new HttpVarious();
63
64         private enum AuthMethod
65         {
66             OAuth,
67             Basic,
68         }
69         private AuthMethod connectionType = AuthMethod.Basic;
70
71         private string requestToken;
72
73         private static string tk = "";
74         private static string tks = "";
75         private static string un = "";
76
77         private Dictionary<string, string> apiStatusHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
78         {
79             {"X-Access-Level", ""},
80             {"X-RateLimit-Limit", ""},
81             {"X-RateLimit-Remaining", ""},
82             {"X-RateLimit-Reset", ""},
83             {"X-Rate-Limit-Limit", ""},
84             {"X-Rate-Limit-Remaining", ""},
85             {"X-Rate-Limit-Reset", ""},
86             {"X-MediaRateLimit-Limit", ""},
87             {"X-MediaRateLimit-Remaining", ""},
88             {"X-MediaRateLimit-Reset", ""},
89         };
90
91         static HttpTwitter()
92         {
93             HttpTwitter.API11Enabled = true;
94         }
95
96         public void Initialize(string accessToken,
97                                         string accessTokenSecret,
98                                         string username,
99                                         long userId)
100         {
101             //for OAuth
102             HttpOAuthApiProxy con = new HttpOAuthApiProxy();
103             if (tk != accessToken || tks != accessTokenSecret ||
104                     un != username || connectionType != AuthMethod.OAuth)
105             {
106                 // 以前の認証状態よりひとつでも変化があったらhttpヘッダより読み取ったカウントは初期化
107                 tk = accessToken;
108                 tks = accessTokenSecret;
109                 un = username;
110             }
111             con.Initialize(ApplicationSettings.TwitterConsumerKey, ApplicationSettings.TwitterConsumerSecret, accessToken, accessTokenSecret, username, userId, "screen_name", "user_id");
112             httpCon = con;
113             connectionType = AuthMethod.OAuth;
114             requestToken = "";
115         }
116
117         public string AccessToken
118         {
119             get
120             {
121                 if (httpCon != null)
122                     return ((HttpConnectionOAuth)httpCon).AccessToken;
123                 else
124                     return "";
125             }
126         }
127
128         public string AccessTokenSecret
129         {
130             get
131             {
132                 if (httpCon != null)
133                     return ((HttpConnectionOAuth)httpCon).AccessTokenSecret;
134                 else
135                     return "";
136             }
137         }
138
139         public string AuthenticatedUsername
140         {
141             get
142             {
143                 if (httpCon != null)
144                     return httpCon.AuthUsername;
145                 else
146                     return "";
147             }
148         }
149
150         public long AuthenticatedUserId
151         {
152             get
153             {
154                 if (httpCon != null)
155                     return httpCon.AuthUserId;
156                 else
157                     return 0;
158             }
159             set
160             {
161                 if (httpCon != null)
162                     httpCon.AuthUserId = value;
163             }
164         }
165
166         public string Password
167         {
168             get
169             {
170                 return "";
171             }
172         }
173
174         public bool AuthGetRequestToken(ref string content)
175         {
176             Uri authUri = null;
177             bool result = ((HttpOAuthApiProxy)httpCon).AuthenticatePinFlowRequest(RequestTokenUrl, AuthorizeUrl, ref requestToken, ref authUri);
178             content = authUri.ToString();
179             return result;
180         }
181
182         public HttpStatusCode AuthGetAccessToken(string pin)
183         {
184             return ((HttpOAuthApiProxy)httpCon).AuthenticatePinFlow(AccessTokenUrl, requestToken, pin);
185         }
186
187         public HttpStatusCode AuthUserAndPass(string username, string password, ref string content)
188         {
189             return httpCon.Authenticate(new Uri(AccessTokenUrlXAuth), username, password, ref content);
190         }
191
192         public void ClearAuthInfo()
193         {
194             this.Initialize("", "", "", 0);
195         }
196
197         public static bool UseSsl
198         {
199             set
200             {
201                 if (value)
202                     _protocol = "https://";
203                 else
204                     _protocol = "http://";
205             }
206         }
207
208         public HttpStatusCode UpdateStatus(string status, long replyToId, ref string content)
209         {
210             Dictionary<string, string> param = new Dictionary<string, string>();
211             param.Add("status", status);
212             if (replyToId > 0) param.Add("in_reply_to_status_id", replyToId.ToString());
213             param.Add("include_entities", "true");
214             //if (AppendSettingDialog.Instance.ShortenTco && AppendSettingDialog.Instance.UrlConvertAuto) param.Add("wrap_links", "true")
215
216             return httpCon.GetContent(PostMethod,
217                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/statuses/update.json" : "/1/statuses/update.json"),
218                 param,
219                 ref content,
220                 null,
221                 null);
222         }
223
224         public HttpStatusCode UpdateStatusWithMedia(string status, long replyToId, FileInfo mediaFile, ref string content)
225         {
226             //画像投稿用エンドポイント
227             Dictionary<string, string> param = new Dictionary<string, string>();
228             param.Add("status", status);
229             if (replyToId > 0) param.Add("in_reply_to_status_id", replyToId.ToString());
230             param.Add("include_entities", "true");
231             //if (AppendSettingDialog.Instance.ShortenTco && AppendSettingDialog.Instance.UrlConvertAuto) param.Add("wrap_links", "true")
232
233             List<KeyValuePair<string, FileInfo>> binary = new List<KeyValuePair<string, FileInfo>>();
234             binary.Add(new KeyValuePair<string, FileInfo>("media[]", mediaFile));
235
236             return httpCon.GetContent(PostMethod,
237                 HttpTwitter.API11Enabled ? CreateTwitterUri("/1.1/statuses/update_with_media.json") : new Uri("https://upload.twitter.com/1/statuses/update_with_media.json"),
238                 param,
239                 binary,
240                 ref content,
241                 this.apiStatusHeaders,
242                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/statuses/update_with_media") : GetApiCallback);
243         }
244
245         public HttpStatusCode DestroyStatus(long id)
246         {
247             string content = null;
248
249             return httpCon.GetContent(PostMethod,
250                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/statuses/destroy/" + id + ".json" : "/1/statuses/destroy/" + id + ".json"),
251                 null,
252                 ref content,
253                 null,
254                 null);
255         }
256
257         public HttpStatusCode SendDirectMessage(string status, string sendto, ref string content)
258         {
259             Dictionary<string, string> param = new Dictionary<string, string>();
260             param.Add("text", status);
261             param.Add("screen_name", sendto);
262             //if (AppendSettingDialog.Instance.ShortenTco && AppendSettingDialog.Instance.UrlConvertAuto) param.Add("wrap_links", "true")
263
264             return httpCon.GetContent(PostMethod,
265                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/direct_messages/new.json" : "/1/direct_messages/new.json"),
266                 param,
267                 ref content,
268                 null,
269                 null);
270         }
271
272         public HttpStatusCode DestroyDirectMessage(long id)
273         {
274             string content = null;
275
276             var param = new Dictionary<string, string>();
277             if (HttpTwitter.API11Enabled)
278                 param.Add("id", id.ToString());
279
280             return httpCon.GetContent(PostMethod,
281                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/direct_messages/destroy.json" : "/1/direct_messages/destroy/" + id + ".json"),
282                 param,
283                 ref content,
284                 null,
285                 null);
286         }
287
288         public HttpStatusCode RetweetStatus(long id, ref string content)
289         {
290             Dictionary<string, string> param = new Dictionary<string, string>();
291             param.Add("include_entities", "true");
292
293             return httpCon.GetContent(PostMethod,
294                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/statuses/retweet/" + id + ".json" : "/1/statuses/retweet/" + id + ".json"),
295                 param,
296                 ref content,
297                 null,
298                 null);
299         }
300
301         public HttpStatusCode ShowUserInfo(string screenName, ref string content)
302         {
303             Dictionary<string, string> param = new Dictionary<string, string>();
304             param.Add("screen_name", screenName);
305             param.Add("include_entities", "true");
306             return httpCon.GetContent(GetMethod,
307                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/users/show.json" : "/1/users/show.json"),
308                 param,
309                 ref content,
310                 this.apiStatusHeaders,
311                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/users/show/:id") : GetApiCallback);
312         }
313
314         public HttpStatusCode CreateFriendships(string screenName, ref string content)
315         {
316             Dictionary<string, string> param = new Dictionary<string, string>();
317             param.Add("screen_name", screenName);
318
319             return httpCon.GetContent(PostMethod,
320                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/friendships/create.json" : "/1/friendships/create.json"),
321                 param,
322                 ref content,
323                 null,
324                 null);
325         }
326
327         public HttpStatusCode DestroyFriendships(string screenName, ref string content)
328         {
329             Dictionary<string, string> param = new Dictionary<string, string>();
330             param.Add("screen_name", screenName);
331
332             return httpCon.GetContent(PostMethod,
333                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/friendships/destroy.json" : "/1/friendships/destroy.json"),
334                 param,
335                 ref content,
336                 null,
337                 null);
338         }
339
340         public HttpStatusCode CreateBlock(string screenName, ref string content)
341         {
342             Dictionary<string, string> param = new Dictionary<string, string>();
343             param.Add("screen_name", screenName);
344
345             return httpCon.GetContent(PostMethod,
346                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/blocks/create.json" : "/1/blocks/create.json"),
347                 param,
348                 ref content,
349                 null,
350                 null);
351         }
352
353         public HttpStatusCode DestroyBlock(string screenName, ref string content)
354         {
355             Dictionary<string, string> param = new Dictionary<string, string>();
356             param.Add("screen_name", screenName);
357
358             return httpCon.GetContent(PostMethod,
359                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/blocks/destroy.json" : "/1/blocks/destroy.json"),
360                 param,
361                 ref content,
362                 null,
363                 null);
364         }
365
366         public HttpStatusCode ReportSpam(string screenName, ref string content)
367         {
368             Dictionary<string, string> param = new Dictionary<string, string>();
369             param.Add("screen_name", screenName);
370
371             return httpCon.GetContent(PostMethod,
372                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/users/report_spam.json" : "/1/report_spam.json"),
373                 param,
374                 ref content,
375                 null,
376                 null);
377         }
378
379         public HttpStatusCode ShowFriendships(string souceScreenName, string targetScreenName, ref string content)
380         {
381             Dictionary<string, string> param = new Dictionary<string, string>();
382             param.Add("source_screen_name", souceScreenName);
383             param.Add("target_screen_name", targetScreenName);
384
385             return httpCon.GetContent(GetMethod,
386                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/friendships/show.json" : "/1/friendships/show.json"),
387                 param,
388                 ref content,
389                 this.apiStatusHeaders,
390                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/friendships/show") : GetApiCallback);
391         }
392
393         public HttpStatusCode ShowStatuses(long id, ref string content)
394         {
395             Dictionary<string, string> param = new Dictionary<string, string>();
396             param.Add("include_entities", "true");
397             return httpCon.GetContent(GetMethod,
398                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/statuses/show/" + id + ".json" : "/1/statuses/show/" + id + ".json"),
399                 param,
400                 ref content,
401                 this.apiStatusHeaders,
402                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/statuses/show/:id") : GetApiCallback);
403         }
404
405         public HttpStatusCode CreateFavorites(long id, ref string content)
406         {
407             var param = new Dictionary<string, string>();
408             if (HttpTwitter.API11Enabled)
409                 param.Add("id", id.ToString());
410
411             return httpCon.GetContent(PostMethod,
412                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/favorites/create.json" : "/1/favorites/create/" + id + ".json"),
413                 param,
414                 ref content,
415                 null,
416                 null);
417         }
418
419         public HttpStatusCode DestroyFavorites(long id, ref string content)
420         {
421             var param = new Dictionary<string, string>();
422             if (HttpTwitter.API11Enabled)
423                 param.Add("id", id.ToString());
424
425             return httpCon.GetContent(PostMethod,
426                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/favorites/destroy.json" : "/1/favorites/destroy/" + id + ".json"),
427                 param,
428                 ref content,
429                 null,
430                 null);
431         }
432
433         public HttpStatusCode HomeTimeline(int count, long max_id, long since_id, ref string content)
434         {
435             Dictionary<string, string> param = new Dictionary<string, string>();
436             if (count > 0)
437                 param.Add("count", count.ToString());
438             if (max_id > 0)
439                 param.Add("max_id", max_id.ToString());
440             if (since_id > 0)
441                 param.Add("since_id", since_id.ToString());
442
443             param.Add("include_entities", "true");
444
445             return httpCon.GetContent(GetMethod,
446                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/statuses/home_timeline.json" : "/1/statuses/home_timeline.json"),
447                 param,
448                 ref content,
449                 this.apiStatusHeaders,
450                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/statuses/home_timeline") : GetApiCallback);
451         }
452
453         public HttpStatusCode UserTimeline(long user_id, string screen_name, int count, long max_id, long since_id, ref string content)
454         {
455             Dictionary<string, string> param = new Dictionary<string, string>();
456
457             if ((user_id == 0 && string.IsNullOrEmpty(screen_name)) ||
458                 (user_id != 0 && !string.IsNullOrEmpty(screen_name))) return HttpStatusCode.BadRequest;
459
460             if (user_id > 0)
461                 param.Add("user_id", user_id.ToString());
462             if (!string.IsNullOrEmpty(screen_name))
463                 param.Add("screen_name", screen_name);
464             if (count > 0)
465                 param.Add("count", count.ToString());
466             if (max_id > 0)
467                 param.Add("max_id", max_id.ToString());
468             if (since_id > 0)
469                 param.Add("since_id", since_id.ToString());
470
471             param.Add("include_rts", "true");
472             param.Add("include_entities", "true");
473
474             return httpCon.GetContent(GetMethod,
475                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/statuses/user_timeline.json" : "/1/statuses/user_timeline.json"),
476                 param,
477                 ref content,
478                 this.apiStatusHeaders,
479                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/statuses/user_timeline") : GetApiCallback);
480         }
481
482         public HttpStatusCode PublicTimeline(int count, long max_id, long since_id, ref string content)
483         {
484             Dictionary<string, string> param = new Dictionary<string, string>();
485             if (count > 0)
486                 param.Add("count", count.ToString());
487             if (max_id > 0)
488                 param.Add("max_id", max_id.ToString());
489             if (since_id > 0)
490                 param.Add("since_id", since_id.ToString());
491
492             param.Add("include_entities", "true");
493
494             // TODO: API v1.1 に存在しない API (旧 API で代替)
495
496             return httpCon.GetContent(GetMethod,
497                 CreateTwitterUri("/1/statuses/public_timeline.json"),
498                 param,
499                 ref content,
500                 this.apiStatusHeaders,
501                 GetApiCallback);
502         }
503
504         public HttpStatusCode Mentions(int count, long max_id, long since_id, ref string content)
505         {
506             Dictionary<string, string> param = new Dictionary<string, string>();
507             if (count > 0)
508                 param.Add("count", count.ToString());
509             if (max_id > 0)
510                 param.Add("max_id", max_id.ToString());
511             if (since_id > 0)
512                 param.Add("since_id", since_id.ToString());
513
514             param.Add("include_entities", "true");
515
516             return httpCon.GetContent(GetMethod,
517                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/statuses/mentions_timeline.json" : "/1/statuses/mentions.json"),
518                 param,
519                 ref content,
520                 this.apiStatusHeaders,
521                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/statuses/mentions_timeline") : GetApiCallback);
522         }
523
524         public HttpStatusCode DirectMessages(int count, long max_id, long since_id, ref string content)
525         {
526             Dictionary<string, string> param = new Dictionary<string, string>();
527             if (count > 0)
528                 param.Add("count", count.ToString());
529             if (max_id > 0)
530                 param.Add("max_id", max_id.ToString());
531             if (since_id > 0)
532                 param.Add("since_id", since_id.ToString());
533             param.Add("include_entities", "true");
534
535             return httpCon.GetContent(GetMethod,
536                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/direct_messages.json" : "/1/direct_messages.json"),
537                 param,
538                 ref content,
539                 this.apiStatusHeaders,
540                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/direct_messages") : GetApiCallback);
541         }
542
543         public HttpStatusCode DirectMessagesSent(int count, long max_id, long since_id, ref string content)
544         {
545             Dictionary<string, string> param = new Dictionary<string, string>();
546             if (count > 0)
547                 param.Add("count", count.ToString());
548             if (max_id > 0)
549                 param.Add("max_id", max_id.ToString());
550             if (since_id > 0)
551                 param.Add("since_id", since_id.ToString());
552             param.Add("include_entities", "true");
553
554             return httpCon.GetContent(GetMethod,
555                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/direct_messages/sent.json" : "/1/direct_messages/sent.json"),
556                 param,
557                 ref content,
558                 this.apiStatusHeaders,
559                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/direct_messages/sent") : GetApiCallback);
560         }
561
562         public HttpStatusCode Favorites(int count, int page, ref string content)
563         {
564             Dictionary<string, string> param = new Dictionary<string, string>();
565             if (count != 20) param.Add("count", count.ToString());
566
567             if (page > 0)
568             {
569                 param.Add("page", page.ToString());
570             }
571
572             param.Add("include_entities", "true");
573
574             return httpCon.GetContent(GetMethod,
575                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/favorites/list.json" : "/1/favorites.json"),
576                 param,
577                 ref content,
578                 this.apiStatusHeaders,
579                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/favorites/list") : GetApiCallback);
580         }
581
582         public HttpStatusCode PhoenixSearch(string querystr, ref string content)
583         {
584             Dictionary<string, string> param = new Dictionary<string, string>();
585             string[] tmp;
586             string[] paramstr;
587             if (string.IsNullOrEmpty(querystr)) return HttpStatusCode.BadRequest;
588
589             tmp = querystr.Split(new char[] {'?', '&'}, StringSplitOptions.RemoveEmptyEntries);
590             foreach (string tmp2 in tmp)
591             {
592                 paramstr = tmp2.Split(new char[] {'='});
593                 param.Add(paramstr[0], paramstr[1]);
594             }
595
596             return httpConVar.GetContent(GetMethod,
597                                          CreateTwitterUri("/phoenix_search.phoenix"),
598                                          param,
599                                          out content,
600                                          null,
601                                          MyCommon.GetAssemblyName());
602         }
603
604         public HttpStatusCode PhoenixSearch(string words, string lang, int rpp, int page, long sinceId, ref string content)
605         {
606             Dictionary<string, string> param = new Dictionary<string, string>();
607             if (!string.IsNullOrEmpty(words)) param.Add("q", words);
608             param.Add("include_entities", "1");
609             param.Add("contributor_details", "true");
610             if (!string.IsNullOrEmpty(lang)) param.Add("lang", lang);
611             if (rpp > 0) param.Add("rpp", rpp.ToString());
612             if (page > 0) param.Add("page", page.ToString());
613             if (sinceId > 0) param.Add("since_id", sinceId.ToString());
614
615             if (param.Count == 0) return HttpStatusCode.BadRequest;
616
617             return httpConVar.GetContent(GetMethod,
618                                          CreateTwitterUri("/phoenix_search.phoenix"),
619                                          param,
620                                          out content,
621                                          null,
622                                          MyCommon.GetAssemblyName());
623         }
624
625         public HttpStatusCode Search(string words, string lang, int count, int page, long sinceId, ref string content)
626         {
627             Dictionary<string, string> param = new Dictionary<string, string>();
628             if (!string.IsNullOrEmpty(words)) param.Add("q", words);
629             if (!string.IsNullOrEmpty(lang)) param.Add("lang", lang);
630             if (count > 0) param.Add(HttpTwitter.API11Enabled ? "count" : "rpp", count.ToString());
631             if (page > 0) param.Add("page", page.ToString());
632             if (sinceId > 0) param.Add("since_id", sinceId.ToString());
633
634             if (param.Count == 0) return HttpStatusCode.BadRequest;
635
636             param.Add("result_type", "recent");
637             param.Add("include_entities", "true");
638             return httpCon.GetContent(GetMethod,
639                 HttpTwitter.API11Enabled ? this.CreateTwitterUri("/1.1/search/tweets.json") : this.CreateTwitterSearchUri("/search.json"),
640                 param,
641                 ref content,
642                 null,
643                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/search/tweets") : GetApiCallback);
644         }
645
646         public HttpStatusCode SavedSearches(ref string content)
647         {
648             return httpCon.GetContent(GetMethod,
649                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/saved_searches/list.json" : "/1/saved_searches.json"),
650                 null,
651                 ref content,
652                 null,
653                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/saved_searches/list") : GetApiCallback);
654         }
655
656         public HttpStatusCode FollowerIds(long cursor, ref string content)
657         {
658             Dictionary<string, string> param = new Dictionary<string, string>();
659             param.Add("cursor", cursor.ToString());
660
661             return httpCon.GetContent(GetMethod,
662                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/followers/ids.json" : "/1/followers/ids.json"),
663                 param,
664                 ref content,
665                 this.apiStatusHeaders,
666                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/followers/ids") : GetApiCallback);
667         }
668
669         public HttpStatusCode NoRetweetIds(long cursor, ref string content)
670         {
671             Dictionary<string, string> param = new Dictionary<string, string>();
672             param.Add("cursor", cursor.ToString());
673
674             return httpCon.GetContent(GetMethod,
675                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/friendships/no_retweets/ids.json" : "/1/friendships/no_retweet_ids.json"),
676                 param,
677                 ref content,
678                 this.apiStatusHeaders,
679                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/friendships/no_retweets/ids") : GetApiCallback);
680         }
681
682         public HttpStatusCode RateLimitStatus(ref string content)
683         {
684             return httpCon.GetContent(GetMethod,
685                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/application/rate_limit_status.json" : "/1/account/rate_limit_status.json"),
686                 null,
687                 ref content,
688                 this.apiStatusHeaders,
689                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/application/rate_limit_status") : GetApiCallback);
690         }
691
692         #region Lists
693         public HttpStatusCode GetLists(string user, long? cursor, ref string content)
694         {
695             Dictionary<string, string> param = new Dictionary<string, string>();
696             param.Add("screen_name", user);
697
698             if (cursor != null)
699                 param.Add("cursor", cursor.Value.ToString()); // API v1
700
701             return httpCon.GetContent(GetMethod,
702                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/lists/list.json" : "/1/lists.json"),
703                 param,
704                 ref content,
705                 this.apiStatusHeaders,
706                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/lists/list") : GetApiCallback);
707         }
708
709         public HttpStatusCode UpdateListID(string user, string list_id, string name, Boolean isPrivate, string description, ref string content)
710         {
711             string mode = "public";
712             if (isPrivate)
713                 mode = "private";
714
715             Dictionary<string, string> param = new Dictionary<string, string>();
716             param.Add("screen_name", user);
717             param.Add("list_id", list_id);
718             if (name != null) param.Add("name", name);
719             if (mode != null) param.Add("mode", mode);
720             if (description != null) param.Add("description", description);
721
722             return httpCon.GetContent(PostMethod,
723                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/lists/update.json" : "/1/lists/update.json"),
724                 param,
725                 ref content,
726                 null,
727                 null);
728         }
729
730         public HttpStatusCode DeleteListID(string user, string list_id, ref string content)
731         {
732             Dictionary<string, string> param = new Dictionary<string, string>();
733             param.Add("screen_name", user);
734             param.Add("list_id", list_id);
735
736             return httpCon.GetContent(PostMethod,
737                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/lists/destroy.json" : "/1/lists/destroy.json"),
738                 param,
739                 ref content,
740                 null,
741                 null);
742         }
743
744         public HttpStatusCode GetListsSubscriptions(string user, long? cursor, ref string content)
745         {
746             Dictionary<string, string> param = new Dictionary<string, string>();
747             param.Add("screen_name", user);
748
749             if (cursor != null)
750                 param.Add("cursor", cursor.Value.ToString()); // API v1
751
752             return httpCon.GetContent(GetMethod,
753                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/lists/subscriptions.json" : "/1/lists/subscriptions.json"),
754                 param,
755                 ref content,
756                 this.apiStatusHeaders,
757                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/lists/subscriptions") : GetApiCallback);
758         }
759
760         public HttpStatusCode GetListsStatuses(long userId, long list_id, int per_page, long max_id, long since_id, Boolean isRTinclude, ref string content)
761         {
762             //認証なくても取得できるが、protectedユーザー分が抜ける
763             Dictionary<string, string> param = new Dictionary<string, string>();
764             param.Add("user_id", userId.ToString());
765             param.Add("list_id", list_id.ToString());
766             param.Add("include_rts", isRTinclude ? "true" : "false");
767             if (per_page > 0)
768                 param.Add(HttpTwitter.API11Enabled ? "count" : "per_page", per_page.ToString());
769             if (max_id > 0)
770                 param.Add("max_id", max_id.ToString());
771             if (since_id > 0)
772                 param.Add("since_id", since_id.ToString());
773             param.Add("include_entities", "true");
774
775             return httpCon.GetContent(GetMethod,
776                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/lists/statuses.json" : "/1/lists/statuses.json"),
777                 param,
778                 ref content,
779                 this.apiStatusHeaders,
780                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/lists/statuses") : GetApiCallback);
781         }
782
783         public HttpStatusCode CreateLists(string listname, Boolean isPrivate, string description, ref string content)
784         {
785             string mode = "public";
786             if (isPrivate)
787                 mode = "private";
788
789             Dictionary<string, string> param = new Dictionary<string, string>();
790             param.Add("name", listname);
791             param.Add("mode", mode);
792             if (!string.IsNullOrEmpty(description))
793                 param.Add("description", description);
794
795             return httpCon.GetContent(PostMethod,
796                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/lists/create.json" : "/1/lists/create.json"),
797                 param,
798                 ref content,
799                 null,
800                 null);
801         }
802
803         public HttpStatusCode GetListMembers(string user, string list_id, long cursor, ref string content)
804         {
805             Dictionary<string, string> param = new Dictionary<string, string>();
806             param.Add("screen_name", user);
807             param.Add("list_id", list_id);
808             param.Add("cursor", cursor.ToString());
809             return httpCon.GetContent(GetMethod,
810                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/lists/members.json" : "/1/lists/members.json"),
811                 param,
812                 ref content,
813                 this.apiStatusHeaders,
814                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/lists/members") : GetApiCallback);
815         }
816
817         public HttpStatusCode CreateListMembers(string list_id, string memberName, ref string content)
818         {
819             Dictionary<string, string> param = new Dictionary<string, string>();
820             param.Add("list_id", list_id);
821             param.Add("screen_name", memberName);
822             return httpCon.GetContent(PostMethod,
823                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/lists/members/create.json" : "/1/lists/members/create.json"),
824                 param,
825                 ref content,
826                 null,
827                 null);
828         }
829
830         //public HttpStatusCode CreateListMembers(string user, string list_id, string memberName, ref string content)
831         //{
832         //    //正常に動かないので旧APIで様子見
833         //    //Dictionary<string, string> param = new Dictionary<string, string>();
834         //    //param.Add("screen_name", user)
835         //    //param.Add("list_id", list_id)
836         //    //param.Add("member_screen_name", memberName)
837         //    //return httpCon.GetContent(PostMethod,
838         //    //                          CreateTwitterUri("/1/lists/members/create.json"),
839         //    //                          param,
840         //    //                          ref content,
841         //    //                          null,
842         //    //                          null)
843         //    Dictionary<string, string> param = new Dictionary<string, string>();
844         //    param.Add("id", memberName)
845         //    return httpCon.GetContent(PostMethod,
846         //                              CreateTwitterUri("/1/" + user + "/" + list_id + "/members.json"),
847         //                              param,
848         //                              ref content,
849         //                              null,
850         //                              null)
851         //}
852
853         public HttpStatusCode DeleteListMembers(string list_id, string memberName, ref string content)
854         {
855             Dictionary<string, string> param = new Dictionary<string, string>();
856             param.Add("screen_name", memberName);
857             param.Add("list_id", list_id);
858             return httpCon.GetContent(PostMethod,
859                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/lists/members/destroy.json" : "/1/lists/members/destroy.json"),
860                 param,
861                 ref content,
862                 null,
863                 null);
864         }
865
866         //public HttpStatusCode DeleteListMembers(string user, string list_id, string memberName, ref string content)
867         //{
868         //    //Dictionary<string, string> param = new Dictionary<string, string>();
869         //    //param.Add("screen_name", user)
870         //    //param.Add("list_id", list_id)
871         //    //param.Add("member_screen_name", memberName)
872         //    //return httpCon.GetContent(PostMethod,
873         //    //                          CreateTwitterUri("/1/lists/members/destroy.json"),
874         //    //                          param,
875         //    //                          ref content,
876         //    //                          null,
877         //    //                          null)
878         //    Dictionary<string, string> param = new Dictionary<string, string>();
879         //    param.Add("id", memberName)
880         //    param.Add("_method", "DELETE")
881         //    return httpCon.GetContent(PostMethod,
882         //                              CreateTwitterUri("/1/" + user + "/" + list_id + "/members.json"),
883         //                              param,
884         //                              ref content,
885         //                              null,
886         //                              null)
887         //}
888
889         public HttpStatusCode ShowListMember(string list_id, string memberName, ref string content)
890         {
891             //新APIがmember_screen_nameもmember_user_idも無視して、自分のIDを返してくる。
892             //正式にドキュメントに反映されるまで旧APIを使用する
893             Dictionary<string, string> param = new Dictionary<string, string>();
894             param.Add("screen_name", memberName);
895             param.Add("list_id", list_id);
896             return httpCon.GetContent(GetMethod,
897                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/lists/members/show.json" : "/1/lists/members/show.json"),
898                 param,
899                 ref content,
900                 this.apiStatusHeaders,
901                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/lists/members/show") : GetApiCallback);
902         }
903         #endregion
904
905         public HttpStatusCode Statusid_retweeted_by_ids(long statusid, int count, int page, ref string content)
906         {
907             Dictionary<string, string> param = new Dictionary<string, string>();
908             if (count > 0)
909                 param.Add("count", count.ToString());
910             if (page > 0)
911                 param.Add("page", page.ToString());
912
913             if (HttpTwitter.API11Enabled)
914                 param.Add("id", statusid.ToString());
915
916             return httpCon.GetContent(GetMethod,
917                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/statuses/retweeters/ids.json" : "/1/statuses/" + statusid + "/retweeted_by/ids.json"),
918                 param,
919                 ref content,
920                 this.apiStatusHeaders,
921                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/statuses/retweeters/ids") : GetApiCallback);
922         }
923
924         public HttpStatusCode UpdateProfile(string name, string url, string location, string description, ref string content)
925         {
926             Dictionary<string, string> param = new Dictionary<string, string>();
927
928             param.Add("name", WebUtility.HtmlEncode(name));
929             param.Add("url", url);
930             param.Add("location", WebUtility.HtmlEncode(location));
931             param.Add("description", WebUtility.HtmlEncode(description));
932             param.Add("include_entities", "true");
933
934             return httpCon.GetContent(PostMethod,
935                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/account/update_profile.json" : "/1/account/update_profile.json"),
936                 param,
937                 ref content,
938                 null,
939                 null);
940         }
941
942         public HttpStatusCode UpdateProfileImage(FileInfo imageFile, ref string content)
943         {
944             List<KeyValuePair<string, FileInfo>> binary = new List<KeyValuePair<string, FileInfo>>();
945             binary.Add(new KeyValuePair<string, FileInfo>("image", imageFile));
946
947             return httpCon.GetContent(PostMethod,
948                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/account/update_profile_image.json" : "/1/account/update_profile_image.json"),
949                 null,
950                 binary,
951                 ref content,
952                 null,
953                 null);
954         }
955
956         public HttpStatusCode GetRelatedResults(long id, ref string content)
957         {
958             //認証なくても取得できるが、protectedユーザー分が抜ける
959             Dictionary<string, string> param = new Dictionary<string, string>();
960
961             param.Add("id", id.ToString());
962             param.Add("include_entities", "true");
963
964             // TODO: API v1.1 に存在しない API (旧 API で代替)
965
966             return httpCon.GetContent(GetMethod,
967                 CreateTwitterUri("/1/related_results/show.json"),
968                 param,
969                 ref content,
970                 this.apiStatusHeaders,
971                 GetApiCallback);
972         }
973
974         public HttpStatusCode GetBlockUserIds(ref string content)
975         {
976             return httpCon.GetContent(GetMethod,
977                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/blocks/ids.json" : "/1/blocks/blocking/ids.json"),
978                 null,
979                 ref content,
980                 this.apiStatusHeaders,
981                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/blocks/ids") : GetApiCallback);
982         }
983
984         public HttpStatusCode GetConfiguration(ref string content)
985         {
986             return httpCon.GetContent(GetMethod,
987                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/help/configuration.json" : "/1/help/configuration.json"),
988                 null,
989                 ref content,
990                 this.apiStatusHeaders,
991                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/help/configuration") : GetApiCallback);
992         }
993
994         public HttpStatusCode VerifyCredentials(ref string content)
995         {
996             return httpCon.GetContent(GetMethod,
997                 CreateTwitterUri(HttpTwitter.API11Enabled ? "/1.1/account/verify_credentials.json" : "/1/account/verify_credentials.json"),
998                 null,
999                 ref content,
1000                 this.apiStatusHeaders,
1001                 HttpTwitter.API11Enabled ? CreateApi11Calllback("/account/verify_credentials") : GetApiCallback);
1002         }
1003
1004         #region Proxy API
1005         private static string _twitterUrl = "api.twitter.com";
1006         private static string _TwitterSearchUrl = "search.twitter.com";
1007         private static string _twitterUserStreamUrl = "userstream.twitter.com";
1008         private static string _twitterStreamUrl = "stream.twitter.com";
1009
1010         private Uri CreateTwitterUri(string path)
1011         {
1012             return new Uri(string.Format("{0}{1}{2}", _protocol, _twitterUrl, path));
1013         }
1014
1015         private Uri CreateTwitterSearchUri(string path)
1016         {
1017             return new Uri(string.Format("{0}{1}{2}", _protocol, _TwitterSearchUrl, path));
1018         }
1019
1020         private Uri CreateTwitterUserStreamUri(string path)
1021         {
1022             return new Uri(string.Format("{0}{1}{2}", "https://", _twitterUserStreamUrl, path));
1023         }
1024
1025         private Uri CreateTwitterStreamUri(string path)
1026         {
1027             return new Uri(string.Format("{0}{1}{2}", "http://", _twitterStreamUrl, path));
1028         }
1029
1030         public static string TwitterUrl
1031         {
1032             set
1033             {
1034                 _twitterUrl = value;
1035                 HttpOAuthApiProxy.ProxyHost = value;
1036             }
1037         }
1038
1039         public static string TwitterSearchUrl
1040         {
1041             set
1042             {
1043                 _TwitterSearchUrl = value;
1044             }
1045         }
1046         #endregion
1047
1048         private void GetApiCallback(Object sender, HttpStatusCode code, string content)
1049         {
1050             if (code < HttpStatusCode.InternalServerError)
1051                 MyCommon.TwitterApiInfo.UpdateFromHeader(this.apiStatusHeaders);
1052         }
1053
1054         private CallbackDelegate CreateApi11Calllback(string endpointName)
1055         {
1056             return (sender, code, content) =>
1057             {
1058                 if (code < HttpStatusCode.InternalServerError)
1059                     MyCommon.TwitterApiInfo11.UpdateFromHeader(this.apiStatusHeaders, endpointName);
1060             };
1061         }
1062
1063         public HttpStatusCode UserStream(ref Stream content,
1064                                          bool allAtReplies,
1065                                          string trackwords,
1066                                          string userAgent)
1067         {
1068             Dictionary<string, string> param = new Dictionary<string, string>();
1069
1070             if (allAtReplies)
1071                 param.Add("replies", "all");
1072
1073             if (!string.IsNullOrEmpty(trackwords))
1074                 param.Add("track", trackwords);
1075
1076             return httpCon.GetContent(GetMethod,
1077                 CreateTwitterUserStreamUri(HttpTwitter.API11Enabled ? "/1.1/user.json" : "/2/user.json"),
1078                 param,
1079                 ref content,
1080                 userAgent);
1081         }
1082
1083         public HttpStatusCode FilterStream(ref Stream content,
1084                                            string trackwords,
1085                                            string userAgent)
1086         {
1087             //文中の日本語キーワードに反応せず、使えない(スペースで分かち書きしてないと反応しない)
1088             Dictionary<string, string> param = new Dictionary<string, string>();
1089
1090             if (!string.IsNullOrEmpty(trackwords))
1091                 param.Add("track", string.Join(",", trackwords.Split(" ".ToCharArray())));
1092
1093             return httpCon.GetContent(PostMethod,
1094                 CreateTwitterStreamUri(HttpTwitter.API11Enabled ? "/1.1/statuses/filter.json" : "/1/statuses/filter.json"),
1095                 param,
1096                 ref content,
1097                 userAgent);
1098         }
1099
1100         public void RequestAbort()
1101         {
1102             httpCon.RequestAbort();
1103         }
1104
1105         public object Clone()
1106         {
1107             HttpTwitter myCopy = new HttpTwitter();
1108             myCopy.Initialize(this.AccessToken, this.AccessTokenSecret, this.AuthenticatedUsername, this.AuthenticatedUserId);
1109             return myCopy;
1110         }
1111     }
1112 }