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 158 by harbaum, Wed Nov 4 14:54:52 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 35  Line 30 
30    
31  #define ID_PATTERN  "guid="  #define ID_PATTERN  "guid="
32    
 typedef struct {  
   char *ptr;  
   int len;  
 } curl_mem_t;  
   
33  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,
34                          void *stream) {                          void *stream) {
35    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 43  static size_t mem_write(void *ptr, size_
43    return nmemb;    return nmemb;
44  }  }
45    
46  #if 0  /* return list of all votes in this file */
47  #define PROXY_KEY  "/system/http_proxy/"  static gcvote_t *votes_parse(xmlDocPtr doc, xmlNode *a_node) {
48      xmlNode *cur_node = NULL;
 typedef struct {  
   char *authentication_password, *authentication_user;  
   char *host;  
   char *ignore_hosts;  
   gint port;  
   gboolean use_authentication;  
 } proxy_t;  
   
 void net_io_set_proxy(CURL *curl, proxy_t *proxy) {  
  /* ------ overwrite with settings from gconf if present ------- */  
   GConfClient *client = gconf_client_get_default();  
   
   /* ------------- get proxy settings -------------------- */  
   if(gconf_client_get_bool(client, PROXY_KEY "use_http_proxy", NULL)) {  
     proxy_t *proxy = settings->proxy = g_new0(proxy_t, 1);  
   
     /* get basic settings */  
     proxy->host = gconf_client_get_string(client, PROXY_KEY "host", NULL);  
     proxy->port = gconf_client_get_int(client, PROXY_KEY "port", NULL);  
     proxy->ignore_hosts =  
       gconf_client_get_string(client, PROXY_KEY "ignore_hosts", NULL);  
   
     /* check for authentication */  
     proxy->use_authentication =  
       gconf_client_get_bool(client, PROXY_KEY "use_authentication", NULL);  
   
     if(proxy->use_authentication) {  
       proxy->authentication_user =  
         gconf_client_get_string(client, PROXY_KEY "authentication_user", NULL);  
       proxy->authentication_password =  
         gconf_client_get_string(client, PROXY_KEY "authentication_password",  
                                 NULL);  
     }  
   }  
   
   if(proxy) {  
     if(proxy->ignore_hosts)  
       printf("WARNING: Pproxy \"ignore_hosts\" unsupported!\n");  
   
     printf("net_io: using proxy %s:%d\n", proxy->host, proxy->port);  
   
     curl_easy_setopt(curl, CURLOPT_PROXY, proxy->host);  
     curl_easy_setopt(curl, CURLOPT_PROXYPORT, proxy->port);  
49    
50      if(proxy->use_authentication) {    gcvote_t *votes = NULL, **cur = &votes;
       printf("net_io:   use auth for user %s\n", proxy->authentication_user);  
51    
52        char *cred = g_strdup_printf("%s:%s",    for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
53                                     proxy->authentication_user,      if (cur_node->type == XML_ELEMENT_NODE) {
                                    proxy->authentication_password);  
54    
55        curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, cred);        if(strcasecmp((char*)cur_node->name, "vote") == 0) {
56        g_free(cred);          *cur = g_new0(gcvote_t, 1);
57            (*cur)->quality = GCVOTE_NONE;
58    
59            /* unhandled attributes: */
60            /* userName, voteAvg, voteUser, waypoint, vote1-5 */
61    
62            /* parse votes attributes */
63            char *prop_str = (char*)xmlGetProp(cur_node, BAD_CAST "voteMedian");
64            if(prop_str) {
65              (*cur)->quality = atoi(prop_str);
66              xmlFree(prop_str);
67            }
68    
69            prop_str = (char*)xmlGetProp(cur_node, BAD_CAST "voteCnt");
70            if(prop_str) {
71              (*cur)->votes = atoi(prop_str);
72              xmlFree(prop_str);
73            }
74    
75            prop_str = (char*)xmlGetProp(cur_node, BAD_CAST "cacheId");
76            if(prop_str) {
77              (*cur)->id = g_strdup(prop_str);
78              xmlFree(prop_str);
79            }
80    
81            cur = &(*cur)->next;
82          } else if(strcasecmp((char*)cur_node->name, "errorstring") == 0) {
83            /* ignore for now ... */
84          } else
85            printf("found unhandled votes/%s\n", cur_node->name);
86      }      }
87    }    }
88      return votes;
89  }  }
 #endif  
