/******************************************************************
 *
 *
 * Copyright (C) 2005 Jim Chandler <jim@n0vh.org>
 * Portions Copyright (C) 2000-2019 The Xastir Group
 *
 * Portions copied from Bruce Bennett's excellent Davis WX work
 *
 * (see the files README and COPYING for more details)
 *
 * This file implements all of the database to APRS daemon.
 *
 *

        LaCrosse/Data Base Weather --> APRS Weather

        Intended use:

        Create & provide APRS style packet string
        without position information from MySQL database
        weather information stored there by open2300
        (See http://open2300.sourceforge.net/ for source) to
        xastir-1.2.1 (See http://www.xastir.org for source)

        Note:  Open2300 is a weather data accumulator
        aimed at LaCrosse weather stations, which stores weather
        data in a mysql database.

        Output is to the ip hostname:port required in the
        command line.

    ACKNOWLEGEMENTS:

        Elements of this software are taken from wx200d ver 1.2
        by Tim Witham <twitham@quiknet.com>, and it is modeled
        after that application and from db2APRS by
        Bruce Bennett <bruts@adelphia.net>.

*******************************************************************/
#include <config.h>
#include <defs.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#include <syslog.h>
#include <errno.h>
#include <getopt.h>
#include <mysql.h>

#define MAXARGS 20      /* maximum CGI args to parse */
#define TMPLEN 128      /* max length of CGI */
#define BUFLEN 32       /* max length of hostname:port */

#define VALID_WINDDIR   0x01
#define VALID_WINDSPD   0x02
#define VALID_WINDGST   0x04
#define VALID_TEMP      0x08
#define VALID_RAIN1HR   0x10
#define VALID_RAIN24H   0x20
#define VALID_HUMIDITY  0x40
#define VALID_AIRPRESS  0x80
#define VALID_RAINTOT   0x100

#define MTPS2MPH        2.2369
#define DEGC2DEGF       1.8
#define MM2IN100TH      3.937
#define INHG2HPA10TH    338.638

#define OUTDOOR_SENSOR  1

//---From the static table "mfield", which really should be dynamically read here---
//    (but then I couldn't use a switch statement)

#define TEMPERATURE         0
#define TEMPERATURE_MIN     1
#define TEMPERATURE_MAX     2
#define HUMIDITY            10
#define HUMIDITY_MIN        11
#define HUMIDITY_MAX        12
#define WETNESS             20
#define WETNESS_MIN         21
#define WETNESS_MAX         22
#define AIR_PRESSURE        30
#define AIR_PRESSURE_MIN    31
#define AIR_PRESSURE_MAX    32
#define SOLAR               40
#define UV                  41
#define RAIN                50
// note: "51" is really rain total
#define RAIN_PER_DAY        51
#define RAIN_PER_HOUR       52
#define WIND_SPEED          60
#define WIND_DIRECTION      61
#define WIND_GUST           62
#define WIND_X              63
#define WIND_Y              64
#define MOISTURE            70
#define WATERLEVEL          71
#define WATERLEVEL_MIN      72
#define WATERLEVEL_MAX      73
#define BATTERY             110
#define TRANSMITTER         111
#define DURATION            120
#define SAMPLES             121

struct dbinfo
{
  char user[30];
  char pswrd[15];
  char name[30];
} db;

char *progname;
char *query;
int *current = 0;

int opt;

MYSQL       mysql;    // Yeah, globals...
MYSQL_RES   *result;
MYSQL_ROW   row;

char last_timestamp[20];

int debug_level;

char wxAPRShost[BUFLEN];
int wxAPRSport = PORT;
int outdoor_instr = OUTDOOR_SENSOR;





