1 #include "config.h"
2 
3 /*  Copyright (C) 2002  Brad Jorsch <anomie@users.sourceforge.net>
4 
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.
9 
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.
14 
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <limits.h>
25 #include <ctype.h>
26 #include <signal.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <sys/stat.h>
30 #include <sys/wait.h>
31 #if TM_IN_SYS_TIME
32 # if TIME_WITH_SYS_TIME
33 #  include <sys/time.h>
34 #  include <time.h>
35 # else
36 #  if HAVE_SYS_TIME_H
37 #   include <sys/time.h>
38 #  else
39 #   include <time.h>
40 #  endif
41 # endif
42 #else
43 #include <time.h>
44 #endif
45 
46 #include <X11/Xlib.h>
47 #include <X11/Xatom.h>
48 #include <X11/xpm.h>
49 
50 #include "wmweather+.h"
51 #include "convert.h"
52 #include "download.h"
53 #include "dock.h"
54 #include "die.h"
55 #include "animation.h"
56 
57 
58 char *ProgName;
59 char *bigbuf;
60 int devnull;
61 char *monthnames[]={ "", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
62 char *monthnames2[]={ "", "", "", "", "", "", "JUNE", "JULY", "", "SEPT", "", "", "" };
63 char *wdaynames[]={ "SUNDAY", "MONDAY", "TUESDAY", "WEDN'SDAY", "THURSDAY", "FRIDAY", "SATURDAY"};
64 char *directions[]={"VRB", "N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
65 
66 char *error;
67 char *unknown_option="Unknown option";
68 
69 #define F(a) fprintf(stderr, a "\n");
70 
71 /***************************************************
72  * Configuration parameters
73  ***************************************************/
74 char *email_address=NULL;
75 char *metar_station=NULL;
76 char *metar_uri=NULL;
77 char *metar_post=NULL;
78 char **warning_zones=NULL;
79 char *warning_uri=NULL;
80 char *warning_post=NULL;
81 char *avn_station=NULL;
82 char *avn_uri=NULL;
83 char *avn_post=NULL;
84 char *eta_station=NULL;
85 char *eta_uri=NULL;
86 char *eta_post=NULL;
87 char *mrf_station=NULL;
88 char *mrf_uri=NULL;
89 char *mrf_post=NULL;
90 char *radar_uri=NULL;
91 char *radar_post=NULL;
92 char *radar_crop=NULL;
93 char *radar_cross=NULL;
94 char *viewer=NULL;
95 int pressure_mode=0;
96 int windspeed_mode=0;
97 int temp_mode=0;
98 int length_mode=0;
99 double latitude=999, longitude=999;
100 int start_do_animation=1;
101 int starting_mode=0;
102 
103 
104 /**********************************
105  * Prototypes
106  **********************************/
107 void usage(int i);
108 void printversion(void);
109 int readconf(char *file);
110 int parse_option(char *option, char *value);
111 char *get_filename(char *file);
112 
113 /**********************************
114  * Functions
115  **********************************/
116 
sigchld(int i)117 void sigchld(int i){
118     while(waitpid(-1, NULL, WNOHANG)>0);
119 }
120 
parse_option(char * option,char * value)121 int parse_option(char *option, char *value){
122     int i;
123     void *v;
124 
125     errno=0;
126     error=unknown_option;
127     if(option[0]=='-') option++;
128     if(option[0]=='-' && option[1]!='\0' && option[2]!='\0') option++;
129     if(option[0]=='\0') return 0;
130     if(value!=NULL && value[0]=='\0') value=NULL;
131 
132     switch (option[0]){
133       case 'a':
134         if(!strncmp(option, "avn-", 4)){
135             if(!strcmp(option+4, "station")){
136                 if(value==NULL){
137                     error="avn-station given with no station ID";
138                     return 0;
139                 }
140                 if(avn_station!=NULL) free(avn_station);
141                 avn_station=strdup(value);
142                 if(avn_station==NULL) die("avn-station strdup");
143                 return 2;
144             } else if(!strcmp(option+4, "uri")){
145                 if(value==NULL){
146                     error="avn-uri given with no URI";
147                     return 0;
148                 }
149                 if(avn_uri!=NULL) free(avn_uri);
150                 avn_uri=strdup(value);
151                 if(avn_uri==NULL) die("avn-uri strdup");
152                 if(avn_post!=NULL) free(avn_post);
153                 avn_post=NULL;
154                 return 2;
155             } else if(!strcmp(option+4, "post")){
156                 if(value==NULL){
157                     error="avn-post given with no data";
158                     return 0;
159                 }
160                 if(avn_uri==NULL){
161                     error="avn-post must come after avn-uri";
162                     return 0;
163                 }
164                 if(avn_post!=NULL) free(avn_post);
165                 avn_post=strdup(value);
166                 if(avn_post==NULL) die("avn-post strdup");
167                 return 2;
168             }
169             break;
170         } else if(!strcmp(option, "atm")){
171             pressure_mode=3;
172             return 1;
173         } else if(!strcmp(option, "animate")){
174             start_do_animation=1;
175             return 1;
176         }
177         break;
178       case 'b':
179         if(!strcmp(option, "beaufort")){
180             windspeed_mode=4;
181             return 1;
182         }
183         break;
184       case 'c':
185         if(option[1]=='\0') return 2; /* -c handled earlier */
186         else if(!strcmp(option, "cm")){
187             length_mode=1;
188             return 1;
189         }
190         break;
191       case 'd':
192         if(!strcmp(option, "display-mode")){
193             if(value==NULL){
194                 error="display-mode given with no mode specified";
195                 return 0;
196             }
197             if(!strcasecmp(value, "cur") || !strcasecmp(value, "current")){
198                 starting_mode=0;
199                 return 2;
200             } else if(!strcasecmp(value, "fcst") || !strcasecmp(value, "forecast")){
201                 starting_mode=1;
202                 return 2;
203             } else if(!strcasecmp(value, "map") || !strcasecmp(value, "radar")){
204                 starting_mode=2;
205                 return 2;
206             } else {
207                 error="display-mode given with unrecognized mode";
208                 return 0;
209             }
210         } else if(!strcmp(option, "display")){
211             return 1;
212         }
213         break;
214       case 'e':
215         if(!strncmp(option, "eta-", 4)){
216             if(!strcmp(option+4, "station")){
217                 if(value==NULL){
218                     error="eta-station given with no station ID";
219                     return 0;
220                 }
221                 if(eta_station!=NULL) free(eta_station);
222                 eta_station=strdup(value);
223                 if(eta_station==NULL) die("eta-station strdup");
224                 return 2;
225             } else if(!strcmp(option+4, "uri")){
226                 if(value==NULL){
227                     error="eta-uri given with no URI";
228                     return 0;
229                 }
230                 if(eta_uri!=NULL) free(eta_uri);
231                 eta_uri=strdup(value);
232                 if(eta_uri==NULL) die("eta-uri strdup");
233                 if(eta_post!=NULL) free(eta_post);
234                 eta_post=NULL;
235                 return 2;
236             } else if(!strcmp(option+4, "post")){
237                 if(value==NULL){
238                     error="eta-post given with no data";
239                     return 0;
240                 }
241                 if(eta_uri==NULL){
242                     error="eta-post must come after eta-uri";
243                     return 0;
244                 }
245                 if(eta_post!=NULL) free(eta_post);
246                 eta_post=strdup(value);
247                 if(eta_post==NULL) die("eta-post strdup");
248                 return 2;
249             }
250             break;
251         } else if(option[1]=='\0' || !strcmp(option, "email")){
252             if(value==NULL){
253                 error="-e/email given with no address";
254                 return 0;
255             }
256             if(email_address!=NULL) free(email_address);
257             email_address=strdup(value);
258             if(email_address==NULL) die("email strdup");
259             return 2;
260         }
261         break;
262       case 'f':
263         if(!strncmp(option, "forget-", 7)){
264             if(!strcmp(option+7, "warning-zones")){
265                 if(warning_zones) free(warning_zones);
266                 warning_zones=NULL;
267                 return 1;
268             }
269             break;
270         }
271         break;
272       case 'h':
273         if(!strcmp(option, "hPa")){
274             pressure_mode=1;
275             return 1;
276         }
277         break;
278       case 'i':
279         if(!strcmp(option, "inHg")){
280             pressure_mode=0;
281             return 1;
282         } else if(!strcmp(option, "in")){
283             length_mode=0;
284             return 1;
285         }
286         break;
287       case 'k':
288         if(!strcmp(option, "kph")){
289             windspeed_mode=1;
290             return 1;
291         } else if(!strcmp(option, "knots")){
292             windspeed_mode=2;
293             return 1;
294         }
295         break;
296       case 'l':
297         if(!strcmp(option, "location")){
298             if(value==NULL){
299                 error="location given with no value";
300                 return 0;
301             }
302             if(!str2dd(value, &latitude, &longitude)){
303                 error="location should be of the form \"dd'mm'ssN dd'mm'ssW\" or \"dd.ddddN dd.dddddW\"\n   Note that, if you're using '-location' on the command line, you will need\n   to quote the value, e.g. '-location \"dd.ddddN dd.dddddW\"'";
304                 return 0;
305             }
306             if(latitude>90 || latitude<-90 || longitude>180 || longitude<-180){
307                 error="latitude or longitude out of range";
308                 return 0;
309             }
310             return 2;
311         }
312         break;
313       case 'm':
314         if(option[1]=='\0' || !strcmp(option, "metric")){
315             pressure_mode=windspeed_mode=temp_mode=length_mode=1;
316             return 1;
317         } else if(!strncmp(option, "metar-", 6)){
318             if(!strcmp(option+6, "station")){
319                 if(value==NULL){
320                     error="metar-station given with no station ID";
321                     return 0;
322                 }
323                 if(metar_station!=NULL) free(metar_station);
324                 metar_station=strdup(value);
325                 if(metar_station==NULL) die("metar-station strdup");
326                 return 2;
327             } else if(!strcmp(option+6, "uri")){
328                 if(value==NULL){
329                     error="metar-uri given with no URI";
330                     return 0;
331                 }
332                 if(metar_uri!=NULL) free(metar_uri);
333                 metar_uri=strdup(value);
334                 if(metar_uri==NULL) die("metar-uri strdup");
335                 if(metar_post!=NULL) free(metar_post);
336                 metar_post=NULL;
337                 return 2;
338             } else if(!strcmp(option+6, "post")){
339                 if(value==NULL){
340                     error="metar-post given with no data";
341                     return 0;
342                 }
343                 if(metar_uri==NULL){
344                     error="metar-post must come after metar-uri";
345                     return 0;
346                 }
347                 if(metar_post!=NULL) free(metar_post);
348                 metar_post=strdup(value);
349                 if(metar_post==NULL) die("metar-post strdup");
350                 return 2;
351             }
352             break;
353         } else if(!strncmp(option, "mrf-", 4)){
354             if(!strcmp(option+4, "station")){
355                 if(value==NULL){
356                     error="mrf-station given with no station ID";
357                     return 0;
358                 }
359                 if(mrf_station!=NULL) free(mrf_station);
360                 mrf_station=strdup(value);
361                 if(mrf_station==NULL) die("mrf-station strdup");
362                 return 2;
363             } else if(!strcmp(option+4, "uri")){
364                 if(value==NULL){
365                     error="mrf-uri given with no URI";
366                     return 0;
367                 }
368                 if(mrf_uri!=NULL) free(mrf_uri);
369                 mrf_uri=strdup(value);
370                 if(mrf_uri==NULL) die("mrf-uri strdup");
371                 if(mrf_post!=NULL) free(mrf_post);
372                 mrf_post=NULL;
373                 return 2;
374             } else if(!strcmp(option+4, "post")){
375                 if(value==NULL){
376                     error="mrf-post given with no data";
377                     return 0;
378                 }
379                 if(mrf_uri==NULL){
380                     error="mrf-post must come after mrf-uri";
381                     return 0;
382                 }
383                 if(mrf_post!=NULL) free(mrf_post);
384                 mrf_post=strdup(value);
385                 if(mrf_post==NULL) die("mrf-post strdup");
386                 return 2;
387             }
388             break;
389         } else if(!strcmp(option, "mmHg")){
390             pressure_mode=2;
391             return 1;
392         } else if(!strcmp(option, "mph")){
393             windspeed_mode=0;
394             return 1;
395         } else if(!strcmp(option, "mps")){
396             windspeed_mode=3;
397             return 1;
398         } else if(!strcmp(option, "mbar")){
399             pressure_mode=1;
400             return 1;
401         }
402         break;
403       case 'n':
404         if(!strcmp(option, "noradar")){
405             if(radar_uri!=NULL) free(radar_uri);
406             radar_uri=NULL;
407             return 1;
408         } else if(!strcmp(option, "noanimate")){
409             start_do_animation=0;
410             return 1;
411         }
412         break;
413       case 'r':
414         if(!strcmp(option, "radar")){
415             warn("'radar' is deprecated, please use 'radar-uri' instead");
416             return parse_option("radar-uri", value);
417         } else if(!strncmp(option, "radar-", 6)){
418             if(!strcmp(option+6, "uri")){
419                 if(value==NULL){
420                     error="radar-uri given with no URI";
421                     return 0;
422                 }
423                 if(radar_uri!=NULL) free(radar_uri);
424                 radar_uri=strdup(value);
425                 if(radar_uri==NULL) die("radar-uri strdup");
426                 if(radar_post!=NULL) free(radar_post);
427                 radar_post=NULL;
428                 return 2;
429             } else if(!strcmp(option+6, "post")){
430                 if(value==NULL){
431                     error="radar-post given with no data";
432                     return 0;
433                 }
434                 if(radar_uri==NULL){
435                     error="radar-post must come after radar-uri";
436                     return 0;
437                 }
438                 if(radar_post!=NULL) free(radar_post);
439                 radar_post=strdup(value);
440                 if(radar_post==NULL) die("radar-post strdup");
441                 return 2;
442             } else if(!strcmp(option+6, "crop")){
443                 if(value==NULL){
444                     error="radar-crop given with no value";
445                     return 0;
446                 }
447                 if(radar_crop!=NULL) free(radar_crop);
448                 radar_crop=strdup(value);
449                 if(radar_crop==NULL) die("radar-crop strdup");
450                 return 2;
451             } else if(!strcmp(option+6, "cross")){
452                 if(value==NULL){
453                     error="radar-cross given with no value";
454                     return 0;
455                 }
456                 if(radar_cross!=NULL) free(radar_cross);
457                 radar_cross=strdup(value);
458                 if(radar_cross==NULL) die("radar-cross strdup");
459                 return 2;
460             }
461             break;
462         }
463         break;
464       case 's':
465         if(option[1]=='\0' || !strcmp(option, "station")){
466             if(value==NULL){
467                 error="-s/station given with no value";
468                 return 0;
469             }
470             if(parse_option("metar-station", value)==2
471                && parse_option("avn-station", value)==2
472                && parse_option("eta-station", value)==2
473                && parse_option("mrf-station", value)==2)
474                 return 2;
475             return 0;
476         }
477         break;
478       case 't':
479         if(!strcmp(option, "tempf")){
480             temp_mode=0;
481             return 1;
482         } else if(!strcmp(option, "tempc")){
483             temp_mode=1;
484             return 1;
485         }
486         break;
487       case 'v':
488         if(option[1]=='\0' || !strcmp(option, "version")){
489             printversion();
490             exit(0);
491         } else if(!strcmp(option, "viewer")){
492             if(value==NULL){
493                 error="viewer given with no value";
494                 return 0;
495             }
496             if(viewer!=NULL) free(viewer);
497             viewer=strdup(value);
498             if(viewer==NULL) die("viewer strdup");
499             return 2;
500         }
501         break;
502       case 'w':
503         if(!strncmp(option, "warning-", 8)){
504             if(!strcmp(option+8, "zone")){
505                 if(value==NULL){
506                     error="warning-zone given with no zone ID";
507                     return 0;
508                 }
509                 if(warning_zones!=NULL){
510                     for(i=0; warning_zones[i]!=NULL; i++);
511                 } else {
512                     i=0;
513                 }
514                 v=realloc(warning_zones, sizeof(*warning_zones)*(i+2));
515                 if(v==NULL) die("warning-zone realloc");
516                 warning_zones=v;
517                 warning_zones[i+1]=NULL;
518                 warning_zones[i]=strdup(value);
519                 if(warning_zones[i]==NULL) die("warning-zone strdup");
520                 return 2;
521             } else if(!strcmp(option+8, "uri")){
522                 if(value==NULL){
523                     error="warning-uri given with no URI";
524                     return 0;
525                 }
526                 if(warning_uri!=NULL) free(warning_uri);
527                 warning_uri=strdup(value);
528                 if(warning_uri==NULL) die("warning-uri strdup");
529                 if(warning_post!=NULL) free(warning_post);
530                 warning_post=NULL;
531                 return 2;
532             } else if(!strcmp(option+8, "post")){
533                 if(value==NULL){
534                     error="warning-post given with no data";
535                     return 0;
536                 }
537                 if(warning_uri==NULL){
538                     error="warning-post must come after warning-uri";
539                     return 0;
540                 }
541                 if(warning_post!=NULL) free(warning_post);
542                 warning_post=strdup(value);
543                 if(warning_post==NULL) die("warning-post strdup");
544                 return 2;
545             }
546             break;
547         }
548         break;
549       case 'z':
550         if(!strcmp(option, "zone")){
551             warn("'zone' is deprecated, please use 'warning-zone' instead");
552             return parse_option("warning-zone", value);
553         }
554         break;
555       default:
556         break;
557     }
558     return 0;
559 }
560 
readconf(char * file)561 int readconf(char *file){
562     char *c, *d;
563     int i, l, flag=1;
564     FILE *fp;
565 
566     if(file==NULL){
567         flag=0;
568         file=get_filename("conf");
569     }
570 
571     if((fp=fopen(file, "r"))==NULL){
572         if(!flag){
573             free(file);
574             return 0;
575         }
576         return 1;
577     }
578 
579     l=0;
580     while(fgets(bigbuf, BIGBUF_LEN, fp)!=NULL){
581         l++;
582         for(i=strlen(bigbuf)-1; i>=0; i--){
583             if (!isspace(bigbuf[i])) break;
584             bigbuf[i]='\0';
585         }
586         c=bigbuf+strspn(bigbuf, " \t");
587         if(*c=='#' || *c=='\0') continue;
588         d=c+strcspn(c, " \t");
589         if(*d=='\0') d=NULL;
590         else {
591             *d='\0';
592             d++;
593             d+=strspn(d+1, " \t");
594             if(*d=='\0') d=NULL;
595         }
596         if(!parse_option(c, d)){
597             warn("%s[%d]: %s", file, l, error);
598             fclose(fp);
599             if(!flag) free(file);
600             return 2;
601         }
602     }
603     fclose(fp);
604     if(!flag) free(file);
605     return 0;
606 }
607 
608 
check_dir(void)609 int check_dir(void){
610     char *c;
611     struct stat statbuf;
612     int i;
613 
614     c=get_filename("");
615     i=stat(c, &statbuf);
616     if(i<0){
617         if(errno==ENOENT){
618             if(mkdir(c, 0777)<0) die("Couldn't create directory %s", c);
619             errno=0;
620             warn("Created directory %s", c);
621             i=stat(c, &statbuf);
622         }
623         if(i<0) die("Couldn't stat %s", c);
624     }
625     if(!S_ISDIR(statbuf.st_mode)) die("%s is not a directory", c);
626     free(c);
627     c=get_filename(".dir-test");
628     if(unlink(c)<0 && errno!=ENOENT) die("Couldn't delete %s", c);
629     if((i=stat(c, &statbuf))!=-1 || errno!=ENOENT){
630         if(i!=-1) errno=EEXIST;
631         die("Couldn't verify nonexistence of %s", c);
632     }
633     if((i=creat(c, 0))<0) die("Couldn't create %s", c);
634     close(i);
635     if(stat(c, &statbuf)<0) die("Couldn't stat %s", c);
636     unlink(c);
637     free(c);
638     return 1;
639 }
640 
sigint(int i)641 void sigint(int i){
642     exit(0);
643 }
644 
main(int argc,char ** argv)645 int main(int argc, char **argv){
646     int i, j;
647     char *c;
648 
649     ProgName = argv[0];
650     if((c=strrchr(ProgName, '/'))!=NULL && *(c+1)!='\0'){
651         ProgName=c+1;
652     }
653 
654     if((bigbuf=malloc(BIGBUF_LEN))==NULL) die("bigbuf malloc");
655     check_dir();
656 
657     devnull=open("/dev/null", O_RDWR);
658     if(devnull<0) die("opening /dev/null");
659     /* Parse Command Line */
660 
661     c=NULL;
662     for(i=1;i<argc;i++){
663         if(!strcmp(argv[i], "-c")){
664             i++;
665             if(!(i<argc)){
666                 F("-c given with no value");
667                 exit(1);
668             }
669             c=argv[i];
670             break;
671         }
672     }
673     if(readconf("/usr/local/etc/wmweather+.conf")>1) exit(1);
674     if((i=readconf(c))==1) warn("Couldn't open %s", c);
675     if(i) exit(1);
676 
677     for(i=1;i<argc;i++){
678         char *arg = argv[i];
679 
680         if(*arg=='-'){
681             j=parse_option(argv[i], (i+1<argc)?argv[i+1]:NULL);
682             if(j==0){
683                 if(error==unknown_option) usage(1);
684                 fprintf(stderr, "%s\n", error);
685                 exit(1);
686             }
687             i+=j-1;
688         }
689     }
690 
691     {
692         struct sigaction act;
693         sigemptyset(&act.sa_mask);
694         act.sa_handler=sigchld;
695         act.sa_flags=SA_RESTART;
696         sigaction(SIGCHLD, &act, NULL);
697         act.sa_handler=sigint;
698         sigaction(SIGINT, &act, NULL);
699     }
700 
701     i=0;
702     if(metar_station==NULL){
703         i=1;
704         F("Please specify a METAR station.\n   See http://www.nws.noaa.gov/tg/siteloc.php\n");
705     }
706     if(latitude==999){{
707         time_t t;
708         int flag=0;
709 
710         /* note: if time_t isn't an arithmetic type, mkgmtime is screwed
711          * anyway. So t=0 is as appropriate as anything else. */
712         t=0;
713         longitude=-mkgmtime(localtime(&t))/240.0;
714         latitude=0;
715         if(longitude<0){
716             flag=1;
717             longitude=-longitude;
718         }
719         fprintf(stderr, "-location not given. Guessing you're at 0N %d'%d'%d%c\n", (int)longitude, (int)(longitude*60)%60, (int)(longitude*3600)%60, flag?'E':'W');
720         if(flag) longitude=-longitude;
721     }} else if(latitude>89.8){
722         F("Latitude greater then 89.9N automatically truncated.\n");
723         latitude=89.8;
724     } else if(latitude<-89.8){
725         F("Latitude greater then 89.9S automatically truncated.\n");
726         latitude=-89.8;
727     }
728     if(i) exit(1);
729     if(viewer==NULL) viewer="xless";
730     if(metar_uri==NULL) metar_uri="http://tgftp.nws.noaa.gov/data/observations/metar/stations/%s.TXT";
731     if(avn_uri==NULL) avn_uri="http://www.nws.noaa.gov/cgi-bin/mos/getmav.pl?sta=%s";
732     if(eta_uri==NULL) eta_uri="http://www.nws.noaa.gov/cgi-bin/mos/getmet.pl?sta=%s";
733     if(mrf_uri==NULL) mrf_uri="http://www.nws.noaa.gov/cgi-bin/mos/getmex.pl?sta=%s";
734     if(warning_uri==NULL) warning_uri="http://tgftp.nws.noaa.gov/data/watches_warnings/%f/%.2z/%z.txt";
735 
736     download_init(email_address);
737     init_dock(argc, argv);
738     while(1){
739         update_dock();
740         download_process(100000);
741     }
742 }
743 
usage(int i)744 void usage(int i) {
745     F("Option         Value      Description");
746     F("------         -----      -----------");
747     F("-c             <file>     Specify a configuration file");
748     F("-e             <address>  Alias for -email");
749     F("-email         <address>  Specify anonymous FTP password");
750     F("-location      <lat+lon>  Specify latitude and longitude. See manpage.");
751     F("-v                        Alias for -version");
752     F("-version                  Display version number");
753     F("-viewer        <program>  Program to display text from stdin");
754     F("-[no]animate              Turn animation on or off");
755     F("");
756     F("-s             <ID>       Alias for -station");
757     F("-station       <ID>       Station ID (all stations)");
758     F("-metar-station <ID>       Station ID for METAR observations");
759     F("-avn-station   <ID>       Station ID for AVN forecasts");
760     F("-eta-station   <ID>       Station ID for ETA forecasts");
761     F("-mrf-station   <ID>       Station ID for MRF forecasts");
762     F("-warning-zone  <zoneID>   Zone ID for weather warnings");
763     F("-*-uri         <URI>      URI for the weather data (see docs for details)");
764     F("-*-post        <DATA>     Post data for the weather data (see docs)");
765     F("  '*' can be metar, avn, eta, mrf, warning");
766     F("-noradar                  Do not display a radar image.");
767     F("-radar-uri     <URI>      URI for radar image");
768     F("-radar-post    <DATA>     Post data for radar image");
769     F("-radar-crop    <string>   How to crop the radar image. XxY+W+H format.");
770     F("-radar-cross   <string>   Where to draw radar crosshairs. XxY format.");
771     F("");
772     F("-m                        Alias for -metric");
773     F("-metric                   Same as -cm -hPa -kph -tempc");
774     F("");
775     F("-in                       Display precipitation amounts in inches");
776     F("-cm                       Display precipitation amounts in centimeters");
777     F("");
778     F("-inHg                     Display pressure in inHg");
779     F("-hPa                      Display pressure in hPa (millibars)");
780     F("-mbar                     Alias for -hPa");
781     F("-mmHg                     Display pressure in mmHg");
782     F("-atm                      Display pressure in atmospheres");
783     F("");
784     F("-mph                      Display windspeed in miles/hour");
785     F("-kph                      Display windspeed in kilometers/hour");
786     F("-knots                    Display windspeed in knots");
787     F("-mps                      Display windspeed in meters/second");
788     F("-beaufort                 Display windspeed on the Beaufort scale");
789     F("");
790     F("-tempf                    Display temperature in degrees Fahrenheit");
791     F("-tempc                    Display temperature in degrees Celcius");
792 
793     exit(i);
794 }
795 
printversion(void)796 void printversion(void) {
797     fprintf(stderr, "%s\n", VERSION);
798 }
799 
get_filename(char * file)800 char *get_filename(char *file){
801     char *f, *c;
802 
803     c=getenv("HOME");
804     if((f=malloc(strlen(c)+strlen(file)+14))==NULL) die("get_filename");
805     strcpy(f, c);
806     strcat(f, "/.wmweather+/");
807     strcat(f, file);
808     return f;
809 }
810 
get_pid_filename(char * file)811 char *get_pid_filename(char *file){
812     char *f, *c;
813     static unsigned short seq=0;
814     char buf[15];
815 
816     snprintf(buf, sizeof(buf), "%08X.%04X-", getpid(), seq++);
817     c=getenv("HOME");
818     if((f=malloc(strlen(c)+strlen(file)+14+14))==NULL) die("get_pid_filename");
819     strcpy(f, c);
820     strcat(f, "/.wmweather+/");
821     strcat(f, buf);
822     strcat(f, file);
823     return f;
824 }
825