90    
91  /* parse root element */  /* parse root element */
92  static void parse_root(xmlDocPtr doc, xmlNode *a_node) {  static gcvote_t *parse_root(xmlDocPtr doc, xmlNode *a_node) {
93    xmlNode *cur_node = NULL;    xmlNode *cur_node = NULL;
94      gcvote_t *votes = NULL;
95    
96    for (cur_node = a_node; cur_node; cur_node = cur_node->next) {    for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
97      if (cur_node->type == XML_ELEMENT_NODE) {      if (cur_node->type == XML_ELEMENT_NODE) {
98    
99        if(strcasecmp((char*)cur_node->name, "WMT_MS_Capabilities") == 0) {        if(strcasecmp((char*)cur_node->name, "votes") == 0) {
100          printf("xyz\n");          if(!votes)
101              votes = votes_parse(doc, cur_node);
102          //      wms_cap_parse(wms, doc, cur_node);          else
103              printf("gcvote: ignoring multiple votes lists\n");
104        } else        } else
105          printf("found unhandled %s\n", cur_node->name);          printf("found unhandled %s\n", cur_node->name);
106      }      }
107    }    }
108      return votes;
109  }  }
110    
111  static void parse_doc(xmlDocPtr doc) {  static gcvote_t *parse_doc(xmlDocPtr doc) {
112    /* Get the root element node */    /* Get the root element node */
113    xmlNode *root_element = xmlDocGetRootElement(doc);    xmlNode *root_element = xmlDocGetRootElement(doc);
114      gcvote_t *votes = parse_root(doc, root_element);
   parse_root(doc, root_element);  
115    
116    /*free the document */    /*free the document */
117    xmlFreeDoc(doc);    xmlFreeDoc(doc);
# Line 145  static void parse_doc(xmlDocPtr doc) { Line 121  static void parse_doc(xmlDocPtr doc) {
121     * have been allocated by the parser.     * have been allocated by the parser.
122     */     */
123    xmlCleanupParser();    xmlCleanupParser();
124    
125      return votes;
126  }  }
127    
128  int gcvote_get(appdata_t *appdata, char *url) {  static void curl_set_proxy(CURL *curl, proxy_t *proxy) {
129    CURL *curl;    if(proxy) {
130    struct curl_httppost *formpost=NULL;      if(proxy->ignore_hosts)
131    struct curl_httppost *lastptr=NULL;        printf("WARNING: Proxy \"ignore_hosts\" unsupported!\n");
132    CURLcode res;  
133    curl_mem_t mem = { NULL, 0 };      printf("gcvote: using proxy %s:%d\n", proxy->host, proxy->port);
134    
135        curl_easy_setopt(curl, CURLOPT_PROXY, proxy->host);
136        curl_easy_setopt(curl, CURLOPT_PROXYPORT, proxy->port);
137    
138        if(proxy->use_authentication) {
139          printf("gcvote:   use auth for user %s\n", proxy->authentication_user);
140    
141    char *id = NULL;        char *cred = g_strdup_printf("%s:%s",
142                                       proxy->authentication_user,
143                                       proxy->authentication_password);
144    
145    if(!url) return GCVOTE_NONE;        curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, cred);
146          g_free(cred);
147        }
148      }
149    }
150    
151    id = strstr(url, ID_PATTERN);  void gcvote_request_free(gcvote_request_t *request) {
152    if(!id) return GCVOTE_NONE;    /* decrease refcount and only free structure if no references are left */
153      request->refcount--;
154      if(request->refcount) {
155        printf("gcvote: still %d references, keeping request\n",
156               request->refcount);
157        return;
158      }
159    
160    id += strlen(ID_PATTERN);    printf("gcvote: no references left, freeing request\n");
161      if(request->url)  g_free(request->url);
162    
163    printf("request to get votes for id %s\n", id);    g_free(request);
164    }
165    
166    /* gcvote net result handler */
167    static gboolean gcvote_result_handler(gpointer data) {
168      gcvote_request_t *request = (gcvote_request_t*)data;
169    
170      printf("gcvote: result handler\n");
171    
172      /* worker thread has already reduced its refcounter */
173      if(request->refcount < 1) {
174        printf("gcvote: main app isn't listening anymore\n");
175        g_free(request->mem.ptr);
176        return FALSE;
177      }
178    
179      if(request->res) {
180        printf("gcvote: curl failed\n");
181        g_free(request->mem.ptr);
182        request->cb(NULL, request->userdata);
183        return FALSE;
184      }
185    
186      /* parse the reply */
187      /* nothing could be parsed, just give up */
188      if(!request->mem.ptr || !request->mem.len) {
189        printf("gcvote: ignoring zero length reply\n");
190        g_free(request->mem.ptr);
191        request->cb(NULL, request->userdata);
192        return FALSE;
193      }
194    
195      /* start XML parser */
196      LIBXML_TEST_VERSION;
197    
198      /* parse the file and get the DOM */
199      xmlDoc *doc = xmlReadMemory(request->mem.ptr, request->mem.len,
200                                  NULL, NULL, 0);
201      g_free(request->mem.ptr);
202    
203      /* nothing could be parsed, just give up */
204      if(!doc) {
205        request->cb(NULL, request->userdata);
206        return FALSE;
207      }
208    
209      vote_t *vote = NULL;
210      gcvote_t *votes = parse_doc(doc);
211    
212      /* search for requested cache in reply and free chain */
213      while(votes) {
214        gcvote_t *next = votes->next;
215    
216        if(!vote && !strcmp(votes->id, request->id) && (votes->quality > 0)) {
217    
218          vote = g_new0(vote_t, 1);
219          vote->quality = votes->quality;
220          vote->votes = votes->votes;
221        }
222    
223        if(votes->id) g_free(votes->id);
224        g_free(votes);
225        votes = next;
226      }
227    
228      if(vote) {
229        printf("gcvote: worker found vote %d/%d\n", vote->quality, vote->votes);
230        request->cb(vote, request->userdata);
231      } else
232        printf("gcvote: no vote found\n");
233    
234      return FALSE;
235    }
236    
237    static void *worker_thread(void *ptr) {
238      gcvote_request_t *request = (gcvote_request_t*)ptr;
239      struct curl_httppost *formpost=NULL;
240      struct curl_httppost *lastptr=NULL;
241    
242      printf("gcvote: worker thread running\n");
243    
244      request->mem.ptr = NULL;
245      request->mem.len = 0;
246    
247      printf("gcvote: request to get votes for id %s\n", request->id);
248    
249    curl_formadd(&formpost, &lastptr,    curl_formadd(&formpost, &lastptr,
250                 CURLFORM_COPYNAME, "version",                 CURLFORM_COPYNAME, "version",
251                 CURLFORM_COPYCONTENTS, APP VERSION,                 CURLFORM_COPYCONTENTS, APP VERSION,
252                 CURLFORM_END);                 CURLFORM_END);
253    
254    curl_formadd(&formpost, &lastptr,    curl_formadd(&formpost, &lastptr,
255                 CURLFORM_COPYNAME, "cacheIds",                 CURLFORM_COPYNAME, "cacheIds",
256                 CURLFORM_COPYCONTENTS, id,                 CURLFORM_COPYCONTENTS, request->id,
257                 CURLFORM_END);                 CURLFORM_END);
258    
259    curl = curl_easy_init();    /* try to init curl */
260    if(!curl) return GCVOTE_NONE;    CURL *curl = curl_easy_init();
261      if(!curl) {
262        curl_formfree(formpost);
263        gcvote_request_free(request);
264    
265        /* callback anyway, so main loop can also clean up */
266        g_idle_add(gcvote_result_handler, request);
267    
268        return NULL;
269      }
270    
271      curl_set_proxy(curl, request->proxy);
272    
273    /* play nice and report some user agent */    /* play nice and report some user agent */
274    curl_easy_setopt(curl, CURLOPT_USERAGENT, APP " " VERSION);    curl_easy_setopt(curl, CURLOPT_USERAGENT, APP " " VERSION);
275    
276    /* download to memory */    /* download to memory */
277    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &mem);    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &request->mem);
278    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, mem_write);    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, mem_write);
279    
280    /* what URL that receives this POST */    /* what URL that receives this POST */
281    curl_easy_setopt(curl, CURLOPT_URL, "http://dosensuche.de/GCVote/getVotes.php");    curl_easy_setopt(curl, CURLOPT_URL,
282                       "http://dosensuche.de/GCVote/getVotes.php");
283    curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);    curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
284    res = curl_easy_perform(curl);  
285      request->res = curl_easy_perform(curl);
286      printf("gcvote: curl perform returned with %d\n", request->res);
287    
288      //  printf("received %d bytes\n", mem.len);
289      //  printf("data: %s\n", mem.ptr);
290    
291    /* always cleanup */    /* always cleanup */
292    curl_easy_cleanup(curl);    curl_easy_cleanup(curl);
293    
294      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &request->response);
295    
296    /* then cleanup the formpost chain */    /* then cleanup the formpost chain */
297    curl_formfree(formpost);    curl_formfree(formpost);
298    
299      printf("gcvote: worker thread done\n");
300      gcvote_request_free(request);
301    
302      /* cause gtk main loop to handle result */
303      g_idle_add(gcvote_result_handler, request);
304    
305      printf("gcvote: thread terminating\n");
306    
307      return NULL;
308    }
309    
310    printf("received %d bytes\n", mem.len);  gcvote_request_t *gcvote_request(appdata_t *appdata, gcvote_cb cb,
311    printf("data: %s\n", mem.ptr);                                 char *url, gpointer data) {
312      if(!url) return NULL;
313    /* start XML parser */  
314    LIBXML_TEST_VERSION;    /* ------ prepare request for worker thread --------- */
315      gcvote_request_t *request = g_new0(gcvote_request_t, 1);
316    /* parse the file and get the DOM */    request->url = g_strdup(url);
317    xmlDoc *doc = xmlReadMemory(mem.ptr, mem.len, NULL, NULL, 0);    request->id = strstr(request->url, ID_PATTERN);
318    if(!doc) {    if(!request->id) {
319      g_free(mem.ptr);      printf("gcvote: unable to find id\n");
320      return GCVOTE_NONE;      gcvote_request_free(request);
321        return NULL;
322    }    }
   
   printf("ok, parse doc tree\n");  
   parse_doc(doc);  
323    
324      request->id += strlen(ID_PATTERN);
325      request->refcount = 2;   // master and worker hold a reference
326      request->cb = cb;
327      request->userdata = data;
328    
329      if(!g_thread_create(&worker_thread, request, FALSE, NULL) != 0) {
330        g_warning("gcvote: failed to create the worker thread");
331    
332        /* free request and return error */
333        request->refcount--;    /* decrease by one for dead worker thread */
334        gcvote_request_free(request);
335        return NULL;
336      }
337    
338    return 0;    return request;
339  }  }
340    

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