summaryrefslogblamecommitdiffstats
path: root/innbbsd/his.c
blob: 773fb78cef0f56088f132e001f141701a18a931f (plain) (tree)
1
2
3
4
5
6
7
8
9




                          
                   


                       
                    

                     





                                                 

                  
                    


                         
                                

      
    
               
                         
 
                     

 
    
                        

                             
 
                         
                          
                                         


               

                           


                  
                            
 
                             


                                   
                           


















                                                                       

                                          







                                                                      




                     
                
 
                             
                             


                                    
                           
                 
     
                                                  
                     




                                          




             
              
 



                                    

                           
                                            
     
                                   
                           
               
     















                                                         
             























                                                                           





                     


                               
              
 
                        

 
   
                    
                             
















                                                                       
                                         






                                                                         
             



  

                                                      













                                                            

                              
    
              

                             



                                                                       














                                                                  


                                                                           

                  

                         
 


                              





                                          
                                    


                                           











                                                     





                                                               
 





                           


                                                   

                                                         

                    

                               

                                                
     
                                            
                                                                            

                                                   
                                               

                    
                                        


                                                        
                     
                                          
                        
         

                                  
                                                               





                                                                     
                                                                   


                                          



                                                                         




                                                                           

                                      


                         
                              
 

                        








                               


                                                                            

              
                      
 
                         




                                
                                             






                        
    
              
                          
 
                                   

 
          
   
                       

                           
 


                           

                         
                           

                     
                                       






                                                             
                                           

                     





                                                        
                                           

                     

                                     
                                       




                

                            

                          
                        
                         
                          
 


                           
 
                                       







                                                                  
                                           

                     





                                                        
                                           

                     

                                     
                                       

                
/*
 * $Revision: 1.1 $ *
 * 
 *  History file routines.
 */
#include <stdlib.h>
#include "innbbsconf.h"
#include "bbslib.h"
#include "his.h"
#include "externs.h"

#define STATIC static
/* STATIC char  HIShistpath[] = _PATH_HISTORY; */
STATIC FILE    *HISwritefp;
STATIC int      HISreadfd;
STATIC int      HISdirty;
STATIC int      HISincore = XINDEX_DBZINCORE;
STATIC char    *LogName = "xindexchan";

#ifndef EXPIREDAYS
#define EXPIREDAYS 4
#endif

#ifndef DEFAULT_HIST_SIZE
#define DEFAULT_HIST_SIZE 100000
#endif

void
hisincore(flag)
    int             flag;
{
    HISincore = flag;
}

void
makedbz(histpath, entry)
    char           *histpath;
    long            entry;
{
    long            size;
    size = dbzsize(entry);
    dbzfresh(histpath, size, '\t', 0, 1);
    dbmclose();
}

void            HISsetup();
void            HISclose();

void
mkhistory(srchist)
    char           *srchist;
{
    FILE           *hismaint;
    char            maintbuff[256];
    char           *ptr;
    hismaint = fopen(srchist, "r");
    if (hismaint == NULL) {
    return;
    } {
    char            newhistpath[1024];
    char            newhistdirpath[1024];
    char            newhistpagpath[1024];
    sprintf(newhistpath, "%s.n", srchist);
    sprintf(newhistdirpath, "%s.n.dir", srchist);
    sprintf(newhistpagpath, "%s.n.pag", srchist);
    if (!isfile(newhistdirpath) || !isfile(newhistpagpath)) {
        makedbz(newhistpath, DEFAULT_HIST_SIZE);
    }
    myHISsetup(newhistpath);
    while (fgets(maintbuff, sizeof(maintbuff), hismaint) != NULL) {
        datum           key;
        ptr = (char *)strchr(maintbuff, '\t');
        if (ptr != NULL) {
        *ptr = '\0';
        ptr++;
        }
        key.dptr = maintbuff;
        key.dsize = strlen(maintbuff);
        myHISwrite(&key, ptr);
    }
    (void)HISclose();
    /*
     * rename(newhistpath, srchist);    rename(newhistdirpath,
     * fileglue("%s.dir", srchist)); rename(newhistpagpath,
     * fileglue("%s.pag", srchist));
     */
    }
    fclose(hismaint);
}

time_t
gethisinfo(void)
{
    FILE           *hismaint;
    time_t          lasthist;
    char            maintbuff[4096];
    char           *ptr;
    hismaint = fopen(HISTORY, "r");
    if (hismaint == NULL) {
    return 0;
    }
    fgets(maintbuff, sizeof(maintbuff), hismaint);
    fclose(hismaint);
    ptr = (char *)strchr(maintbuff, '\t');
    if (ptr != NULL) {
    ptr++;
    lasthist = atol(ptr);
    return lasthist;
    }
    return 0;
}

