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
28 #include "wmweather+.h"
35 #include "sunzenith.h"
39 /* Important variables */
41 static time_t eta_time
=0;
42 static char *eta_file
=NULL
;
43 static char *eta_newfile
=NULL
;
44 static char *eta_req
[2]={ NULL
, NULL
};
45 static struct forecast forecasts
[ETA_MAX
];
48 /********* init functions ************/
49 static int parse_eta(char *file
);
51 static void reset_eta(void){
54 for(i
=0; i
<ETA_MAX
; i
++) reset_forecast(&forecasts
[i
]);
60 struct subst_val subs
[]={
61 { 's', STRING
, &eta_station
},
65 strncpy(bigbuf
, eta_station
, BIGBUF_LEN
-14);
66 bigbuf
[BIGBUF_LEN
-14]='\0';
67 for(e
=bigbuf
; *e
!='\0'; e
++);
68 strcpy(e
, ".eta.txt");
69 eta_file
=get_pid_filename(bigbuf
);
70 strcpy(e
, ".new-eta.txt");
71 eta_newfile
=get_pid_filename(bigbuf
);
73 if((eta_req
[0]=subst(eta_uri
, subs
))==NULL
) die("init_eta");
74 if(eta_post
!=NULL
&& (eta_req
[1]=subst(eta_post
, subs
))==NULL
) die("init_eta");
77 /* Remove stale file */
81 for(i
=0; i
<ETA_MAX
; i
++) add_forecast(&forecasts
[i
], "ETA", eta_station
);
85 /********* download functions ************/
87 static void eta_callback(char *filename
, void *v
){
90 if(stat(eta_newfile
, &statbuf
)>=0){
91 if(S_ISREG(statbuf
.st_mode
) && statbuf
.st_size
!=0
92 && diff(eta_newfile
, eta_file
) && parse_eta(eta_newfile
)){
93 eta_time
=find_next_time(eta_newfile
, "MOS GUIDANCE", 720);
94 rename(eta_newfile
, eta_file
);
97 if(!parse_eta(eta_file
)) reset_eta();
102 void eta_cleanup(void){
103 if(eta_file
==NULL
) return;
108 void update_eta(int force
){
111 if(eta_file
==NULL
) return;
114 if(!force
&& eta_time
>t
) return;
116 eta_time
=find_next_time(eta_file
, "MOS GUIDANCE", 15);
117 download_file(eta_newfile
, eta_req
[0], eta_req
[1], force
?DOWNLOAD_KILL_OTHER_REQUESTS
:0, eta_callback
, NULL
);
121 /********* parse functions ************/
123 #define NEXT(s) free(s); \
124 len=getLine(&s, fp); \
125 if(strstr(s, "</PRE>")!=NULL) len=0;
127 #define DIE() return (free(s), fclose(fp), 0)
133 memset(split,'\0',sizeof(split)); \
134 for(n=0, c=s+4; c<s+len && n<ETA_MAX; n++, c+=3){ \
141 #define ASSIGN(field) \
142 for(n=0; n<ETA_MSG_MAX; n++) forecasts[n].field=atoi(split[n]);
144 #define ASSIGN2(field, inval) \
145 for(n=0; n<ETA_MSG_MAX; n++){ \
147 if(i!=inval) forecasts[n].field=i; \
150 static int parse_eta(char *file
){
151 int ETA_MSG_MAX
= ETA_MAX
;
156 int h
, i
=0, j
, k
, m
, n
, x
, y
, z
;
158 char split
[ETA_MAX
][4];
161 if((fp
=fopen(file
, "r"))==NULL
) return 0;
163 /* Look for something like an ETA coded forecast */
167 if((c
=strstr(s
, "MOS GUIDANCE"))!=NULL
) break;
170 if(c
==NULL
) return (fclose(fp
), 0);
172 if(c
==NULL
|| !isdigit(*(c
-1)) || !isdigit(*(c
+1))) DIE();
175 if(c
==NULL
|| !isdigit(*(c
-1)) || !isdigit(*(c
+1))) DIE();
181 if(strncmp(s
, "DT ", 3)) DIE();
188 for(mon
=1; mon
<=12; mon
++){
189 if(!strncmp(c
+1, monthnames
[mon
], 3) && isspace(*(c
+4))) break;
190 if(!strncmp(c
+1, monthnames2
[mon
], 4) && isspace(*(c
+5))){
203 if(strncmp(s
, "HR ", 3)) DIE();
207 for(n
=0; n
<ETA_MAX
; n
++){
208 if(split
[n
][0]=='\0'){
215 fix_date(&mon
, &x
, &y
, NULL
);
220 h
=utc2local(i
*100, &m
, &j
, &z
, &k
)/100;
221 forecasts
[n
].month
=m
;
226 if(latitude
!=999 && calcSolarZenith(latitude
, longitude
, y
, mon
, x
, i
*60)>90)
227 forecasts
[n
].moon
=calc_moon(m
, j
, z
, h
*100);
235 if(!strcmp(ID
, "X/N")) j
=1;
236 else if(!strcmp(ID
, "N/X")) j
=2;
239 for(n
=0; n
<ETA_MSG_MAX
; n
++){
240 if(!isdigit(split
[n
][2])) continue;
243 for(m
=0; m
<ETA_MSG_MAX
; m
++){
245 ((forecasts
[m
].day
==k
-1 && forecasts
[m
].hour
>=19)
246 || (forecasts
[m
].day
==k
&& forecasts
[m
].hour
<19)))
249 ((forecasts
[m
].day
==k
-1 && forecasts
[m
].hour
>=8)
250 || (forecasts
[m
].day
==k
&& forecasts
[m
].hour
<8)))
257 if(!strcmp(ID
, "TMP")){
261 if(!strcmp(ID
, "DPT")){
265 if(!strcmp(ID
, "WDR")){
266 for(n
=0; n
<ETA_MSG_MAX
; n
++){
268 if(i
==99) forecasts
[n
].winddir
=0;
269 else forecasts
[n
].winddir
=((int)((i
+1.125)/2.25))%16+1;
273 if(!strcmp(ID
, "WSP")){
274 ASSIGN2(windspeed
, 99);
277 if(!strcmp(ID
, "P06")){
278 for(m
=0; m
<ETA_MSG_MAX
; m
++){
279 if(!isdigit(split
[m
][2])) continue;
282 forecasts
[m
].pcp_total
=i
;
283 /* ETA_MSG_MAX-2 because the last 2
284 * are already 6-hour intervals */
285 if(m
>0 && m
<ETA_MSG_MAX
-2) forecasts
[m
-1].pcp_total
=i
;
290 if(!strcmp(ID
, "T06")){
291 for(m
=1; m
<ETA_MSG_MAX
; m
+=2){
292 if(!isdigit(split
[m
][2])) continue;
293 i
=atoi(split
[m
]); if(i
==999) i
=0;
294 j
=atoi(split
[m
+1]+1); if(j
==99) j
=0;
296 forecasts
[m
].tstorm
=forecasts
[m
+1].tstorm
=i
;
297 forecasts
[m
].svtstorm
=forecasts
[m
+1].svtstorm
=j
;
301 if(!strcmp(ID
, "Q06")){
302 for(m
=0; m
<ETA_MSG_MAX
; m
++){
303 if(!isdigit(split
[m
][2])) continue;
306 forecasts
[m
].precipamt
=i
;
307 /* ETA_MSG_MAX-2 because the last 2
308 * are already 6-hour intervals */
309 if(m
>0 && m
<ETA_MSG_MAX
-2) forecasts
[m
-1].precipamt
=i
;
314 if(!strcmp(ID
, "CLD")){
315 for(m
=0; m
<ETA_MSG_MAX
; m
++){
316 if(split
[m
][1]=='C') forecasts
[m
].sky
=0;
317 if(split
[m
][1]=='F') forecasts
[m
].sky
=1;
318 if(split
[m
][1]=='S') forecasts
[m
].sky
=2;
319 if(split
[m
][1]=='B') forecasts
[m
].sky
=3;
320 if(split
[m
][1]=='O') forecasts
[m
].sky
=4;
324 if(!strcmp(ID
, "VIS")){
328 if(!strcmp(ID
, "OBV")){
329 for(m
=0; m
<ETA_MSG_MAX
; m
++){
330 if(split
[m
][2]=='N') forecasts
[m
].obs
=0;
331 if(split
[m
][2]=='R' || split
[m
][2]=='G') forecasts
[m
].obs
=1;
332 if(split
[m
][2]=='Z') forecasts
[m
].obs
=2;
333 if(split
[m
][2]=='L') forecasts
[m
].obs
=3;
337 if(!strcmp(ID
, "POZ")){
341 if(!strcmp(ID
, "POS")){
349 for(m
=0; m
<ETA_MSG_MAX
; m
++){
350 forecasts
[m
].rh
=rh_F(forecasts
[m
].temp
, forecasts
[m
].dewpt
);
351 forecasts
[m
].heatindex
=heatindex_F(forecasts
[m
].temp
, forecasts
[m
].rh
);
352 forecasts
[m
].windchill
=windchill_F(forecasts
[m
].temp
, forecasts
[m
].windspeed
);
353 forecasts
[m
].rain
=93-forecasts
[m
].frz
-forecasts
[m
].snow
;
354 forecasts
[m
].rain
=forecasts
[m
].rain
*forecasts
[m
].pcp_total
/93;
355 forecasts
[m
].snow
=forecasts
[m
].snow
*forecasts
[m
].pcp_total
/93;
356 forecasts
[m
].frz
=forecasts
[m
].frz
*forecasts
[m
].pcp_total
/93;