summaryrefslogblamecommitdiffstats
path: root/innbbsd/bbslib.c
blob: 1bc0db3c55b01ed9c1f5f9f4346eea917d5d694a (plain) (tree)
1
2
3
4
5
6
7
8
                
                   
                   
                   
                    

                       
 

















                                                             

                     
                                                             

      
                         
 

                                
 


                                        
 
    
                         
 







                                                                  
 
 
    

            
                    

 
    
              
 
                    

 
   
              
 
                       

 
    
               
 




                           

 
    
                          
 


                                
 

                         
 
                      
 

                                                                     
 






                                                   
                   





                                                    

 
    
              
                       
     
                      
      
 


                                
 
                      
 

                                                                     
 



                                       
                   





                                                    

 
   
                           
 




                            




                           
                    

                      

      








                                                    
                            
































                                                                                  
                 

































                                                                             
                    






                                                              
                                                    



                                                               
                          



                                                
      
             

 
          
                                           
 



                                                                 
                                                                                                

 
          
                                   
 



                                                                            
                                                                                                  

 
          
                                   
 


                                                                   
                                                                                    

 
          
                                          
 



                                                                             
                                                                                            


                                            
   
                                          
 


                               
                             
                                      
                                  


                                               
                     

                                              
     


                                              

                               
                                                        
            
                                                                       
     
                     
                                                  






                                       


                           

                                                                                       
            

                                                                                                         
     

                                         


                      
                                                                                                                   
                                    





                                                  


                                                      
                            






                                                                  
                            






                                                                       
                
                                             
         













                                                                                                                                             
                
                                             
         


                                               
                            

















                                                        

                                                        
                                                                        


             
   
                          
 







                                                
                     

                                              
     


                                              

                                
                                                         
            
                                                                         
     
                     
                                                  






                                        


                            

                                                                                           
            

                                                                                                               
     

                                                                                                                      
                             



                                           




























                                                         

                                                          
                                                                            
             

 

                         
 








                                                                                                                       

 

                                  
 








                                                                                                                  


 

                                            
 











                                                                                                  

 

                             
 





                                                                                                 

 

                      
 



                                
                                                                                 
                   

 

                                 
 












                                          

 

                  
 
                             
                      


                                                   



               

                               
 
                                    
                      


                                                   



               
    
                       
 
                      



                                              
 




                                 


                            
 














                                                             

 

                    
 











































                                                                          

 

                             
 













                                                             

 

                                        
 




                                           
                          
                       








                                        




             

                                 

      
#include "bbs.h"
#include <stdlib.h>
#include <stdarg.h>
#include "config.h"
#include "externs.h"
#include "innbbsconf.h"
#include "bbslib.h"

char            INNBBSCONF[MAXPATHLEN];
char            INNDHOME[MAXPATHLEN];
char            HISTORY[MAXPATHLEN];
char            LOGFILE[MAXPATHLEN];
char            MYBBSID[MAXPATHLEN];
char            ECHOMAIL[MAXPATHLEN];
char            BBSFEEDS[MAXPATHLEN];
char            LOCALDAEMON[MAXPATHLEN];

int             His_Maint_Min = HIS_MAINT_MIN;
int             His_Maint_Hour = HIS_MAINT_HOUR;
int             Expiredays = EXPIREDAYS;

nodelist_t     *NODELIST = NULL, **NODELIST_BYNODE = NULL;
newsfeeds_t    *NEWSFEEDS = NULL, **NEWSFEEDS_BYBOARD = NULL;
static char    *NODELIST_BUF, *NEWSFEEDS_BUF;
int             NFCOUNT, NLCOUNT;
int             LOCALNODELIST = 0, NONENEWSFEEDS = 0;

#ifndef _PATH_BBSHOME
#define _PATH_BBSHOME "/u/staff/bbsroot/csie_util/bntpd/home"
#endif

static FILE    *bbslogfp;

static int
                verboseFlag = 0;

static char    *
                verboseFilename = NULL;
static char     verbosename[MAXPATHLEN];

