Line | Branch | Exec | Source |
---|---|---|---|
1 | /* GATE PROJECT LICENSE: | ||
2 | +----------------------------------------------------------------------------+ | ||
3 | | Copyright(c) 2018-2025, Stefan Meislinger | | ||
4 | | All rights reserved. | | ||
5 | | | | ||
6 | | Redistribution and use in source and binary forms, with or without | | ||
7 | | modification, are permitted provided that the following conditions are met:| | ||
8 | | | | ||
9 | | 1. Redistributions of source code must retain the above copyright notice, | | ||
10 | | this list of conditions and the following disclaimer. | | ||
11 | | 2. Redistributions in binary form must reproduce the above copyright | | ||
12 | | notice, this list of conditions and the following disclaimer in the | | ||
13 | | documentation and/or other materials provided with the distribution. | | ||
14 | | | | ||
15 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"| | ||
16 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | ||
17 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ||
18 | | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | | ||
19 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | ||
20 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | ||
21 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | ||
22 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | ||
23 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | ||
24 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | | ||
25 | | THE POSSIBILITY OF SUCH DAMAGE. | | ||
26 | +----------------------------------------------------------------------------+ | ||
27 | */ | ||
28 | |||
29 | #include "gate/tech/webapis.h" | ||
30 | #include "gate/results.h" | ||
31 | #include "gate/encode/xml.h" | ||
32 | |||
33 | #define GATE_WEBAPIS_NEWSFEED_REQUEST_NAME GATE_STRUCT_WEBAPIS_NAME("newsfeed_request") | ||
34 | #define GATE_WEBAPIS_NEWSFEED_RESPONSE_NAME GATE_STRUCT_WEBAPIS_NAME("newsfeed_response") | ||
35 | #define GATE_WEBAPIS_NEWSENTRY_NAME GATE_STRUCT_WEBAPIS_NAME("newsfeed_entry") | ||
36 | |||
37 | |||
38 | |||
39 | /* newsfeed request initialization */ | ||
40 | |||
41 | static gate_struct_item_t const newsfeed_request_members[] = | ||
42 | { | ||
43 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsfeed_request_t, GATE_TYPE_STRING, request_url, "Request URL", GATE_STRUCT_FLAG_DEFAULT) | ||
44 | }; | ||
45 | |||
46 | static gate_struct_descriptor_t const newsfeed_request_descriptor = | ||
47 | GATE_STRUCT_DESCRIPTOR(gate_tech_webapi_newsfeed_request_t, GATE_WEBAPIS_NEWSFEED_REQUEST_NAME, newsfeed_request_members); | ||
48 | |||
49 | 1 | GATE_TECH_API void gate_tech_webapi_newsfeed_request_init(gate_tech_webapi_newsfeed_request_t* request) | |
50 | { | ||
51 | 1 | gate_mem_clear(request, sizeof(gate_tech_webapi_newsfeed_request_t)); | |
52 | 1 | request->struct_base.struct_descriptor = &newsfeed_request_descriptor; | |
53 | 1 | } | |
54 | |||
55 | |||
56 | |||
57 | /* newsentry initialization */ | ||
58 | |||
59 | static gate_struct_item_t const newsentry_members[] = | ||
60 | { | ||
61 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsentry_t, GATE_TYPE_STRING, uid, "Unique-ID", GATE_STRUCT_FLAG_DEFAULT), | ||
62 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsentry_t, GATE_TYPE_STRING, title, "Title", GATE_STRUCT_FLAG_DEFAULT), | ||
63 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsentry_t, GATE_TYPE_STRING, link, "Link", GATE_STRUCT_FLAG_DEFAULT), | ||
64 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsentry_t, GATE_TYPE_TIME, update_time, "Updated", GATE_STRUCT_FLAG_DEFAULT), | ||
65 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsentry_t, GATE_TYPE_STRING, author, "Author", GATE_STRUCT_FLAG_DEFAULT), | ||
66 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsentry_t, GATE_TYPE_STRING, category, "Category", GATE_STRUCT_FLAG_DEFAULT), | ||
67 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsentry_t, GATE_TYPE_STRING, summary, "Summary", GATE_STRUCT_FLAG_DEFAULT), | ||
68 | |||
69 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsentry_t, GATE_TYPE_STRING, content, "Content", GATE_STRUCT_FLAG_DEFAULT) | ||
70 | }; | ||
71 | |||
72 | static gate_struct_descriptor_t const newsentry_descriptor = | ||
73 | GATE_STRUCT_DESCRIPTOR(gate_tech_webapi_newsentry_t, GATE_WEBAPIS_NEWSENTRY_NAME, newsentry_members); | ||
74 | |||
75 | 20 | void gate_tech_webapi_newsentry_init(gate_tech_webapi_newsentry_t* entry) | |
76 | { | ||
77 | 20 | gate_mem_clear(entry, sizeof(gate_tech_webapi_newsentry_t)); | |
78 | 20 | entry->struct_base.struct_descriptor = &newsentry_descriptor; | |
79 | 20 | } | |
80 | 51 | static gate_result_t gate_tech_webapi_newsentry_copyctor(void* target, void const* source) | |
81 | { | ||
82 | gate_result_t result; | ||
83 | 51 | gate_tech_webapi_newsentry_t* ptr_dst = (gate_tech_webapi_newsentry_t*)target; | |
84 | 51 | gate_tech_webapi_newsentry_t const* ptr_src = (gate_tech_webapi_newsentry_t const*)source; | |
85 | |||
86 |
1/2✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
|
51 | if (ptr_src) |
87 | { | ||
88 | 51 | gate_mem_clear(ptr_dst, sizeof(gate_tech_webapi_newsentry_t)); | |
89 | 51 | result = gate_struct_copy(&ptr_dst->struct_base, &ptr_src->struct_base); | |
90 | } | ||
91 | else | ||
92 | { | ||
93 | ✗ | gate_tech_webapi_newsentry_init(ptr_dst); | |
94 | ✗ | result = GATE_RESULT_OK; | |
95 | } | ||
96 | 51 | return result; | |
97 | } | ||
98 | |||
99 | |||
100 | |||
101 | |||
102 | static gate_struct_item_t const newsfeed_response_members[] = | ||
103 | { | ||
104 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsfeed_response_t, GATE_TYPE_STRING, request_url, "Request URL", GATE_STRUCT_FLAG_DEFAULT), | ||
105 | |||
106 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsfeed_response_t, GATE_TYPE_STRING, uid, "Unique-ID", GATE_STRUCT_FLAG_DEFAULT), | ||
107 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsfeed_response_t, GATE_TYPE_STRING, title, "Title", GATE_STRUCT_FLAG_DEFAULT), | ||
108 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsfeed_response_t, GATE_TYPE_STRING, link, "Link", GATE_STRUCT_FLAG_DEFAULT), | ||
109 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsfeed_response_t, GATE_TYPE_TIME, update_time, "Updated", GATE_STRUCT_FLAG_DEFAULT), | ||
110 | |||
111 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsfeed_response_t, GATE_TYPE_STRING, description,"Description", GATE_STRUCT_FLAG_DEFAULT), | ||
112 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsfeed_response_t, GATE_TYPE_STRING, language, "Language", GATE_STRUCT_FLAG_DEFAULT), | ||
113 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsfeed_response_t, GATE_TYPE_STRING, publisher, "Publisher", GATE_STRUCT_FLAG_DEFAULT), | ||
114 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsfeed_response_t, GATE_TYPE_STRING, contact, "Contact", GATE_STRUCT_FLAG_DEFAULT), | ||
115 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsfeed_response_t, GATE_TYPE_STRING, image, "Image", GATE_STRUCT_FLAG_DEFAULT), | ||
116 | |||
117 | GATE_STRUCT_ITEM_EX(gate_tech_webapi_newsfeed_response_t, GATE_TYPE_ARRAYLIST_STRUCT, entries, "Entries", GATE_STRUCT_FLAG_DEFAULT) | ||
118 | }; | ||
119 | |||
120 | static gate_struct_descriptor_t const newsfeed_response_descriptor = | ||
121 | GATE_STRUCT_DESCRIPTOR(gate_tech_webapi_newsfeed_response_t, GATE_WEBAPIS_NEWSFEED_RESPONSE_NAME, newsfeed_response_members); | ||
122 | |||
123 | 1 | GATE_TECH_API void gate_tech_webapi_newsfeed_response_init(gate_tech_webapi_newsfeed_response_t* response) | |
124 | { | ||
125 | 1 | gate_mem_clear(response, sizeof(gate_tech_webapi_newsfeed_response_t)); | |
126 | 1 | response->struct_base.struct_descriptor = &newsfeed_response_descriptor; | |
127 | 1 | response->entries = gate_arraylist_create(sizeof(gate_tech_webapi_newsentry_t), NULL, 0, | |
128 | &gate_tech_webapi_newsentry_copyctor, &gate_struct_destructor); | ||
129 | 1 | } | |
130 | |||
131 | |||
132 | 462 | static gate_bool_t xml_node_is_tag(gate_xml_node_t const* node, gate_string_t const* tagname) | |
133 | { | ||
134 | 462 | return gate_string_equals(&node->tag, tagname); | |
135 | } | ||
136 | |||
137 | 87 | static gate_xml_node_t const* get_child_by_tag(gate_xml_node_t const* node, gate_string_t const* tagname) | |
138 | { | ||
139 | 87 | gate_size_t children = gate_xml_node_children_count(node); | |
140 | gate_size_t ndx; | ||
141 | 87 | gate_xml_node_t const* ptr_child = NULL; | |
142 |
2/2✓ Branch 0 taken 434 times.
✓ Branch 1 taken 23 times.
|
457 | for (ndx = 0; ndx != children; ++ndx) |
143 | { | ||
144 | 434 | ptr_child = gate_xml_node_child_ptr(node, ndx); | |
145 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 434 times.
|
434 | if (!ptr_child) |
146 | { | ||
147 | ✗ | continue; | |
148 | } | ||
149 |
2/2✓ Branch 1 taken 64 times.
✓ Branch 2 taken 370 times.
|
434 | if (xml_node_is_tag(ptr_child, tagname)) |
150 | { | ||
151 | 64 | return ptr_child; | |
152 | } | ||
153 | } | ||
154 | 23 | return NULL; | |
155 | } | ||
156 | |||
157 | 20 | static gate_bool_t parse_time(gate_string_t const* str, gate_datetime_t* dt) | |
158 | { | ||
159 | /* "Thu, 11 Apr 2024 21:47:03" */ | ||
160 | 20 | gate_string_t str_day = GATE_STRING_INIT_STATIC("01"); | |
161 | 20 | gate_string_t str_mon = GATE_STRING_INIT_STATIC("Jan"); | |
162 | 20 | gate_string_t str_year = GATE_STRING_INIT_STATIC("1970"); | |
163 | 20 | gate_string_t str_hour = GATE_STRING_INIT_STATIC("00"); | |
164 | 20 | gate_string_t str_min = GATE_STRING_INIT_STATIC("00"); | |
165 | 20 | gate_string_t str_sec = GATE_STRING_INIT_STATIC("00"); | |
166 | 20 | gate_size_t len = gate_string_length(str); | |
167 | 20 | char const* ptr = gate_string_ptr(str, 0); | |
168 | gate_uint64_t num; | ||
169 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | if (len < 16) |
170 | { | ||
171 | ✗ | return false; | |
172 | } | ||
173 |
4/8✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 20 times.
|
20 | if ((ptr[3] != ',') || (ptr[4] != ' ') || (ptr[7] != ' ') || (ptr[11] != ' ')) |
174 | { | ||
175 | ✗ | return false; | |
176 | } | ||
177 | |||
178 | 20 | gate_mem_clear(dt, sizeof(gate_datetime_t)); | |
179 | |||
180 | 20 | gate_string_create_static_len(&str_day, &ptr[5], 2); | |
181 | 20 | gate_string_create_static_len(&str_mon, &ptr[8], 3); | |
182 | 20 | gate_string_create_static_len(&str_year, &ptr[12], 4); | |
183 | |||
184 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | if (len >= 22) |
185 | { | ||
186 | 20 | gate_string_create_static_len(&str_hour, &ptr[17], 2); | |
187 | 20 | gate_string_create_static_len(&str_min, &ptr[20], 2); | |
188 | } | ||
189 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | if (len >= 25) |
190 | { | ||
191 | 20 | gate_string_create_static_len(&str_sec, &ptr[23], 2); | |
192 | } | ||
193 | |||
194 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | if (gate_string_parse_uint(&str_day, &num) > 0) |
195 | { | ||
196 | 20 | dt->date.day = (gate_uint8_t)num; | |
197 | } | ||
198 | |||
199 | 20 | gate_date_parse_month(str_mon.str, str_mon.length, &dt->date.month); | |
200 | |||
201 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | if (gate_string_parse_uint(&str_year, &num) > 0) |
202 | { | ||
203 | 20 | dt->date.year = (gate_uint16_t)num; | |
204 | } | ||
205 | |||
206 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | if (gate_string_parse_uint(&str_hour, &num) > 0) |
207 | { | ||
208 | 20 | dt->time.hour = (gate_uint8_t)num; | |
209 | } | ||
210 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | if (gate_string_parse_uint(&str_min, &num) > 0) |
211 | { | ||
212 | 20 | dt->time.minute = (gate_uint8_t)num; | |
213 | } | ||
214 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | if (gate_string_parse_uint(&str_sec, &num) > 0) |
215 | { | ||
216 | 20 | dt->time.second = (gate_uint8_t)num; | |
217 | } | ||
218 | 20 | return true; | |
219 | } | ||
220 | |||
221 | 66 | static gate_bool_t extract_content(gate_xml_node_t const* node, gate_string_t* target) | |
222 | { | ||
223 | gate_size_t children, ndx; | ||
224 | gate_xml_node_t const* child; | ||
225 | 66 | gate_strbuilder_t builder = GATE_INIT_EMPTY; | |
226 | |||
227 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 22 times.
|
66 | if (node) |
228 | { | ||
229 |
1/2✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
|
44 | if (node->node_type == GATE_XML_NODE_TYPE_ELEMENT) |
230 | { | ||
231 | 44 | children = gate_array_length(&node->child_nodes); | |
232 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | if (children == 1) |
233 | { | ||
234 | ✗ | child = (gate_xml_node_t const*)gate_array_get(&node->child_nodes, 0); | |
235 | ✗ | if (child && (child->node_type == GATE_XML_NODE_TYPE_CDATA)) | |
236 | { | ||
237 | ✗ | gate_string_clone(target, &child->content); | |
238 | } | ||
239 | } | ||
240 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 43 times.
|
44 | else if (children > 1) |
241 | { | ||
242 | 1 | gate_strbuilder_create(&builder, 0); | |
243 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | for (ndx = 0; ndx != children; ++ndx) |
244 | { | ||
245 | 3 | child = (gate_xml_node_t const*)gate_array_get(&node->child_nodes, ndx); | |
246 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
3 | if (child && (child->node_type == GATE_XML_NODE_TYPE_CDATA)) |
247 | { | ||
248 | ✗ | gate_strbuilder_append_string(&builder, &child->content); | |
249 | } | ||
250 | } | ||
251 | 1 | gate_strbuilder_to_string(&builder, target); | |
252 | 1 | gate_strbuilder_release(&builder); | |
253 | } | ||
254 | else | ||
255 | { | ||
256 | 43 | gate_xml_decode(&node->content, target); | |
257 | } | ||
258 | 44 | return true; | |
259 | } | ||
260 | } | ||
261 | 22 | return false; | |
262 | } | ||
263 | |||
264 | ✗ | static gate_bool_t extract_attribute(gate_xml_node_t const* node, gate_string_t const* attr, gate_string_t* target) | |
265 | { | ||
266 | gate_string_t const* ptr_attrvalue; | ||
267 | ✗ | if (node) | |
268 | { | ||
269 | ✗ | ptr_attrvalue = gate_xml_node_attribute_ptr_by_name(node, attr); | |
270 | ✗ | if (ptr_attrvalue) | |
271 | { | ||
272 | ✗ | gate_string_clone(target, ptr_attrvalue); | |
273 | ✗ | return true; | |
274 | } | ||
275 | } | ||
276 | ✗ | return false; | |
277 | } | ||
278 | |||
279 | ✗ | static gate_bool_t extract_node_attribute(gate_xml_node_t const* node, gate_string_t const* tagname, gate_string_t const* attr, gate_string_t* target) | |
280 | { | ||
281 | gate_string_t const* ptr_attrvalue; | ||
282 | ✗ | gate_xml_node_t const* child = get_child_by_tag(node, tagname); | |
283 | ✗ | if (child) | |
284 | { | ||
285 | ✗ | ptr_attrvalue = gate_xml_node_attribute_ptr_by_name(node, attr); | |
286 | ✗ | if (ptr_attrvalue) | |
287 | { | ||
288 | ✗ | gate_string_clone(target, ptr_attrvalue); | |
289 | ✗ | return true; | |
290 | } | ||
291 | } | ||
292 | ✗ | return false; | |
293 | } | ||
294 | |||
295 | |||
296 | ✗ | static gate_bool_t extract_time(gate_xml_node_t const* node, gate_time_t* timestamp) | |
297 | { | ||
298 | gate_datetime_t dt; | ||
299 | ✗ | if (node) | |
300 | { | ||
301 | ✗ | if (gate_date_parse_string(node->content.str, node->content.length, &dt, NULL) > 0) | |
302 | { | ||
303 | ✗ | gate_date_to_time(&dt, timestamp); | |
304 | ✗ | return true; | |
305 | } | ||
306 | } | ||
307 | ✗ | return false; | |
308 | } | ||
309 | |||
310 | ✗ | static gate_result_t parse_atom(gate_string_t const* url, gate_xml_doc_t const* doc, gate_xml_node_t const* root, gate_tech_webapi_newsfeed_response_t* response) | |
311 | { | ||
312 | static gate_string_t const tag_title = GATE_STRING_INIT_STATIC("title"); | ||
313 | static gate_string_t const tag_subtitle = GATE_STRING_INIT_STATIC("subtitle"); | ||
314 | static gate_string_t const tag_link = GATE_STRING_INIT_STATIC("link"); | ||
315 | static gate_string_t const tag_id = GATE_STRING_INIT_STATIC("id"); | ||
316 | static gate_string_t const tag_updated = GATE_STRING_INIT_STATIC("updated"); | ||
317 | static gate_string_t const attr_href = GATE_STRING_INIT_STATIC("href"); | ||
318 | |||
319 | static gate_string_t const tag_entry = GATE_STRING_INIT_STATIC("entry"); | ||
320 | /*static gate_string_t const tag_published = GATE_STRING_INIT_STATIC("published");*/ | ||
321 | static gate_string_t const tag_summary = GATE_STRING_INIT_STATIC("summary"); | ||
322 | static gate_string_t const tag_content = GATE_STRING_INIT_STATIC("content"); | ||
323 | static gate_string_t const tag_author = GATE_STRING_INIT_STATIC("author"); | ||
324 | static gate_string_t const tag_name = GATE_STRING_INIT_STATIC("name"); | ||
325 | static gate_string_t const tag_email = GATE_STRING_INIT_STATIC("email"); | ||
326 | |||
327 | ✗ | gate_result_t ret = GATE_RESULT_FAILED; | |
328 | gate_size_t root_children, ndx; | ||
329 | gate_xml_node_t const* entry; | ||
330 | gate_xml_node_t const* subentry; | ||
331 | gate_tech_webapi_newsentry_t news_entry; | ||
332 | |||
333 | GATE_UNUSED_ARG(doc); | ||
334 | |||
335 | do | ||
336 | { | ||
337 | ✗ | gate_string_clone(&response->request_url, url); | |
338 | ✗ | extract_content(get_child_by_tag(root, &tag_title), &response->title); | |
339 | ✗ | extract_content(get_child_by_tag(root, &tag_subtitle), &response->description); | |
340 | ✗ | extract_attribute(get_child_by_tag(root, &tag_link), &attr_href, &response->link); | |
341 | ✗ | extract_content(get_child_by_tag(root, &tag_id), &response->uid); | |
342 | ✗ | extract_time(get_child_by_tag(root, &tag_updated), &response->update_time); | |
343 | ✗ | subentry = get_child_by_tag(root, &tag_author); | |
344 | ✗ | if (subentry) | |
345 | { | ||
346 | ✗ | extract_content(get_child_by_tag(subentry, &tag_email), &response->contact); | |
347 | ✗ | extract_content(get_child_by_tag(subentry, &tag_name), &response->publisher); | |
348 | } | ||
349 | |||
350 | ✗ | root_children = gate_xml_node_children_count(root); | |
351 | ✗ | for (ndx = 0; ndx != root_children; ++ndx) | |
352 | { | ||
353 | ✗ | entry = gate_xml_node_child_ptr(root, ndx); | |
354 | ✗ | if (!entry) | |
355 | { | ||
356 | ✗ | continue; | |
357 | } | ||
358 | ✗ | if (!xml_node_is_tag(entry, &tag_entry)) | |
359 | { | ||
360 | /* skip non-channels */ | ||
361 | ✗ | continue; | |
362 | } | ||
363 | |||
364 | ✗ | gate_tech_webapi_newsentry_init(&news_entry); | |
365 | |||
366 | ✗ | extract_content(get_child_by_tag(entry, &tag_title), &news_entry.title); | |
367 | ✗ | extract_attribute(get_child_by_tag(entry, &tag_link), &attr_href, &news_entry.link); | |
368 | ✗ | extract_content(get_child_by_tag(entry, &tag_id), &news_entry.uid); | |
369 | ✗ | extract_content(get_child_by_tag(entry, &tag_summary), &news_entry.summary); | |
370 | ✗ | extract_content(get_child_by_tag(entry, &tag_content), &news_entry.content); | |
371 | ✗ | extract_time(get_child_by_tag(entry, &tag_updated), &news_entry.update_time); | |
372 | ✗ | subentry = get_child_by_tag(entry, &tag_author); | |
373 | ✗ | if (subentry) | |
374 | { | ||
375 | ✗ | if (!extract_content(get_child_by_tag(subentry, &tag_name), &news_entry.author)) | |
376 | { | ||
377 | ✗ | gate_string_clone(&news_entry.author, &response->publisher); | |
378 | } | ||
379 | } | ||
380 | else | ||
381 | { | ||
382 | ✗ | gate_string_clone(&news_entry.author, &response->publisher); | |
383 | } | ||
384 | |||
385 | ✗ | gate_arraylist_add(response->entries, &news_entry); | |
386 | ✗ | gate_struct_release(&news_entry.struct_base); | |
387 | } | ||
388 | |||
389 | ✗ | ret = GATE_RESULT_OK; | |
390 | } while (0); | ||
391 | |||
392 | |||
393 | ✗ | return ret; | |
394 | } | ||
395 | |||
396 | |||
397 | 1 | static gate_result_t parse_rss(gate_string_t const* url, gate_xml_doc_t const* doc, gate_xml_node_t const* root, gate_tech_webapi_newsfeed_response_t* response) | |
398 | { | ||
399 | static gate_string_t const tag_channel = GATE_STRING_INIT_STATIC("channel"); | ||
400 | /*static gate_string_t const tag_category = GATE_STRING_INIT_STATIC("category");*/ | ||
401 | static gate_string_t const tag_title = GATE_STRING_INIT_STATIC("title"); | ||
402 | static gate_string_t const tag_link = GATE_STRING_INIT_STATIC("link"); | ||
403 | static gate_string_t const tag_descr = GATE_STRING_INIT_STATIC("description"); | ||
404 | static gate_string_t const tag_date = GATE_STRING_INIT_STATIC("pubDate"); | ||
405 | static gate_string_t const tag_item = GATE_STRING_INIT_STATIC("item"); | ||
406 | /*static gate_string_t const tag_author = GATE_STRING_INIT_STATIC("author");*/ | ||
407 | /*static gate_string_t const tag_guid = GATE_STRING_INIT_STATIC("guid");*/ | ||
408 | /*static gate_string_t const tag_content = GATE_STRING_INIT_STATIC("content");*/ | ||
409 | static gate_string_t const tag_language = GATE_STRING_INIT_STATIC("language"); | ||
410 | static gate_string_t const tag_image = GATE_STRING_INIT_STATIC("image"); | ||
411 | static gate_string_t const tag_webmaster = GATE_STRING_INIT_STATIC("webMaster"); | ||
412 | |||
413 | 1 | gate_result_t ret = GATE_RESULT_FAILED; | |
414 | gate_size_t root_children; | ||
415 | gate_size_t ndx_channel; | ||
416 | gate_xml_node_t const* ptr_channel; | ||
417 | gate_xml_node_t const* ptr_channel_title; | ||
418 | gate_xml_node_t const* ptr_channel_link; | ||
419 | gate_xml_node_t const* ptr_channel_descr; | ||
420 | gate_xml_node_t const* ptr_channel_date; | ||
421 | gate_xml_node_t const* ptr_channel_lang; | ||
422 | gate_xml_node_t const* ptr_channel_icon; | ||
423 | gate_xml_node_t const* ptr_channel_webmaster; | ||
424 | gate_xml_node_t const* ptr_item; | ||
425 | gate_size_t item_counter; | ||
426 | gate_size_t item_index; | ||
427 | gate_xml_node_t const* ptr_item_title; | ||
428 | gate_xml_node_t const* ptr_item_link; | ||
429 | gate_xml_node_t const* ptr_item_description; | ||
430 | gate_xml_node_t const* ptr_item_pubdate; | ||
431 | gate_datetime_t dt; | ||
432 | gate_tech_webapi_newsentry_t news_entry; | ||
433 | |||
434 | do | ||
435 | { | ||
436 | 1 | gate_string_clone(&response->request_url, url); | |
437 | 1 | gate_string_clone(&response->uid, url); | |
438 | |||
439 | 1 | root_children = gate_xml_node_children_count(root); | |
440 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (ndx_channel = 0; ndx_channel != root_children; ++ndx_channel) |
441 | { | ||
442 | 1 | ptr_channel = gate_xml_node_child_ptr(root, ndx_channel); | |
443 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!ptr_channel) |
444 | { | ||
445 | ✗ | continue; | |
446 | } | ||
447 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!xml_node_is_tag(ptr_channel, &tag_channel)) |
448 | { | ||
449 | /* skip non-channels */ | ||
450 | ✗ | continue; | |
451 | } | ||
452 | 1 | ptr_channel_title = get_child_by_tag(ptr_channel, &tag_title); | |
453 | 1 | ptr_channel_link = get_child_by_tag(ptr_channel, &tag_link); | |
454 | 1 | ptr_channel_descr = get_child_by_tag(ptr_channel, &tag_descr); | |
455 | 1 | ptr_channel_date = get_child_by_tag(ptr_channel, &tag_date); | |
456 | 1 | ptr_channel_lang = get_child_by_tag(ptr_channel, &tag_language); | |
457 | 1 | ptr_channel_icon = get_child_by_tag(ptr_channel, &tag_image); | |
458 | 1 | ptr_channel_webmaster = get_child_by_tag(ptr_channel, &tag_webmaster); | |
459 | |||
460 | 1 | extract_content(ptr_channel_title, &response->title); | |
461 | 1 | extract_content(ptr_channel_link, &response->link); | |
462 | 1 | extract_content(ptr_channel_descr, &response->description); | |
463 | 1 | extract_content(ptr_channel_lang, &response->language); | |
464 | 1 | extract_content(ptr_channel_icon, &response->image); | |
465 | 1 | extract_content(ptr_channel_webmaster, &response->contact); | |
466 | |||
467 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ptr_channel_date) |
468 | { | ||
469 | ✗ | if (parse_time(&ptr_channel_date->content, &dt)) | |
470 | { | ||
471 | ✗ | gate_date_to_time(&dt, &response->update_time); | |
472 | } | ||
473 | } | ||
474 | |||
475 | 1 | item_counter = gate_xml_node_children_count(ptr_channel); | |
476 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 1 times.
|
28 | for (item_index = 0; item_index != item_counter; ++item_index) |
477 | { | ||
478 | 27 | ptr_item = gate_xml_node_child_ptr(ptr_channel, item_index); | |
479 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
|
27 | if (!ptr_item) |
480 | { | ||
481 | ✗ | continue; | |
482 | } | ||
483 |
2/2✓ Branch 1 taken 7 times.
✓ Branch 2 taken 20 times.
|
27 | if (!xml_node_is_tag(ptr_item, &tag_item)) |
484 | { | ||
485 | /* skip non-items*/ | ||
486 | 7 | continue; | |
487 | } | ||
488 | |||
489 | 20 | gate_tech_webapi_newsentry_init(&news_entry); | |
490 | |||
491 | 20 | ptr_item_title = get_child_by_tag(ptr_item, &tag_title); | |
492 | 20 | ptr_item_link = get_child_by_tag(ptr_item, &tag_link); | |
493 | 20 | ptr_item_description = get_child_by_tag(ptr_item, &tag_descr); | |
494 | 20 | ptr_item_pubdate = get_child_by_tag(ptr_item, &tag_date); | |
495 | |||
496 | 20 | extract_content(ptr_item_title, &news_entry.title); | |
497 | 20 | extract_content(ptr_item_link, &news_entry.link); | |
498 | 20 | extract_content(ptr_item_description, &news_entry.summary); | |
499 | |||
500 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | if (ptr_item_pubdate) |
501 | { | ||
502 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | if (parse_time(&ptr_item_pubdate->content, &dt)) |
503 | { | ||
504 | 20 | gate_date_to_time(&dt, &news_entry.update_time); | |
505 | } | ||
506 | } | ||
507 | |||
508 | 20 | gate_arraylist_add(response->entries, &news_entry); | |
509 | 20 | gate_struct_release(&news_entry.struct_base); | |
510 | } | ||
511 | } | ||
512 | 1 | ret = GATE_RESULT_OK; | |
513 | } while (0); | ||
514 | |||
515 | 1 | return ret; | |
516 | } | ||
517 | |||
518 | |||
519 | 1 | gate_result_t gate_tech_webapi_newsfeed(gate_tech_webapi_context_t* context, | |
520 | gate_tech_webapi_newsfeed_request_t* request, | ||
521 | gate_tech_webapi_newsfeed_response_t* response) | ||
522 | { | ||
523 | 1 | gate_result_t ret = GATE_RESULT_FAILED; | |
524 | 1 | gate_uri_t url = GATE_INIT_EMPTY; | |
525 | 1 | gate_uint32_t http_status = 0; | |
526 | 1 | gate_stringstream_t* content = NULL; | |
527 | 1 | gate_xml_doc_t doc = GATE_INIT_EMPTY; | |
528 | gate_xml_node_t const* ptr_node; | ||
529 | 1 | gate_string_t tag_name = GATE_STRING_INIT_EMPTY; | |
530 | static gate_string_t const atom_root = GATE_STRING_INIT_STATIC("feed"); | ||
531 | static gate_string_t const rss_root = GATE_STRING_INIT_STATIC("rss"); | ||
532 | |||
533 | do | ||
534 | { | ||
535 | 1 | ret = gate_uri_parse(&url, &request->request_url); | |
536 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | GATE_BREAK_IF_FAILED(ret); |
537 | |||
538 | 1 | content = gate_stringstream_create(0); | |
539 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!content) |
540 | { | ||
541 | ✗ | ret = GATE_RESULT_OUTOFMEMORY; | |
542 | ✗ | break; | |
543 | } | ||
544 | |||
545 | 1 | ret = gate_tech_webapi_get(context, &url, NULL, &http_status, (gate_stream_t*)content, NULL); | |
546 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | GATE_BREAK_IF_FAILED(ret); |
547 | |||
548 | 1 | ret = gate_xml_doc_load(&doc, (gate_stream_t*)content); | |
549 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | GATE_BREAK_IF_FAILED(ret); |
550 | |||
551 | 1 | ret = gate_xml_doc_root_element(&doc, &ptr_node); | |
552 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | GATE_BREAK_IF_FAILED(ret); |
553 | |||
554 | 1 | ret = gate_xml_parse_decompose_name(&ptr_node->tag, NULL, &tag_name); | |
555 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | GATE_BREAK_IF_FAILED(ret); |
556 | |||
557 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (gate_string_equals(&tag_name, &atom_root)) |
558 | { | ||
559 | /* parse atom feed */ | ||
560 | ✗ | ret = parse_atom(&request->request_url, &doc, ptr_node, response); | |
561 | } | ||
562 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | else if (gate_string_equals(&tag_name, &rss_root)) |
563 | { | ||
564 | /* parse RSS */ | ||
565 | 1 | ret = parse_rss(&request->request_url, &doc, ptr_node, response); | |
566 | } | ||
567 | else | ||
568 | { | ||
569 | ✗ | ret = GATE_RESULT_INVALIDCONTENT; | |
570 | } | ||
571 | |||
572 | } while (0); | ||
573 | |||
574 | 1 | gate_string_release(&tag_name); | |
575 | |||
576 | 1 | gate_xml_doc_destroy(&doc); | |
577 | |||
578 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (content != NULL) |
579 | { | ||
580 | 1 | gate_object_release(content); | |
581 | } | ||
582 | 1 | gate_uri_destroy(&url); | |
583 | |||
584 | 1 | return ret; | |
585 | |||
586 | } | ||
587 | |||
588 |