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

                                       
   
                                           
   
                                                                    
   
                                                          
   
                                                                         
   
                                     
   






                                                                                
   











                                                                             
                            
 
                                                                                       









                                                 

                                          






                    
                  


              
                      





                                       


                             
 

                                           
 







                                                            

                


                                                   

      






                                                                                                                        
                      
 


                 




                                         

                                     
 






                                                  
     





                                                          
     

                                                
     





                                                                                                                        
     











                                                                                

               






























                                                                                                                            




                                          


                             
 































                                                                                                                        
                      

 


                 


 
                          




                          












                                                          

                        
                               
                                                                        





                                                                                
                                                                     

                                                                              

      



                                                          
                        






                                                                                         
      
     
 



                                                         
                        






                                                                                         
      
     
 



                                                            
                        






                                                                                         
      
     































                                                    
     



                                                  
     
 







                                                         
                













                                                           
     

      





                                                                                              
     
                     

                
                  

      



                                         
 

                                                                   
 

























































                                                                                                                                                                 
     








                                                                   
     
             



                 































                                                                                                         
     
             


                           
                          
 









                                                          

            
                                                 

      


                                 
     









                                                   
         






































































                                                                                                                    

                  












                                                                                                     
      




                                                                          
     



                                                                  

      








                                                          
     















                                                                       
     
             







                                                                                       
                
                                                                     



                                         
 



















                                                              
     












                                                              
     

            
                                    

      



                                  

                
                                                           

      



                                                                  
     








                                                            
     
                                           

                



                                           

     










                                                                            

      



                                                  
                           

                


  

                         
 
                            
 
                             
 


                                           
 

                                            


 
                                                
 
















                                                                                        






                                  




                                       



                     

                          
 


                                         






                                            




                                 
 
                            
 


                                                                        
 
                                                 

                   
                                                 

      





                                                                          

                   
                                                         

      


                   
     






                                                                                 
 
                                                                   
                   
                                                      

      






                               
     


                                                                         

                   
                                                   

      



                           

                       
             


                                     

                                 
 











                                                                
     


































                                                                                        
     

              


                      

                     

                   
                
                                                                     



                                         
 






















                                                                

            
                                        

      
                                      

                
                                                               

      














                                                              
     

                       





                                                                

      
                


                                     

                                 
 
                          

                        

                          
 

                                                                

      



                                                                          

                       
                                                                













                                                                               
                          


      
/*
 * BBS implementation dependendent part
 * 
 * The only two interfaces you must provide
 * 
 * #include "inntobbs.h" int receive_article(); 0 success not 0 fail
 * 
 * if (storeDB(HEADER[MID_H], hispaths) < 0) { .... fail }
 * 
 * int cancel_article_front( char *msgid );          0 success not 0 fail
 * 
 * char *ptr = (char*)DBfetch(msgid);
 * 
 * 收到之文章內容 (body)在 char *BODY, 檔頭 (header)在 char *HEADER[] SUBJECT_H,
 * FROM_H, DATE_H, MID_H, NEWSGROUPS_H, NNTPPOSTINGHOST_H, NNTPHOST_H,
 * CONTROL_H, PATH_H, ORGANIZATION_H
 */

/*
 * Sample Implementation
 * 
 * receive_article()         --> post_article()   --> bbspost_write_post();
 * cacnel_article_front(mid) --> cancel_article() --> bbspost_write_cancel();
 */


#ifndef PowerBBS
#include "innbbsconf.h"
#include "daemon.h"
#include "bbslib.h"
#include "inntobbs.h"
#include "antisplam.h"

extern int      Junkhistory;

char           *post_article ARG((char *, char *, char *, int (*) (), char *, char *));
int cancel_article ARG((char *, char *, char *));


#ifdef  MapleBBS
#include "config.h"
#include "pttstruct.h"
#define _BBS_UTIL_C_
#else
report()
{
    /* Function called from record.o */
    /* Please leave this function empty */
}
#endif


#if defined(PalmBBS)

#ifndef PATH
#define PATH XPATH
#endif

#ifndef HEADER
#define HEADER XHEADER
#endif

#endif