void
verboseon(char *filename)
{
    verboseFlag = 1;
    if (filename != NULL) {
    if (strchr(filename, '/') == NULL) {
        sprintf(verbosename, "%s/innd/%s", BBSHOME, filename);
        filename = verbosename;
    }
    }
    verboseFilename = filename;
}

void
verboseoff()
{
    verboseFlag = 0;
}

void
setverboseon()
{
    verboseFlag = 1;
}

int
isverboselog()
{
    return verboseFlag;
}

void
setverboseoff()
{
    verboseoff();
    if (bbslogfp != NULL) {
    fclose(bbslogfp);
    bbslogfp = NULL;
    }
}

void
verboselog(char *fmt, ...)
{
    va_list         ap;
    char            datebuf[40];
    time_t          now;

    if (verboseFlag == 0)
    return;

    va_start(ap, fmt);

    time(&now);
    strftime(datebuf, sizeof(datebuf), "%b %d %X ", localtime(&now));

    if (bbslogfp == NULL) {
    if (verboseFilename != NULL)
        bbslogfp = fopen(verboseFilename, "a");
    else
        bbslogfp = fdopen(1, "a");
    }
    if (bbslogfp == NULL) {
    va_end(ap);
    return;
    }
    fprintf(bbslogfp, "%s[%d] ", datebuf, getpid());
    vfprintf(bbslogfp, fmt, ap);
    fflush(bbslogfp);
    va_end(ap);
}

void
#ifdef PalmBBS
xbbslog(char *fmt, ...)
#else
bbslog(char *fmt, ...)
#endif
{
    va_list         ap;
    char            datebuf[40];
    time_t          now;

    va_start(ap, fmt);

    time(&now);
    strftime(datebuf, sizeof(datebuf), "%b %d %X ", localtime(&now));

    if (bbslogfp == NULL) {
    bbslogfp = fopen(LOGFILE, "a");
    }
    if (bbslogfp == NULL) {
    va_end(ap);
    return;
    }
    fprintf(bbslogfp, "%s[%d] ", datebuf, getpid());
    vfprintf(bbslogfp, fmt, ap);
    fflush(bbslogfp);
    va_end(ap);
}

