/*  
　　このプログラムはＳＭＣ−ＮＥＴが配布しているＭＢＸ(MS-DOS版)の添付ソフトで、
　　メールデータベースの主にリスト出力を行うプログラムです。
　　　　　　　MBLS.C　　このプログラム
　　　　　　　MBFUNC.C　サブルーチンの集まり
　　　　　　　TIMECVT.C サブルーチン
              MBTOOL.H　ヘッダーファイル

    MBLS  MBX Tool  -LS-  original JA3JWI yamada 
                          modified JH1RSV shimizu
                          modified JH1NAI goda      V1.3 1989-1-14
                                   JH1NAI Goda      V2.4 1991-4-20
*/
#include "mbtool.h"
#include <time.h>

/*  MS-DOS or PC-DOS */
#define RCFILE  "mbxrc"   

extern char *strlwr(), *strupr() ; 

extern int  errno;                  /* AY-880101 */
char	*prognam = "MBLS" ;         /* 1989-1-8 jh1nai */
static char daytime[20];
char status;

short ufwdm, ufwdn, bfwdm, bfwdn;
char  *mm[num_mm];
MAIL_HDR  *mfhs;
MSG_HDR   *mmhs;
MSG_EXT   *mmes;
MSG_BID	  *msgbid;

word local;
int mfl;
char tmpbuf[BUFSIZ];
char	ucall[ln_call];
byte	uoptions;

char	*msg;
char	type;
long	newthan, oldthan;
int	mine, withbid, expand, convt;
int	uflag;

/*
 *  Open the mail file.
 */

opnmsg(path)
char *path;
{
/*
 *  Allocate space for the mail file records.
 */

  if ((mfhs	=  (MAIL_HDR *) malloc(sizeof(MAIL_HDR))) == NULL) {
	fprintf(stderr,"%s: Can't get memory\n",prognam); exit(1);
  }
  if ((msgbid = (MSG_BID *) malloc(sizeof(MSG_BID))) == NULL) {
	fprintf(stderr,"%s: Can't get memory\n",prognam); exit(1);
  }
  if ((mmhs =  (MSG_HDR *) malloc(sizeof(MSG_HDR))) == NULL) {
	fprintf(stderr,"%s: Can't get memory\n",prognam); exit(1);
  }
  if ((mmes	=  (MSG_EXT *)	malloc(sizeof(MSG_EXT))) == NULL) {
	fprintf(stderr,"%s: Can't get memory\n",prognam); exit(1);
  }
  if ((mfl = open(path, (O_RDONLY|O_BINARY))) < 0) {
	fprintf(stderr,"%s: Can't open \"%s\".\n", prognam, path); exit(1);
  }
  if(!(read_rec(mfl, 0, (char *)mfhs))) {
	fprintf(stderr,"%s: Can't read first block.\n", prognam); exit(1);
  }
}

/*
 *  Check TO or FROM.
 */

permit(tocall, fmcall)
char *tocall, *fmcall ;
{
   char call [ln_call+3] ;

	if (!(*tocall && *fmcall))
		return true;
        unbl ( call, mmhs->to, ln_call) ;  /* 1989-1-8 jh1nai */
        if (wcm (tocall, call))
		return true;
        unbl (call, mmhs->from, ln_call) ; /* 1989-1-8 jh1nai */
        
        if (wcm (fmcall, call))
		return true;

	return false;
}

usage(msg)
char *msg;
{
    fprintf(stderr, "\n %s   MBX-Tool  * MBLS *  V2.4 \n",prognam) ;
    fprintf(stderr, " Copyright by SMC-NET Apr.20,1991. \n\n") ;
    fprintf(stderr,
                " USAGE : %s [opts][lopt][> file_name]\n", prognam);
    fprintf(stderr, " opts:\n");
    fprintf(stderr, "   -@ call: list all of @ call mail\n");
    fprintf(stderr, "   -$: list mail with Bulletin ID \n");
    fprintf(stderr, "   -L[NO] mmmm: list from(New/Old) mail_NO. mmmm \n");
    fprintf(stderr, "   -8: list mail with 8bit-code title \n") ;
    fprintf(stderr, "   -D[NO] nn: list New/Old than nn Days\n");
    fprintf(stderr, "   -F call: list all of From: call mail\n");
    fprintf(stderr, "   -# nn: list latest nn mails\n");
    fprintf(stderr, "   -M call: list Mine.\n");
    fprintf(stderr, "   -N yymmdd[hhmmss]: list mail new than yymmdd[hhmmss]\n");
    fprintf(stderr, "   -O yymmdd[hhmmss]: list mail old than yymmdd[hhmmss]\n");
    fprintf(stderr, "   -P[BPT]: select message type. \n") ;
    fprintf(stderr, "   -S[YNFCKU]: Select by Message Status.\n");
    fprintf(stderr, "   -T call: list all of TO: call mail\n");
    fprintf(stderr, "   -W out-file: Add write filename to -R option\n");
    fprintf(stderr, " lopt:  list_out format option\n") ;
    fprintf(stderr, "   -K:(Kill) -R:(Read) -E:(Extend) -C:(AWK) \n") ;
	exit(1);
}