/* process post write */
bbspost_write_post(fh, board, filename)
    int             fh;
    char           *board;
    char           *filename;
{
    char           *fptr, *ptr;
    FILE           *fhfd = fdopen(fh, "w");

    if (fhfd == NULL) {
    bbslog("can't fdopen, maybe disk full\n");
    return -1;
    }
    fprintf(fhfd, "發信人: %.60s, 看板: %s\n", FROM, board);
    fprintf(fhfd, "標  題: %.70s\n", SUBJECT);
    fprintf(fhfd, "發信站: %.43s (%s)\n", SITE, DATE);
    fprintf(fhfd, "轉信站: %.70s\n", PATH);

#ifndef MapleBBS
    if (POSTHOST != NULL) {
    fprintf(fhfd, "Origin: %.70s\n", POSTHOST);
    }
#endif

    fprintf(fhfd, "\n");
    for (fptr = BODY, ptr = strchr(fptr, '\r'); ptr != NULL && *ptr != '\0'; fptr = ptr + 1, ptr = strchr(fptr, '\r')) {
    int             ch = *ptr;
    *ptr = '\0';
    fputs(fptr, fhfd);
    *ptr = ch;
    }
    fputs(fptr, fhfd);

    fflush(fhfd);
    fclose(fhfd);
    return 0;
}

#ifdef  KEEP_NETWORK_CANCEL
/* process cancel write */
bbspost_write_cancel(fh, board, filename)
    int             fh;
    char           *board, *filename;
{
    char           *fptr, *ptr;
    FILE           *fhfd = fdopen(fh, "w"), *fp;
    char            buffer[256];

    if (fhfd == NULL) {
    bbslog("can't fdopen, maybe disk full\n");
    return -1;
    }
    fprintf(fhfd, "發信人: %s, 信區: %s\n", FROM, board);
    fprintf(fhfd, "標  題: %s\n", SUBJECT);
    fprintf(fhfd, "發信站: %.43s (%s)\n", SITE, DATE);
    fprintf(fhfd, "轉信站: %.70s\n", PATH);
    if (HEADER[CONTROL_H] != NULL) {
    fprintf(fhfd, "Control: %s\n", HEADER[CONTROL_H]);
    }
    if (POSTHOST != NULL) {
    fprintf(fhfd, "Origin: %s\n", POSTHOST);
    }
    fprintf(fhfd, "\n");
    for (fptr = BODY, ptr = strchr(fptr, '\r'); ptr != NULL && *ptr != '\0'; fptr = ptr + 1, ptr = strchr(fptr, '\r')) {
    int             ch = *ptr;
    *ptr = '\0';
    fputs(fptr, fhfd);
    *ptr = ch;
    }
    fputs(fptr, fhfd);
    if (POSTHOST != NULL) {
    fprintf(fhfd, "\n * Origin: ● %.26s ● From: %.40s\n", SITE, POSTHOST);
    }
    fprintf(fhfd, "\n---------------------\n");
    fp = fopen(filename, "r");
    if (fp == NULL) {
    bbslog("can't open %s\n", filename);
    return -1;
    }
    while (fgets(buffer, sizeof buffer, fp) != NULL) {
    fputs(buffer, fhfd);
    }
    fclose(fp);
    fflush(fhfd);
    fclose(fhfd);

    {
    fp = fopen(filename, "w");
    if (fp == NULL) {
        bbslog("can't write %s\n", filename);
        return -1;
    }
    fprintf(fp, "發信人: %s, 信區: %s\n", FROM, board);
    fprintf(fp, "標  題: %.70s\n", SUBJECT);
    fprintf(fp, "發信站: %.43s (%s)\n", SITE, DATE);
    fprintf(fp, "轉信站: %.70s\n", PATH);
    if (POSTHOST != NULL) {
        fprintf(fhfd, "Origin: %s\n", POSTHOST);
    }
    if (HEADER[CONTROL_H] != NULL) {
        fprintf(fhfd, "Control: %s\n", HEADER[CONTROL_H]);
    }
    fprintf(fp, "\n");
    for (fptr = BODY, ptr = strchr(fptr, '\r'); ptr != NULL && *ptr != '\0'; fptr = ptr + 1, ptr = strchr(fptr, '\r')) {
        *ptr = '\0';
        fputs(fptr, fp);
    }
    fputs(fptr, fp);
    if (POSTHOST != NULL) {
        fprintf(fp, "\n * Origin: ● %.26s ● From: %.40s\n", SITE, POSTHOST);
    }
    fclose(fp);
    }
    return 0;
}
#endif