int
initial_bbs(char *outgoing)
{
#ifdef WITH_ECHOMAIL
    FILE *FN;
    char *bbsnameptr = NULL;
#endif

    /* reopen bbslog */
    if (bbslogfp != NULL) {
    fclose(bbslogfp);
    bbslogfp = NULL;
    }
#ifdef WITH_ECHOMAIL
    init_echomailfp();
    init_bbsfeedsfp();
#endif

    LOCALNODELIST = 0, NONENEWSFEEDS = 0;
    sprintf(INNDHOME, "%s/innd", BBSHOME);
    sprintf(HISTORY, "%s/history", INNDHOME);
    sprintf(LOGFILE, "%s/bbslog", INNDHOME);
    sprintf(ECHOMAIL, "%s/echomail.log", BBSHOME);
    sprintf(LOCALDAEMON, "%s/.innbbsd", INNDHOME);
    sprintf(INNBBSCONF, "%s/innbbs.conf", INNDHOME);
    sprintf(BBSFEEDS, "%s/bbsfeeds.log", INNDHOME);

    if (dashf(INNBBSCONF)) {
    FILE           *conf;
    char            buffer[MAXPATHLEN];
    conf = fopen(INNBBSCONF, "r");
    if (conf != NULL) {
        while (fgets(buffer, sizeof buffer, conf) != NULL) {
        char           *ptr, *front = NULL, *value = NULL, *value2 = NULL,
                       *value3 = NULL;
        if (buffer[0] == '#' || buffer[0] == '\n')
            continue;
        for (front = buffer; *front && isspace(*front); front++);
        for (ptr = front; *ptr && !isspace(*ptr); ptr++);
        if (*ptr == '\0')
            continue;
        *ptr++ = '\0';
        for (; *ptr && isspace(*ptr); ptr++);
        if (*ptr == '\0')
            continue;
        value = ptr++;
        for (; *ptr && !isspace(*ptr); ptr++);
        if (*ptr) {
            *ptr++ = '\0';
            for (; *ptr && isspace(*ptr); ptr++);
            value2 = ptr++;
            for (; *ptr && !isspace(*ptr); ptr++);
            if (*ptr) {
            *ptr++ = '\0';
            for (; *ptr && isspace(*ptr); ptr++);
            value3 = ptr++;
            for (; *ptr && !isspace(*ptr); ptr++);
            if (*ptr) {
                *ptr++ = '\0';
            }
            }
        }
        if (strcasecmp(front, "expiredays") == 0) {
            Expiredays = atoi(value);
            if (Expiredays < 0) {
            Expiredays = EXPIREDAYS;
            }
        } else if (strcasecmp(front, "expiretime") == 0) {
            ptr = strchr(value, ':');
            if (ptr == NULL) {
            fprintf(stderr, "Syntax error in innbbs.conf\n");
            } else {
            *ptr++ = '\0';
            His_Maint_Hour = atoi(value);
            His_Maint_Min = atoi(ptr);
            if (His_Maint_Hour < 0)
                His_Maint_Hour = HIS_MAINT_HOUR;
            if (His_Maint_Min < 0)
                His_Maint_Min = HIS_MAINT_MIN;
            }
        } else if (strcasecmp(front, "newsfeeds") == 0) {
            if (strcmp(value, "none") == 0)
            NONENEWSFEEDS = 1;
        } else if (strcasecmp(front, "nodelist") == 0) {
            if (strcmp(value, "local") == 0)
            LOCALNODELIST = 1;
        }       /* else if ( strcasecmp(front,"newsfeeds") ==
                 * 0) { printf("newsfeeds %s\n", value); }
                 * else if ( strcasecmp(front,"nodelist") ==
                 * 0) { printf("nodelist %s\n", value); }
                 * else if ( strcasecmp(front,"bbsname") ==
                 * 0) { printf("bbsname %s\n", value); } */
        }
        fclose(conf);
    }
    }
#ifdef WITH_ECHOMAIL
    bbsnameptr = (char *)fileglue("%s/bbsname.bbs", INNDHOME);
    if ((FN = fopen(bbsnameptr, "r")) == NULL) {
    fprintf(stderr, "can't open file %s\n", bbsnameptr);
    return 0;
    }
    while (fscanf(FN, "%s", MYBBSID) != EOF);
    fclose(FN);
    if (!dashd(fileglue("%s/out.going", BBSHOME))) {
    mkdir((char *)fileglue("%s/out.going", BBSHOME), 0750);
    }
    if (NONENEWSFEEDS == 0)
    readnffile(INNDHOME);
    readNCMfile(INNDHOME);
    if (LOCALNODELIST == 0) {
    if (readnlfile(INNDHOME, outgoing) != 0)
        return 0;
    }
#endif
    return 1;
}

static int
nf_byboardcmp(const void *a, const void *b)
{
    /*
     * if (!a || !*a || !(*a)->board) return -1; if (!b || !*b ||
     * !(*b)->board) return 1;
     */
    return strcasecmp((*((const newsfeeds_t **)a))->board, (*((const newsfeeds_t **)b))->board);
}

static int
nfcmp(const void *a, const void *b)
{
    /*
     * if (!a || !a->newsgroups) return -1; if (!b || !b->newsgroups) return
     * 1;
     */
    return strcasecmp(((const newsfeeds_t *)a)->newsgroups, ((const newsfeeds_t *)b)->newsgroups);
}

static int
nlcmp(const void *a, const void *b)
{
    /*
     * if (!a || !a->host) return -1; if (!b || !b->host) return 1;
     */
    return strcasecmp(((const nodelist_t *)a)->host, ((const nodelist_t *)b)->host);
}

static int
nl_bynodecmp(const void *a, const void *b)
{
    /*
     * if (!a || !*a || !(*a)->node) return -1; if (!b || !*b || !(*b)->node)
     * return 1;
     */
    return strcasecmp((*((const nodelist_t **)a))->node, (*((const nodelist_t **)b))->node);
}