/******************************************************************
1/4/2003
            Usage brief

*******************************************************************/
void usage(int ret)
{
  if (query)
  {
    printf("Content-type: text/plain\nStatus: 200\n\n");
  }
  printf("usage: %s [options] \n",progname);
  printf("VERSION: %s\n",VERSION);
  printf("  -h    --help                      show this help and exit\n");
  printf("  -v    --verbose                   debugging info --> stderr\n");
  printf("  -c    --cport [port#]             IP port for data output\n");
  printf("  -u    --user [database user]      username for mysql - default meteo\n");
  printf("  -p    --password [db passwd]      password for mysql - default none\n");
  printf("  -b    --database [database]       database name - default meteo\n");
  printf("  -n    --nodaemon                  do not run as daemon\n");
  printf("  -r    --repeat                    keep running\n");
  printf("options may be uniquely abbreviated; units are as defined in APRS\n");
  printf("Specification 1.0.1 for positionless weather data (English/hPa).\n");
  exit(ret);
}





/******************************************************************
1/2/2003
            Make an APRS string out of WX data

*******************************************************************/

int APRS_str(char *APRS_buf,
             double winddir,
             double windspeed,
             double windgust,
             double temp,
             double rain1hr,
             double rain24h,
             double raintot,
             double humidity,
             double airpressure,
             unsigned int valid_data_flgs,
             int Metric_Data)
{

  int intval;
  char pbuf[10];

  if (APRS_buf == NULL)
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"err: Null string buffer for APRS string.\n");
    }
    return 0;  //  Ooo!!  *****Nasty Bad Exit Point Here****

  }
  if (valid_data_flgs & VALID_WINDDIR)
  {
    intval = (winddir + 0.5); // rounding to whole degrees
    if (intval > 360)
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Wind direction > 360\n");
      }
      sprintf(APRS_buf, "c...");
    }
    else if (intval < 0)
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Wind direction negative\n");
      }
      sprintf(APRS_buf, "c...");

    }
    else
    {
      sprintf(APRS_buf, "c%0.3d", intval);
    }
  }
  else
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"info: Wind direction flagged as invalid\n");
    }
    sprintf(APRS_buf, "c...");

  }

  if (valid_data_flgs & VALID_WINDSPD)
  {
    if (Metric_Data)
    {
      intval = (windspeed*MTPS2MPH + 0.5); // converting & rounding to whole MPH
    }
    else
    {
      intval = (windspeed + 0.5); // rounding to whole MPH
    }
    if (intval > 600) // Let's be reasonable here - center of a tornado??
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Wind speed > 600 MPH\n");
      }
      sprintf(pbuf, "s...");

    }
    else if (intval < 0)
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Wind speed negative\n");
      }
      sprintf(pbuf, "s...");

    }
    else
    {
      sprintf(pbuf, "s%0.3d", intval);
    }
  }
  else
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"info: Wind speed flagged as invalid\n");
    }
    sprintf(pbuf, "s...");

  }
  strcat(APRS_buf,pbuf);

  if (valid_data_flgs & VALID_WINDGST)
  {
    if (Metric_Data)
    {
      intval = (windgust*MTPS2MPH + 0.5); // converting & rounding to whole MPH
    }
    else
    {
      intval = (windgust + 0.5); // rounding to whole MPH
    }
    if (intval > 600)  // Let's be reasonable here - center of a tornado??
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Wind gust > 600 MPH\n");
      }
      sprintf(pbuf, "g...");

    }
    else if (intval < 0)
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Wind speed negative\n");
      }
      sprintf(pbuf, "g...");

    }
    else
    {
      sprintf(pbuf, "g%0.3d", intval);
    }

  }
  else
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"info: Wind gust flagged as invalid\n");
    }
    sprintf(pbuf, "g...");

  }
  strcat(APRS_buf,pbuf);

  if (valid_data_flgs & VALID_TEMP)
  {
    if (Metric_Data)
    {
      intval = ((temp)*DEGC2DEGF + 0.5)+32; // converting & rounding to whole Deg F
    }
    else
    {
      intval = (temp + 0.5); // rounding to whole Deg F
    }
    if (intval > 200)  // Let's be reasonable here - boiling?
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Temperature > 200 Deg F\n");
      }
      sprintf(pbuf, "t...");

    }
    else if (intval < -99)
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Temperature < -99 Deg F\n");
      }
      sprintf(pbuf, "t...");

    }
    else
    {
      if (intval < 0)
      {
        sprintf(pbuf,"t%0.2d",intval);
      }
      else
      {
        sprintf(pbuf, "t%0.3d", intval);
      }
    }

  }
  else
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"info: Temperature flagged as invalid\n");
    }
    sprintf(pbuf, "t...");

  }
  strcat(APRS_buf,pbuf);

  if (valid_data_flgs & VALID_RAIN1HR)
  {
    if (Metric_Data)
    {
      intval = ((rain1hr)*MM2IN100TH + 0.5); // converting & rounding to whole 1/100 inch
    }
    else
    {
      intval = (rain1hr*100.0 + 0.5); // rounding to whole 1/100 inch
    }
    if (intval > 999)  // 10 in/hr? Garden Hose -> rain gauge?
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Rainfall/Hr > 9.99 inch\n");
      }
      sprintf(pbuf, "\0\0\0\0");

    }
    else if (intval < -99)
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Rainfall/Hr negative\n");
      }
      sprintf(pbuf, "\0\0\0\0");

    }
    else
    {
      sprintf(pbuf, "r%0.3d", intval);
    }
  }
  else
  {

    if (debug_level & 1)
    {
      fprintf(stderr,"info: Rainfall/Hr flagged as invalid\n");
    }
    sprintf(pbuf, "\0\0\0\0");

  }
  strcat(APRS_buf,pbuf);

  if (valid_data_flgs & VALID_RAIN24H)
  {
    if (Metric_Data)
    {
      intval = ((rain24h)*MM2IN100TH + 0.5); // converting & rounding to whole 1/100 inch
    }
    else
    {
      intval = (rain24h*100.0 + 0.5); // rounding to whole 1/100 inch
    }
    if (intval > 999)  // Can't handle greater than 9.99 inches of rain in 24 hours
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Rainfall/24Hr > 9.99 inch - reporting 9.99 inches\n");
      }
      sprintf(pbuf, "p999");

    }
    else if (intval < -99)
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Rainfall/Hr negative\n");
      }
      sprintf(pbuf, "\0\0\0\0");

    }
    else
    {
      sprintf(pbuf, "p%0.3d", intval);
    }
  }
  else
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"info: Rainfall/24Hr flagged as invalid\n");
    }
    sprintf(pbuf, "\0\0\0\0");

  }
  strcat(APRS_buf,pbuf);


  if (valid_data_flgs & VALID_HUMIDITY)
  {
    intval = (humidity + 0.5); // rounding to whole percent
    if (intval > 100)  // Unlike the space shuttle engines, 100 % is max
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Humidity reported > 100%\n");
      }
      sprintf(pbuf, "\0\0\0\0");

    }
    else if (intval < 1)
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Humidity reported < 1%\n");
      }
      sprintf(pbuf, "\0\0\0\0");

    }
    else
    {
      if (intval == 100)  // Report 100% as 'h00'
      {
        intval = 0;
      }
      sprintf(pbuf, "h%0.2d", intval);
    }
  }
  else
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"info: Humidity flagged as invalid\n");
    }
    sprintf(pbuf, "\0\0\0\0");

  }
  strcat(APRS_buf,pbuf);

  if (valid_data_flgs & VALID_AIRPRESS)
  {
    if (Metric_Data)
    {
      intval = (airpressure*10.0 + 0.5); //  rounding to whole tenth of a hPa
    }
    else
    {
      intval = (airpressure*INHG2HPA10TH + 0.5); // convering In-Hg to 1/10 hPa and rounding
    }
    if (intval > 20000)  //two atmospheres - about 29 PSIA
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Air Pressure reported > 2 Atmospheres%\n");
      }
      sprintf(pbuf, "\0\0\0\0");

    }
    else if (intval < 0)
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: Air Pressure reported negative%\n");
      }
      sprintf(pbuf, "\0\0\0\0");

    }
    else
    {
      sprintf(pbuf, "b%0.5d", intval);
    }
  }
  else
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"info: Air Pressure flagged as invalid\n");
    }
    sprintf(pbuf, "\0\0\0\0");

  }
  strcat(APRS_buf,pbuf);

  // NOW THIS MAKES THE STRING NO LONGER A VALID APRS WX REPORT, but
  // we don't care:  Xastir does NOT just transmit this string, it parses it
  // and re-recreates the correct string to transmit.  We do this because
  // APRS doesn't have a "total rain" string in its weather report, but
  // Xastir likes to have that value around.
  if (valid_data_flgs & VALID_RAINTOT)
  {
    if (Metric_Data)
    {
      intval = ((raintot)*MM2IN100TH + 0.5); // converting & rounding to whole 1/100 inch
    }
    else
    {
      intval = (raintot*100.0 + 0.5); // rounding to whole 1/100 inch
    }

    // Can't handle greater than 99.99 inches of total rain
    if (intval > 9999)
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: total Rainfall  > 99.99 inch - reporting 9.99 inches\n");
      }
      sprintf(pbuf, "T9999");

    }
    else if (intval < -99)
    {
      if (debug_level & 1)
      {
        fprintf(stderr,"err: total Rainfall negative\n");
      }
      sprintf(pbuf, "\0\0\0\0\0");

    }
    else
    {
      sprintf(pbuf, "T%0.4d", intval);
    }
  }
  else
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"info: total Rainfall flagged as invalid\n");
    }
    sprintf(pbuf, "\0\0\0\0\0");

  }
  strcat(APRS_buf,pbuf);

  strcat(APRS_buf,"xDvs\n");  // add X aprs and LaCrosse WX station ID's and <lf>

  if (debug_level & 1)
  {
    fprintf(stderr,"\ninfo: APRS Version of WX - %s\n\n",APRS_buf);
  }
  return strlen(APRS_buf);
}





