Better argument handling for rss/curl/weather.
[monky] / src / ccurl_thread.c
1 /*
2  * Conky, a system monitor, based on torsmo
3  *
4  * Please see COPYING for details
5  *
6  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
7  *      (see AUTHORS)
8  * All rights reserved.
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "conky.h"
25 #include "logging.h"
26 #include "ccurl_thread.h"
27
28 #ifdef DEBUG
29 #include <assert.h>
30 #endif /* DEBUG */
31
32 #include <curl/curl.h>
33 #include <curl/types.h>
34 #include <curl/easy.h>
35
36 typedef struct _ccurl_memory_t {
37         char *memory;
38         size_t size;
39 } ccurl_memory_t;
40
41 ccurl_location_t *ccurl_find_location(ccurl_location_t **locations_head, char *uri)
42 {
43         ccurl_location_t *tail = *locations_head;
44         ccurl_location_t *new = 0;
45         while (tail) {
46                 if (tail->uri &&
47                                 strcmp(tail->uri, uri) == EQUAL) {
48                         return tail;
49                 }
50                 tail = tail->next;
51         }
52         if (!tail) { /* new location!!!!!!! */
53                 DBGP("new curl location: '%s'", uri);
54                 new = malloc(sizeof(ccurl_location_t));
55                 memset(new, 0, sizeof(ccurl_location_t));
56                 new->uri = strndup(uri, text_buffer_size);
57                 tail = *locations_head;
58                 while (tail && tail->next) {
59                         tail = tail->next;
60                 }
61                 if (!tail) {
62                         /* omg the first one!!!!!!! */
63                         *locations_head = new;
64                 } else {
65                         tail->next = new;
66                 }
67         }
68         return new;
69 }
70
71 void ccurl_free_locations(ccurl_location_t **locations_head)
72 {
73         ccurl_location_t *tail = *locations_head;
74         ccurl_location_t *last = 0;
75
76         while (tail) {
77                 if (tail->uri) free(tail->uri);
78                 if (tail->result) free(tail->result);
79                 last = tail;
80                 tail = tail->next;
81                 free(last);
82         }
83         *locations_head = 0;
84 }
85
86 size_t ccurl_write_memory_callback(void *ptr, size_t size, size_t nmemb, void *data)
87 {
88         size_t realsize = size * nmemb;
89         ccurl_memory_t *mem = (ccurl_memory_t*)data;
90
91         mem->memory = (char *) realloc(mem->memory, mem->size + realsize + 1);
92         if (mem->memory) {
93                 memcpy(&(mem->memory[mem->size]), ptr, realsize);
94                 mem->size += realsize;
95                 mem->memory[mem->size] = 0;
96         }
97         return realsize;
98 }
99
100
101
102 void ccurl_fetch_data(ccurl_location_t *curloc)
103 {
104         CURL *curl = NULL;
105         CURLcode res;
106
107         // curl temps
108         ccurl_memory_t chunk;
109
110         chunk.memory = NULL;
111         chunk.size = 0;
112
113         curl = curl_easy_init();
114         if (curl) {
115                 DBGP("reading curl data from '%s'", curloc->uri);
116                 curl_easy_setopt(curl, CURLOPT_URL, curloc->uri);
117                 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
118                 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ccurl_write_memory_callback);
119                 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &chunk);
120                 curl_easy_setopt(curl, CURLOPT_USERAGENT, "conky-curl/1.0");
121
122                 res = curl_easy_perform(curl);
123                 if (res == CURLE_OK && chunk.size) {
124                         timed_thread_lock(curloc->p_timed_thread);
125                         (*curloc->process_function)(curloc->result, chunk.memory);
126                         timed_thread_unlock(curloc->p_timed_thread);
127                         free(chunk.memory);
128                 } else {
129                         ERR("weather: no data from server");
130                 }
131
132                 curl_easy_cleanup(curl);
133         }
134
135         return;
136 }
137
138 void *ccurl_thread(void *) __attribute__((noreturn));
139
140 void ccurl_init_thread(ccurl_location_t *curloc, int interval)
141 {
142 #ifdef DEBUG
143         assert(curloc->result);
144 #endif /* DEBUG */
145         curloc->p_timed_thread =
146                 timed_thread_create(&ccurl_thread,
147                                 (void *)curloc, interval * 1000000);
148
149         if (!curloc->p_timed_thread) {
150                 ERR("curl thread: error creating timed thread");
151         }
152         timed_thread_register(curloc->p_timed_thread,
153                         &curloc->p_timed_thread);
154         if (timed_thread_run(curloc->p_timed_thread)) {
155                 ERR("curl thread: error running timed thread");
156         }
157 }
158
159 void *ccurl_thread(void *arg)
160 {
161         ccurl_location_t *curloc = (ccurl_location_t*)arg;
162
163         while (1) {
164                 ccurl_fetch_data(curloc);
165                 if (timed_thread_test(curloc->p_timed_thread, 0)) {
166                         timed_thread_exit(curloc->p_timed_thread);
167                 }
168         }
169         /* never reached */
170 }
171
172 static ccurl_location_t *ccurl_locations_head = 0;
173
174 void ccurl_free_info(void)
175 {
176         ccurl_free_locations(&ccurl_locations_head);
177 }
178
179 void ccurl_parse_data(void *result, const char *data)
180 {
181         strncpy(result, data, max_user_text);
182 }
183
184 void ccurl_process_info(char *p, int p_max_size, char *uri, int interval)
185 {
186         ccurl_location_t *curloc = ccurl_find_location(&ccurl_locations_head, uri);
187         if (!curloc->p_timed_thread) {
188                 curloc->result = malloc(max_user_text);
189                 memset(curloc->result, 0, max_user_text);
190                 curloc->process_function = &ccurl_parse_data;
191                 ccurl_init_thread(curloc, interval);
192                 if (!curloc->p_timed_thread) {
193                         ERR("error setting up weather thread");
194                 }
195         }
196
197         timed_thread_lock(curloc->p_timed_thread);
198         strncpy(p, curloc->result, p_max_size);
199         timed_thread_unlock(curloc->p_timed_thread);
200 }
201