/* read in newsfeeds.bbs and nodelist.bbs */
int
readnlfile(char *inndhome, char *outgoing)
{
    FILE           *fp;
    char            buff[1024];
    struct stat     st;
    int             i, count;
    char           *ptr, *nodelistptr;
    static int      lastcount = 0;

    sprintf(buff, "%s/nodelist.bbs", inndhome);
    fp = fopen(buff, "r");
    if (fp == NULL) {
    fprintf(stderr, "open fail %s", buff);
    return -1;
    }
    if (fstat(fileno(fp), &st) != 0) {
    fprintf(stderr, "stat fail %s", buff);
    return -1;
    }
    if (NODELIST_BUF == NULL) {
    NODELIST_BUF = (char *)mymalloc(st.st_size + 1);
    } else {
    NODELIST_BUF = (char *)myrealloc(NODELIST_BUF, st.st_size + 1);
    }
    i = 0, count = 0;
    while (fgets(buff, sizeof buff, fp) != NULL) {
    if (buff[0] == '#')
        continue;
    if (buff[0] == '\n')
        continue;
    strcpy(NODELIST_BUF + i, buff);
    i += strlen(buff);
    count++;
    }
    fclose(fp);
    if (NODELIST == NULL) {
    NODELIST = (nodelist_t *) mymalloc(sizeof(nodelist_t) * (count + 1));
    NODELIST_BYNODE = (nodelist_t **) mymalloc(sizeof(nodelist_t *) * (count + 1));
    } else {
    NODELIST = (nodelist_t *) myrealloc(NODELIST, sizeof(nodelist_t) * (count + 1));
    NODELIST_BYNODE = (nodelist_t **) myrealloc(NODELIST_BYNODE, sizeof(nodelist_t *) * (count + 1));
    }
    for (i = lastcount; i < count; i++) {
    NODELIST[i].feedfp = NULL;
    }
    lastcount = count;
    NLCOUNT = 0;
    for (ptr = NODELIST_BUF; (nodelistptr = (char *)strchr(ptr, '\n')) != NULL; ptr = nodelistptr + 1, NLCOUNT++) {
    char           *nptr, *tptr;
    *nodelistptr = '\0';
    NODELIST[NLCOUNT].host = "";
    NODELIST[NLCOUNT].exclusion = "";
    NODELIST[NLCOUNT].node = "";
    NODELIST[NLCOUNT].protocol = "IHAVE(119)";
    NODELIST[NLCOUNT].comments = "";
    NODELIST_BYNODE[NLCOUNT] = NODELIST + NLCOUNT;
    for (nptr = ptr; *nptr && isspace(*nptr);)
        nptr++;
    if (*nptr == '\0') {
        bbslog("nodelist.bbs %d entry read error\n", NLCOUNT);
        return -1;
    }
    /* NODELIST[NLCOUNT].id = nptr; */
    NODELIST[NLCOUNT].node = nptr;
    for (nptr++; *nptr && !isspace(*nptr);)
        nptr++;
    if (*nptr == '\0') {
        bbslog("nodelist.bbs node %d entry read error\n", NLCOUNT);
        return -1;
    }
    *nptr = '\0';
    if ((tptr = strchr(NODELIST[NLCOUNT].node, '/'))) {
        *tptr = '\0';
        NODELIST[NLCOUNT].exclusion = tptr + 1;
    } else {
        NODELIST[NLCOUNT].exclusion = "";
    }
    for (nptr++; *nptr && isspace(*nptr);)
        nptr++;
    if (*nptr == '\0')
        continue;
    if (*nptr == '+' || *nptr == '-') {
        NODELIST[NLCOUNT].feedtype = *nptr;
        if (NODELIST[NLCOUNT].feedfp != NULL) {
        fclose(NODELIST[NLCOUNT].feedfp);
        }
        if (NODELIST[NLCOUNT].feedtype == '+')
        if (outgoing != NULL) {
            NODELIST[NLCOUNT].feedfp = fopen((char *)fileglue("%s/out.going/%s.%s", BBSHOME, NODELIST[NLCOUNT].node, outgoing), "a");
        }
        nptr++;
    } else {
        NODELIST[NLCOUNT].feedtype = ' ';
    }
    NODELIST[NLCOUNT].host = nptr;
    for (nptr++; *nptr && !isspace(*nptr);)
        nptr++;
    if (*nptr == '\0') {
        continue;
    }
    *nptr = '\0';
    for (nptr++; *nptr && isspace(*nptr);)
        nptr++;
    if (*nptr == '\0')
        continue;
    NODELIST[NLCOUNT].protocol = nptr;
    for (nptr++; *nptr && !isspace(*nptr);)
        nptr++;
    if (*nptr == '\0')
        continue;
    *nptr = '\0';
    for (nptr++; *nptr && strchr(" \t\r\n", *nptr);)
        nptr++;
    if (*nptr == '\0')
        continue;
    NODELIST[NLCOUNT].comments = nptr;
    }
    qsort(NODELIST, NLCOUNT, sizeof(nodelist_t), nlcmp);
    qsort(NODELIST_BYNODE, NLCOUNT, sizeof(nodelist_t *), nl_bynodecmp);
    return 0;
}