/*
 *  L command, list messages.
 */

main(argc, argv)
int argc;
char *argv[];
{
register FILE *rcfile;
register int newcheck, oldcheck, typecheck, statcheck;
register short done, ok, nmsg, kflag;
word h, found, smsg,emsg, ok10, ok20, ok1,ok3,ok6,ok7,ok8,ok9,ok12;
word ok13, make_batch;
char newctime[ln_date + ln_time + 3], oldctime[ln_date + ln_time + 3];
long temp, oldtime, newtime, timecvt();
int  atcheck, tocheck, fmcheck, otcheck ;
char    *atcall, *fmcall, *tocall, filename[80], buf[80], ofile[80];

	/* prognam = argv[0];   1989-1-8 jh1nai */

	if ((rcfile = fopen(RCFILE, "r")) == NULL)
	{
		fprintf(stderr, "%s: Can't open %s\n", prognam, RCFILE);
		exit(1);
	}

	fgets(filename, sizeof(filename), rcfile);

	for (atcall = filename; *atcall; atcall++)
	{
		if (*atcall <= 0x20)
		{
			*atcall = '\0';
			break;
		}
	}

        fmcall = atcall = tocall = "";
	statcheck = typecheck = local = uflag = mine = 0;
        make_batch = oldcheck = withbid = emsg = found = expand = 0;
        newcheck = atcheck = tocheck = fmcheck = kflag = convt = otcheck = 0;
        nmsg = 65535; smsg = 65535; ofile[0] = '\0';

	/* newthan oldthan will be set here */

/*
 *  First set up arguments.
 */
    while (--argc != 0 && ((**++argv == '-')||(**argv == '/'))) {
            char *optp = *argv;

            switch (*++optp) {
                case '$':                       /* Bid */
                        withbid = 1; break;
                case 'c': case 'C' :          /* convert for awk */
                        convt = 1; break;
                case 'D':case 'd':
                        if (--argc) {
                                cvtdaytime(*++argv);
                                temp = timecvt(daytime);
                                        switch(*++optp) {
			                    case 'o': case 'O' :
						oldcheck = 1;
						oldthan = temp;
						break;
			                    case 'n': case 'N' :
						newcheck = 1;
						newthan = temp;
						break;
                                            default:
						usage(prognam);
					}
                        } else {
                                usage(prognam);
                        } break;
                case 'S': case 's':          /* Check by Status */
                        statcheck = 1;
                        switch(*++optp) {
                                case 'Y':  case 'y' :
					status |= m_read; break;
                                case 'N':  case 'n' :
					status |= 0; break;
                                case 'F':  case 'f' :
					status |= m_fwd; break;
                                case 'C':  case 'c' :
					status |= m_chk; break;
                                case 'U':  case 'u' :
					status |= m_unk; break;
                                case 'K':  case 'k' :
					status |= m_known; break;
				default:
                                        usage(prognam);
                        }
                        break;
                case 'P': case 'p' :          /* Check by type */
                        strupr(++optp);
                        typecheck = 1;
                        if ((type = *optp) == '\0') type = ' ';
                        break;
                case 'e': case 'E' :          /* Show expanded Item */
                        expand = 1; break;
	  	case 'u':			/* unread */
                        uflag = 1; break;
                case '8':            /* list kanji hdr */
                        kflag = 1; break;
                case 'K': case 'k' :          /* Create Batch file "K"*/
                        make_batch = 1; break;
                case 'R': case 'r' :          /* Create Batch file "R"*/
                        make_batch = 2; break;
                case 'j':           /* Use local time */
                        local = 1; break;
                case 'L': case 'l' :
                        if (--argc == 0) usage(prognam);
                        /*nmsg = */smsg = 65535 ;
                        emsg = atoi(*++argv);
                        switch (*++optp){
                                case 'N':case 'n': /* new than nnn */
                                        emsg++ ; break ;
                                case 'O': case 'o': /* Old than nnn */
                                        smsg = emsg - 1 ; emsg = 0; break;
                        }
                        break;
                case '#':
                        if (--argc == 0) usage(prognam);
                        /* smsg = 65535; emsg = 0 ; */
                        nmsg = atoi(*++argv) ;
                        break;
                case 'n': case 'N':          /* new than */
                        if (--argc == 0) usage(prognam);
                        newcheck = 1; argv++;
                        if (strlen(*argv) < 12) {
                                strcpy(newctime, *argv);
                                strncat(newctime, "000000000000",
                                                         12-strlen(*argv));
                        }
                        if((newthan = timecvt(newctime)) == 0) exit(1);
                        break;
                case 'o': case 'O' :         /* older than */
                        if (--argc == 0) usage(prognam);
                        argv++; oldcheck = 1;
                        if (strlen(*argv) < 12) {
                                strcpy(oldctime, *argv);
                                strncat(oldctime, "000000000000",
                                                         12-strlen(*argv));
                        }
                        if((oldthan = timecvt(oldctime)) == 0) exit(1);
                        break;
                case '@':                   /* At bbs */
                        if (--argc == 0) *atcall = '\0' ;
                            else { atcall = *++argv;
                                   if (*atcall == '@') *atcall = '\0' ; }
                        strupr(atcall);
                        atcheck = 1;
                        break;
                case 'f': case 'F' :          /* from */
                        if (--argc == 0) usage(prognam);
                        fmcall = *++argv;
                        strupr(fmcall);
                        fmcheck = 1;
                        break;
                case 'M': case 'm' :         /* Mine */
                        if (--argc == 0) usage(prognam);
                        fmcall = *++argv;
                        strupr(fmcall);
                        mine = 1;
                        break;
                case 'y':case 'Y':       /* path of source(mail.dat) */
                        if (--argc == 0) usage(prognam);
                        argv++;
                        strcpy(filename, *argv);
                        break;
                case 'W':case 'w':      /* SET output File */
                        if (--argc == 0) usage(prognam);
                        argv++;
                        strcpy(ofile,*argv);
                        break ;
                case 't': case 'T':          /* to */
                        if (--argc == 0) usage(prognam);
                        tocall = *++argv;
                        strupr(tocall);
                        tocheck = 1;
                        break;
                default: {
                         fprintf(stderr,
                             "%s: bad argument[s]= \"%c\"\n", prognam, *optp);
                         usage(prognam);
                         }

            }
        }
	opnmsg(filename);
/*
 *  Paw through the messages and show what requested.
 */

	done = false;
	for (h = mfhs->last; h and !done; h = mmhs->prev) {
		if (!(read_rec(mfl, h, (char *)mmhs))) {
			fprintf(stderr,"%s: Bad record size.\n",prognam);
			exit(1);
		}
                if (mmhs->number > smsg) continue;
                if (nmsg == 0)  done = true ;
                   else         done =  (mmhs->number < emsg);
                ok = !done;

/*
 *  Does this user have read permission for this message?
 */

 		if (ok) ok = permit(tocall, fmcall);

/*
 *  Is this message wanted?
 */
		ok1 = ok3 = ok6 = ok7 = ok8 = ok9 = 1;
		ok13 = ok12 = ok10= ok20 = 1;
		unbl(oldctime, mmhs->date, ln_date);
		unbl(oldctime+6, mmhs->time, ln_time);
		unbl(oldctime+10, "00", 2);

		if (newcheck) ok10 = (newthan < timecvt(oldctime));
		if (oldcheck) ok20 = (oldthan > timecvt(oldctime));
		if (withbid) ok1 = checkbid();
   		if (mine) ok3 = checkmine(fmcall);
		if (atcheck) ok6 = checkatcall(atcall);
		if (tocheck) ok7 = checktocall(tocall);
		if (fmcheck) ok8 = checkfmcall(fmcall);
		if (kflag) ok9 = checkkanji();
		if (statcheck) ok12 = statuscheck();
		if (typecheck) ok13 = checktype();

                if (ok && ok13 && ok10 && ok20 && ok1 && ok3
                        && ok6 && ok7 && ok8 && ok9 && ok12)

                {    nmsg-- ;
                     otcheck = 1 ;
                     switch (make_batch){    /* Feb.25,1990 */
                          case 1:
                                printf ("K %5u\n",mmhs->number) ; break ;
                          case 2:
                                printf ("R %5u",mmhs->number);
                                make_batch = 3 ;
                                break ;
                          case 3:
                                printf (" %5u", mmhs->number ) ; break ;
                          default:
                                prthdr(); break ;
                      }
                  }
        }
        if ((make_batch == 2) || (make_batch == 3))
                if ( (ofile[0]) && ( otcheck > 0 ) ) printf( " \> %s\n",ofile);
                                                  else printf ("\n") ;
}
statuscheck()
{
	if (mmhs->stat & status) return(1);
        if (mmhs->stat == status) return(1);

	return (0);
}