bbspost_write_control(fh, board, filename)
    int             fh;
    char           *board;
    char           *filename;
{
    char           *fptr, *ptr;
    FILE           *fhfd = fdopen(fh, "w");

    if (fhfd == NULL) {
    bbslog("can't fdopen, maybe disk full\n");
    return -1;
    }
    fprintf(fhfd, "Path: %s!%s\n", MYBBSID, HEADER[PATH_H]);
    fprintf(fhfd, "From: %s\n", FROM);
    fprintf(fhfd, "Newsgroups: %s\n", GROUPS);
    fprintf(fhfd, "Subject: %s\n", SUBJECT);
    fprintf(fhfd, "Date: %s\n", DATE);
    fprintf(fhfd, "Organization: %s\n", SITE);
    if (POSTHOST != NULL) {
    fprintf(fhfd, "NNTP-Posting-Host: %.70s\n", POSTHOST);
    }
    if (HEADER[CONTROL_H] != NULL) {
    fprintf(fhfd, "Control: %s\n", HEADER[CONTROL_H]);
    }
    if (HEADER[APPROVED_H] != NULL) {
    fprintf(fhfd, "Approved: %s\n", HEADER[APPROVED_H]);
    }
    if (HEADER[DISTRIBUTION_H] != NULL) {
    fprintf(fhfd, "Distribution: %s\n", HEADER[DISTRIBUTION_H]);
    }
    fprintf(fhfd, "\n");
    for (fptr = BODY, ptr = strchr(fptr, '\r'); ptr != NULL && *ptr != '\0'; fptr = ptr + 1, ptr = strchr(fptr, '\r')) {
    int             ch = *ptr;
    *ptr = '\0';
    fputs(fptr, fhfd);
    *ptr = ch;
    }
    fputs(fptr, fhfd);


    fflush(fhfd);
    fclose(fhfd);
    return 0;
}


time_t          datevalue;