/******************************************************************
1/2/2003
            Get the latest set of Weather Data from the Data Base

*******************************************************************/

int Get_Latest_WX( double *winddir,
                   double *windspeed,
                   double *windgust,
                   double *temp,
                   double *rain1hr,
                   double *rain24h,
                   double *raintot,
                   double *humidity,
                   double *airpressure,
                   unsigned int *valid_data_flgs,
                   int *Metric_Data)

{

  char query_buffer[160];
  int nrows, item_count;
  int nfields;


  // Find latest, see if it's new to us
  // --new to us is a simple timestamp follower, so upon startup
  // it will always read one set of data, assuming any exists

  if (mysql_query(&mysql, "SELECT MAX(timestamp) from weather"))
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"err: Latest timestamp query failed - exiting: %s\n", mysql_error(&mysql));
    }
    return 0;
  }

  if (!(result = mysql_store_result(&mysql)))
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"err: Latest timestamp query failed - exiting: %s\n", mysql_error(&mysql));
    }
    return 0;
  }

  if (mysql_num_rows(result) != 1 )
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"err: Latest timestamp query failed - exiting: number of results %d\n",
              mysql_num_rows(result));
    }
    // release query buffer
    mysql_free_result(result);
    return 0;
  }

  row = mysql_fetch_row(result);

  if ( row[0] == NULL )
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"err: NULL result for timestamp query\n");
    }
    // release query buffer
    mysql_free_result(result);
    return 0;
  }
  // if no new data. exit with negative status

  if (!strncmp(last_timestamp, row[0], 14))
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"info: No new weather data recorded - exiting: negative data\n");
    }
    // release query buffer
    mysql_free_result(result);
    return -1;
  }
  strcpy(last_timestamp, row[0]);   // For next pass & following query

  if ( debug_level & 1)
  {
    fprintf(stdout,"Timestamp: %s\n",last_timestamp);
  }

  // release query buffer
  mysql_free_result(result);

  sprintf(query_buffer,"SELECT wind_angle, windspeed, temp_out, rain_1h, rain_24h, rel_hum_out, rel_pressure, rain_total FROM weather WHERE timestamp = %s", last_timestamp);

  if (mysql_query(&mysql, query_buffer))
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"err: Latest Weather Data query failed - exiting: %s\n\t --Query: %s\n",
              mysql_error(&mysql), query_buffer);
    }
    return 0;
  }

  if (!(result = mysql_store_result(&mysql)))
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"err: Latest Weather Data query failed - exiting: %s\n", mysql_error(&mysql));
    }
    return 0;
  }
  if ((nrows=mysql_num_rows(result)) < 1 )
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"err: Latest Weather Data query failed - exiting: number of results %d\n",nrows);
    }
    // release query buffer
    mysql_free_result(result);
    return 0;
  }
  else
  {
    nfields=mysql_num_fields(result);
    row=mysql_fetch_row(result);
    if (debug_level & 1)
    {
      fprintf(stderr,"info: Latest Weather Data query: number of types of readings %d\n",nfields);
    }
  }

  *valid_data_flgs = 0;
  item_count = 0;

  //WIND_DIRECTION :
  *winddir = strtod(row[0],NULL);
  *valid_data_flgs |= VALID_WINDDIR;
  item_count++;
  if (debug_level & 1)
  {
    fprintf(stderr,"wind direction %f\n ",*winddir);
  }

  //case WIND_SPEED :
  *windspeed = strtod(row[1],NULL);
  *windspeed = *windspeed * 1.15077945; // Convert from knots to mph
  *valid_data_flgs |= VALID_WINDSPD;
  item_count++;
  if (debug_level & 1)
  {
    fprintf(stderr,"wind speed %f\n ",*windspeed);
  }

  //case WIND_GUST :
  *windgust = strtod("0",NULL);
  //*valid_data_flgs |= VALID_WINDGST;  No gust information from open2300
  item_count++;
  if (debug_level & 1)
  {
    fprintf(stderr,"wind gust speed %f\n ",*windgust);
  }

  //case TEMPERATURE :
  *temp = strtod(row[2],NULL);
  *valid_data_flgs |= VALID_TEMP;
  item_count++;
  if (debug_level & 1)
  {
    fprintf(stderr,"temperature %f\n ",*temp);
  }

  //case RAIN_PER_HOUR :
  *rain1hr = strtod(row[3],NULL);
  *valid_data_flgs |= VALID_RAIN1HR;
  item_count++;
  if (debug_level & 1)
  {
    fprintf(stderr,"rainfall for 1 hr %f\n ",*rain1hr);
  }

  //case RAIN_PER_DAY :
  *rain24h = strtod(row[4],NULL);
  *valid_data_flgs |= VALID_RAIN24H;
  item_count++;
  if (debug_level & 1)
  {
    fprintf(stderr,"rainfall for 24 hrs %f\n ",*rain24h);
  }

  //case HUMIDITY :
  *humidity = strtod(row[5],NULL);
  *valid_data_flgs |= VALID_HUMIDITY;
  item_count++;
  if (debug_level & 1)
  {
    fprintf(stderr,"humidity %f\n ",*humidity);
  }

  //case AIR_PRESSURE :
  *airpressure = strtod(row[6],NULL);
  *valid_data_flgs |= VALID_AIRPRESS;
  item_count++;
  if (debug_level & 1)
  {
    fprintf(stderr,"air pressure %f\n ",*airpressure);
  }

  //case  RAIN_TOTAL
  *raintot = strtod(row[7],NULL);
  *valid_data_flgs |= VALID_RAINTOT;
  item_count++;
  if (debug_level & 1)
  {
    fprintf(stderr,"rainfall since reset %f\n ",*raintot);
  }

  *Metric_Data = 0;  // My station reports F, knots and inHG
  // release query buffer & close connection
  mysql_free_result(result);

  if (debug_level & 1)
  {
    fprintf(stderr,"info: success - Weather Data number of reading types %d\n",
            item_count);
  }

  return item_count;
}