checktype()
{
	if (mmhs->type == type)
		return (1);
	return (0);
}

checkkanji()
{
register char *p;
register int i;

	for (p = mmhs->title, i = 0; *p && i < mhtitl; p++, i++) {
		if (*p & 0x80) return (1);
		if (*p == 0x1b) return (1);	/* Can't put ESC at Header */
	}
	return (0);
}

checkmine(fmcall)
char *fmcall;
{
register int ok;
char call[ln_call + 3], *name;


        unbl (call, mmhs->to, ln_call) ;

        ok = wcm(fmcall, call) ;
        unbl (call, mmhs->from, ln_call) ;

        if (!ok) ok = wcm (fmcall, call) ;

	return ok;
}

checkatcall(atcall)
char *atcall;
{
char *name, call[ln_call+3];

        unbl (call,mmhs->bbs,ln_call); /* 1989-1-8 */

        if (wcm (atcall, call)) return 1 ;
	return 0;
}

checkfmcall(fmcall)
char *fmcall;
{
char *name, call[ln_call+3];

        unbl (call, mmhs->from, ln_call) ; /* 1989-1-8 jh1nai */

        if (wcm (fmcall, call)) return 1 ;
	return 0;

}

checktocall(tocall)
char *tocall;
{
char *name, call[ln_call+3];


        unbl (call, mmhs->to, ln_call) ;   /* 1989-1-9 jh1nai */

        if (wcm (tocall, call)) return 1 ;
	return 0;
}

