view src/content.c @ 45:32ba1198c6fa noffle

[svn] * Makefile.in, configure, configure.in, docs/Makefile.in, src/Makefile.in: Added checks for the mail and sort programs. ./configure will abort if they're not found. * README: Removed the paragraph about news client software, as it's the same as the one in docs/NOTES. * TODO: Removed 'expiring by groups' and 'move some text from noffle.1 to noffle.conf.5'. * docs/NOTES: Changed the text about -DDEBUG to explain one should use './configure --enable-debug'. * docs/noffle.1, docs/noffle.conf.5: Minor fixes. Added myself and Jim Hague to the AUTHORS section :-) * src/client.h, src/common.h, src/configfile.h, src/content.c, src/content.h, src/control.c, src/control.h, src/database.h, src/dynamicstring.c, src/dynamicstring.h, src/fetch.h, src/fetchlist.h, src/group.h, src/itemlist.c, src/itemlist.h, src/lock.h, src/log.c, src/log.h, src/noffle.c, src/online.h, src/outgoing.h, src/over.c, src/over.h, src/post.h, src/protocol.h, src/pseudo.h, src/request.h, src/server.h, src/util.c, src/util.h: Added the <config.h> include. * src/content.c: Added missing include "content.h". Added a missing 'void' in the declaration of clearCont(). * src/fetchlist.c: Casted fetchlist.size to (size_t) in a call to qsort(), as qsort() expects a size_t. This removes a warning. * src/noffle.c: Made doRequested() static. Added missing void to enableCorefiles(). * src/log.c, src/protocol.c, src/online.c, src/pseudo.c: Added missing includes. * src/pseudo.c: Made genOv() and genPseudo() static. * src/server.c: Added missing void to postArts(). Made touchArticle() static. * src/util.c: Casted arguments of malloc() and memcpy() to size_t. * src/dynamicstring.c, src/itemlist.c, src/over.c, src/request.c, src/util.c: Removed casting of the result of malloc(). This is not necessary and can hide a missing include of <stdlib.h>.
author uh1763
date Sat, 06 May 2000 00:49:38 +0100
parents 2842f50feb55
children 5ecb646acf97
line wrap: on
line source

/*
  content.c

  $Id: content.c 51 2000-05-05 23:49:38Z uh1763 $
*/

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

#include <stdio.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "common.h"
#include "configfile.h"
#include "group.h"
#include "log.h"
#include "over.h"
#include "pseudo.h"
#include "util.h"
#include "content.h"

struct
{
    DIR *dir;           /* Directory for browsing through all
                           groups */
    int vecFirst;	/* First article number in vector */
    int first;		/* First live article number */
    int last;		/* Last article number */
    unsigned int size;  /* Number of overviews. */
    unsigned int max;   /* Size of elem. */
    Over **elem;        /* Ptr to array with ptrs to overviews.
                           NULL entries for non-existing article numbers
                           in group. */
    Str name;
    Str file;
} cont = { NULL, 1, 1, 0, 0, 0, NULL, "", "" };

void
Cont_app( Over *ov )
{
    if ( cont.max < cont.size + 1 )
    {
        if ( ! ( cont.elem = realloc( cont.elem,
                                      ( cont.max + 500 )
                                      * sizeof( cont.elem[ 0 ] ) ) ) )
        {
            Log_err( "Could not realloc overview list" );
            exit( EXIT_FAILURE );
        }
        cont.max += 500;
    }
    ASSERT( cont.vecFirst > 0 );
    if ( ov )
        Ov_setNumb( ov, cont.vecFirst + cont.size );
    cont.elem[ cont.size++ ] = ov;
    cont.last = cont.vecFirst + cont.size - 1;
}

Bool
Cont_validNumb( int n )
{
    return ( n != 0 && n >= cont.first && n <= cont.last
             && cont.elem[ n - cont.vecFirst ] );
}

void
Cont_delete( int n )
{
    Over **ov;

    if ( ! Cont_validNumb( n ) )
        return;
    ov = &cont.elem[ n - cont.vecFirst ];
    free( *ov );
    *ov = NULL;
}

/* Remove all overviews from content. */
static void
clearCont( void )
{
    int i;

    for ( i = 0; i < cont.size; ++i )
        del_Over( cont.elem[ i ] );
    cont.size = 0;
}