/* process cancel write */
receive_article()
{
    int             i;
    char           *user, *userptr;
    char           *ngptr, *nngptr, *pathptr;
    char          **splitptr;
    static char     userid[32];
    static char     xdate[32];
    static char     xpath[180];
    newsfeeds_t    *nf;
    char           *boardhome;
    char            hispaths[4096];
    char            firstpath[MAXPATHLEN], *firstpathbase;
    char           *lesssym, *nameptrleft, *nameptrright;
    static char     sitebuf[80];

#ifdef HMM_USE_ANTI_SPAM
    char           *notitle[] =
    {"行銷", "業務代表", "徵", "資訊", "免費", "大贈送", "傳銷", "未滿",
    "年費", "傳呼", "價", "操你媽", "未成年", "馬賽克", "信用", "賺錢",
    "=?", "!!!",
    "操你", "操你", "幹妳", "操妳", "**", "★★", "**", "$$", "泡麵", NULL},
                   *nofrom[] =
    {"TaipeiNet.Net", "hotmail.com", "mt.touc.edu.tw", "ms11.hinet.net", NULL},
                   *nocont[] =
    {"名額有限", "優惠價", "動作要快", "訂購", "特價", "專賣", "BBC",
    "幹你", "操你", "幹妳", "操妳", "每片", "最新目錄", "http://", "收錢",
    "創業", "付款", "廣告信", "只賣", "市價", "NCg", "ICAg", NULL};
#endif

    if (FROM == NULL) {
    bbslog(":Err: article without usrid %s\n", MSGID);
    return 0;
    } else {
#ifdef HMM_USE_ANTI_SPAM
    for (i = 0; nofrom[i]; i++)
        if (strstr(FROM, nofrom[i])) {
        morelog_to(INNBBSD_SPAM, "spam from [%s]: %s\n", nofrom[i], FROM);
        morelog_to(INNBBSD_SPAM, "  %s %s %s %s\n", FROM, PATH, GROUPS, SUBJECT);
        bbslog(":Ptt: spam from [%s]: %s\n", nofrom[i], FROM);
        return 0;
        }
#endif
    }

    if (!BODY) {
    bbslog(":Err: article without body %s\n", MSGID);
    return 0;
    } else {
#ifdef HMM_USE_ANTI_SPAM
    for (i = 0; nocont[i]; i++)
        if (strstr(BODY, nocont[i])) {
        morelog_to(INNBBSD_SPAM, "spam body [%s]: %s\n", nocont[i]);
        morelog_to(INNBBSD_SPAM, "  %s %s %s %s\n", FROM, PATH, GROUPS, SUBJECT);
        bbslog(":Ptt: spam body [%s]: %s\n", nocont[i]);
        return 0;
        }
#endif
    }

    if (!SUBJECT) {
    bbslog(":Err: article without subject %s\n", MSGID);
    return 0;
    } else {
#ifdef HMM_USE_ANTI_SPAM
    for (i = 0; notitle[i]; i++)
        if (strstr(SUBJECT, notitle[i])) {
        morelog_to(INNBBSD_SPAM, "spam title [%s]: %s\n", notitle[i], SUBJECT);
        morelog_to(INNBBSD_SPAM, "  %s %s %s %s\n", FROM, PATH, GROUPS, SUBJECT);
        bbslog(":Ptt: spam title [%s]: %s\n", notitle[i], SUBJECT);
        return 0;
        }
#endif
    }


    user = (char *)strchr(FROM, '@');
    lesssym = (char *)strchr(FROM, '<');
    nameptrleft = NULL, nameptrright = NULL;
    if (lesssym == NULL || lesssym >= user) {
    lesssym = FROM;
    nameptrleft = strchr(FROM, '(');
    if (nameptrleft != NULL)
        nameptrleft++;
    nameptrright = strrchr(FROM, ')');
    } else {
    nameptrleft = FROM;
    nameptrright = strrchr(FROM, '<');
    lesssym++;
    }
    if (user != NULL) {
    *user = '\0';
    userptr = (char *)strchr(FROM, '.');
    if (userptr != NULL) {
        *userptr = '\0';
        strncpy(userid, lesssym, sizeof userid);
        *userptr = '.';
    } else {
        strncpy(userid, lesssym, sizeof userid);
    }
    *user = '@';
    } else {
    strncpy(userid, lesssym, sizeof userid);
    }
    strcat(userid, ".");

    {
    struct tm       tmbuf;

    strptime(DATE, "%d %b %Y %X GMT", &tmbuf);
    datevalue = timegm(&tmbuf);
    }

    if (datevalue > 0) {
    char           *p;
    strncpy(xdate, ctime(&datevalue), sizeof(xdate));
    p = (char *)strchr(xdate, '\n');
    if (p != NULL)
        *p = '\0';
    DATE = xdate;
    }
#ifndef MapleBBS
    if (SITE == NULL || *SITE == '\0') {
    if (nameptrleft != NULL && nameptrright != NULL) {
        char            savech = *nameptrright;
        *nameptrright = '\0';
        strncpy(sitebuf, nameptrleft, sizeof sitebuf);
        *nameptrright = savech;
        SITE = sitebuf;
    } else
        /* SITE = "(Unknown)"; */
        SITE = "";
    }
    if (strlen(MYBBSID) > 70) {
    bbslog(" :Err: your bbsid %s too long\n", MYBBSID);
    return 0;
    }
#endif

    sprintf(xpath, "%s!%.*s", MYBBSID, sizeof(xpath) - strlen(MYBBSID) - 2, PATH);
    PATH = xpath;
    for (pathptr = PATH; pathptr != NULL && (pathptr = strstr(pathptr, ".edu.tw")) != NULL;) {
    if (pathptr != NULL) {
        strcpy(pathptr, pathptr + 7);
    }
    }
    xpath[71] = '\0';

#ifndef MapleBBS
    echomaillog();
#endif

    *hispaths = '\0';
    splitptr = (char **)BNGsplit(GROUPS);
    firstpath[0] = '\0';
    firstpathbase = firstpath;

    for (ngptr = *splitptr; ngptr != NULL; ngptr = *(++splitptr)) {
    char           *boardptr, *nboardptr;

    if (*ngptr == '\0')
        continue;
    nf = (newsfeeds_t *) search_group(ngptr);
    if (nf == NULL) {
        bbslog("unwanted \'%s\'\n", ngptr);
        continue;
    }
    if (nf->board == NULL || !*nf->board)
        continue;
    if (nf->path == NULL || !*nf->path)
        continue;
    for (boardptr = nf->board, nboardptr = (char *)strchr(boardptr, ','); boardptr != NULL && *boardptr != '\0'; nboardptr = (char *)strchr(boardptr, ',')) {
        if (nboardptr != NULL) {
        *nboardptr = '\0';
        }
        if (*boardptr == '\t') {
        goto boardcont;
        }
        boardhome = (char *)fileglue("%s/boards/%c/%s", BBSHOME, boardptr[0], boardptr);
        if (!isdir(boardhome)) {
        bbslog(":Err: unable to write %s\n", boardhome);
        } else {
        char           *fname;
        /*
         * if ( !isdir( boardhome )) { bbslog( ":Err: unable to write
         * %s\n",boardhome); testandmkdir(boardhome); }
         */
        fname = (char *)post_article(boardhome, userid, boardptr,
                       bbspost_write_post, NULL, firstpath);
        if (fname != NULL) {
            fname = (char *)fileglue("%s/%s", boardptr, fname);
            if (firstpath[0] == '\0') {
            sprintf(firstpath, "%s/boards/%c, %s", BBSHOME, fname[0], fname);
            firstpathbase = firstpath + strlen(BBSHOME) + strlen("/boards/x/");
            }
            if (strlen(fname) + strlen(hispaths) + 1 < sizeof(hispaths)) {
            strcat(hispaths, fname);
            strcat(hispaths, " ");
            }
        } else {
            bbslog("fname is null %s\n", boardhome);
            return -1;
        }
        }

    boardcont:
        if (nboardptr != NULL) {
        *nboardptr = ',';
        boardptr = nboardptr + 1;
        } else
        break;

    }           /* for board1,board2,... */
    /*
     * if (nngptr != NULL) ngptr = nngptr + 1; else break;
     */
    if (*firstpathbase)
        feedfplog(nf, firstpathbase, 'P');
    }
    if (*hispaths)
    bbsfeedslog(hispaths, 'P');

    if (Junkhistory || *hispaths) {
    if (storeDB(HEADER[MID_H], hispaths) < 0) {
        bbslog("store DB fail\n");
        /* I suspect here will introduce duplicated articles */
        /* return -1; */
    }
    }
    return 0;
}

