Add Cristian Greco as uploader
[debian/pino.git] / src / rest_api_timeline.vala
1 /* rest_api_timeline.vala
2  *
3  * Copyright (C) 2009-2010  troorl
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  * Author:
19  *      troorl <troorl@gmail.com>
20  */
21
22 using Soup;
23 using Gee;
24 using Xml;
25 using Auth;
26 using TimeUtils;
27
28 namespace RestAPI {
29
30 public class RestAPITimeline : RestAPIAbstract {
31         
32         private TimelineType timeline_type;
33         
34         public RestAPITimeline(Account? _account,
35                 TimelineType _timeline_type) {
36                 base(_account);
37                 this.timeline_type = _timeline_type;
38         }
39         
40         /* destroy status */
41         public override void destroy_status(string id) throws RestError {
42                 string req_url = urls.destroy_status().printf(id);
43                 make_request(req_url, "POST");
44         }
45         
46         /* add to favorites */
47         public override void favorite_create(string id) throws RestError {
48                 string req_url = urls.favorite_create().printf(id);
49                 make_request(req_url, "POST");
50         }
51         
52         /* remove from favorites */
53         public override void favorite_destroy(string id) throws RestError {
54                 string req_url = urls.favorite_destroy().printf(id);
55                 make_request(req_url, "POST");
56         }
57         
58         /* for timelines (home, mentions, public etc.) */
59         public override ArrayList<Status>? get_timeline(int count = 0, FullStatus? fstatus = null,
60                 string since_id = "", string max_id = "", bool async = true) throws RestError, ParseError {
61                 
62                 if(account == null)
63                         no_account();
64                 
65                 string req_url = "";
66                 
67                 switch(timeline_type) {
68                         case TimelineType.HOME:
69                                 req_url = urls.home();
70                                 break;
71                         case TimelineType.MENTIONS:
72                                 req_url = urls.mentions();
73                                 break;
74                         case TimelineType.USER:
75                                 req_url = urls.users_timeline().printf(fstatus.user_screen_name);
76                                 break;
77                         case TimelineType.FAVORITES:
78                                 req_url = urls.favorites();
79                                 break;
80                 }
81                 
82                 var map = new HashTable<string, string>(str_hash, str_equal);
83                 if(count != 0)
84                         map.insert("count", count.to_string());
85                 if(since_id != "")
86                         map.insert("since_id", since_id);
87                 if(max_id != "")
88                         map.insert("max_id", max_id);
89                 debug(req_url);
90                 
91                 string data = make_request(req_url, "GET", map, async);
92
93                 Parser.init();
94                 ArrayList<Status> result = parse_timeline(data, fstatus);
95                 Parser.cleanup();
96                 return result;
97         }
98         
99         /* parsing timeline */
100         private ArrayList<Status> parse_timeline(string data,
101                 FullStatus? fstatus) throws ParseError {
102                 
103                 Xml.Doc* xmlDoc = Parser.parse_memory(data, (int)data.size());
104                 if(xmlDoc == null)
105                         throw new ParseError.CODE("Invalid XML data");
106                 
107                 Xml.Node* rootNode = xmlDoc->get_root_element();
108                 
109                 //changing locale to C
110                 string currentLocale = GLib.Intl.setlocale(GLib.LocaleCategory.TIME, null);
111                 GLib.Intl.setlocale(GLib.LocaleCategory.TIME, "C");
112                 //debug(data);
113                 ArrayList<Status> lst = new ArrayList<Status>();
114                 debug("start parsing");
115                 for(Xml.Node* iter = rootNode->children; iter != null; iter = iter->next) {
116                         if(iter == null)
117                                 debug("hoho! iter is null!");
118                         
119                         //debug("we in the loop");
120                         if(iter->type != ElementType.ELEMENT_NODE)
121                                 continue;
122                         //debug("And here we go");
123                         if(iter->name == "status") {
124                                 
125                                 if(iter->children != null) {
126                                 Status status = new Status();
127                                 Xml.Node *iter_in;
128                                     
129                                     for(iter_in = iter->children->next; iter_in != null; iter_in = iter_in->next) {
130                                         
131                                         if(iter_in->is_text() != 1) {
132                                                 
133                                                 switch(iter_in->name) {
134                                                         case "id":
135                                                                 status.id = iter_in->get_content();
136                                                                 break;
137                                                         
138                                                         case "created_at":
139                                                                 status.created_at = str_to_time(iter_in->get_content());
140                                                                 status.created_at_s = iter_in->get_content();
141                                                                 //debug(iter_in->get_content());
142                                                                 break;
143                                                         
144                                                         case "text":
145                                                                 status.text = iter_in->get_content();
146                                                                 break;
147                                                         
148                                                         case "in_reply_to_screen_name":
149                                                                 status.to_user = iter_in->get_content();
150                                                                 break;
151                                                         
152                                                         case "in_reply_to_status_id":
153                                                                 status.to_status_id = iter_in->get_content();
154                                                                 break;
155                                                         
156                                                         case "favorited":
157                                                                 status.is_favorite = iter_in->get_content().to_bool();
158                                                                 break;
159                                                         
160                                                         case "retweeted_status":
161                                                                 status.is_retweet = true;
162                                                                 
163                                                                 Xml.Node *iter_retweet;
164                                                                 
165                                                                 for(iter_retweet = iter_in->children->next; iter_retweet != null; iter_retweet = iter_retweet->next) {
166                                                                         if(iter_retweet->is_text() != 1) {
167                                                                                 
168                                                                                         switch(iter_retweet->name) {
169                                                                                                 case "text":
170                                                                                                         status.re_text = iter_retweet->get_content();
171                                                                                                         break;
172                                                                                                 
173                                                                                                 case "user":
174                                                                                                         Xml.Node *iter_re_user;
175                                                                                                         
176                                                                                                         for(iter_re_user = iter_retweet->children->next; iter_re_user != null; iter_re_user = iter_re_user->next) {
177                                                                                                                 switch(iter_re_user->name) {
178                                                                                                                         case "name":
179                                                                                                                                 status.re_user_name = iter_re_user->get_content();
180                                                                                                                                 break;
181                                                                                                                         
182                                                                                                                         case "screen_name":
183                                                                                                                                 status.re_user_screen_name = iter_re_user->get_content();
184                                                                                                                                 break;
185                                                                                                                         
186                                                                                                                         case "profile_image_url":
187                                                                                                                                 status.re_user_avatar = iter_re_user->get_content();
188                                                                                                                                 break;
189                                                                                                                 }
190                                                                                                         }
191                                                                                                         delete iter_re_user;
192                                                                                                         break;
193                                                                                         }
194                                                                         }
195                                                                 }
196                                                                 
197                                                                 delete iter_retweet;
198                                                                 break;
199                                                         
200                                                         case "user":
201                                                                 Xml.Node *iter_user;
202                                                                 
203                                                                         for(iter_user = iter_in->children->next; iter_user != null; iter_user = iter_user->next) {
204                                                                                 if(fstatus != null && !fstatus.done) { //get full info about this user
205                                                                                         switch(iter_user->name) {
206                                                                                                 case "name":
207                                                                                                         status.user_name = iter_user->get_content();
208                                                                                                         fstatus.user_name = iter_user->get_content();
209                                                                                                         break;
210                                                                                         
211                                                                                                 case "screen_name":
212                                                                                                         debug("This is %s", iter_user->get_content());
213                                                                                                         status.user_screen_name = iter_user->get_content();
214                                                                                                         fstatus.user_screen_name = iter_user->get_content();
215                                                                                                         break;
216                                                                                         
217                                                                                                 case "profile_image_url":
218                                                                                                         status.user_avatar = iter_user->get_content();
219                                                                                                         fstatus.user_avatar = iter_user->get_content();
220                                                                                                         break;
221                                                                                                 
222                                                                                                 case "followers_count":
223                                                                                                         fstatus.followers = iter_user->get_content();
224                                                                                                         break;
225                                                                                                 
226                                                                                                 case "friends_count":
227                                                                                                         fstatus.friends = iter_user->get_content();
228                                                                                                         break;
229                                                                                                 
230                                                                                                 case "statuses_count":
231                                                                                                         fstatus.statuses = iter_user->get_content();
232                                                                                                         break;
233                                                                                                 
234                                                                                                 case "url":
235                                                                                                         fstatus.url = iter_user->get_content();
236                                                                                                         break;
237                                                                                                 
238                                                                                                 case "description":
239                                                                                                         fstatus.desc = iter_user->get_content();
240                                                                                                         break;
241                                                                                         }
242                                                                                 } else {
243                                                                                         switch(iter_user->name) {
244                                                                                                 case "name":
245                                                                                                         status.user_name = iter_user->get_content();
246                                                                                                         break;
247                                                                                         
248                                                                                                 case "screen_name":
249                                                                                                         status.user_screen_name = iter_user->get_content();
250                                                                                                         break;
251                                                                                         
252                                                                                                 case "profile_image_url":
253                                                                                                         status.user_avatar = iter_user->get_content();
254                                                                                                         break;
255                                                                                         }
256                                                                                 }
257                                                                         
258                                                                 }
259                                                                 
260                                                                 if(fstatus != null)
261                                                                         fstatus.done = true;
262                                                                 
263                                                                 delete iter_user;
264                                                                 break;
265                                                 }
266                                         }
267                                     }
268                                     delete iter_in;
269                                     
270                                     lst.add(status);
271                                     
272                                 }
273                     }
274                     delete iter; //memory leak was here >:3
275                 }
276                 
277                 //back to the normal locale
278                 GLib.Intl.setlocale(GLib.LocaleCategory.TIME, currentLocale);
279                 return lst;
280         }
281         
282         /* return single status */
283         public override Status get_status(string id) throws RestError, ParseError {
284                 string req_url = urls.status().printf(id);
285                 string data = make_request(req_url, "GET");
286                 
287                 return parse_status(data);
288         }
289         
290         private Status parse_status(string data) throws ParseError {
291                 Xml.Doc* xmlDoc = Parser.parse_memory(data, (int)data.size());
292                 Xml.Node* rootNode = xmlDoc->get_root_element();
293                 
294                 //changing locale to C
295                 string currentLocale = GLib.Intl.setlocale(GLib.LocaleCategory.TIME, null);
296                 GLib.Intl.setlocale(GLib.LocaleCategory.TIME, "C");
297                 
298                 Status status = new Status();
299                 
300                 for(Xml.Node* iter = rootNode->children; iter != null; iter = iter->next) {
301                         if(iter->type != ElementType.ELEMENT_NODE)
302                                 continue;
303                         
304                         switch(iter->name) {
305                                 case "id":
306                                         status.id = iter->get_content();
307                                 break;
308                         
309                         case "created_at":
310                                 status.created_at = str_to_time(iter->get_content());
311                                 break;
312                         
313                         case "text":
314                                 status.text = iter->get_content();
315                                 break;
316                         
317                         case "in_reply_to_screen_name":
318                                 status.to_user = iter->get_content();
319                                 break;
320                         
321                         case "in_reply_to_status_id":
322                                 status.to_status_id = iter->get_content();
323                                 break;
324                         
325                         case "user":
326                                 Xml.Node *iter_user;
327                                 
328                                         for(iter_user = iter->children->next; iter_user != null; iter_user = iter_user->next) {
329                                                 switch(iter_user->name) {
330                                                         case "id":
331                                                         break;
332                                                 
333                                                 case "name":
334                                                         status.user_name = iter_user->get_content();
335                                                         break;
336                                                 
337                                                 case "screen_name":
338                                                         status.user_screen_name = iter_user->get_content();
339                                                         break;
340                                                 
341                                                 case "profile_image_url":
342                                                         status.user_avatar = iter_user->get_content();
343                                                         break;
344                                                 }
345                                 }
346                                 delete iter_user;
347                                 break;
348                         }
349                 }
350                 
351                 //back to the normal locale
352                 GLib.Intl.setlocale(GLib.LocaleCategory.TIME, currentLocale);
353                 
354                 return status;
355         }
356 }
357
358 }