static void
setupEmpty( const char *name )
{
    cont.last = Grp_last( name );
    cont.first = cont.vecFirst = cont.last + 1;
    ASSERT( cont.first > 0 );
}

/* Extend content list to size "cnt" and append NULL entries. */
static void
extendCont( int cnt )
{
    int i, n;
    
    if ( cont.size < cnt )
    {
        n = cnt - cont.size;
        for ( i = 0; i < n; ++i )
            Cont_app( NULL );
    }
}

/* Discard all cached overviews, and read in the overviews of a new group
   from its overviews file. */
void
Cont_read( const char *name )
{
    FILE *f;
    Over *ov;
    int numb;
    Str line;

    /* Delete old overviews and make room for new ones. */
    cont.vecFirst = 0;
    cont.first = 0;
    cont.last = 0;
    Utl_cpyStr( cont.name, name );
    clearCont();

    /* read overviews from overview file and store them in the overviews
       list */
    snprintf( cont.file, MAXCHAR, "%s/overview/%s", Cfg_spoolDir(), name ); 
    f = fopen( cont.file, "r" );
    if ( ! f )
    {
        Log_dbg( "No group overview file: %s", cont.file );
	setupEmpty( name );
        return;
    }
    Log_dbg( "Reading %s", cont.file );
    while ( fgets( line, MAXCHAR, f ) )
    {
        if ( ! ( ov = Ov_read( line ) ) )
        {
            Log_err( "Overview corrupted in %s: %s", name, line );
            continue;
        }
        numb = Ov_numb( ov );
        if ( numb < cont.first )
        {
            Log_err( "Wrong ordering in %s: %s", name, line );
            continue;
        }
        if ( cont.first == 0 )
            cont.first = cont.vecFirst = numb;
        cont.last = numb;
        extendCont( numb - cont.first + 1 );
        cont.elem[ numb - cont.first ] = ov;
    }
    fclose( f );

    if ( cont.first == 0 )
	setupEmpty( name );		/* Corrupt overview file recovery */
}

void
Cont_write( void )
{
    Bool anythingWritten;
    int i;
    FILE *f;
    const Over *ov;


    /* Move the first article no. to the first active article */
    while ( ! Cont_validNumb( cont.first ) && cont.first <= cont.last )
        ++cont.first;

    /* Save the overview */
    if ( ! ( f = fopen( cont.file, "w" ) ) )
    {
        Log_err( "Could not open %s for writing", cont.file );
        return;
    }
    Log_dbg( "Writing %s (%lu)", cont.file, cont.size );
    anythingWritten = FALSE;
    for ( i = 0; i < cont.size; ++i )
    {
        if ( ( ov = cont.elem[ i ] ) )
        {
            if ( ! Pseudo_isGeneralInfo( Ov_msgId( ov ) ) )
            {
                if ( ! Ov_write( ov, f ) )
                {
                    Log_err( "Writing of overview line failed" );
                    break;
                }
                else
                    anythingWritten = TRUE;
            }
        }
    }
    fclose( f );

    /*
      If empty, remove the overview file and set set first to one
      beyond last to flag said emptiness.
     */
    if ( ! anythingWritten )
    {
	unlink( cont.file );
	cont.first = cont.last + 1;
    }
}

const Over *
Cont_get( int numb )
{
    if ( ! Cont_validNumb( numb ) )
        return NULL;
    return cont.elem[ numb - cont.vecFirst ];
}

int
Cont_first( void ) { return cont.first; }

int
Cont_last( void ) { return cont.last; }

const char *
Cont_grp( void ) { return cont.name; }

Bool
Cont_nextGrp( Str result )
{
    struct dirent *d;
    
    ASSERT( cont.dir );
    if ( ! ( d = readdir( cont.dir ) ) )
    {
        cont.dir = NULL;
        return FALSE;
    }
    if ( ! d->d_name )
        return FALSE;
    Utl_cpyStr( result, d->d_name );
    result[ MAXCHAR - 1 ] = '\0';
    return TRUE;
}

Bool
Cont_firstGrp( Str result )
{
    Str name;

    snprintf( name, MAXCHAR, "%s/overview", Cfg_spoolDir() );
    if ( ! ( cont.dir = opendir( name ) ) )
    {
        Log_err( "Cannot open %s", name );
        return FALSE;
    }
    Cont_nextGrp( result ); /* "."  */
    Cont_nextGrp( result ); /* ".." */
    return Cont_nextGrp( result );
}