void
HISmaint(void)
{
    FILE           *hismaint;
    time_t          lasthist, now;
    char            maintbuff[4096];
    char           *ptr;

    if (!isfile(HISTORY)) {
    makedbz(HISTORY, DEFAULT_HIST_SIZE);
    }
    hismaint = fopen(HISTORY, "r");
    if (hismaint == NULL) {
    return;
    }
    fgets(maintbuff, sizeof(maintbuff), hismaint);
    ptr = (char *)strchr(maintbuff, '\t');
    if (ptr != NULL) {
    ptr++;
    lasthist = atol(ptr);
    time(&now);
    if (lasthist + 86400 * Expiredays * 2 < now) {
        char            newhistpath[1024];
        char            newhistdirpath[1024];
        char            newhistpagpath[1024];
        (void)HISclose();
        sprintf(newhistpath, "%s.n", HISTORY);
        sprintf(newhistdirpath, "%s.n.dir", HISTORY);
        sprintf(newhistpagpath, "%s.n.pag", HISTORY);
        if (!isfile(newhistdirpath)) {
        makedbz(newhistpath, DEFAULT_HIST_SIZE);
        }
        myHISsetup(newhistpath);
        while (fgets(maintbuff, sizeof(maintbuff), hismaint) != NULL) {
        datum           key;
        ptr = (char *)strchr(maintbuff, '\t');
        if (ptr != NULL) {
            *ptr = '\0';
            ptr++;
            lasthist = atol(ptr);
        } else {
            continue;
        }
        if (lasthist + 99600 * Expiredays < now)
            continue;
        key.dptr = maintbuff;
        key.dsize = strlen(maintbuff);
        myHISwrite(&key, ptr);
        }
        (void)HISclose();
        rename(HISTORY, (char *)fileglue("%s.o", HISTORY));
        rename(newhistpath, HISTORY);
        rename(newhistdirpath, (char *)fileglue("%s.dir", HISTORY));
        rename(newhistpagpath, (char *)fileglue("%s.pag", HISTORY));
        (void)HISsetup();
    }
    }
    fclose(hismaint);
}


/*
 * *  Set up the history files.
 */
void
HISsetup(void)
{
    myHISsetup(HISTORY);
}

int
myHISsetup(histpath)
    char           *histpath;
{
    if (HISwritefp == NULL) {
    /* Open the history file for appending formatted I/O. */
    if ((HISwritefp = fopen(histpath, "a")) == NULL) {
        syslog(LOG_CRIT, "%s cant fopen %s %m", LogName, histpath);
        exit(1);
    }
    CloseOnExec((int)fileno(HISwritefp), TRUE);

    /* Open the history file for reading. */
    if ((HISreadfd = open(histpath, O_RDONLY)) < 0) {
        syslog(LOG_CRIT, "%s cant open %s %m", LogName, histpath);
        exit(1);
    }
    CloseOnExec(HISreadfd, TRUE);

    /* Open the DBZ file. */
    /* (void)dbzincore(HISincore); */
    (void)dbzincore(HISincore);
    (void)dbzwritethrough(1);
    if (dbminit(histpath) < 0) {
        syslog(LOG_CRIT, "%s cant dbminit %s %m", histpath, LogName);
        exit(1);
    }
    }
    return 0;
}


/*
 * *  Synchronize the in-core history file (flush it).
 */
void
HISsync()
{
    if (HISdirty) {
    if (dbzsync()) {
        syslog(LOG_CRIT, "%s cant dbzsync %m", LogName);
        exit(1);
    }
    HISdirty = 0;
    }
}


/*
 * *  Close the history files.
 */
void
HISclose(void)
{
    if (HISwritefp != NULL) {
    /*
     * Since dbmclose calls dbzsync we could replace this line with
     * "HISdirty = 0;".  Oh well, it keeps the abstraction clean.
     */
    HISsync();
    if (dbmclose() < 0)
        syslog(LOG_ERR, "%s cant dbmclose %m", LogName);
    if (fclose(HISwritefp) == EOF)
        syslog(LOG_ERR, "%s cant fclose history %m", LogName);
    HISwritefp = NULL;
    if (close(HISreadfd) < 0)
        syslog(LOG_ERR, "%s cant close history %m", LogName);
    HISreadfd = -1;
    }
}


#ifdef HISset
/*
 * *  File in the DBZ datum for a Message-ID, making sure not to copy any *
 * illegal characters.
 */
STATIC void
HISsetkey(p, keyp)
    register char  *p;
    datum          *keyp;
{
    static BUFFER   MessageID;
    register char  *dest;
    register int    i;

    /* Get space to hold the ID. */
    i = strlen(p);
    if (MessageID.Data == NULL) {
    MessageID.Data = NEW(char, i + 1);
    MessageID.Size = i;
    } else if (MessageID.Size < i) {
    RENEW(MessageID.Data, char, i + 1);
    MessageID.Size = i;
    }
    for (keyp->dptr = dest = MessageID.Data; *p; p++)
    if (*p == HIS_FIELDSEP || *p == '\n')
        *dest++ = HIS_BADCHAR;
    else
        *dest++ = *p;
    *dest = '\0';

    keyp->dsize = dest - MessageID.Data + 1;
}

#endif
/*
 * *  Get the list of files under which a Message-ID is stored.
 */