receive_control()
{
    char           *boardhome, *fname;
    char            firstpath[MAXPATHLEN], *firstpathbase;
    char          **splitptr, *ngptr;
    newsfeeds_t    *nf;

    bbslog("control post %s\n", HEADER[CONTROL_H]);
    boardhome = (char *)fileglue("%s/boards/c/control", BBSHOME);
    testandmkdir(boardhome);
    *firstpath = '\0';
    if (isdir(boardhome)) {
    fname = (char *)post_article(boardhome, FROM, "control", bbspost_write_control, NULL, firstpath);
    if (fname != NULL) {
        if (firstpath[0] == '\0')
        sprintf(firstpath, "%s/boards/c/control/%s", BBSHOME, fname);
        if (storeDB(HEADER[MID_H], (char *)fileglue("control/%s", fname)) < 0) {
        }
        bbsfeedslog(fileglue("control/%s", fname), 'C');
        firstpathbase = firstpath + strlen(BBSHOME) + strlen("/boards/x/");
        splitptr = (char **)BNGsplit(GROUPS);
        for (ngptr = *splitptr; ngptr != NULL; ngptr = *(++splitptr)) {
        if (*ngptr == '\0')
            continue;
        nf = (newsfeeds_t *) search_group(ngptr);
        if (nf == NULL)
            continue;
        if (nf->board == NULL)
            continue;
        if (nf->path == NULL)
            continue;
        feedfplog(nf, firstpathbase, 'C');
        }
    }
    }
    return 0;
}

cancel_article_front(msgid)
    char           *msgid;
{
    char           *ptr = (char *)DBfetch(msgid);
    char           *filelist, filename[2048];
    char            histent[4096];
    char            firstpath[MAXPATHLEN], *firstpathbase;
    if (ptr == NULL) {
    bbslog("cancel failed(DBfetch): %s\n", msgid);
    return 0;
    }
    strncpy(histent, ptr, sizeof histent);
    ptr = histent;

#ifdef DEBUG
    printf("**** try to cancel %s *****\n", ptr);
#endif

    filelist = strchr(ptr, '\t');
    if (filelist != NULL) {
    filelist++;
    }
    *firstpath = '\0';
    for (ptr = filelist; ptr && *ptr;) {
    char           *file;
    for (; *ptr && isspace(*ptr); ptr++);
    if (*ptr == '\0')
        break;
    file = ptr;
    for (ptr++; *ptr && !isspace(*ptr); ptr++);
    if (*ptr != '\0') {
        *ptr++ = '\0';
    }
    sprintf(filename, "%s/boards/%c/%s", BBSHOME, file[0], file);
    bbslog("cancel post %s\n", filename);
    if (isfile(filename)) {
        FILE           *fp = fopen(filename, "r");
        char            buffer[1024];
        char            xfrom0[100], xfrom[100], xpath[1024], *boardhome;

        if (fp == NULL)
        continue;
        strncpy(xfrom0, HEADER[FROM_H], 99);
        xfrom0[99] = 0;
        strtok(xfrom0, ", ");
        while (fgets(buffer, sizeof buffer, fp) != NULL) {
        char           *hptr;
        if (buffer[0] == '\n')
            break;
        hptr = strchr(buffer, '\n');
        if (hptr != NULL)
            *hptr = '\0';
        if (strncmp(buffer, "發信人: ", 8) == 0) {
            strncpy(xfrom, buffer + 8, 99);
            xfrom[99] = 0;
            strtok(xfrom, ", ");
        } else if (strncmp(buffer, "轉信站: ", 8) == 0) {
            strcpy(xpath, buffer + 8);
        }
        }
        fclose(fp);
        if (strcmp(xfrom0, xfrom)) {
        bbslog("Invalid cancel %s, path: %s!%s, [`%s` != `%s`]\n",
               FROM, MYBBSID, PATH, xfrom0, xfrom);
        return 0;
        }
#ifdef  KEEP_NETWORK_CANCEL
        bbslog("cancel post %s\n", filename);
        boardhome = (char *)fileglue("%s/boards/d/deleted", BBSHOME);
        testandmkdir(boardhome);
        if (isdir(boardhome)) {
        char            subject[1024];
        char           *fname;
        if (POSTHOST) {
            sprintf(subject, "cancel by: %.1000s", POSTHOST);
        } else {
            char           *body, *body2;
            body = strchr(BODY, '\r');
            if (body != NULL)
            *body = '\0';
            body2 = strchr(BODY, '\n');
            if (body2 != NULL)
            *body = '\0';
            sprintf(subject, "%.1000s", BODY);
            if (body != NULL)
            *body = '\r';
            if (body2 != NULL)
            *body = '\n';
        }
        if (*subject) {
            SUBJECT = subject;
        }
        fname = (char *)post_article(boardhome, FROM, "deleted", bbspost_write_cancel, filename, firstpath);
        if (fname != NULL) {
            if (firstpath[0] == '\0') {
            sprintf(firstpath, "%s/boards/d/deleted/%s", BBSHOME, fname);
            firstpathbase = firstpath + strlen(BBSHOME) + strlen("/boards/x/");
            }
            if (storeDB(HEADER[MID_H], (char *)fileglue("deleted/%s", fname)) < 0) {
            /* should do something */
            bbslog("store DB fail\n");
            /* return -1; */
            }
            bbsfeedslog(fileglue("deleted/%s", fname), 'D');

#ifdef OLDDISPATCH
            {
            char            board[256];
            newsfeeds_t    *nf;
            char           *filebase = filename + strlen(BBSHOME) + strlen("/boards/x/");
            char           *filetail = strrchr(filename, '/');
            if (filetail != NULL) {
                strncpy(board, filebase, filetail - filebase);
                nf = (newsfeeds_t *) search_board(board);
                if (nf != NULL && nf->board && nf->path) {
                feedfplog(nf, firstpathbase, 'D');
                }
            }
            }
#endif
        } else {
            bbslog(" fname is null %s %s\n", boardhome, filename);
            return -1;
        }
        }
#else
        /* bbslog("**** %s should be removed\n", filename); */
        /*
         * unlink(filename);
         */
#endif

        {
        char           *fp = strrchr(file, '/');
        if (fp != NULL) {
            *fp = '\0';
            cancel_article(BBSHOME, file, fp + 1);
            *fp = '/';
        }
        }
    }
    }
    if (*firstpath) {
    char          **splitptr, *ngptr;
    newsfeeds_t    *nf;
    splitptr = (char **)BNGsplit(GROUPS);
    for (ngptr = *splitptr; ngptr != NULL; ngptr = *(++splitptr)) {
        if (*ngptr == '\0')
        continue;
        nf = (newsfeeds_t *) search_group(ngptr);
        if (nf == NULL)
        continue;
        if (nf->board == NULL)
        continue;
        if (nf->path == NULL)
        continue;
        feedfplog(nf, firstpathbase, 'D');
    }
    }
    return 0;
}


