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 159 by harbaum, Wed Nov 4 20:28:54 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  typedef struct {    gcvote_t *votes = NULL, **cur = &votes;
55    char *authentication_password, *authentication_user;  
56    char *host;    for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
57    char *ignore_hosts;      if (cur_node->type == XML_ELEMENT_NODE) {
58    gint port;  
59    gboolean use_authentication;        if(strcasecmp((char*)cur_node->name, "vote") == 0) {
60  } proxy_t;          *cur = g_new0(gcvote_t, 1);
61            (*cur)->quality = GCVOTE_NONE;
62  void net_io_set_proxy(CURL *curl, proxy_t *proxy) {  
63   /* ------ overwrite with settings from gconf if present ------- */          /* unhandled attributes: */
64    GConfClient *client = gconf_client_get_default();          /* userName, voteAvg, voteUser, waypoint, vote1-5 */
65    
66    /* ------------- get proxy settings -------------------- */          /* parse votes attributes */
67    if(gconf_client_get_bool(client, PROXY_KEY "use_http_proxy", NULL)) {          char *prop_str = (char*)xmlGetProp(cur_node, BAD_CAST "voteMedian");
68      proxy_t *proxy = settings->proxy = g_new0(proxy_t, 1);          if(prop_str) {
69              (*cur)->quality = atoi(prop_str);
70      /* get basic settings */            xmlFree(prop_str);
71      proxy->host = gconf_client_get_string(client, PROXY_KEY "host", NULL);          }
72      proxy->port = gconf_client_get_int(client, PROXY_KEY "port", NULL);  
73      proxy->ignore_hosts =          prop_str = (char*)xmlGetProp(cur_node, BAD_CAST "voteCnt");
74        gconf_client_get_string(client, PROXY_KEY "ignore_hosts", NULL);          if(prop_str) {
75              (*cur)->votes = atoi(prop_str);
76      /* check for authentication */            xmlFree(prop_str);
77      proxy->use_authentication =          }
78        gconf_client_get_bool(client, PROXY_KEY "use_authentication", NULL);  
79            prop_str = (char*)xmlGetProp(cur_node, BAD_CAST "cacheId");
80      if(proxy->use_authentication) {          if(prop_str) {
81        proxy->authentication_user =            (*cur)->id = g_strdup(prop_str);
82          gconf_client_get_string(client, PROXY_KEY "authentication_user", NULL);            xmlFree(prop_str);
83        proxy->authentication_password =          }
84          gconf_client_get_string(client, PROXY_KEY "authentication_password",  
85                                  NULL);          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        }
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 112  void net_io_set_proxy(CURL *curl, proxy_ Line 151  void net_io_set_proxy(CURL *curl, proxy_
151      }      }
152    }    }
153  }  }
 #endif  
