## root/source/datimec.c

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following definitions.

1. main
2. parse_comline
3. c_initialize
4. get_server_time
5. get_current_time
6. cset_time
7. app_out
8. term_app

    /* datimec - A client application which uses TCP sockets or QNX
       message passing to obtain the current date/time from a
       'timesync' server and adjust the local machine date/time if
       necessary. Rick Smereka, Copyright (C) 2001-2006.

       This program is free software; you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published by
       the Free Software Foundation; either version 2 of the License, or
       (at your option) any later version.

       This program is distributed in the hope that it will be useful,
       but WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       GNU General Public License for more details.

       You should have received a copy of the GNU General Public License
       along with this program; if not, get a copy via the Internet at
       http://gnu.org/copyleft/gpl.html or write to the Free Software
       Foundation, Inc., 59 Temple Place, Suite 330, Boston,
       MA 02111-1307 USA

       You can contact the author via email at rsmereka@future-lab.com

       Original version for Linux. Program syntax:

          datimec [-n] [-q] [-l[ log_file]]

       Where the option 'n' will report but not set the date/time,
       the option 'q' will suppress all console message output (quiet)
       and the 'l' (el) option will output all messages to either the default
       log file or the supplied log file. Note that the option/switch
       character is based on the platform and may be not the hyphen.
       Ported to Windows 32bit. Dec/2001, Rick Smereka

       Changed conditional compilation directive in 'cset_time' that was
       used for Red Hat Linux to now be compiled for any Linux via the
       pre-processor define 'OS_UNIX_LINUX' defined in the script
       '.include.linux'. This was done after discovering that Debian
       Linux's 'date' command is identical to Red Hat's. I am assuming
       that any Linux will have the same 'date' command syntax.
       Oct/2002, Rick Smereka

       Ported to Debian Linux. Jan/2003, Rick Smereka

       Modified for the updated 'socloc' API ('sloc.c').
       May/2003, Rick Smereka

       Added function 'term_app'. Modified for the updated
       'timeysnc' API ('timesapi.c'). Jul/2003,
       Rick Smereka

       Modifed to use 'logman' API for logging calls.
       Mar/2004, Rick Smereka

       Re-compile after changing the 'socloc' API.
       Jan/2005, Rick Smereka

       Modified for FreeBSD. Oct/2005, Rick Smereka

       Re-compile after modifications to low level TCP socket communication
       module (ipcomm.c). Feb/2006, Rick Smereka */

    #include "stdhead.h"
    #include "flsocket.h"
    #include "timesync.h"
    #ifdef IPC_TCP
    #include "socloc.h"
    #include "sloc.h"
    #include "slconfig.h"
    #include "sliocode.h"
    #endif

    #define APPNAME "datimec"
    #define VERSION "1.08.01-2006.02.23"
    #define DEFAULT_LOG_FILE "datimec.log"
    #define DATIMEC_MAXMES 2048

    /* date/time structure storage */

    struct time_store
       {
       int year;
       int month;
       int day;
       int hour;
       int minute;
       int second;
       };

    /* global data */

    struct time_store server_time, current_time;
    char c_log_file[128];
    int console_output = TRUE;
    int log_output = FALSE;
    int should_set = TRUE;

    #ifdef OS_WIN32
    WSADATA wsaData;
    #endif

    /* function prototypes */

    int main(int, char **);
    int parse_comline(int, char **);
    int c_initialize(void);
    int get_server_time(void);
    void get_current_time(void);
    void cset_time(void);
    void app_out(char *,...);
    void term_app(void);

    int main(int argc, char **argv)
    {
       char mes[128], mname[] = "main";
       int ret, lstatus;

       /* parse command line */

       if (!parse_comline(argc, argv))
          return(0);

       if (!c_initialize())
          {
          term_app();
          return(0);
          }

       /* build logo string based on platform */

    #ifndef OS_UNIX
       /* non-Unix */

       app_out("%s for %s Version %s", APPNAME, PLATFORM_STRING,
               VERSION);
    #else
       /* Unix */

       app_out("%s for %s Version %s", APPNAME, SUB_PLATFORM_STRING,
               VERSION);
    #endif

       app_out("By Rick Smereka, Copyright (c) 2001-2006");
       app_out("%s comes with ABSOLUTELY NO WARRANTY", APPNAME);
       app_out("This is free software, and you are welcome to redistribute it");
       app_out("under certain conditions; see 'gpl.txt' for information.");

       if (!get_server_time())
          {
          term_app();
          return(0);
          }

       app_out("%s:%s:server time:yr=%d,mo=%d,dy=%d,hr=%d,mi=%d,se=%d",
              APPNAME, mname, server_time.year, server_time.month,
              server_time.day, server_time.hour, server_time.minute,
              server_time.second);
       get_current_time();
       app_out("%s:%s:current time=yr=%d,mo=%d,dy=%d,hr=%d,mi=%d,se=%d",
               APPNAME, mname, current_time.year, current_time.month,
               current_time.day, current_time.hour, current_time.minute,
               current_time.second);
       cset_time();
       app_out("%s:%s:program complete", APPNAME, mname);
       term_app();
       return(0);
    }

    int parse_comline(int c_count, char **c_parm)
    {
       /* Parse the command line for parameters. Function
          returns 'TRUE' if no error was detected, 'FALSE'
          otherwise. */

       char mname[] = "parse_comline";
       int parms = 1, done = FALSE;

       /* set default log file */

       strcpy(c_log_file, DEFAULT_LOG_FILE);

       if (c_count == 1)
          done = TRUE;

       while(!done)
          {
          if (c_parm[parms][0] == SWITCH_CHAR)
             {
             switch(toupper(c_parm[parms][1]))
                {
                case 'L':
                   if (strlen(c_parm[parms]) > 2)
                      printf("%s:%s:extraneous input with log switch, "
                             "ignoring\n", APPNAME, mname);

                   parms++;

                   if (c_count > parms)
                      {
                      strcpy(c_log_file, c_parm[parms]);
                      parms++;
                      }

                   log_output = TRUE;
                   break;

                case 'N':
                   should_set = FALSE;
                   parms++;
                   break;

                case 'Q':
                   console_output = FALSE;
                   parms++;
                   break;

                default:
                   printf("%s:%s:unknown switch[%s], program abort\n",
                          APPNAME, mname, c_parm[parms]);
                   return(FALSE);
                };
             }

          if (parms >= c_count)
             done = TRUE;
          }

       return(TRUE);
    }

    int c_initialize(void)
    {
       /* Initialize server communication, form connection to
          'socloc' server (TCP only), update the config list and connect
          to a 'timesync' server. Function returns 'TRUE' upon
          success, 'FALSE' otherwise. */

       char mname[] = "c_initialize";
       char *thelist, mes[128];
       int ret;

       /* startup WinSock (if Windoze) */

    #ifdef OS_WIN32
       if (WSAStartup(WINSOCK_VERSION, &wsaData))
          {
          printf("%s:%s:unable to start WinSock. "
                 "Program abort\n", APPNAME, mname);
          return(FALSE);
          }
    #endif

    #ifdef IPC_TCP
       /* attempt to connect to a 'socloc' server */

       if ((ret = sloc_initialize()) != SL_OK)
          {
          sl_code_string(ret, mes);
          printf("%s:%s:error initializing socloc interface,rc[%s]. "
                 "Program abort\n", APPNAME, mname, mes);
          return(FALSE);
          }

       /* get config list from 'socloc' server and update
          the client list with it */

       if ((thelist = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
          {
          printf("%s:%s:alloc fail[thelist]. Program abort\n",
                 APPNAME, mname);
          return(FALSE);
          }

       if ((ret = sloc_config_get_list(thelist)) != SL_OK)
          {
          free(thelist);
          sl_code_string(ret, mes);
          printf("%s:%s:error getting socloc config list,rc[%s]. "
                 "Program abort\n", APPNAME, mname, mes);
          return(FALSE);
          }

       if ((ret = sl_config_put_list(thelist)) != SL_OK)
          {
          sl_code_string(ret, mes);
          printf("%s:%s:error putting socloc config list,rc[%s]. ",
                 "Program abort\n", APPNAME, mname, mes);
          free(thelist);
          return(FALSE);
          }

       free(thelist);
    #endif

       /* start log if requested and make sure log file name is valid */

       if (log_output && logman_start(c_log_file, APPNAME))
          {
          printf("%s:%s:unable to start logging, "
                 "program abort\n", APPNAME, mname);
          return(FALSE);
          }

       /* set logger console output flag */

       if (log_output)
          logman_console(console_output);

       /* attempt to locate a 'timesync' server and connect to it */

       if ((ret = timesync_init()) != TS_OK)
          {
          ts_code_string(ret, mes);
          app_out("%s:%s:error connecting to the timesync server,rc[%s]. "
                  "Program abort", APPNAME, mname, mes);
          return(FALSE);
          }

       /* display current connected server host name and
          TCP port number */

    #ifdef IPC_TCP
       timesync_get_active(mes, &ret);
       app_out("%s:%s:connected to timesync server %s on TCP port %d "
               "(decimal)", APPNAME, mname, mes, ret);
    #endif

       return(TRUE);
    }

    int get_server_time(void)
    {
       /* Get the date/time string from the server and load the 'server_time',
          structure from it. Function returns 'TRUE' upon success, 'FALSE'
          otherwise. */

       char mname[] = "get_server_time", mes[128];
       int ret;

       logman("%s:%s:enter", APPNAME, mname);

       if ((ret = timesync_get_datime(&server_time.year, &server_time.month,
                                      &server_time.day, &server_time.hour,
                                      &server_time.minute, &server_time.second))
           != TS_OK)
          {
          ts_code_string(ret, mes);
          app_out("%s:%s:bad rc[%s] from timesync_get_datime",
                  APPNAME, mname, mes);
          return(FALSE);
          }

       logman("%s:%s:normal exit[TRUE]", APPNAME, mname);
       return(TRUE);
    }

    void get_current_time(void)
    {
       /* Get the current date/time from this computer clock. */

       time_t tod;
       struct tm *tmbuf;
       char mname[] = "get_current_time", buf[15];

       logman("%s:%s:enter", APPNAME, mname);
       tod = time(NULL);
       tmbuf = localtime(&tod);

       /* load current time structure */

       current_time.year = tmbuf->tm_year + 1900;
       current_time.month =  tmbuf->tm_mon + 1;
       current_time.day = tmbuf->tm_mday;
       current_time.hour = tmbuf->tm_hour;
       current_time.minute = tmbuf->tm_min;
       current_time.second = tmbuf->tm_sec;
       logman("%s:normal exit", mname);
    }

    void cset_time(void)
    {
       /* Compare the server time with the local machine time and
          adjust if necessary. */

       char mname[] = "cset_time", comm[50];
       int should_set_date = FALSE, should_set_time = FALSE;

       logman("%s:%s:enter", APPNAME, mname);

       if (server_time.year != current_time.year)
          should_set_date = TRUE;

       if (server_time.month != current_time.month)
          should_set_date = TRUE;

       if (server_time.day != current_time.day)
          should_set_date = TRUE;

       if (server_time.hour != current_time.hour)
          should_set_time = TRUE;

       if (server_time.minute != current_time.minute)
          should_set_time = TRUE;

       if (server_time.second != current_time.second)
          should_set_time = TRUE;

       /* set date/time based on platform if necessary */

    #ifdef OS_UNIX_LINUX
       /* Linux's 'date' command is not POSIX, format:

             mmddhhmmyyyy.ss */

       if (should_set && (should_set_date || should_set_time))
          {
          sprintf(comm, "date %02d%02d%02d%02d%d.%02d", server_time.month,
                  server_time.day, server_time.hour, server_time.minute,
                  server_time.year, server_time.second);
          (void)system(comm);
          }
    #endif

    #ifdef OS_UNIX_FREEBSD
       /* FreeBSD uses the POSIX 'date' command, format:

            yyyymmddhhmm.ss */

       if (should_set && (should_set_date || should_set_time))
          {
          sprintf(comm, "date %d%02d%02d%02d%02d.%02d", server_time.year,
                  server_time.month, server_time.day, server_time.hour,
                  server_time.minute, server_time.second);
          (void)system(comm);
          }
    #endif

    #ifdef OS_QNX_4X
       /* QNX 4.x uses the POSIX 'date' command, format:

            yyyymmddhhmmss */

       if (should_set && (should_set_date || should_set_time))
          {
          sprintf(comm, "date %d%02d%02d%02d%02d%02d", server_time.year,
                  server_time.month, server_time.day, server_time.hour,
                  server_time.minute, server_time.second);
          (void)system(comm);
          }
    #endif

    #ifdef OS_WIN32
       /* Windoze has two separate commands 'date' and 'time', date format:

            dd-mm-yyyy

          time format:

             hh:mm:ss */

       if (should_set && should_set_date)
          {
          sprintf(comm, "date %02d-%02d-%d", server_time.day, server_time.month,
                  server_time.year);
          (void)system(comm);
          }

       if (should_set && should_set_time)
          {
          sprintf(comm, "time %02d:%02d:%02d", server_time.hour,
                  server_time.minute, server_time.second);
          (void)system(comm);
          }
    #endif

       if (should_set)
          {
          if (should_set_date)
             app_out("%s:%s:date adjusted", APPNAME, mname);

          if (should_set_time)
             app_out("%s:%s:time adjusted", APPNAME, mname);
          }
       else
          {
          if (should_set_date)
             app_out("%s:%s:date should be adjusted", APPNAME, mname);

          if (should_set_time)
             app_out("%s:%s:time should be adjusted", APPNAME, mname);
          }

       if (!should_set_date && !should_set_time)
          app_out("%s:%s:no adjustment necessary", APPNAME, mname);

       logman("%s:%s:normal exit", APPNAME, mname);
    }

    void app_out(char *fmt,...)
    {
       /* Output a message to the console and/or the log file. */

       va_list argptr;
       char *mes, mname[] = "app_out";
       int ret;

       /* if no output, return */

       if (!console_output && !log_output)
          return;

       va_start(argptr, fmt);

       if ((mes = (char *)malloc(DATIMEC_MAXMES)) == (char *)NULL)
          {
          logman("%s:%s:alloc fail[mes]", APPNAME, mname);
          return;
          }

       /* format message */

       memset(mes, 0, DATIMEC_MAXMES);
       vsprintf(mes, fmt, argptr);

       if (log_output)
          logman_nf(mes);

       if (!log_output && console_output)
          printf("%s\n", mes);

       free(mes);
    }

    void term_app(void)
    {
       // Prepare to terminate the application. Shutdown all IPC API's.

       timesync_end();

       if (log_output)
          logman_end();

    #ifdef IPC_TCP
       // with TCP IPC method
       sloc_term_api();
    #ifdef OS_WIN32
       // under Windoze
       WSACleanup();
    #endif
    #endif
    }

/* [<][>][^][v][top][bottom][index][help] */