#if defined(PhoenixBBS) || defined(SecretBBS) || defined(PivotBBS) || defined(MapleBBS)
/* for PhoenixBBS's post article and cancel article */
#include "config.h"


char           *
post_article(homepath, userid, board, writebody, pathname, firstpath)
    char           *homepath;
    char           *userid, *board;
    int             (*writebody) ();
    char           *pathname, *firstpath;
{
    struct userec_t record;
    struct fileheader_t header;
    char           *subject = SUBJECT;
    char            index[MAXPATHLEN];
    static char     name[MAXPATHLEN];
    char            article[MAXPATHLEN];
    char            buf[MAXPATHLEN], *ptr;
    FILE           *fidx;
    int             fh, bid;
    time_t          now;
    int             linkflag;
    /*
     * Ptt if(bad_subject(subject))  return NULL;
     */
    sprintf(index, "%s/.DIR", homepath);
    if ((fidx = fopen(index, "r")) == NULL) {
    if ((fidx = fopen(index, "w")) == NULL) {
        bbslog(":Err: Unable to post in %s.\n", homepath);
        return NULL;
    }
    }
    fclose(fidx);

    now = time(NULL);
    while (1) {
    sprintf(name, "M.%d.A", ++now);
    sprintf(article, "%s/%s", homepath, name);
    fh = open(article, O_CREAT | O_EXCL | O_WRONLY, 0644);
    if (fh >= 0)
        break;
    if (errno != EEXIST) {
        bbslog(" Err: can't writable or other errors\n");
        return NULL;
    }
    }

#ifdef DEBUG
    printf("post to %s\n", article);
#endif

    linkflag = 1;
    if (firstpath && *firstpath) {
    close(fh);
    unlink(article);

#ifdef DEBUGLINK
    bbslog("try to link %s to %s", firstpath, article);
#endif

    linkflag = link(firstpath, article);
    if (linkflag) {
        fh = open(article, O_CREAT | O_EXCL | O_WRONLY, 0644);
    }
    }
    if (linkflag) {
    if (writebody) {
        if ((*writebody) (fh, board, pathname) < 0)
        return NULL;
    } else {
        if (bbspost_write_post(fh, board, pathname) < 0)
        return NULL;
    }
    close(fh);
    }
    bzero((void *)&header, sizeof(header));

#ifndef MapleBBS
    strcpy(header.filename, name);
    strncpy(header.owner, userid, IDLEN);
    strncpy(header.title, subject, STRLEN);
    header.filename[STRLEN - 1] = 'M';
#else

    strcpy(header.filename, name);
    if (userid[IDLEN])
    strcpy(&userid[IDLEN], ".");
    strcpy(header.owner, userid);
    strncpy(header.title, subject, TTLEN);
    header.filemode |= FILE_MULTI;
    {
    struct tm      *ptime;
    ptime = localtime(&datevalue);
    sprintf(header.date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday);
    }
#endif

    append_record(index, &header, sizeof(header));

    if ((bid = getbnum(board)) > 0) {
    touchbtotal(bid);
    touchdircache(bid);
    }
    return name;
}

