Fix previous commit
[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                 Parser.init();
288                 Status status = parse_status(data);
289                 Parser.cleanup();
290                 
291                 return status;
292         }
293         
294         private Status parse_status(string data) throws ParseError {
295                 Xml.Doc* xmlDoc = Parser.parse_memory(data, (int)data.size());
296                 Xml.Node* rootNode = xmlDoc->get_root_element();
297                 
298                 //changing locale to C
299                 string currentLocale = GLib.Intl.setlocale(GLib.LocaleCategory.TIME, null);
300                 GLib.Intl.setlocale(GLib.LocaleCategory.TIME, "C");
301                 
302                 Status status = new Status();
303                 
304                 for(Xml.Node* iter = rootNode->children; iter != null; iter = iter->next) {
305                         if(iter->type != ElementType.ELEMENT_NODE)
306                                 continue;
307                         
308                         switch(iter->name) {
309                                 case "id":
310                                         status.id = iter->get_content();
311                                 break;
312                         
313                         case "created_at":
314                                 status.created_at = str_to_time(iter->get_content());
315                                 status.created_at_s = iter->get_content();
316                                 break;
317                         
318                         case "text":
319                                 status.text = iter->get_content();
320                                 break;
321                         
322                         case "in_reply_to_screen_name":
323                                 status.to_user = iter->get_content();
324                                 break;
325                         
326                         case "in_reply_to_status_id":
327                                 status.to_status_id = iter->get_content();
328                                 break;
329                         
330                         case "user":
331                                 Xml.Node *iter_user;
332                                 
333                                         for(iter_user = iter->children->next; iter_user != null; iter_user = iter_user->next) {
334                                                 switch(iter_user->name) {
335                                                         case "id":
336                                                         break;
337                                                 
338                                                 case "name":
339                                                         status.user_name = iter_user->get_content();
340                                                         break;
341                                                 
342                                                 case "screen_name":
343                                                         status.user_screen_name = iter_user->get_content();
344                                                         break;
345                                                 
346                                                 case "profile_image_url":
347                                                         status.user_avatar = iter_user->get_content();
348                                                         break;
349                                                 }
350                                 }
351                                 delete iter_user;
352                                 break;
353                         }
354                 }
355                 
356                 //back to the normal locale
357                 GLib.Intl.setlocale(GLib.LocaleCategory.TIME, currentLocale);
358                 
359                 return status;
360         }
361 }
362
363 }