here comes the big header include rewrite
[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 "logging.h"
30 #include "prss.h"
31 #include <time.h>
32 #include <assert.h>
33 #include <curl/curl.h>
34 #include <curl/types.h>
35 #include <curl/easy.h>
36
37 #define MAX_FEEDS 16
38
39 struct MemoryStruct {
40         char *memory;
41         size_t size;
42 };
43
44 typedef struct feed_ {
45         char *uri;
46         int last_update;
47         PRSS *data;
48 } feed;
49
50 int num_feeds = 0;
51 feed feeds[MAX_FEEDS];
52
53 size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
54 {
55         size_t realsize = size * nmemb;
56         struct MemoryStruct *mem = (struct MemoryStruct *) data;
57
58         mem->memory = (char *) realloc(mem->memory, mem->size + realsize + 1);
59         if (mem->memory) {
60                 memcpy(&(mem->memory[mem->size]), ptr, realsize);
61                 mem->size += realsize;
62                 mem->memory[mem->size] = 0;
63         }
64         return realsize;
65 }
66
67 int rss_delay(int *wait_time, int delay)
68 {
69         time_t now = time(NULL);
70
71         // make it minutes
72         if (delay < 1) {
73                 delay = 1;
74         }
75         delay *= 60;
76
77         if (!*wait_time) {
78                 *wait_time = now + delay;
79                 return 1;
80         }
81
82         if (now >= *wait_time + delay) {
83                 *wait_time = now + delay;
84                 return 1;
85         }
86
87         return 0;
88 }
89
90 void init_rss_info(void)
91 {
92         int i;
93
94         for (i = 0; i < MAX_FEEDS; i++) {
95                 feeds[i].uri = NULL;
96                 feeds[i].data = NULL;
97                 feeds[i].last_update = 0;
98         }
99 }
100
101 void free_rss_info(void)
102 {
103         int i;
104
105         for (i = 0; i < num_feeds; i++) {
106                 if (feeds[i].uri != NULL) {
107                         free(feeds[i].uri);
108                 }
109         }
110 }
111
112 PRSS *get_rss_info(char *uri, int delay)
113 {
114         CURL *curl = NULL;
115         CURLcode res;
116
117         // pointers to struct
118         feed *curfeed = NULL;
119         PRSS *curdata = NULL;
120         int *last_update = 0;
121
122         int i;
123
124         // curl temps
125         struct MemoryStruct chunk;
126
127         chunk.memory = NULL;
128         chunk.size = 0;
129
130         // first seek for the uri in list
131         for (i = 0; i < num_feeds; i++) {
132                 if (feeds[i].uri != NULL) {
133                         if (!strcmp(feeds[i].uri, uri)) {
134                                 curfeed = &feeds[i];
135                                 break;
136                         }
137                 }
138         }
139
140         if (!curfeed) { // new feed
141                 if (num_feeds == MAX_FEEDS - 1) {
142                         return NULL;
143                 }
144                 curfeed = &feeds[num_feeds];
145                 curfeed->uri = strndup(uri, text_buffer_size);
146                 num_feeds++;
147         }
148
149         last_update = &curfeed->last_update;
150         curdata = curfeed->data;
151
152         if (!rss_delay(last_update, delay)) {
153                 return curdata; // wait for delay to pass
154         }
155
156         if (curdata != NULL) {
157                 prss_free(curdata);     // clean up old data
158                 curdata = NULL;
159         }
160
161         curl = curl_easy_init();
162         if (curl) {
163                 curl_easy_setopt(curl, CURLOPT_URL, uri);
164                 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
165                 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
166                 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &chunk);
167                 curl_easy_setopt(curl, CURLOPT_USERAGENT, "conky-rss/1.0");
168
169                 res = curl_easy_perform(curl);
170                 if (chunk.size) {
171                         curdata = prss_parse_data(chunk.memory);
172                         free(chunk.memory);
173                 } else {
174                         ERR("No data from server");
175                 }
176
177                 curl_easy_cleanup(curl);
178         }
179
180         curfeed->data = curdata;
181
182         return curdata;
183 }