/*
 * woju Cross-fs rename()
 */

Rename(char *src, char *dst)
{
    char            cmd[200];

    bbslog("Rename: %s -> %s\n", src, dst);
    if (rename(src, dst) == 0)
    return 0;

    sprintf(cmd, "/bin/mv %s %s", src, dst);
    return system(cmd);
}


cancelpost(fileheader_t * fhdr, char *boardname)
{
    int             fd;
    char            fpath[MAXPATHLEN];

    sprintf(fpath, BBSHOME "/boards/%c/%s/%s", boardname[0], boardname, fhdr->filename);
    if ((fd = open(fpath, O_RDONLY)) >= 0) {
    fileheader_t    postfile;
    char            fn2[MAXPATHLEN] = BBSHOME "/boards/d/deleted",
                   *junkdir;

    stampfile(fn2, &postfile);
    memcpy(postfile.owner, fhdr->owner, IDLEN + TTLEN + 10);
    close(fd);
    Rename(fpath, fn2);
    strcpy(strrchr(fn2, '/') + 1, ".DIR");
    append_record(fn2, &postfile, sizeof(postfile));
    } else
    bbslog("cancelpost: %s opened error\n", fpath);
}


/* ---------------------------- */
/* new/old/lock file processing */
/* ---------------------------- */

typedef struct {
    char            newfn[MAXPATHLEN];
    char            oldfn[MAXPATHLEN];
    char            lockfn[MAXPATHLEN];
}               nol;


static void
nolfilename(n, fpath)
    nol            *n;
    char           *fpath;
{
    sprintf(n->newfn, "%s.new", fpath);
    sprintf(n->oldfn, "%s.old", fpath);
    sprintf(n->lockfn, "%s.lock", fpath);
}



int
delete_record(char *fpath, int size, int id)
{
    nol             my;
    char            abuf[512];
    int             fdr, fdw, fd;
    int             count;
    fileheader_t    fhdr;

    nolfilename(&my, fpath);

    if ((fd = open(my.lockfn, O_RDWR | O_CREAT | O_APPEND, 0644)) == -1)
    return -1;
    flock(fd, LOCK_EX);

    if ((fdr = open(fpath, O_RDONLY, 0)) == -1) {

#ifdef  HAVE_REPORT
    report("delete_record failed!!! (open)");
#endif

    flock(fd, LOCK_UN);
    close(fd);
    return -1;
    }
    if ((fdw = open(my.newfn, O_WRONLY | O_CREAT | O_EXCL, 0644)) == -1) {
    flock(fd, LOCK_UN);

#ifdef  HAVE_REPORT
    report("delete_record failed!!! (open tmpfile)");
#endif

    close(fd);
    close(fdr);
    return -1;
    }
    count = 1;
    while (read(fdr, abuf, size) == size) {
    if (id == count) {
        memcpy(&fhdr, abuf, sizeof(fhdr));
        bbslog("delete_record: %d, %s, %s\n", count, fhdr.owner, fhdr.title);
    }
    if (id != count++ && (write(fdw, abuf, size) == -1)) {

        bbslog("delete_record: %s failed!!! (write)\n", fpath);
#ifdef  HAVE_REPORT
        report("delete_record failed!!! (write)");
#endif

        unlink(my.newfn);
        close(fdr);
        close(fdw);
        flock(fd, LOCK_UN);
        close(fd);
        return -1;
    }
    }
    close(fdr);
    close(fdw);
    if (Rename(fpath, my.oldfn) == -1 || Rename(my.newfn, fpath) == -1) {

#ifdef  HAVE_REPORT
    report("delete_record failed!!! (Rename)");
#endif

    flock(fd, LOCK_UN);
    close(fd);
    return -1;
    }
    flock(fd, LOCK_UN);
    close(fd);
    return 0;
}

