wmpager: drop tooltip suport
[dockapps.git] / wmweather+ / mrf.c
blobf33b79f281698ba9b2adb80760f3ba93c4d787c4
1 #include "config.h"
3 /* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <time.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <math.h>
27 #include <sys/stat.h>
29 #include "wmweather+.h"
30 #include "forecast.h"
31 #include "getLine.h"
32 #include "convert.h"
33 #include "download.h"
34 #include "diff.h"
35 #include "die.h"
36 #include "subst.h"
38 /* Important variables */
39 #define MRF_MAX 7
40 static time_t mrf_time=0;
41 static char *mrf_file=NULL;
42 static char *mrf_newfile=NULL;
43 static char *mrf_req[2]={ NULL, NULL };
44 static struct forecast forecasts[MRF_MAX];
47 /********* init functions ************/
48 static int parse_mrf(char *file);
50 static void reset_mrf(void){
51 int i;
53 for(i=0; i<MRF_MAX; i++) reset_forecast(&forecasts[i]);
56 void init_mrf(void){
57 int i;
58 char *e;
59 struct subst_val subs[]={
60 { 's', STRING, &mrf_station },
61 { 0, 0, 0 }
64 strncpy(bigbuf, mrf_station, BIGBUF_LEN-14);
65 bigbuf[BIGBUF_LEN-14]='\0';
66 for(e=bigbuf; *e!='\0'; e++);
67 strcpy(e, ".mrf.txt");
68 mrf_file=get_pid_filename(bigbuf);
69 strcpy(e, ".new-mrf.txt");
70 mrf_newfile=get_pid_filename(bigbuf);
72 if((mrf_req[0]=subst(mrf_uri, subs))==NULL) die("init_mrf");
73 if(mrf_post!=NULL && (mrf_req[1]=subst(mrf_post, subs))==NULL) die("init_mrf");
74 mrf_time=0;
76 /* Remove stale file */
77 unlink(mrf_file);
78 unlink(mrf_newfile);
79 reset_mrf();
80 for(i=0; i<MRF_MAX; i++) add_forecast(&forecasts[i], "MRF", mrf_station);
83 static void mrf_callback(char *filename, void *v){
84 struct stat statbuf;
86 if(stat(mrf_newfile, &statbuf)>=0){
87 if(S_ISREG(statbuf.st_mode) && statbuf.st_size!=0
88 && diff(mrf_newfile, mrf_file) && parse_mrf(mrf_newfile)){
89 mrf_time=find_next_time(mrf_newfile, "MOS GUIDANCE", 1440);
90 rename(mrf_newfile, mrf_file);
91 } else {
92 unlink(mrf_newfile);
93 if(!parse_mrf(mrf_file)) reset_mrf();
98 void mrf_cleanup(void){
99 if(mrf_file==NULL) return;
100 unlink(mrf_newfile);
101 unlink(mrf_file);
104 void update_mrf(int force){
105 time_t t;
107 if(mrf_file==NULL) return;
109 t=time(NULL)/60;
110 if(!force && mrf_time>t) return;
112 mrf_time=find_next_time(mrf_file, "MOS GUIDANCE", 15);
113 download_file(mrf_newfile, mrf_req[0], mrf_req[1], 0, mrf_callback, NULL);
117 #define NEXT(s) free(s); \
118 len=getLine(&s, fp); \
119 if(strstr(s, "</PRE>")!=NULL) len=0;
121 #define DIE() return (free(s), fclose(fp), 0)
122 #define INT(c) (tmp[0]=*c, tmp[1]=*(c+1), tmp[2]=*(c+2), tmp[3]=0, atoi(tmp))
124 static int parse_mrf(char *file){
125 FILE *fp;
126 char *s, *c;
127 int len;
128 int mon, day;
129 int i, j, m, x, y;
130 int flag;
131 char tmp[4]={0, 0, 0, 0};
133 flag=0;
134 reset_mrf();
135 if((fp=fopen(file, "r"))==NULL) return 0;
137 /* Look for something like an MRF coded forecast */
138 c=NULL;
139 while(!feof(fp)){
140 len=getLine(&s, fp);
141 if((c=strstr(s, "MOS GUIDANCE"))!=NULL) break;
142 free(s);
144 if(c==NULL) return (fclose(fp), 0);
145 c=strchr(c, '/');
146 if(c==NULL || !isdigit(*(c-1)) || !isdigit(*(c+1))) DIE();
147 mon=atoi(c-2);
148 x=atoi(c+1);
149 if(mon<1 || mon>12 || x<1 || x>31) DIE();
150 c=strchr(c+1, '/');
151 if(c==NULL || !isdigit(*(c-1)) || !isdigit(*(c+1))) DIE();
152 y=atoi(c+1)-1900;
154 NEXT(s);
155 if(len<10) DIE();
156 if(strncmp(s, "FHR", 3)) DIE();
158 NEXT(s);
159 if(len<10) DIE();
160 for(i=0; i<7; i++){
161 if(!strncmp(s, wdaynames[i], 3)) break;
163 if(i>=7) DIE();
164 day=atoi(s+4);
165 if(x>25 && day<5) mon++;
166 if(x<5 && day>25) mon--;
167 for(m=0; m<MRF_MAX; m++){
168 day++;
169 i++; i%=7;
170 fix_date(&mon, &day, &y, &j);
171 if(j!=i){
172 warn("Something wicked happened with the mrf_parse dates...");
173 DIE();
175 forecasts[m].month=mon;
176 forecasts[m].day=day;
177 forecasts[m].year=y;
178 forecasts[m].wday=i;
179 forecasts[m].hour=-1;
182 while(1){
183 NEXT(s);
184 if(len<=10) break;
186 if(!strncmp(s, "X/N", 3)){
187 for(c=s+12, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
188 forecasts[m].high=INT(c);
189 if(c+4<s+len) forecasts[m].low=INT((c+4));
191 continue;
193 if(!strncmp(s, "TMP", 3)){
194 for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
195 i=INT(c); j=INT((c+4));
196 if(i!=999 && j!=999) forecasts[m].temp=(i+j)/2;
197 else if(i!=999) forecasts[m].temp=i;
198 else if(j!=999) forecasts[m].temp=j;
200 continue;
202 if(!strncmp(s, "DPT", 3)){
203 for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
204 i=INT(c); j=INT((c+4));
205 if(i!=999 && j!=999) forecasts[m].dewpt=(i+j)/2;
206 else if(i!=999) forecasts[m].dewpt=i;
207 else if(j!=999) forecasts[m].dewpt=j;
209 continue;
211 if(!strncmp(s, "WND", 3)){
212 for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
213 i=INT(c); j=INT((c+4));
214 if(i!=999 && j!=999) forecasts[m].windspeed=(i+j)/2;
215 else if(i!=999) forecasts[m].windspeed=i;
216 else if(j!=999) forecasts[m].windspeed=j;
218 continue;
220 if(!strncmp(s, "T24", 3)){
221 for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
222 i=atoi(c);
223 if(i!=999) forecasts[m].tstorm=i;
225 continue;
227 if(!strncmp(s, "Q24", 3)){
228 for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
229 i=atoi(c);
230 if(i!=9) forecasts[m].precipamt=i;
232 continue;
234 if(!strncmp(s, "SNW", 3)){
235 for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
236 i=atoi(c);
237 if(i!=9) forecasts[m].snowamt=i;
239 continue;
241 if(!strncmp(s, "CLD", 3)){
242 for(c=s+13, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
243 if(*c=='C') forecasts[m].sky=0;
244 if(*c=='P'){
245 if(*(c-4)=='C') forecasts[m].sky=2;
246 else if(*(c-4)=='O') forecasts[m].sky=3;
247 else if(c+4<s+len && *(c+4)=='C') forecasts[m].sky=2;
248 else if(c+4<s+len && *(c+4)=='O') forecasts[m].sky=3;
249 else forecasts[m].sky=3;
251 if(*c=='O') forecasts[m].sky=4;
253 continue;
255 if(!strncmp(s, "PZP", 3)){
256 for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
257 i=INT(c); j=INT((c+4));
258 if(i!=999 && j!=999) forecasts[m].frz=(i+j)/2;
259 else if(i!=999) forecasts[m].frz=i;
260 else if(j!=999) forecasts[m].frz=j;
262 continue;
264 if(!strncmp(s, "PSN", 3)){
265 for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
266 i=INT(c); j=INT((c+4));
267 if(i!=999 && j!=999) forecasts[m].snow=(i+j)/2;
268 else if(i!=999) forecasts[m].snow=i;
269 else if(j!=999) forecasts[m].snow=j;
271 continue;
273 if(!strncmp(s, "PRS", 3)){
274 /* stick "rain & snow" prob into rain for later */
275 flag=1;
276 for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
277 i=INT(c); j=INT((c+4));
278 if(i!=999 && j!=999) forecasts[m].rain=(i+j)/2;
279 else if(i!=999) forecasts[m].rain=i;
280 else if(j!=999) forecasts[m].rain=j;
282 continue;
284 if(!strncmp(s, "P24", 3)){
285 for(c=s+8, m=0; c<s+len && m<MRF_MAX; c+=8, m++){
286 i=atoi(c);
287 if(i!=999) forecasts[m].pcp_total=i;
289 continue;
292 free(s);
293 fclose(fp);
295 for(m=0; m<MRF_MAX; m++){
296 forecasts[m].rh=rh_F(forecasts[m].temp, forecasts[m].dewpt);
297 forecasts[m].heatindex=heatindex_F(forecasts[m].temp, forecasts[m].rh);
298 forecasts[m].windchill=windchill_F(forecasts[m].temp, forecasts[m].windspeed);
299 /* real rain = 100 - frz - snow
300 * real snow = snow + "rain & snow"
302 i=100-forecasts[m].frz-forecasts[m].snow;
303 forecasts[m].snow+=forecasts[m].rain;
304 forecasts[m].rain=i;
305 forecasts[m].rain=forecasts[m].rain*forecasts[m].pcp_total/100;
306 forecasts[m].snow=forecasts[m].snow*forecasts[m].pcp_total/100;
307 forecasts[m].frz=forecasts[m].frz*forecasts[m].pcp_total/100;
309 /* These aren't really useful here... */
310 forecasts[m].temp=999;
311 forecasts[m].dewpt=999;
314 return 1;
316 #undef NEXT
317 #undef DIE
318 #undef INT