Contents of /trunk/src/gcvote.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 194 - (hide annotations)
Wed Nov 18 11:40:31 2009 UTC (14 years, 6 months ago) by harbaum
File MIME type: text/plain
File size: 11399 byte(s)
Some geotoad work
1 harbaum 157 /*
2     * This file is part of GPXView.
3     *
4     * GPXView is free software: you can redistribute it and/or modify
5     * it under the terms of the GNU General Public License as published by
6     * the Free Software Foundation, either version 3 of the License, or
7     * (at your option) any later version.
8     *
9     * GPXView is distributed in the hope that it will be useful,
10     * but WITHOUT ANY WARRANTY; without even the implied warranty of
11     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12     * GNU General Public License for more details.
13     *
14     * You should have received a copy of the GNU General Public License
15     * along with GPXView. If not, see <http://www.gnu.org/licenses/>.
16     */
17 harbaum 152
18 harbaum 157 #include <curl/curl.h>
19     #include <curl/types.h>
20     #include <curl/easy.h>
21    
22     #include <libxml/parser.h>
23     #include <libxml/tree.h>
24    
25 harbaum 159 #include <glib/gstdio.h>
26    
27     #include <fcntl.h>
28    
29 harbaum 157 #ifndef LIBXML_TREE_ENABLED
30     #error "Tree not enabled in libxml"
31     #endif
32    
33     #include "gpxview.h"
34    
35     #define ID_PATTERN "guid="
36    
37     static size_t mem_write(void *ptr, size_t size, size_t nmemb,
38     void *stream) {
39     curl_mem_t *p = (curl_mem_t*)stream;
40    
41     p->ptr = g_realloc(p->ptr, p->len + size*nmemb + 1);
42     if(p->ptr) {
43     memcpy(p->ptr+p->len, ptr, size*nmemb);
44     p->len += size*nmemb;
45     p->ptr[p->len] = 0;
46     }
47     return nmemb;
48     }
49    
50 harbaum 158 /* return list of all votes in this file */
51     static gcvote_t *votes_parse(xmlDocPtr doc, xmlNode *a_node) {
52     xmlNode *cur_node = NULL;
53 harbaum 157
54 harbaum 158 gcvote_t *votes = NULL, **cur = &votes;
55 harbaum 157
56 harbaum 158 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
57     if (cur_node->type == XML_ELEMENT_NODE) {
58 harbaum 157
59 harbaum 158 if(strcasecmp((char*)cur_node->name, "vote") == 0) {
60     *cur = g_new0(gcvote_t, 1);
61     (*cur)->quality = GCVOTE_NONE;
62 harbaum 157
63 harbaum 158 /* unhandled attributes: */
64     /* userName, voteAvg, voteUser, waypoint, vote1-5 */
65 harbaum 157
66 harbaum 158 /* parse votes attributes */
67     char *prop_str = (char*)xmlGetProp(cur_node, BAD_CAST "voteMedian");
68     if(prop_str) {
69     (*cur)->quality = atoi(prop_str);
70     xmlFree(prop_str);
71     }
72 harbaum 157
73 harbaum 158 prop_str = (char*)xmlGetProp(cur_node, BAD_CAST "voteCnt");
74     if(prop_str) {
75     (*cur)->votes = atoi(prop_str);
76     xmlFree(prop_str);
77     }
78 harbaum 157
79 harbaum 158 prop_str = (char*)xmlGetProp(cur_node, BAD_CAST "cacheId");
80     if(prop_str) {
81     (*cur)->id = g_strdup(prop_str);
82     xmlFree(prop_str);
83     }
84 harbaum 157
85 harbaum 158 cur = &(*cur)->next;
86     } else if(strcasecmp((char*)cur_node->name, "errorstring") == 0) {
87     /* ignore for now ... */
88     } else
89     printf("found unhandled votes/%s\n", cur_node->name);
90 harbaum 157 }
91 harbaum 158 }
92     return votes;
93 harbaum 157 }
94    
95     /* parse root element */
96 harbaum 158 static gcvote_t *parse_root(xmlDocPtr doc, xmlNode *a_node) {
97 harbaum 157 xmlNode *cur_node = NULL;
98 harbaum 158 gcvote_t *votes = NULL;
99 harbaum 157
100     for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
101     if (cur_node->type == XML_ELEMENT_NODE) {
102    
103 harbaum 158 if(strcasecmp((char*)cur_node->name, "votes") == 0) {
104     if(!votes)
105     votes = votes_parse(doc, cur_node);
106     else
107     printf("gcvote: ignoring multiple votes lists\n");
108 harbaum 157 } else
109     printf("found unhandled %s\n", cur_node->name);
110     }
111     }
112 harbaum 158 return votes;
113 harbaum 157 }
114    
115 harbaum 158 static gcvote_t *parse_doc(xmlDocPtr doc) {
116 harbaum 157 /* Get the root element node */
117     xmlNode *root_element = xmlDocGetRootElement(doc);
118 harbaum 158 gcvote_t *votes = parse_root(doc, root_element);
119 harbaum 157
120     /*free the document */
121     xmlFreeDoc(doc);
122    
123     /*
124     * Free the global variables that may
125     * have been allocated by the parser.
126     */
127     xmlCleanupParser();
128 harbaum 158
129     return votes;
130 harbaum 157 }
131    
132 harbaum 158 static void curl_set_proxy(CURL *curl, proxy_t *proxy) {
133 harbaum 194 if(proxy && proxy->host) {
134 harbaum 158 if(proxy->ignore_hosts)
135     printf("WARNING: Proxy \"ignore_hosts\" unsupported!\n");
136 harbaum 157
137 harbaum 158 printf("gcvote: using proxy %s:%d\n", proxy->host, proxy->port);
138 harbaum 157
139 harbaum 158 curl_easy_setopt(curl, CURLOPT_PROXY, proxy->host);
140     curl_easy_setopt(curl, CURLOPT_PROXYPORT, proxy->port);
141 harbaum 157
142 harbaum 194 if(proxy->use_authentication &&
143     proxy->authentication_user && proxy->authentication_password) {
144 harbaum 158 printf("gcvote: use auth for user %s\n", proxy->authentication_user);
145 harbaum 157
146 harbaum 158 char *cred = g_strdup_printf("%s:%s",
147     proxy->authentication_user,
148     proxy->authentication_password);
149 harbaum 157
150 harbaum 158 curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, cred);
151     g_free(cred);
152     }
153 harbaum 161 } else
154     printf("gcvote: no proxy configured\n");
155 harbaum 158 }
156 harbaum 157
157 harbaum 158 void gcvote_request_free(gcvote_request_t *request) {
158     /* decrease refcount and only free structure if no references are left */
159     request->refcount--;
160 harbaum 194 if(request->refcount > 0) {
161 harbaum 158 printf("gcvote: still %d references, keeping request\n",
162     request->refcount);
163     return;
164     }
165    
166     printf("gcvote: no references left, freeing request\n");
167     if(request->url) g_free(request->url);
168    
169 harbaum 159 if(request->mem.ptr)
170     g_free(request->mem.ptr);
171    
172 harbaum 158 g_free(request);
173     }
174    
175     /* gcvote net result handler */
176     static gboolean gcvote_result_handler(gpointer data) {
177     gcvote_request_t *request = (gcvote_request_t*)data;
178    
179     printf("gcvote: result handler\n");
180    
181 harbaum 162 if(request->refcount < 2) {
182 harbaum 158 printf("gcvote: main app isn't listening anymore\n");
183 harbaum 162 gcvote_request_free(request);
184 harbaum 158 return FALSE;
185     }
186    
187     if(request->res) {
188     printf("gcvote: curl failed\n");
189     request->cb(NULL, request->userdata);
190 harbaum 162 gcvote_request_free(request);
191 harbaum 158 return FALSE;
192     }
193    
194     /* parse the reply */
195     /* nothing could be parsed, just give up */
196     if(!request->mem.ptr || !request->mem.len) {
197     printf("gcvote: ignoring zero length reply\n");
198     request->cb(NULL, request->userdata);
199 harbaum 162 gcvote_request_free(request);
200 harbaum 158 return FALSE;
201     }
202    
203     /* start XML parser */
204     LIBXML_TEST_VERSION;
205    
206     /* parse the file and get the DOM */
207     xmlDoc *doc = xmlReadMemory(request->mem.ptr, request->mem.len,
208     NULL, NULL, 0);
209    
210     /* nothing could be parsed, just give up */
211     if(!doc) {
212     request->cb(NULL, request->userdata);
213 harbaum 162 gcvote_request_free(request);
214 harbaum 158 return FALSE;
215     }
216    
217     vote_t *vote = NULL;
218     gcvote_t *votes = parse_doc(doc);
219    
220     /* search for requested cache in reply and free chain */
221     while(votes) {
222     gcvote_t *next = votes->next;
223    
224     if(!vote && !strcmp(votes->id, request->id) && (votes->quality > 0)) {
225    
226     vote = g_new0(vote_t, 1);
227     vote->quality = votes->quality;
228     vote->votes = votes->votes;
229     }
230    
231     if(votes->id) g_free(votes->id);
232     g_free(votes);
233     votes = next;
234     }
235    
236     if(vote) {
237     printf("gcvote: worker found vote %d/%d\n", vote->quality, vote->votes);
238     request->cb(vote, request->userdata);
239     } else
240     printf("gcvote: no vote found\n");
241    
242 harbaum 162 gcvote_request_free(request);
243 harbaum 158 return FALSE;
244     }
245    
246 harbaum 160 static void gcvotes_free(gcvote_t *votes) {
247     while(votes) {
248     gcvote_t *next = votes->next;
249     if(votes->id) g_free(votes->id);
250     g_free(votes);
251     votes = next;
252     }
253     }
254    
255 harbaum 159 void gcvote_save(appdata_t *appdata, cache_t *cache, curl_mem_t *mem) {
256     if(!mem->len || !mem->ptr) return;
257    
258     /* save data to disk */
259     char *filename = g_strdup_printf("%s%s/gcvote.xml",
260     appdata->image_path,
261     cache->id);
262     if(checkdir(filename) != 0)
263     printf("gcvote: unable to create file path\n");
264     else {
265     printf("gcvote: write %d bytes to %s\n", mem->len, filename);
266    
267     int handle = g_open(filename, O_WRONLY | O_CREAT, 0644);
268     if(handle >= 0) {
269     int len = write(handle, mem->ptr, mem->len);
270     close(handle);
271    
272     /* if write failed, then remove the file */
273     if(len != mem->len)
274     g_remove(filename);
275     }
276     }
277    
278     free(filename);
279     }
280    
281 harbaum 158 static void *worker_thread(void *ptr) {
282     gcvote_request_t *request = (gcvote_request_t*)ptr;
283     struct curl_httppost *formpost=NULL;
284     struct curl_httppost *lastptr=NULL;
285    
286     printf("gcvote: worker thread running\n");
287    
288     request->mem.ptr = NULL;
289     request->mem.len = 0;
290    
291     printf("gcvote: request to get votes for id %s\n", request->id);
292    
293 harbaum 157 curl_formadd(&formpost, &lastptr,
294 harbaum 158 CURLFORM_COPYNAME, "version",
295     CURLFORM_COPYCONTENTS, APP VERSION,
296     CURLFORM_END);
297 harbaum 157
298     curl_formadd(&formpost, &lastptr,
299 harbaum 158 CURLFORM_COPYNAME, "cacheIds",
300     CURLFORM_COPYCONTENTS, request->id,
301     CURLFORM_END);
302    
303     /* try to init curl */
304     CURL *curl = curl_easy_init();
305     if(!curl) {
306     curl_formfree(formpost);
307 harbaum 157
308 harbaum 158 /* callback anyway, so main loop can also clean up */
309     g_idle_add(gcvote_result_handler, request);
310    
311     return NULL;
312     }
313    
314     curl_set_proxy(curl, request->proxy);
315    
316 harbaum 157 /* play nice and report some user agent */
317     curl_easy_setopt(curl, CURLOPT_USERAGENT, APP " " VERSION);
318 harbaum 158
319 harbaum 157 /* download to memory */
320 harbaum 158 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &request->mem);
321 harbaum 157 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, mem_write);
322    
323     /* what URL that receives this POST */
324 harbaum 158 curl_easy_setopt(curl, CURLOPT_URL,
325     "http://dosensuche.de/GCVote/getVotes.php");
326 harbaum 157 curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
327    
328 harbaum 158 request->res = curl_easy_perform(curl);
329     printf("gcvote: curl perform returned with %d\n", request->res);
330    
331     // printf("received %d bytes\n", mem.len);
332     // printf("data: %s\n", mem.ptr);
333    
334 harbaum 157 /* always cleanup */
335     curl_easy_cleanup(curl);
336 harbaum 165
337     printf("gcvote: 1\n");
338    
339 harbaum 157 /* then cleanup the formpost chain */
340     curl_formfree(formpost);
341 harbaum 160
342 harbaum 165 printf("gcvote: 2\n");
343    
344 harbaum 162 /* cause gtk main loop to handle result only if main loop */
345     /* is still interested. Don't free request then, since the */
346     /* gcvote_result_handler will do this */
347     if(request->refcount > 1)
348     g_idle_add(gcvote_result_handler, request);
349     else
350     gcvote_request_free(request);
351    
352 harbaum 158 printf("gcvote: worker thread done\n");
353 harbaum 159
354 harbaum 158 return NULL;
355     }
356 harbaum 157
357 harbaum 158 gcvote_request_t *gcvote_request(appdata_t *appdata, gcvote_cb cb,
358     char *url, gpointer data) {
359     if(!url) return NULL;
360    
361     /* ------ prepare request for worker thread --------- */
362     gcvote_request_t *request = g_new0(gcvote_request_t, 1);
363     request->url = g_strdup(url);
364     request->id = strstr(request->url, ID_PATTERN);
365     if(!request->id) {
366     printf("gcvote: unable to find id\n");
367     gcvote_request_free(request);
368     return NULL;
369     }
370    
371 harbaum 161 request->proxy = appdata->proxy;
372 harbaum 158 request->id += strlen(ID_PATTERN);
373     request->refcount = 2; // master and worker hold a reference
374     request->cb = cb;
375     request->userdata = data;
376 harbaum 157
377 harbaum 158 if(!g_thread_create(&worker_thread, request, FALSE, NULL) != 0) {
378     g_warning("gcvote: failed to create the worker thread");
379    
380     /* free request and return error */
381     request->refcount--; /* decrease by one for dead worker thread */
382     gcvote_request_free(request);
383     return NULL;
384 harbaum 157 }
385    
386 harbaum 158 return request;
387     }
388 harbaum 157
389 harbaum 160 vote_t *gcvote_restore(appdata_t *appdata, cache_t *cache) {
390     /* load data from disk */
391     char *filename = g_strdup_printf("%s%s/gcvote.xml",
392     appdata->image_path,
393     cache->id);
394    
395     printf("gcvote: trying to restore from %s\n", filename);
396    
397     /* no such file? */
398     if(!g_file_test(filename, G_FILE_TEST_EXISTS)) {
399     printf("gcvote: no such file\n");
400     free(filename);
401     return NULL;
402     }
403    
404     LIBXML_TEST_VERSION;
405     xmlDoc *doc = xmlReadFile(filename, NULL, 0);
406    
407     if(doc == NULL) {
408     printf("gcvote: error, could not parse file %s\n", filename);
409     free(filename);
410     return NULL;
411     }
412    
413     free(filename);
414    
415     /* in this case this will sure only return one result */
416     gcvote_t *votes = parse_doc(doc);
417    
418     if(!votes) {
419     printf("gcvote: error, no vote found\n");
420     free(filename);
421     return NULL;
422     }
423    
424     vote_t *vote = g_new0(vote_t, 1);
425     vote->quality = votes->quality;
426     vote->votes = votes->votes;
427    
428     printf("gcvote: found vote %d/%d\n", vote->quality, vote->votes);
429    
430     gcvotes_free(votes);
431    
432     return vote;
433     }