cancel_article(homepath, board, file)
    char           *homepath;
    char           *board, *file;
{
    struct fileheader_t header;
    struct stat     state;
    char            dirname[MAXPATHLEN];
    char            buf[MAXPATHLEN];
    long            numents, size, time, now;
    int             fd, lower, ent;


    if (file == NULL || file[0] != 'M' || file[1] != '.' ||
    (time = atoi(file + 2)) <= 0) {
    bbslog("cancel_article: invalid filename `%s`\n", file);
    return 0;
    }
    size = sizeof(header);
    sprintf(dirname, "%s/boards/%c/%s/.DIR", homepath, board[0], board);
    if ((fd = open(dirname, O_RDONLY)) == -1) {
    bbslog("cancel_article: open `%s` error\n", dirname);
    return 0;
    }
    fstat(fd, &state);
    ent = ((long)state.st_size) / size;
    lower = 0;
    while (1) {
    ent -= 8;
    if (ent <= 0 || lower >= 2)
        break;
    lseek(fd, size * ent, SEEK_SET);
    if (read(fd, &header, size) != size) {
        ent = 0;
        break;
    }
    now = atoi(header.filename + 2);
    lower = (now < time) ? lower + 1 : 0;
    }
    if (ent < 0)
    ent = 0;
    while (read(fd, &header, size) == size) {
    if (strcmp(file, header.filename) == 0) {
        if ((header.filemode & FILE_MARKED)
         || (header.filemode & FILE_DIGEST) || (header.owner[0] == '-'))
        break;
        delete_record(dirname, sizeof(fileheader_t), lseek(fd, 0, SEEK_CUR) / size);
        cancelpost(&header, board);
        break;
    }
    now = atoi(header.filename + 2);
    if (now > time)
        break;
    }
    close(fd);
    return 0;
}

#elif defined(PalmBBS)
#undef PATH XPATH
#undef HEADER XHEADER
#include "server.h"

char           *
post_article(homepath, userid, board, writebody, pathname, firstpath)
    char           *homepath;
    char           *userid, *board;
    int             (*writebody) ();
    char           *pathname, *firstpath;
{
    PATH            msgdir, msgfile;
    static PATH     name;

    READINFO        readinfo;
    SHORT           fileid;
    char            buf[MAXPATHLEN];
    struct stat     stbuf;
    int             fh;

    strcpy(msgdir, homepath);
    if (stat(msgdir, &stbuf) == -1 || !S_ISDIR(stbuf.st_mode)) {
    /* A directory is missing! */
    bbslog(":Err: Unable to post in %s.\n", msgdir);
    return NULL;
    }
    get_filelist_ids(msgdir, &readinfo);

    for (fileid = 1; fileid <= BBS_MAX_FILES; fileid++) {
    int             oumask;
    if (test_readbit(&readinfo, fileid))
        continue;
    fileid_to_fname(msgdir, fileid, msgfile);
    sprintf(name, "%04x", fileid);

#ifdef DEBUG
    printf("post to %s\n", msgfile);
#endif

    if (firstpath && *firstpath) {

#ifdef DEBUGLINK
        bbslog("try to link %s to %s", firstpath, msgfile);
#endif

        if (link(firstpath, msgfile) == 0)
        break;
    }
    oumask = umask(0);
    fh = open(msgfile, O_CREAT | O_EXCL | O_WRONLY, 0664);
    umask(oumask);
    if (writebody) {
        if ((*writebody) (fh, board, pathname) < 0)
        return NULL;
    } else {
        if (bbspost_write_post(fh, board, pathname) < 0)
        return NULL;
    }
    close(fh);
    break;
    }

#ifdef CACHED_OPENBOARD
    {
    char           *bname;
    bname = strrchr(msgdir, '/');
    if (bname)
        notify_new_post(++bname, 1, fileid, stbuf.st_mtime);
    }
#endif

    return name;
}

cancel_article(homepath, board, file)
    char           *homepath;
    char           *board, *file;
{
    PATH            fname;

#ifdef  CACHED_OPENBOARD
    PATH            bdir;
    struct stat     stbuf;

    sprintf(bdir, "%s/boards/%c/%s", homepath, board[0], board);
    stat(bdir, &stbuf);
#endif

    sprintf(fname, "%s/boards/%c/%s/%s", homepath, board[0], board, file);
    unlink(fname);
    /* kill it now! the function is far small then original..  :) */
    /* because it won't make system load heavy like before */

#ifdef CACHED_OPENBOARD
    notify_new_post(board, -1, hex2SHORT(file), stbuf.st_mtime);
#endif
}

#else
error("You should choose one of the systems: PhoenixBBS, PowerBBS, or PalmBBS")
#endif

#else

receive_article()
{
}

cancel_article_front(msgid)
    char           *msgid;
{
}
#endif