checkbid()
{
	if (mmhs->unu2) return 1; /* ";" delete  jh1nai */
	return 0;
}


/*
**	Out put K[ill] Command
prthdr2(i)
int i;
{       char c ;
        if (i == 1) c = 'K'; else c = 'R' ;
        printf("%c %5u\n", c, mmhs->number);
}
*/
/*
 *  Create the header line.
 */

makehdr() 
{
register char st, st1;
register int  i;
char fromcall[ln_call+1], tocall[ln_call+1], atcall[ln_call+1], tp[2];

	st = 'N'; st1 = ' ';
	if (mmhs->stat & m_read)
		st = 'Y';
	if (mmhs->stat & m_fwd)
		st = 'F';

	if (mmhs->ext)
	if(!(read_rec(mfl, mmhs->ext, (char *)mmes)))
		exit(1);

	if (mmhs->unu2) {
		if(!(read_rec(mfl, mmhs->unu2, (char *)msgbid)))
			exit(1); else

		if (*msgbid->bid && mmhs->stat & m_fwd)
			st1 = '@';
	}

	if (convt) {
		unbl(atcall, mmhs->bbs, ln_call);
		unbl(fromcall, mmhs->from, ln_call);
		unbl(tocall, mmhs->to, ln_call);

		if (mmhs->type == ' ')
			sprintf(tp, "%s", "");
		else
			sprintf(tp, "%c", mmhs->type);

		sprintf(tmpbuf,"%u:%s:%c:%u:%s:%s:%s:%6.6s%4.4s:",
		mmhs->number, tp, st, mmhs->size,
		tocall, fromcall, atcall, mmhs->date, mmhs->time);
		printf(tmpbuf);
		sprintf(tmpbuf, "%s\n", mmhs->title);

		if (mmhs->ext > 0) {
			if (mmhs->unu2 > 0)
				printf("%s:", msgbid->bid);
			else
				printf(":");

			for (i = 0; i < mmes->count; i++) {
				if (mmes->flag[i] == true)
					printf("+");
				else
					printf("-");
				unbl(tmpbuf, mmes->call[i], ln_call);
				strlwr(tmpbuf);
				printf("%s", tmpbuf);
			}
			printf(":");
		} else if (mmhs->unu2 > 0) {
			if ((mmhs->stat & m_read)||(mmhs->stat & m_fwd))
				printf("*");
			printf("%s:", msgbid->bid);
		} else {
			printf(":");
		}

		sprintf(tmpbuf, "%s\n", mmhs->title);
		return;
	}
  
	if (mmhs->unu2)
	if (*msgbid->bid)
		st = '$';
	if (mmhs->stat & m_chk)
		st = 'C';
	if (mmhs->stat & m_known)
		st = 'K';
	if (mmhs->stat & m_unk)
		st = 'U';

	if (mmhs->type == ' ')
		mmhs->type = '-';

	sprintf(tmpbuf,"%5u %c%c %5u %6.6s %6.6s %c%6.6s %4.4s/%4.4s %s\n",
			mmhs->number,
			mmhs->type,
			st,
			mmhs->size,
			mmhs->to,
			mmhs->from,
			st1,
			mmhs->bbs,
			mmhs->date + 2,
			mmhs->time,
			mmhs->title );

	if (strlen(tmpbuf) > 80) {
		if (mmhs->unu3)
			strcpy((tmpbuf + 78), "\n");
		else
			strcpy((tmpbuf + 79), "\n");
	}
}

