view src/fetchlist.c @ 244:4e69e9b722ae noffle

[svn] * src/database.c,src/protocol.c,src/util.c,src/util.h: The latest IETF article format draft draft-ietf-usefor-article-06.txt recommends that Xref: references contain the FQDN of the server. We were using the host name without the domain. So split the routine used for obtaining the FQDN from protocol.c into util.c, and use it when adding Xrefs.
author bears
date Fri, 15 Mar 2002 10:50:33 +0000
parents f8a91e2b4060
children 5eece4dfd945
line wrap: on
line source

/*
  fetchlist.c

  $Id: fetchlist.c 368 2002-02-14 17:14:34Z bears $
*/

#if HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include "fetchlist.h"
#include "configfile.h"
#include "log.h"
#include "util.h"
#include "portable.h"

struct Elem
{
    Str name;
    FetchMode mode;
};

static struct Fetchlist
{
    struct Elem *elem;
    int size;
    int max;
    Bool dirty;
} fetchlist = { NULL, 0, 0, FALSE };

static void
clearList( void )
{
    fetchlist.size = 0;
    fetchlist.dirty = FALSE;
}

static int
compareElem( const void *elem1, const void *elem2 )
{
    const struct Elem* e1 = (const struct Elem*)elem1; 
    const struct Elem* e2 = (const struct Elem*)elem2;
    return strcmp( e1->name, e2->name );
}

static struct Elem *
searchElem( const char *name )
{
    int i;
    
    for ( i = 0; i < fetchlist.size; ++i )
        if ( strcmp( name, fetchlist.elem[ i ].name ) == 0 )
            return &fetchlist.elem[ i ];
    return NULL;
}

static void
appGrp( const char *name, FetchMode mode )
{
    struct Elem elem;

    if ( fetchlist.max < fetchlist.size + 1 )
    {
        if ( ! ( fetchlist.elem
                 = realloc( fetchlist.elem,
                            ( fetchlist.max + 50 )
                            * sizeof( fetchlist.elem[ 0 ] ) ) ) )
        {
            Log_err( "Could not realloc fetchlist" );
            exit( EXIT_FAILURE );
        }
        fetchlist.max += 50;
    }
    strcpy( elem.name, name );
    elem.mode = mode;
    fetchlist.elem[ fetchlist.size++ ] = elem;
}

void
Fetchlist_read( void )
{
    FILE *f;
    Str file;
    char *p;
    FetchMode mode = OVER;
    Bool valid;
    int ret;
    Str line, grp, modeStr;

    Log_dbg( LOG_DBG_FETCH, "Reading %s", file );
    snprintf( file, MAXCHAR, "%s/fetchlist", Cfg_spoolDir() );
    clearList();
    if ( ! ( f = fopen( file, "r" ) ) )
    {
        Log_inf( "No file %s", file );
        return;
    }
    while ( fgets( line, MAXCHAR, f ) )
    {
        p = Utl_stripWhiteSpace( line );
        if ( *p == '#' || *p == '\0' )
            continue;
        ret = sscanf( p, "%s %s", grp, modeStr );
        valid = TRUE;
        if ( ret < 1 || ret > 2 )
            valid = FALSE;
        else if ( ret >= 2 )
        {
            if ( strcmp( modeStr, "full" ) == 0 )
                mode = FULL;
            else if ( strcmp( modeStr, "thread" ) == 0 )
                mode = THREAD;
            else if ( strcmp( modeStr, "over" ) == 0 )
                mode = OVER;
            else
                valid = FALSE;
        }
        if ( ! valid )
        {
            Log_err( "Invalid entry in %s: %s", file, line );
            continue;
        }
        appGrp( grp, mode );
    }
    if ( ferror( f ) )
        Log_err( "Error reading %s: %s", file, strerror( errno ) );
    if ( fclose( f ) != 0 )
        Log_err( "Error closing %s; %s", file, strerror( errno ) );
}

Bool
Fetchlist_write( void )
{
    int i;
    FILE *f;
    Str file, tmpfname;
    const char *modeStr = "";
    Bool res;

    /* Any changes? */
    if ( ! fetchlist.dirty )
        return TRUE;
    
    qsort( fetchlist.elem, (size_t)fetchlist.size,
           sizeof( fetchlist.elem[ 0 ] ), compareElem );
    
    snprintf( file, MAXCHAR, "%s/fetchlist", Cfg_spoolDir() );
    snprintf( tmpfname, MAXCHAR, "%s/.#%d.fetchlist",
              Cfg_spoolDir(), (int) getpid() );
    
    if ( ! ( f = fopen( tmpfname, "w" ) ) )
    {
        Log_err( "Could not open %s for writing", file );
        return FALSE;
    }
    res = TRUE;
    for ( i = 0; i < fetchlist.size; ++i )
    {
        switch ( fetchlist.elem[ i ].mode )
        {
        case FULL:
            modeStr = "full"; break;
        case THREAD:
            modeStr = "thread"; break;
        case OVER:
            modeStr = "over"; break;
        }
        fprintf( f, "%s %s\n", fetchlist.elem[ i ].name, modeStr );
        if ( ferror( f ) )
        {
            Log_err( "Error writing %s: %s", tmpfname, strerror( errno ) );
            clearerr( f );
            res = FALSE;
        }
    }
    if ( fclose( f ) != 0 )
    {
        Log_err( "Error closing %s: %s", tmpfname, strerror( errno ) );
        res = FALSE;
    }

    if ( res )
    {
        if ( rename( tmpfname, file ) < 0 )
        {
            Log_err( "Rename of %s to %s failed: %s", tmpfname, file,
                     strerror( errno ) );
            res = FALSE;
        }
    }
        
    return res;
}

int
Fetchlist_size( void )
{
    return fetchlist.size;
}

Bool
Fetchlist_contains( const char *name, FetchMode *mode )
{
    struct Elem *elem = searchElem( name );
    if ( elem == NULL )
	return FALSE;
    if ( mode != NULL )
	*mode = elem->mode;
    return TRUE;
}

Bool
Fetchlist_element( const char **name, FetchMode *mode, int idx )
{
    if ( idx < 0 || idx >= fetchlist.size )
        return FALSE;
    *name = fetchlist.elem[ idx ].name;
    *mode = fetchlist.elem[ idx ].mode;
    return TRUE;
}

Bool
Fetchlist_add( const char *name, FetchMode mode )
{
    struct Elem *elem = searchElem( name );
    fetchlist.dirty = TRUE;
    if ( elem == NULL )
    {
        appGrp( name, mode );
        return TRUE;
    }
    strcpy( elem->name, name );
    elem->mode = mode;
    return FALSE;
}

Bool
Fetchlist_remove( const char *name )
{
    struct Elem *elem = searchElem( name );
    if ( elem == NULL )
        return FALSE;
    fetchlist.dirty = TRUE;
    *elem = fetchlist.elem[ fetchlist.size - 1 ];
    --fetchlist.size;
    return TRUE;
}