1938cb481dc5d8693b60014de0935293f6a305b6
[monky] / src / rss.c
1 /* Conky, a system monitor, based on torsmo
2  *
3  * Any original torsmo code is licensed under the BSD license
4  *
5  * All code written since the fork of torsmo is licensed under the GPL
6  *
7  * Please see COPYING for details
8  *
9  * Copyright (c) 2007 Toni Spets
10  * Copyright (c) 2005-2008 Brenden Matthews, Philip Kovacs, et. al.
11  *      (see AUTHORS)
12  * All rights reserved.
13  *
14  * This program is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * You should have received a copy of the GNU General Public License
24  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25  *
26  */
27
28 #include "conky.h"
29 #include "prss.h"
30 #include <time.h>
31 #include <assert.h>
32 #include <curl/curl.h>
33 #include <curl/types.h>
34 #include <curl/easy.h>
35
36 #define MAX_FEEDS 16
37
38 struct MemoryStruct {
39         char *memory;
40         size_t size;
41 };
42
43 typedef struct feed_ {
44         char *uri;
45         int last_update;
46         PRSS *data;
47 } feed;
48
49 int num_feeds = 0;
50 feed feeds[MAX_FEEDS];
51
52 size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
53 {
54         size_t realsize = size * nmemb;
55         struct MemoryStruct *mem = (struct MemoryStruct *) data;
56
57         mem->memory = (char *) realloc(mem->memory, mem->size + realsize + 1);
58         if (mem->memory) {
59                 memcpy(&(mem->memory[mem->size]), ptr, realsize);
60                 mem->size += realsize;
61                 mem->memory[mem->size] = 0;
62         }
63         return realsize;
64 }
65
66 int rss_delay(int *wait_time, int delay)
67 {
68         time_t now = time(NULL);
69
70         // make it minutes
71         if (delay < 1) {
72                 delay = 1;
73         }
74         delay *= 60;
75
76         if (!*wait_time) {
77                 *wait_time = now + delay;
78                 return 1;
79         }
80
81         if (now >= *wait_time + delay) {
82                 *wait_time = now + delay;
83                 return 1;
84         }
85
86         return 0;
87 }
88
89 void init_rss_info(void)
90 {
91         int i;
92
93         for (i = 0; i < MAX_FEEDS; i++) {
94                 feeds[i].uri = NULL;
95                 feeds[i].data = NULL;
96                 feeds[i].last_update = 0;
97         }
98 }
99
100 void free_rss_info(void)
101 {
102         int i;
103
104         for (i = 0; i < num_feeds; i++) {
105                 if (feeds[i].uri != NULL) {
106                         free(feeds[i].uri);
107                 }
108         }
109 }
110
111 PRSS *get_rss_info(char *uri, int delay)
112 {
113         CURL *curl = NULL;
114         CURLcode res;
115
116         // pointers to struct
117         feed *curfeed = NULL;
118         PRSS *curdata = NULL;
119         int *last_update = 0;
120
121         int i;
122
123         // curl temps
124         struct MemoryStruct chunk;
125
126         chunk.memory = NULL;
127         chunk.size = 0;
128
129         // first seek for the uri in list
130         for (i = 0; i < num_feeds; i++) {
131                 if (feeds[i].uri != NULL) {
132                         if (!strcmp(feeds[i].uri, uri)) {
133                                 curfeed = &feeds[i];
134                                 break;
135                         }
136                 }
137         }
138
139         if (!curfeed) { // new feed
140                 if (num_feeds == MAX_FEEDS - 1) {
141                         return NULL;
142                 }
143                 curfeed = &feeds[num_feeds];
144                 curfeed->uri = strndup(uri, text_buffer_size);
145                 num_feeds++;
146         }
147
148         last_update = &curfeed->last_update;
149         curdata = curfeed->data;
150
151         if (!rss_delay(last_update, delay)) {
152                 return curdata; // wait for delay to pass
153         }
154
155         if (curdata != NULL) {
156                 prss_free(curdata);     // clean up old data
157                 curdata = NULL;
158         }
159
160         curl = curl_easy_init();
161         if (curl) {
162                 curl_easy_setopt(curl, CURLOPT_URL, uri);
163                 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
164                 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
165                 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &chunk);
166                 curl_easy_setopt(curl, CURLOPT_USERAGENT, "conky-rss/1.0");
167
168                 res = curl_easy_perform(curl);
169                 if (chunk.size) {
170                         curdata = prss_parse_data(chunk.memory);
171                         free(chunk.memory);
172                 } else {
173                         ERR("No data from server");
174                 }
175
176                 curl_easy_cleanup(curl);
177         }
178
179         curfeed->data = curdata;
180
181         return curdata;
182 }