/*
 *  Print a message header.
 */

prthdr()
{
register short i;
char to[ln_call + 1];

	makehdr();
        printf("%s",tmpbuf);            /* V2.4 Apr.20,91 */
	if (expand)
	if (mmhs->ext) {

		if (*msgbid->domain) {
			unbl(to, mmhs->to, ln_call);
			printf("   Address <%s@%s> ", to, msgbid->domain);
		}

		if (*msgbid->bid)
			printf("   Bul: [%s]", msgbid->bid);
		else
			printf("    Cc:");

		for (i = 0; i < mmes->count; i++) {
			if (mmes->flag[i])
				printf(" ");
			else
				printf(" *");
			unbl(tmpbuf, mmes->call[i], ln_call);
			strlwr(tmpbuf);
			printf(tmpbuf);
		}
		printf("\n");
		return;
	}
 
	if (expand)
	if (mmhs->unu2) {
		if (*msgbid->domain) {
			unbl(to, mmhs->to, ln_call);
			printf("   Address <%s@%s>", to, msgbid->domain);
		}

		if (*msgbid->bid) {
			sprintf(tmpbuf, "   Bid: [%s]\n", msgbid->bid);
			if (mmhs->stat & m_read) *(tmpbuf + 7) = '*';
			if (mmhs->stat & m_fwd)  *(tmpbuf + 7) = '*';
			printf(tmpbuf);
		} else {
			printf("\n");
		}
	}

}


cvtdaytime(date)
char *date;
{
long dt, t, time();
struct tm *l, *gmtime();

	dt = atoi(date);
	dt = dt * 24 * 60 * 60;

	t = time(0);
	if (t >= dt)
		t -= dt;
	if (local)
		l = localtime(&t);
	else
		l = gmtime(&t);

	sprintf(daytime, "%02d%02d%02d%02d%02d00",
		l->tm_year,
		l->tm_mon + 1,
		l->tm_mday,
		l->tm_hour,
		l->tm_min
		);
}
/*
 *      wild card match with ? and * in first arg.
*/
wcm(s1, s2)
char *s1, *s2 ;
{
        register short ln ;
        for (ln = 0; ln < ln_call, *s1; ln++, s1++, s2++) {
                if (*s1 == '*') return true ;
                if (*s1 != '?') if (*s1 != *s2) return false ;
        }
        if ( strlen(s1) != strlen(s2)) return false ;
        return true ;
}