char           *
HISfilesfor(key, output)
    datum          *key;
    datum          *output;
{
    char           *dest;
    datum           val;
    long            offset;
    register char  *p;
    register int    i;
    int             Used;

    /* Get the seek value into the history file. */
    val = dbzfetch(*key);
    if (val.dptr == NULL || val.dsize != sizeof offset) {
    /* printf("fail here val.dptr %d\n",val.dptr); */
    return NULL;
    }
    /* Get space. */
    if (output->dptr == NULL) {
    printf("fail here output->dptr null\n");
    return NULL;
    }
    /* Copy the value to an aligned spot. */
    for (p = val.dptr, dest = (char *)&offset, i = sizeof offset; --i >= 0;)
    *dest++ = *p++;
    if (lseek(HISreadfd, offset, SEEK_SET) == -1) {
    printf("fail here lseek %d\n", offset);
    return NULL;
    }
    /* Read the text until \n or EOF. */
    for (output->dsize = 0, Used = 0;;) {
    i = read(HISreadfd,
         &output->dptr[output->dsize], LEN - 1);
    if (i <= 0) {
        printf("fail here i %d\n", i);
        return NULL;
    }
    Used += i;
    output->dptr[Used] = '\0';
    if ((p = (char *)strchr(output->dptr, '\n')) != NULL) {
        *p = '\0';
        break;
    }
    }

    /* Move past the first two fields -- Message-ID and date info. */
    if ((p = (char *)strchr(output->dptr, HIS_FIELDSEP)) == NULL) {
    printf("fail here no HIS_FILE\n");
    return NULL;
    }
    return p + 1;
    /*
     * if ((p = (char*)strchr(p + 1, HIS_FIELDSEP)) == NULL) return NULL;
     */

    /* Translate newsgroup separators to slashes, return the fieldstart. */
}

/*
 * *  Have we already seen an article?
 */
#ifdef HISh
BOOL
HIShavearticle(MessageID)
    char           *MessageID;
{
    datum           key;
    datum           val;

    HISsetkey(MessageID, &key);
    val = dbzfetch(key);
    return val.dptr != NULL;
}
#endif


/*
 * *  Turn a history filename entry from slashes to dots.  It's a pity *  we
 * have to do this.
 */
STATIC void
HISslashify(p)
    register char  *p;
{
    register char  *last;

    for (last = NULL; *p; p++) {
    if (*p == '/') {
        *p = '.';
        last = p;
    } else if (*p == ' ' && last != NULL)
        *last = '/';
    }
    if (last)
    *last = '/';
}


void
IOError(error)
    char           *error;
{
    fprintf(stderr, "%s\n", error);
}

/* BOOL */
int
myHISwrite(key, remain)
    datum          *key;
    char           *remain;
{
    long            offset;
    datum           val;
    int             i;

    val = dbzfetch(*key);
    if (val.dptr != NULL) {
    return FALSE;
    }
    flock(fileno(HISwritefp), LOCK_EX);
    offset = ftell(HISwritefp);
    i = fprintf(HISwritefp, "%s%c%s",
        key->dptr, HIS_FIELDSEP, remain);
    if (i == EOF || fflush(HISwritefp) == EOF) {
    /* The history line is now an orphan... */
    IOError("history");
    syslog(LOG_ERR, "%s cant write history %m", LogName);
    flock(fileno(HISwritefp), LOCK_UN);
    return FALSE;
    }
    /* Set up the database values and write them. */
    val.dptr = (char *)&offset;
    val.dsize = sizeof offset;
    if (dbzstore(*key, val) < 0) {
    IOError("my history database");
    syslog(LOG_ERR, "%s cant dbzstore %m", LogName);
    flock(fileno(HISwritefp), LOCK_UN);
    return FALSE;
    }
    if (++HISdirty >= ICD_SYNC_COUNT)
    HISsync();
    flock(fileno(HISwritefp), LOCK_UN);
    return TRUE;
}


/*
 * *  Write a history entry.
 */
BOOL
HISwrite(key, date, paths)
    datum          *key;
    long            date;
    char           *paths;
{
    long            offset;
    datum           val;
    int             i;

    flock(fileno(HISwritefp), LOCK_EX);
    offset = ftell(HISwritefp);
    i = fprintf(HISwritefp, "%s%c%ld%c%s\n",
        key->dptr, HIS_FIELDSEP, (long)date, HIS_FIELDSEP,
        paths);
    if (i == EOF || fflush(HISwritefp) == EOF) {
    /* The history line is now an orphan... */
    IOError("history");
    syslog(LOG_ERR, "%s cant write history %m", LogName);
    flock(fileno(HISwritefp), LOCK_UN);
    return FALSE;
    }
    /* Set up the database values and write them. */
    val.dptr = (char *)&offset;
    val.dsize = sizeof offset;
    if (dbzstore(*key, val) < 0) {
    IOError("history database");
    syslog(LOG_ERR, "%s cant dbzstore %m", LogName);
    flock(fileno(HISwritefp), LOCK_UN);
    return FALSE;
    }
    if (++HISdirty >= ICD_SYNC_COUNT)
    HISsync();
    flock(fileno(HISwritefp), LOCK_UN);
    return TRUE;
}