summaryrefslogblamecommitdiffstats
path: root/mbbsd/mail.c
blob: 35b6a00018d5ed30c95bfc67c746711ead0fb87c (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
                                                     














                      
                               













                                                                            
                                 













                                                                      
                  
















                                                                 
                                        
                               
                                                                          




















































































                                                                              
                                                                   
                                                         
                                                              




























































































                                                                               
                                      





















                                                    
                                                                   























































































































































































































                                                                               
                                                                  





































































































                                                                    
                                                          

































































































































































































































































                                                                              
                                        





























                                                                            
                                
                                                 

                                                                               












                                                                 
                                                    






                                          
                          
                
                                                             
                                                     
                                                                           
























































                                                                         
                      
            

                                                                                



























































































                                                                     
                  
 

                                                                            












































                                                                       




               




                                                                     




















                                                                        
                                                            


























































































                                                                       






                                                                       







































                                                                    


























                                                                       


























































































                                                                          





















































































                                                                             
                 








































































                                                                           







                                                    






                                                                               













































































































                                                                           
/* $Id: mail.c,v 1.7 2002/05/13 03:20:04 ptt Exp $ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include "config.h"
#include "pttstruct.h"
#include "common.h"
#include "perm.h"
#include "modes.h"
#include "proto.h"

extern struct bcache_t *brdshm;
extern int TagNum;
extern int b_lines;               /* Screen bottom line number: t_lines-1 */
extern char save_title[];         /* used by editor when inserting */
extern int curredit;
extern char *err_uid;
extern char *msg_cancel;
extern char *msg_uid;
extern char *fn_overrides;
extern char quote_file[80];
extern char quote_user[80];
extern char *fn_notes;
extern char *msg_mailer;
extern char *msg_sure_ny;
extern char *BBSName;
extern char currtitle[TTLEN + 1];
extern unsigned char currfmode;               /* current file mode */
extern char *msg_del_ny;
extern char currfile[FNLEN];
extern int currmode;
extern char currboard[];        /* name of currently selected board */
extern char *str_space;
extern char *str_author1;
extern char *str_author2;
extern userinfo_t *currutmp;
extern unsigned int currstat;
extern pid_t currpid;
extern int usernum;
extern char *str_mail_address;
extern userec_t cuser;
extern time_t now;
char currmaildir[32];
static char msg_cc[] = "\033[32m[群組名單]\033[m\n";
static char listfile[] = "list.0";
static int mailkeep = 0, mailsum = 0;
static int mailsumlimit = 0,mailmaxkeep = 0;

int setforward() {
    char buf[80], ip[50] = "", yn[4];
    FILE *fp;
    
    sethomepath(buf, cuser.userid);
    strcat(buf,"/.forward");
    if((fp = fopen(buf,"r"))) {
    fscanf(fp,"%s",ip);
    fclose(fp);
    }
    getdata_buf(b_lines - 1, 0, "請輸入信箱自動轉寄的email地址:",
        ip, sizeof(ip), DOECHO);
    if(ip[0] && ip[0] != ' ') {
    getdata(b_lines, 0, "確定開啟自動轉信功\能?(Y/n)", yn, sizeof(yn),
        LCECHO);
    if(yn[0] != 'n' && (fp = fopen(buf, "w"))) {
        move(b_lines,0);
        clrtoeol();
        fprintf(fp,"%s",ip);
        fclose(fp);
        outs("設定完成!");
        refresh();
        return 0;
    }
    }
    move(b_lines,0);
    clrtoeol();
    outs("取消自動轉信!");
    unlink(buf);
    refresh();
    return 0;
}

int built_mail_index() {
    char genbuf[128];
    
    getdata(b_lines, 0,
        "重建信箱?(警告:請確定信箱有問題時才使用)(y/N)", genbuf, 3,
            LCECHO);
    if(genbuf[0] != 'y') return 0;  

    sprintf(genbuf, BBSHOME "/bin/buildir " BBSHOME "/home/%c/%s",
        cuser.userid[0], cuser.userid);
    move(22,0);
    prints("\033[1;31m已經處理完畢!! 諸多不便 敬請原諒~\033[m");pressanykey();
    system(genbuf);
    return 0;
}

int mailalert(char *userid)
{
    userinfo_t *uentp=NULL;
    int n,tuid,i;     

    if((tuid=searchuser(userid))==0) return -1;

    n=count_logins(tuid, 0);
    for(i=1;i<=n;i++)
       if((uentp = (userinfo_t *)search_ulistn(tuid, i)))
         uentp->mailalert=1;
    return 0;
}

int mail_muser(userec_t muser, char *title, char *filename) {
    return mail_id(muser.userid, title, filename, cuser.userid);
}

/* Heat: 用id來寄信,內容則link準備好的檔案 */
int mail_id(char* id, char *title, char *filename, char *owner) {
    fileheader_t mhdr;
    char genbuf[128];
    sethomepath(genbuf, id);
    if(stampfile(genbuf, &mhdr))
        return 0;
    strcpy(mhdr.owner, owner);
    strncpy(mhdr.title, title, TTLEN);
    mhdr.savemode = 0;
    mhdr.filemode = 0;
    Link(filename, genbuf);
    sethomedir(genbuf,id);
    append_record(genbuf, &mhdr, sizeof(mhdr));
    mailalert(id);
    return 0;
}    
          
int invalidaddr(char *addr) {
    if(*addr == '\0')
    return 1;                   /* blank */
    while(*addr) {
    if(not_alnum(*addr) && !strchr("[].%!@:-_;", *addr))
        return 1;
    addr++;
    }
    return 0;
}

int m_internet() {
    char receiver[60];
    
    getdata(20, 0, "收信人:", receiver, sizeof(receiver), DOECHO);
    if(strchr(receiver, '@') && !invalidaddr(receiver) &&
       getdata(21, 0, "主  題:", save_title, STRLEN, DOECHO))
    do_send(receiver, save_title);
    else {
    move(22, 0);
    outs("收信人或主題不正確, 請重新選取指令");
    pressanykey();
    }
    return 0;
}

void m_init() {
    sethomedir(currmaildir, cuser.userid);
}

int chkmailbox() {
    if(!HAVE_PERM(PERM_SYSOP) && !HAVE_PERM(PERM_MAILLIMIT)) {
        int max_keepmail = MAX_KEEPMAIL;
        if ( HAS_PERM(PERM_SYSSUBOP) || HAS_PERM(PERM_SMG) ||
           HAS_PERM(PERM_PRG) || HAS_PERM(PERM_ACTION) || HAS_PERM(PERM_PAINT))
          {
            mailsumlimit = 700;
            max_keepmail = 500;
          }
    else if(HAS_PERM(PERM_BM))
          {
        mailsumlimit = 500;
            max_keepmail = 300;
      }
    else if(HAS_PERM(PERM_LOGINOK))
        mailsumlimit = 200;
    else
        mailsumlimit = 50;
    mailsumlimit += cuser.exmailbox * 10;
    mailmaxkeep = max_keepmail + cuser.exmailbox;
    m_init();
    if((mailkeep = get_num_records(currmaildir, sizeof(fileheader_t))) >
       mailmaxkeep) {
        move(b_lines, 0);
        clrtoeol();
        bell();
        prints("您保存信件數目 %d 超出上限 %d, 請整理",
           mailkeep, mailmaxkeep);
        bell();
        refresh();
        igetch();
        return mailkeep;
    }
    if((mailsum = get_sum_records(currmaildir, sizeof(fileheader_t))) >
       mailsumlimit) {
        move(b_lines, 0);
        clrtoeol();
        bell();
        prints("您保存信件容量 %d(k)超出上限 %d(k), 請整理",
           mailsum, mailsumlimit);
        bell();
        refresh();
        igetch();
        return mailkeep;
    }
    }
    return 0;
}

static void do_hold_mail(char *fpath, char *receiver, char *holder) {
    char buf[80], title[128];
    
    fileheader_t mymail;
    
    sethomepath(buf, holder);
    stampfile(buf, &mymail);
    
    mymail.savemode = 'H';        /* hold-mail flag */
    mymail.filemode = FILE_READ;
    strcpy(mymail.owner, "[備.忘.錄]");
    if(receiver) {
    sprintf(title, "(%s) %s", receiver, save_title);
    strncpy(mymail.title, title, TTLEN);
    } else
    strcpy(mymail.title, save_title);
    
    sethomedir(title, holder);
    
    unlink(buf);
    Link(fpath, buf);
    /* Ptt: append_record->do_append */
    do_append(title, &mymail, sizeof(mymail));
}

extern userec_t xuser;

void hold_mail(char *fpath, char *receiver) {
    char buf[4];
    
    getdata(b_lines - 1, 0, "已順利寄出,是否自存底稿(Y/N)?[N] ",
        buf, sizeof(buf), LCECHO);
    
    if(buf[0] == 'y')
    do_hold_mail(fpath, receiver, cuser.userid);
}

int do_send(char *userid, char *title) {
    fileheader_t mhdr;
    char fpath[STRLEN];
    char receiver[IDLEN];
    char genbuf[200];
    int internet_mail, i;
    
    if(strchr(userid, '@'))
    internet_mail = 1;
    else {
    internet_mail = 0;
    if(!getuser(userid))
        return -1;
    if(!(xuser.userlevel & PERM_READMAIL))
        return -3;
    
    if(!title)
        getdata(2, 0, "主題:", save_title, STRLEN-20, DOECHO);
    curredit |= EDIT_MAIL;
    curredit &= ~EDIT_ITEM;
    }
    
    setutmpmode(SMAIL);
    
    fpath[0] = '\0';
    
    if(internet_mail) {
    int res, ch;

    if(vedit(fpath, NA, NULL) == -1) {
        unlink(fpath);
        clear();
        return -2;
    }
    clear();
    prints("信件即將寄給 %s\n標題為:%s\n確定要寄出嗎? (Y/N) [Y]",
           userid, title);
    ch = igetch();
    switch(ch) {
    case 'N':
    case 'n':
        outs("N\n信件已取消");
        res = -2;
        break;
    default:
        outs("Y\n請稍候, 信件傳遞中...\n");
        res =
#ifndef USE_BSMTP
        bbs_sendmail(fpath, title, userid);
#else
            bsmtp(fpath, title, userid,0);
#endif
        hold_mail(fpath, userid);
    }
    unlink(fpath);
    return res;
    } else {
    strcpy(receiver, userid);
    sethomepath(genbuf, userid);
    stampfile(genbuf, &mhdr);
    strcpy(mhdr.owner, cuser.userid);
    strncpy(mhdr.title, save_title, TTLEN);
    mhdr.savemode = '\0';
    if(vedit(genbuf, YEA, NULL) == -1) {
        unlink(genbuf);
        clear();
        return -2;
    }
    clear();
    sethomefile(fpath, userid, FN_OVERRIDES);
        i=belong(fpath, cuser.userid);
        sethomefile(fpath, userid, FN_REJECT);

        if(i || !belong(fpath, cuser.userid)) //Ptt:用belong有點討厭 
           {
        sethomedir(fpath, userid);
            if(append_record(fpath, &mhdr, sizeof(mhdr)) == -1)
            return -1;
            mailalert(userid);
       }
    hold_mail(genbuf, userid);
    return 0;
    }
}

void my_send(char *uident) {
    switch(do_send(uident, NULL)) {
    case -1:
    outs(err_uid);
    break;
    case -2:
    outs(msg_cancel);
    break;
    case -3:
    prints("使用者 [%s] 無法收信", uident);
    break;
    }
    pressanykey();
}

int m_send() {
    char uident[40];

    stand_title("且聽風的話");
    usercomplete(msg_uid, uident);
    showplans(uident);
    if(uident[0])
    my_send(uident);
    return 0;
}

/* 群組寄信、回信 : multi_send, multi_reply */
extern struct word_t *toplev;

static void multi_list(int *reciper) {
    char uid[16];
    char genbuf[200];

    while(1) {
    stand_title("群組寄信名單");
    ShowNameList(3, 0, msg_cc);
    getdata(1, 0,
        "(I)引入好友 (O)引入上線通知 (N)引入新文章通知 "
        "(0-9)引入其他特別名單\n"
        "(A)增加     (D)刪除         (M)確認寄信名單   (Q)取消 ?[M]",
        genbuf, 4, LCECHO);
    switch(genbuf[0]) {
    case 'a':
        while(1) {
        move(1, 0);
        usercomplete("請輸入要增加的代號(只按 ENTER 結束新增): ", uid);
        if(uid[0] == '\0')
            break;
        
        move(2, 0);
        clrtoeol();
        
        if(!searchuser(uid))
            outs(err_uid);
        else if(!InNameList(uid)) {
            AddNameList(uid);
            (*reciper)++;
        }
        ShowNameList(3, 0, msg_cc);
        }
        break;
    case 'd':
        while(*reciper) {
        move(1, 0);
        namecomplete("請輸入要刪除的代號(只按 ENTER 結束刪除): ", uid);
        if(uid[0] == '\0')
            break;
        if(RemoveNameList(uid))
            (*reciper)--;
        ShowNameList(3, 0, msg_cc);
        }
        break;
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
        listfile[5] = genbuf[0];
        genbuf[0] = '1';
    case 'i':
        setuserfile(genbuf, genbuf[0] == '1' ? listfile : fn_overrides);
        ToggleNameList(reciper, genbuf, msg_cc);
        break;
    case 'o':
        setuserfile(genbuf, "alohaed");
        ToggleNameList(reciper, genbuf, msg_cc);
        break;
    case 'n':
        setuserfile(genbuf, "postlist");
        ToggleNameList(reciper, genbuf, msg_cc);
        break;
    case 'q':
        *reciper = 0;
        return;
    default:
        return;
    }
    }
}

static void multi_send(char *title) {
    FILE *fp;
    struct word_t *p;
    fileheader_t mymail;
    char fpath[TTLEN], *ptr;
    int reciper, listing;
    char genbuf[256];
    
    CreateNameList();
    listing = reciper = 0;
    if(*quote_file) {
    AddNameList(quote_user);
    reciper = 1;
    fp = fopen(quote_file, "r");
    while(fgets(genbuf, 256, fp)) {
        if(strncmp(genbuf, "※ ", 3)) {
        if(listing)
            break;
        } else {
        if(listing) {
            strtok(ptr = genbuf + 3, " \n\r");
            do {
            if(searchuser(ptr) && !InNameList(ptr) &&
               strcmp(cuser.userid, ptr)) {
                AddNameList(ptr);
                reciper++;
            }
            } while((ptr = (char *)strtok(NULL, " \n\r")));
        } else if(!strncmp(genbuf + 3, "[通告]", 6))
            listing = 1;
        }
    }
    ShowNameList(3, 0, msg_cc);
    }
    
    multi_list(&reciper);
    move(1, 0);
    clrtobot();
    
    if(reciper) {
    setutmpmode(SMAIL);
    if(title)
        do_reply_title(2, title);
    else {
        getdata(2, 0, "主題:", fpath, sizeof(fpath), DOECHO);
        sprintf(save_title, "[通告] %s", fpath);
    }
    
    setuserfile(fpath, fn_notes);
    
    if((fp = fopen(fpath, "w"))) {
        fprintf(fp, "※ [通告] 共 %d 人收件", reciper);
        listing = 80;

        for(p = toplev; p; p = p->next) {
        reciper = strlen(p->word) + 1;
        if(listing + reciper > 75) {
            listing = reciper;
            fprintf(fp, "\n※");
        } else
            listing += reciper;
        
        fprintf(fp, " %s", p->word);
        }
        memset(genbuf, '-', 75);
        genbuf[75] = '\0';
        fprintf(fp, "\n%s\n\n", genbuf);
        fclose(fp);
    }
    
    curredit |= EDIT_LIST;

    if(vedit(fpath, YEA, NULL) == -1) {
        unlink(fpath);
        curredit = 0;
        outs(msg_cancel);
        pressanykey();
        return;
    }
    
    stand_title("寄信中...");
    refresh();
    
    listing = 80;
    
    for(p = toplev; p; p = p->next) {
        reciper = strlen(p->word) + 1;
        if(listing + reciper > 75) {
        listing = reciper;
        outc('\n');
        } else {
        listing += reciper;
        outc(' ');
        }
        outs(p->word);
        if(searchuser(p->word) && strcmp(STR_GUEST, p->word) )
        sethomepath(genbuf, p->word);
        else
        continue;
        stampfile(genbuf, &mymail);
        unlink(genbuf);
        Link(fpath, genbuf);
        
        strcpy(mymail.owner, cuser.userid);
        strcpy(mymail.title, save_title);
        mymail.savemode = 'M';    /* multi-send flag */
        sethomedir(genbuf, p->word);
        if(append_record(genbuf, &mymail, sizeof(mymail)) == -1)
        outs(err_uid);
        mailalert(p->word);
    }
    hold_mail(fpath, NULL);
    unlink(fpath);
    curredit = 0;
    } else
    outs(msg_cancel);
    pressanykey();
}

static int multi_reply(int ent, fileheader_t *fhdr, char *direct) {
    if(fhdr->savemode != 'M')
    return mail_reply(ent, fhdr, direct);

    stand_title("群組回信");
    strcpy(quote_user, fhdr->owner);
    setuserfile(quote_file, fhdr->filename);
    multi_send(fhdr->title);
    return 0;
}

int mail_list() {
    stand_title("群組作業");
    multi_send(NULL);
    return 0;
}

int mail_all() {
    FILE *fp;
    fileheader_t mymail;
    char fpath[TTLEN];
    char genbuf[200];
    extern struct uhash_t *uhash;
    int i, unum;
    char *userid;
    
    stand_title("給所有使用者的系統通告");
    setutmpmode(SMAIL);
    getdata(2, 0, "主題:", fpath, sizeof(fpath), DOECHO);
    sprintf(save_title, "[系統通告]\033[1;32m %s\033[m", fpath);
    
    setuserfile(fpath, fn_notes);
    
    if((fp = fopen(fpath, "w"))) {
    fprintf(fp, "※ [\033[1m系統通告\033[m] 這是封給所有使用者的信\n");
    fprintf(fp, "-----------------------------------------------------"
        "----------------------\n");
    fclose(fp);
    }
    
    *quote_file = 0;
    
    curredit |= EDIT_MAIL;
    curredit &= ~EDIT_ITEM;
    if(vedit(fpath, YEA, NULL) == -1) {
    curredit = 0;
    unlink(fpath);
    outs(msg_cancel);
    pressanykey();
    return 0;
    }
    curredit = 0;
    
    setutmpmode(MAILALL);
    stand_title("寄信中...");
    
    sethomepath(genbuf, cuser.userid);
    stampfile(genbuf, &mymail);
    unlink(genbuf);
    Link(fpath, genbuf);
    unlink(fpath);
    strcpy(fpath, genbuf);
    
    strcpy(mymail.owner, cuser.userid);  /*站長 ID*/
    strcpy(mymail.title, save_title);
    mymail.savemode = 0;
    
    sethomedir(genbuf, cuser.userid);
    if(append_record(genbuf, &mymail, sizeof(mymail)) == -1)
    outs(err_uid);
    
    for(unum = uhash->number, i = 0; i < unum; i++) {
    if(bad_user_id(uhash->userid[i]))
        continue; /* Ptt */
    
    userid = uhash->userid[i];
    if(strcmp(userid,STR_GUEST) && strcmp(userid, "new") &&
       strcmp(userid, cuser.userid)) {
        sethomepath(genbuf, userid);
        stampfile(genbuf, &mymail);
        unlink(genbuf);
        Link(fpath, genbuf);
        
        strcpy(mymail.owner, cuser.userid);
        strcpy(mymail.title, save_title);
        mymail.savemode = 0;
        /* mymail.filemode |= FILE_MARKED; Ptt 公告改成不會mark */
        sethomedir(genbuf, userid);
        if(append_record(genbuf, &mymail, sizeof(mymail)) == -1)
        outs(err_uid);
        sprintf(genbuf, "%*s %5d / %5d", IDLEN + 1, userid, i + 1, unum);
        outmsg(genbuf);
        refresh();
    }
    }
    return 0;
}

int mail_mbox() {
    char cmd[100];
    fileheader_t fhdr;

    sprintf(cmd, "/tmp/%s.uu", cuser.userid);
    sprintf(fhdr.title, "%s 私人資料", cuser.userid);
    doforward(cmd, &fhdr, 'Z');
    return 0;
}

static int m_forward(int ent, fileheader_t *fhdr, char *direct) {
    char uid[STRLEN];

    stand_title("轉達信件");
    usercomplete(msg_uid, uid);
    if(uid[0] == '\0')
    return FULLUPDATE;

    strcpy(quote_user, fhdr->owner);
    setuserfile(quote_file, fhdr->filename);
    sprintf(save_title, "%.64s (fwd)", fhdr->title);
    move(1, 0);
    clrtobot();
    prints("轉信給: %s\n標  題: %s\n", uid, save_title);

    switch(do_send(uid, save_title)) {
    case -1:
    outs(err_uid);
    break;
    case -2:
    outs(msg_cancel);
    break;
    case -3:
    prints("使用者 [%s] 無法收信", uid);
    break;
    }
    pressanykey();
    return FULLUPDATE;
}

static int delmsgs[128];
static int delcnt;
static int mrd;

static int read_new_mail(fileheader_t *fptr) {
    static int idc;
    char done = NA, delete_it;
    char fname[256];
    char genbuf[4];
    
    if(fptr == NULL) {
    delcnt = 0;
    idc = 0;
    return 0;
    }
    idc++;
    if(fptr->filemode)
    return 0;
    clear();
    move(10, 0);
    prints("您要讀來自[%s]的訊息(%s)嗎?", fptr->owner, fptr->title);
    getdata(11, 0, "請您確定(Y/N/Q)?[Y] ", genbuf, 3, DOECHO);
    if(genbuf[0] == 'q')
    return QUIT;
    if(genbuf[0] == 'n')
    return 0;
    
    setuserfile(fname, fptr->filename);
    fptr->filemode |= FILE_READ;
    if(substitute_record(currmaildir, fptr, sizeof(*fptr), idc))
    return -1;
    
    mrd = 1;
    delete_it = NA;
    while(!done) {
    int more_result = more(fname, YEA);

    switch(more_result) {
    case 1:
        return READ_PREV;
    case 2:
        return RELATE_PREV;
    case 3:
        return READ_NEXT;
    case 4:
        return RELATE_NEXT;
    case 5:
        return RELATE_FIRST;
    case 6:
        return 0;
    case 7:
        mail_reply(idc, fptr, currmaildir);
        return FULLUPDATE;
    case 8:
        multi_reply(idc, fptr, currmaildir);
        return FULLUPDATE;
    }
    move(b_lines, 0);
    clrtoeol();
    outs(msg_mailer);
    refresh();
    
    switch(egetch()) {
    case 'r':
    case 'R':
        mail_reply(idc, fptr, currmaildir);
        break;
    case 'x':
        m_forward(idc, fptr, currmaildir);
        break;
    case 'y':
        multi_reply(idc, fptr, currmaildir);
        break;
    case 'd':
    case 'D':
        delete_it = YEA;
    default:
        done = YEA;
    }
    }
    if(delete_it) {
    clear();
    prints("刪除信件《%s》", fptr->title);
    getdata(1, 0, msg_sure_ny, genbuf, 2, LCECHO);
    if(genbuf[0] == 'y') {
        unlink(fname);
        delmsgs[delcnt++] = idc;
    }
    }
    clear();
    return 0;
}

int m_new() {
    clear();
    mrd = 0;
    setutmpmode(RMAIL);
    read_new_mail(NULL);
    clear();
    curredit |= EDIT_MAIL;
    curredit &= ~EDIT_ITEM;
    if(apply_record(currmaildir, read_new_mail, sizeof(fileheader_t)) == -1) {
    outs("沒有新信件了");
    pressanykey();
    return -1;
    }
    curredit = 0;
    if(delcnt) {
    while(delcnt--)
        delete_record(currmaildir, sizeof(fileheader_t), delmsgs[delcnt]);
    }
    outs(mrd ? "信已閱\畢" : "沒有新信件了");
    pressanykey();
    return -1;
}

static void mailtitle() {
    char buf[256] = "";

    showtitle("\0郵件選單", BBSName);
    sprintf(buf,"[←]離開[↑↓]選擇[→]閱\讀信件 [R]回信 [x]轉達 "
     "[y]群組回信 [O]站外信:%s [h]求助\n\033[7m"
     "編號   日 期  作 者          信  件  標  題     \033[32m",
     HAS_PERM(PERM_NOOUTMAIL)? "\033[31m關\033[m":"開");
    outs(buf);
    buf[0]=0;
    if(mailsumlimit) {
    sprintf(buf,"(容量:%d/%dk %d/%d篇)", mailsum, mailsumlimit,
        mailkeep, mailmaxkeep);
    }
    sprintf(buf, "%s%*s\033[m", buf, 29 - (int) strlen(buf), "");
    outs(buf);
}

static void maildoent(int num, fileheader_t *ent) {
    char *title, *mark, color, type = "+ Mm"[ent->filemode];

    if (TagNum && !Tagger(atoi(ent->filename + 2), 0, TAG_NIN))
            type = 'D';     

    title = subject(mark = ent->title);
    if(title == mark) {
    color = '1';
    mark = "◇";
    } else {
    color = '3';
    mark = "R:";
    }

    if(strncmp(currtitle, title, TTLEN))
    prints("%5d %c %-7s%-15.14s%s %.46s\n", num, type,
           ent->date, ent->owner, mark, title);
    else
    prints("%5d %c %-7s%-15.14s\033[1;3%cm%s %.46s\033[0m\n", num, type,
           ent->date, ent->owner, color, mark, title);
}

#ifdef POSTBUG
extern int bug_possible;
#endif


static int m_idle(int ent, fileheader_t *fhdr, char *direct) {
    t_idle();
    return FULLUPDATE;
}

static int mail_del(int ent, fileheader_t *fhdr, char *direct) {
    char genbuf[200];

    if(fhdr->filemode & FILE_MARKED)
    return DONOTHING;

    getdata(1, 0, msg_del_ny, genbuf, 3, LCECHO);
    if(genbuf[0] == 'y') {
    strcpy(currfile, fhdr->filename);
    if(!delete_file(direct, sizeof(*fhdr), ent, cmpfilename)) {
        setdirpath(genbuf, direct, fhdr->filename);
        unlink(genbuf);
        if((currmode & MODE_SELECT)) {
            int index;  
        sethomedir(genbuf, cuser.userid);
        index = getindex(genbuf, fhdr->filename, sizeof(fileheader_t));
        delete_file(genbuf, sizeof(fileheader_t), index, cmpfilename);
        }
        return DIRCHANGED;
    }
    }
    return FULLUPDATE;
}

static int mail_read(int ent, fileheader_t *fhdr, char *direct) {
    char buf[64];
    char done, delete_it, replied;

    clear();
    setdirpath(buf, direct, fhdr->filename);
    strncpy(currtitle, subject(fhdr->title), TTLEN);
    done = delete_it = replied = NA;
    while(!done) {
    int more_result = more(buf, YEA);
    
    if(more_result != -1) {
        fhdr->filemode |= FILE_READ;
        if((currmode & MODE_SELECT)) {
        int index;
        
        index = getindex(currmaildir, fhdr->filename,
                   sizeof(fileheader_t));
        substitute_record(currmaildir, fhdr, sizeof(*fhdr), index);
        substitute_record(direct, fhdr, sizeof(*fhdr), ent);
        }
        else
        substitute_record(currmaildir, fhdr, sizeof(*fhdr), ent);
    }
    switch(more_result) {
    case 1:
        return READ_PREV;
    case 2:
        return RELATE_PREV;
    case 3:
        return READ_NEXT;
    case 4:
        return RELATE_NEXT;
    case 5:
        return RELATE_FIRST;
    case 6:
        return FULLUPDATE;
    case 7:
        mail_reply(ent, fhdr, direct);
        return FULLUPDATE;
    case 8:
        multi_reply(ent, fhdr, direct);
        return FULLUPDATE;
    }
    move(b_lines, 0);
    clrtoeol();
    refresh();
    outs(msg_mailer);
    
    switch(egetch()) {
    case 'r':
    case 'R':
        replied = YEA;
        mail_reply(ent, fhdr, direct);
        break;
    case 'x':
        m_forward(ent, fhdr, direct);
        break;
    case 'y':
        multi_reply(ent, fhdr, direct);
        break;
    case 'd':
        delete_it = YEA;
    default:
        done = YEA;
    }
    }
    if(delete_it)
    mail_del(ent, fhdr, direct);
    else {
    fhdr->filemode |= FILE_READ;
#ifdef POSTBUG
    if(replied)
        bug_possible = YEA;
#endif
    if((currmode & MODE_SELECT)) {
        int index;
        
        index = getindex(currmaildir, fhdr->filename, sizeof(fileheader_t));
        substitute_record(currmaildir, fhdr, sizeof(*fhdr), index);
        substitute_record(direct, fhdr, sizeof(*fhdr), ent);
    } else
        substitute_record(currmaildir, fhdr, sizeof(*fhdr), ent);
#ifdef POSTBUG
    bug_possible = NA;
#endif
    }
    return FULLUPDATE;
}

/* in boards/mail 回信給原作者,轉信站亦可 */
int mail_reply(int ent, fileheader_t *fhdr, char *direct) {
    char uid[STRLEN];
    char *t;
    FILE *fp;
    char genbuf[512];

    stand_title("回  信");

    /* 判斷是 boards 或 mail */
    if(curredit & EDIT_MAIL)
    setuserfile(quote_file, fhdr->filename);
    else
    setbfile(quote_file, currboard, fhdr->filename);

    /* find the author */
    strcpy(quote_user, fhdr->owner);
    if(strchr(quote_user, '.')) {
    genbuf[0] = '\0';
    if((fp = fopen(quote_file, "r"))) {
        fgets(genbuf, 512, fp);
        fclose(fp);
    }
    
    t = strtok(genbuf, str_space);
    if(!strcmp(t, str_author1) || !strcmp(t, str_author2))
        strcpy(uid, strtok(NULL, str_space));
    else {
        outs("錯誤: 找不到作者。");
        pressanykey();
        return FULLUPDATE;
    }
    } else
    strcpy(uid, quote_user);
    
    /* make the title */
    do_reply_title(3, fhdr->title);
    prints("\n收信人: %s\n標  題: %s\n", uid, save_title);
    
    /* edit, then send the mail */
    ent = curredit;
    switch(do_send(uid, save_title)) {
    case -1:
    outs(err_uid);
    break;
    case -2:
    outs(msg_cancel);
    break;
    case -3:
    prints("使用者 [%s] 無法收信", uid);
    break;
    }
    curredit = ent;
    pressanykey();
    return FULLUPDATE;
}

static int mail_edit(int ent, fileheader_t *fhdr, char *direct) {
    char genbuf[200];

    if(!HAS_PERM(PERM_SYSOP) && 
       strcmp(cuser.userid, fhdr->owner) &&
       strcmp("[備.忘.錄]", fhdr->owner))
    return DONOTHING;

    setdirpath(genbuf, direct, fhdr->filename);
    vedit(genbuf, NA, NULL);
    return FULLUPDATE;
}

static int mail_nooutmail(int ent, fileheader_t *fhdr, char *direct)
{
    cuser.userlevel ^= PERM_NOOUTMAIL;
    passwd_update(usernum, &cuser);
    return FULLUPDATE;

}

static int mail_mark(int ent, fileheader_t *fhdr, char *direct) {
    fhdr->filemode ^= FILE_MARKED;
    
    if((currmode & MODE_SELECT)) {
    int index;

    index = getindex(currmaildir, fhdr->filename, sizeof(fileheader_t));
    substitute_record(currmaildir, fhdr, sizeof(*fhdr), index);
    substitute_record(direct, fhdr, sizeof(*fhdr), ent);
    } else
    substitute_record(currmaildir, fhdr, sizeof(*fhdr), ent);
    return PART_REDRAW;
}

/* help for mail reading */
static char *mail_help[] = {
    "\0電子信箱操作說明",
    "\01基本命令",
    "(p)(↑)    前一篇文章",
    "(n)(↓)    下一篇文章",
    "(P)(PgUp)  前一頁",
    "(N)(PgDn)  下一頁",
    "(##)(cr)   跳到第 ## 筆",
    "($)        跳到最後一筆",
    "\01進階命令",
    "(r)(→)/(R)讀信 / 回信",
    "(O)        關閉/開啟 站外信件轉入",
    "(c/z)      收入此信件進入私人信件夾/進入私人信件夾",
    "(x/X)      轉達信件/轉錄文章到其他看板",
    "(y)        群組回信",
    "(F)        將信傳送回您的電子信箱      (u)水球整理寄回信箱",
    "(d)        殺掉此信",
    "(D)        殺掉指定範圍的信",
    "(m)        將信標記,以防被清除",
    "(^G)       立即重建信箱 (信箱毀損時用)",
    "(t)        標記欲刪除信件",
    "(^D)       刪除已標記信件",
    NULL
};

static int m_help() {
    show_help(mail_help);
    return FULLUPDATE;
}

static int mail_cross_post(int ent, fileheader_t *fhdr, char *direct) {
    char xboard[20], fname[80], xfpath[80], xtitle[80], inputbuf[10];
    fileheader_t xfile;
    FILE *xptr;
    int author = 0;
    char genbuf[200];
    char genbuf2[4];
    
    move(2, 0);
    clrtoeol();
    move(3, 0);
    clrtoeol();
    move(1, 0);
    generalnamecomplete("轉錄本文章於看板:", xboard, sizeof(xboard),
            brdshm->number,
            completeboard_compar,
            completeboard_permission,
            completeboard_getname);
    if(*xboard == '\0' || !haspostperm(xboard))
    return FULLUPDATE;
    
    ent = 1;
    if(HAS_PERM(PERM_SYSOP) || !strcmp(fhdr->owner, cuser.userid)) {
    getdata(2, 0, "(1)原文轉載 (2)舊轉錄格式?[1] ",
        genbuf, 3, DOECHO);
    if(genbuf[0] != '2') {
        ent = 0;
        getdata(2, 0, "保留原作者名稱嗎?[Y] ", inputbuf, 3, DOECHO);
        if(inputbuf[0] != 'n' && inputbuf[0] != 'N')
        author = 1;
    }
    }
    
    if(ent)
    sprintf(xtitle, "[轉錄]%.66s", fhdr->title);
    else
    strcpy(xtitle, fhdr->title);
    
    sprintf(genbuf, "採用原標題《%.60s》嗎?[Y] ", xtitle);
    getdata(2, 0, genbuf, genbuf2, sizeof(genbuf2), LCECHO);
    if(*genbuf2 == 'n')
    if(getdata(2, 0, "標題:", genbuf, TTLEN, DOECHO))
        strcpy(xtitle, genbuf);
    
    getdata(2, 0, "(S)存檔 (L)站內 (Q)取消?[Q] ", genbuf, 3, LCECHO);
    if(genbuf[0] == 'l' || genbuf[0] == 's') {
    int currmode0 = currmode;

    currmode = 0;
    setbpath(xfpath, xboard);
    stampfile(xfpath, &xfile);
    if(author)
        strcpy(xfile.owner, fhdr->owner);
    else
        strcpy(xfile.owner, cuser.userid);
    strcpy(xfile.title, xtitle);
    if(genbuf[0] == 'l') {
        xfile.savemode = 'L';
        xfile.filemode = FILE_LOCAL;
    } else
        xfile.savemode = 'S';
    
    setuserfile(fname, fhdr->filename);
    if(ent) {
        xptr = fopen(xfpath, "w");
        
        strcpy(save_title, xfile.title);
        strcpy(xfpath, currboard);
        strcpy(currboard, xboard);
        write_header(xptr);
        strcpy(currboard, xfpath);
        
        fprintf(xptr, "※ [本文轉錄自 %s 信箱]\n\n", cuser.userid);
        
        b_suckinfile(xptr, fname);
        addsignature(xptr,0);
        fclose(xptr);
    } else {
        unlink(xfpath);
        Link(fname, xfpath);
    }
    
    setbdir(fname, xboard);
    append_record(fname, &xfile, sizeof(xfile));
    setbtotal(getbnum(xboard));
    if(!xfile.filemode)
        outgo_post(&xfile, xboard);
    cuser.numposts++;
    passwd_update(usernum, &cuser);
    outs("文章轉錄完成");
    pressanykey();
    currmode = currmode0;
    }
    return FULLUPDATE;
}

int mail_man() {
    char buf[64],buf1[64];
    if (HAS_PERM(PERM_MAILLIMIT)) {
    int mode0 = currutmp->mode;
    int stat0 = currstat;
    
    sethomeman(buf, cuser.userid);
    sprintf(buf1, "%s 的信件夾", cuser.userid);
    a_menu(buf1, buf, 1);
    currutmp->mode = mode0;
    currstat = stat0;
    return FULLUPDATE;
    }
    return DONOTHING;
}

static int mail_cite(int ent, fileheader_t *fhdr, char *direct) {
    char fpath[256];
    char title[TTLEN + 1];
    static char xboard[20];
    char buf[20];
    boardheader_t *bp;

    setuserfile(fpath, fhdr->filename);
    strcpy(title, "◇ ");
    strncpy(title+3, fhdr->title, TTLEN-3);
    title[TTLEN] = '\0';
    a_copyitem(fpath, title, 0, 1);

    if(cuser.userlevel >= PERM_BM) {
    move(2, 0);
    clrtoeol();
    move(3, 0);
    clrtoeol();
    move(1, 0);

    generalnamecomplete("輸入看版名稱 (直接Enter進入私人信件夾):",
                buf, sizeof(buf),
                brdshm->number,
                completeboard_compar,
                completeboard_permission,
                completeboard_getname);
    if(*buf)
        strcpy(xboard, buf);
    if(*xboard && (bp = getbcache(getbnum(xboard)))) {
        setapath(fpath, xboard);
        setutmpmode(ANNOUNCE);
        a_menu(xboard, fpath, HAS_PERM(PERM_ALLBOARD) ? 2 :
           is_BM(bp->BM) ? 1 : 0);
    } else {
        mail_man();
    }
    return FULLUPDATE;
    } else {
    mail_man();
        return FULLUPDATE;
    }
}

static int mail_save(int ent, fileheader_t *fhdr, char *direct) {
    char fpath[256];
    char title[TTLEN+1];

    if(HAS_PERM(PERM_MAILLIMIT)) {
    setuserfile(fpath, fhdr->filename);
    strcpy(title, "◇ ");
    strncpy(title + 3, fhdr->title, TTLEN - 3);
    title[TTLEN] = '\0';
    a_copyitem(fpath, title, fhdr->owner, 1);
    sethomeman(fpath, cuser.userid);
    a_menu(cuser.userid, fpath, 1);
    return FULLUPDATE;
    }
    return DONOTHING;
}

#ifdef OUTJOBSPOOL
static int mail_waterball(int ent, fileheader_t *fhdr, char *direct)
{
    static  char address[60], cmode = 1;
    char    fname[500], genbuf[200];
    FILE    *fp;

    if(!address[0])
    strcpy(address, cuser.email);
    if(address[0]) {
    sprintf(genbuf, "寄給 [%s] 嗎(Y/N/Q)?[Y] ", address);
    getdata(b_lines - 2, 0, genbuf, fname, 3, LCECHO);
    if(fname[0] == 'q') { outmsg("取消處理"); return 1; }
    if(fname[0] == 'n')
        address[0] = '\0';
    }
    
    if(!address[0]) {
    getdata(b_lines - 2, 0, "請輸入郵件地址:", fname, 60, DOECHO);
    if(fname[0] && strchr(fname, '.')) {
        strcpy(address, fname);
    } else {
        outmsg("取消處理");
        return 1;
    }
    }
    if(invalidaddr(address))
    return -2;
    
    //    sprintf(fname, "%d\n", cmode);
    getdata(b_lines - 1, 0, "使用模式(0/1)? [1]", fname, 3, LCECHO);
    cmode = (fname[0] != '0' && fname[0] != '1') ? 1 : fname[0] - '0';
    
    sprintf(fname, BBSHOME "/jobspool/water.src.%s-%d",
        cuser.userid, now);
    sprintf(genbuf, "cp " BBSHOME "/home/%c/%s/%s %s",
        cuser.userid[0], cuser.userid, fhdr->filename, fname);
    system(genbuf);
    /* dirty code ;x */
    sprintf(fname, BBSHOME "/jobspool/water.des.%s-%d",
        cuser.userid, now);
    fp = fopen(fname, "wt");
    fprintf(fp, "%s\n%s\n%d\n", cuser.userid, address, cmode);
    fclose(fp);
    return FULLUPDATE;
}
#endif
static struct onekey_t mail_comms[] = {
    {'z', mail_man},
    {'c', mail_cite},
    {'s', mail_save},
    {'d', mail_del},
    {'D', del_range},
    {'r', mail_read},
    {'R', mail_reply},
    {'E', mail_edit},
    {'m', mail_mark},
    {'O', mail_nooutmail},
    {'T', edit_title},
    {'x', m_forward},
    {'X', mail_cross_post},
    {Ctrl('G'), built_mail_index}, /* 修信箱 */
    {'y', multi_reply},
    {Ctrl('I'), m_idle},
    {'h', m_help},
#ifdef OUTJOBSPOOL
    {'u', mail_waterball},
#endif
    {'\0', NULL}
};

int m_read() {
    if(get_num_records(currmaildir, sizeof(fileheader_t))) {
    curredit = EDIT_MAIL;
    curredit &= ~EDIT_ITEM;
    i_read(RMAIL, currmaildir, mailtitle, maildoent, mail_comms,  -1);
    curredit = 0;
        currutmp->mailalert = load_mailalert(cuser.userid);
    return 0;
    } else {
    outs("您沒有來信");
    return XEASY;
    }
}

/* 寄站內信 */
static int send_inner_mail(char *fpath, char *title, char *receiver) {
    char genbuf[256];
    fileheader_t mymail;
    
    if(!searchuser(receiver))
    return -2;
    sethomepath(genbuf, receiver);
    stampfile(genbuf, &mymail);
    if(!strcmp(receiver, cuser.userid)) {
    strcpy(mymail.owner, "[" BBSNAME "]");
    mymail.filemode = FILE_READ;
    } else
    strcpy(mymail.owner, cuser.userid);
    strncpy(mymail.title, title, TTLEN);
    unlink(genbuf);
    Link(fpath, genbuf);
    sethomedir(genbuf, receiver);
    return do_append(genbuf, &mymail, sizeof(mymail));    
}

#include <netdb.h>
#include <pwd.h>
#include <time.h>

#ifndef USE_BSMTP
static int bbs_sendmail(char *fpath, char *title, char *receiver) {
    static int configured = 0;
    static char myhostname[STRLEN];
    static char myusername[20];
    struct hostent *hbuf;
    struct passwd *pbuf;
    char *ptr;
    char genbuf[256];
    FILE *fin, *fout;

    /* 中途攔截 */
    if((ptr = strchr(receiver, ';'))) {
    struct tm *ptime;
    
    *ptr = '\0';
    }
    
    if((ptr = strstr(receiver, str_mail_address)) || !strchr(receiver,'@')) {
    char hacker[20];
    int len;

    if(strchr(receiver,'@')) {
            len = ptr - receiver;
            memcpy(hacker, receiver, len);
            hacker[len] = '\0';
        } else
            strcpy(hacker,receiver);
    return send_inner_mail(fpath, title, hacker);
    }
    
    /* setup the hostname and username */
    if(!configured) {
    /* get host name */
    hbuf = gethostbyname("localhost");
    if(hbuf)
        strncpy(myhostname, hbuf->h_name, STRLEN);

    /* get bbs uident */
    pbuf = getpwuid(getuid());
    if(pbuf)
        strncpy(myusername, pbuf->pw_name, 20);
    if(hbuf && pbuf)
        configured = 1;
    else
        return -1;
    }
    
    /* Running the sendmail */
    if(fpath == NULL) {
    sprintf(genbuf, "/usr/sbin/sendmail %s > /dev/null", receiver);
    fin = fopen("etc/confirm", "r");
    } else {
    sprintf(genbuf, "/usr/sbin/sendmail -f %s%s %s > /dev/null",
        cuser.userid, str_mail_address, receiver);
    fin = fopen(fpath, "r");
    }
    fout = popen(genbuf, "w");
    if(fin == NULL || fout == NULL)
    return -1;
    
    if(fpath)
    fprintf(fout, "Reply-To: %s%s\nFrom: %s%s\n",
        cuser.userid, str_mail_address, cuser.userid,
        str_mail_address);
    fprintf(fout, "To: %s\nSubject: %s\n", receiver, title);
    fprintf(fout, "X-Disclaimer: " BBSNAME "對本信內容恕不負責。\n\n");
    
    while(fgets(genbuf, 255, fin)) {
    if(genbuf[0] == '.' && genbuf[1] == '\n')
        fputs(". \n", fout);
    else
        fputs(genbuf, fout);
    }
    fclose(fin);
    fprintf(fout, ".\n");
    pclose(fout);
    return 0;
}
#else /* USE_BSMTP */

int bsmtp(char *fpath, char *title, char *rcpt, int method) {
    char buf[80], *ptr;
    time_t chrono;
    MailQueue mqueue;

    /* check if the mail is a inner mail */
    if((ptr = strstr(rcpt, str_mail_address)) || !strchr(rcpt, '@')) {
    char hacker[20];
    int len;

    if(strchr(rcpt,'@')) {
            len = ptr - rcpt;
            memcpy(hacker, rcpt, len);
            hacker[len] = '\0';
        } else
            strcpy(hacker, rcpt);
    return send_inner_mail(fpath, title, hacker);
    }
    
    chrono = now;
    if(method != MQ_JUSTIFY) { /* 認證信 */
    /* stamp the queue file */
    strcpy(buf, "out/");
    for(;;) {
        sprintf(buf + 4,"M.%ld.A", ++chrono);
        if(!dashf(buf)) {
        Link(fpath, buf);
        break;
        }
    }
    
    fpath = buf;

    strcpy(mqueue.filepath, fpath);
    strcpy(mqueue.subject, title);
    }
    /* setup mail queue */    
    mqueue.mailtime = chrono;
    mqueue.method = method;
    strcpy(mqueue.sender, cuser.userid);
    strcpy(mqueue.username, cuser.username);
    strcpy(mqueue.rcpt, rcpt);
    if(do_append("out/.DIR", (fileheader_t *)&mqueue, sizeof(mqueue)) < 0)
    return 0;
    return chrono;
}
#endif /* USE_BSMTP */

int doforward(char *direct, fileheader_t *fh, int mode) {
    static char address[60];
    char fname[500];
    int return_no;
    char genbuf[200];
    
    if(!address[0])
    strcpy(address, cuser.email);

    if(address[0]) {
    sprintf(genbuf, "確定轉寄給 [%s] 嗎(Y/N/Q)?[Y] ", address);
    getdata(b_lines - 1, 0, genbuf, fname, 3, LCECHO);
    
    if(fname[0] == 'q') {
        outmsg("取消轉寄");
        return 1;
    }
    if(fname[0] == 'n')
        address[0] = '\0';
    }
    
    if(!address[0]) {
    do{
        getdata(b_lines - 1, 0, "請輸入轉寄地址:", fname, 60, DOECHO);
        if(fname[0]) {
        if(strchr(fname, '.'))
            strcpy(address, fname);
        else
            sprintf(address, "%s.bbs@%s", fname, MYHOSTNAME);
        } else {
        outmsg("取消轉寄");
        return 1;
        }
    }while(mode=='Z' && strstr(address, MYHOSTNAME));
    }
    if(invalidaddr(address))
    return -2;
    
    sprintf(fname, "正轉寄給 %s, 請稍候...", address);
    outmsg(fname);
    move(b_lines - 1, 0);
    refresh();
    
    /* 追蹤使用者 */
    if(HAS_PERM(PERM_LOGUSER)) {
    char msg[200];
    
    sprintf(msg, "%s mailforward to %s at %s",
        cuser.userid, address, Cdate(&now));
    log_user(msg);
    }
    
    if(mode == 'Z') {
    sprintf(fname, TAR_PATH " cfz /tmp/home.%s.tgz home/%c/%s; "
        MUTT_PATH" -a /tmp/home.%s.tgz -s 'home.%s.tgz' %s </dev/null;"
        "rm /tmp/home.%s.tgz",
        cuser.userid, cuser.userid[0], cuser.userid,
        cuser.userid, cuser.userid, address, cuser.userid);
    system(fname);
    return 0;
    sprintf(fname, TAR_PATH " cfz - home/%c/%s | "
        "/usr/bin/uuencode %s.tgz > %s",
        cuser.userid[0], cuser.userid, cuser.userid, direct);
    system(fname);
    strcpy(fname, direct);
    } else if(mode == 'U') {
    char tmp_buf[128];

    sprintf(fname, "/tmp/bbs.uu%05d", currpid);
    sprintf(tmp_buf, "/usr/bin/uuencode %s/%s uu.%05d > %s",
        direct, fh->filename, currpid, fname);
    system(tmp_buf);
    } else if (mode == 'F'){
    char tmp_buf[128];
    
    sprintf(fname, "/tmp/bbs.f%05d", currpid);
    sprintf(tmp_buf, "cp %s/%s %s",direct,fh->filename,fname);
    system(tmp_buf);
    } else
    return -1;
    
    return_no =
#ifndef USE_BSMTP
    bbs_sendmail(fname, fh->title, address);
#else
    bsmtp(fname, fh->title, address,mode);
#endif
    unlink(fname);
    return (return_no);
}

int load_mailalert(char *userid) {
    struct stat st;
    char maildir[256];
    int fd;
    register int numfiles;
    fileheader_t my_mail;

    sethomedir(maildir, userid); 
    if(!HAS_PERM(PERM_BASIC))
    return 0;
    if(stat(maildir, &st) < 0)
    return 0;
    numfiles = st.st_size / sizeof(fileheader_t);
    if(numfiles <= 0)
    return 0;
    
    /* 看看有沒有信件還沒讀過?從檔尾回頭檢查,效率較高 */    
    if((fd = open(maildir, O_RDONLY)) > 0) {
    lseek(fd, st.st_size - sizeof(fileheader_t), SEEK_SET);
    while(numfiles--) {
        read(fd, &my_mail, sizeof(fileheader_t));
        if(!(my_mail.filemode & FILE_READ)) {
        close(fd);
        return 1;
        }
        lseek(fd, -(off_t)2 * sizeof(fileheader_t), SEEK_CUR);
    }
    close(fd);
    }
    return 0;
}

#ifdef  EMAIL_JUSTIFY
static void mail_justify(userec_t muser) {
    fileheader_t mhdr;
    char title[128], buf1[80];
    FILE* fp;
    
    sethomepath(buf1, muser.userid);
    stampfile(buf1, &mhdr);
    unlink(buf1);
    strcpy(mhdr.owner, cuser.userid);
    strncpy(mhdr.title, "[審核通過]", TTLEN);
    mhdr.savemode = 0;
    mhdr.filemode = 0;

    if(valid_ident(muser.email) && !invalidaddr(muser.email)) {
    char title[80], *ptr;
    unsigned short checksum;            /* 16-bit is enough */
    char ch;
    
    checksum = searchuser(muser.userid);
    ptr = muser.email;
    while((ch = *ptr++)) {
        if(ch <= ' ')
        break;
        if(ch >= 'A' && ch <= 'Z')
        ch |= 0x20;
        checksum = (checksum << 1) ^ ch;
    }
    
    sprintf(title, "[PTT BBS]To %s(%d:%d) [User Justify]",
        muser.userid, getuser(muser.userid) + MAGIC_KEY, checksum);
    if(
#ifndef USE_BSMTP
        bbs_sendmail(NULL, title, muser.email)
#else
        bsmtp(NULL, title, muser.email, MQ_JUSTIFY);
#endif
        < 0)
        Link("etc/bademail", buf1);
    else
        Link("etc/replyemail", buf1);
    } else
    Link("etc/bademail", buf1);
    sethomedir(title, muser.userid);
    append_record(title, &mhdr, sizeof(mhdr));
}
#endif /* EMAIL_JUSTIFY */