int
readnffile(char *inndhome)
{
    FILE           *fp;
    char            buff[1024];
    struct stat     st;
    int             i, count;
    char           *ptr, *newsfeedsptr;

    sprintf(buff, "%s/newsfeeds.bbs", inndhome);
    fp = fopen(buff, "r");
    if (fp == NULL) {
    fprintf(stderr, "open fail %s", buff);
    return -1;
    }
    if (fstat(fileno(fp), &st) != 0) {
    fprintf(stderr, "stat fail %s", buff);
    return -1;
    }
    if (NEWSFEEDS_BUF == NULL) {
    NEWSFEEDS_BUF = (char *)mymalloc(st.st_size + 1);
    } else {
    NEWSFEEDS_BUF = (char *)myrealloc(NEWSFEEDS_BUF, st.st_size + 1);
    }
    i = 0, count = 0;
    while (fgets(buff, sizeof buff, fp) != NULL) {
    if (buff[0] == '#')
        continue;
    if (buff[0] == '\n')
        continue;
    strcpy(NEWSFEEDS_BUF + i, buff);
    i += strlen(buff);
    count++;
    }
    fclose(fp);
    if (NEWSFEEDS == NULL) {
    NEWSFEEDS = (newsfeeds_t *) mymalloc(sizeof(newsfeeds_t) * (count + 1));
    NEWSFEEDS_BYBOARD = (newsfeeds_t **) mymalloc(sizeof(newsfeeds_t *) * (count + 1));
    } else {
    NEWSFEEDS = (newsfeeds_t *) myrealloc(NEWSFEEDS, sizeof(newsfeeds_t) * (count + 1));
    NEWSFEEDS_BYBOARD = (newsfeeds_t **) myrealloc(NEWSFEEDS_BYBOARD, sizeof(newsfeeds_t *) * (count + 1));
    }
    NFCOUNT = 0;
    for (ptr = NEWSFEEDS_BUF; (newsfeedsptr = (char *)strchr(ptr, '\n')) != NULL; ptr = newsfeedsptr + 1, NFCOUNT++) {
    char           *nptr;
    *newsfeedsptr = '\0';
    NEWSFEEDS[NFCOUNT].newsgroups = "";
    NEWSFEEDS[NFCOUNT].board = "";
    NEWSFEEDS[NFCOUNT].path = NULL;
    NEWSFEEDS_BYBOARD[NFCOUNT] = NEWSFEEDS + NFCOUNT;
    for (nptr = ptr; *nptr && isspace(*nptr);)
        nptr++;
    if (*nptr == '\0')
        continue;
    NEWSFEEDS[NFCOUNT].newsgroups = nptr;
    for (nptr++; *nptr && !isspace(*nptr);)
        nptr++;
    if (*nptr == '\0')
        continue;
    *nptr = '\0';
    for (nptr++; *nptr && isspace(*nptr);)
        nptr++;
    if (*nptr == '\0')
        continue;
    NEWSFEEDS[NFCOUNT].board = nptr;
    for (nptr++; *nptr && !isspace(*nptr);)
        nptr++;
    if (*nptr == '\0')
        continue;
    *nptr = '\0';
    for (nptr++; *nptr && isspace(*nptr);)
        nptr++;
    if (*nptr == '\0')
        continue;
    NEWSFEEDS[NFCOUNT].path = nptr;
    for (nptr++; *nptr && !strchr("\r\n", *nptr);)
        nptr++;
    *nptr = '\0';
    }
    qsort(NEWSFEEDS, NFCOUNT, sizeof(newsfeeds_t), nfcmp);
    qsort(NEWSFEEDS_BYBOARD, NFCOUNT, sizeof(newsfeeds_t *), nf_byboardcmp);
    return 0;
}

