/* ========================================================================== */
/*! \file
 * \brief Server protocol logging
 *
 * Copyright (c) 2012-2020 by the developers. See the LICENSE file for details.
 * If nothing else is specified, functions return zero to indicate success
 * and a negative value to indicate an error.
 */


/* ========================================================================== */
/* Include headers */

#include "posix.h"  /* Include this first because of feature test macros */

#include <stdio.h>
#include <string.h>

#include "config.h"
#include "fileutils.h"
#include "log.h"
#include "main.h"
#include "xdg.h"


/* ========================================================================== */
/*! \defgroup LOGGING LOG: Logging of NNTP communication
 *
 * Location of protocol logfile: \c $XDG_CONFIG_HOME/$CFG_NAME/logfile
 */
/*! @{ */


/* ========================================================================== */
/* Constants */

/*! \brief Message prefix for LOG module */
#define MAIN_ERR_PREFIX  "LOG: "

/*! \brief Permissions for server protocol logfile */
#define LOG_PERM  (posix_mode_t) (POSIX_S_IRUSR | POSIX_S_IWUSR)


/* ========================================================================== */
/*! \brief Get logfile pathname
 *
 * This function must be thread safe.
 * The caller is responsible to free the memory for the buffer on success.
 *
 * \return
 * - Pointer to logfile pathname on success
 * - \c NULL on error
 */

const char*  log_get_logpathname(void)
{
   static const char  logname[] = "logfile";
   const char*  res = NULL;
   int  rv;

   /* This requires the UI mutex */
   res = xdg_get_confdir(CFG_NAME);
   if(NULL != res)
   {
      rv = fu_create_path(res, (posix_mode_t) POSIX_S_IRWXU);
      if(0 == rv)
      {
         /* Store scorefile pathname */
         rv = xdg_append_to_path(&res, logname);
         if(0 != rv)
         {
            posix_free((void*) res);
            res = NULL;
         }
      }
   }

   return(res);
}


/* ========================================================================== */
/*! \brief Delete logfile if present */

void  log_delete_logfile(void)
{
   const char*  lfpn = log_get_logpathname();

   if(NULL != lfpn)
   {
      (void) fu_unlink_file(lfpn);
      posix_free((void*) lfpn);
   }
}


/* ========================================================================== */
/*! \brief Open logfile
 *
 * \param[out] lfs      Pointer to logfile stream
 * \param[in]  logfile  Pathname of logfile to open
 *
 * A valid stream pointer was written to \e lfs before success is returned.
 * Otherwise the location pointed to by \e lfs is not changed.
 *
 * \note
 * If \e logfile is \c NULL , the file \c /dev/null is used instead.
 *
 * \return
 * - Zero on success
 * - -1 on error
 */

int  log_open_logfile(FILE**  lfs, const char*  logfile)
{
   static const char*  null = "/dev/null";
   int  res = 0;
   int  fd = -1;
   FILE*  fs = NULL;

   if(NULL == logfile)  { logfile = null; }

   /* Open logfile */
   res = fu_open_file(logfile, &fd,
                      POSIX_O_WRONLY | POSIX_O_CREAT | POSIX_O_TRUNC, LOG_PERM);
   if(res)
   {
      PRINT_ERROR("Opening logfile failed");
      res = -1;
   }
   else
   {
      /* Assign stream to logfile */
      res = fu_assign_stream(fd, &fs, "wb");
      if(res)
      {
         PRINT_ERROR("Cannot assign stream to logfile");
         fu_close_file(&fd, NULL);
         res = -1;
      }
      else
      {
         /* Success => Write stream pointer to 'lfs' */
         *lfs = fs;
      }
   }

   return(res);
}


/* ========================================================================== */
/*! \brief Close logfile
 *
 * \param[in] lfs   Pointer to logfile stream
 */

void  log_close_logfile(FILE**  lfs)
{
   fu_close_file(NULL, lfs);

   return;
}


/* ========================================================================== */
/*! \brief Add data to end of logfile
 *
 * \param[in] lfs   Logfile stream
 * \param[in] data  Data string that should be added to logfile
 *
 * This function never fail, write errors are ignored.
 */

void  log_add(FILE*  lfs, const char*  data)
{
   size_t  i = 0;

   while(data[i])
   {
      /* Delete CR characters */
      if((char) 0x0D != data[i])  { fputc((int) data[i], lfs); }
      ++i;
   }
   fflush(lfs);
}


/* ========================================================================== */
/*! \brief Free an object allocated by logging module
 *
 * Use this function to release dynamic memory that was allocated by the
 * logging module.
 *
 * \param[in] p  Pointer to object
 *
 * Release the memory for the object pointed to by \e p.
 */

void  log_free(void*  p)
{
   posix_free(p);
}


/*! @} */

/* EOF */
