/* babel - News transport agent for STiK
 *
 * files.c - File handling routines
 *
 * (c)1996 Mark Baker. Distributable under the terms of the GNU
 *                     general public licence
 *
 * $Id: files.c,v 1.14 1996/10/01 18:30:34 mnb20 Exp $
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include "babel.h"

/* Search directories: . NEWSDIR1 and NEWSDIR2 */
#define NEWSDIR1 "news\\"
#define NEWSDIR2 "\\news\\"

/* Filenames */
#define ACTIVE "active"
#define TEMPACTIVE "active.tmp"

/* Environment variable to check */
#define ENV_NEWSDIR "NEWSDIR"

/* Maximum path length */
#define PATHLENGTH 64

/* Option imported from main.c */
extern char *opt_directory ;

/* File handles (exported) */
FILE *act_in ;
FILE *act_out ;

FILE *groups ;
FILE *newgroups ;
FILE *descriptions ;

/* Current path */
char path[PATHLENGTH] ;

/*
 * open_files() opens the active file, and a temporary file to
 *    write an updated active file to. It tries various places
 *    to find the file. Note that preprocessor concatenation is
 *    used in a few places.
 */

void open_files( void )
{
  char *env_newsdir ;
  char trypath1[PATHLENGTH], trypath2[PATHLENGTH] ;
  char filename[PATHLENGTH] ;

  /* Path to active file using -d option */
  sprintf( trypath1, "%s\\" ACTIVE, opt_directory ) ;

  /* Path to active file using NEWSDIR environment */
  env_newsdir = getenv( ENV_NEWSDIR ) ;
  if( env_newsdir )
    sprintf( trypath2, "%s\\" ACTIVE, env_newsdir ) ;

  /* Try different filenames, and remember which path works */
  /* --directory command line option */
  if( !access( trypath1, R_OK | W_OK ) )
    sprintf( path, "%s\\", opt_directory ) ;
  /* Environment variable */
  else if( env_newsdir && !access( trypath2, R_OK | W_OK ) )
    sprintf( path, "%s\\", env_newsdir ) ;
  /* current directory */
  else if( !access( ACTIVE, R_OK | W_OK ) )
    strcpy( path, ".\\" ) ;
  /* .\news */
  else if( !access( NEWSDIR1 ACTIVE, R_OK | W_OK ) )
    strcpy( path, NEWSDIR1 ) ;
  /* \news */
  else if( !access( NEWSDIR2 ACTIVE, R_OK | W_OK ) )
    strcpy( path, NEWSDIR2 ) ;
  else
    {
      /* Can't find active file anywhere - die */
      alert( strings.noactivefile ) ;
      exit(1) ;
    }

  /* Open active file */
  strcpy( filename, path ) ;
  strcat( filename, ACTIVE ) ;
  act_in = fopen( filename, "r" ) ;

  /* Open temporary output file */
  strcpy( filename, path ) ;
  strcat( filename, TEMPACTIVE ) ;

  act_out = fopen( filename, "w" ) ;
  if( act_out == NULL )
    {
      /* Can't open file for writing - die */
      alert( strings.cantwriteactivetmp ) ;
      exit(1) ;
    }
}

/*
 * close_files() er, like, closes them. Oh, and it removes the
 *    "active" file and renames "active.tmp" to "active"
 */

void close_files( void )
{
  char filename[PATHLENGTH] ;
  char filename2[PATHLENGTH] ;

  /* Close files */
  fclose( act_in ) ;
  fclose( act_out ) ;

  /* Delete active */
  strcpy( filename, path ) ;
  strcat( filename, ACTIVE ) ;
  remove( filename ) ;

  /* Rename file active.tmp to active */
  strcpy( filename2, path ) ;
  strcat( filename2, TEMPACTIVE ) ;
  rename( filename2, filename ) ;
}

/*
 * group_list_file() opens a file for a group list, generating the
 *    filename.
 */

void group_list_file( char *server_name, char *filename )
{
  char group_path[PATHLENGTH] ;
  char *fnptr ;
  int i ;
  int get_next_letter = 1 ;
  int name_unique = 0 ;
  char *ch ;

  /* Generate filename */
  fnptr = filename ;
  for( i=0; server_name[i] != '\0'; i++ )
    {
      if( get_next_letter )
	{
	  *fnptr++ = server_name[i] ;
	  get_next_letter = 0 ;
	}
      if( server_name[i] == '.' )
	get_next_letter = 1 ;
    }
  
  /* Terminate filename */
  *fnptr = '\0' ;

  /* Ensure filename is no more than seven characters */
  filename[7] = '\0' ;

  /* Ensure name is unique */
  do
    {
      /* Full path name */
      sprintf( group_path, "%s%s.ngp", path, filename ) ;

      /* Does it exist? */
      name_unique = access( group_path, W_OK ) ;

      if( !name_unique )
	{
	  /* Change name so it is unique */
	  ch = &( filename[ strlen( filename ) - 1 ] ) ;
	  if( isdigit( *ch ) )
	    {
	      /* Increment number if there already is one */
	      (*ch)++ ;
	    }
	  else
	  {
	    /* Add a 1 to the end */
	    strcat( filename, "1" ) ;
	  }
	}
    }
  while( !name_unique ) ;

  /* Open group file */
  groups = fopen( group_path, "w" ) ;

  /* Open descriptions file */
  sprintf( group_path, "%s%s.dsc", path, filename ) ;
  descriptions = fopen( group_path, "w" ) ;
}

/*
 * new_groups_file() opens a file for new groups. very simple,
 *    just done here to keep the path mangling all in this
 *    file, otherwise I wouldn't bother making it a separate
 *    function as it's only a couple of lines.
 */

void new_groups_file( char *basename )
{
  char name[PATHLENGTH] ;

  sprintf( name, "%s%s.new", path, basename ) ;
  newgroups = fopen( name, "w+" ) ;

  sprintf( name, "%s%s.ngp", path, basename ) ;
  groups = fopen( name, "a" ) ;

  sprintf( name, "%s%s.dsc", path, basename ) ;
  descriptions = fopen( name, "a" ) ;
}

/*
 * open_group_header() opens the header file for a group 
 */

FILE *open_group_header( char *basename, char *mode )
{
  char name[PATHLENGTH] ;

  sprintf( name, "%s%s.hdr", path, basename ) ;
  
  return fopen( name, mode ) ;
}

/*
 * open_messages() opens the messages file for a group
 */

FILE *open_messages( char *basename )
{
  char name[PATHLENGTH] ;  

  sprintf( name, "%s%s.msg", path, basename ) ;
  
  return fopen( name, "a+" ) ;
}

/*
 * temp_messages() creates a temporary message file for a group
 */

FILE *temp_messages( char *basename )
{
  char name[PATHLENGTH] ;

  sprintf( name, "%s%s.tmp", path, basename ) ;

  return fopen( name, "w" ) ;
}

/*
 * close_messages() closes both the messages file and the temporary
 *    file, then deletes the old messages file and renames the 
 *    temporary file to correspond
 */

void close_messages( FILE *old, FILE *temp, char *basename )
{
  char filename[PATHLENGTH] ;
  char filename2[PATHLENGTH] ;

  /* Close files */
  fclose( old ) ;
  fclose( temp ) ;

  /* Delete old file */
  sprintf( filename, "%s%s.msg", path, basename ) ;
  remove( filename ) ;

  /* Rename file *.tmp to *.msg */
  sprintf( filename2, "%s%s.tmp", path, basename ) ;
  rename( filename2, filename ) ;
}