newsfeeds_t *
search_board(char *board)
{
    newsfeeds_t     nft, *nftptr, **find;
    if (NONENEWSFEEDS)
    return NULL;
    nft.board = board;
    nftptr = &nft;
    find = (newsfeeds_t **) bsearch((char *)&nftptr, NEWSFEEDS_BYBOARD, NFCOUNT, sizeof(newsfeeds_t *), nf_byboardcmp);
    if (find != NULL)
    return *find;
    return NULL;
}

nodelist_t *
search_nodelist_bynode(char *node)
{
    nodelist_t      nlt, *nltptr, **find;
    if (LOCALNODELIST)
    return NULL;
    nlt.node = node;
    nltptr = &nlt;
    find = (nodelist_t **) bsearch((char *)&nltptr, NODELIST_BYNODE, NLCOUNT, sizeof(nodelist_t *), nl_bynodecmp);
    if (find != NULL)
    return *find;
    return NULL;
}


nodelist_t *
search_nodelist(char *site, char *identuser)
{
    nodelist_t      nlt, *find;
    char            buffer[1024];
    if (LOCALNODELIST)
    return NULL;
    nlt.host = site;
    find = (nodelist_t *) bsearch((char *)&nlt, NODELIST, NLCOUNT, sizeof(nodelist_t), nlcmp);
    if (find == NULL && identuser != NULL) {
    sprintf(buffer, "%s@%s", identuser, site);
    nlt.host = buffer;
    find = (nodelist_t *) bsearch((char *)&nlt, NODELIST, NLCOUNT, sizeof(nodelist_t), nlcmp);
    }
    return find;
}

newsfeeds_t *
search_group(char *newsgroup)
{
    newsfeeds_t     nft, *find;
    if (NONENEWSFEEDS)
    return NULL;
    nft.newsgroups = newsgroup;
    find = (newsfeeds_t *) bsearch((char *)&nft, NEWSFEEDS, NFCOUNT, sizeof(newsfeeds_t), nfcmp);
    return find;
}

char *
ascii_date(time_t now)
{
    static char     datebuf[40];
    /*
     * time_t now; time(&now);
     */
    strftime(datebuf, sizeof(datebuf), "%d %b %Y %X " INNTIMEZONE, gmtime(&now));
    return datebuf;
}

char *
restrdup(char *ptr, char *string)
{
    int             len;
    if (string == NULL) {
    if (ptr != NULL)
        *ptr = '\0';
    return ptr;
    }
    len = strlen(string) + 1;
    if (ptr != NULL) {
    ptr = (char *)myrealloc(ptr, len);
    } else
    ptr = (char *)mymalloc(len);
    strcpy(ptr, string);
    return ptr;
}

void *
mymalloc(int size)
{
    void *ptr = malloc(size);
    if (ptr == NULL) {
    fprintf(stderr, "cant allocate memory\n");
    syslog(LOG_ERR, "cant allocate memory %m");
    exit(1);
    }
    return ptr;
}