154    
155  /* parse root element */  void gcvote_request_free(gcvote_request_t *request) {
156  static void parse_root(xmlDocPtr doc, xmlNode *a_node) {    /* decrease refcount and only free structure if no references are left */
157    xmlNode *cur_node = NULL;    request->refcount--;
158      if(request->refcount) {
159        printf("gcvote: still %d references, keeping request\n",
160               request->refcount);
161        return;
162      }
163    
164    for (cur_node = a_node; cur_node; cur_node = cur_node->next) {    printf("gcvote: no references left, freeing request\n");
165      if (cur_node->type == XML_ELEMENT_NODE) {    if(request->url)  g_free(request->url);
166    
167        if(strcasecmp((char*)cur_node->name, "WMT_MS_Capabilities") == 0) {    if(request->mem.ptr)
168          printf("xyz\n");      g_free(request->mem.ptr);
169    
170          //      wms_cap_parse(wms, doc, cur_node);    g_free(request);
       } else  
         printf("found unhandled %s\n", cur_node->name);  
     }  
   }  
171  }  }
172    
173  static void parse_doc(xmlDocPtr doc) {  /* gcvote net result handler */
174    /* Get the root element node */  static gboolean gcvote_result_handler(gpointer data) {
175    xmlNode *root_element = xmlDocGetRootElement(doc);    gcvote_request_t *request = (gcvote_request_t*)data;
176    
177      printf("gcvote: result handler\n");
178    
179      /* worker thread has already reduced its refcounter */
180      if(request->refcount < 1) {
181        printf("gcvote: main app isn't listening anymore\n");
182        return FALSE;
183      }
184    
185    parse_root(doc, root_element);    if(request->res) {
186        printf("gcvote: curl failed\n");
187        request->cb(NULL, request->userdata);
188        return FALSE;
189      }
190    
191    /*free the document */    /* parse the reply */
192    xmlFreeDoc(doc);    /* nothing could be parsed, just give up */
193      if(!request->mem.ptr || !request->mem.len) {
194        printf("gcvote: ignoring zero length reply\n");
195        request->cb(NULL, request->userdata);
196        return FALSE;
197      }
198    
199    /*    /* start XML parser */
200     * Free the global variables that may    LIBXML_TEST_VERSION;
201     * have been allocated by the parser.  
202     */    /* parse the file and get the DOM */
203    xmlCleanupParser();    xmlDoc *doc = xmlReadMemory(request->mem.ptr, request->mem.len,
204                                  NULL, NULL, 0);
205    
206      /* nothing could be parsed, just give up */
207      if(!doc) {
208        request->cb(NULL, request->userdata);
209        return FALSE;
210      }
211    
212      vote_t *vote = NULL;
213      gcvote_t *votes = parse_doc(doc);
214    
215      /* search for requested cache in reply and free chain */
216      while(votes) {
217        gcvote_t *next = votes->next;
218    
219        if(!vote && !strcmp(votes->id, request->id) && (votes->quality > 0)) {
220    
221          vote = g_new0(vote_t, 1);
222          vote->quality = votes->quality;
223          vote->votes = votes->votes;
224        }
225    
226        if(votes->id) g_free(votes->id);
227        g_free(votes);
228        votes = next;
229      }
230    
231      if(vote) {
232        printf("gcvote: worker found vote %d/%d\n", vote->quality, vote->votes);
233        request->cb(vote, request->userdata);
234      } else
235        printf("gcvote: no vote found\n");
236    
237      return FALSE;
238  }  }
239    
240  int gcvote_get(appdata_t *appdata, char *url) {  void gcvote_save(appdata_t *appdata, cache_t *cache, curl_mem_t *mem) {
241    CURL *curl;    if(!mem->len || !mem->ptr) return;
   struct curl_httppost *formpost=NULL;  
   struct curl_httppost *lastptr=NULL;  
   CURLcode res;  
   curl_mem_t mem = { NULL, 0 };  
242    
243    char *id = NULL;    /* save data to disk */
244      char *filename = g_strdup_printf("%s%s/gcvote.xml",
245                                       appdata->image_path,
246                                       cache->id);
247      if(checkdir(filename) != 0)
248        printf("gcvote: unable to create file path\n");
249      else {
250        printf("gcvote: write %d bytes to %s\n", mem->len, filename);
251    
252        int handle = g_open(filename, O_WRONLY | O_CREAT, 0644);
253        if(handle >= 0) {
254          int len = write(handle, mem->ptr, mem->len);
255          close(handle);
256    
257          /* if write failed, then remove the file */
258          if(len != mem->len)
259            g_remove(filename);
260        }
261      }
262    
263    if(!url) return GCVOTE_NONE;    free(filename);
264    }
265    
266    id = strstr(url, ID_PATTERN);  static void *worker_thread(void *ptr) {
267    if(!id) return GCVOTE_NONE;    gcvote_request_t *request = (gcvote_request_t*)ptr;
268      struct curl_httppost *formpost=NULL;
269      struct curl_httppost *lastptr=NULL;
270    
271      printf("gcvote: worker thread running\n");
272    
273    id += strlen(ID_PATTERN);    request->mem.ptr = NULL;
274      request->mem.len = 0;
275    
276    printf("request to get votes for id %s\n", id);    printf("gcvote: request to get votes for id %s\n", request->id);
277    
278    curl_formadd(&formpost, &lastptr,    curl_formadd(&formpost, &lastptr,
279                 CURLFORM_COPYNAME, "version",                 CURLFORM_COPYNAME, "version",
280                 CURLFORM_COPYCONTENTS, APP VERSION,                 CURLFORM_COPYCONTENTS, APP VERSION,
281                 CURLFORM_END);                 CURLFORM_END);
282    
283    curl_formadd(&formpost, &lastptr,    curl_formadd(&formpost, &lastptr,
284                 CURLFORM_COPYNAME, "cacheIds",                 CURLFORM_COPYNAME, "cacheIds",
285                 CURLFORM_COPYCONTENTS, id,                 CURLFORM_COPYCONTENTS, request->id,
286                 CURLFORM_END);                 CURLFORM_END);
287    
288    curl = curl_easy_init();    /* try to init curl */
289    if(!curl) return GCVOTE_NONE;    CURL *curl = curl_easy_init();
290      if(!curl) {
291        curl_formfree(formpost);
292        gcvote_request_free(request);
293    
294        /* callback anyway, so main loop can also clean up */
295        g_idle_add(gcvote_result_handler, request);
296    
297        return NULL;
298      }
299    
300      curl_set_proxy(curl, request->proxy);
301    
302    /* play nice and report some user agent */    /* play nice and report some user agent */
303    curl_easy_setopt(curl, CURLOPT_USERAGENT, APP " " VERSION);    curl_easy_setopt(curl, CURLOPT_USERAGENT, APP " " VERSION);
304    
305    /* download to memory */    /* download to memory */
306    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &mem);    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &request->mem);
307    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, mem_write);    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, mem_write);
308    
309    /* what URL that receives this POST */    /* what URL that receives this POST */
310    curl_easy_setopt(curl, CURLOPT_URL, "http://dosensuche.de/GCVote/getVotes.php");    curl_easy_setopt(curl, CURLOPT_URL,
311                       "http://dosensuche.de/GCVote/getVotes.php");
312    curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);    curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
313    res = curl_easy_perform(curl);  
314      request->res = curl_easy_perform(curl);
315      printf("gcvote: curl perform returned with %d\n", request->res);
316    
317      //  printf("received %d bytes\n", mem.len);
318      //  printf("data: %s\n", mem.ptr);
319    
320    /* always cleanup */    /* always cleanup */
321    curl_easy_cleanup(curl);    curl_easy_cleanup(curl);
322    
323      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &request->response);
324    
325    /* then cleanup the formpost chain */    /* then cleanup the formpost chain */
326    curl_formfree(formpost);    curl_formfree(formpost);
327    
328      printf("gcvote: worker thread done\n");
329      gcvote_request_free(request);
330    
331    printf("received %d bytes\n", mem.len);    /* cause gtk main loop to handle result */
332    printf("data: %s\n", mem.ptr);    g_idle_add(gcvote_result_handler, request);
333    
334      printf("gcvote: thread terminating\n");
335    
336      return NULL;
337    }
338    
339    /* start XML parser */  gcvote_request_t *gcvote_request(appdata_t *appdata, gcvote_cb cb,
340    LIBXML_TEST_VERSION;                                 char *url, gpointer data) {
341      if(!url) return NULL;
342    /* parse the file and get the DOM */  
343    xmlDoc *doc = xmlReadMemory(mem.ptr, mem.len, NULL, NULL, 0);    /* ------ prepare request for worker thread --------- */
344    if(!doc) {    gcvote_request_t *request = g_new0(gcvote_request_t, 1);
345      g_free(mem.ptr);    request->url = g_strdup(url);
346      return GCVOTE_NONE;    request->id = strstr(request->url, ID_PATTERN);
347      if(!request->id) {
348        printf("gcvote: unable to find id\n");
349        gcvote_request_free(request);
350        return NULL;
351    }    }
   
   printf("ok, parse doc tree\n");  
   parse_doc(doc);  
352    
353      request->id += strlen(ID_PATTERN);
354      request->refcount = 2;   // master and worker hold a reference
355      request->cb = cb;
356      request->userdata = data;
357    
358      if(!g_thread_create(&worker_thread, request, FALSE, NULL) != 0) {
359        g_warning("gcvote: failed to create the worker thread");
360    
361        /* free request and return error */
362        request->refcount--;    /* decrease by one for dead worker thread */
363        gcvote_request_free(request);
364        return NULL;
365      }
366    
367    return 0;    return request;
368  }  }
369    

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