/******************************************************************
1/5/2003
            SIGPIPE signal handler

*******************************************************************/
void pipe_handler(int sig)  /*  */
{
  signal(SIGPIPE, SIG_IGN);
  if (sig == SIGPIPE)   // client went bye-bye
  {
    shutdown(*current, 2);
    close(*current);
    *current = -1;
    if (debug_level & 1)
    {
      fprintf(stderr, "info: %s - TCP client timed out", progname);
    }
  }
}





/******************************************************************
1/5/2003
            SIGTERM signal handler

*******************************************************************/
void term_handler( int UNUSED(sig) )  /*  */
{
  if (debug_level & 1)
  {
    fprintf(stderr, "info: %s - ordered to DIE, complying", progname);
  }

  // release query buffer & close connection
  mysql_free_result(result);

  mysql_close(&mysql);

  exit( 0 );
}





/******************************************************************
1/2/2003
        Coordinating MAIN point

*******************************************************************/
int main(int argc, char **argv)
{
  const char *flags = "Hhvnc:u:p:d:s:r";
  char WX_APRS[120];
  int data_len = 0 ;
  double winddir;
  double windspeed;
  double windgust;
  double temp;
  double rain1hr;
  double rain24h;
  double raintot;
  double humidity;
  double airpressure;
  unsigned int valid_data_flgs;
  int Metric_Data = 0, dsts = 0;
  int  pid, s;
  socklen_t clen = sizeof(struct sockaddr_in);
  int fd[CONNECTIONS];
  int *max = 0,  dly_cnt = 1;
  int not_a_daemon = 0, repetitive = 0, tcp_wx_port = PORT;
  int  i, index = 0;
  struct sockaddr_in server, client;
  struct in_addr bind_address;
  fd_set rfds;
  struct timeval tv;

  struct option longopt[] =
  {
    {"help", 0, 0, 'h'},
    {"refresh", 0, 0, 'r'},
    {"verbose", 0, 0, 'v'},
    {"user", 1, 0, 'u'},
    {"password", 1, 0, 'p'},
    {"database", 1, 0, 'd'},
    {"cport", 1, 0, 'c'},
    {"nodaemon", 0, 0, 'n'},
    {0, 0, 0, 0}
  };

  debug_level = 0;

  strcpy(db.user,"open2300"); // set default values for database access
  strcpy(db.name,"open2300");
  memset(db.pswrd,0,15);

  mysql_init(&mysql);


  progname = strrchr(argv[0], '/');
  if (progname == NULL)
  {
    progname = argv[0];
  }
  else
  {
    progname++;
  }

  while ((opt = getopt_long(argc, argv, flags, longopt, &index)) != EOF)
  {
    switch (opt)  /* parse command-line or CGI options */
    {
      case 'r':
        repetitive = 1;
        break;
      case 'v':
        fprintf(stdout,"Verbose mode set:\n");
        debug_level = 1;
        break;
      case 'u': // mysql username
        strncpy(db.user,(char *)optarg,30);
        break;
      case 'p': // mysql password
        strncpy(db.pswrd,(char *)optarg,15);
        break;
      case 'd': // mysql database name
        strncpy(db.name,(char *)optarg,30);
        break;
      case 'n': /* do not fork and become a daemon */
        not_a_daemon = 1;
        break;
      case 'c': /* port to use */
        tcp_wx_port = strtol(optarg, NULL, 0);
        break;

      case '?':
      case 'h':
      case 'H':
        usage(0);
        break;
      default :
        usage(1);
    }
  }
  if (debug_level & 1)
  {
    fprintf(stdout,"Starting...");
    if (repetitive)
    {
      fprintf(stdout, " forever ");
    }
    else
    {
      fprintf(stdout, " one pass only ");
    }
    fprintf(stdout," with  database user=%s, password=%s, for database=%s\n",
            db.user, db.pswrd, db.name);
    if (not_a_daemon)
    {
      fprintf(stdout," as a program ");
    }
    else
    {
      fprintf(stdout," as a daemon ");
    }
    fprintf(stdout, " using TCP port %d\n",tcp_wx_port);
  }

  // Data base connection


  if (!(mysql_real_connect(&mysql, "localhost", db.user, db.pswrd, db.name, 0, NULL, 0)))
  {
    if (debug_level & 1)
    {
      fprintf(stderr,"err: Data Base connect for user:%s to database:%s failed - exiting: \n\t%s\n",
              db.user, db.name, mysql_error(&mysql));
    }
    exit(9);
  }

  server.sin_family = AF_INET;
  bind_address.s_addr = htonl(INADDR_ANY);
  server.sin_addr = bind_address;
  server.sin_port = htons(tcp_wx_port);

  if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
  {
    if (debug_level & 1)
    {
      fprintf(stderr, "err: %s - no socket", progname);
    }
    exit(10);
  }
  /* <dirkx@covalent.net> / April 2001 Minor change to allow quick
   * (re)start of deamon or client while there are pending
   * conncections during the quit. To avoid addresss/port in use
   * error.  */
  i = 1;
  if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) == -1)
  {
    if (debug_level & 1)
    {
      fprintf(stderr, "err: %s - setsockopt", progname);
    }
  }
  if (bind(s, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1)
  {
    if (debug_level & 1)
    {
      fprintf(stderr, "err: %s - cannot bind to socket", progname);
    }
    exit(11);
  }
  if (listen(s, CONNECTIONS) == -1)
  {
    if (debug_level & 1)
    {
      fprintf(stderr, "err: %s - listen", progname);
    }
    exit(12);
  }

  if (debug_level & 1)
  {
    fprintf(stdout,"Sockets UP.\n");
  }

  umask(0022);
  for (i = 0; i < CONNECTIONS; i++)
  {
    fd[i] = -1;
  }
  tv.tv_sec = 0;
  tv.tv_usec = 0;

  if (!not_a_daemon)  /* setup has worked; now become a daemon? */
  {

    if ((pid = fork()) == -1)
    {
      syslog(LOG_ERR, "can't fork() to become daemon: %m");
      exit(20);
    }
    else if (pid)
    {
      exit (0);
    }

    setsid();
    for (i = 0; i < NOFILE; i++)
    {
      if ( i != s)
      {
        close(i);
      }
    }
  }

  /* catch signals to close the database connection */
  signal( SIGTERM, term_handler );/* termination */
#if defined(SIGPWR) /* SIGPWR is linux centric */
  signal( SIGPWR, term_handler ); /* power failure */
#endif

  if (debug_level & 1)
  {
    fprintf(stdout,"Main Loop...\n");
  }
  dly_cnt = 1;  //N0VH, change back to 1
  do
  {
    if (!(dly_cnt--))
    {
      dly_cnt = 25; // Every 'dly_cnt' passes check for WX data update
      if ((dsts = Get_Latest_WX(&winddir,&windspeed,&windgust,
                                &temp,&rain1hr,&rain24h,&raintot,
                                &humidity,&airpressure,
                                &valid_data_flgs,&Metric_Data)) !=0 )
      {
        if ( dsts > 0 )
        {
          data_len = APRS_str(WX_APRS, winddir,windspeed,windgust,
                              temp, rain1hr, rain24h, raintot,
                              humidity, airpressure,
                              valid_data_flgs, Metric_Data);

          if (!data_len)
          {
            if (debug_level & 1)
            {
              fprintf(stderr, "err: WX info formatting problem!");
            }
            exit(13);
          }
        }
      }
      else
      {
        exit(dsts);
      }
    }
    FD_ZERO(&rfds);
    FD_SET(s, &rfds);
    if (select(s + 1, &rfds, NULL, NULL, &tv) > 0)
    {
      for (current = fd; (*current > 0) && (current < fd + CONNECTIONS - 1); current++);
      if (current > max)
      {
        max = current;
      }
      if ((*current = accept(s, (struct sockaddr *)&client, &clen)) != -1)
      {
        write(*current, WX_APRS, data_len);
      }
    }
    if (dly_cnt == 25)
    {
      if (debug_level & 1)
      {
        fprintf(stdout,"Updating clients:");
      }
      for (current = fd; current <=max; current++)
      {
        if (*current > 0)    // active socket
        {
          if (debug_level & 1)
          {
            fprintf(stdout," #");
          }
          signal(SIGPIPE, pipe_handler);
          write(*current, WX_APRS, data_len);
        }
        if (debug_level & 1)
        {
          fprintf(stdout," done\n");
        }
      }
    }
    sleep(1);  //
  }
  while (repetitive);

  mysql_close(&mysql);

  if (debug_level & 1)
  {
    fprintf(stdout,"Exiting normally.\n");
  }
  exit(0);
}