void *
myrealloc(void *optr, int size)
{
    void *ptr = realloc(optr, size);
    if (ptr == NULL) {
    fprintf(stderr, "cant allocate memory\n");
    syslog(LOG_ERR, "cant allocate memory %m");
    exit(1);
    }
    return ptr;
}

void
testandmkdir(char *dir)
{
    if (!dashd(dir)) {
    char            path[MAXPATHLEN + 12];
    sprintf(path, "mkdir -p %s", dir);
    system(path);
    }
}

static char     splitbuf[2048];
static char     joinbuf[1024];
#define MAXTOK 50
static char    *Splitptr[MAXTOK];

char **
split(char *line, char *pat)
{
    char           *p;
    int             i;

    for (i = 0; i < MAXTOK; ++i)
    Splitptr[i] = NULL;
    strncpy(splitbuf, line, sizeof splitbuf - 1);
    /* printf("%d %d\n",strlen(line),strlen(splitbuf)); */
    splitbuf[sizeof splitbuf - 1] = '\0';
    for (i = 0, p = splitbuf; *p && i < MAXTOK - 1;) {
    for (Splitptr[i++] = p; *p && !strchr(pat, *p); p++);
    if (*p == '\0')
        break;
    for (*p++ = '\0'; *p && strchr(pat, *p); p++);
    }
    return Splitptr;
}

char **
BNGsplit(char *line)
{
    char          **ptr = split(line, ",");
    newsfeeds_t    *nf1, *nf2;
    char           *n11, *n12, *n21, *n22;
    int             i, j;
    for (i = 0; ptr[i] != NULL; i++) {
    nf1 = (newsfeeds_t *) search_group(ptr[i]);
    for (j = i + 1; ptr[j] != NULL; j++) {
        if (strcmp(ptr[i], ptr[j]) == 0) {
        *ptr[j] = '\0';
        continue;
        }
        nf2 = (newsfeeds_t *) search_group(ptr[j]);
        if (nf1 && nf2) {
        if (strcmp(nf1->board, nf2->board) == 0) {
            *ptr[j] = '\0';
            continue;
        }
        for (n11 = nf1->board, n12 = (char *)strchr(n11, ',');
             n11 && *n11; n12 = (char *)strchr(n11, ',')) {
            if (n12)
            *n12 = '\0';
            for (n21 = nf2->board, n22 = (char *)strchr(n21, ',');
             n21 && *n21; n22 = (char *)strchr(n21, ',')) {
            if (n22)
                *n22 = '\0';
            if (strcmp(n11, n21) == 0) {
                *n21 = '\t';
            }
            if (n22) {
                *n22 = ',';
                n21 = n22 + 1;
            } else
                break;
            }
            if (n12) {
            *n12 = ',';
            n11 = n12 + 1;
            } else
            break;
        }
        }
    }
    }
    return ptr;
}

char **
ssplit(char *line, char *pat)
{
    char           *p;
    int             i;
    for (i = 0; i < MAXTOK; ++i)
    Splitptr[i] = NULL;
    strncpy(splitbuf, line, 1024);
    for (i = 0, p = splitbuf; *p && i < MAXTOK;) {
    for (Splitptr[i++] = p; *p && !strchr(pat, *p); p++);
    if (*p == '\0')
        break;
    *p = 0;
    p++;
    /* for (*p='\0'; strchr(pat,*p);p++); */
    }
    return Splitptr;
}

char *
join(char **lineptr, char *pat, int num)
{
    int             i;
    joinbuf[0] = '\0';
    if (lineptr[0] != NULL)
    strncpy(joinbuf, lineptr[0], 1024);
    else {
    joinbuf[0] = '\0';
    return joinbuf;
    }
    for (i = 1; i < num; i++) {
    strcat(joinbuf, pat);
    if (lineptr[i] != NULL)
        strcat(joinbuf, lineptr[i]);
    else
        break;
    }
    return joinbuf;
}

#ifdef BBSLIB
main()
{
    initial_bbs("feed");
    printf("%s\n", ascii_date());
}
#endif