Diff of /trunk/src/gcvote.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.157  
changed lines
  Added in v.165