diff options
author | BBS Administrator <bbs@sony.tfcis.org> | 2013-02-08 16:53:05 +0800 |
---|---|---|
committer | BBS Administrator <bbs@sony.tfcis.org> | 2013-02-08 16:53:05 +0800 |
commit | 838b5338b88e0af60a8808036a0a2e17411db917 (patch) | |
tree | 875117556a8aef47d53a052eac76592de1ac1bca | |
download | sonybbs-838b5338b88e0af60a8808036a0a2e17411db917.tar.gz sonybbs-838b5338b88e0af60a8808036a0a2e17411db917.tar.zst sonybbs-838b5338b88e0af60a8808036a0a2e17411db917.zip |
SonyBBS Initial Commit - Version 20121021
301 files changed, 112879 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c37954d --- /dev/null +++ b/.gitignore @@ -0,0 +1,93 @@ +*.o +*.a +*.so +*.bak +*.duck +*.old* +*.swp +*.swo +/daemon/bguard +/daemon/bhttpd +/daemon/bmtad +/daemon/bnntpd +/daemon/bpop3d +/daemon/gemd +/daemon/xchatd +/innbbsd/bbslink +/innbbsd/innbbsd +/maple/bbsd +/util/account +/util/acl-sort +/util/backup/backupacct +/util/backup/backupbrd +/util/backup/backupgem +/util/backup/backupoth +/util/backup/backupusr +/util/backup/restoreacct +/util/backup/restorebrd +/util/backup/restoregem +/util/backup/restoreusr +/util/bbsmail +/util/bquota +/util/brdmail +/util/camera +/util/changeperm +/util/counter +/util/gem-index +/util/give_paycheck +/util/hdr-dump +/util/mailpost +/util/outgo +/util/poststat +/util/reaper +/util/redir +/util/setperm +/util/setusr +/util/showACCT +/util/showBRD +/util/showDIR +/util/showUSR +/util/showperm +/util/topgem +/util/topsong +/util/topusr +/util/tran/ats2bmw +/util/tran/ats2brd +/util/tran/ats2gem +/util/tran/ats2mf +/util/tran/ats2pal +/util/tran/ats2usr +/util/tran/brd2gem +/util/tran/cola2brd +/util/tran/cola2gem +/util/tran/cola2post +/util/tran/cola2usr +/util/tran/fb2brd +/util/tran/fb2gem +/util/tran/fb2pal +/util/tran/fb2usr +/util/tran/mag2brd +/util/tran/mag2gem +/util/tran/mag2usr +/util/tran/snap2brd +/util/tran/snap2usr +/util/tran/sob2brd +/util/tran/sob2gem +/util/tran/sob2pal +/util/tran/sob2usr +/util/tran/transacct +/util/tran/transbrd +/util/tran/wd2bmw +/util/tran/wd2brd +/util/tran/wd2gem +/util/tran/wd2list +/util/tran/wd2mf +/util/tran/wd2pal +/util/tran/wd2pip +/util/tran/wd2usr +/util/tran/windtop2brd +/util/tran/windtop2pip +/util/tran/windtop2usr +/util/uno/collect_uno +/util/uno/conflict_uno +/util/uno/fix_uno diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d3f5358 --- /dev/null +++ b/Makefile @@ -0,0 +1,147 @@ +# ------------------------------------------------------- # +# src/Makefile ( NTHU CS MapleBBS Ver 3.10 ) # +# ------------------------------------------------------- # +# target : Makefile for ALL # +# create : 00/02/12 # +# update : / / # +# ------------------------------------------------------- # + + +# ¤ä´©ªº OS-type +# sun linux solaris sol-x86 freebsd bsd cygwin + +# »Ýn compile ªº¥Ø¿ý +# lib daemon innbbsd maple so game pip util util/backup util/tran util/uno + + +all: + @echo "Please enter 'make sys-type', " + @echo " make sun : for Sun-OS 4.x and maybe some BSD systems, cc or gcc" + @echo " make linux : for Linux" + @echo " make solaris : for Sun-OS 5.x gcc" + @echo " make sol-x86 : for Solaris 7 x86" + @echo " make freebsd : for BSD 4.4 systems" + @echo " make bsd : for BSD systems, cc or gcc, if not in the above lists" + @echo " make cygwin : for Microsoft Windows and Cygwin gcc" + + +sun: + @cd lib; make + @cd daemon; make sun + @cd innbbsd; make sun + @cd maple; make sun + @cd so; make sun + @cd game; make sun + @cd pip; make sun + @cd util; make sun + @cd util/backup; make sun + @cd util/tran; make sun + @cd util/uno; make sun + +linux: + @cd lib; make + @cd daemon; make linux + @cd innbbsd; make linux + @cd maple; make linux + @cd so; make linux + @cd game; make linux + @cd pip; make linux + @cd util; make linux + @cd util/backup; make linux + @cd util/tran; make linux + @cd util/uno; make linux + +solaris: + @cd lib; make + @cd daemon; make solaris + @cd innbbsd; make solaris + @cd maple; make solaris + @cd so; make solaris + @cd game; make solaris + @cd pip; make solaris + @cd util; make solaris + @cd util/backup; make solaris + @cd util/tran; make solaris + @cd util/uno; make solaris + +sol-x86: + @cd lib; make + @cd daemon; make sol-x86 + @cd innbbsd; make sol-x86 + @cd maple; make sol-x86 + @cd so; make sol-x86 + @cd game; make sol-x86 + @cd pip; make sol-x86 + @cd util; make sol-x86 + @cd util/backup; make sol-x86 + @cd util/tran; make sol-x86 + @cd util/uno; make sol-x86 + +freebsd: + @cd lib; make + @cd daemon; make freebsd + @cd innbbsd; make freebsd + @cd maple; make freebsd + @cd so; make freebsd + @cd game; make freebsd + @cd pip; make freebsd + @cd util; make freebsd + @cd util/backup; make freebsd + @cd util/tran; make freebsd + @cd util/uno; make freebsd + +bsd: + @cd lib; make + @cd daemon; make bsd + @cd innbbsd; make bsd + @cd maple; make bsd + @cd so; make bsd + @cd game; make bsd + @cd pip; make bsd + @cd util; make bsd + @cd util/backup; make bsd + @cd util/tran; make bsd + @cd util/uno; make bsd + +cygwin: + @cd lib; make + @cd daemon; make cygwin + @cd innbbsd; make cygwin + @cd maple; make cygwin + @cd so; make cygwin + @cd game; make cygwin + @cd pip; make cygwin + @cd util; make cygwin + @cd util/backup; make cygwin + @cd util/tran; make cygwin + @cd util/uno; make cygwin + +install: + @cd daemon; make install + @cd innbbsd; make install + @cd maple; make install + @cd so; make install + @cd game; make install + @cd pip; make install + @cd util; make install + @cd util/backup; make install + @cd util/tran; make install + @cd util/uno; make install + +update: + @cd daemon; make update + @cd innbbsd; make update + @cd maple; make update + +clean: + @cd lib; make clean + @cd daemon; make clean + @cd innbbsd; make clean + @cd maple; make clean + @cd so; make clean + @cd game; make clean + @cd pip; make clean + @cd util; make clean + @cd util/backup; make clean + @cd util/tran; make clean + @cd util/uno; make clean diff --git a/daemon/Makefile b/daemon/Makefile new file mode 100644 index 0000000..b65a717 --- /dev/null +++ b/daemon/Makefile @@ -0,0 +1,65 @@ +# ------------------------------------------------------- # +# util/Makefile ( NTHU CS MapleBBS Ver 3.10 ) # +# ------------------------------------------------------- # +# target : Makefile # +# create : 95/03/29 # +# update : 95/12/15 # +# ------------------------------------------------------- # + + +# ------------------------------------------------------ # +# ¤U¦Cªº make rules ¤£»Ý×§ï # +# ------------------------------------------------------ # + +#EXE = bguard bhttpd bmtad bnntpd bpop3d gemd xchatd +EXE = bguard bmtad bnntpd bpop3d gemd xchatd + +all: + @echo "Please enter 'make sys-type', " + @echo " make sun : for Sun-OS 4.x and maybe some BSD systems, cc or gcc" + @echo " make linux : for Linux" + @echo " make solaris : for Sun-OS 5.x gcc" + @echo " make sol-x86 : for Solaris 7 x86" + @echo " make freebsd : for BSD 4.4 systems" + @echo " make bsd : for BSD systems, cc or gcc, if not in the above lists" + @echo " make cygwin : for Microsoft Windows and Cygwin gcc" + +sun: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -fomit-frame-pointer -Wunused -I../include" LDFLAGS="-s -L../lib -ldao" $(EXE) + +linux: + @$(MAKE) CC=gcc CFLAGS="-DLINUX -O2 -pipe -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao -lcrypt -lresolv" $(EXE) + +solaris: + @$(MAKE) CC=gcc CFLAGS="-DSOLARIS -O2 -pipe -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao -lsocket -lresolv -lnsl -L/usr/ucblib -lucb -R/usr/ucblib" $(EXE) + +sol-x86: + @$(MAKE) CC=gcc CFLAGS="-DSOLARIS -O2 -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao -lsocket -lresolv -lnsl" $(EXE) + +freebsd: + @$(MAKE) CC=gcc CFLAGS="-DBSD44 -O2 -pipe -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao -lcrypt" $(EXE) + +bsd: + @$(MAKE) CC=gcc CFLAGS="-DBSD44 -O2 -pipe -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao" $(EXE) + +cygwin: + @$(MAKE) CC=gcc CFLAGS="-DLINUX -DCYGWIN -O2 -pipe -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao -lcrypt -lresolv -lcygipc" $(EXE) + + +.c: ; $(CC) -o $@ $@.c $(CFLAGS) $(LDFLAGS) + + +install: $(EXE) + install -m 0700 $? $(HOME)/bin + +update: + -csh -c "kill `tail -1 $(HOME)/run/bguard.pid | awk '{print $$1}'`";exit 0 + -csh -c "kill `tail -1 $(HOME)/run/bhttp.pid | awk '{print $$1}'`";exit 0 + -csh -c "kill `tail -1 $(HOME)/run/bmta.pid | awk '{print $$1}'`";exit 0 + -csh -c "kill `tail -1 $(HOME)/run/bnntp.pid | awk '{print $$1}'`";exit 0 + -csh -c "kill `tail -1 $(HOME)/run/pop3.pid | awk '{print $$1}'`";exit 0 + -csh -c "kill `tail -1 $(HOME)/run/gemd.pid | awk '{print $$1}'`";exit 0 + -csh -c "kill `tail -1 $(HOME)/run/chat.pid | awk '{print $$1}'`";exit 0 + +clean: + rm -f $(EXE) *.exe *.o *~ diff --git a/daemon/bguard.c b/daemon/bguard.c new file mode 100644 index 0000000..6a05755 --- /dev/null +++ b/daemon/bguard.c @@ -0,0 +1,1229 @@ +/*-------------------------------------------------------*/ +/* util/bguard.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : BBS finger daemon ¦C¥X¯¸¤º¨Ï¥ÎªÌ¸ê®Æ */ +/* create : 96/11/20 */ +/* update : 96/12/15 */ +/*-------------------------------------------------------*/ +/* syntax : bguard */ +/*-------------------------------------------------------*/ +/* notice : ushm (utmp shared memory) synchronize */ +/*-------------------------------------------------------*/ + + +#define _MODES_C_ +#define VERBOSE +#define WATCH_DOG + + +#include "bbs.h" + + +#include <sys/ipc.h> + +#ifdef HAVE_SEM +#include <sys/sem.h> +#endif + +#include <sys/shm.h> +#include <sys/resource.h> +#include <sys/wait.h> +#include <netinet/tcp.h> + + +static int gline; + + +#ifdef WATCH_DOG +# define MYDOG gline = __LINE__ +#else +# define MYDOG /* NOOP */ +#endif + + +#define GUARD_LOGFILE "run/bguard.log" +#define GUARD_PIDFILE "run/bguard.pid" + + +#define LOAD_INTERVAL 90 /* check system load */ +#define GUARD_INTERVAL 60 /* check user status */ +#define FINGER_INTERVAL (30 * 60) + + +#define FINGER_TIMEOUT (60 * 3) + + +#define TCP_QLEN 3 +#define TCP_BUFSIZ (512 * 7) +#define TCP_LINSIZ 256 +#define TCP_RCVSIZ 128 + + +/* ----------------------------------------------------- */ +/* client connection structure */ +/* ----------------------------------------------------- */ + + +typedef struct Agent Agent; + + +struct Agent +{ + Agent *next; + int sock; + int state; + int locus; + time_t uptime; /* «Ø¥ß connection ªº®É¶¡ */ + + int count; /* ½u¤W¦@¦³¦h¤Ö¤H¡H */ + UTMP *uentp; + + char pool[TCP_BUFSIZ]; /* buffered I/O pool */ + + /* Thor:980726: ending zero for string */ + char ZERO; +}; + + +/* ----------------------------------------------------- */ +/* connection state */ +/* ----------------------------------------------------- */ + + +#define CS_FREE 0x00 +#define CS_READING 0x01 +#define CS_WRITING 0x02 + + +/* ----------------------------------------------------- */ +/* operation log and debug information */ +/* ----------------------------------------------------- */ + + +static FILE *flog; /* log file descriptor */ + + +extern int errno; + + +static void +logit(key, msg) + char *key; + char *msg; +{ + time_t now; + struct tm *p; + + time(&now); + p = localtime(&now); + fprintf(flog, "%02d/%02d %02d:%02d:%02d %-8s%s\n", + p->tm_mon + 1, p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec, key, msg); +} + + +static void +log_open() +{ + FILE *fp; + + umask(077); + + if (fp = fopen(GUARD_PIDFILE, "w")) + { + fprintf(fp, "%d\n", getpid()); + fclose(fp); + } + + flog = fopen(GUARD_LOGFILE, "a"); + logit("START", "guard (finger) daemon"); +} + + +/*-------------------------------------------------------*/ +/* .UTMP cache */ +/*-------------------------------------------------------*/ + + +static UCACHE *ushm; +static UTMP *ushm_head, *ushm_tail; + + +static void +attach_err(shmkey, name) + int shmkey; + char *name; +{ + char buf[80]; + + sprintf(buf, "error, key = %x", shmkey); + logit(name, buf); + exit(1); +} + + +#ifdef HAVE_SEM +/* ----------------------------------------------------- */ +/* semaphore : for critical section */ +/* ----------------------------------------------------- */ + + +static int mysemid; + + +static void +resolve_sem() +{ + int semid; + + union semun + { + int val; + struct semid_ds *buf; + ushort *array; + } arg = + { + 1 + }; + + semid = semget(BSEM_KEY, 1, 0); + if (semid == -1) + { + semid = semget(BSEM_KEY, 1, IPC_CREAT | BSEM_FLG); + if (semid == -1) + attach_err(BSEM_KEY, "semget"); + semctl(semid, 0, SETVAL, arg); + } + mysemid = semid; +} + + +static void +sem_lock(op) + int op; /* op is BSEM_ENTER or BSEM_LEAVE */ +{ + struct sembuf sops; + + sops.sem_num = 0; + sops.sem_flg = SEM_UNDO; + sops.sem_op = op; + semop(mysemid, &sops, 1); +} +#endif /* HAVE_SEM */ + + +static void +init_ushm() +{ + UCACHE *xshm; + int shmsize; + int shmid; + + shmsize = sizeof(UCACHE); + shmid = shmget(UTMPSHM_KEY, shmsize, 0); + if (shmid < 0) + { + shmid = shmget(UTMPSHM_KEY, shmsize, IPC_CREAT | 0600); + if (shmid < 0) + attach_err(UTMPSHM_KEY, "shmget"); + } + else + { + shmsize = 0; + } + + xshm = (UCACHE *) shmat(shmid, NULL, 0); + if (xshm == (UCACHE *) - 1) + attach_err(UTMPSHM_KEY, "shmat"); + + if (shmsize) + { + memset(xshm, 0, shmsize); + if (xshm->mbase < xshm->mpool) + xshm->mbase = xshm->mpool; + } + + ushm = xshm; + ushm_head = xshm->uslot; + ushm_tail = ushm_head + MAXACTIVE; +} + + +static void +ushm_guard() +{ + static int flip; + int flop; + usint count; + UTMP *uentp, *uceil, *utail; + int idle; + pid_t pid; + UCACHE *xshm; + char buf[128]; +#ifdef DETAIL_IDLETIME + time_t now; +#endif + + flop = ++flip; + count = 0; + uentp = ushm_head; + utail = ushm_tail; + uceil = uentp; + +#ifdef HAVE_SEM + sem_lock(BSEM_ENTER); +#endif + +#ifdef DETAIL_IDLETIME + time(&now); +#endif + + do + { + flop++; + if (pid = uentp->pid) + { +#ifdef DETAIL_IDLETIME + idle = (now - uentp->idle_time) / 60; +#else + idle = uentp->idle_time; +#endif + if (flop & 15) + { +#ifdef TIME_KICKER + if (idle >= IDLE_TIMEOUT) + { + errno = 0; + if ((kill(pid, SIGTERM) < 0) && (errno == ESRCH)) + { + uentp->pid = uentp->userno = 0; + ushm->count--; + } + } + else +#endif + { + if (uceil < uentp) + uceil = uentp; + count++; + } + } + else + { + int sig; + + errno = sig = 0; + +#ifdef TIME_KICKER + if (idle >= IDLE_TIMEOUT) + sig = SIGTERM; +#endif + + if ((kill(pid, sig) < 0) && (errno == ESRCH)) + { + uentp->pid = uentp->userno = 0; + ushm->count--; + } + else + { + if (!sig) + { + if (uceil < uentp) + uceil = uentp; + count++; + } + } + } + } + } while (++uentp < utail); + + xshm = ushm; + xshm->count = count; + xshm->offset = (void *) uceil - (void *) ushm_head; + +#ifdef HAVE_SEM + sem_lock(BSEM_LEAVE); +#endif + +#ifdef VERBOSE + sprintf(buf, "%d %p (%p - %p)", count, uceil, ushm_head, utail); + logit("count", buf); +#endif +} + + +/*-------------------------------------------------------*/ +/* check system / memory / CPU loading */ +/*-------------------------------------------------------*/ + + +static int fkmem; + + +#ifdef SOLARIS +static void +chkload_init() +{ +#include <nlist.h> +#define VMUNIX "/dev/ksyms" +#define KMEM "/dev/kmem" + /* Thor.981207: °O±ocheck permission nbbs readable */ + + static struct nlist nlst[] = + { + {"avenrun"}, + {0} + }; + + int kmem; + long offset; + + nlist(VMUNIX, nlst); + if (nlst[0].n_type == 0) + exit(1); + offset = (long) nlst[0].n_value; + + if ((kmem = open(KMEM, O_RDONLY)) == -1) + exit(1); + + if (lseek(kmem, offset, L_SET) == -1) + exit(1); + + fkmem = kmem; +} +#endif + + +static void +chkload() +{ + + struct + { + int avgload; + double sysload[3]; + } myload; +#define cpu_load myload.sysload + + +#if defined(LINUX) + FILE *fp; + + MYDOG; + fp = fopen("/proc/loadavg", "r"); + if (!fp) + cpu_load[0] = cpu_load[1] = cpu_load[2] = 0; + else + { + float av[3]; + + fscanf(fp, "%g %g %g", av, av + 1, av + 2); + fclose(fp); + cpu_load[0] = av[0]; + cpu_load[1] = av[1]; + cpu_load[2] = av[2]; + } + +#elif defined(BSD44) + getloadavg(cpu_load, 3); + +#else + + long avenrun[3]; + int i; + + i = fkmem; + + if (read(i, (char *) avenrun, sizeof(avenrun)) == -1) + exit(1); + + lseek(i, -(off_t) sizeof(avenrun), SEEK_CUR); + +#define loaddouble(la) ((double)(la) / (1 << 8)) + + for (i = 0; i < 3; i++) + cpu_load[i] = loaddouble(avenrun[i]); + + /* Thor.980728: lkchu patch: linux³¡¤À¤Î bsd³¡ ¤À¤w¦³©w cpu_load */ + +#endif + + myload.avgload = cpu_load[0] + cpu_load[1] * 4; + /* memcpy(&ushm->avgload, &myload, sizeof(myload)); */ + + ushm->avgload = myload.avgload; + ushm->sysload[0] = myload.sysload[0]; + ushm->sysload[1] = myload.sysload[1]; + ushm->sysload[2] = myload.sysload[2]; +} + + +/* ----------------------------------------------------- */ +/* server side stuff */ +/* ----------------------------------------------------- */ + + +static char * +mail_string(fpath) + char *fpath; +{ + char *answer; + int fd, size; + struct stat st; + + answer = "³£¬Ý¹L¤F"; + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + if (!fstat(fd, &st) && (size = st.st_size) > 0) + { + char *fimage; + HDR *fhdr; + + fimage = (char *) malloc(size); + read(fd, fimage, size); + fhdr = (HDR *) (fimage + size); + while (--fhdr >= (HDR *) fimage) + { + if (!(fhdr->xmode & MAIL_READ)) + { + answer = "¦³·s«H¥ó"; + break; + } + } + free(fimage); + } + close(fd); + } + + return answer; +} + + +static void +serve_finger(ap) + Agent *ap; +{ + char *base, *head, fpath[128]; + int fd; + + base = head = ap->pool; + + /* Thor.980726: pool¤º®e¤£·|¶W¹L idlen */ + head[IDLEN] = '\0'; + + + sprintf(fpath, "usr/%c/%s/.ACCT", *head, head); + + MYDOG; + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + char *str, *mailstr, *modestr; + UTMP *uentp, *utail; + int len; + ACCT acct; + + read(fd, &acct, sizeof(ACCT)); + close(fd); + + /* ¬O§_¦³·s«H¥óÁÙ¨S¬Ý¡H */ + + str = (char *) strchr(fpath, '.'); + strcpy(str, FN_DIR); + MYDOG; + mailstr = mail_string(fpath); + + /* ¬O§_¦b½u¤W¡H */ + + MYDOG; + + uentp = ushm_head; + utail = ushm_tail; + fd = acct.userno; + modestr = "¤£¦b¯¸¤W"; + + do + { + if (fd == uentp->userno && !(uentp->ufo & (UFO_CLOAK | UFO_SUPERCLOAK))) + { + modestr = ModeTypeTable[uentp->mode]; + break; + } + } while (++uentp < utail); + + sprintf(head, "%s(%s) ¦@¤W¯¸ %d ¦¸¡Aµoªí¤å³¹ %d ½g¡C\n" + "³Ìªñ(%s)¨Ó¦Û(%s)\n%s³q¹L¨¤À»{ÃÒ [°ÊºA] %s [«H½c] %s\n", + acct.userid, acct.username, acct.numlogins, acct.numposts, + Btime(&(acct.lastlogin)), acct.lasthost, + acct.userlevel & PERM_VALID ? "¤w¸g" : "©|¥¼", + modestr, mailstr); + + head += strlen(head); + + /* Åã¥Ü [¦W¤ù/pµeÀÉ] */ + + MYDOG; + strcpy(str, FN_PLANS); + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + strcpy(head, "[pµe]\n"); + head += strlen(head); + + /* °²³] buffer ºïºï¦³¾l¡AÅý¨Æ±¡Â²¤Æ */ + + len = read(fd, head, TCP_BUFSIZ - (head - base) - 10); + close(fd); + + if (len > 0) + { + head += len; + strcpy(head, "\033[m\n"); + head += strlen(head); + } + } + } + else + { + strcat(head, " ==> not exist here.\n"); + head += strlen(head); + } + + ap->locus = head - base; + ap->count = -1; /* ¥Nªí end of transmission */ +} + + +static void +serve_userlist(ap) + Agent *ap; +{ + int count; + UTMP *uentp, *utail; + char *base, *head, *tail; + + count = ap->count; + uentp = ap->uentp; + utail = ushm_tail; + + base = ap->pool; + head = base + ap->locus; + tail = base + TCP_BUFSIZ - TCP_LINSIZ; + + for (;;) + { + if (uentp->pid && uentp->userno && +#ifdef HAVE_SUPERCLOAK + !(uentp->ufo & UFO_SUPERCLOAK) && +#endif + !(uentp->ufo & UFO_CLOAK)) /* lkchu.990118: Áô¨¤£Åã¥Ü */ + { + sprintf(head, "%-13s%-25s%-30.29s%s\n", + uentp->userid, uentp->username, uentp->from, + ModeTypeTable[uentp->mode]); + count++; + head += strlen(head); + if (head > tail) + { + uentp++; + break; + } + } + + if (++uentp >= utail) + { + sprintf(head, "============ ======================== ============================= ==========\n" + "¡i" BBSNAME "¡j Total users = %d\n", count); + head += strlen(head); + count = -1; + break; + } + } + + ap->uentp = uentp; + ap->count = count; + ap->locus = head - base; +} + + +/* ----------------------------------------------------- */ +/* client's service dispatcher */ +/* ----------------------------------------------------- */ + + +static void +agent_serve(ap) + Agent *ap; +{ + char *cmd, *str; + int ch; + + cmd = str = ap->pool; + + while (ch = *str) + { + str++; + if (ch != ' ' && ch != '\t') + { + if (ch >= 'A' && ch <= 'Z') + ch |= 0x20; + else if (ch == '.' || ch == '@') + { + *cmd = '\0'; + break; + } + *cmd++ = ch; + } + } + + str = ap->pool; + ap->state = CS_WRITING; + if (str == cmd) + { + strcpy(str, "ID Nick From Mode\n" + "============ ======================== ============================= ==========\n"); + ap->locus = strlen(str); + ap->count = 0; + ap->uentp = ushm_head; + serve_userlist(ap); + } + else + { + serve_finger(ap); + } +} + + +/* ----------------------------------------------------- */ +/* send output to client */ +/* ----------------------------------------------------- */ + + +static int +agent_write(ap) + Agent *ap; +{ + int len, bytes; + char *str; + + len = ap->locus; + str = ap->pool; + bytes = send(ap->sock, str, len, 0); + if (bytes <= 0) + { + len = errno; + if (len != EWOULDBLOCK) + { + logit("write", strerror(len)); + return 0; + } + + return -1; + } + + len -= bytes; + ap->locus = len; + if (len) + { + memcpy(str, str + bytes, len); + return bytes; + } + + if (ap->count >= 0) + { + serve_userlist(ap); + return bytes; + } + + return 0; +} + + +/* ----------------------------------------------------- */ +/* receive request from client */ +/* ----------------------------------------------------- */ + + +static int +agent_read(ap) + Agent *ap; +{ + int pos, len, cc; + char *str; + + pos = ap->locus; + str = &ap->pool[pos]; + len = recv(ap->sock, str, BMIN(TCP_RCVSIZ, sizeof(ap->pool)-pos), 0); + /* Thor.980726: Á×§K pool overflow */ + + if (len <= 0) + { + len = errno; + if (len != EWOULDBLOCK) + { + logit("read", strerror(len)); + return 0; + } + + return -1; /* would block, so leave it to do later */ + } + + str[len] = '\0'; + + while (cc = *str) + { + if (cc == '\r' || cc == '\n') + { + *str = '\0'; + agent_serve(ap); + return 1; + } + str++; + } + + ap->locus = pos + len; + return 1; +} + + +/* ---------------------------------------------------- */ +/* server core routines */ +/* ---------------------------------------------------- */ + + +static void +servo_daemon(inetd) + int inetd; +{ + int fd, value; + char buf[80]; + struct sockaddr_in sin; + struct linger ld; + + /* + * More idiot speed-hacking --- the first time conversion makes the C + * library open the files containing the locale definition and time zone. + * If this hasn't happened in the parent process, it happens in the + * children, once per connection --- and it does add up. + */ + + time_t dummy; + struct tm *dummy_time; + +#ifdef HAVE_RLIMIT + struct rlimit limit; +#endif + + time(&dummy); + dummy_time = gmtime(&dummy); + dummy_time = localtime(&dummy); + strftime(buf, 80, "%d/%b/%Y:%H:%M:%S", dummy_time); + +#ifdef HAVE_RLIMIT + /* --------------------------------------------------- */ + /* adjust the resource limit */ + /* --------------------------------------------------- */ + + getrlimit(RLIMIT_NOFILE, &limit); + limit.rlim_cur = limit.rlim_max; + setrlimit(RLIMIT_NOFILE, &limit); + + limit.rlim_cur = limit.rlim_max = 16 * 1024 * 1024; + setrlimit(RLIMIT_FSIZE, &limit); + + limit.rlim_cur = limit.rlim_max = 4 * 1024 * 1024; + setrlimit(RLIMIT_DATA, &limit); + +#ifdef SOLARIS +#define RLIMIT_RSS RLIMIT_AS /* Thor.981206: port for solaris 2.6 */ +#endif + + setrlimit(RLIMIT_RSS, &limit); + + limit.rlim_cur = limit.rlim_max = 0; + setrlimit(RLIMIT_CORE, &limit); +#endif + + /* --------------------------------------------------- */ + /* detatch & daemonize */ + /* --------------------------------------------------- */ + + close(1); + close(2); + + if (inetd) + return; + + close(0); + + if (fork()) + exit(0); + + setsid(); + + if (fork()) + exit(0); + + /* --------------------------------------------------- */ + /* setup socket */ + /* --------------------------------------------------- */ + + + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + value = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value, sizeof(value)); + + ld.l_onoff = ld.l_linger = 0; + setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &ld, sizeof(ld)); + + sin.sin_family = AF_INET; + sin.sin_port = htons(FINGER_PORT); + sin.sin_addr.s_addr = htonl(INADDR_ANY); + memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); + + if (bind(fd, (struct sockaddr *) & sin, sizeof(sin)) || + listen(fd, TCP_QLEN)) + exit(1); +} + + +static void +server_usage() +{ + struct rusage ru; + + if (getrusage(RUSAGE_SELF, &ru)) + return; + + fprintf(flog, "\n[Server Usage]\n\n" + "user time: %.6f\n" + "system time: %.6f\n" + "maximum resident set size: %lu P\n" + "integral resident set size: %lu\n" + "page faults not requiring physical I/O: %d\n" + "page faults requiring physical I/O: %d\n" + "swaps: %d\n" + "block input operations: %d\n" + "block output operations: %d\n" + "messages sent: %d\n" + "messages received: %d\n" + "signals received: %d\n" + "voluntary context switches: %d\n" + "involuntary context switches: %d\n" + "gline: %d\n\n", + + (double) ru.ru_utime.tv_sec + (double) ru.ru_utime.tv_usec / 1000000.0, + (double) ru.ru_stime.tv_sec + (double) ru.ru_stime.tv_usec / 1000000.0, + ru.ru_maxrss, + ru.ru_idrss, + ru.ru_minflt, + ru.ru_majflt, + ru.ru_nswap, + ru.ru_inblock, + ru.ru_oublock, + ru.ru_msgsnd, + ru.ru_msgrcv, + ru.ru_nsignals, + ru.ru_nvcsw, + ru.ru_nivcsw, + gline); +} + + +static void +sig_trap(sig) + int sig; +{ + char buf[80]; + + close(fkmem); + sprintf(buf, "signal %d", sig); + logit("EXIT", buf); + server_usage(); + fclose(flog); + exit(1); +} + + +static void +reaper() +{ + while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0) + ; +} + + +static void +main_signals() +{ + struct sigaction act; + + /* sigblock(sigmask(SIGPIPE)); */ + /* Thor.981206: ²Î¤@ POSIX ¼Ð·Ç¥Îªk */ + + /* act.sa_mask = 0; */ /* Thor.981105: ¼Ð·Ç¥Îªk */ + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + act.sa_handler = reaper; + sigaction(SIGCHLD, &act, NULL); + + act.sa_handler = sig_trap; + sigaction(SIGTERM, &act, NULL); + sigaction(SIGBUS, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + + act.sa_handler = server_usage; + sigaction(SIGPROF, &act, NULL); + + /* Thor.981206: lkchu patch: ²Î¤@ POSIX ¼Ð·Ç¥Îªk */ + /* ¦b¦¹É¥Î sigset_t act.sa_mask */ + sigaddset(&act.sa_mask, SIGPIPE); + sigprocmask(SIG_BLOCK, &act.sa_mask, NULL); + +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int csock, nfds, state; + Agent **FBI, *Scully, *Mulder, *agent; + fd_set rset, wset, xset; + struct timeval tv; + time_t uptime, tcheck, tguard, tagent; + + state = 0; + + while ((nfds = getopt(argc, argv, "hid")) != -1) + { + switch (nfds) + { + case 'i': + state = 1; + break; + + case 'd': + break; + + case 'h': + default: + + fprintf(stderr, "Usage: %s [options]\n" + "\t-i start from inetd with wait option\n" + "\t-d debug mode\n" + "\t-h help\n", + argv[0]); + exit(0); + } + } + + servo_daemon(state); + /* start_daemon(); */ + setgid(BBSGID); + setuid(BBSUID); + chdir(BBSHOME); + main_signals(); + log_open(); + +#ifdef HAVE_SEM + resolve_sem(); +#endif + + init_ushm(); +#ifdef SOLARIS + chkload_init(); +#endif + + /* Thor.981221: for future reservation bug */ + tcheck = tguard = tagent = 0; + + Scully = Mulder = NULL; + + for (;;) /* Thor.981221: µù¸Ñ: Main loop begin */ + { + uptime = time(0); + + /* system guard / resource and garbage collection */ + + if (uptime > tcheck) + { + chkload(); + tcheck = uptime + LOAD_INTERVAL; + + if (uptime > tguard) + { + ushm_guard(); + tguard = uptime + GUARD_INTERVAL; + } + + if (uptime > tagent) + { + tagent = uptime - FINGER_TIMEOUT; + + for (FBI = &Scully; agent = *FBI;) + { + if (agent->uptime < tagent) + { + csock = agent->sock; + if (csock > 0) + { + shutdown(csock, 2); + close(csock); + } + + *FBI = agent->next; + + agent->next = Mulder; + Mulder = agent; + } + else + { + FBI = &(agent->next); + } + } + + tagent = uptime + FINGER_INTERVAL; + fflush(flog); + } + } + + /* Set up the fdsets. */ + + FD_ZERO(&rset); + FD_ZERO(&wset); + FD_ZERO(&xset); + + FD_SET(0, &rset); + nfds = 0; + + for (agent = Scully; agent; agent = agent->next) + { + csock = agent->sock; + state = agent->state; + + if (nfds < csock) + nfds = csock; + + FD_SET(csock, state == CS_READING ? &rset : &wset); + + FD_SET(csock, &xset); + } + + /* Thor.981221: for future reservation bug */ + tv.tv_sec = LOAD_INTERVAL; + tv.tv_usec = 0; + + nfds = select(nfds + 1, &rset, &wset, &xset, &tv); + + if (nfds == 0) + continue; + + if (nfds < 0) + { + csock = errno; + if (csock != EINTR) + { + logit("select", strerror(csock)); + } + continue; + } + + /* ------------------------------------------------- */ + /* serve active agents */ + /* ------------------------------------------------- */ + + uptime = time(0); + + for (FBI = &Scully; agent = *FBI;) + { + csock = agent->sock; + + if (FD_ISSET(csock, &wset)) + { + state = agent_write(agent); + } + else if (FD_ISSET(csock, &rset)) + { + state = agent_read(agent); + } + else if (FD_ISSET(csock, &xset)) + { + state = 0; + } + else + { + state = -1; + } + + if (state == 0) /* fire this agent */ + { + shutdown(csock, 2); + close(csock); + *FBI = agent->next; + + agent->next = Mulder; + Mulder = agent; + continue; + } + + if (state > 0) + { + agent->uptime = uptime; + } + + FBI = &(agent->next); + } + + /* ------------------------------------------------- */ + /* serve new connection */ + /* ------------------------------------------------- */ + + if (FD_ISSET(0, &rset)) + { + for (;;) + { + csock = accept(0, NULL, NULL); + + if (csock > 0) + { + if (agent = Mulder) + { + Mulder = agent->next; + } + else + { + agent = (Agent *) malloc(sizeof(Agent)); + } + + *FBI = agent; + + /* variable initialization */ + + agent->next = NULL; + agent->sock = csock; + agent->state = CS_READING; + agent->locus = 0; + agent->uptime = uptime; + agent->count = 0; + agent->uentp = NULL; + + break; + } + + state = errno; + if (state != EINTR) + { + logit("accept", strerror(state)); + break; + } + while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0); + } + } + + /* ------------------------------------------------- */ + /* tail of main loop */ + /* ------------------------------------------------- */ + } +} diff --git a/daemon/bhttpd.c b/daemon/bhttpd.c new file mode 100644 index 0000000..a813004 --- /dev/null +++ b/daemon/bhttpd.c @@ -0,0 +1,4122 @@ +/*-------------------------------------------------------*/ +/* bhttpd.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : BBS's HTTP daemon */ +/* create : 05/07/11 */ +/* update : 05/08/04 */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/* author : yiting.bbs@bbscs.tku.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 /* ³sµ²¤@Äýªí */ + + http://my.domain/ º¶ + http://my.domain/brdlist ¬ÝªO¦Cªí + http://my.domain/fvrlist §Úªº³Ì·R + http://my.domain/usrlist ¨Ï¥ÎªÌ¦W³æ + http://my.domain/brd?brdname&## ¤å³¹¦Cªí¡A¦C¥X¬ÝªO [brdname] ½s¸¹ ## ¶}©lªº 50 ½g¤å³¹ + http://my.domain/gem?brdname&folder ºëµØ°Ï¦Cªí¡A¦C¥X¬ÝªO [brdname] ºëµØ°Ï¤¤ folder ³oÓ¨÷©v¤Uªº©Ò¦³ªF¦è + http://my.domain/mbox?## «H½c¦Cªí¡A¦C¥X«H½c¤¤½s¸¹ ## ¶}©lªº 50 ½g¤å³¹ + http://my.domain/bmore?brdname&## ¾\Ū¬ÝªO¤å³¹¡A¾\Ū¬ÝªO [brdname] ªº²Ä ## ½g¤å³¹ + http://my.domain/bmost?brdname&## ¾\Ū¬ÝªO¤å³¹¡A¾\Ū¬ÝªO [brdname] ¤¤©Ò¦³¦W²Ä ## ½g¦P¼ÐÃDªº¤å³¹ + http://my.domain/gmore?brdname&folder&## ¾\ŪºëµØ°Ï¤å³¹¡A¾\Ū¬ÝªO [brdname] ºëµØ°Ï¤¤ folder ³oÓ¨÷©v¤Uªº²Ä ## ½g¤å³¹ + http://my.domain/mmore?## ¾\Ū«H½c¤å³¹¡A¾\Ū«H½c¤¤²Ä ## ½g¤å³¹ + http://my.domain/dopost?brdname µoªí¤å³¹©ó¬ÝªO [brdname] + http://my.domain/domail?userid µo°e«H¥óµ¹ [userid] + http://my.domain/dpost?brdname&##&### ¸ß°Ý½T©w§R°£¬ÝªO [brdname] ¤¤²Ä ## ½g¤å³¹ (¨ä chrono ¬O ###) + http://my.domain/delpost?brdname&##&### §R°£¬ÝªO [brdname] ¤¤²Ä ## ½g¤å³¹ (¨ä chrono ¬O ###) + http://my.domain/mpost?brdname&##&### ¼Ð°O¬ÝªO [brdname] ¤¤²Ä ## ½g¤å³¹ (¨ä chrono ¬O ###) + http://my.domain/dmail?##&### ¸ß°Ý½T©w§R°£«H½c¤¤²Ä ## ½g¤å³¹ (¨ä chrono ¬O ###) + http://my.domain/delmail?##&### §R°£«H½c¤¤²Ä ## ½g¤å³¹ (¨ä chrono ¬O ###) + http://my.domain/mmail?##&### ¼Ð°O«H½c¤¤²Ä ## ½g¤å³¹ (¨ä chrono ¬O ###) + http://my.domain/query?userid ¬d¸ß userid + http://my.domain/img?filename Åã¥Ü¹ÏÀÉ + http://my.domain/rss?brdname ¦U¬ÝªOªºRSS Feed + http://my.domain/class?folder ¦C¥X¤ÀÃþ¤¤ [folder] ³oÓ¨÷©v¤Uªº©Ò¦³¬ÝªO + http://my.domain/robot.txt Robot Exclusion + +#endif + + +#define _MODES_C_ + +#include "bbs.h" + + +#include <sys/wait.h> +#include <netinet/tcp.h> +#include <sys/resource.h> + +#undef ROBOT_EXCLUSION /* robot exclusion */ + + +#define SERVER_USAGE +#undef LOG_VERBOSE /* ¸Ô²Ó¬ö¿ý */ + + +#define BHTTP_PIDFILE "run/bhttp.pid" +#define BHTTP_LOGFILE "run/bhttp.log" + + +#define BHTTP_PERIOD (60 * 5) /* ¨C 5 ¤ÀÄÁ check ¤@¦¸ */ +#define BHTTP_TIMEOUT (60 * 3) /* ¶W¹L 3 ¤ÀÄÁªº³s½u´Nµø¬°¿ù»~ */ +#define BHTTP_FRESH 86400 /* ¨C 1 ¤Ñ¾ã²z¤@¦¸ log ÀÉ */ + + +#define TCP_BACKLOG 3 +#define TCP_RCVSIZ 2048 + + +#define MIN_DATA_SIZE (TCP_RCVSIZ + 3) +#define MAX_DATA_SIZE 262143 /* POST ªº¤j¤p¨î(byte) */ + + +/* Thor.000425: POSIX ¥Î O_NONBLOCK */ + +#ifndef O_NONBLOCK +#define M_NONBLOCK FNDELAY +#else +#define M_NONBLOCK O_NONBLOCK +#endif + +#define HTML_TALL 50 /* ¦Cªí¤@¶ 50 ½g */ + + +/* ----------------------------------------------------- */ +/* ¿ï³æªºÃC¦â */ +/* ----------------------------------------------------- */ + +#define HCOLOR_BG "#000000" /* I´ºªºÃC¦â */ +#define HCOLOR_TEXT "#ffffff" /* ¤å¦rªºÃC¦â */ +#define HCOLOR_LINK "#00ffff" /* ¥¼ÂsÄý¹L³sµ²ªºÃC¦â */ +#define HCOLOR_VLINK "#c0c0c0" /* ¤wÂsÄý¹L³sµ²ªºÃC¦â */ +#define HCOLOR_ALINK "#ff0000" /* ³sµ²³QÀ£¤U®ÉªºÃC¦â */ + +#define HCOLOR_NECK "#000070" /* ²ä¤lªºÃC¦â */ +#define HCOLOR_TIE "#a000a0" /* »â±aªºÃC¦â */ + +#define HCOLOR_BAR "#808080" /* ¥ú´ÎÃC¦â */ + + +/* ----------------------------------------------------- */ +/* HTTP commands */ +/* ----------------------------------------------------- */ + +typedef struct +{ + int (*func) (); + char *cmd; + int len; /* strlen(Command.cmd) */ +} Command; + + +/* ----------------------------------------------------- */ +/* client connection structure */ +/* ----------------------------------------------------- */ + +#define LEN_COOKIE (IDLEN + PASSLEN + 3 + 1) /* userid&p=passwd */ + +typedef struct Agent +{ + struct Agent *anext; + int sock; + + unsigned int ip_addr; + + time_t tbegin; /* ³s½u¶}©l®É¶¡ */ + time_t uptime; /* ¤W¦¸¤U«ü¥Oªº®É¶¡ */ + + char url[48]; /* ±ýÂsÄýªººô¶ */ + char *urlp; + + char cookie[32]; + int setcookie; + + char modified[30]; + + /* ¨Ï¥ÎªÌ¸ê®Æn¥ý acct_fetch() ¤~¯à¨Ï¥Î */ + int userno; + char userid[IDLEN + 1]; + char username[UNLEN + 1]; + usint userlevel; + + /* ©Ò¯à¬Ý¨ìªº¬ÝªO¦Cªí©Î¨Ï¥ÎªÌ¦W³æ */ + +#if MAXBOARD > MAXACTIVE + void *myitem[MAXBOARD]; +#else + void *myitem[MAXACTIVE]; +#endif + int total_item; + + /* input ¥Î */ + + char *data; + int size; /* ¥Ø«e data ©Ò malloc ªºªÅ¶¡¤j¤p */ + int used; + + /* output ¥Î */ + + FILE *fpw; +} Agent; + + +/* ----------------------------------------------------- */ +/* http state code */ +/* ----------------------------------------------------- */ + +enum +{ + HS_END, + + HS_ERROR, /* »yªk¿ù»~ */ + HS_ERR_LOGIN, /* ©|¥¼µn¤J */ + HS_ERR_USER, /* ±b¸¹Åª¨ú¿ù»~ */ + HS_ERR_MORE, /* ¤å³¹Åª¨ú¿ù»~ */ + HS_ERR_BOARD, /* ¬ÝªOŪ¨ú¿ù»~ */ + HS_ERR_MAIL, /* «H¥óŪ¨ú¿ù»~ */ + HS_ERR_CLASS, /* ¤ÀÃþŪ¨ú¿ù»~ */ + HS_ERR_PERM, /* Åv¤£¨¬ */ + + HS_OK, + + HS_REDIRECT, /* «·s¾É¦V */ + HS_NOTMOIDIFY, /* ÀɮרS¦³Åܧó */ + HS_BADREQUEST, /* ¿ù»~ªºn¨D */ + HS_FORBIDDEN, /* ¥¼±ÂÅvªº¶± */ + HS_NOTFOUND, /* §ä¤£¨ìÀÉ®× */ + + LAST_HS +}; + + +static char *http_msg[LAST_HS] = +{ + NULL, + + "»yªk¿ù»~", + "±z©|¥¼µn¤J", + "¨S¦³³oÓ±b¸¹", + "¾Þ§@¿ù»~¡G±z©Ò¿ï¨úªº¤å³¹¤£¦s¦b©Î¤w§R°£", + "¾Þ§@¿ù»~¡GµL¦¹¬ÝªO©Î±zªºÅv¤£¨¬", + "¾Þ§@¿ù»~¡GµL¦¹«H¥ó©Î±z©|¥¼µn¤J", + "¾Þ§@¿ù»~¡G±z©Ò¿ï¨úªº¤ÀÃþ¤£¦s¦b©Î¤w§R°£", + "¾Þ§@¿ù»~¡G±z©|¥¼µn¤J©ÎÅv¤£¨¬¡AµLªk¶i¦æ³o¶µ¾Þ§@", + + "200 OK", + + "302 Found", + "304 Not Modified", + "400 Bad Request", + "403 Forbidden", + "404 Not Found", +}; + + +#define HS_REFRESH 0x0100 /* ¦Û°Ê¸õ¶(¹w³]¬O3¬í) */ + + +/* ----------------------------------------------------- */ +/* AM : Agent Mode */ +/* ----------------------------------------------------- */ + +#define AM_GET 0x010 +#define AM_POST 0x020 + + +/* ----------------------------------------------------- */ +/* operation log and debug information */ +/* ----------------------------------------------------- */ +/* @START | ... | time */ +/* ----------------------------------------------------- */ + +static FILE *flog; + +extern int errno; +extern char *crypt(); + +static void +log_fresh() +{ + int count; + char fsrc[64], fdst[64]; + char *fpath = BHTTP_LOGFILE; + + if (flog) + fclose(flog); + + count = 9; + do + { + sprintf(fdst, "%s.%d", fpath, count); + sprintf(fsrc, "%s.%d", fpath, --count); + rename(fsrc, fdst); + } while (count); + + rename(fpath, fsrc); + flog = fopen(fpath, "a"); +} + + +static void +logit(key, msg) + char *key; + char *msg; +{ + time_t now; + struct tm *p; + + time(&now); + p = localtime(&now); + /* Thor.990329: y2k */ + fprintf(flog, "%s\t%s\t%02d/%02d/%02d %02d:%02d:%02d\n", + key, msg, p->tm_year % 100, p->tm_mon + 1, p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec); +} + + +static void +log_open() +{ + FILE *fp; + + umask(077); + + if (fp = fopen(BHTTP_PIDFILE, "w")) + { + fprintf(fp, "%d\n", getpid()); + fclose(fp); + } + + flog = fopen(BHTTP_LOGFILE, "a"); + logit("START", "MTA daemon"); +} + + +/* ----------------------------------------------------- */ +/* target : ANSI text to HTML tag */ +/* author : yiting.bbs@bbs.cs.tku.edu.tw */ +/* ----------------------------------------------------- */ + +#define ANSI_TAG 27 +#define is_ansi(ch) ((ch >= '0' && ch <= '9') || ch == ';' || ch == '[') + +#define HAVE_HYPERLINK /* ³B²z¶W³sµ² */ +#undef HAVE_ANSIATTR /* «Ü¤Ö¥Î¨ì¦Ó¥BIE¤£¤ä´©°{Ã{¡A°®¯Ü¤£³B²z :( */ +#define HAVE_SAKURA /* Äåªá¤é¤å¦Û°ÊÂàUnicode */ + +#ifdef HAVE_ANSIATTR +#define ATTR_UNDER 0x1 /* ©³½u */ +#define ATTR_BLINK 0x2 /* °{°Ê */ +#define ATTR_ITALIC 0x4 /* ±×Åé */ + +static int old_attr, now_attr; +#endif + +static int old_color, now_color; +static char ansi_buf[1024]; /* ANSILINELEN * 4 */ + + +#ifdef HAVE_HYPERLINK +static uschar *linkEnd = NULL; + +static void +ansi_hyperlink(fpw, src) + FILE *fpw; + uschar *src; +{ + int ch; + + linkEnd = src; + fputs("<a class=PRE target=_blank href=", fpw); + while (ch = *linkEnd) + { + if (ch < '#' || ch == '<' || ch == '>' || ch > '~') + break; + fputc(ch, fpw); + linkEnd++; + } + fputc('>', fpw); +} +#endif + + +#ifdef HAVE_SAKURA +static int +sakura2unicode(code) + int code; +{ + if (code > 0xC6DD && code < 0xC7F3) + { + if (code > 0xC7A0) + code -= 38665; + else if (code > 0xC700) + code -= 38631; + else if (code > 0xC6E6) + code -= 38566; + else if (code == 0xC6E3) + return 0x30FC; + else + code -= 38619; + if (code > 0x3093) + code += 13; + return code; + } + return 0; +} +#endif + + +static int +ansi_remove(psrc) + uschar **psrc; +{ + uschar *src = *psrc; + int ch = *src; + + while (is_ansi(ch)) + ch = *(++src); + + if (ch && ch != '\n') + ch = *(++src); + + *psrc = src; + return ch; +} + + +static int +ansi_color(psrc) + uschar **psrc; +{ + uschar *src, *ptr; + int ch, value; + int color = old_color; +#ifdef HAVE_ANSIATTR + int attr = old_attr; +#endif + uschar *cptr = (uschar *) & color; + + src = ptr = (*psrc) + 1; + + ch = *src; + while (ch) + { + if (ch == ';' || ch == 'm') + { + *src = '\0'; + value = atoi(ptr); + ptr = src + 1; + if (value == 0) + { + color = 0x00003740; + +#ifdef HAVE_ANSIATTR + attr = 0; +#endif + } + else if (value >= 30 && value <= 37) + cptr[1] = value + 18; + else if (value >= 40 && value <= 47) + cptr[0] = value + 24; + else if (value == 1) + cptr[2] = 1; + +#ifdef HAVE_ANSIATTR + else if (value == 4) + attr |= ATTR_UNDER; + else if (value == 5) + attr |= ATTR_BLINK; + else if (value == 7) /* ¤Ï¥Õªº®ÄªG¥Î±×Åé¨Ó¥N´À */ + attr |= ATTR_ITALIC; +#endif + + if (ch == 'm') + { + now_color = color; + +#ifdef HAVE_ANSIATTR + now_attr = attr; +#endif + + ch = *(++src); + break; + } + } + else if (ch < '0' || ch > '9') + { + ch = *(++src); + break; + } + ch = *(++src); + } + + *psrc = src; + return ch; +} + + +static void +ansi_tag(fpw) + FILE *fpw; +{ +#ifdef HAVE_ANSIATTR + /* Äݩʤ£¦P¤~»Ýn¦L¥X */ + if (!(now_attr & ATTR_ITALIC) && (old_attr & ATTR_ITALIC)) + { + fputs("</I>", fpw); + } + if (!(now_attr & ATTR_UNDER) && (old_attr & ATTR_UNDER)) + { + fputs("</U>", fpw); + } + if (!(now_attr & ATTR_BLINK) && (old_attr & ATTR_BLINK)) + { + fputs("</BLINK>", fpw); + } +#endif + + /* ÃC¦â¤£¦P¤~»Ýn¦L¥X */ + if (old_color != now_color) + { + fprintf(fpw, "</font><font class=A%05X>", now_color); + old_color = now_color; + } + +#ifdef HAVE_ANSIATTR + /* Äݩʤ£¦P¤~»Ýn¦L¥X */ + if (oldattr != attr) + { + if ((now_attr & ATTR_ITALIC) && !(old_attr & ATTR_ITALIC)) + { + fputs("<I>", fpw); + } + if ((now_attr & ATTR_UNDER) && !(old_attr & ATTR_UNDER)) + { + fputs("<U>", fpw); + } + if ((now_attr & ATTR_BLINK) && !(old_attr & ATTR_BLINK)) + { + fputs("<BLINK>", fpw); + } + old_attr = now_attr; + } +#endif +} + + +static void +ansi_html(fpw, src) + FILE *fpw; + uschar *src; +{ + int ch1, ch2; + int has_ansi = 0; + +#ifdef HAVE_SAKURA + int scode; +#endif + + ch2 = *src; + while (ch2) + { + ch1 = ch2; + ch2 = *(++src); + if (IS_ZHC_HI(ch1)) + { + while (ch2 == ANSI_TAG) + { + if (*(++src) == '[') /* ÃC¦â */ + { + ch2 = ansi_color(&src); + has_ansi = 1; + } + else /* ¨ä¥Lª½±µ§R°£ */ + ch2 = ansi_remove(&src); + } + if (ch2) + { + if (ch2 < ' ') /* ©È¥X²{\n */ + fputc(ch2, fpw); +#ifdef HAVE_SAKURA + else if (scode = sakura2unicode((ch1 << 8) | ch2)) + fprintf(fpw, "&#%d;", scode); +#endif + else + { + fputc(ch1, fpw); + fputc(ch2, fpw); + } + ch2 = *(++src); + } + if (has_ansi) + { + has_ansi = 0; + if (ch2 != ANSI_TAG) + ansi_tag(fpw); + } + continue; + } + else if (ch1 == ANSI_TAG) + { + do + { + if (ch2 == '[') /* ÃC¦â */ + ch2 = ansi_color(&src); + else if (ch2 == '*') /* ±±¨î½X */ + fputc('*', fpw); + else /* ¨ä¥Lª½±µ§R°£ */ + ch2 = ansi_remove(&src); + } while (ch2 == ANSI_TAG && (ch2 = *(++src))); + ansi_tag(fpw); + continue; + } + /* ³Ñ¤Uªº¦r¤¸°µhtmlÂà´« */ + if (ch1 == '<') + { + fputs("<", fpw); + } + else if (ch1 == '>') + { + fputs(">", fpw); + } + else if (ch1 == '&') + { + fputc(ch1, fpw); + if (ch2 == '#') /* Unicode¦r¤¸¤£Âà´« */ + { + fputc(ch2, fpw); + ch2 = *(++src); + } + else if (ch2 >= 'A' && ch2 <= 'z') + { + fputs("amp;", fpw); + fputc(ch2, fpw); + ch2 = *(++src); + } + } +#ifdef HAVE_HYPERLINK + else if (linkEnd) /* ³B²z¶W³sµ² */ + { + fputc(ch1, fpw); + if (linkEnd <= src) + { + fputs("</a>", fpw); + linkEnd = NULL; + } + } +#endif + else + { +#ifdef HAVE_HYPERLINK + /* ¨ä¥Lªº¦Û¤v¥[§a :) */ + if (!str_ncmp(src - 1, "http://", 7)) + ansi_hyperlink(fpw, src - 1); + else if (!str_ncmp(src - 1, "telnet://", 9)) + ansi_hyperlink(fpw, src - 1); +#endif + + fputc(ch1, fpw); + } + } +} + + +static char * +str_html(src, len) + uschar *src; + int len; +{ + int in_chi, ch; + uschar *dst = ansi_buf, *end = src + len; + + ch = *src; + while (ch && src < end) + { + if (IS_ZHC_HI(ch)) + { + in_chi = *(++src); + while (in_chi == ANSI_TAG) + { + src++; + in_chi = ansi_remove(&src); + } + + if (in_chi) + { + if (in_chi < ' ') /* ¥i¯à¥u¦³¥bÓ¦r¡A«e¥b³¡´N¤£n¤F */ + *dst++ = in_chi; +#ifdef HAVE_SAKURA + else if (len = sakura2unicode((ch << 8) + in_chi)) + { + sprintf(dst, "&#%d;", len); /* 12291~12540 */ + dst += 8; + } +#endif + else + { + *dst++ = ch; + *dst++ = in_chi; + } + } + else + break; + } + else if (ch == ANSI_TAG) + { + src++; + ch = ansi_remove(&src); + continue; + } + else if (ch == '<') + { + strcpy(dst, "<"); + dst += 4; + } + else if (ch == '>') + { + strcpy(dst, ">"); + dst += 4; + } + else if (ch == '&') + { + ch = *(++src); + if (ch == '#') + { + if ((uschar *) strchr(src + 1, ';') >= end) /* ¥i¯à·|¤£¬O©Îªø«×¨S¶W¹L */ + break; + *dst++ = '&'; + *dst++ = '#'; + } + else + { + strcpy(dst, "&"); + dst += 5; + continue; + } + } + else + *dst++ = ch; + ch = *(++src); + } + + *dst = '\0'; + return ansi_buf; +} + + +static int +ansi_quote(fpw, src) /* ¦pªG¬O¤Þ¨¥¡A´N²¤¹L©Ò¦³ªº ANSI ½X */ + FILE *fpw; + uschar *src; +{ + int ch1, ch2; + + ch1 = src[0]; + ch2 = src[1]; + if (ch2 == ' ' && (ch1 == QUOTE_CHAR1 || ch1 == QUOTE_CHAR2)) /* ¤Þ¨¥ */ + { + ch2 = src[2]; + if (ch2 == QUOTE_CHAR1 || ch2 == QUOTE_CHAR2) /* ¤Þ¥Î¤@¼h/¤G¼h¤£¦PÃC¦â */ + now_color = 0x00003340; + else + now_color = 0x00003640; + } + else if (ch1 == '\241' && ch2 == '\260') /* ¡° ¤Þ¨¥ªÌ */ + { + now_color = 0x00013640; + } + else + { + ansi_tag(fpw); + return 0; /* ¤£¬O¤Þ¨¥ */ + } + + ansi_tag(fpw); + fputs(str_html(src, ANSILINELEN), fpw); + now_color = 0x00003740; + return 1; +} + + +static void +txt2htm(fpw, fp) + FILE *fpw; + FILE *fp; +{ + static const char header1[LINE_HEADER][LEN_AUTHOR1] = {"§@ªÌ", "¼ÐÃD", "®É¶¡"}; + static const char header2[LINE_HEADER][LEN_AUTHOR2] = {"µo«H¤H", "¼Ð ÃD", "µo«H¯¸"}; + int i; + char *headvalue, *pbrd, *board; + char buf[ANSILINELEN]; + + fputs("<table width=760 cellspacing=0 cellpadding=0 border=0>\n", fpw); + /* ³B²zÀÉÀY */ + for (i = 0; i < LINE_HEADER; i++) + { + if (!fgets(buf, ANSILINELEN, fp)) /* ÁöµM³sÀÉÀY³£ÁÙ¨S¦L§¹¡A¦ý¬OÀɮפw¸gµ²§ô¡Aª½±µÂ÷¶} */ + { + fputs("</table>\n", fpw); + return; + } + + if (memcmp(buf, header1[i], LEN_AUTHOR1 - 1) && memcmp(buf, header2[i], LEN_AUTHOR2 - 1)) /* ¤£¬OÀÉÀY */ + break; + + /* §@ªÌ/¬ÝªO ÀÉÀY¦³¤GÄæ¡A¯S§O³B²z */ + if (i == 0 && ((pbrd = strstr(buf, "¬ÝªO:")) || (pbrd = strstr(buf, "¯¸¤º:")))) + { + if (board = strchr(pbrd, '\n')) + *board = '\0'; + board = pbrd + 6; + pbrd[-1] = '\0'; + pbrd[4] = '\0'; + } + + if (!(headvalue = strchr(buf, ':'))) + break; + + fprintf(fpw, "<tr>\n" + " <td align=center width=10%% class=A03447>%s</td>\n", header1[i]); + + str_html(headvalue + 2, TTLEN); + if (i == 0 && pbrd) + { + fprintf(fpw, " <td width=60%% class=A03744> %s</td>\n" + " <td align=center width=10%% class=A03447>%s</td>\n" + " <td width=20%% class=A03744> %s</td>\n</tr>\n", + ansi_buf, pbrd, board); + } + else + { + fputs(" <td width=90% colspan=3 class=A03744> ", fpw); + fputs(ansi_buf, fpw); + fputs("</td>\n</tr>\n", fpw); + } + } + + fputs("<tr>\n" + "<td colspan=4><pre><font class=A03740>", fpw); + + old_color = now_color = 0x00003740; + +#ifdef HAVE_ANSIATTR + old_attr = now_attr = 0; +#endif + + if (i >= LINE_HEADER) /* ³Ì«á¤@¦æ¬OÀÉÀY */ + fgets(buf, ANSILINELEN, fp); + + /* ³B²z¤º¤å */ + do + { + if (!ansi_quote(fpw, buf)) + ansi_html(fpw, buf); + } while (fgets(buf, ANSILINELEN, fp)); + + fputs("</font></pre></td>\n</table>\n", fpw); +} + + +/* ----------------------------------------------------- */ +/* HTML output basic function */ +/* ----------------------------------------------------- */ + +static char * +Gtime(now) + time_t *now; +{ + static char datemsg[32]; + + strftime(datemsg, sizeof(datemsg), "%a, %d %b %Y %T GMT", gmtime(now)); + return datemsg; +} + + +static FILE * +out_http(ap, code, type) + Agent *ap; + int code; + char *type; +{ + time_t now; + FILE *fpw; + int state; + + fpw = ap->fpw; + state = code & ~HS_REFRESH; + + /* HTTP 1.0 ÀÉÀY */ + time(&now); + + fprintf(fpw, "HTTP/1.0 %s\r\n" + "Date: %s\r\n" + "Server: MapleBBS 3.10\r\n" + "Connection: close\r\n", http_msg[state], Gtime(&now)); + + if (state == HS_NOTMOIDIFY) + { + fputs("\r\n", fpw); + } + else if (state == HS_REDIRECT)/* Location¤§«á¤£»Ýn¤º®e */ + { +#if BHTTP_PORT == 80 + fprintf(fpw, "Location: http://" MYHOSTNAME "/\r\n\r\n"); +#else + fprintf(fpw, "Location: http://" MYHOSTNAME ":%d/\r\n\r\n", BHTTP_PORT); +#endif + } + else + { + if (code & HS_REFRESH) + { + if (!type) + type = "/"; + fprintf(fpw, "Refresh: 3; url=%s\r\n", type); + } + if ((code & HS_REFRESH) || !type) + { + fputs("Pragma: no-cache\r\n" /* ºô¶¤@«ß¤£Åýproxy°µcache */ + "Content-Type: text/html; charset=" MYCHARSET "\r\n", fpw); + } + else + fprintf(fpw, "Content-Type: %s\r\n", type); + + if (ap->setcookie) /* cmd_login() §¹¥H«á¤~»Ýn Set-Cookie */ + fprintf(fpw, "Set-Cookie: user=%s; path=/\r\n", ap->cookie); + } + + return fpw; +} + + +static void +out_error(ap, code) /* code¤£¥i¥H¬OHS_OK */ + Agent *ap; + int code; +{ + char *msg; + + if (code < HS_OK) + { + fprintf(ap->fpw, "<BR>%s<BR><BR>\n", http_msg[code]); + return; + } + + out_http(ap, code, NULL); + switch (code) + { + case HS_BADREQUEST: + msg = "Your browser sent a request that this server could not understand."; + break; + case HS_FORBIDDEN: + msg = "You don't have permission to access the URL on this server."; + break; + case HS_NOTFOUND: + msg = "The requested URL was not found on this server."; + break; + default: /* HS_REDIRECT, HS_NOTMOIDIFY */ + return; + } + /* html ÀÉ®×¶}©l */ + fprintf(ap->fpw, "\r\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n" + "<HTML><HEAD>\n" + "<TITLE>%s</TITLE>\n" + "</HEAD><BODY>\n" + "<H1>%s</H1>\n%s\n<HR>\n" + "<ADDRESS>MapleBBS/3.10 Server at " MYHOSTNAME "</ADDRESS>\n" + "</BODY></HTML>\n", http_msg[code], http_msg[code] + 4, msg); +} + + +/* out_head() ¤¤ªº <HTML> <BODY> <CENTER> ¤TÓ¤j¼g¼ÐÅÒ³e¬ï¾ãÓ html ÀÉ + ª½¨ì out_tail() ¤~¥Ñ </HTML> </BODY> </CENTER> ÁÙì */ + + +static void +out_title(fpw, title) + FILE *fpw; + char *title; +{ + /* html ÀÉ®×¶}©l */ + fprintf(fpw, "\r\n<HTML><HEAD>\n" + "<meta http-equiv=Content-Type content=\"text/html; charset=" MYCHARSET "\">\n" + "<title>-=" BBSNAME "=- %s</title>\n", title); + + fputs("<script language=javascript>\n" + " function mOver(obj) {obj.bgColor='" HCOLOR_BAR "';}\n" + " function mOut(obj) {obj.bgColor='" HCOLOR_BG "';}\n" + "</script>\n<style type=text/css>\n" + " PRE {font-size: 15pt; line-height: 15pt; font-weight: lighter; background-color: #000000; color: #C0C0C0;}\n" + " TD {font-size: 15pt; line-height: 15pt; font-weight: lighter;}\n" + "</style>\n" + "<link rel=stylesheet href=/img?ansi.css type=text/css>\n" + "</head>\n" + "<BODY bgcolor=" HCOLOR_BG " text=" HCOLOR_TEXT " link=" HCOLOR_LINK " vlink=" HCOLOR_VLINK " alink=" HCOLOR_ALINK "><CENTER>\n" + "<a href=/><img src=/img?site.gif border=0></a><br>\n" + "<input type=image src=/img?back.gif onclick=\"javascript:history.go(-1);\"> / " + "<a href=/class><img src=/img?class.gif border=0></a> / " + "<a href=/brdlist><img src=/img?board.gif border=0></a> / " + "<a href=/fvrlist><img src=/img?favor.gif border=0></a> / " + "<a href=/mbox><img src=/img?mbox.gif border=0></a> / " + "<a href=/usrlist><img src=/img?user.gif border=0></a> / " + "<a href=telnet://" MYHOSTNAME "><img src=/img?telnet.gif border=0></a><br>\n", fpw); +} + + +static FILE * +out_head(ap, title) + Agent *ap; + char *title; +{ + FILE *fpw = out_http(ap, HS_OK, NULL); + out_title(fpw, title); + return fpw; +} + + +static void +out_mesg(fpw, msg) + FILE *fpw; + char *msg; +{ + fprintf(fpw, "<BR>%s<BR><BR>\n", msg); +} + + +static void +out_style(fpw) + FILE *fpw; +{ +#ifdef HAVE_HYPERLINK + fputs("<style type=text/css>\n" + " a:link.PRE {COLOR: #FFFFFF}\n" + " a:visited.PRE {COLOR: #FFFFFF}\n" + " a:active.PRE {COLOR: " HCOLOR_ALINK "; TEXT-DECORATION: none}\n" + " a:hover.PRE {COLOR: " HCOLOR_ALINK "; TEXT-DECORATION: none}\n" + "</style>\n", fpw); +#endif +} + + +static void +out_article(fpw, fpath) + FILE *fpw; + char *fpath; +{ + FILE *fp; + + if (fp = fopen(fpath, "r")) + { + out_style(fpw); + txt2htm(fpw, fp); + fclose(fp); + } +} + + +static void +out_tail(fpw) + FILE *fpw; +{ + fputs("</CENTER></BODY></HTML>\n", fpw); +} + + +static void +out_reload(fpw, msg) /* God.050327: ±N¥Dµøµ¡ reload ¨ÃÃö±¼·s¶}µøµ¡ */ + FILE *fpw; + char *msg; +{ + fprintf(fpw, "</CENTER></BODY></HTML>\n" + "<script>alert(\'%s\');\n" + "opener.location.reload();\n" + "parent.close();</script>", msg); +} + + +/* ----------------------------------------------------- */ +/* ¸Ñ½X¤ÀªR°Ñ¼Æ */ +/* ----------------------------------------------------- */ + +#define hex2int(x) ((x >= 'A') ? (x - 'A' + 10) : (x - '0')) + +static int /* 1:¦¨¥\ */ +arg_analyze(argc, mark, str, arg1, arg2, arg3, arg4) + int argc; /* ¦³´XÓ°Ñ¼Æ */ + int mark; /* !=0: str n¬O mark ¶}ÀYªº¦r¦ê */ + char *str; /* ¤Þ¼Æ */ + char **arg1; /* °Ñ¼Æ¤@ */ + char **arg2; /* °Ñ¼Æ¤G */ + char **arg3; /* °Ñ¼Æ¤T */ + char **arg4; /* °Ñ¼Æ¥| */ +{ + int i, ch; + char *dst; + + if ((mark && *str++ != mark) || !(ch = *str)) + { + *arg1 = NULL; + return 0; + } + + *arg1 = dst = str; + i = 2; + + while (ch) + { + if (ch == '&' || ch == '\r') + { + if (i > argc) + break; + + *dst++ = '\0'; + if (i == 2) + *arg2 = dst; + else if (i == 3) + *arg3 = dst; + else /* if (i == 4) */ + *arg4 = dst; + i++; + } + else if (ch == '+') + { + *dst++ = ' '; + } + else if (ch == '%') + { + ch = *(++str); + if (isxdigit(ch) && isxdigit(str[1])) + { + ch = (hex2int(ch) << 4) + hex2int(str[1]); + str++; + if (ch != '\r') /* '\r' ´N¤£n¤F */ + *dst++ = ch; + } + else + { + *dst++ = '%'; + continue; + } + } + else + *dst++ = ch; + + ch = *(++str); + } + *dst = '\0'; + + return i > argc; +} + + +/* ----------------------------------------------------- */ +/* ¥Ñ Cookie ¬Ý¨Ï¥ÎªÌ¬O§_µn¤J */ +/* ----------------------------------------------------- */ + +static int guestuno = 0; + +static void +guest_userno() +{ + char fpath[64]; + ACCT acct; + + usr_fpath(fpath, STR_GUEST, FN_ACCT); + if (!rec_get(fpath, &acct, sizeof(ACCT), 0)) + guestuno = acct.userno; +} + +static int /* 1:µn¤J¦¨¥\ 0:µn¤J¥¢±Ñ */ +acct_fetch(ap) + Agent *ap; +{ + char *userid, *passwd; + char fpath[64]; + ACCT acct; + + if (ap->cookie[0]) + { + /* u=userid&p=passwd */ + if (!arg_analyze(2, 0, ap->cookie, &userid, &passwd, NULL, NULL)) + return 0; + + passwd += 2; /* skip "p=" */ + + if (*userid && *passwd && strlen(userid) <= IDLEN && strlen(passwd) == PASSLEN) + { + usr_fpath(fpath, userid, FN_ACCT); + if (!rec_get(fpath, &acct, sizeof(ACCT), 0) && + !(acct.userlevel & (PERM_DENYLOGIN | PERM_PURGE)) && + !strncmp(acct.passwd, passwd, PASSLEN)) /* µn¤J¦¨¥\ */ + { + ap->userno = acct.userno; + strcpy(ap->userid, acct.userid); + strcpy(ap->username, acct.username); + ap->userlevel = acct.userlevel; + return 1; + } + } + } + + /* ¨S¦³µn¤J¡Bµn¤J¥¢±Ñ */ + ap->userno = guestuno; /* ¶ñ¤J¹ê»Úguestªºuserno¡A¥H«K°µpalÀˬd */ + ap->userlevel = 0; + strcpy(ap->userid, STR_GUEST); + strcpy(ap->username, STR_GUEST); + return 0; +} + + +/* ----------------------------------------------------- */ +/* UTMP shm ³¡¤À¶·»P cache.c ¬Û®e */ +/* ----------------------------------------------------- */ + +static UCACHE *ushm; + +static void +init_ushm() +{ + ushm = shm_new(UTMPSHM_KEY, sizeof(UCACHE)); +} + + +static int /* 1: userno ¦b pool ¦W³æ¤W */ +pertain_pal(pool, max, userno) /* °Ñ¦Ò pal.c:belong_pal() */ + int *pool; + int max; + int userno; +{ + int datum, mid; + + while (max > 0) + { + datum = pool[mid = max >> 1]; + if (userno == datum) + { + return 1; + } + if (userno > datum) + { + pool += (++mid); + max -= mid; + } + else + { + max = mid; + } + } + return 0; +} + + +static int /* 1: ¹ï¤è³]§Ú¬°Ãa¤H */ +is_hisbad(up, userno) /* °Ñ¦Ò pal.c:is_obad() */ + UTMP *up; + int userno; +{ +#ifdef HAVE_BADPAL + return pertain_pal(up->pal_spool, up->pal_max, -userno); +#else + return 0; +#endif +} + + +static int /* 1:¥i¬Ý¨£ 0:¤£¥i¬Ý¨£ */ +can_seen(up, userno, ulevel) /* °Ñ¦Ò bmw.c:can_see() */ + UTMP *up; + int userno; + usint ulevel; +{ + usint urufo; + + urufo = up->ufo; + + if (!(ulevel & PERM_SEECLOAK) && ((urufo & UFO_CLOAK) || is_hisbad(up, userno))) + return 0; + +#ifdef HAVE_SUPERCLOAK + if (urufo & UFO_SUPERCLOAK) + return 0; +#endif + + return 1; +} + + +/* itoc.030711: ¥[¤WÀˬd¨Ï¥ÎªÌ±b¸¹ªº³¡¤À¡A¥H§K¦³¤H¶Ã¿å */ +static int +allow_userid(ap, userid) + Agent *ap; + char *userid; +{ + int ch, rc; + char *str; + + rc = 0; + ch = strlen(userid); + if (ch >= 2 && ch <= IDLEN && is_alpha(*userid)) + { + rc = 1; + str = userid; + while (ch = *(++str)) + { + if (!is_alnum(ch)) + { + rc = 0; + break; + } + } + } + + return rc; +} + + +/* ----------------------------------------------------- */ +/* board¡Gshm ³¡¥÷¶·»P cache.c ¬Û®e */ +/* ----------------------------------------------------- */ + +static BCACHE *bshm; + +static void +init_bshm() +{ + /* itoc.030727: ¦b¶}±Ò bbsd ¤§«e¡AÀ³¸Ó´Nn°õ¦æ¹L account¡A + ©Ò¥H bshm À³¸Ó¤w³]©w¦n */ + + if (bshm) + return; + + bshm = shm_new(BRDSHM_KEY, sizeof(BCACHE)); + + if (bshm->uptime <= 0) /* bshm ¥¼³]©w§¹¦¨ */ + exit(0); +} + + +#ifdef HAVE_MODERATED_BOARD +static int /* !=0:¬OªO¦n 0:¤£¦b¦W³æ¤¤ */ +is_brdgood(userno, bpal) /* °Ñ¦Ò pal.c:is_bgood() */ + int userno; + BPAL *bpal; +{ + return pertain_pal(bpal->pal_spool, bpal->pal_max, userno); +} + + +static int /* !=0:¬OªOÃa 0:¤£¦b¦W³æ¤¤ */ +is_brdbad(userno, bpal) /* °Ñ¦Ò pal.c:is_bbad() */ + int userno; + BPAL *bpal; +{ +#ifdef HAVE_BADPAL + return pertain_pal(bpal->pal_spool, bpal->pal_max, -userno); +#else + return 0; +#endif +} +#endif + + +static int +Ben_Perm(brd, uno, uid, ulevel) /* °Ñ¦Ò board.c:Ben_Perm() */ + BRD *brd; + int uno; + char *uid; + usint ulevel; +{ + usint readlevel, postlevel, bits; + char *blist, *bname; + +#ifdef HAVE_MODERATED_BOARD + BPAL *bpal; + int ftype; /* 0:¤@¯ëID 1:ªO¦n 2:ªOÃa */ + + /* itoc.040103: ¬ÝªO¾\Ūµ¥¯Å»¡©úªí + + ¢z¢w¢w¢w¢w¢s¢w¢w¢w¢w¢s¢w¢w¢w¢w¢s¢w¢w¢w¢w¢{ + ¢x ¢x¤@¯ë¥Î¤á¢x¬ÝªO¦n¤Í¢x¬ÝªOÃa¤H¢x + ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢q¢w¢w¢w¢w¢q¢w¢w¢w¢w¢t + ¢x¤@¯ë¬ÝªO¢xÅv¨M©w¢x ¤ô±í ¢x ¬Ý¤£¨£ ¢x ¬Ý¤£¨£¡G¦b¬ÝªO¦Cªí¤¤µLªk¬Ý¨ì³oÓªO¡A¤]¶i¤£¥h + ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢q¢w¢w¢w¢w¢q¢w¢w¢w¢w¢t ¶i¤£¥h¡G¦b¬ÝªO¦Cªí¤¤¥i¥H¬Ý¨ì³oÓªO¡A¦ý¬O¶i¤£¥h + ¢x¦n¤Í¬ÝªO¢x ¶i¤£¥h ¢x §¹¾ã ¢x ¤ô±í ¢x ¤ô ±í¡G¦b¬ÝªO¦Cªí¤¤¥i¥H¬Ý¨ì³oÓªO¡A¤]¶i±o¥h¡A¦ý¬O¤£¯àµo¤å + ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢q¢w¢w¢w¢w¢q¢w¢w¢w¢w¢t §¹ ¾ã¡G¦b¬ÝªO¦Cªí¤¤¥i¥H¬Ý¨ì³oÓªO¡A¤]¶i±o¥h¤Îµo¤å + ¢x¯µ±K¬ÝªO¢x ¬Ý¤£¨£ ¢x §¹¾ã ¢x ¤ô±í ¢x + ¢|¢w¢w¢w¢w¢r¢w¢w¢w¢w¢r¢w¢w¢w¢w¢r¢w¢w¢w¢w¢} + */ + + static int bit_data[9] = + { /* ¤@¯ë¥Î¤á ¬ÝªO¦n¤Í ¬ÝªOÃa¤H */ + /* ¤½¶}¬ÝªO */ 0, BRD_L_BIT | BRD_R_BIT, 0, + /* ¦n¤Í¬ÝªO */ BRD_L_BIT, BRD_L_BIT | BRD_R_BIT | BRD_W_BIT, BRD_L_BIT | BRD_R_BIT, + /* ¯µ±K¬ÝªO */ 0, BRD_L_BIT | BRD_R_BIT | BRD_W_BIT, BRD_L_BIT | BRD_R_BIT, + }; +#endif + + if (!brd) + return 0; + bname = brd->brdname; + if (!*bname) + return 0; + + readlevel = brd->readlevel; + +#ifdef HAVE_MODERATED_BOARD + bpal = bshm->pcache + (brd - bshm->bcache); + ftype = is_brdgood(uno, bpal) ? 1 : is_brdbad(uno, bpal) ? 2 : 0; + + if (readlevel == PERM_SYSOP) /* ¯µ±K¬ÝªO */ + bits = bit_data[6 + ftype]; + else if (readlevel == PERM_BOARD) /* ¦n¤Í¬ÝªO */ + bits = bit_data[3 + ftype]; + else if (ftype) /* ¤½¶}¬ÝªO¡AY¦bªO¦n/ªOÃa¦W³æ¤¤ */ + bits = bit_data[ftype]; + else /* ¤½¶}¬ÝªO¡A¨ä¥L¨ÌÅv§P©w */ +#endif + + if (!readlevel || (readlevel & ulevel)) + { + bits = BRD_L_BIT | BRD_R_BIT; + + postlevel = brd->postlevel; + if (!postlevel || (postlevel & ulevel)) + bits |= BRD_W_BIT; + } + else + { + bits = 0; + } + + /* Thor.980813.µù¸Ñ: ¯S§O¬° BM ¦Ò¶q¡AªO¥D¦³¸ÓªOªº©Ò¦³Åv */ + blist = brd->BM; + if ((ulevel & PERM_BM) && blist[0] > ' ' && str_has(blist, uid, strlen(uid))) + bits = BRD_L_BIT | BRD_R_BIT | BRD_W_BIT | BRD_X_BIT | BRD_M_BIT; + + /* itoc.030515: ¬ÝªOÁ`ºÞ«·s§PÂ_ */ + else if (ulevel & PERM_ALLBOARD) + bits = BRD_L_BIT | BRD_R_BIT | BRD_W_BIT | BRD_X_BIT; + + return bits; +} + + +static BRD * +brd_get(bname) + char *bname; +{ + BRD *bhdr, *tail; + + bhdr = bshm->bcache; + tail = bhdr + bshm->number; + do + { + if (!strcmp(bname, bhdr->brdname)) + return bhdr; + } while (++bhdr < tail); + return NULL; +} + + +static int /* ¦^¶ÇPermBits¤è«K°µ¦h¦¸§PÂ_ */ +ben_perm(ap, brdname) + Agent *ap; + char *brdname; +{ + BRD *brd; + + if (acct_fetch(ap) && (brd = brd_get(brdname))) + return Ben_Perm(brd, ap->userno, ap->userid, ap->userlevel); + return 0; +} + + +static BRD * +allow_brdname(ap, brdname) + Agent *ap; + char *brdname; +{ + BRD *bhdr; + + if (bhdr = brd_get(brdname)) + { + /* Y readlevel == 0¡Aªí¥Ü guest ¥iŪ¡AµL»Ý acct_fetch() */ + if (!bhdr->readlevel) + return bhdr; + + if (acct_fetch(ap) && (Ben_Perm(bhdr, ap->userno, ap->userid, ap->userlevel) & BRD_R_BIT)) + return bhdr; + } + return NULL; +} + + +/* ----------------------------------------------------- */ +/* movie¡Gshm ³¡¥÷¶·»P cache.c ¬Û®e */ +/* ----------------------------------------------------- */ + +static FCACHE *fshm; + + +static void +init_fshm() +{ + fshm = shm_new(FILMSHM_KEY, sizeof(FCACHE)); +} + + +static void +out_film(fpw, tag) + FILE *fpw; + int tag; +{ + int i, *shot, len; + char *film, buf[FILM_SIZ]; + + shot = fshm->shot; + for (i = 0; !(*shot) && i < 5; ++i) + sleep(1); + + if (!(*shot)) + return; /* Y 5 ¬í¥H«áÁÙ¨S´«¦n¤ù¡A¥i¯à¬O¨S¶] camera¡Aª½±µÂ÷¶} */ + + film = fshm->film; + if (tag) + { + len = shot[tag]; + film += len; + len = shot[tag + 1] - len; + } + else + len = shot[1]; + + memcpy(buf, film, len); + buf[len] = '\0'; + + out_style(fpw); + fputs("<table width=760 cellspacing=0 cellpadding=0 border=0>\n" + "<tr>\n" + "<td colspan=4><pre><font class=A03740>", fpw); + ansi_html(fpw, buf); + fputs("</font></pre></td>\n</table>\n", fpw); +} + + +/* ----------------------------------------------------- */ +/* command dispatch (GET) */ +/* ----------------------------------------------------- */ + + /* --------------------------------------------------- */ + /* ³q¥Î²M³æ */ + /* --------------------------------------------------- */ + +static void +list_neck(fpw, start, total, title) + FILE *fpw; + int start, total; + char *title; +{ + fputs("<br>\n" + "<table cellspacing=0 cellpadding=1 border=0 width=760>\n" + "<tr bgcolor=" HCOLOR_NECK ">\n <td width=15%", fpw); + if (start != 1) + { + fprintf(fpw, " align=center><a href=?%d>¤W%dÓ</a", + (start > HTML_TALL ? start - HTML_TALL : 1), HTML_TALL); + } + fputs("></td>\n <td width=15%", fpw); + + start += HTML_TALL; + if (start <= total) + { + fprintf(fpw, " align=center><a href=?%d>¤U%dÓ</a", + start, HTML_TALL); + } + fputs("></td>\n <td width=40% align=center>", fpw); + fprintf(fpw, title, total); + fprintf(fpw, "</td>\n" + " <td width=15%% align=center><a href=?1>«e%dÓ</a></td>\n" + " <td width=15%% align=center><a href=?0>¥½%dÓ</a></td>\n" + "</tr></table><br>\n", HTML_TALL, HTML_TALL); +} + + +static void +cmdlist_list(ap, title, list_tie, list_item) + Agent *ap; + char *title; + void (*list_tie) (FILE *); + void (*list_item) (FILE *, void *, int); +{ + int i, start, end, total; + char *number; + FILE *fpw; + + if (!arg_analyze(1, '?', ap->urlp, &number, NULL, NULL, NULL)) + start = 1; + else + start = atoi(number); + total = ap->total_item; + if (start <= 0 || start > total) /* ¶W¹L½d³òªº¸Ü¡Aª½±µ¨ì³Ì«á¤@¶ */ + start = total > HTML_TALL ? total - HTML_TALL + 1 : 1; + + fpw = ap->fpw; + list_neck(fpw, start, total, title); + fputs("<table cellspacing=0 cellpadding=4 border=0>\n<tr bgcolor=" HCOLOR_TIE ">\n", fpw); + list_tie(fpw); + + end = start + HTML_TALL - 1; + if (end > total) + end = total; + for (i = start - 1; i < end; i++) + { + fputs("<tr onmouseover=mOver(this); onmouseout=mOut(this);>\n", fpw); + list_item(fpw, ap->myitem[i], i + 1); + } + + fputs("</table>\n", fpw); + list_neck(fpw, start, total, title); +} + + + /* --------------------------------------------------- */ + /* ¨Ï¥ÎªÌ¦W³æ */ + /* --------------------------------------------------- */ + +static int +userid_cmp(a, b) + UTMP **a, **b; +{ + return str_cmp((*a)->userid, (*b)->userid); +} + + +static void +init_myusr(ap) + Agent *ap; +{ + int num, userno; + UTMP *uentp, *uceil; + usint ulevel; + + acct_fetch(ap); + uentp = ushm->uslot; + uceil = (void *)uentp + ushm->offset; + userno = ap->userno; + ulevel = ap->userlevel; + num = 0; + + do + { + if (!uentp->pid || !uentp->userno || !can_seen(uentp, userno, ulevel)) + continue; + + ap->myitem[num] = uentp; + num++; + } while (++uentp <= uceil); + + if (num > 1) + qsort(ap->myitem, num, sizeof(UTMP *), userid_cmp); + + ap->total_item = num; +} + + +static void +userlist_tie(fpw) + FILE *fpw; +{ + fputs(" <td width=40>½s¸¹</td>\n" + " <td width=100>ºô¤Í¥N¸¹</td>\n" + " <td width=210>ºô¤Í¼ÊºÙ</td>\n" + " <td width=230>«È³~¬G¶m</td>\n" + " <td width=100>ºô¤Í°ÊºA</td>\n" + "</tr>\n", fpw); +} + + +static void +userlist_item(fpw, up, n) + FILE *fpw; + UTMP *up; + int n; +{ + fprintf(fpw, " <td>%d</td>\n" + " <td><a href=/query?%s>%s</a></td>\n" + " <td>%s</td>\n" + " <td>%s</td>\n" + " <td>%s</td>\n" + "</tr>\n", + n, + up->userid, up->userid, + str_html(up->username, UNLEN), + up->from, + ModeTypeTable[up->mode]); +} + + +static int +cmd_userlist(ap) + Agent *ap; +{ + init_myusr(ap); + out_head(ap, "¨Ï¥ÎªÌ¦W³æ"); + + cmdlist_list(ap, "¥Ø«e¯¸¤W¦³ %d Ó¤H", userlist_tie, userlist_item); + + return HS_END; +} + + + /* --------------------------------------------------- */ + /* ¬ÝªO¦Cªí */ + /* --------------------------------------------------- */ + +static int +brdtitle_cmp(a, b) + BRD **a, **b; +{ + /* itoc.010413: ¤ÀÃþ/ªO¦W¥æ¤e¤ñ¹ï */ + int k = strcmp((*a)->class, (*b)->class); + return k ? k : str_cmp((*a)->brdname, (*b)->brdname); +} + + +static void +init_mybrd(ap) + Agent *ap; +{ + int num, uno; + char *uid; + usint ulevel; + BRD *bhdr, *tail; + + acct_fetch(ap); + uno = ap->userno; + uid = ap->userid; + ulevel = ap->userlevel; + bhdr = bshm->bcache; + tail = bhdr + bshm->number; + num = 0; + + do + { + if (Ben_Perm(bhdr, uno, uid, ulevel) & BRD_R_BIT) + { + ap->myitem[num] = bhdr; + num++; + } + } while (++bhdr < tail); + + if (num > 1) + qsort(ap->myitem, num, sizeof(BRD *), brdtitle_cmp); + + ap->total_item = num; +} + + +static void +boardlist_tie(fpw) + FILE *fpw; +{ + fputs(" <td width=40>½s¸¹</td>\n" + " <td width=80>¬ÝªO</td>\n" + " <td width=40>Ãþ§O</td>\n" + " <td width=25>Âà</td>\n" + " <td width=350>¤¤¤å±Ôz</td>\n" + " <td width=75>ªO¥D</td>\n" + "</tr>\n", fpw); +} + + +static void +boardlist_item(fpw, brd, n) + FILE *fpw; + BRD *brd; + int n; +{ + fprintf(fpw, " <td>%d</td>\n" + " <td><a href=/brd?%s>%s</a></td>\n" + " <td>%s</td>\n" + " <td>%s</td>\n" + " <td>%s</td>\n" + " <td>%.13s</td>\n" + "</tr>\n", + n, + brd->brdname, brd->brdname, + brd->class, + (brd->battr & BRD_NOTRAN) ? ICON_NOTRAN_BRD : ICON_TRAN_BRD, + str_html(brd->title, 33), + brd->BM); +} + + +static int +cmd_boardlist(ap) + Agent *ap; +{ + init_mybrd(ap); + out_head(ap, "¬ÝªO¦Cªí"); + + cmdlist_list(ap, "¥Ø«e¯¸¤W¦³ %d ÓªO", boardlist_tie, boardlist_item); + + return HS_END; +} + + + /* --------------------------------------------------- */ + /* §Úªº³Ì·R */ + /* --------------------------------------------------- */ + +static void +init_myfavor(ap) + Agent *ap; +{ + int num, uno; + usint ulevel; + char *uid, fpath[64]; + BRD *bhdr; + FILE *fp; + MF mf; + + uno = ap->userno; + uid = ap->userid; + ulevel = ap->userlevel; + num = 0; + usr_fpath(fpath, ap->userid, "MF/" FN_MF); + + if (fp = fopen(fpath, "r")) + { + while (fread(&mf, sizeof(MF), 1, fp) == 1) + { + /* ¥u¤ä´©²Ä¤@¼hªº¬ÝªO */ + if ((mf.mftype & MF_BOARD) && + (bhdr = brd_get(mf.xname)) && + (Ben_Perm(bhdr, uno, uid, ulevel) & BRD_R_BIT)) + { + ap->myitem[num] = bhdr; + num++; + } + } + fclose(fp); + } + ap->total_item = num; +} + + +static int +cmd_favorlist(ap) + Agent *ap; +{ + out_head(ap, "§Úªº³Ì·R"); + if (!acct_fetch(ap)) + return HS_ERR_LOGIN; + + init_myfavor(ap); + + cmdlist_list(ap, "§Úªº³Ì·R", boardlist_tie, boardlist_item); + + return HS_END; +} + + + /* --------------------------------------------------- */ + /* ¤ÀÃþ¬ÝªO¦Cªí */ + /* --------------------------------------------------- */ + +static void +class_neck(fpw) + FILE *fpw; +{ + fputs("<br>\n" + "<table cellspacing=0 cellpadding=1 border=0 width=760>\n" + "<tr bgcolor=" HCOLOR_NECK ">\n" + " <td width=50%></td>\n" + " <td width=50% align=center><a href=/class>¦^³Ì¤W¼h</a></td>\n" + "</tr></table><br>\n", fpw); +} + + +static int +cmd_class(ap) + Agent *ap; +{ + int fd, i, userno; + usint ulevel; + char folder[64], *xname, *userid; + BRD *brd; + HDR hdr; + FILE *fpw = out_head(ap, "¤ÀÃþ¬ÝªO"); + + if (!arg_analyze(1, '?', ap->urlp, &xname, NULL, NULL, NULL)) + xname = CLASS_INIFILE; + + if (strlen(xname) > 12) + return HS_ERROR; + + sprintf(folder, "gem/@/@%s", xname); + if ((fd = open(folder, O_RDONLY)) < 0) + return HS_ERR_CLASS; + + acct_fetch(ap); + userno = ap->userno; + userid = ap->userid; + ulevel = ap->userlevel; + + class_neck(fpw); + fputs("<table cellspacing=0 cellpadding=4 border=0>\n<tr bgcolor=" HCOLOR_TIE ">\n", fpw); + boardlist_tie(fpw); + i = 1; + while (read(fd, &hdr, sizeof(HDR)) == sizeof(HDR)) + { + fputs("<tr onmouseover=mOver(this); onmouseout=mOut(this);>\n", fpw); + if (hdr.xmode & GEM_BOARD) /* ¬ÝªO */ + { + if ((brd = brd_get(hdr.xname)) && + Ben_Perm(brd, userno, userid, ulevel) & BRD_R_BIT) + { + boardlist_item(fpw, brd, i); + } + else + continue; + } + else if ((hdr.xmode & GEM_FOLDER) && *hdr.xname == '@') /* ¤ÀÃþ */ + { + fprintf(fpw, " <td>%d</td>\n" + " <td><a href=/class?%s>%s/</a></td>\n" + " <td>¤ÀÃþ</td>\n" + " <td>¡¼</td>\n" + " <td colspan=2>%s</td>\n</tr>\n", + i, + hdr.xname + 1, hdr.xname + 1, + str_html(hdr.title + 21, 52)); + } + else /* ¨ä¥LÃþ§O´N¤£¨q¤F */ + { + continue; + } + + i++; + } + close(fd); + fputs("</table>\n", fpw); + class_neck(fpw); + return HS_END; +} + + + /* --------------------------------------------------- */ + /* ¤å³¹¦Cªí */ + /* --------------------------------------------------- */ + +static void +postlist_list(fpw, folder, brdname, start, total) + FILE *fpw; + char *folder, *brdname; + int start, total; +{ + HDR hdr; + char owner[80], *ptr1, *ptr2; + int fd; + + fputs("<table cellspacing=0 cellpadding=4 border=0>\n<tr bgcolor=" HCOLOR_TIE ">\n" + " <td width=15>¼Ð</td>\n" + " <td width=15>§R</td>\n" + " <td width=50>½s¸¹</td>\n" + " <td width=10>m</td>\n" + +#ifdef HAVE_SCORE + " <td width=10> </td>\n" +#endif + + " <td width=50>¤é´Á</td>\n" + " <td width=100>§@ªÌ</td>\n" + " <td width=400>¼ÐÃD</td>\n" + "</tr>\n", fpw); + + if ((fd = open(folder, O_RDONLY)) >= 0) + { + int i, end; + + /* ¨q¥X¬ÝªOªº²Ä start ½g¶}©lªº HTML_TALL ½g */ + i = start; + end = i + HTML_TALL; + + lseek(fd, (off_t) (sizeof(HDR) * (i - 1)), SEEK_SET); + + while (i < end && read(fd, &hdr, sizeof(HDR)) == sizeof(HDR)) + { + strcpy(owner, hdr.owner); + if (ptr1 = strchr(owner, '.')) /* ¯¸¥~§@ªÌ */ + *(ptr1 + 1) = '\0'; + if (ptr2 = strchr(owner, '@')) /* ¯¸¥~§@ªÌ */ + *ptr2 = '\0'; + + fputs("<tr onmouseover=mOver(this); onmouseout=mOut(this);>\n", fpw); + if (brdname) + { + fprintf(fpw, " <td><a href=/mpost?%s&%d&%d><img src=/img?mark.gif border=0></a></td>\n" + " <td><a href=/dpost?%s&%d&%d><img src=/img?del.gif border=0></a></td>\n", + brdname, i, hdr.chrono, brdname, i, hdr.chrono); + } + else + { + fprintf(fpw, " <td><a href=/mmail?%d&%d><img src=/img?mark.gif border=0></a></td>\n" + " <td><a href=/dmail?%d&%d><img src=/img?del.gif border=0></a></td>\n", + i, hdr.chrono, i, hdr.chrono); + } + + if (hdr.xmode & POST_BOTTOM) + fputs(" <td>«n</td>\n", fpw); + else + fprintf(fpw, " <td>%d</td>\n", i); + fprintf(fpw, " <td>%s</td>\n <td>", hdr.xmode & POST_MARKED ? "m" : ""); + +#ifdef HAVE_SCORE + if (hdr.xmode & POST_SCORE) + fprintf(fpw, "<font color='%s'>%d</font>", hdr.score >= 0 ? "red" : "green", abs(hdr.score)); +#endif + + fprintf(fpw, "</td>\n <td>%s</td>\n <td><a href=%s%s>%s</a></td>\n", + hdr.date + 3, (ptr1 || ptr2) ? "mailto:" : "/query?", hdr.owner, owner); + + if (brdname) + fprintf(fpw, " <td><a href=/bmore?%s&%d>", brdname, i); + else + fprintf(fpw, " <td><a href=/mmore?%d&>", i); + + fprintf(fpw, "%s</td>\n</tr>\n", str_html(hdr.title, 50)); + + i++; + } + close(fd); + } + + fputs("</table>\n", fpw); +} + + +static void +postlist_neck(fpw, start, total, brdname) + FILE *fpw; + int start, total; + char *brdname; +{ + fputs("<br>\n" + "<table cellspacing=0 cellpadding=1 border=0 width=760>\n" + "<tr bgcolor=" HCOLOR_NECK ">\n <td width=20%", fpw); + + if (start > HTML_TALL) + { + fprintf(fpw, " align=center><a href=?%s&%d>¤W%d½g</a", + brdname, start - HTML_TALL, HTML_TALL); + } + fputs("></td>\n <td width=20%", fpw); + + start += HTML_TALL; + if (start <= total) + { + fprintf(fpw, " align=center><a href=?%s&%d>¤U%d½g</a", + brdname, start, HTML_TALL); + } + + fprintf(fpw, "></td>\n <td width=20%% align=center><a href=/dopost?%s target=_blank>µoªí¤å³¹</a></td>\n" + " <td width=20%% align=center><a href=/gem?%s>ºëµØ°Ï</a></td>\n" + " <td width=20%% align=center><a href=/brdlist>¬ÝªO¦Cªí</a> " + "<a href=/rss?%s><img border=0 src=/img?xml.gif alt=\"RSS q¾\\³oӬݪO\"></a></td>\n" + "</tr></table><br>\n", + brdname, brdname, brdname, brdname); +} + + +static int +cmd_postlist(ap) + Agent *ap; +{ + int start, total; + char folder[64], *brdname, *number; + FILE *fpw = out_head(ap, "¤å³¹¦Cªí"); + + if (!arg_analyze(2, '?', ap->urlp, &brdname, &number, NULL, NULL)) + { + if (brdname) + number = "0"; + else + return HS_ERROR; + } + + if (!allow_brdname(ap, brdname)) + return HS_ERR_BOARD; + + brd_fpath(folder, brdname, FN_DIR); + + start = atoi(number); + total = rec_num(folder, sizeof(HDR)); + if (start <= 0 || start > total) /* ¶W¹L½d³òªº¸Ü¡Aª½±µ¨ì³Ì«á¤@¶ */ + start = (total - 1) / HTML_TALL * HTML_TALL + 1; + + postlist_neck(fpw, start, total, brdname); + + postlist_list(fpw, folder, brdname, start, total); + + postlist_neck(fpw, start, total, brdname); + return HS_END; +} + + + /* --------------------------------------------------- */ + /* «H½c¦Cªí */ + /* --------------------------------------------------- */ + +static void +mboxlist_neck(fpw, start, total) + FILE *fpw; + int start, total; +{ + fputs("<br>\n" + "<table cellspacing=0 cellpadding=1 border=0 width=760>\n" + "<tr bgcolor=" HCOLOR_NECK ">\n <td width=33% ", fpw); + + if (start > HTML_TALL) + { + fprintf(fpw, "align=center><a href=?%d>¤W%d½g</a", + start - HTML_TALL, HTML_TALL); + } + fputs("></td>\n <td width=33%", fpw); + + start += HTML_TALL; + if (start <= total) + { + fprintf(fpw, " align=center><a href=?%d>¤U%d½g</a", + start, HTML_TALL); + } + + fputs("></td>\n <td width=34% align=center><a href=/domail target=_blank>µo°e«H¥ó</a></td>\n" + "</tr></table><br>\n", fpw); +} + + +static int +cmd_mboxlist(ap) + Agent *ap; +{ + int start, total; + char folder[64], *number; + FILE *fpw = out_head(ap, "«H½c¦Cªí"); + + if (!acct_fetch(ap)) + return HS_ERR_LOGIN; + + if (!arg_analyze(1, '?', ap->urlp, &number, NULL, NULL, NULL)) + number = "0"; + + usr_fpath(folder, ap->userid, FN_DIR); + + start = atoi(number); + total = rec_num(folder, sizeof(HDR)); + if (start <= 0 || start > total) /* ¶W¹L½d³òªº¸Ü¡Aª½±µ¨ì³Ì«á¤@¶ */ + start = (total - 1) / HTML_TALL * HTML_TALL + 1; + + mboxlist_neck(fpw, start, total); + + postlist_list(fpw, folder, NULL, start, total); + + mboxlist_neck(fpw, start, total); + return HS_END; +} + + + /* --------------------------------------------------- */ + /* ºëµØ°Ï¦Cªí */ + /* --------------------------------------------------- */ + +static void +gemlist_neck(fpw, brdname) + FILE *fpw; + char *brdname; +{ + fprintf(fpw, "<br>\n" + "<table cellspacing=0 cellpadding=1 border=0 width=760>\n" + "<tr bgcolor=" HCOLOR_NECK ">\n" + " <td width=50%% align=center><a href=/brd?%s>¦^¨ì¬ÝªO</a></td>\n" + " <td width=50%% align=center><a href=/brdlist>¬ÝªO¦Cªí</a></td>\n" + "</tr></table><br>\n", + brdname); +} + + +static int +cmd_gemlist(ap) + Agent *ap; +{ + int fd, i; + char folder[64], *brdname, *xname; + HDR hdr; + FILE *fpw = out_head(ap, "ºëµØ°Ï"); + + if (!arg_analyze(2, '?', ap->urlp, &brdname, &xname, NULL, NULL)) + { + if (brdname) + xname = FN_DIR; + else + return HS_ERROR; + } + + if ((*xname != 'F' || strlen(xname) != 8) && strcmp(xname, FN_DIR)) + return HS_ERROR; + + if (!allow_brdname(ap, brdname)) + return HS_ERR_BOARD; + + gemlist_neck(fpw, brdname); + + fputs("<table cellspacing=0 cellpadding=4 border=0>\n" + "<tr bgcolor=" HCOLOR_TIE ">\n" + " <td width=50>½s¸¹</td>\n" + " <td width=400>¼ÐÃD</td>\n" + "</tr>\n", fpw); + + if (*xname == '.') + sprintf(folder, "gem/brd/%s/%s", brdname, FN_DIR); + else /* if (*xname == 'F') */ + sprintf(folder, "gem/brd/%s/%c/%s", brdname, xname[7], xname); + + if ((fd = open(folder, O_RDONLY)) >= 0) + { + i = 1; + while (read(fd, &hdr, sizeof(HDR)) == sizeof(HDR)) + { + fprintf(fpw, "<tr onmouseover=mOver(this); onmouseout=mOut(this);>\n" + " <td>%d</td>\n", i); + if (hdr.xmode & GEM_RESTRICT) + { + fputs(" <td>[°ßŪ] ¸ê®Æ«O±K</td>\n</tr>\n", fpw); + } + else if (hdr.xname[0] == 'A') /* ¤å³¹ */ + { + fprintf(fpw, " <td><a href=/gmore?%s&%s&%d>[¤å³¹] %s</a></td>\n</tr>\n", + brdname, xname, i, str_html(hdr.title, TTLEN)); + } + else if (hdr.xname[0] == 'F') /* ¨÷©v */ + { + fprintf(fpw, " <td><a href=/gem?%s&%s>[¨÷©v] %s</a></td>\n</tr>\n", + brdname, hdr.xname, str_html(hdr.title, TTLEN)); + } + else /* ¨ä¥LÃþ§O´N¤£¨q¤F */ + { + fputs(" <td>[°ßŪ] ¨ä¥L¸ê®Æ</td>\n</tr>\n", fpw); + } + + i++; + } + close(fd); + } + + fputs("</table>\n", fpw); + + gemlist_neck(fpw, brdname); + return HS_END; +} + + + /* --------------------------------------------------- */ + /* ¾\Ū¬ÝªO¤å³¹ */ + /* --------------------------------------------------- */ + +static void +more_neck(fpw, pos, total, brdname, xname) + FILE *fpw; + int pos, total; + char *brdname, *xname; +{ + fputs("<br>\n" + "<table cellspacing=0 cellpadding=1 border=0 width=760>\n" + "<tr bgcolor=" HCOLOR_NECK ">\n <td width=20%", fpw); + + if (pos > 1) + { + fputs(" align=center><a href=?", fpw); + if (brdname) + fprintf(fpw, "%s&", brdname); + if (xname) + fprintf(fpw, "%s&", xname); + fprintf(fpw, "%d>¤W¤@½g</a", pos - 1); + } + fputs("></td>\n <td width=20%", fpw); + + if (pos < total) + { + fputs(" align=center><a href=?", fpw); + if (brdname) + fprintf(fpw, "%s&", brdname); + if (xname) + fprintf(fpw, "%s&", xname); + fprintf(fpw, "%d>¤U¤@½g</a", pos + 1); + } + + if (xname) + fprintf(fpw, "></td>\n <td width=60%% align=center><a href=/gem?%s&%s>¦^¨ì¨÷©v</a", brdname, xname); + else if (brdname) + { + fprintf(fpw, "></td>\n <td width=20%% align=center><a href=/bmost?%s&%d target=_blank>¦P¼ÐÃD</a></td>\n" + " <td width=20%% align=center><a href=/dopost?%s target=_blank>µoªí¤å³¹</a></td>\n" + " <td width=20%% align=center><a href=/brd?%s>¤å³¹¦Cªí</a", + brdname, pos, + brdname, brdname); + } + else + fputs("></td>\n <td width=60% align=center><a href=/mbox>«H½c¦Cªí</a", fpw); + + fputs("></td>\n</tr></table><br>\n", fpw); +} + + +static int +more_item(fpw, folder, pos, brdname) + FILE *fpw; + char *folder; + int pos; + char *brdname; +{ + int fd, total; + HDR hdr; + char fpath[64]; + + total = rec_num(folder, sizeof(HDR)); + if ((fd = open(folder, O_RDONLY)) >= 0) + { + int find; + + lseek(fd, (off_t) (sizeof(HDR) * (pos - 1)), SEEK_SET); + find = read(fd, &hdr, sizeof(HDR)) == sizeof(HDR); + close(fd); + + if (find) + { + more_neck(fpw, pos, total, brdname, NULL); + +#ifdef HAVE_REFUSEMARK + if (!(hdr.xmode & POST_RESTRICT)) + { +#endif + hdr_fpath(fpath, folder, &hdr); + out_article(fpw, fpath); +#ifdef HAVE_REFUSEMARK + } + else + out_mesg(fpw, "³o¬O¥[±Kªº¤å³¹¡A±zµLªk¾\\Ū"); +#endif + + more_neck(fpw, pos, total, brdname, NULL); + return HS_END; + } + } + + return HS_ERR_MORE; +} + + +static int +cmd_brdmore(ap) + Agent *ap; +{ + int pos; + char folder[64], *brdname, *number; + FILE *fpw = out_head(ap, "¾\\Ū¬ÝªO¤å³¹"); + + if (!arg_analyze(2, '?', ap->urlp, &brdname, &number, NULL, NULL)) + return HS_ERROR; + + if (!allow_brdname(ap, brdname)) + return HS_ERR_BOARD; + + brd_fpath(folder, brdname, FN_DIR); + + if ((pos = atoi(number)) <= 0) + pos = 1; + + return more_item(fpw, folder, pos, brdname); +} + + + /* --------------------------------------------------- */ + /* ¾\Ū«H½c¤å³¹ */ + /* --------------------------------------------------- */ + +static int +cmd_mboxmore(ap) + Agent *ap; +{ + int pos; + char folder[64], *number; + FILE *fpw = out_head(ap, "¾\\Ū«H½c¤å³¹"); + + if (!arg_analyze(1, '?', ap->urlp, &number, NULL, NULL, NULL)) + return HS_ERROR; + + if (!acct_fetch(ap)) + return HS_ERR_LOGIN; + + usr_fpath(folder, ap->userid, FN_DIR); + + if ((pos = atoi(number)) <= 0) + pos = 1; + + return more_item(fpw, folder, pos, NULL); +} + + + /* --------------------------------------------------- */ + /* ¾\Ū¬ÝªO¦P¼ÐÃD¤å³¹ */ + /* --------------------------------------------------- */ + +static void +do_brdmost(fpw, folder, title) + FILE *fpw; + char *folder, *title; +{ + int fd; + char fpath[64]; + FILE *fp; + HDR hdr; + + if ((fd = open(folder, O_RDONLY)) >= 0) + { + while (read(fd, &hdr, sizeof(HDR)) == sizeof(HDR)) + { +#ifdef HAVE_REFUSEMARK + if (hdr.xmode & POST_RESTRICT) + continue; +#endif + + if (!strcmp(str_ttl(hdr.title), title)) + { + hdr_fpath(fpath, folder, &hdr); + if (fp = fopen(fpath, "r")) + { + txt2htm(fpw, fp); + fclose(fp); + } + } + } + close(fd); + } +} + + +static void +brdmost_neck(fpw) + FILE *fpw; +{ + fputs("<br>\n" + "<table cellspacing=0 cellpadding=1 border=0 width=760>\n" + "<tr bgcolor=" HCOLOR_NECK ">\n" + " <td align=center>¦P¼ÐÃD¾\\Ū</td>\n" + "</tr></table><br>\n", fpw); +} + + +static int +cmd_brdmost(ap) + Agent *ap; +{ + int fd, pos; + char folder[64], *brdname, *number; + HDR hdr; + FILE *fpw = out_head(ap, "¾\\Ū¬ÝªO¦P¼ÐÃD¤å³¹"); + + if (!arg_analyze(2, '?', ap->urlp, &brdname, &number, NULL, NULL)) + return HS_ERROR; + + if (!allow_brdname(ap, brdname)) + return HS_ERR_BOARD; + + brd_fpath(folder, brdname, FN_DIR); + + if ((pos = atoi(number)) <= 0) + pos = 1; + + if ((fd = open(folder, O_RDONLY)) >= 0) + { + int find; + + lseek(fd, (off_t) (sizeof(HDR) * (pos - 1)), SEEK_SET); + find = read(fd, &hdr, sizeof(HDR)) == sizeof(HDR); + close(fd); + + if (find) + { + brdmost_neck(fpw); + out_style(fpw); + do_brdmost(fpw, folder, str_ttl(hdr.title)); + brdmost_neck(fpw); + return HS_END; + } + } + return HS_ERR_MORE; +} + + + /* --------------------------------------------------- */ + /* ¾\ŪºëµØ°Ï¤å³¹ */ + /* --------------------------------------------------- */ + +static int +cmd_gemmore(ap) + Agent *ap; +{ + int fd, pos, total; + char *brdname, *xname, *number, folder[64]; + HDR hdr; + FILE *fpw = out_head(ap, "¾\\ŪºëµØ°Ï¤å³¹"); + + if (!arg_analyze(3, '?', ap->urlp, &brdname, &xname, &number, NULL)) + return HS_ERROR; + + if (*xname != 'F' && strlen(xname) != 8 && strcmp(xname, FN_DIR)) + return HS_ERROR; + + if (!allow_brdname(ap, brdname)) + return HS_ERR_BOARD; + + if (*xname == '.') + gem_fpath(folder, brdname, FN_DIR); + else /* if (*xname == 'F') */ + sprintf(folder, "gem/brd/%s/%c/%s", brdname, xname[7], xname); + + if ((pos = atoi(number)) <= 0) + pos = 1; + total = rec_num(folder, sizeof(HDR)); + + if ((fd = open(folder, O_RDONLY)) >= 0) + { + int find; + + lseek(fd, (off_t) (sizeof(HDR) * (pos - 1)), SEEK_SET); + find = read(fd, &hdr, sizeof(HDR)) == sizeof(HDR); + close(fd); + + if (find) + { + more_neck(fpw, pos, total, brdname, xname); + if (hdr.xname[0] == 'A') + { + if (!(hdr.xmode & GEM_RESTRICT)) + { + sprintf(folder, "gem/brd/%s/%c/%s", brdname, hdr.xname[7], hdr.xname); + out_article(fpw, folder); + } + else + out_mesg(fpw, "¦¹¬°«O±KºëµØ°Ï¡A±zµLªk¾\\Ū"); + } + else + out_mesg(fpw, "³o¬O¨÷©v©Î°ßŪ¸ê®Æ¡A±z¥²¶·¥ÑºëµØ°Ï¦Cªí¨ÓŪ¨ú"); + more_neck(fpw, pos, total, brdname, xname); + return HS_END; + } + } + + return HS_ERR_MORE; +} + + + /* --------------------------------------------------- */ + /* µoªí¤å³¹ */ + /* --------------------------------------------------- */ + +static int +cmd_dopost(ap) + Agent *ap; +{ + char *brdname; + FILE *fpw = out_head(ap, "µoªí¤å³¹"); + + if (!arg_analyze(1, '?', ap->urlp, &brdname, NULL, NULL, NULL)) + return HS_ERROR; + + if (!(ben_perm(ap, brdname) & BRD_W_BIT)) + return HS_ERR_BOARD; + + fputs("<form method=post onsubmit=\"if(t.value.length==0 || c.value.length==0) {alert('¼ÐÃD¡B¤º®e§¡¤£¥i¬°ªÅ¥Õ'); return false;} return true;\">\n" + " <input type=hidden name=dopost>\n" + " ½Ð¿é¤J¼ÐÃD¡G<br>\n", fpw); + fprintf(fpw, + " <input type=hidden name=b value=%s>\n" + " <input type=text name=t size=%d maxlength=%d><br><br>\n" + " ½Ð¿é¤J¤º®e¡G<br>\n" + " <textarea name=c rows=10 cols=%d></textarea><br><br>\n" + " <input type=hidden name=end>\r\n" + " <input type=submit value=°e¥X¤å³¹> " + " <input type=reset value=«·s¶ñ¼g>" + "</form>\n", + brdname, + TTLEN, TTLEN, + SCR_WIDTH); + + return HS_END; +} + + + /* --------------------------------------------------- */ + /* µo°e«H¥ó */ + /* --------------------------------------------------- */ + +static int +cmd_domail(ap) + Agent *ap; +{ + char *userid; + FILE *fpw = out_head(ap, "µo°e«H¥ó"); + + if (!acct_fetch(ap)) + return HS_ERR_LOGIN; + + if (!arg_analyze(1, '?', ap->urlp, &userid, NULL, NULL, NULL)) + userid = ""; + + fputs("<form method=post onsubmit=\"if(u.value.length==0 || t.value.length==0 || c.value.length==0) {alert('¦¬«H¤H¡B¼ÐÃD¡B¤º®e§¡¤£¥i¬°ªÅ¥Õ'); return false;} return true;\">\n" + " <input type=hidden name=domail>\n" + " ½Ð¿é¤J¦¬«H¤H¢×¢Ò¡G<br>\n", fpw); + fprintf(fpw, + " <input type=text name=u size=%d maxlength=%d value=%s><br><br>\n" + " ½Ð¿é¤J¼ÐÃD¡G<br>\n" + " <input type=text name=t size=%d maxlength=%d><br><br>\n" + " ½Ð¿é¤J¤º®e¡G<br>\n" + " <textarea name=c rows=10 cols=%d></textarea><br><br>\n" + " <input type=hidden name=end>\r\n" + " <input type=submit value=°e¥X«H¥ó> " + " <input type=reset value=«·s¶ñ¼g>" + "</form>\n", + IDLEN, IDLEN, userid, + TTLEN, TTLEN, + SCR_WIDTH); + + return HS_END; +} + + + /* --------------------------------------------------- */ + /* ¼Ð°O/§R°£ ¤å³¹ */ + /* --------------------------------------------------- */ + +static void outgo_post(); + +static void +move_post(userid, hdr, folder, by_bm) /* ±N hdr ±q folder ·h¨ì§OªºªO */ + char *userid; + HDR *hdr; + char *folder; + int by_bm; +{ + HDR post; + int xmode; + char fpath[64], fnew[64], *board; + + xmode = hdr->xmode; + hdr_fpath(fpath, folder, hdr); + + if (!(xmode & POST_BOTTOM)) /* ¸m©³¤å³Q¬å¤£¥Î move_post */ + { +#ifdef HAVE_REFUSEMARK + board = by_bm && !(xmode & POST_RESTRICT) ? BN_DELETED : BN_JUNK; /* ¥[±K¤å³¹¥á¥h junk */ +#else + board = by_bm ? BN_DELETED : BN_JUNK; +#endif + + brd_fpath(fnew, board, FN_DIR); + hdr_stamp(fnew, HDR_LINK | 'A', &post, fpath); + + /* ª½±µ½Æ»s trailing data¡Gowner(§t)¥H¤U©Ò¦³Äæ¦ì */ + memcpy(post.owner, hdr->owner, sizeof(HDR) - + (sizeof(post.chrono) + sizeof(post.xmode) + sizeof(post.xid) + sizeof(post.xname))); + + if (by_bm) + sprintf(post.title, "%-13s%.59s", userid, hdr->title); + + rec_bot(fnew, &post, sizeof(HDR)); + brd_get(board)->btime = -1; + } + unlink(fpath); +} + + +static int +op_shell(op_func, ap, title, msg) + int (*op_func) (Agent *, char *, char *); + Agent *ap; + char *title, *msg; +{ + int ret = op_func(ap, title, msg); + if (ret != HS_END) + out_head(ap, title + 1); + return ret; +} + + +static int +post_op(ap, title, msg) + Agent *ap; + char *title, *msg; +{ + int pos; + time_t chrono; + HDR hdr; + usint bits; + char *brdname, *number, *stamp, folder[64]; + FILE *fpw; + + if (!arg_analyze(3, '?', ap->urlp, &brdname, &number, &stamp, NULL) || + (pos = atoi(number) - 1) < 0 || + (chrono = atoi(stamp)) < 0) + return HS_ERROR; + + if (bits = ben_perm(ap, brdname)) + { + brd_fpath(folder, brdname, FN_DIR); + if (rec_get(folder, &hdr, sizeof(HDR), pos) || + (hdr.chrono != chrono)) + return HS_ERR_MORE; + + if (*title == 'm') + { + if (!(bits & BRD_X_BIT)) + return HS_ERR_PERM; + + hdr.xmode ^= POST_MARKED; + rec_put(folder, &hdr, sizeof(HDR), pos, NULL); + } + else /* if (*title == 'd') */ + { + if (!(hdr.xmode & POST_MARKED)) + { + if (!(bits & BRD_X_BIT) && + (!(bits & BRD_W_BIT) || strcmp(ap->userid, hdr.owner))) + return HS_ERR_PERM; + + rec_del(folder, sizeof(HDR), pos, NULL); + move_post(ap->userid, &hdr, folder, bits & BRD_X_BIT); + brd_get(brdname)->btime = -1; + /* ³s½u¬å«H */ + if ((hdr.xmode & POST_OUTGO) && /* ¥~Âà«H¥ó */ + hdr.chrono > (time(0) - 7 * 86400)) /* 7 ¤Ñ¤§¤º¦³®Ä */ + { + hdr.chrono = -1; + outgo_post(&hdr, brdname); + } + } + } + + sprintf(folder, "/brd?%s&%d", brdname, (pos - 1) / HTML_TALL * HTML_TALL + 1); + fpw = out_http(ap, HS_OK | HS_REFRESH, folder); + out_title(fpw, title + 1); + out_mesg(fpw, msg); + fprintf(fpw, "<a href=%s>¦^¤å³¹¦Cªí</a>\n", folder); + + return HS_END; + } + return HS_ERR_BOARD; +} + + +static int +cmd_markpost(ap) + Agent *ap; +{ + return op_shell(post_op, ap, "m¼Ð°O¤å³¹", "¤w°õ¦æ(¨ú®ø)¼Ð°O«ü¥O"); +} + + +static int +cmd_delpost(ap) + Agent *ap; +{ + return op_shell(post_op, ap, "d§R°£¤å³¹", "¤w°õ¦æ§R°£«ü¥O¡AY¥¼§R°£ªí¥Ü¦¹¤å³¹³Q¼Ð°O¤F"); +} + + +static int +cmd_predelpost(ap) + Agent *ap; +{ + char *brdname, *number, *stamp; + FILE *fpw = out_head(ap, "½T»{§R°£¤å³¹"); + + if (!arg_analyze(3, '?', ap->urlp, &brdname, &number, &stamp, NULL)) + return HS_ERROR; + + out_mesg(fpw, "Y½T©wn§R°£¦¹½g¤å³¹¡A½Ð¦A¦¸ÂI¿ï¥H¤U³sµ²¡FYn¨ú®ø§R°£¡A½Ð«ö [¤W¤@¶]"); + fprintf(fpw, "<a href=/delpost?%s&%s&%s>§R°£ [%s] ªO²Ä %s ½g¤å³¹</a><br>\n", + brdname, number, stamp, brdname, number); + + return HS_END; +} + + + /* --------------------------------------------------- */ + /* ¼Ð°O/§R°£ «H¥ó */ + /* --------------------------------------------------- */ + +static int +mail_op(ap, title, msg) + Agent *ap; + char *title, *msg; +{ + int pos; + time_t chrono; + HDR hdr; + char *number, *stamp, folder[64], fpath[64]; + + if (!arg_analyze(2, '?', ap->urlp, &number, &stamp, NULL, NULL) || + (pos = atoi(number) - 1) < 0 || + (chrono = atoi(stamp)) < 0) + return HS_ERROR; + + if (acct_fetch(ap)) + { + usr_fpath(folder, ap->userid, FN_DIR); + if (rec_get(folder, &hdr, sizeof(HDR), pos) || + (hdr.chrono != chrono)) + return HS_ERR_MAIL; + + if (*title == 'm') + { + hdr.xmode ^= POST_MARKED; + rec_put(folder, &hdr, sizeof(HDR), pos, NULL); + } + else /* if (*title == 'd') */ + { + if (!(hdr.xmode & POST_MARKED)) + { + rec_del(folder, sizeof(HDR), pos, NULL); + hdr_fpath(fpath, folder, &hdr); + unlink(fpath); + } + } + + sprintf(folder, "/mbox?%d", (pos - 1) / HTML_TALL * HTML_TALL + 1); + out_title(out_http(ap, HS_OK | HS_REFRESH, folder), title + 1); + out_mesg(ap->fpw, msg); + fprintf(ap->fpw, "<a href=%s>¦^«H½c¦Cªí</a>\n", folder); + return HS_END; + } + return HS_ERR_LOGIN; +} + + +static int +cmd_markmail(ap) + Agent *ap; +{ + return op_shell(mail_op, ap, "m¼Ð°O«H¥ó", "¤w°õ¦æ(¨ú®ø)¼Ð°O«ü¥O"); +} + + +static int +cmd_delmail(ap) + Agent *ap; +{ + return op_shell(mail_op, ap, "d§R°£«H¥ó", "¤w°õ¦æ§R°£«ü¥O¡AY¥¼§R°£ªí¥Ü¦¹«H¥ó³Q¼Ð°O¤F"); +} + + +static int +cmd_predelmail(ap) + Agent *ap; +{ + char *number, *stamp; + FILE *fpw = out_head(ap, "½T»{§R°£«H¥ó"); + + if (!arg_analyze(2, '?', ap->urlp, &number, &stamp, NULL, NULL)) + return HS_ERROR; + + out_mesg(fpw, "Y½T©wn§R°£¦¹½g«H¥ó¡A½Ð¦A¦¸ÂI¿ï¥H¤U³sµ²¡FYn¨ú®ø§R°£¡A½Ð«ö [¤W¤@¶]"); + fprintf(fpw, "<a href=/delmail?%s&%s>§R°£«H½c²Ä %s ½g«H¥ó</a><br>\n", + number, stamp, number); + + return HS_END; +} + + + /* --------------------------------------------------- */ + /* ¬d¸ß¨Ï¥ÎªÌ */ + /* --------------------------------------------------- */ + +static int +cmd_query(ap) + Agent *ap; +{ + int fd; + ACCT acct; + char fpath[64], *userid; + FILE *fpw = out_head(ap, "¬d¸ß¨Ï¥ÎªÌ"); + + if (!arg_analyze(1, '?', ap->urlp, &userid, NULL, NULL, NULL)) + return HS_ERROR; + + if (!allow_userid(ap, userid)) + return HS_ERR_USER; + + usr_fpath(fpath, userid, FN_ACCT); + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + read(fd, &acct, sizeof(ACCT)); + close(fd); + + fprintf(fpw, "<pre>\n" + "<a target=_blank href=domail?%s>%s (%s)</a><br>\n" + "%s³q¹L»{ÃÒ¡A¦@¤W¯¸ %d ¦¸¡Aµoªí¹L %d ½g¤å³¹<br>\n" + "³Ìªñ(%s)±q[%s]¤W¯¸<br>\n" + "</pre>\n", + acct.userid, acct.userid, + str_html(acct.username, UNLEN), + (acct.userlevel & PERM_VALID) ? "¤w" : "¥¼", acct.numlogins, acct.numposts, + Btime(&(acct.lastlogin)), acct.lasthost); + + usr_fpath(fpath, acct.userid, FN_PLANS); + out_article(fpw, fpath); + return HS_END; + } + + return HS_ERR_USER; +} + + + /* --------------------------------------------------- */ + /* Åã¥Ü¹Ï¤ù */ + /* --------------------------------------------------- */ + +static int +valid_path(str) + char *str; +{ + int ch; + + if (!*str) + return; + + while (ch = *str++) + { + if (!is_alnum(ch) && ch != '.' && ch != '-' && ch != '_') + return 0; + } + return 1; +} + + +static int +cmd_image(ap) + Agent *ap; +{ + FILE *fpw; + struct stat st; + char *fname, *ptr, fpath[64]; + + if (!arg_analyze(1, '?', ap->urlp, &fname, NULL, NULL, NULL)) + return HS_NOTFOUND; + + if (!valid_path(fname) || !(ptr = strchr(fname, '.'))) + return HS_NOTFOUND; + + /* ¤ä´©®æ¦¡ */ + if (!str_cmp(ptr, ".html")) + ptr = "text/html"; + else if (!str_cmp(ptr, ".gif")) + ptr = "image/gif"; + else if (!str_cmp(ptr, ".jpg")) + ptr = "image/jpeg"; + else if (!str_cmp(ptr, ".css")) + ptr = "text/css"; + else if (!str_cmp(ptr, ".png")) + ptr = "image/png"; + else + return HS_NOTFOUND; + + sprintf(fpath, "run/html/%.40s", fname); + if (stat(fpath, &st)) + return HS_NOTFOUND; + + if (ap->modified[0] && !strcmp(Gtime(&st.st_mtime), ap->modified)) /* ¨S¦³Åܧ󤣻Ýn¶Ç¿é */ + return HS_NOTMOIDIFY; + + fpw = out_http(ap, HS_OK, ptr); + fprintf(fpw, "Content-Length: %d\r\n", st.st_size); + fprintf(fpw, "Last-Modified: %s\r\n\r\n", Gtime(&st.st_mtime)); + f_suck(fpw, fpath); + + return HS_OK; +} + + + /* --------------------------------------------------- */ + /* RSS */ + /* --------------------------------------------------- */ + +static int +cmd_rss(ap) + Agent *ap; +{ + time_t blast; + char folder[64], *brdname, *ptr; + BRD *brd; + HDR hdr; + FILE *fpw; + int fd; + + if (!arg_analyze(1, '?', ap->urlp, &brdname, NULL, NULL, NULL)) + return HS_BADREQUEST; + + if (!(brd = brd_get(brdname))) + return HS_NOTFOUND; + + if (brd->readlevel) /* ¥u¦³¤½¶}ªO¤~´£¨Ñ rss */ + return HS_FORBIDDEN; + + blast = brd->blast; + + if (ap->modified[0] && !strcmp(Gtime(&blast), ap->modified)) /* ¨S¦³Åܧ󤣻Ýn¶Ç¿é */ + return HS_NOTMOIDIFY; + + fpw = out_http(ap, HS_OK, "application/xml"); + fprintf(fpw, "Last-Modified: %s\r\n\r\n", Gtime(&blast)); + + /* xml header */ + fputs("<?xml version=\"1.0\" encoding=\"" MYCHARSET "\" ?>\n" + "<rss version=\"2.0\">\n" + "<channel>\n", fpw); + ptr = Gtime(&blast); + ptr[4] = '\0'; + fprintf(fpw, "<title>" BBSNAME "-%sªO</title>\n" +#if BHTTP_PORT == 80 + "<link>http://" MYHOSTNAME "/brd?%s</link>\n" +#else + "<link>http://" MYHOSTNAME ":%d/brd?%s</link>\n" +#endif + "<description>%s</description>\n" + "<language>zh-tw</language>\n" + "<lastBuildDate>%s ", + brdname, +#if BHTTP_PORT != 80 + BHTTP_PORT, +#endif + brdname, + str_html(brd->title, TTLEN), ptr); + ptr += 5; + if (*ptr == '0') + ptr++; + fprintf(fpw, "%s</lastBuildDate>\n<image>\n" + "<title>" BBSNAME "</title>" +#if BHTTP_PORT == 80 + "<link>http://" MYHOSTNAME "</link>\n" + "<url>http://" MYHOSTNAME "/img?rss.gif</url>\n" +#else + "<link>http://" MYHOSTNAME ":%d</link>\n" + "<url>http://" MYHOSTNAME ":%d/img?rss.gif</url>\n" +#endif + "</image>\n", +#if BHTTP_PORT == 80 + ptr); +#else + ptr, BHTTP_PORT, BHTTP_PORT); +#endif + + /* rss item */ + brd_fpath(folder, brdname, FN_DIR); + if ((fd = open(folder, O_RDONLY)) >= 0) + { + int fsize; + struct stat st; + + if (!fstat(fd, &st) && (fsize = st.st_size) >= sizeof(HDR)) + { + int i, end; + + /* ¥u¦C¥X³Ì«á¤G¤Q½g */ + if (fsize > 20 * sizeof(HDR)) + end = fsize - 20 * sizeof(HDR); + else + end = 0; + i = fsize / sizeof(HDR); + + while ((fsize -= sizeof(HDR)) >= end) + { + lseek(fd, fsize, SEEK_SET); + read(fd, &hdr, sizeof(HDR)); + + ptr = Gtime(&hdr.chrono); + ptr[4] = '\0'; + fprintf(fpw, "<!-- %d --><item><title>%s</title>" +#if BHTTP_PORT == 80 + "<link>http://" MYHOSTNAME "/bmore?%s&%d</link>" +#else + "<link>http://" MYHOSTNAME ":%d/bmore?%s&%d</link>" +#endif + "<author>%s</author>" + "<pubDate>%s ", + hdr.chrono, str_html(hdr.title, TTLEN), +#if BHTTP_PORT != 80 + BHTTP_PORT, +#endif + brdname, i, + hdr.owner, + ptr); + ptr += 5; + if (*ptr == '0') + ptr++; + fprintf(fpw, "%s</pubDate></item>\n", ptr); + + i--; + } + } + close(fd); + } + fputs("</channel>\n</rss>\n", fpw); + + return HS_OK; +} + + + /* --------------------------------------------------- */ + /* Robot Exclusion */ + /* --------------------------------------------------- */ + +#ifdef ROBOT_EXCLUSION +static int +cmd_robot(ap) + Agent *ap; +{ + FILE *fpw = out_http(ap, HS_OK, NULL); + + fprintf(fpw, "Content-Length: 28\r\n"); /* robot.txt ªºªø«× */ + fprintf(fpw, "Last-Modified: Sat, 01 Jan 2000 00:02:21 GMT\r\n\r\n"); /* ÀH«Kµ¹Ó®É¶¡ */ + + fprintf(fpw, "User-agent: *\r\nDisallow: /\r\n"); + + return HS_OK; +} +#endif + + + /* --------------------------------------------------- */ + /* º¶ */ + /* --------------------------------------------------- */ + +static void +mainpage_neck(fpw, userid, logined) + FILE *fpw; + char *userid; + int logined; +{ + fprintf(fpw, "<br>\n" + "<table cellspacing=0 cellpadding=1 border=0 width=760>\n" + "<tr bgcolor=" HCOLOR_NECK ">\n" + " <td width=100%% align=center>%s%sÅwªï¥úÁ{</td>\n" + "</tr></table><br>\n", + logined ? userid : "", + logined ? "¡A" : ""); +} + + +static int +cmd_mainpage(ap) + Agent *ap; +{ + int logined; + FILE *fpw = out_head(ap, ""); + + logined = acct_fetch(ap); + mainpage_neck(fpw, ap->userid, logined); + + out_film(fpw, (ap->uptime % 3) + FILM_OPENING0); + /* µn¤J */ + if (!logined) + { + /* ¶}ÀYµe± */ + fputs("<form method=post>\n" + " <input type=hidden name=login>\n" + " ±b¸¹ <input type=text name=u size=12 maxlength=12> " + " ±K½X <input type=password name=p size=12 maxlength=8> " + " <input type=submit value=µn¤J> " + " <input type=reset value=²M°£>" + "</form>\n", fpw); + } + + mainpage_neck(fpw, ap->userid, logined); + return HS_END; +} + + + /* --------------------------------------------------- */ + /* «ü¥O¶° */ + /* --------------------------------------------------- */ + +static Command cmd_table_get[] = +{ + cmd_userlist, "usrlist", 7, + cmd_boardlist, "brdlist", 7, + cmd_favorlist, "fvrlist", 7, + cmd_class, "class", 5, + + cmd_postlist, "brd", 3, + cmd_gemlist, "gem", 3, + cmd_mboxlist, "mbox", 4, + + cmd_brdmore, "bmore", 5, + cmd_brdmost, "bmost", 5, + cmd_gemmore, "gmore", 5, + cmd_mboxmore, "mmore", 5, + + cmd_dopost, "dopost", 6, + cmd_domail, "domail", 6, + + cmd_delpost, "delpost", 7, + cmd_predelpost, "dpost", 5, + cmd_delmail, "delmail", 7, + cmd_predelmail, "dmail", 5, + cmd_markpost, "mpost", 5, + cmd_markmail, "mmail", 5, + + cmd_query, "query", 5, + + cmd_image, "img", 3, + cmd_rss, "rss", 3, + +#ifdef ROBOT_EXCLUSION + cmd_robot, "robot.txt", 9, +#endif + + cmd_mainpage, "", 0, + + NULL, NULL, 0 +}; + + +/* ----------------------------------------------------- */ +/* command dispatch (POST) */ +/* ----------------------------------------------------- */ + +static char * +getfromhost(pip) + void *pip; +{ + struct hostent *hp; + + if (hp = gethostbyaddr((char *)pip, 4, AF_INET)) + return hp->h_name; + return inet_ntoa(*(struct in_addr *) pip); +} + + + /* --------------------------------------------------- */ + /* ¨Ï¥ÎªÌµn¤J */ + /* --------------------------------------------------- */ + +static int +cmd_login(ap) + Agent *ap; +{ + char *userid, *passwd; + char fpath[64]; + ACCT acct; + + /* u=userid&p=passwd */ + if (!arg_analyze(2, 0, ap->urlp, &userid, &passwd, NULL, NULL)) + return HS_ERROR; + + userid += 2; /* skip "u=" */ + passwd += 2; /* skip "p=" */ + + if (*userid && *passwd && strlen(userid) <= IDLEN && strlen(passwd) <= PSWDLEN) + { + usr_fpath(fpath, userid, FN_ACCT); + if (!rec_get(fpath, &acct, sizeof(ACCT), 0) && + !(acct.userlevel & (PERM_DENYLOGIN | PERM_PURGE)) && + !chkpasswd(acct.passwd, passwd)) /* µn¤J¦¨¥\ */ + { + /* itoc.040308: ²£¥Í Cookie */ + sprintf(ap->cookie, "%s&p=%s", userid, acct.passwd); + ap->setcookie = 1; + } + } + + return cmd_mainpage(ap); +} + + + /* --------------------------------------------------- */ + /* µoªí·s¤å³¹ */ + /* --------------------------------------------------- */ + +static void +outgo_post(hdr, board) + HDR *hdr; + char *board; +{ + bntp_t bntp; + + memset(&bntp, 0, sizeof(bntp_t)); + bntp.chrono = hdr->chrono; + strcpy(bntp.board, board); + strcpy(bntp.xname, hdr->xname); + strcpy(bntp.owner, hdr->owner); + strcpy(bntp.nick, hdr->nick); + strcpy(bntp.title, hdr->title); + rec_add("innd/out.bntp", &bntp, sizeof(bntp_t)); +} + + +static int +cmd_addpost(ap) + Agent *ap; +{ + char *brdname, *title, *content, *end; + char folder[64], fpath[64]; + HDR hdr; + BRD *brd; + FILE *fp; + FILE *fpw = out_head(ap, "¤å³¹µoªí"); + + if (!acct_fetch(ap)) + return HS_ERR_LOGIN; + + /* b=brdname&t=title&c=content&end= */ + if (arg_analyze(4, 0, ap->urlp, &brdname, &title, &content, &end)) + { + brdname += 2; /* skip "b=" */ + title += 2; /* skip "t=" */ + content += 2; /* skip "c=" */ + + if (*brdname && *title && *content) + { + if ((brd = brd_get(brdname)) && + (Ben_Perm(brd, ap->userno, ap->userid, ap->userlevel) & BRD_W_BIT)) + { + brd_fpath(folder, brdname, FN_DIR); + + fp = fdopen(hdr_stamp(folder, 'A', &hdr, fpath), "w"); + fprintf(fp, "%s %s (%s) %s %s\n", + STR_AUTHOR1, ap->userid, ap->username, + STR_POST2, brdname); + str_ncpy(hdr.title, title, sizeof(hdr.title)); + fprintf(fp, "¼ÐÃD: %s\n®É¶¡: %s\n\n", hdr.title, Now()); + fprintf(fp, "%s\n", content); + fprintf(fp, EDIT_BANNER, ap->userid, getfromhost(&(ap->ip_addr))); + fclose(fp); + + hdr.xmode = (brd->battr & BRD_NOTRAN) ? 0 : POST_OUTGO; + strcpy(hdr.owner, ap->userid); + strcpy(hdr.nick, ap->username); + rec_bot(folder, &hdr, sizeof(HDR)); + + brd->btime = -1; + if (hdr.xmode & POST_OUTGO) + outgo_post(&hdr, brdname); + + out_reload(fpw, "±zªº¤å³¹µoªí¦¨¥\\"); + return HS_OK; + } + return HS_ERR_BOARD; + } + } + + out_reload(fpw, "±zªº¤å³¹µoªí¥¢±Ñ"); + return HS_OK; +} + + + /* --------------------------------------------------- */ + /* µo°e·s«H¥ó */ + /* --------------------------------------------------- */ + +static int +cmd_addmail(ap) + Agent *ap; +{ + char *userid, *title, *content, *end; + char folder[64], fpath[64]; + HDR hdr; + FILE *fp; + FILE *fpw = out_head(ap, "«H¥óµo°e"); + + /* u=userid&t=title&c=content&end= */ + if (arg_analyze(4, 0, ap->urlp, &userid, &title, &content, &end)) + { + userid += 2; /* skip "u=" */ + title += 2; /* skip "t=" */ + content += 2; /* skip "c=" */ + + if (*userid && *title && *content && allow_userid(ap, userid)) + { + usr_fpath(fpath, userid, FN_ACCT); + if (dashf(fpath) && acct_fetch(ap)) + { + usr_fpath(folder, userid, FN_DIR); + + fp = fdopen(hdr_stamp(folder, 0, &hdr, fpath), "w"); + fprintf(fp, "%s %s (%s)\n", + STR_AUTHOR1, ap->userid, ap->username); + str_ncpy(hdr.title, title, sizeof(hdr.title)); + fprintf(fp, "¼ÐÃD: %s\n®É¶¡: %s\n\n", hdr.title, Now()); + fprintf(fp, "%s\n", content); + fprintf(fp, EDIT_BANNER, ap->userid, getfromhost(&(ap->ip_addr))); + fclose(fp); + + strcpy(hdr.owner, ap->userid); + strcpy(hdr.nick, ap->username); + rec_add(folder, &hdr, sizeof(HDR)); + + out_reload(fpw, "±zªº«H¥óµo°e¦¨¥\\"); + return HS_OK; + } + } + } + + out_reload(fpw, "±zªº«H¥óµo°e¥¢±Ñ¡A¤]³\\¬O¦]¬°±z©|¥¼µn¤J©Î¬O¬dµL¦¹¨Ï¥ÎªÌ"); + return HS_OK; +} + + + /* --------------------------------------------------- */ + /* «ü¥O¶° */ + /* --------------------------------------------------- */ + +static Command cmd_table_post[] = +{ + cmd_login, "login=&", 7, + cmd_addpost, "dopost=&", 8, + cmd_addmail, "domail=&", 8, + + NULL, NULL, 0 +}; + + +/* ----------------------------------------------------- */ +/* close a connection & release its resource */ +/* ----------------------------------------------------- */ + +static void +agent_fire(ap) + Agent *ap; +{ + int csock; + + csock = ap->sock; + if (csock > 0) + { + fcntl(csock, F_SETFL, M_NONBLOCK); + shutdown(csock, 2); + + /* fclose(ap->fpw); */ + close(csock); + } + + if (ap->data) + free(ap->data); +} + + +/* ----------------------------------------------------- */ +/* receive request from client */ +/* ----------------------------------------------------- */ + +static int /* >=0:mode -1:µ²§ô */ +do_cmd(ap, str, end, mode) + Agent *ap; + uschar *str, *end; /* command line ªº¶}ÀY©Mµ²§À */ + int mode; +{ + int code; + char *ptr; + + if (!(mode & (AM_GET | AM_POST))) + { + if (!str_ncmp(str, "GET ", 4)) /* str ®æ¦¡¬° GET /index.htm HTTP/1.0 */ + { + mode ^= AM_GET; + str += 4; + + if (*str != '/') + { + out_error(ap, HS_BADREQUEST); + return -1; + } + + if (ptr = strchr(str, ' ')) + { + *ptr = '\0'; + str_ncpy(ap->url, str + 1, sizeof(ap->url)); + } + else + { + *ap->url = '\0'; + } + } + else if (!str_ncmp(str, "POST ", 5)) /* str ®æ¦¡¬° POST /dopost?sysop HTTP/1.0 */ + { + mode ^= AM_POST; + } + } + else + { + if (*str) /* ¤£¬OªÅ¦æ¡GÀÉÀY */ + { + /* ¤ÀªR Cookie */ + if (!str_ncmp(str, "Cookie: user=", 13)) + str_ncpy(ap->cookie, str + 13, LEN_COOKIE); + + /* ¤ÀªR If-Modified-Since */ + if ((mode & AM_GET) && !str_ncmp(str, "If-Modified-Since: ", 19)) /* str ®æ¦¡¬° If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT */ + str_ncpy(ap->modified, str + 19, sizeof(ap->modified)); + } + else /* ªÅ¦æ */ + { + Command *cmd; + char *url; + + if (mode & AM_GET) + { + cmd = cmd_table_get; + url = ap->url; + } + else /* if (mode & AM_POST) */ + { + cmd = cmd_table_post; + /* ¦b AM_POST ®É¡AªÅ¦æªº¤U¤@¦æ¬O POST ªº¤º®e */ + for (url = end + 1; *url == '\r' || *url == '\n'; url++) /* §ä¤U¤@¦æ */ + ; + } + + for (; ptr = cmd->cmd; cmd++) + { + if (!str_ncmp(url, ptr, cmd->len)) + break; + } + + /* ¦pªG¦b command_table ¸Ì±§ä¤£¨ì¡A¨º»ò¦Û°Ê«·s¾É¦V */ + if (!ptr) + { + out_http(ap, HS_REDIRECT, NULL); + return -1; + } + + ap->urlp = url + cmd->len; + + code = (*cmd->func) (ap); + if (code != HS_OK) + { + if (code != HS_END) + out_error(ap, code); + if (code < HS_OK) + out_tail(ap->fpw); + } + return -1; + } + } + + return mode; +} + + +static int +agent_recv(ap) + Agent *ap; +{ + int cc, mode, size, used; + uschar *data, *head; + + used = ap->used; + data = ap->data; + + if (used > 0) + { + /* check the available space */ + + size = ap->size; + cc = size - used; + + if (cc < TCP_RCVSIZ + 3) + { + if (size < MAX_DATA_SIZE) + { + size += TCP_RCVSIZ + (size >> 2); + + if (data = (uschar *) realloc(data, size)) + { + ap->data = data; + ap->size = size; + } + else + { +#ifdef LOG_VERBOSE + fprintf(flog, "ERROR\trealloc: %d\n", size); +#endif + return 0; + } + } + else + { +#ifdef LOG_VERBOSE + fprintf(flog, "WARN\tdata too long\n"); +#endif + return 0; + } + } + } + + head = data + used; + cc = recv(ap->sock, head, TCP_RCVSIZ, 0); + + if (cc <= 0) + { + cc = errno; + if (cc != EWOULDBLOCK) + { +#ifdef LOG_VERBOSE + fprintf(flog, "RECV\t%s\n", strerror(cc)); +#endif + return 0; + } + + /* would block, so leave it to do later */ + + return -1; + } + + head[cc] = '\0'; + ap->used = (used += cc); + + /* itoc.050807: recv() ¤@¦¸ÁÙŪ¤£§¹ªº¡A¤@©w¬O cmd_dopost ©Î cmd_domail¡A³o¤GªÌªºµ²§ô³£¦³ &end= */ + if (used >= TCP_RCVSIZ) + { + /* ¦h -2 ¬O¦]¬°¦³¨ÇÂsÄý¾¹·|¦Û°Ê¸É¤W \r\n */ + if (!strstr(head + cc - strlen("&end=") - 2, "&end=")) /* ÁÙ¨SŪ§¹¡AÄ~ÄòŪ */ + return 1; + } + + mode = 0; + head = data; + + while (cc = *head) + { + if (cc == '\n') + { + data++; + } + else if (cc == '\r') + { + *head = '\0'; + + if ((mode = do_cmd(ap, data, head, mode)) < 0) + { + fflush(ap->fpw); /* do_cmd() ¦^¶Ç -1 ªí¥Üµ²§ô¡A´N fflush ©Ò¦³µ²ªG */ + return 0; + } + + data = head + 1; + } + head++; + } + + return 0; +} + + +/* ----------------------------------------------------- */ +/* accept a new connection */ +/* ----------------------------------------------------- */ + +static int +agent_accept(ipaddr) + unsigned int *ipaddr; +{ + int csock; + int value; + struct sockaddr_in csin; + + for (;;) + { + value = sizeof(csin); + csock = accept(0, (struct sockaddr *) & csin, &value); + /* if (csock > 0) */ + if (csock >= 0) /* Thor.000126: more proper */ + break; + + csock = errno; + if (csock != EINTR) + { +#ifdef LOG_VERBOSE + fprintf(flog, "ACCEPT\t%s\n", strerror(csock)); +#endif + return -1; + } + + while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0); + } + + value = 1; + /* Thor.000511: µù¸Ñ: don't delay send to coalesce(Áp¦X) packets */ + setsockopt(csock, IPPROTO_TCP, TCP_NODELAY, (char *)&value, sizeof(value)); + + *ipaddr = csin.sin_addr.s_addr; + + return csock; +} + + +/* ----------------------------------------------------- */ +/* signal routines */ +/* ----------------------------------------------------- */ + +#ifdef SERVER_USAGE +static void +servo_usage() +{ + struct rusage ru; + + if (getrusage(RUSAGE_SELF, &ru)) + return; + + fprintf(flog, "\n[Server Usage]\n\n" + " user time: %.6f\n" + " system time: %.6f\n" + " maximum resident set size: %lu P\n" + " integral resident set size: %lu\n" + " page faults not requiring physical I/O: %d\n" + " page faults requiring physical I/O: %d\n" + " swaps: %d\n" + " block input operations: %d\n" + " block output operations: %d\n" + " messages sent: %d\n" + " messages received: %d\n" + " signals received: %d\n" + " voluntary context switches: %d\n" + " involuntary context switches: %d\n", + + (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec / 1000000.0, + (double)ru.ru_stime.tv_sec + (double)ru.ru_stime.tv_usec / 1000000.0, + ru.ru_maxrss, + ru.ru_idrss, + ru.ru_minflt, + ru.ru_majflt, + ru.ru_nswap, + ru.ru_inblock, + ru.ru_oublock, + ru.ru_msgsnd, + ru.ru_msgrcv, + ru.ru_nsignals, + ru.ru_nvcsw, + ru.ru_nivcsw); + + fflush(flog); +} +#endif + + +static void +sig_term(sig) + int sig; +{ + char buf[80]; + + sprintf(buf, "sig: %d, errno: %d => %s", sig, errno, strerror(errno)); + logit("EXIT", buf); + fclose(flog); + exit(0); +} + + +static void +reaper() +{ + while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0); +} + + +static void +servo_signal() +{ + struct sigaction act; + + /* sigblock(sigmask(SIGPIPE)); *//* Thor.981206: ²Î¤@ POSIX ¼Ð·Ç¥Îªk */ + + /* act.sa_mask = 0; *//* Thor.981105: ¼Ð·Ç¥Îªk */ + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + act.sa_handler = sig_term; + sigaction(SIGTERM, &act, NULL); /* forced termination */ + sigaction(SIGSEGV, &act, NULL); /* if rlimit violate */ + sigaction(SIGBUS, &act, NULL); + +#if 1 /* Thor.990203: §ì signal */ + sigaction(SIGURG, &act, NULL); + sigaction(SIGXCPU, &act, NULL); + sigaction(SIGXFSZ, &act, NULL); + +#ifdef SOLARIS + sigaction(SIGLOST, &act, NULL); + sigaction(SIGPOLL, &act, NULL); + sigaction(SIGPWR, &act, NULL); +#endif + +#ifdef LINUX + sigaction(SIGSYS, &act, NULL); + /* sigaction(SIGEMT, &act, NULL); */ + /* itoc.010317: §Úªº linux ¨S¦³³oÓ»¡ :p */ +#endif + + sigaction(SIGFPE, &act, NULL); + sigaction(SIGWINCH, &act, NULL); + sigaction(SIGINT, &act, NULL); + sigaction(SIGQUIT, &act, NULL); + sigaction(SIGILL, &act, NULL); + sigaction(SIGTRAP, &act, NULL); + sigaction(SIGABRT, &act, NULL); + sigaction(SIGTSTP, &act, NULL); + sigaction(SIGTTIN, &act, NULL); + sigaction(SIGTTOU, &act, NULL); + sigaction(SIGVTALRM, &act, NULL); +#endif + + sigaction(SIGHUP, &act, NULL); + + act.sa_handler = reaper; + sigaction(SIGCHLD, &act, NULL); + +#ifdef SERVER_USAGE + act.sa_handler = servo_usage; + sigaction(SIGPROF, &act, NULL); +#endif + + /* Thor.981206: lkchu patch: ²Î¤@ POSIX ¼Ð·Ç¥Îªk */ + /* ¦b¦¹É¥Î sigset_t act.sa_mask */ + sigaddset(&act.sa_mask, SIGPIPE); + sigprocmask(SIG_BLOCK, &act.sa_mask, NULL); +} + + +/* ----------------------------------------------------- */ +/* server core routines */ +/* ----------------------------------------------------- */ + +static void +servo_daemon(inetd) + int inetd; +{ + int fd, value; + char buf[80]; + struct linger ld; + struct sockaddr_in sin; + +#ifdef HAVE_RLIMIT + struct rlimit limit; +#endif + + /* More idiot speed-hacking --- the first time conversion makes the C * + * library open the files containing the locale definition and time zone. * + * If this hasn't happened in the parent process, it happens in the * + * children, once per connection --- and it does add up. */ + + time((time_t *) & value); + gmtime((time_t *) & value); + strftime(buf, 80, "%d/%b/%Y:%H:%M:%S", localtime((time_t *) & value)); + +#ifdef HAVE_RLIMIT + /* --------------------------------------------------- */ + /* adjust the resource limit */ + /* --------------------------------------------------- */ + + getrlimit(RLIMIT_NOFILE, &limit); + limit.rlim_cur = limit.rlim_max; + setrlimit(RLIMIT_NOFILE, &limit); + + limit.rlim_cur = limit.rlim_max = 16 * 1024 * 1024; + setrlimit(RLIMIT_FSIZE, &limit); + + limit.rlim_cur = limit.rlim_max = 16 * 1024 * 1024; + setrlimit(RLIMIT_DATA, &limit); + +#ifdef SOLARIS +#define RLIMIT_RSS RLIMIT_AS /* Thor.981206: port for solaris 2.6 */ +#endif + + setrlimit(RLIMIT_RSS, &limit); + + limit.rlim_cur = limit.rlim_max = 0; + setrlimit(RLIMIT_CORE, &limit); +#endif + + /* --------------------------------------------------- */ + /* detach daemon process */ + /* --------------------------------------------------- */ + + close(1); + close(2); + + if (inetd) + return; + + close(0); + + if (fork()) + exit(0); + + setsid(); + + if (fork()) + exit(0); + + /* --------------------------------------------------- */ + /* setup socket */ + /* --------------------------------------------------- */ + + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + value = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&value, sizeof(value)); + + ld.l_onoff = ld.l_linger = 0; + setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&ld, sizeof(ld)); + + sin.sin_family = AF_INET; + sin.sin_port = htons(BHTTP_PORT); + sin.sin_addr.s_addr = htonl(INADDR_ANY); + memset((char *)&sin.sin_zero, 0, sizeof(sin.sin_zero)); + + if (bind(fd, (struct sockaddr *) & sin, sizeof(sin)) || + listen(fd, TCP_BACKLOG)) + exit(1); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int n, sock, cc; + time_t uptime, tcheck, tfresh; + Agent **FBI, *Scully, *Mulder, *agent; + fd_set rset; + struct timeval tv; + + cc = 0; + + while ((n = getopt(argc, argv, "i")) != -1) + { + switch (n) + { + case 'i': + cc = 1; + break; + + default: + fprintf(stderr, "Usage: %s [options]\n" + "\t-i start from inetd with wait option\n", + argv[0]); + exit(0); + } + } + + servo_daemon(cc); + + setgid(BBSGID); + setuid(BBSUID); + chdir(BBSHOME); + + init_bshm(); + init_ushm(); + init_fshm(); + + guest_userno(); + + servo_signal(); + + log_open(); + dns_init(); + + uptime = time(0); + tcheck = uptime + BHTTP_PERIOD; + tfresh = uptime + BHTTP_FRESH; + + Scully = Mulder = NULL; + + for (;;) + { + /* maintain : resource and garbage collection */ + + uptime = time(0); + if (tcheck < uptime) + { + /* ----------------------------------------------- */ + /* ±N¹L¤[¨S¦³°Ê§@ªº agent ½ð°£ */ + /* ----------------------------------------------- */ + + tcheck = uptime - BHTTP_TIMEOUT; + + for (FBI = &Scully; agent = *FBI;) + { + if (agent->uptime < tcheck) + { + agent_fire(agent); + + *FBI = agent->anext; + + agent->anext = Mulder; + Mulder = agent; + } + else + { + FBI = &(agent->anext); + } + } + + /* ----------------------------------------------- */ + /* maintain server log */ + /* ----------------------------------------------- */ + + if (tfresh < uptime) + { + tfresh = uptime + BHTTP_FRESH; +#ifdef SERVER_USAGE + servo_usage(); +#endif + log_fresh(); + } + else + { + fflush(flog); + } + + tcheck = uptime + BHTTP_PERIOD; + } + + /* ------------------------------------------------- */ + /* Set up the fdsets */ + /* ------------------------------------------------- */ + + FD_ZERO(&rset); + FD_SET(0, &rset); + + n = 0; + for (agent = Scully; agent; agent = agent->anext) + { + sock = agent->sock; + + if (n < sock) + n = sock; + + FD_SET(sock, &rset); + } + + /* in order to maintain history, timeout every BHTTP_PERIOD seconds in case no connections */ + tv.tv_sec = BHTTP_PERIOD; + tv.tv_usec = 0; + if (select(n + 1, &rset, NULL, NULL, &tv) <= 0) + continue; + + /* ------------------------------------------------- */ + /* serve active agents */ + /* ------------------------------------------------- */ + + uptime = time(0); + + for (FBI = &Scully; agent = *FBI;) + { + sock = agent->sock; + + if (FD_ISSET(sock, &rset)) + cc = agent_recv(agent); + else + cc = -1; + + if (cc == 0) + { + agent_fire(agent); + + *FBI = agent->anext; + + agent->anext = Mulder; + Mulder = agent; + + continue; + } + + if (cc > 0) /* ÁÙ¦³¸ê®Æn recv */ + agent->uptime = uptime; + + FBI = &(agent->anext); + } + + /* ------------------------------------------------- */ + /* serve new connection */ + /* ------------------------------------------------- */ + + /* Thor.000209: ¦Ò¼{²¾«e¦¹³¡¤À, §K±o¥d¦b accept() */ + if (FD_ISSET(0, &rset)) + { + unsigned int ip_addr; + + sock = agent_accept(&ip_addr); + if (sock > 0) + { + Agent *anext; + + if (agent = Mulder) + { + anext = agent->anext; + } + else + { + if (!(agent = (Agent *) malloc(sizeof(Agent)))) + { + fcntl(sock, F_SETFL, M_NONBLOCK); + shutdown(sock, 2); + close(sock); + +#ifdef LOG_VERBOSE + fprintf(flog, "ERROR\tNot enough space in main()\n"); +#endif + continue; + } + anext = NULL; + } + + /* variable initialization */ + + memset(agent, 0, sizeof(Agent)); + + agent->sock = sock; + agent->tbegin = agent->uptime = uptime; + + agent->ip_addr = ip_addr; + + if (!(agent->data = (char *) malloc(MIN_DATA_SIZE))) + { + agent_fire(agent); +#ifdef LOG_VERBOSE + fprintf(flog, "ERROR\tNot enough space in agent->data\n"); +#endif + continue; + } + agent->size = MIN_DATA_SIZE; + agent->used = 0; + + agent->fpw = fdopen(sock, "w"); + + Mulder = anext; + *FBI = agent; + } + } + + /* ------------------------------------------------- */ + /* tail of main loop */ + /* ------------------------------------------------- */ + } + + logit("EXIT", "shutdown"); + fclose(flog); + + exit(0); +} diff --git a/daemon/bmtad.c b/daemon/bmtad.c new file mode 100644 index 0000000..f51affe --- /dev/null +++ b/daemon/bmtad.c @@ -0,0 +1,4004 @@ +/*-------------------------------------------------------*/ +/* util/bmtad.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : Mail Transport Agent for BBS */ +/* create : 96/11/20 */ +/* update : 96/12/15 */ +/*-------------------------------------------------------*/ +/* syntax : bmtad */ +/*-------------------------------------------------------*/ +/* notice : brdshm (board shared memory) synchronize */ +/*-------------------------------------------------------*/ + + +#define FORGE_CHECK +#undef SMTP_CONN_CHECK +#define HELO_CHECK + +#define ANTI_HTMLMAIL /* itoc.021014: ¾× html_mail */ +#define ANTI_NOTMYCHARSETMAIL /* itoc.030513: ¾× not-mycharset mail */ + + +#include "bbs.h" + + +/* Thor.990221: ¾¨¶q fflush ¥X log */ +#undef DEBUG + +#define ADM_ALIASES {"root", "mailer-daemon", NULL} + + +#include <sys/wait.h> +#include <netinet/tcp.h> +#include <sys/resource.h> + + +#define SERVER_USAGE +#define WATCH_DOG + + +#define BMTA_PIDFILE "run/bmta.pid" +/* #define BMTA_LOGFILE "run/bmta.log" */ /* ·h¥h global.h */ +#define BMTA_DEBUGFILE "run/bmta.debug" + + +#define BMTA_PERIOD (60 * 15) /* ¨C 15 ¤ÀÄÁ check ¤@¦¸ */ +#define BMTA_TIMEOUT (60 * 30) /* ¶W¹L 30 ¤ÀÄÁªº³s½u´Nµø¬°¿ù»~ */ +#define BMTA_FRESH 86400 /* ¨C 1 ¤Ñ¾ã²z¤@¦¸ */ +#define BMTA_FAULT 100 + + +#define TCP_BACKLOG 3 +#define TCP_BUFSIZ 4096 +#define TCP_LINSIZ 256 +#define TCP_RCVSIZ 2048 + + +#define MIN_DATA_SIZE 8000 +#define MAX_DATA_SIZE 262143 /* ¨C¤@«Ê«Hªº¤j¤p¨î(byte) */ +#define MAX_CMD_LEN 1024 +#define MAX_RCPT 7 /* ¦P¤@«H¦³¶W¹L 7 Ó¦¬«HªÌ´N¾×±¼ */ +#define MAX_HOST_CONN 2 + + +#define SPAM_MHOST_LIMIT 1000 /* ¦P¤@Ó @host ±H¶i¨Ó¶W¹L 1000 «Ê«H¡A´N±N¦¹ @host µø¬°¼s§i°Ó */ +#define SPAM_MFROM_LIMIT 100 /* ¦P¤@Ó from ±H¶i¨Ó¶W¹L 100 «Ê«H¡A´N±N¦¹ from µø¬°¼s§i°Ó */ + +#define SPAM_TITLE_LIMIT 50 /* ¦P¤@Ó¼ÐÃD±H¶i¨Ó¶W¹L 50 ¦¸´N¯S§O°O¿ý */ +#define SPAM_FORGE_LIMIT 10 /* ¦P¤@Ó @domain ¿ù 10 ¦¸¥H¤W¡A´N»{©w¤£¬Oµ§»~¡A¦Ó¬O¬G·Nªº */ + + +/* Thor.000425: POSIX ¥Î O_NONBLOCK */ + +#ifndef O_NONBLOCK +#define M_NONBLOCK FNDELAY +#else +#define M_NONBLOCK O_NONBLOCK +#endif + +/* ----------------------------------------------------- */ +/* SMTP commands */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + void (*func) (); + char *cmd; + char *help; +} Command; + + +/* ----------------------------------------------------- */ +/* client connection structure */ +/* ----------------------------------------------------- */ + + +typedef struct RCPT +{ + struct RCPT *rnext; + char userid[0]; +} RCPT; + + +typedef struct Agent +{ + struct Agent *anext; + int sock; + int sno; + int state; + int mode; + int letter; /* 1:±Hµ¹ *.bbs@ 0:±Hµ¹ *.brd@ */ + u_long ip_addr; + + time_t uptime; + time_t tbegin; + + int xsize; + int xrcpt; + int xdata; + int xerro; + int xspam; + + char ident[80]; + char memo[80]; + char fpath[80]; + + char from[80]; + char title[80]; + + char addr[80]; + char nick[256]; /* Thor.000131: ¦³ªº¤HµoºÆµ¹¤Óªø */ + + int nrcpt; /* number of rcpt */ + RCPT *rcpt; + + char *data; + int used; + int size; +} Agent; + + +static int servo_sno; + + +/* ----------------------------------------------------- */ +/* connection state */ +/* ----------------------------------------------------- */ + + +#define CS_FREE 0x00 +#define CS_RECV 0x01 +#define CS_REPLY 0x02 +#define CS_SEND 0x03 +#define CS_FLUSH 0x04 /* flush data and quit */ + + +/* ----------------------------------------------------- */ +/* AM : Agent Mode */ +/* ----------------------------------------------------- */ + + +#define AM_VALID 0x001 /* ¦¬¥ó¤H¬O bbsreg@MYHOSTNAME */ +#define AM_BBSADM 0x002 /* ¦¬¥ó¤H¬O ADM_ALIASES@MYHOSTNAME */ + +#define AM_DROP 0x010 /* swallow command */ +#define AM_SWALLOW 0x020 /* swallow data */ +#define AM_DATA 0x040 /* data mode */ + +#define AM_SPAM 0x100 + +#define AM_HELO 0x200 /* HELOed */ + +#ifdef DEBUG +#define AM_DEBUG 0x400 /* for tracing malicious connection */ +#endif + +/* ----------------------------------------------------- */ +/* operation log and debug information */ +/* ----------------------------------------------------- */ +/* @START | ... | time */ +/* @CONN | [sno] ident | time */ +/* ----------------------------------------------------- */ + + +static FILE *flog; +static int gline; +static char gtext[100]; + + +#ifdef WATCH_DOG +#define MYDOG gline = __LINE__ +#else +#define MYDOG /* NOOP */ +#endif + + +extern int errno; +extern char *crypt(); + + +static void +log_fresh() +{ + int count; + char fsrc[64], fdst[64]; + char *fpath = BMTA_LOGFILE; + + if (flog) + fclose(flog); + + count = 9; + do + { + sprintf(fdst, "%s.%d", fpath, count); + sprintf(fsrc, "%s.%d", fpath, --count); + rename(fsrc, fdst); + } while (count); + + rename(fpath, fsrc); + flog = fopen(fpath, "a"); +} + + +static void +logit(key, msg) + char *key; + char *msg; +{ + time_t now; + struct tm *p; + + time(&now); + p = localtime(&now); + /* Thor.990329: y2k */ + fprintf(flog, "%s\t%s\t%02d/%02d/%02d %02d:%02d:%02d\n", + key, msg, p->tm_year % 100, p->tm_mon + 1, p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec); + +#ifdef DEBUG + fflush(flog); +#endif +} + + +static void +log_open() +{ + FILE *fp; + + umask(077); + + if (fp = fopen(BMTA_PIDFILE, "w")) + { + fprintf(fp, "%d\n", getpid()); + fclose(fp); + } + + flog = fopen(BMTA_LOGFILE, "a"); + logit("START", "MTA daemon"); +} + + +static inline void +agent_log(ap, key, msg) + Agent *ap; + char *key; + char *msg; +{ + fprintf(flog, "%s\t[%d] %s\n", key, ap->sno, msg); + +#ifdef DEBUG + fflush(flog); +#endif +} + + +static void +agent_reply(ap, msg) + Agent *ap; + char *msg; +{ + int cc; + char *base, *head; + + head = base = ap->data; + while (cc = *msg++) + { + *head++ = cc; + } + *head++ = '\r'; + *head++ = '\n'; + ap->used = head - base; + ap->state = CS_SEND; +} + + +/* ----------------------------------------------------- */ +/* server side routines */ +/* ----------------------------------------------------- */ + + +#ifdef EMAIL_JUSTIFY +static int +is_badid(userid) + char *userid; +{ + int ch; + char *str; + + if (strlen(userid) < 2) + return 1; + + if (!is_alpha(*userid)) + return 1; + + str = userid; + while (ch = *(++str)) + { + if (!is_alnum(ch)) + return 1; + } + return 0; +} + + +static int +acct_fetch(userid, acct) + char *userid; + ACCT *acct; +{ + int fd; + char fpath[64]; + + if (is_badid(userid)) + return -1; + + usr_fpath(fpath, userid, FN_ACCT); + fd = open(fpath, O_RDWR, 0600); + if (fd >= 0) + { + if (read(fd, acct, sizeof(ACCT)) != sizeof(ACCT)) + { + close(fd); + fd = -1; + } + } + return fd; +} +#endif + + +/* ----------------------------------------------------- */ +/* board¡Gshm ³¡¥÷¶·»P cache.c ¬Û®e */ +/* ----------------------------------------------------- */ + + +static BCACHE *bshm; + + +static void +init_bshm() +{ + /* itoc.030727: ¦b¶}±Ò bbsd ¤§«e¡AÀ³¸Ó´Nn°õ¦æ¹L account¡A + ©Ò¥H bshm À³¸Ó¤w³]©w¦n */ + + bshm = shm_new(BRDSHM_KEY, sizeof(BCACHE)); + + if (bshm->uptime <= 0) /* bshm ¥¼³]©w§¹¦¨ */ + exit(0); +} + + +static BRD * +brd_get(bname) + char *bname; +{ + BRD *bhdr, *tail; + + bhdr = bshm->bcache; + tail = bhdr + bshm->number; + do + { + if (!str_cmp(bname, bhdr->brdname)) + return bhdr; + } while (++bhdr < tail); + return NULL; +} + + +static int /* 1: §ä¨ì¤F³oÓªO¡A¥BªO¦W¦b brdname */ +getbrdname(brdname) + char *brdname; +{ + BRD *brd; + + if (brd = brd_get(brdname)) + { + strcpy(brdname, brd->brdname); /* ´«¦¨¥¿½Tªº¤j¤p¼g */ + return 1; + } + return 0; +} + + +static void +update_btime(brdname) + char *brdname; +{ + BRD *brd; + + if (brd = brd_get(brdname)) + brd->btime = -1; +} + + +/* ----------------------------------------------------- */ +/* user¡Gshm ³¡¥÷¶·»P cache.c ¬Û®e */ +/* ----------------------------------------------------- */ + + +static UCACHE *ushm; + + +static inline void +init_ushm() +{ + ushm = shm_new(UTMPSHM_KEY, sizeof(UCACHE)); +} + + +static inline void +bbs_biff(userno) + int userno; +{ + UTMP *utmp, *uceil; + usint offset; + + offset = ushm->offset; + if (offset > (MAXACTIVE - 1) * sizeof(UTMP)) /* Thor.980805: ¤£µMcall¤£¨ì */ + offset = (MAXACTIVE - 1) * sizeof(UTMP); + + utmp = ushm->uslot; + uceil = (void *) utmp + offset; + + do + { + if (utmp->userno == userno) + utmp->status |= STATUS_BIFF; + } while (++utmp <= uceil); +} + + +/* ----------------------------------------------------- */ +/* Hash Table */ +/* ----------------------------------------------------- */ + + +#define HASH_TABLE_SIZE 256 +#define HASH_TABLE_SEED 101 + + +typedef struct HashEntry +{ + struct HashEntry *next; + usint hv; /* hashing value */ + time_t uptime; + int visit; /* reference counts */ + int score; + int fsize; /* file size (¥u¦³¦b title_ht ¤~¦³¥Î) */ + struct HashEntry *ttl; /* title (¥u¦³¦b mfrom_ht ¤~¦³¥Î) */ + char key[0]; +} HashEntry; + + +typedef struct +{ + int mask; + int keylen; /* 0 : string */ + int tale; + int leak; + int (*comp) (const void *k1, const void *k2, int len); + int (*hash) (const void *key, int len); + HashEntry *bucket[0]; +} HashTable; + + +static int +he_hash(key, len) + const unsigned char *key; + int len; /* 0 : string */ +{ + usint seed, shft; + + seed = HASH_TABLE_SEED; + shft = 0; + + if (len > 0) + { + while (len-- > 0) + { + seed += (*key++) << shft; + shft = (shft + 1) & 7; + } + } + else + { + while (len = *key) + { + key++; + seed += len << shft; + shft = (shft + 1) & 7; + } + } + + return seed; +} + + +static HashTable * +ht_new(size, keylen) + int size; /* 2's power */ + int keylen; /* 0 : key is string */ +{ + HashTable *ht; + int he_len; + + if (size <= 0) + size = HASH_TABLE_SIZE; + + he_len = size * sizeof(HashEntry *); + if (ht = (HashTable *) malloc(sizeof(HashTable) + he_len)) + { + ht->mask = size - 1; + ht->keylen = keylen; + ht->tale = 0; + ht->leak = 0; + if (keylen) + { + ht->hash = he_hash; + ht->comp = (void *) memcmp; + + } + else + { + ht->hash = (void *) hash32; + ht->comp = (void *) str_cmp; + } + + memset(ht->bucket, 0, he_len); + } + return ht; +} + + +#if 0 +static void +ht_free(ht) + HashTable *ht; +{ + int i, len; + HashEntry *node, *next; + + len = ht->keylen; + for (i = ht->mask; i >= 0; i--) + { + node = ht->bucket[i]; + while (node) + { + next = node->next; + if (len > 0) + free(node->ttl); + free(node); + node = next; + } + } + + free(ht); +} + + +static void +ht_apply(ht, func) + HashTable *ht; + int (*func) (const HashEntry * he); +{ + int i, len; + HashEntry *he, **hp; + + len = ht->len; + for (i = ht->mask; i >= 0; i--) + { + hp = &(ht->bucket[i]); + while (he = *hp) + { + if (func(he) < 0) /* unlink this entry */ + { + *hp = he->next; + if (len > 0) + free(he->ttl); + free(he); + ht->tale--; + } + else + { + hp = &(he->next); + } + } + } +} + + +static HashEntry * +ht_look(ht, key) + HashTable *ht; + const void *key; +{ + int len; + usint hv; + HashEntry *he; + int (*comp) (); + + len = ht->keylen; + comp = ht->comp; + hv = ht->hash(key, len); + he = ht->bucket[hv & (ht->mask)]; + while (he) + { + if (hv == he->hv && !comp(key, he->key, len)) + break; + he = he->next; + } + return he; +} +#endif + + +static HashEntry * +ht_add(ht, key) + HashTable *ht; + const void *key; +{ + HashEntry *he, **hp; + int len; + usint hv; + int (*comp) (); + + len = ht->keylen; + comp = ht->comp; + hv = ht->hash(key, len); + hp = &(ht->bucket[hv & (ht->mask)]); + + for (;;) + { + he = *hp; + if (he == NULL) + { + if (len == 0) + len = strlen(key) + 1; + if (he = (HashEntry *) malloc(sizeof(HashEntry) + len)) + { + *hp = he; + he->hv = hv; + he->next = NULL; + he->visit = 0; + he->score = 0; + he->fsize = 0; + he->ttl = NULL; + memcpy(he->key, key, len); + ht->tale++; + ht->leak++; + } + break; + } + + if (hv == he->hv && !comp(key, he->key, len)) + break; + + hp = &(he->next); + } + + he->visit++; + return he; +} + + +static void +ht_expire(ht, expire) + HashTable *ht; + time_t expire; +{ + int i, delta, tale, score; + HashEntry *he, **hp; + + tale = ht->tale; + delta = 2 + (ht->leak >> 4) + (tale >> 6); + ht->leak = 0; + + for (i = ht->mask; i >= 0; i--) + { + hp = &(ht->bucket[i]); + while (he = *hp) + { + if (he->uptime < expire) + { + score = he->score - delta; + if (score <= 0 && he->visit <= 0) /* unlink this entry */ + { + *hp = he->next; + free(he); + tale--; + continue; + } + + if (score < 0) + score = 0; + he->score -= score; + } + + hp = &(he->next); + } + } + + ht->tale = tale; +} + + +/* ----------------------------------------------------- */ +/* Host Hash Table */ +/* ----------------------------------------------------- */ + + +#define HOST_HASH_TABLE_SIZE 256 +#define HOST_HASH_ENTRY_LIFE (30 * 60) +#define HOST_HASH_ENTRY_DELTA 8 + + +typedef union +{ + unsigned long addr; + unsigned char ipv4[4]; +} HostAddr; + + +typedef struct HostHashEntry +{ + unsigned long hostaddr; + struct HostHashEntry *next; + time_t uptime; + int ref; + int hflag; + char hostname[0]; +} HostHashEntry; + + +static HostHashEntry *HostHashTable[HOST_HASH_TABLE_SIZE]; + + +static int +hht_look(addr, host) + HostAddr *addr; + char *host; +{ + int hv; + HostHashEntry *he; + + /* hash value of 140.114.87.5 : 114 ^ 87 ^ 5 */ + + hv = (addr->ipv4[1] ^ addr->ipv4[2] ^ addr->ipv4[3]) & + (HOST_HASH_TABLE_SIZE - 1); + + he = HostHashTable[hv]; + + for (;;) + { + if (!he) + { + int hflag, len; + + hflag = dns_name((char *)addr, host); + len = strlen(host) + 1; + he = (HostHashEntry *) malloc(sizeof(HostHashEntry) + len); + he->hostaddr = addr->addr; + he->next = HostHashTable[hv]; + he->ref = 0; + he->hflag = hflag; + memcpy(he->hostname, host, len); + HostHashTable[hv] = he; + break; + } + + if (he->hostaddr == addr->addr) + { + strcpy(host, he->hostname); + break; + } + + he = he->next; + } + + he->ref++; + time(&he->uptime); + + return he->hflag; +} + + +static void +hht_expire(now) + time_t now; +{ + int i; + HostHashEntry **hp, *he; + + now -= HOST_HASH_ENTRY_LIFE; + + for (i = 0; i < HOST_HASH_TABLE_SIZE; i++) + { + hp = &HostHashTable[i]; + + while (he = *hp) + { + if (he->uptime < now) + { + if (he->ref <= HOST_HASH_ENTRY_DELTA) + { + *hp = he->next; + free(he); + continue; + } + + he->ref -= HOST_HASH_ENTRY_DELTA; + } + + hp = &(he->next); + } + } +} + + +/* ----------------------------------------------------- */ +/* Anti Spam */ +/* ----------------------------------------------------- */ + + +static HashTable *mrcpt_ht; +static HashTable *mhost_ht; +static HashTable *mfrom_ht; +static HashTable *title_ht; + + +#ifdef FORGE_CHECK +static HashTable *forge_ht; + +static int /* 1: host/domain ¬O°²³yªº */ +is_forge(host) + char *host; +{ + HashEntry *he; + int score; + unsigned long addr; + + he = ht_add(forge_ht, host); + if ((score = he->score) == 0) + { + /* he->uptime = addr = dns_addr(host); */ + + /* Thor.990811: check forge by dns mx & a record */ + char mxlist[MAX_MXLIST]; + /* if (dns_aton(domain) != INADDR_NONE) return; */ + dns_mx(host, mxlist); + if (!*mxlist && dns_a(host) == INADDR_NONE) + he->uptime = addr = INADDR_NONE; /* Thor.990811: ¬Otªº, ·|³Q expire */ + else + he->uptime = addr = time(0); /* Thor.990811: ¤Ï¥¿¥un¤£¬OINADDR_NONE´N¥i¥H¤F */ + } + else + addr = he->uptime; + + /* if (addr != INADDR_NONE) */ /* Thor.990811: ¦s¦bªºhost¤~¥[¤À¡A¯dµÛ */ + he->score = ++score; + + if (score == SPAM_FORGE_LIMIT) + { + fprintf(flog, "FORGE_L\t%s\n", host); + he->score = 0; /* Thor.000623: release this hashing entry for expire aging */ + } + + return (addr == INADDR_NONE); +} + +#else + +static int /* 1: host/domain ¬O°²³yªº */ +is_forge(host) + char *host; +{ + int cc; + char *str; + + str = NULL; + + while (cc = *host) + { + host++; + if (cc == '.') + str = host; + } + + return ((str == NULL) || (host - str <= 1)); +} +#endif /* FORGE_CHECK */ + + +static void +spam_add(he) + HashEntry *he; +{ + FILE *fp; + + if (fp = fopen(UNMAIL_ACLFILE, "a")) + { + struct tm *p; + + p = localtime(&he->uptime); + str_lower(he->key, he->key); + /* Thor.990329: y2k */ + fprintf(fp, "%s # %d %02d/%02d/%02d %02d:%02d:%02d\n", + he->key, he->score, + p->tm_year % 100, p->tm_mon + 1, p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec); + fclose(fp); + } + + he->score = 0; /* release this hashing entry */ +} + + +/* ----------------------------------------------------- */ +/* statistics of visitor */ +/* ----------------------------------------------------- */ + + +#include "splay.h" + + +static int +vx_cmp(x, y) + HashEntry *x; + HashEntry *y; +{ + int dif; + + dif = y->visit - x->visit; + if (dif) + return dif; + return str_cmp(x->key, y->key); +} + + +static void +vx_out(fp, top) + FILE *fp; + SplayNode *top; +{ + HashEntry *he; + + if (top == NULL) + return; + + vx_out(fp, top->left); + + he = (HashEntry *) top->data; + + fprintf(fp, "%6d %s\n", he->visit, he->key); + + vx_out(fp, top->right); +} + + +static void +splay_free(top) + SplayNode *top; +{ + SplayNode *node; + + if (top == NULL) + return; + + if (node = top->left) + splay_free(node); + + if (node = top->right) + splay_free(node); + + MYDOG; + free(top); + MYDOG; +} + + +static void +vx_log(fp, tag, ht) + FILE *fp; + char *tag; + HashTable *ht; +{ + int i, nentry, nvisit; + SplayNode *top; + HashEntry *he; + + fprintf(fp, "[%s]\n\n", tag); + + top = NULL; + nentry = 0; + nvisit = 0; + + /* splay sort */ + + for (i = ht->mask; i >= 0; i--) + { + for (he = ht->bucket[i]; he; he = he->next) + { + nentry++; + nvisit += he->visit; + top = splay_in(top, he, vx_cmp); + } + } + + /* report */ + + fprintf(fp, "%d entry, %d visit:\n\n", nentry, nvisit); + vx_out(fp, top); + + /* free memory */ + + splay_free(top); + + for (i = ht->mask; i >= 0; i--) + { + for (he = ht->bucket[i]; he; he = he->next) + { + he->visit = 0; + } + } +} + + +static void +visit_fresh() +{ + char folder[64], fpath[64]; + FILE *fp; + HDR hdr; + + brd_fpath(folder, BN_JUNK, FN_DIR); + + if (!(fp = fdopen(hdr_stamp(folder, 'A', &hdr, fpath), "w"))) + return; + + vx_log(fp, "Host", mhost_ht); + vx_log(fp, "From", mfrom_ht); + vx_log(fp, "Rcpt", mrcpt_ht); + vx_log(fp, "¼ÐÃD", title_ht); + fclose(fp); + + hdr.xmode = POST_MARKED; + strcpy(hdr.owner, "<BMTA>"); + strcpy(hdr.title, "²Îp¸ê®Æ"); + rec_bot(folder, &hdr, sizeof(HDR)); + + update_btime(BN_JUNK); +} + + +/* ----------------------------------------------------- */ +/* memo of mail header / body */ +/* ----------------------------------------------------- */ + + +static void +mta_memo(ap, mark) + Agent *ap; + int mark; +{ + /* char folder[64], fpath[64], nick[80], *memo; */ + char folder[64], fpath[64], nick[256], *memo; /* Thor.000131: ¥H¨¾¸U¤@ */ + FILE *fp; + HDR hdr; + + memo = ap->nick; + if (*memo) + sprintf(nick, " (%s)", memo); + else + nick[0] = '\0'; + + memo = ap->memo; + if (!*memo) + { + memo = ap->fpath; + if (!*memo) + { + memo = ap->title; + } + } + + brd_fpath(folder, BN_JUNK, FN_DIR); + + if (!(fp = fdopen(hdr_stamp(folder, 'A', &hdr, fpath), "w"))) + return; + + /* Thor.990915: Åã¥Ü mail from ¥H«K°lÂÜ */ + fprintf(fp, "MAIL FROM: <%s>\nFrom: %s%s\nSubj: %s\nDate: %s\n" + "Host: %s\nMemo: %s\nFile: %s\nSize: %d\n%s", + ap->from, ap->addr, nick, ap->title, Btime(&hdr.chrono), + ap->ident, ap->memo, ap->fpath, ap->used, ap->data); + fclose(fp); + + if (mark) + hdr.xmode = POST_MARKED; + + strcpy(hdr.owner, "<BMTA>"); + strcpy(hdr.title, memo); + rec_bot(folder, &hdr, sizeof(HDR)); + + update_btime(BN_JUNK); +} + + +/* ----------------------------------------------------- */ +/* mailers */ +/* ----------------------------------------------------- */ + + +static int +bbs_mail(ap, data, userid) + Agent *ap; + char *data; + char *userid; +{ + HDR hdr; + int fd, method, sno; + FILE *fp; + char folder[80], buf[256], from[256], *author, *fpath, *title; + struct stat st; + + fp = flog; + sno = ap->sno; + + usr_fpath(folder, userid, FN_DIR); + + /* Thor.990617: get file stat */ + if (!stat(folder, &st) && st.st_size > MAX_BBSMAIL * sizeof(HDR)) + { + fprintf(fp, "MAIL-\t[%d] <%s> over-spammed\n", sno, userid); + return -1; + } + + /* allocate a file for the new mail */ + + fpath = ap->fpath; + method = *fpath ? HDR_LINK : 0; + if ((fd = hdr_stamp(folder, method, &hdr, fpath)) < 0) + { + fprintf(fp, "MAIL-\t[%d] <%s> stamp error\n", sno, userid); + return -2; + } + + author = ap->addr; + title = ap->nick; + sprintf(ap->memo, "%s -> %s", author, userid); + + if (*title) + sprintf(from, "%s (%s)", author, title); + else + strcpy(from, author); + + title = ap->title; + if (!method) + { + if (!*title) + sprintf(title, "¨Ó¦Û %.64s", author); + + sprintf(buf, "§@ªÌ: %.72s\n¼ÐÃD: %.72s\n®É¶¡: %s\n\n", + from, title, Btime(&hdr.chrono)); + + write(fd, buf, strlen(buf)); + write(fd, data, ap->data + ap->used - data); + close(fd); + } + + hdr.xmode = MAIL_INCOME; + str_ncpy(hdr.owner, author, sizeof(hdr.owner)); + str_ncpy(hdr.title, title, sizeof(hdr.title)); + rec_add(folder, &hdr, sizeof(HDR)); + + fprintf(fp, "%d\t%s\t%s\t%s/%s\n", sno, author, title, userid, hdr.xname); + ap->xrcpt++; + ap->xdata += ap->used; + + /* --------------------------------------------------- */ + /* ³qª¾ user ¦³·s«H¥ó */ + /* --------------------------------------------------- */ + + sprintf(folder, "usr/%c/%s/.ACCT", *userid, userid); + fd = open(folder, O_RDONLY); + if (fd >= 0) + { + if ((read(fd, &sno, sizeof(sno)) == sizeof(sno)) && (sno > 0)) + bbs_biff(sno); + close(fd); + } + + mta_memo(ap, 0); + return 0; +} + + +static int +bbs_brd(ap, data, brdname) /* itoc.030323: ±H«Hµ¹¬ÝªO */ + Agent *ap; + char *data; + char *brdname; +{ + HDR hdr; + int fd, method, sno; + FILE *fp; + char folder[80], buf[256], from[256], *author, *fpath, *title; + + fp = flog; + sno = ap->sno; + + brd_fpath(folder, brdname, FN_DIR); + + BRD* brd=brd_get(brdname); + if(brd->battr & BRD_LOCAL){ + return -2; + } + + /* allocate a file for the new post */ + fpath = ap->fpath; + method = *fpath ? HDR_LINK | 'A' : 'A'; + if ((fd = hdr_stamp(folder, method, &hdr, fpath)) < 0) + { + fprintf(fp, "MAIL-\t[%d] <%s> stamp error\n", sno, brdname); + return -2; + } + + author = ap->addr; + title = ap->nick; + + sprintf(ap->memo, "%s -> %s", author, brdname); + + if (*title) + sprintf(from, "%s (%s)", author, title); + else + strcpy(from, author); + + title = ap->title; + if (method == 'A') + { + if (!*title) + sprintf(title, "¨Ó¦Û %.64s", author); + + sprintf(buf, "µo«H¤H: %.50s ¬ÝªO: %s\n¼Ð ÃD: %.72s\nµo«H¯¸: %s\n\n", + from, brdname, title, Btime(&hdr.chrono)); + + write(fd, buf, strlen(buf)); + write(fd, data, ap->data + ap->used - data); + close(fd); + } + + hdr.xmode = POST_INCOME; + str_ncpy(hdr.owner, author, sizeof(hdr.owner)); + str_ncpy(hdr.title, title, sizeof(hdr.title)); + rec_bot(folder, &hdr, sizeof(HDR)); + + update_btime(brdname); + + fprintf(fp, "%d\t%s\t%s\t%s/%s\n", sno, author, title, brdname, hdr.xname); + ap->xrcpt++; + ap->xdata += ap->used; + + mta_memo(ap, 0); + return 0; +} + + +#ifdef EMAIL_JUSTIFY +static int +bbs_valid(ap) + Agent *ap; +{ + int fd, sno; + FILE *fp; + char pool[256], folder[64], justify[128], *str, *ptr, *userid; + ACCT acct; + HDR hdr; + + fp = flog; + sno = ap->sno; + ptr = ap->title; + + /* itoc.µù¸Ñ: mail.c: TAG_VALID " userid(regkey) [VALID]" */ + if (!(str = strstr(ptr, TAG_VALID))) + { + sprintf(ap->memo, "REG : %.64s", ptr); + fprintf(fp, "REG-\t[%d] %s\n", sno, ptr); + return -2; + } + + userid = pool; + strcpy(userid, str + sizeof(TAG_VALID)); + if (!(str = strchr(userid, '('))) + return -1; + + *str = '\0'; + + if (!(ptr = (char *) strchr(str + 1, ')')) || !strstr(ptr, "[VALID]")) + { + sprintf(ap->memo, "REG - %s (format)", userid); + fprintf(fp, "REG-\t[%d] <%s> format\n", sno, userid); + return -1; + } + + *ptr++ = 0; + + if ((fd = acct_fetch(userid, &acct)) < 0) + { + sprintf(ap->memo, "REG - %s (not exist)", userid); + fprintf(fp, "REG-\t[%d] <%s> not exist\n", sno, userid); + return -1; + } + + if (str_hash(acct.email, acct.tvalid) != chrono32(str)) + { + close(fd); + sprintf(ap->memo, "REG - %s (checksum)", userid); + fprintf(fp, "REG-\t[%d] <%s> check sum: %s\n", sno, acct.userid, str + 1); + return -1; + } + + /* ´£¤ÉÅv */ + acct.userlevel |= PERM_VALID; + time(&acct.tvalid); + lseek(fd, 0, SEEK_SET); + write(fd, &acct, sizeof(ACCT)); + close(fd); + + usr_fpath(folder, userid, FN_DIR); + if (!hdr_stamp(folder, HDR_LINK, &hdr, FN_ETC_JUSTIFIED)) + { + strcpy(hdr.title, MSG_REG_VALID); + strcpy(hdr.owner, STR_SYSOP); + hdr.xmode = MAIL_NOREPLY; + rec_add(folder, &hdr, sizeof(HDR)); + } + + ptr = ap->nick; + if (*ptr) + sprintf(justify, "RPY: %s (%s)", ap->addr, ptr); + else + sprintf(justify, "RPY: %s", ap->addr); + + usr_fpath(folder, userid, FN_JUSTIFY); + if (fp = fopen(folder, "a")) + { + fprintf(fp, "%s\n", justify); + fclose(fp); + } + + /* ¦b usr ¥Ø¿ý¯d¤U§¹¾ã¦^«H°O¿ý */ + usr_fpath(folder, userid, FN_EMAIL); + if (fp = fopen(folder, "w")) + { + fprintf(fp, "ID: %s\nVALID: %s\nHost: %s\nFrom: %s\n%s\n", + userid, justify, ap->ident, ap->addr, ap->data); + fclose(fp); + } + + /* Thor.990414: ¥[¦L Timestamp, ¤è«K°l¬d */ + fprintf(fp, "REG\t[%d] <%s> %s %s\n", sno, acct.userid, justify, str + 1); + sprintf(ap->memo, "REG + %s", userid); + ap->xrcpt++; + + return 0; +} +#endif + + +/* ----------------------------------------------------- */ +/* Access Control List routines */ +/* ----------------------------------------------------- */ + +/* ----------------------------------------------------- */ +/* ACL config file format */ +/* ----------------------------------------------------- */ +/* user: majordomo@ bad@cs.nthu.edu.tw */ +/* host: cs.nthu.edu.tw 140.114.77.1 */ +/* subnet: .nthu.edu.tw 140.114.77. */ +/* ----------------------------------------------------- */ + + + +typedef struct ACL_t +{ + struct ACL_t *nacl; /* next acl */ + int locus; + unsigned char filter[0]; +} ACL_t; + + +static int +str_cpy(dst, src, n) + unsigned char *dst; + unsigned char *src; + int n; +{ + int cc, len; + + len = 0; + for (;;) + { + cc = *src; + if (cc >= 'A' && cc <= 'Z') + cc |= 0x20; + *dst = cc; + if ((len > n) || (!cc)) /* lkchu.990511: Á×§K overflow */ + break; + src++; + dst++; + len++; + } + return len; +} + + +static ACL_t * +acl_add(root, filter) + ACL_t *root; + unsigned char *filter; +{ + int at, cc, len; + char *str; + ACL_t *ax; + + str = filter; + at = len = 0; + for (;;) + { + cc = *str; + if (cc == '\n' || cc == ' ' || cc == '#' || cc == '\t' || cc == '\r') + { + *str = '\0'; + break; + } + if (!cc) + break; + + str++; + len++; + if (cc == '@') + at = -len; + } + + if (len <= 0) + return root; + + ax = (ACL_t *) malloc(sizeof(ACL_t) + len + 1); + + ax->nacl = root; + ax->locus = at ? at : len; + + str = ax->filter; + do + { + cc = *filter++; + if (cc >= 'A' && cc <= 'Z') + cc |= 0x20; + } while (*str++ = cc); + + return ax; +} + + +static ACL_t * +acl_load(fpath, root) + char *fpath; + ACL_t *root; +{ + FILE *fp; + char buf[256]; + ACL_t *ax, *nacl; + + /* ¥ý²MªÅ */ + if (ax = root) + { + do + { + nacl = ax->nacl; + free(ax); + } while (ax = nacl); + + ax = NULL; + } + + if (fp = fopen(fpath, "r")) + { + fpath = buf; + while (fgets(fpath, sizeof(buf), fp)) + { + if (!*fpath) + break; + + if (*fpath == '#') + continue; + + ax = acl_add(ax, fpath); + } + fclose(fp); + } + + return ax; +} + + +static int +acl_match(root, ruser, rhost) + ACL_t *root; + unsigned char *ruser; + unsigned char *rhost; +{ + ACL_t *ax; + unsigned char *filter, xuser[80], xhost[128]; + int lhost, luser, locus, len; + + if (!(ax = root)) + return 0; + + /* lkchu.990511: rhost ©M ruser ³£¨S¦³¥ýÀˬdªø«×´N copy, + «Ü¥i¯àµo¥Í segmentation fault */ + luser = str_cpy(xuser, ruser, sizeof(xuser)); + lhost = str_cpy(xhost, rhost, sizeof(xhost)); + ruser = xuser; + rhost = xhost; + + do + { + filter = ax->filter; + locus = ax->locus; + + /* match remote user name */ + + if (locus < 0) + { + len = -1 - locus; + if ((len != luser) || memcmp(ruser, filter, luser)) + continue; + + filter -= locus; + if (*filter == '\0') /* majordomo@ */ + return 1; + locus = strlen(filter); + } + + /* match remote host name */ + +#if 0 + if (locus == lhost) + { + if (!strcmp(filter, rhost)) + return 1; + } + else if (locus < lhost) + { + if (*filter == '.') + { + if (!strcmp(filter, rhost + lhost - locus)) + return 1; + } + else if (filter[locus - 1] == '.') + { + if (!memcmp(filter, rhost, locus)) + return 1; + } + } +#endif + + /* subnet ¬Û¦P¤]ºâ match */ + if (locus <= lhost) + { + if (!strcmp(rhost + lhost - locus, filter)) + return 1; + } + } while (ax = ax->nacl); + + return 0; +} + + +static ACL_t *mail_root = NULL; /* MAIL_ACLFILE ªº acl_root */ +static ACL_t *unmail_root = NULL; /* UNMAIL_ACLFILE ªº acl_root */ + + +static int /* 1: spam */ +acl_spam(ruser, rhost) + unsigned char *ruser; + unsigned char *rhost; +{ + /* ¤£¦b¥Õ¦W³æ¤W©Î¦b¶Â¦W³æ¤W */ + return (!acl_match(mail_root, ruser, rhost) || acl_match(unmail_root, ruser, rhost)); +} + + +/* ----------------------------------------------------- */ +/* mail header routines */ +/* ----------------------------------------------------- */ + +/* ----------------------------------------------------- */ +/* From xyz Wed Dec 24 17:05:37 1997 */ +/* From: xyz (nick) */ +/* From user@domain Wed Dec 24 18:00:26 1997 */ +/* From: user@domain (nick) */ +/* ----------------------------------------------------- */ + + +static char * +mta_from(ap, str) + Agent *ap; + unsigned char *str; /* Thor.990629: ¤¤¤å? */ +{ + int cc; + char pool[512], *head, *tail; + + head = pool; + tail = head + sizeof(pool) - 1; + + for (;;) + { + /* skip leading space */ + while (*str == ' ' || *str == '\t') + str++; + + /* copy the <From> to buffer pool */ + + for (;;) + { + cc = *str; + + if (cc == '\0') + { + *head = '\0'; + sprintf(head, "%s %s", pool, ap->addr); + agent_log(ap, "From:", head); + return str; + } + + str++; + if (cc == '\n') + break; + + *head++ = cc; + + if (head >= tail) + return str; + } + + /* if (*str != ' ') */ + if (*str > ' ' || *str == '\n') /* Thor.990617: for merge multiline */ + break; + + /* go on to merge multi-line <From> */ + } + + *head = '\0'; + + str_from(pool, head = ap->addr, ap->nick); + + /* Thor.000909: ¨S¦³head (from)ªº´N¦Û¤v¸É¤W¤F */ + if (!*head) + strcpy(head, ap->from); + + if (str_cmp(head, ap->from)) + { /* Thor.000911.µù¸Ñ: ¦pªG¤£¤@¼Ëªº¸Ü, ncheck; ¤@¼Ëªº¤§«echeck¹L¤F */ + if (tail = strchr(head, '@')) /* Thor.000911.µù¸Ñ: ¥¿±`ªºaddrªº¸Ü */ + { + *tail++ = '\0'; + + if (is_forge(tail)) /* Thor.990811: °²³yªº, ·Q³£§O·Q */ + return NULL; + + /* Àˬd From: ¬O§_¦b¶Â¥Õ¦W³æ¤W */ + if (!(ap->mode & (AM_VALID | AM_BBSADM)) && acl_spam(head, tail)) + { + tail[-1] = '@'; + agent_log(ap, "SPAM-M", head); + return NULL; + } + + tail[-1] = '@'; + } + else /* Thor.000911: ¤£¦¬¤£¥¿±`ªº addr */ + { + return NULL; + } + } + + return str; +} + + +static char * +mta_subject(ap, str) + Agent *ap; + unsigned char *str; +{ + int cc; + char pool[640], *head, *tail; /* *line */ + + head = pool; + tail = head + sizeof(pool) - 128; + + /* Thor.980831: modified for multi-line header */ + + /* skip leading space */ + + /* while (*str == ' ') str++; */ + while (*str == ' ' || *str == '\t') + str++; + + /* copy the <Subject> to buffer pool */ + + for (;;) + { + cc = *str; + + if (cc == '\0') + { + sprintf(head, "%s %s", ap->from, ap->addr); + agent_log(ap, "Subj:", pool /* head */ ); /* Thor.980904:·Q¬Ýsubj¥þ»ª */ + return str; + } + + str++; + /* Thor.980906: |no body |header |body seperator */ + if (cc == '\n') + { + if (!*str || *str > ' ' || *str == '\n') + break; + /* Thor.991014: skip next line leading space */ + while (*str == ' ' || *str == '\t') + str++; + continue; + } + + *head++ = cc; + + if (head >= tail) /* line too long */ + { + agent_log(ap, "Subj:", pool); /* Xshadow.980906: really line too long? */ + return str; + } + } + + *head = 0; + + str_decode(pool); + str_ansi(ap->title, pool, sizeof(ap->title)); + return str; +} + + +static inline int +is_host_alias(addr) + char *addr; +{ + int i; + char *str; + static char *alias[] = HOST_ALIASES; + + /* check the aliases */ + + for (i = 0; str = alias[i]; i++) + { + if (!str_cmp(addr, str)) + return 1; + } + return 0; +} + + +/* Thor.980901: mail decode, only for ONE part, not for "This is a multi-part message in MIME format." */ + +static char * +mta_decode(ap, str, code) + Agent *ap; + unsigned char *str; + char *code; +{ + str = mm_getencode(str, code); + + /* skip whole line */ + while (*str && *str++ != '\n') + ; + + return str; +} + + +static char * +mta_boundary(ap, str, boundary) + Agent *ap; + unsigned char *str; + char *boundary; +{ + int cc; + char *base = boundary; + + *boundary = 0; + /* skip leading space */ + while (*str == ' ') + str++; + + if (!str_ncmp(str, "multipart", 9)) + { + char *tmp; + + if (tmp = str_str(str, "boundary=")) + { + /* Thor.990221: ©~µM¦³ªº¤H¤£¥Î " */ + tmp += 9; + if (*tmp == '"') + tmp++; + + while (*tmp && *tmp != '"' && *tmp != '\n') + *boundary++ = *tmp++; + /* *boundary++ = '\n'; */ /* Thor.980907: ¤§«á·|³QµL·N¶¡¸õ¹L */ + *boundary = 0; + } + logit("MULTI", base); + } + + while (cc = *str) + { + str++; + if (cc == '\n' && (!*str || *str > ' ' || *str == '\n')) + break; + } + + return str; +} + + +/* Thor.980907: support multipart mime */ +/* ----------------------------------------------------- */ +/* multipart decoder */ +/* ----------------------------------------------------- */ + + +static int +multipart(src, dst, boundary) + unsigned char *src; + unsigned char *dst; /* Thor: no ending 0 */ + unsigned char *boundary; /* Thor: should include "--" */ +{ + unsigned char *base = dst; + char *bound; + unsigned char *tmp; + char decode; + char buf[512] = "--"; /* Thor: sub mime boundary */ + int cc; + int boundlen; + + boundlen = strlen(boundary); + if (boundlen < 6) + return 0; /* Thor: boundary too small, "\n> <\n" */ + + while (*src) + { + bound = strstr(src, boundary); + + if (bound) + *bound = 0; + + if (buf[2]) /* Thor: multipart & encoded can't be happened simutaneously */ + { + cc = multipart(src, dst, buf); + if (cc > 0) + dst += cc; + else + goto bypass; + } + else + { + bypass: + while (*src) + *dst++ = *src++; + } + + /* reset */ + buf[2] = 0; + decode = 0; + + if (!bound) + break; + + src = bound + boundlen; /* Thor: src over boundary */ + + tmp = dst + boundlen - 3 /* " <\n" */ ; + + *dst++ = '\n'; + *dst++ = '>'; + *dst++ = ' '; + + while (dst < tmp) + *dst++ = '-'; + + *dst++ = ' '; + *dst++ = '<'; + *dst++ = '\n'; + + for (;;) /* Thor: processing sub-header */ + { + if (!str_ncmp(src, "Content-Transfer-Encoding:", 26)) + { /* Thor.980901: ¸Ñ rfc1522 body code */ + src = mta_decode(NULL, src + 26, &decode); + } + else if (!str_ncmp(src, "Content-Type:", 13)) + { + src = mta_boundary(NULL, src + 13, buf + 2); + } + else + { + while (cc = *src) + /* Thor.980907: è¦n¸õ¤Fboundary«áªº \n,¤£¬O¬G·Nªº :p */ + { + src++; + if (cc == '\n') + break; + } + } + if (!*src || *src == '\n') + break; /* null body or end of mail header */ + } + + } + return dst - base; +} + + +/* ----------------------------------------------------- */ +/* mailer */ +/* ----------------------------------------------------- */ + + +static int +mta_mailer(ap) + Agent *ap; +{ + char *data, *str, *addr, *delimiter, decode = 0; + char boundary[512] = "--"; + int cc, mode; + RCPT *rcpt; + + mode = ap->mode; + data = ap->data + 1; /* skip leading stuff */ + + /* --------------------------------------------------- */ + /* parse the mail header and filter spam mails */ + /* --------------------------------------------------- */ + + for (;;) + { + if (!str_ncmp(data, "From:", 5)) + { + data += 5; + data = mta_from(ap, data); + if (!data) + { + agent_reply(ap, "550 you are not in my access list"); + return -1; + } + } + else if (!str_ncmp(data, "Subject:", 8)) + { + data = mta_subject(ap, data + 8); + } + else if (!str_ncmp(data, "Content-Transfer-Encoding:", 26)) + { /* Thor.980901: ¸Ñ rfc1522 body code */ + data = mta_decode(ap, data + 26, &decode); + } + else if (!str_ncmp(data, "Content-Type:", 13)) + { /* Thor.980907: ¸Ñ multi-part */ +#ifdef ANTI_HTMLMAIL + /* ¤@¯ë BBS ¨Ï¥ÎªÌ³q±`¥u±H¤å¦r¶l¥ó©Î¬O±q¨ä¥L BBS ¯¸±H¤å³¹¨ì¦Û¤vªº«H½c + ¦Ó¼s§i«H¥ó³q±`¬O html ®æ¦¡©Î¬O¸Ì±¦³§¨±a¨ä¥LÀÉ®× + §Q¥Î¶l¥óªºÀÉÀY¦³ Content-Type: ªºÄݩʧⰣ¤F text/plain (¤å¦r¶l¥ó) ªº«H¥ó³£¾×¤U¨Ó */ + char *content = data + 14; + if (*content != '\0' && str_ncmp(content, "text/plain", 10)) + { + agent_reply(ap, "550 we only accept plain text"); + return -1; + } +#endif + +#ifdef ANTI_NOTMYCHARSETMAIL + { + char charset[32]; + mm_getcharset(data + 13, charset, sizeof(charset)); + if (str_cmp(charset, MYCHARSET) && str_cmp(charset, "us-ascii")) + { + agent_reply(ap, "550 non-supported charset"); + return -1; + } + } +#endif + + data = mta_boundary(ap, data + 13, boundary + 2); + } + else + { + /* skip this line */ + for (;;) + { + cc = *data; + + if (cc == '\0') /* null body */ + { + data--; + goto mta_mail_body; + /* return 0; */ + } + + data++; + + if (cc == '\n') + break; + } + } + + if (*data == '\n') + break; /* end of mail header */ + } + + /* --------------------------------------------------- */ + /* process the mail body */ + /* --------------------------------------------------- */ + +mta_mail_body: + + if (mode & AM_BBSADM) + { + sprintf(ap->memo, "ADM: %.64s", ap->from); + mta_memo(ap, 1); /* lkchu: mark ADM's letter */ + + return 0; + } + + *data = '\0'; + + /* --------------------------------------------------- */ + /* validate user's character */ + /* --------------------------------------------------- */ + + rcpt = ap->rcpt; + +#ifdef EMAIL_JUSTIFY + if (mode & AM_VALID) + { + /* Thor.000328: µù¸Ñ: rcpt to bbsreg@MYHOSTNAME */ + if (bbs_valid(ap) == -2) + *data = '\n'; + + mta_memo(ap, 0); + + if (rcpt == NULL) + return 0; + } +#endif + + /* --------------------------------------------------- */ + /* check mail body */ + /* --------------------------------------------------- */ + + delimiter = data; + + for (;;) + { + cc = *++data; + if (cc == '\0') /* null mail body */ + { + /* Thor.000327: °O¿ýªÅ«H */ + fprintf(flog, "NULL BODY\t[%d] from:%s nrcpt:%d\n", ap->sno, ap->from, ap->nrcpt); + return 0; + } + + if (cc != '\n') /* skip empty lines in mail body */ + break; + } + + /* --------------------------------------------------- */ + /* decode mail body */ + /* --------------------------------------------------- */ + + /* Thor.980901: decode multipart body */ + if (boundary[2]) + { + /* logit("MULTIDATA",data); */ + cc = multipart(data, data, boundary); + if (cc > 0) + ap->used = (data - ap->data) + cc; /* (data - ap->data) ¬O header ªø«×¡Acc ¬O«H¤º®eªºªø«× */ + } + /* Thor.980901: decode mail body */ + else if (decode) + { + /* data[mmdecode(data,decode,data)]=0; */ + /* Thor.980901: ¦] decode¥²¬° b or q, ¬G mmdecode¤£¬°-1, * + * ¥²©w¦¨¥\, ¤S¦] mmdecode¤£¦Û°Ê¥[ 0, ¬G¤â°Ê¥[¤W */ + + /* Thor.980901: ¤£¥Î 0 §@µ²§ô, ¦Ó¥Îªø«×, pºâ¤è¦¡¦p¤U * + * write(fd, data, ap->data + ap->used - data); * + * ¬G×§ï ap->used, ¥HºI±¼¹Lªø data */ + + cc = mmdecode(data, decode, data); + if (cc > 0) + ap->used = (data - ap->data) + cc; /* (data - ap->data) ¬O header ªø«×¡Acc ¬O«H¤º®eªºªø«× */ + + /* logit("DECODEDATA", data); */ + } + + /* --------------------------------------------------- */ + /* check E-mail address for anti-spam first */ + /* --------------------------------------------------- */ + + addr = ap->addr; + if ((str = strchr(addr, '@')) && str_ncmp(addr, "mailer-daemon@", 14)) + { + HashEntry *he, *hx; + int nrcpt, score, delta; + time_t uptime; + + uptime = ap->uptime; + nrcpt = ap->nrcpt; + + /* -------------------------------------------------- */ + /* Àˬd³oÓ @host ±H¶i¨Óªº«H¦³µL¶W¹L SPAM_MHOST_LIMIT */ + /* -------------------------------------------------- */ + + he = ht_add(mhost_ht, ++str); + he->uptime = uptime; + he->score += (nrcpt > 0) ? nrcpt : 1; /* ¤@Ó¦¬¥ó¤H³£¨S¦³¤]ºâ¤@¦¸³X°Ý */ + + if (he->score >= SPAM_MHOST_LIMIT) + { + unmail_root = acl_add(unmail_root, str); + spam_add(he); + fprintf(flog, "SPAM-H\t[%d] %s\n", ap->sno, str); + + sprintf(ap->memo, "SPAM : %s", str); + *delimiter = '\n'; + } + + /* -------------------------------------------- */ + /* Àˬd³oÓ title ªº«H¦³µL¶W¹L SPAM_TITLE_LIMIT */ + /* -------------------------------------------- */ + + if (nrcpt > 0) + { + hx = ht_add(title_ht, str_ttl(ap->title)); + hx->uptime = uptime; + hx->visit += nrcpt - 1; /* title_ht ªº visit ¬O°O¿ý³o¼ÐÃDªº«H¦³´X¤H¦¬¹L */ + hx->score += nrcpt; + if (hx->score >= SPAM_TITLE_LIMIT) + fprintf(flog, "TITLE\t[%d] %s\n", ap->sno, ap->title); + + /* ¦pªG³o¦¸¨Ó«H©M¤W¦¸¦P¼ÐÃDªº¨Ó«HÀÉ®×®t¤£¦h¤j¡A¨º»ò³o¦¸¨Ó«H«Ü¥i¯à¬O¼s§i«H */ + score = nrcpt; + delta = hx->fsize - ap->used; + if (delta >= -16 && delta <= 16) + score += SPAM_MFROM_LIMIT >> 5; + hx->fsize = ap->used; /* °O¿ý¥Î³o¼ÐÃDªº³Ì«á¤@«Ê«H¤§Àɮפj¤p */ + } + else + { + score = 1; + } + + /* ------------------------------------------------- */ + /* Àˬd³oÓ from ±H¶i¨Óªº«H¦³µL¶W¹L SPAM_MFROM_LIMIT */ + /* ------------------------------------------------- */ + + he = ht_add(mfrom_ht, addr); + he->uptime = uptime; + + if (nrcpt > 0) /* ¦³ title_ht ªº HashEntry hx-> */ + { + /* itoc.060420.µù¸Ñ: ¦³¨Ç¨Ï¥ÎªÌ·|±q§Oªº BBS ¯¸¤@¦¸Âà±H¾ãÓ°Q½×¦êªº¤å³¹(¦P¼ÐÃD) + ¨Ó¥»¯¸¡A´N·|¦]¬°¤U±³o±ø rule ¦Ó³Qµø¬°¼s§i°Ó */ + + /* ¦pªG³oÓ from ¦b³o¦¸¨Ó«H©M¥L¦Û¤v¤W¦¸¨Ó«Hªº¼ÐÃD¬Û¦P¡A¨º»ò³oÓ from «Ü¥i¯à¬O¼s§i°Ó */ + if (he->ttl == hx) + score += SPAM_MFROM_LIMIT >> 4; + else + he->ttl = hx; /* °O¿ý³oÓ from ¦b³o¦¸¨Ó«Hªº¼ÐÃD */ + } + + he->score += score; + + if (he->score >= SPAM_MFROM_LIMIT) + { + unmail_root = acl_add(unmail_root, addr); + spam_add(he); + fprintf(flog, "SPAM-F\t[%d] %s\n", ap->sno, addr); + + sprintf(ap->memo, "SPAM : %s", addr); + *delimiter = '\n'; + } + + /* ------------------------------------------------- */ + + if (*delimiter) /* Y *delimiter == '\n'¡Aªí¥Ü¶W¹L SPAM_*_LIMIT */ + { + MYDOG; + mta_memo(ap, 0); + MYDOG; + return 0; + } + } + + /* --------------------------------------------------- */ + /* mail user */ + /* --------------------------------------------------- */ + + if (rcpt) + { + char *dot; + + addr = ap->addr; + if (dot = strchr(addr, '.')) + { + if (!str_cmp(dot, ".bbs@" MYHOSTNAME)) /* itoc.020125.µù¸Ñ: Y±H«HªÌ¬°¥»¯¸µo«H¡A¥u¯d ID */ + *dot = '\0'; + else + dot = NULL; + } + + do + { + str = rcpt->userid; + if (ap->letter) + bbs_mail(ap, data, str); + else + bbs_brd(ap, data, str); + } while (rcpt = rcpt->rnext); + + if (dot) + *dot = '.'; + } + + return 0; +} + + +/* ----------------------------------------------------- */ +/* command dispatch */ +/* ----------------------------------------------------- */ + + +static void +agent_free_rcpt(ap) + Agent *ap; +{ + RCPT *rcpt, *next; + + ap->nrcpt = 0; + + if (rcpt = ap->rcpt) + { + ap->rcpt = NULL; + do + { + next = rcpt->rnext; + free(rcpt); + } while (rcpt = next); + } +} + + +static void +agent_spam(ap) + Agent *ap; +{ + int cc; + char *from; + FILE *fp; + + from = ap->from; + cc = *from; + if (cc == ' ' || cc == '\0') + return; + + unmail_root = acl_add(unmail_root, from); + + if (fp = fopen(UNMAIL_ACLFILE, "a")) + { + struct tm *p; + + p = localtime(&ap->uptime); + /* Thor.990329: y2k */ + fprintf(fp, "%s # 100 %02d/%02d/%02d %02d:%02d:%02d\n", + from, + p->tm_year % 100, p->tm_mon + 1, p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec); + fclose(fp); + } +} + + +/* ----------------------------------------------------- */ +/* command dispatch */ +/* ----------------------------------------------------- */ + + +static void +cmd_what(ap) + Agent *ap; +{ + ap->xerro++; + agent_reply(ap, "500 Command unrecognized"); +} + + +static void +cmd_help(ap) + Agent *ap; +{ + agent_reply(ap, "214-Commands:\r\n" + "214- HELO MAIL RCPT DATA\r\n" + "214- NOOP QUIT RSET HELP\r\n" + "214-See RFC-821 for more info.\r\n" + "214 End of HELP info"); +} + + +static void +cmd_noop(ap) + Agent *ap; +{ + agent_reply(ap, "250 OK"); +} + + +static void +agent_reset(ap) + Agent *ap; +{ + MYDOG; + +#ifdef HELO_CHECK + ap->mode &= AM_HELO; +#else + ap->mode = 0; +#endif + + ap->memo[0] = '\0'; + ap->fpath[0] = '\0'; + ap->from[0] = '\0'; + ap->title[0] = '\0'; + ap->addr[0] = '\0'; + ap->nick[0] = '\0'; + MYDOG; + agent_free_rcpt(ap); + MYDOG; +} + + +static void +cmd_rset(ap) + Agent *ap; +{ + agent_reset(ap); + agent_reply(ap, "250 Reset state"); +} + + +/* ----------------------------------------------------- */ +/* 0 : OK , -1 : error, -2 : <>, 1 : relayed */ +/* ----------------------------------------------------- */ + + +static int +parse_addr(addr, user, domain) + char *addr, **user, **domain; +{ + int ch, relay; + char *ptr, *str; + + /* <[@domain_list:]user@doamin> */ + + addr = strchr(addr, '<'); + if (!addr) + return -1; + + ptr = strrchr(++addr, '>'); + if (!ptr) + return -1; + + if (ptr == addr) + return -2; /* <> null domain */ + + *ptr = '\0'; + if (ptr = strrchr(addr, ':')) + { + relay = 1; + addr = ptr + 1; + } + else + { + relay = 0; + } + + /* check the E-mail address format */ + + *user = str = addr; + + /* Thor.000607: dequote */ + if (**user == '"') + (*user)++; + + for (ptr = NULL; ch = *addr; addr++) + { + if (ch == '@') + { + if (ptr) + return -1; + + ptr = addr; + continue; + } + + /* Thor.000607: dequote */ + if (ch == '"') + { + *addr = 0; + continue; + } + + if (ch <= 32 || ch >= 127) + return -1; + if (strchr("<>()[]\\,;:", ch)) + return -1; + } + + if (!ptr) + return -1; + + *ptr++ = '\0'; + *domain = ptr; + + if (!*user) /* more ... */ + { + return -1; + } + + return relay; +} + + +static void +cmd_mail(ap) + Agent *ap; +{ + char *data, *from, *user, *domain, *ptr; + int cc; + +#ifdef HELO_CHECK + if (!(ap->mode & AM_HELO)) + { + ap->xerro++; + agent_reply(ap, "503 Polite people say HELO first"); + return; + } +#endif + + from = ap->from; + if (*from) + { + ap->xerro++; + agent_reply(ap, "503 Sender already specified"); + return; + } + + /* mail from:<[@domain_list:]user@doamin> */ + + data = ap->data; + MYDOG; + cc = parse_addr(data, &user, &domain); + MYDOG; + + if (cc) + { + if (cc == -2) /* null domain */ + { + from[0] = ' '; + from[1] = '\0'; + + strcpy(data, "250 Sender ok\r\n"); + ap->used = strlen(data); + ap->state = CS_SEND; + return; + } + + ap->xerro++; + agent_reply(ap, cc < 0 ? "501 Syntax error" : + "551 we dont accept relayed mail"); + return; + } + + /* Thor.990811: §ì°²³yªºdomain */ + MYDOG; + if (is_forge(domain)) + { + ap->xspam++; + ap->mode |= AM_SPAM; + agent_log(ap, "FORGE", domain); + agent_reply(ap, "501 Sender host must exist"); + return; + } + + /* Thor.990817: ¦pªGhost°²³y¡A³s¥[³£¤£·Q¥[¤Jmfrom_ht */ + MYDOG; + ptr = data + MAX_CMD_LEN; + sprintf(ptr, "%s@%s", user, domain); + ht_add(mfrom_ht, ptr); + + MYDOG; + /* Àˬd MAIL FROM: ¬O§_¦b¶Â¥Õ¦W³æ¤W */ + if (acl_spam(user, domain)) + { + ap->xspam++; + ap->mode |= AM_SPAM; + agent_log(ap, "SPAM-M", ptr); + agent_reply(ap, "550 you are not in my access list"); + return; + } + + str_ncpy(from, ptr, sizeof(ap->from)); + sprintf(data, "250 <%s> Sender ok\r\n", ptr); + ap->used = strlen(data); + ap->state = CS_SEND; + MYDOG; +} + + +static int /* AM_VALID:»{ÃÒ«H AM_BBSADM:bbsadm 0:¤@¯ë«H -1:©Ú¦¬ */ +is_rcpt(rcpt, letter) + char *rcpt; + int *letter; /* ¦^¶Ç 1:±Hµ¹ *.bbs@ 0:±Hµ¹ *.brd@ */ +{ + int len; + char *str, fpath[64]; + char *alias[] = ADM_ALIASES; + +#ifdef EMAIL_JUSTIFY + if (!str_cmp(rcpt, "bbsreg")) + return AM_VALID; +#endif + + /* check the aliases */ + + for (len = 0; str = alias[len]; len++) + { + if (!str_cmp(rcpt, str)) + return AM_BBSADM; + } + + /* check the users */ + + len = strlen(rcpt); + if (len > 4) /* ".bbs" ©Î ".brd" => 4 */ + { + str = rcpt + len - 4; + + if (!str_cmp(str, ".bbs")) + { + if (len <= IDLEN + 4) + { + *str = '\0'; + str_lower(rcpt, rcpt); + sprintf(fpath, "usr/%c/%s/@", *rcpt, rcpt); + if (dashd(fpath)) + { + *letter = 1; + return 0; + } + } + } + else if (!str_cmp(str, ".brd")) + { + if (len <= BNLEN + 4) + { + *str = '\0'; + if (getbrdname(rcpt)) + { + *letter = 0; + return 0; + } + } + } + } + + return -1; +} + + +static void +cmd_rcpt(ap) + Agent *ap; +{ + char *data, *user, *domain; + int cc, letter; + RCPT *rcpt; + + if (!ap->from[0]) + { + ap->xerro++; + agent_reply(ap, "503 MAIL first"); + return; + } + + if (ap->nrcpt > MAX_RCPT) + { + /* maybe spammer */ + + /* Thor.000131: ³o¼Ë´N¤£¥Î¤@ª½¥h§Runmail.acl«ÂЪºentry :) */ + if (!(ap->mode & AM_SPAM)) + agent_spam(ap); /* ¦P¤@«H±Hµ¹¤Ó¦h¦¬«HªÌª½±µ¾×±¼ */ + + ap->mode |= AM_SPAM; + ap->xspam += ap->nrcpt; + agent_log(ap, "SPAM-R", "too many recipients"); + agent_reply(ap, "552 Too many recipients"); + return; + } + + /* rcpt to:<[@domain_list:]user@doamin> */ + + data = ap->data; + cc = parse_addr(data, &user, &domain); + if (cc) + { + ap->xerro++; + agent_reply(ap, cc < 0 ? "501 Syntax error" : "551 we dont accept relayed mail"); + + return; + } + + if (domain == NULL) + { + agent_reply(ap, "550 null domain"); + return; + } + + /* if (str_cmp(domain, MYHOSTNAME)) */ + if (!is_host_alias(domain)) /* HOST_ALIAS ¸Ìªº³£¥i¥H */ + { + ap->xerro++; + agent_reply(ap, "550 we dont relay mail"); + return; + } + + ht_add(mrcpt_ht, user); + + cc = is_rcpt(user, &letter); + + if (cc < 0) /* µL¦¹¨Ï¥ÎªÌ©Î¬ÝªO */ + { + ap->xerro++; + agent_reply(ap, "550 no such user or board"); + return; + } + + if (cc) /* AM_VALID¡BAM_BBSADM */ + { + ap->mode |= cc; + } + else /* Thor.991130.µù¸Ñ: ¤@¯ë *.bbs@ ©Î *.brd@ ±¡ªp */ + { +#if 1 /* Thor.981227: ½T©w¤£¬O bbsreg ¤~¾×¡Adelay ¾×³s½u */ + /* format: sprintf(servo_ident, "[%d] %s ip:%08x", ++servo_sno, rhost, csin.sin_addr.s_addr); */ + char rhost[256], *s; + + if (s = strchr(ap->ident, ' ')) + { + strcpy(rhost, s + 1); + if (s = strchr(rhost, ' ')) + { + *s = '\0'; + + /* Àˬd µo«Hªº¾÷¾¹ ¬O§_¦b¶Â¥Õ¦W³æ¤W */ + if (acl_spam("*", rhost)) + { + ap->mode |= AM_SPAM; + agent_log(ap, "SPAM-M", rhost); + agent_reply(ap, "550 deny connection"); + return; + } + } + } +#endif + +#if 1 /* Thor.981223: ½T©w¤£¬O bbsreg ´N¾× */ + if (ap->mode & AM_SPAM) + { + agent_reply(ap, "550 spam mail"); + return; + } +#endif + + ap->letter = letter; + ap->nrcpt++; + cc = strlen(user) + 1; + MYDOG; + rcpt = (RCPT *) malloc(sizeof(RCPT) + cc); + MYDOG; + if (!rcpt) /* Thor.990205: °O¿ýªÅ¶¡¤£°÷ */ + logit("ERROR", "Not enough space in cmd_rcpt()"); + + rcpt->rnext = ap->rcpt; + memcpy(rcpt->userid, user, cc); + ap->rcpt = rcpt; + } + + agent_reply(ap, "250 Recipient ok"); +} + + +static void +cmd_helo(ap) + Agent *ap; +{ + char *data; + +#ifdef SMTP_CONN_CHECK + /* Thor.990806: check if the peer is a normal smtp server, otherwise possibly a dialup spammer */ + + struct sockaddr_in sin; + int sock = sizeof(sin); + + if (getpeername(ap->sock, (struct sockaddr *) & sin, &sock) >= 0) + { + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock >= 0) + { + int t; + + sin.sin_port = htons(BMTA_PORT); + t = connect(sock, (struct sockaddr *) & sin, sizeof sin); + close(sock); + + if (t < 0) + { + data = ap->data; + strcpy(data, "550 reject non-smtp server\r\n"); + ap->used = strlen(data); + ap->state = CS_FLUSH; + return; + } + } + } +#endif + + data = ap->data; + sprintf(data, "250 Hello %s\r\n", ap->ident); + ap->used = strlen(data); + ap->state = CS_SEND; + +#ifdef HELO_CHECK + ap->mode |= AM_HELO; +#endif +} + + +static void +cmd_data(ap) + Agent *ap; +{ + int mode; + + mode = ap->mode; + if (!ap->rcpt && !(mode & (AM_VALID | AM_BBSADM))) + { + ap->xerro++; + agent_reply(ap, "503 RCPT first"); + return; + } + + ap->mode = mode | AM_DATA; + agent_reply(ap, "354 go ahead"); +} + + +static void +cmd_quit(ap) + Agent *ap; +{ + char *data; + + data = ap->data; + strcpy(data, "221 bye\r\n"); + ap->used = strlen(data); + ap->state = CS_FLUSH; +} + + +static void +cmd_nogo(ap) + Agent *ap; +{ + agent_reply(ap, "502 operation not allowed"); + return; +} + + +static Command cmd_table[] = +{ + cmd_helo, "helo", "HELO <hostname> - Introduce yourself", + cmd_nogo, "ehlo", "", /* Thor.980929: ¤£¤ä´©enhanced smtp */ + cmd_mail, "mail", "MAIL FROM: <sender> - Specifies the sender", + cmd_rcpt, "rcpt", "RCPT TO: <recipient> - Specifies the recipient", + cmd_data, "data", "", + cmd_quit, "quit", "QUIT - Exit sendmail (SMTP)", + cmd_noop, "noop", "NOOP - Do nothing", + cmd_rset, "rset", "RSET - Resets the system", + cmd_help, "help", "HELP [ <topic> ] - gives help info", + cmd_nogo, "expn", "", + cmd_nogo, "vrfy", "", + cmd_what, NULL, NULL +}; + + +/* ----------------------------------------------------- */ +/* send output to client */ +/* ----------------------------------------------------- */ +/* return value : */ +/* > 0 : bytes sent */ +/* = 0 : close this agent */ +/* < 0 : there are some error, but keep trying */ +/* ----------------------------------------------------- */ + + +static int +agent_send(ap) + Agent *ap; +{ + int csock, len, cc; + char *data; + + csock = ap->sock; + data = ap->data; + len = ap->used; + cc = send(csock, data, len, 0); + +#ifdef AM_DEBUG + if (ap->mode & AM_DEBUG) + { + char buf[1024]; + + sprintf(buf, "%s\t[%d]\tbmtad>>>\n", Now(), ap->sno); + f_cat(BMTA_DEBUGFILE, buf); + str_ncpy(buf, data, len + 1); + f_cat(BMTA_DEBUGFILE, buf); + sprintf(buf, "\t[%d]\tbmtad<<<\n", ap->sno); + f_cat(BMTA_DEBUGFILE, buf); + } +#endif + + if (cc < 0) + { + cc = errno; + if (cc != EWOULDBLOCK) + { + agent_log(ap, "SEND", strerror(cc)); + return 0; + } + + /* would block, so leave it to do later */ + return -1; + } + + if (cc == 0) + return -1; + + len -= cc; + ap->used = len; + if (len) + { + memcpy(data, data + cc, len); + return cc; + } + + if (ap->state == CS_FLUSH) + { + shutdown(csock, 2); + close(csock); + ap->sock = -1; + return 0; + } + + ap->state = CS_RECV; + return cc; +} + + +/* ----------------------------------------------------- */ +/* receive request from client */ +/* ----------------------------------------------------- */ + + +static int +agent_recv(ap) + Agent *ap; +{ + int cc, mode, size, used; + char *data, *head, *dest; + + mode = ap->mode; + used = ap->used; + data = ap->data; + + if (mode & AM_DATA) + { + if (used <= 0) + { + /* pre-set data */ + + *data = '\n'; + used = 1; + } + else + { + /* check the available space */ + + size = ap->size; + cc = size - used; + + if (cc < TCP_RCVSIZ + 3) + { + if (size < MAX_DATA_SIZE) + { + size += TCP_RCVSIZ + (size >> 2); + + if (data = (char *) realloc(data, size)) + { + ap->data = data; + ap->size = size; + } + else + { + fprintf(flog, "ERROR\t[%d] malloc: %d\n", ap->sno, size); + +#ifdef DEBUG + fflush(flog); +#endif + + return 0; + } + } + else + { + /* DATA ¤Óªø¤F¡A³q³q¦Y¤U¨Ó¡A¨Ã°²³] mail header ¤£·|¶W¹L HEADER_SIZE */ + +#define HEADER_SIZE 8192 + data[HEADER_SIZE - 2] = data[used - 2]; + data[HEADER_SIZE - 1] = data[used - 1]; + used = HEADER_SIZE; +#undef HEADER_SIZE + ap->mode = (mode |= AM_SWALLOW); + ap->xerro++; + fprintf(flog, "ERROR\t[%d] data too long\n", ap->sno); + +#ifdef DEBUG + fflush(flog); +#endif + } + } + } + } + + head = data + used; + MYDOG; + cc = recv(ap->sock, head, TCP_RCVSIZ, 0); + MYDOG; + + if (cc <= 0) + { + cc = errno; + MYDOG; + if (cc != EWOULDBLOCK) + { + agent_log(ap, "RECV", strerror(cc)); + return 0; + } + + /* would block, so leave it to do later */ + + return -1; + } + MYDOG; + + head[cc] = '\0'; + ap->xsize += cc; + +#ifdef AM_DEBUG + if (mode & AM_DEBUG) + { + char buf[80]; + sprintf(buf, "%s\t[%d]\tpeer>>>\n", Now(), ap->sno); + f_cat(BMTA_DEBUGFILE, buf); + f_cat(BMTA_DEBUGFILE, head); + sprintf(buf, "\t[%d]\tpeer<<<\n", ap->sno); + f_cat(BMTA_DEBUGFILE, buf); + } +#endif + + /* --------------------------------------------------- */ + /* DATA mode */ + /* --------------------------------------------------- */ + + if (mode & AM_DATA) + { + dest = head - 1; + + for (;;) + { + cc = *head; + + if (!cc) + { + ap->used = dest - data + 1; + return 1; + } + + head++; + + if (cc == '\r') + continue; + + if (cc == '\n') + { + /* Thor.990604: \n«á°¨¤Wcheck, ¥H¥ß¨è±Æ°£ \r\n.\r\n ªºª¬ªp */ + used = dest - data + 1; + if (used >= 2 && *dest == '.' && dest[-1] == '\n') + break; /* end of mail body */ + + for (;;) + { + used = *dest; + + if (used == ' ' || used == '\t') + { + dest--; /* strip the trailing space */ + continue; + } + break; + } + + /* Thor.990604: strip leading ".." to "." */ + { + char *first = dest; + + while (first >= data && *first != '\n') + first--; + first++; + + if (first <= dest && *first == '.') + { + while (first < dest) + { + *first = first[1]; + first++; + } + dest--; + } + } + } + + *++dest = cc; + } + MYDOG; + +#if 1 /* Thor.990906: null from ´N±µ¦a:p */ + cc = *ap->from; + if (cc == ' ' || cc == '\0') + { + agent_reply(ap, "250 Message dropped"); + agent_log(ap, "SPAM-NULL", ap->ident); + MYDOG; + return -1; + } +#endif + + if (mode & AM_SWALLOW) + { + agent_reset(ap); + agent_reply(ap, "552 Too much mail data"); + MYDOG; + return -1; + } + + /* strip the trailing empty lines */ + + dest -= 2; /* 3; */ + + while (*dest == '\n' && dest > data) + dest--; + dest += 2; + *dest = '\0'; + + ap->used = dest - data; + + MYDOG; + /* Thor.981223: ½T©w¤£¬O bbsreg ¤~¾× */ + if (!(mode & (AM_VALID | AM_BBSADM)) && (mode & AM_SPAM)) + { + sprintf(ap->memo, "SPAM : %s", ap->from); + mta_memo(ap, 0); + + agent_reply(ap, "250 Message dropped"); + agent_log(ap, "SPAM", "mail"); + } + else + { + MYDOG; + cc = mta_mailer(ap); + MYDOG; + if (!cc) + { + agent_reply(ap, "250 Message accepted"); + MYDOG; + } + else if (cc < 0) + { + ap->xspam++; + MYDOG; + agent_log(ap, "SPAM", "mail"); + MYDOG; + } + } + + MYDOG; + agent_reset(ap); + MYDOG; + return 1; + } + + /* --------------------------------------------------- */ + /* command mode */ + /* --------------------------------------------------- */ + + used += cc; + + if (used >= MAX_CMD_LEN) + { + fprintf(flog, "CMD\t[%d] too long (%d) %.32s\n", + ap->sno, used, data); + +#ifdef DEBUG + fflush(flog); +#endif + + ap->mode = (mode |= AM_DROP); + ap->xerro += 10; /* are you hacker ? */ + used = 32; + } + + while (cc = *head) + { + if (cc == '\r' || cc == '\n') + { + Command *cmd; + + *head = '\0'; + + if (mode & AM_DROP) + { + agent_reset(ap); + agent_reply(ap, "552 command too long"); + MYDOG; + return -1; + } + + for (cmd = cmd_table; head = cmd->cmd; cmd++) + { + if (!str_ncmp(data, head, 4)) + break; + } + + MYDOG; + ap->used = 0; + + sprintf(gtext, "ip:%08x ", ap->ip_addr); + str_ncpy(gtext + 3 + 8 + 1, data, 50); + + (*cmd->func) (ap); + + *gtext = 0; + MYDOG; + return 1; + } + + if (cc == '\t') + *head = ' '; + + head++; + } + + MYDOG; + ap->used = used; + return 1; +} + + +/* ----------------------------------------------------- */ +/* close a connection & release its resource */ +/* ----------------------------------------------------- */ + + +static void +agent_fire(ap) + Agent *ap; +{ + int num; + char *data, *key, xerro[32], xspam[32]; + + num = ap->sock; + if (num > 0) + { + MYDOG; + fcntl(num, F_SETFL, M_NONBLOCK); + MYDOG; + +#define MSG_ABORT "\r\n450 buggy, closing ...\r\n" + send(num, MSG_ABORT, sizeof(MSG_ABORT) - 1, 0); +#undef MSG_ABORT + MYDOG; + shutdown(num, 2); + MYDOG; + close(num); + MYDOG; + + key = "END"; + } + else + { + key = "BYE"; + } + + MYDOG; + agent_free_rcpt(ap); + MYDOG; + + /* log */ + + data = ap->data; + + *xerro = *xspam = '\0'; + if ((num = ap->xerro) > 0) + sprintf(xerro, " X%d", num); + if ((num = ap->xspam) > 0) + sprintf(xspam, " Z%d", num); + + sprintf(data, "[%d] T%d R%d D%d S%d%s%s", ap->sno, time(0) - ap->tbegin, + ap->xrcpt, ap->xdata, ap->xsize, xerro, xspam); + logit(key, data); + + MYDOG; + free(data); + MYDOG; +} + + +/* ----------------------------------------------------- */ +/* accept a new connection */ +/* ----------------------------------------------------- */ + + +static char servo_ident[128]; + + +static int +agent_accept() +{ + int csock; + int value; + struct sockaddr_in csin; + char rhost[160], *ident; + + for (;;) + { + value = sizeof(csin); + MYDOG; + csock = accept(0, (struct sockaddr *) & csin, &value); + MYDOG; + /* if (csock > 0) */ + if (csock >= 0) /* Thor.000126: more proper */ + break; + + csock = errno; + if (csock != EINTR) + { + logit("ACCEPT", strerror(csock)); + return -1; + } + + MYDOG; + while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0); + MYDOG; + } + MYDOG; + + value = 1; + + /* Thor.000511: µù¸Ñ: don't delay send to coalesce(Áp¦X) packets */ + setsockopt(csock, IPPROTO_TCP, TCP_NODELAY, (char *) &value, sizeof(value)); + + /* --------------------------------------------------- */ + /* check remote host / user name */ + /* --------------------------------------------------- */ + + MYDOG; + + /* Thor.001026: °lÂÜ¥d¦bþ */ + sprintf(gtext, "ip:%08x", csin.sin_addr.s_addr); + + hht_look((HostAddr *) &csin.sin_addr, rhost); + + *gtext = 0; + MYDOG; + /* Thor.981207: °lÂÜ ip address */ + sprintf(ident = servo_ident, "[%d] %s ip:%08x", ++servo_sno, rhost, csin.sin_addr.s_addr); + + MYDOG; + ht_add(mhost_ht, rhost); + logit("CONN", ident); + MYDOG; + return csock; +} + + +/* ----------------------------------------------------- */ +/* signal routines */ +/* ----------------------------------------------------- */ + + +#ifdef SERVER_USAGE +static void +servo_usage() +{ + struct rusage ru; + + if (getrusage(RUSAGE_SELF, &ru)) + return; + + fprintf(flog, "\n[Server Usage]\n\n" + " user time: %.6f\n" + " system time: %.6f\n" + " maximum resident set size: %lu P\n" + " integral resident set size: %lu\n" + " page faults not requiring physical I/O: %d\n" + " page faults requiring physical I/O: %d\n" + " swaps: %d\n" + " block input operations: %d\n" + " block output operations: %d\n" + " messages sent: %d\n" + " messages received: %d\n" + " signals received: %d\n" + " voluntary context switches: %d\n" + " involuntary context switches: %d\ngline: %d\ngtext: %s\n", + + (double) ru.ru_utime.tv_sec + (double) ru.ru_utime.tv_usec / 1000000.0, + (double) ru.ru_stime.tv_sec + (double) ru.ru_stime.tv_usec / 1000000.0, + ru.ru_maxrss, + ru.ru_idrss, + ru.ru_minflt, + ru.ru_majflt, + ru.ru_nswap, + ru.ru_inblock, + ru.ru_oublock, + ru.ru_msgsnd, + ru.ru_msgrcv, + ru.ru_nsignals, + ru.ru_nvcsw, + ru.ru_nivcsw, gline, gtext); + + fflush(flog); +} +#endif + + +#define SS_CONFIG 1 +#define SS_SHUTDOWN 2 + + +static int servo_state; + + +static void +sig_hup() +{ + servo_state |= SS_CONFIG; +} + + +static void +sig_term() /* graceful termination */ +{ + servo_state |= SS_SHUTDOWN; +} + + +static void +sig_abort(sig) + int sig; +{ + char buf[80]; + + sprintf(buf, "abort: %d, errno: %d, gline: %d", sig, errno, gline); + logit("EXIT", buf); + fclose(flog); + exit(0); +} + + +static void +reaper() +{ + while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0); +} + + +static void +servo_signal() +{ + struct sigaction act; + + /* sigblock(sigmask(SIGPIPE)); *//* Thor.981206: ²Î¤@ POSIX ¼Ð·Ç¥Îªk */ + + /* act.sa_mask = 0; *//* Thor.981105: ¼Ð·Ç¥Îªk */ + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + act.sa_handler = sig_term; /* forced termination */ + sigaction(SIGTERM, &act, NULL); + + act.sa_handler = sig_abort; /* forced termination */ + sigaction(SIGSEGV, &act, NULL); /* if rlimit violate */ + sigaction(SIGBUS, &act, NULL); + +#if 1 /* Thor.990203: §ì signal */ + sigaction(SIGURG, &act, NULL); + sigaction(SIGXCPU, &act, NULL); + sigaction(SIGXFSZ, &act, NULL); + +#ifdef SOLARIS + sigaction(SIGLOST, &act, NULL); + sigaction(SIGPOLL, &act, NULL); + sigaction(SIGPWR, &act, NULL); +#endif + +#ifdef LINUX + sigaction(SIGSYS, &act, NULL); + /* sigaction(SIGEMT, &act, NULL); */ + /* itoc.010317: §Úªº linux ¨S¦³³oÓ»¡ :p */ +#endif + + sigaction(SIGFPE, &act, NULL); + sigaction(SIGWINCH, &act, NULL); + sigaction(SIGINT, &act, NULL); + sigaction(SIGQUIT, &act, NULL); + sigaction(SIGILL, &act, NULL); + sigaction(SIGTRAP, &act, NULL); + sigaction(SIGABRT, &act, NULL); + sigaction(SIGTSTP, &act, NULL); + sigaction(SIGTTIN, &act, NULL); + sigaction(SIGTTOU, &act, NULL); + sigaction(SIGVTALRM, &act, NULL); +#endif + + act.sa_handler = sig_hup; /* restart config */ + sigaction(SIGHUP, &act, NULL); + + act.sa_handler = reaper; + sigaction(SIGCHLD, &act, NULL); + +#ifdef SERVER_USAGE + act.sa_handler = servo_usage; + sigaction(SIGPROF, &act, NULL); +#endif + + /* Thor.981206: lkchu patch: ²Î¤@ POSIX ¼Ð·Ç¥Îªk */ + /* ¦b¦¹É¥Î sigset_t act.sa_mask */ + sigaddset(&act.sa_mask, SIGPIPE); + sigprocmask(SIG_BLOCK, &act.sa_mask, NULL); +} + + +/* ----------------------------------------------------- */ +/* server core routines */ +/* ----------------------------------------------------- */ + + +static void +servo_daemon(inetd) + int inetd; +{ + int fd, value; + char buf[80]; + struct linger ld; + struct sockaddr_in sin; +#ifdef HAVE_RLIMIT + struct rlimit limit; +#endif + + /* More idiot speed-hacking --- the first time conversion makes the C * + * library open the files containing the locale definition and time zone. * + * If this hasn't happened in the parent process, it happens in the * + * children, once per connection --- and it does add up. */ + + time((time_t *) & value); + gmtime((time_t *) & value); + strftime(buf, 80, "%d/%b/%Y:%H:%M:%S", localtime((time_t *) & value)); + +#ifdef HAVE_RLIMIT + /* --------------------------------------------------- */ + /* adjust the resource limit */ + /* --------------------------------------------------- */ + + getrlimit(RLIMIT_NOFILE, &limit); + limit.rlim_cur = limit.rlim_max; + setrlimit(RLIMIT_NOFILE, &limit); + + limit.rlim_cur = limit.rlim_max = 16 * 1024 * 1024; + setrlimit(RLIMIT_FSIZE, &limit); + + limit.rlim_cur = limit.rlim_max = 16 * 1024 * 1024; + setrlimit(RLIMIT_DATA, &limit); + +#ifdef SOLARIS +#define RLIMIT_RSS RLIMIT_AS /* Thor.981206: port for solaris 2.6 */ +#endif + + setrlimit(RLIMIT_RSS, &limit); + + limit.rlim_cur = limit.rlim_max = 0; + setrlimit(RLIMIT_CORE, &limit); +#endif + + /* --------------------------------------------------- */ + /* detach daemon process */ + /* --------------------------------------------------- */ + + close(1); + close(2); + + if (inetd) + return; + + close(0); + + if (fork()) + exit(0); + + setsid(); + + if (fork()) + exit(0); + + /* --------------------------------------------------- */ + /* setup socket */ + /* --------------------------------------------------- */ + + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + value = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value, sizeof(value)); + + ld.l_onoff = ld.l_linger = 0; + setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &ld, sizeof(ld)); + + sin.sin_family = AF_INET; + sin.sin_port = htons(BMTA_PORT); + sin.sin_addr.s_addr = htonl(INADDR_ANY); + memset((char *) &sin.sin_zero, 0, sizeof(sin.sin_zero)); + + if (bind(fd, (struct sockaddr *) & sin, sizeof(sin)) || + listen(fd, TCP_BACKLOG)) + exit(1); +} + + +/* Thor.990204: µù¸Ñ: ¨C¤Ñ¦¤W 5:30 ¾ã²z¤@¦¸ */ +#define SERVO_HOUR 5 +#define SERVO_MIN 30 + + +static time_t +fresh_time(uptime) + time_t uptime; +{ + struct tm *local; + int i; + + local = localtime(&uptime); + i = (SERVO_HOUR - local->tm_hour) * 3600 + (SERVO_MIN - local->tm_min) * 60; + if (i < 120) /* «O¯d®É¶¡®t 120 ¬í */ + i += BMTA_FRESH; + return (uptime + i); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int n, sock, state; + time_t uptime, tcheck, tfresh, tscore; + Agent **FBI, *Scully, *Mulder, *agent; + fd_set rset, wset, xset; + static struct timeval tv = {BMTA_PERIOD, 0}; + + state = 0; + + while ((n = getopt(argc, argv, "i")) != -1) + { + switch (n) + { + case 'i': + state = 1; + break; + + default: + fprintf(stderr, "Usage: %s [options]\n" + "\t-i start from inetd with wait option\n", + argv[0]); + exit(0); + } + } + + servo_daemon(state); + + setgid(BBSGID); + setuid(BBSUID); + chdir(BBSHOME); + servo_signal(); + + mail_root = acl_load(MAIL_ACLFILE, mail_root); + unmail_root = acl_load(UNMAIL_ACLFILE, unmail_root); + + log_open(); + init_bshm(); + init_ushm(); + dns_init(); + + mrcpt_ht = ht_new(128, 0); + mhost_ht = ht_new(256, 0); + mfrom_ht = ht_new(256, 0); + title_ht = ht_new(512, 0); + +#ifdef FORGE_CHECK + forge_ht = ht_new(256, 0); +#endif + + uptime = time(0); + tcheck = uptime + BMTA_PERIOD; + tfresh = fresh_time(uptime); + tscore = uptime + 2 * 60 * 60; + + Scully = Mulder = NULL; + + for (;;) + { + /* maintain : resource and garbage collection */ + + uptime = time(0); + if (tcheck < uptime) + { + /* ----------------------------------------------- */ + /* agent_audit (uptime - BMTA_TIMEOUT) */ + /* ----------------------------------------------- */ + + tcheck = uptime - BMTA_TIMEOUT; + + for (FBI = &Scully; agent = *FBI;) + { + if ((agent->uptime < tcheck) || (agent->xerro > BMTA_FAULT)) + { + agent_fire(agent); + + *FBI = agent->anext; + + agent->anext = Mulder; + Mulder = agent; + } + else + { + FBI = &(agent->anext); + } + } + + /* ----------------------------------------------- */ + /* expire SPAM HashTable */ + /* ----------------------------------------------- */ + + if (uptime > tscore) + { + tscore = uptime + 120 * 60; + + /* ¶W¹L 120 ¤ÀÄÁ¨S·s¶i°O¿ý¡A´N¶}©l expire */ + + tcheck = uptime - 120 * 60; + ht_expire(mfrom_ht, tcheck); + ht_expire(mhost_ht, tcheck); + ht_expire(mrcpt_ht, tcheck); + ht_expire(title_ht, tcheck); + + /* --------------------------------------------- */ + /* expire DNS HostHashTable cache */ + /* --------------------------------------------- */ + + hht_expire(uptime - 3 * 60 * 60); + + /* ht_expire(forge_ht, tcheck); /* never expire */ + +#ifdef FORGE_CHECK + /* Thor.990811: expire±¼¨S¥Îªºforge host */ + ht_expire(forge_ht, tcheck); +#endif + } + + /* ----------------------------------------------- */ + /* maintain SPAM & server log */ + /* ----------------------------------------------- */ + + if (tfresh < uptime) + { + tfresh = uptime + BMTA_FRESH; + visit_fresh(); +#ifdef SERVER_USAGE + servo_usage(); +#endif + log_fresh(); + } + else + { + fflush(flog); + } + + tcheck = uptime + BMTA_PERIOD; + } + + /* ------------------------------------------------- */ + /* check servo operation state */ + /* ------------------------------------------------- */ + + n = 0; + + if (state = servo_state) + { + if (state & SS_CONFIG) + { + state ^= SS_CONFIG; + + mail_root = acl_load(MAIL_ACLFILE, mail_root); + unmail_root = acl_load(UNMAIL_ACLFILE, unmail_root); + } + + if (state & SS_SHUTDOWN) /* graceful shutdown */ + { + n = -1; + close(0); + } + + servo_state = state; + } + + /* ------------------------------------------------- */ + /* Set up the fdsets */ + /* ------------------------------------------------- */ + + FD_ZERO(&rset); + FD_ZERO(&wset); + FD_ZERO(&xset); + + if (n == 0) + FD_SET(0, &rset); + + for (agent = Scully; agent; agent = agent->anext) + { + sock = agent->sock; + state = agent->state; + + if (n < sock) + n = sock; + + if (state == CS_RECV) + { + FD_SET(sock, &rset); + } + else + { + FD_SET(sock, &wset); + } + + FD_SET(sock, &xset); + } + + /* no active agent and ready to die */ + + if (n < 0) + { + break; + } + + { + struct timeval tv_tmp = tv; + /* Thor.981221: for future reservation bug */ + n = select(n + 1, &rset, &wset, &xset, &tv_tmp); + } + + if (n == 0) + { + continue; + } + + if (n < 0) + { + n = errno; + if (n != EINTR) + { + logit("SELECT", strerror(n)); + } + continue; + } + + /* ------------------------------------------------- */ + /* serve active agents */ + /* ------------------------------------------------- */ + + uptime = time(0); + + MYDOG; + for (FBI = &Scully; agent = *FBI;) + { + sock = agent->sock; + + if (FD_ISSET(sock, &wset)) + { + MYDOG; + state = agent_send(agent); + MYDOG; + } + else if (FD_ISSET(sock, &rset)) + { + MYDOG; + state = agent_recv(agent); + MYDOG; + } + else if (FD_ISSET(sock, &xset)) + { + MYDOG; + state = 0; + MYDOG; + } + else + { + state = -1; + } + + if (state == 0) /* fire this agent */ + { + MYDOG; + agent_fire(agent); + MYDOG; + + *FBI = agent->anext; + + agent->anext = Mulder; + Mulder = agent; + + continue; + } + + if (state > 0) + { + agent->uptime = uptime; + } + + FBI = &(agent->anext); + } + MYDOG; + + /* ------------------------------------------------- */ + /* serve new connection */ + /* ------------------------------------------------- */ + + /* Thor.000209: ¦Ò¼{²¾«e¦¹³¡¤À, §K±o¥d¦b accept() */ + if (FD_ISSET(0, &rset)) + { + /* Thor.990319: check maximum connection number */ + u_long ip_addr; + MYDOG; + sock = agent_accept(); + MYDOG; + + if (sock > 0) + { +#if 1 + /* Thor.990319: check maximum connection number */ + int num = 0; + + sscanf(strstr(servo_ident, "ip:") + 3, "%x", &ip_addr); + for (agent = Scully; agent; agent = agent->anext) + { + if (agent->ip_addr == ip_addr) + num++; + } + if (num >= MAX_HOST_CONN) + { + char buf[256]; + + sprintf(buf, "421 %s over max connection\r\n", MYHOSTNAME); + + MYDOG; + fcntl(sock, F_SETFL, M_NONBLOCK); /* Thor.000511: ©È block */ + MYDOG; + send(sock, buf, strlen(buf), 0); /* Thor.981206: ¸ÉÓ0¤W¨Ó */ + MYDOG; + shutdown(sock, 2); + MYDOG; + close(sock); + MYDOG; + logit("OVER", servo_ident); + MYDOG; + continue; + } +#endif + + if (agent = Mulder) + { + Mulder = agent->anext; + } + else + { + MYDOG; + agent = (Agent *) malloc(sizeof(Agent)); + MYDOG; + if (!agent) /* Thor.990205: °O¿ýªÅ¶¡¤£°÷ */ + logit("ERROR", "Not enough space in main()"); + } + + *FBI = agent; + + /* variable initialization */ + + memset(agent, 0, sizeof(Agent)); + + agent->sock = sock; + agent->sno = servo_sno; + agent->state = CS_SEND; + agent->tbegin = agent->uptime = uptime; + strcpy(agent->ident, servo_ident); + + /* Thor.990319: check maximum connection number */ + agent->ip_addr = ip_addr; + +#ifdef AM_DEBUG + if (strstr(agent->ident, "8c7a4133")) + { /* Thor.990221: that's mail.cc.ntnu.edu.tw */ + agent->mode |= AM_DEBUG; + } +#endif + + MYDOG; + agent->data = (char *) malloc(MIN_DATA_SIZE); + MYDOG; + if (!agent->data) /* Thor.990205: °O¿ýªÅ¶¡¤£°÷ */ + logit("ERROR", "Not enough space in agent->data"); + sprintf(agent->data, "220 " MYHOSTNAME " SMTP ready %s\r\n", servo_ident); /* Thor.981001: ¤£¥Î enhanced SMTP */ + agent->used = strlen(agent->data); + agent->size = MIN_DATA_SIZE; + } + } + + /* ------------------------------------------------- */ + /* tail of main loop */ + /* ------------------------------------------------- */ + } + + logit("EXIT", "shutdown"); + fclose(flog); + + exit(0); +} diff --git a/daemon/bnntpd.c b/daemon/bnntpd.c new file mode 100644 index 0000000..42b2bdf --- /dev/null +++ b/daemon/bnntpd.c @@ -0,0 +1,1500 @@ +/*-------------------------------------------------------*/ +/* bnntpd.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : BBS's NNTP daemon */ +/* create : 03/12/14 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#include <sys/wait.h> +#include <netinet/tcp.h> +#include <sys/resource.h> + + +#define SERVER_USAGE + + +#define BNNTP_PIDFILE "run/bnntp.pid" +#define BNNTP_LOGFILE "run/bnntp.log" + + +#define BNNTP_PERIOD (60 * 15) /* ¨C 15 ¤ÀÄÁ check ¤@¦¸ */ +#define BNNTP_TIMEOUT (60 * 30) /* ¶W¹L 30 ¤ÀÄÁªº³s½u´Nµø¬°¿ù»~ */ +#define BNNTP_FRESH 86400 /* ¨C 1 ¤Ñ¾ã²z¤@¦¸ */ + + +#define TCP_BACKLOG 3 +#define TCP_BUFSIZ 4096 +#define TCP_LINSIZ 256 +#define TCP_RCVSIZ 2048 + + +#define MIN_DATA_SIZE 2048 +#define MAX_CMD_LEN 1024 + + +/* Thor.000425: POSIX ¥Î O_NONBLOCK */ + +#ifndef O_NONBLOCK +#define M_NONBLOCK FNDELAY +#else +#define M_NONBLOCK O_NONBLOCK +#endif + +/* ----------------------------------------------------- */ +/* SMTP commands */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + void (*func) (); + char *cmd; + int len; /* strlen(Command.cmd) */ +} Command; + + +/* ----------------------------------------------------- */ +/* client connection structure */ +/* ----------------------------------------------------- */ + + +typedef struct Agent +{ + struct Agent *anext; + int sock; + int sno; + int state; + int mode; + unsigned int ip_addr; + + time_t tbegin; /* ³s½u¶}©l®É¶¡ */ + time_t uptime; /* ¤W¦¸¤U«ü¥Oªº®É¶¡ */ + + char newsgroup[BNLEN + 1]; /* ¥Ø«e©Ò¦bªº¬ÝªO */ + + char *data; + int used; + int size; /* ¥Ø«e data ©Ò malloc ªºªÅ¶¡¤j¤p */ +} Agent; + + +static int servo_sno = 0; + + +/* ----------------------------------------------------- */ +/* connection state */ +/* ----------------------------------------------------- */ + + +#define CS_FREE 0x00 +#define CS_RECV 0x01 +#define CS_SEND 0x02 +#define CS_FLUSH 0x03 /* flush data and quit */ + + +/* ----------------------------------------------------- */ +/* AM : Agent Mode */ +/* ----------------------------------------------------- */ + + +#define AM_DROP 0x010 /* swallow command */ + + +/* ----------------------------------------------------- */ +/* operation log and debug information */ +/* ----------------------------------------------------- */ +/* @START | ... | time */ +/* ----------------------------------------------------- */ + + +static FILE *flog; + + +extern int errno; +extern char *crypt(); + + +static void +log_fresh() +{ + int count; + char fsrc[64], fdst[64]; + char *fpath = BNNTP_LOGFILE; + + if (flog) + fclose(flog); + + count = 9; + do + { + sprintf(fdst, "%s.%d", fpath, count); + sprintf(fsrc, "%s.%d", fpath, --count); + rename(fsrc, fdst); + } while (count); + + rename(fpath, fsrc); + flog = fopen(fpath, "a"); +} + + +static void +logit(key, msg) + char *key; + char *msg; +{ + time_t now; + struct tm *p; + + time(&now); + p = localtime(&now); + /* Thor.990329: y2k */ + fprintf(flog, "%s\t%s\t%02d/%02d/%02d %02d:%02d:%02d\n", + key, msg, p->tm_year % 100, p->tm_mon + 1, p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec); +} + + +static void +log_open() +{ + FILE *fp; + + umask(077); + + if (fp = fopen(BNNTP_PIDFILE, "w")) + { + fprintf(fp, "%d\n", getpid()); + fclose(fp); + } + + flog = fopen(BNNTP_LOGFILE, "a"); + logit("START", "MTA daemon"); +} + + +static inline void +agent_log(ap, key, msg) + Agent *ap; + char *key; + char *msg; +{ + fprintf(flog, "%s\t[%d] %s\n", key, ap->sno, msg); +} + + +static void +agent_reply(ap, msg) /* ±N msg °e¥X¥h */ + Agent *ap; + char *msg; +{ + int cc; + char *base, *head; + + head = base = ap->data; + while (cc = *msg++) + { + *head++ = cc; + } + *head++ = '\r'; + *head++ = '\n'; + ap->used = head - base; + ap->state = CS_SEND; +} + + +static void +agent_write(ap, ftemp) /* ±N ftemp ¸Ì±ªº¤º®e°e¥X¥h */ + Agent *ap; + char *ftemp; +{ + int fd, fsize; + char *data; + struct stat st; + + if ((fd = open(ftemp, O_RDONLY)) >= 0) + { + fstat(fd, &st); + if ((fsize = st.st_size) > 0) + { + data = ap->data; + if (fsize > ap->size) + { + ap->data = data = realloc(data, fsize); + ap->size = fsize; + } + read(fd, data, fsize); + } + + close(fd); + unlink(ftemp); + + ap->used = fsize; + ap->state = CS_SEND; + } +} + + +/* ----------------------------------------------------- */ +/* board¡Gshm ³¡¥÷¶·»P cache.c ¬Û®e */ +/* ----------------------------------------------------- */ + + +static BCACHE *bshm; + + +static void +init_bshm() +{ + /* itoc.030727: ¦b¶}±Ò bbsd ¤§«e¡AÀ³¸Ó´Nn°õ¦æ¹L account¡A + ©Ò¥H bshm À³¸Ó¤w³]©w¦n */ + + if (bshm) + return; + + bshm = shm_new(BRDSHM_KEY, sizeof(BCACHE)); + + if (bshm->uptime <= 0) /* bshm ¥¼³]©w§¹¦¨ */ + exit(0); +} + + +/* ----------------------------------------------------- */ +/* command dispatch */ +/* ----------------------------------------------------- */ + + + /* --------------------------------------------------- */ + /* ¯S®í«ü¥O */ + /* --------------------------------------------------- */ + + +static void +cmd_what(ap) + Agent *ap; +{ + agent_reply(ap, "500 Bad command use"); +} + + +static void +cmd_help(ap) + Agent *ap; +{ + agent_reply(ap, "100 Legal commands\r\n" + " article [Number]\r\n" + " group newsgroup\r\n" + " head [Number]\r\n" + " help\r\n" + " list\r\n" + " mode reader\r\n" + " quit\r\n" + " xhdr header [range]\r\n" + " xover [range]\r\n" + "Report problems to the "STR_SYSOP".bbs@"MYHOSTNAME); +} + + +static void +cmd_quit(ap) + Agent *ap; +{ + char *data; + + data = ap->data; + strcpy(data, "205 closing connection - goodbye!\r\n"); + ap->used = strlen(data); + ap->state = CS_FLUSH; +} + + + /* --------------------------------------------------- */ + /* ¼Ò¦¡ */ + /* --------------------------------------------------- */ + + +static void +cmd_mode(ap) + Agent *ap; +{ + if (ap->data[4] == '\0') /* mode */ + agent_reply(ap, "reader"); + else /* mode reader */ + agent_reply(ap, "200 MapleBBS NNTP server ready (read only)"); +} + + + /* --------------------------------------------------- */ + /* ¦C¥X©Ò¦³¬ÝªO */ + /* --------------------------------------------------- */ + + +static void +cmd_list(ap) + Agent *ap; +{ + char ftemp[64]; + BRD *brdp, *bend; + FILE *fp; + + sprintf(ftemp, "tmp/bnntp.%d", ap->sno); + fp = fopen(ftemp, "w"); + + fputs("215 list of newsgroups follows\r\n", fp); + + brdp = bshm->bcache; + bend = brdp + bshm->number; + + do + { + if (brdp->brdname[0] && !brdp->readlevel) /* guest ¥iŪ */ + fprintf(fp, "%s %d 1 y\r\n", brdp->brdname, brdp->bpost); + } while (++brdp < bend); + + fputs(".\r\n", fp); + fclose(fp); + + agent_write(ap, ftemp); +} + + + /* --------------------------------------------------- */ + /* ¤Á´«¸s²Õ */ + /* --------------------------------------------------- */ + + +static BRD * +brd_get(brdname) + char *brdname; +{ + BRD *bhdr, *tail; + + bhdr = bshm->bcache; + tail = bhdr + bshm->number; + + do + { + if (!str_cmp(brdname, bhdr->brdname)) + { + if (!bhdr->readlevel) /* guest ¥iŪ */ + return bhdr; + return NULL; + } + } while (++bhdr < tail); + + return NULL; +} + + +static void +cmd_group(ap) + Agent *ap; +{ + char *brdname, msg[80]; + BRD *brd; + + brdname = ap->data + 6; + + if (*brdname && (brd = brd_get(brdname))) + { + strcpy(ap->newsgroup, brd->brdname); + sprintf(msg, "211 %d 1 %d %s selected", brd->bpost, brd->bpost, brd->brdname); + } + else + { + sprintf(msg, "411 No such group %s", brdname); + } + agent_reply(ap, msg); +} + + + /* --------------------------------------------------- */ + /* ´M°ÝÀÉÀY */ + /* --------------------------------------------------- */ + + +static char * +postowner(owner) + char *owner; +{ + static char ownmsg[80]; + + if (strchr(owner, '@')) + return owner; + sprintf(ownmsg, "%s@"MYHOSTNAME, owner); + return ownmsg; +} + + +static char * +Gtime(now) + time_t now; +{ + static char datemsg[40]; + + strftime(datemsg, sizeof(datemsg), "%d %b %Y %X GMT", gmtime(&now)); + return datemsg; +} + + +static void +cmd_xhdr(ap) + Agent *ap; +{ + char *str, *newsgroup, *ptr1, *ptr2; + char folder[64], ftemp[64]; + int low, high, max, fd, patern; + HDR hdr; + FILE *fp; + + newsgroup = ap->newsgroup; + + if (*newsgroup == '\0') + { + agent_reply(ap, "412 no newsgroup has been selected"); + return; + } + + str = ap->data + 5; + + /* ¥u¤ä´© subject from date message-id ³o¥|ºØÀÉÀY */ + if (!str_ncmp(str, "subject", 7)) + patern = 1; + else if (!str_ncmp(str, "from", 4)) + patern = 2; + else if (!str_ncmp(str, "date", 4)) + patern = 3; + else if (!strncmp(str, "message-id", 10)) + patern = 4; + else + patern = 0; + + if ((ptr1 = strchr(str, ' ')) && *(++ptr1) && (ptr2 = strchr(ptr1, '-')) && *(++ptr2)) + { + low = atoi(ptr1) - 1; + if (low < 0) + low = 0; + high = atoi(ptr2) - 1; + } + else + { + low = 0; + high = 0; + } + + brd_fpath(folder, newsgroup, FN_DIR); + max = rec_num(folder, sizeof(HDR)) - 1; + if (high > max) + high = max; + + sprintf(ftemp, "tmp/bnntp.%d", ap->sno); + fp = fopen(ftemp, "w"); + + fputs("221 header fields follow\r\n", fp); + if (!patern) + { + while (low <= high) + fprintf(fp, "%d (none)\r\n", ++low); + } + else + { + if ((fd = open(folder, O_RDONLY)) >= 0) + { + lseek(fd, (off_t) (sizeof(HDR) * low), SEEK_SET); + while (low <= high && read(fd, &hdr, sizeof(HDR)) == sizeof(HDR)) + { + low++; + + if (patern == 1) + { + fprintf(fp, "%d ", low); + output_rfc2047_qp(fp, "", hdr.title, MYCHARSET, "\r\n"); + } + else if (patern == 2) + { + fprintf(fp, "%d %s (%s)\r\n", low, postowner(hdr.owner), hdr.nick); + } + else if (patern == 3) + { + fprintf(fp, "%d %s\r\n", low, Gtime(hdr.chrono)); + } + else /* if (patern == 4) */ + { + fprintf(fp, "%d %s$%s@"MYHOSTNAME"\r\n", low, hdr.xname, newsgroup); + } + } + close(fd); + } + } + fputs(".\r\n", fp); + + fclose(fp); + + agent_write(ap, ftemp); +} + + +static void +cmd_xover(ap) + Agent *ap; +{ + char *str, *newsgroup, *ptr; + char folder[64], ftemp[64]; + int low, high, max, fd; + HDR hdr; + FILE *fp; + + newsgroup = ap->newsgroup; + + if (*newsgroup == '\0') + { + agent_reply(ap, "412 no newsgroup has been selected"); + return; + } + + str = ap->data + 6; + + if (*str && (ptr = strchr(str, '-')) && *(++ptr)) + { + low = atoi(str) - 1; + if (low < 0) + low = 0; + high = atoi(ptr) - 1; + } + else + { + low = 0; + high = 0; + } + + brd_fpath(folder, newsgroup, FN_DIR); + max = rec_num(folder, sizeof(HDR)) - 1; + if (high > max) + high = max; + + sprintf(ftemp, "tmp/bnntp.%d", ap->sno); + fp = fopen(ftemp, "w"); + + fputs("224 data follows\r\n", fp); + if ((fd = open(folder, O_RDONLY)) >= 0) + { + lseek(fd, (off_t) (sizeof(HDR) * low), SEEK_SET); + while (low <= high && read(fd, &hdr, sizeof(HDR)) == sizeof(HDR)) + { + /* subject from date message-id references lines xref */ + low++; + fprintf(fp, "%d\t", low); + output_rfc2047_qp(fp, "", hdr.title, MYCHARSET, "\t"); + fprintf(fp, "%s (%s)\t", postowner(hdr.owner), hdr.nick); + fprintf(fp, "%s\t", Gtime(hdr.chrono)); + fprintf(fp, "<%s$%s@"MYHOSTNAME">\t", hdr.xname, newsgroup); + fprintf(fp, "%d\t", low); + fprintf(fp, "6\t"); /* lines ÀH«Kµ¹ */ + fprintf(fp, "%s.%s\r\n", newsgroup, hdr.xname); + } + close(fd); + } + fputs(".\r\n", fp); + + fclose(fp); + + agent_write(ap, ftemp); +} + + + /* --------------------------------------------------- */ + /* §ì¨ú¤å³¹ */ + /* --------------------------------------------------- */ + + +static void +fetch_article(ap, str, mode) + Agent *ap; + char *str; + int mode; +{ + char *newsgroup; + char folder[64], fpath[64], ftemp[64], buf[ANSILINELEN]; + int pos, max; + HDR hdr; + FILE *fp, *fpr; + + newsgroup = ap->newsgroup; + + if (*newsgroup == '\0') + { + agent_reply(ap, "412 no newsgroup has been selected"); + return; + } + + brd_fpath(folder, newsgroup, FN_DIR); + if (*str) + { + pos = atoi(str) - 1; + max = rec_num(folder, sizeof(HDR)) - 1; + if (pos > max) + pos = max; + if (pos < 0) + pos = 0; + } + else + { + pos = 0; + } + + sprintf(ftemp, "tmp/bnntp.%d", ap->sno); + fp = fopen(ftemp, "w"); + + fprintf(fp, "22%d %d article retrieved - %s follows\r\n", mode, pos + 1, mode ? "head" : "article"); + if (!rec_get(folder, &hdr, sizeof(HDR), pos)) + { + /* ¤å³¹ÀÉÀY */ + fprintf(fp, "From: %s (%s)\r\n", postowner(hdr.owner), hdr.nick); + fprintf(fp, "Newsgroups: %s\r\n", newsgroup); + output_rfc2047_qp(fp, "Subject: ", hdr.title, MYCHARSET, "\r\n"); + fprintf(fp, "Date: %s\r\n", Gtime(hdr.chrono)); + fprintf(fp, "Message-ID: <%s$%s@"MYHOSTNAME">\r\n", hdr.xname, newsgroup); + fprintf(fp, "Mime-Version: 1.0\r\n"); + fprintf(fp, "Content-Type: text/plain; charset=\""MYCHARSET"\"\r\n"); + fprintf(fp, "Content-Transfer-Encoding: 8bit\r\n"); + + /* ¤å³¹¤º®e */ + if (!mode) + { + fputs("\r\n", fp); /* ÀÉÀY©M¤º¤åªÅ¤@¦æ */ + +#ifdef HAVE_REFUSEMARK + if (!(hdr.xmode & POST_RESTRICT)) + { +#endif + hdr_fpath(fpath, folder, &hdr); + if (fpr = fopen(fpath, "r")) + { + while (fgets(buf, ANSILINELEN, fpr)) + { + str_ansi(buf, buf, sizeof(buf)); /* ¥h°£ '\n' ¤Î±±¨î½X */ + fprintf(fp, "%s\r\n", buf); + } + fclose(fpr); + } +#ifdef HAVE_REFUSEMARK + } +#endif + } + } + fputs(".\r\n", fp); + + fclose(fp); + + agent_write(ap, ftemp); +} + + +static void +cmd_head(ap) + Agent *ap; +{ + fetch_article(ap, ap->data + 5, 1); +} + + +static void +cmd_article(ap) + Agent *ap; +{ + fetch_article(ap, ap->data + 8, 0); +} + + + /* --------------------------------------------------- */ + /* «ü¥O¶° */ + /* --------------------------------------------------- */ + + +static Command cmd_table[] = +{ + cmd_help, "help", 4, + cmd_quit, "quit", 4, + + cmd_mode, "mode", 4, + cmd_list, "list", 4, + + cmd_group, "group ", 6, + + cmd_xhdr, "xhdr ", 5, + cmd_xover, "xover ", 6, + + cmd_head, "head ", 5, + cmd_article, "article ", 8, + + cmd_what, NULL, 0 +}; + + +/* ----------------------------------------------------- */ +/* send output to client */ +/* ----------------------------------------------------- */ +/* return value : */ +/* > 0 : bytes sent */ +/* = 0 : close this agent */ +/* < 0 : there are some error, but keep trying */ +/* ----------------------------------------------------- */ + + +static int +agent_send(ap) + Agent *ap; +{ + int csock, len, cc; + char *data; + + csock = ap->sock; + data = ap->data; + len = ap->used; + cc = send(csock, data, len, 0); + + if (cc < 0) + { + cc = errno; + if (cc != EWOULDBLOCK) + { + agent_log(ap, "SEND", strerror(cc)); + return 0; + } + + /* would block, so leave it to do later */ + return -1; + } + + if (cc == 0) + return -1; + + len -= cc; + ap->used = len; + if (len) + { + memcpy(data, data + cc, len); + return cc; + } + + if (ap->state == CS_FLUSH) + { + shutdown(csock, 2); + close(csock); + ap->sock = -1; + return 0; + } + + ap->state = CS_RECV; + return cc; +} + + +/* ----------------------------------------------------- */ +/* receive request from client */ +/* ----------------------------------------------------- */ + + +static int +agent_recv(ap) + Agent *ap; +{ + int cc, mode, used; + char *data, *head; + + mode = ap->mode; + used = ap->used; + data = ap->data; + + head = data + used; + cc = recv(ap->sock, head, TCP_RCVSIZ, 0); + + if (cc <= 0) + { + cc = errno; + if (cc != EWOULDBLOCK) + { + agent_log(ap, "RECV", strerror(cc)); + return 0; + } + + /* would block, so leave it to do later */ + + return -1; + } + + head[cc] = '\0'; + used += cc; + + if (used >= MAX_CMD_LEN) + { + fprintf(flog, "CMD\t[%d] too long (%d) %.32s\n", + ap->sno, used, data); + + ap->mode = (mode |= AM_DROP); + used = 32; + } + + while (cc = *head) + { + if (cc == '\r' || cc == '\n') + { + Command *cmd; + + *head = '\0'; + + if (mode & AM_DROP) + { + ap->mode = mode ^ AM_DROP; + agent_reply(ap, "552 command too long"); + return -1; + } + + for (cmd = cmd_table; head = cmd->cmd; cmd++) + { + if (!str_ncmp(data, head, cmd->len)) + break; + } + + ap->used = 0; + + (*cmd->func) (ap); + + return 1; + } + + if (cc == '\t') + *head = ' '; + + head++; + } + + ap->used = used; + return 1; +} + + +/* ----------------------------------------------------- */ +/* close a connection & release its resource */ +/* ----------------------------------------------------- */ + + +static void +agent_fire(ap) + Agent *ap; +{ + int num; + char *data, *key; + + num = ap->sock; + if (num > 0) + { + fcntl(num, F_SETFL, M_NONBLOCK); + +#define MSG_ABORT "\r\n450 buggy, closing ...\r\n" + send(num, MSG_ABORT, sizeof(MSG_ABORT) - 1, 0); +#undef MSG_ABORT + shutdown(num, 2); + close(num); + + key = "END"; + } + else + { + key = "BYE"; + } + + /* log */ + + data = ap->data; + + sprintf(data, "[%d] T%d", ap->sno, time(0) - ap->tbegin); + logit(key, data); + + free(data); +} + + +/* ----------------------------------------------------- */ +/* accept a new connection */ +/* ----------------------------------------------------- */ + + +static int +agent_accept() +{ + int csock; + int value; + struct sockaddr_in csin; + + for (;;) + { + value = sizeof(csin); + csock = accept(0, (struct sockaddr *) & csin, &value); + /* if (csock > 0) */ + if (csock >= 0) /* Thor.000126: more proper */ + break; + + csock = errno; + if (csock != EINTR) + { + logit("ACCEPT", strerror(csock)); + return -1; + } + + while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0); + } + + value = 1; + + /* Thor.000511: µù¸Ñ: don't delay send to coalesce(Áp¦X) packets */ + setsockopt(csock, IPPROTO_TCP, TCP_NODELAY, (char *) &value, sizeof(value)); + + /* --------------------------------------------------- */ + /* check remote host / user name */ + /* --------------------------------------------------- */ + + logit("CONN", ""); + return csock; +} + + +/* ----------------------------------------------------- */ +/* signal routines */ +/* ----------------------------------------------------- */ + + +#ifdef SERVER_USAGE +static void +servo_usage() +{ + struct rusage ru; + + if (getrusage(RUSAGE_SELF, &ru)) + return; + + fprintf(flog, "\n[Server Usage]\n\n" + " user time: %.6f\n" + " system time: %.6f\n" + " maximum resident set size: %lu P\n" + " integral resident set size: %lu\n" + " page faults not requiring physical I/O: %d\n" + " page faults requiring physical I/O: %d\n" + " swaps: %d\n" + " block input operations: %d\n" + " block output operations: %d\n" + " messages sent: %d\n" + " messages received: %d\n" + " signals received: %d\n" + " voluntary context switches: %d\n" + " involuntary context switches: %d\n", + + (double) ru.ru_utime.tv_sec + (double) ru.ru_utime.tv_usec / 1000000.0, + (double) ru.ru_stime.tv_sec + (double) ru.ru_stime.tv_usec / 1000000.0, + ru.ru_maxrss, + ru.ru_idrss, + ru.ru_minflt, + ru.ru_majflt, + ru.ru_nswap, + ru.ru_inblock, + ru.ru_oublock, + ru.ru_msgsnd, + ru.ru_msgrcv, + ru.ru_nsignals, + ru.ru_nvcsw, + ru.ru_nivcsw); + + fflush(flog); +} +#endif + + +#define SS_CONFIG 1 +#define SS_SHUTDOWN 2 + + +static int servo_state; + + +static void +sig_hup() +{ + servo_state |= SS_CONFIG; +} + + +static void +sig_term() /* graceful termination */ +{ + servo_state |= SS_SHUTDOWN; +} + + +static void +sig_abort(sig) + int sig; +{ + char buf[80]; + + sprintf(buf, "abort: %d, errno: %d", sig, errno); + logit("EXIT", buf); + fclose(flog); + exit(0); +} + + +static void +reaper() +{ + while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0); +} + + +static void +servo_signal() +{ + struct sigaction act; + + /* sigblock(sigmask(SIGPIPE)); *//* Thor.981206: ²Î¤@ POSIX ¼Ð·Ç¥Îªk */ + + /* act.sa_mask = 0; *//* Thor.981105: ¼Ð·Ç¥Îªk */ + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + act.sa_handler = sig_term; /* forced termination */ + sigaction(SIGTERM, &act, NULL); + + act.sa_handler = sig_abort; /* forced termination */ + sigaction(SIGSEGV, &act, NULL); /* if rlimit violate */ + sigaction(SIGBUS, &act, NULL); + +#if 1 /* Thor.990203: §ì signal */ + sigaction(SIGURG, &act, NULL); + sigaction(SIGXCPU, &act, NULL); + sigaction(SIGXFSZ, &act, NULL); + +#ifdef SOLARIS + sigaction(SIGLOST, &act, NULL); + sigaction(SIGPOLL, &act, NULL); + sigaction(SIGPWR, &act, NULL); +#endif + +#ifdef LINUX + sigaction(SIGSYS, &act, NULL); + /* sigaction(SIGEMT, &act, NULL); */ + /* itoc.010317: §Úªº linux ¨S¦³³oÓ»¡ :p */ +#endif + + sigaction(SIGFPE, &act, NULL); + sigaction(SIGWINCH, &act, NULL); + sigaction(SIGINT, &act, NULL); + sigaction(SIGQUIT, &act, NULL); + sigaction(SIGILL, &act, NULL); + sigaction(SIGTRAP, &act, NULL); + sigaction(SIGABRT, &act, NULL); + sigaction(SIGTSTP, &act, NULL); + sigaction(SIGTTIN, &act, NULL); + sigaction(SIGTTOU, &act, NULL); + sigaction(SIGVTALRM, &act, NULL); +#endif + + act.sa_handler = sig_hup; /* restart config */ + sigaction(SIGHUP, &act, NULL); + + act.sa_handler = reaper; + sigaction(SIGCHLD, &act, NULL); + +#ifdef SERVER_USAGE + act.sa_handler = servo_usage; + sigaction(SIGPROF, &act, NULL); +#endif + + /* Thor.981206: lkchu patch: ²Î¤@ POSIX ¼Ð·Ç¥Îªk */ + /* ¦b¦¹É¥Î sigset_t act.sa_mask */ + sigaddset(&act.sa_mask, SIGPIPE); + sigprocmask(SIG_BLOCK, &act.sa_mask, NULL); +} + + +/* ----------------------------------------------------- */ +/* server core routines */ +/* ----------------------------------------------------- */ + + +static void +servo_daemon(inetd) + int inetd; +{ + int fd, value; + char buf[80]; + struct linger ld; + struct sockaddr_in sin; +#ifdef HAVE_RLIMIT + struct rlimit limit; +#endif + + /* More idiot speed-hacking --- the first time conversion makes the C * + * library open the files containing the locale definition and time zone. * + * If this hasn't happened in the parent process, it happens in the * + * children, once per connection --- and it does add up. */ + + time((time_t *) & value); + gmtime((time_t *) & value); + strftime(buf, 80, "%d/%b/%Y:%H:%M:%S", localtime((time_t *) & value)); + +#ifdef HAVE_RLIMIT + /* --------------------------------------------------- */ + /* adjust the resource limit */ + /* --------------------------------------------------- */ + + getrlimit(RLIMIT_NOFILE, &limit); + limit.rlim_cur = limit.rlim_max; + setrlimit(RLIMIT_NOFILE, &limit); + + limit.rlim_cur = limit.rlim_max = 16 * 1024 * 1024; + setrlimit(RLIMIT_FSIZE, &limit); + + limit.rlim_cur = limit.rlim_max = 16 * 1024 * 1024; + setrlimit(RLIMIT_DATA, &limit); + +#ifdef SOLARIS +#define RLIMIT_RSS RLIMIT_AS /* Thor.981206: port for solaris 2.6 */ +#endif + + setrlimit(RLIMIT_RSS, &limit); + + limit.rlim_cur = limit.rlim_max = 0; + setrlimit(RLIMIT_CORE, &limit); +#endif + + /* --------------------------------------------------- */ + /* detach daemon process */ + /* --------------------------------------------------- */ + + close(1); + close(2); + + if (inetd) + return; + + close(0); + + if (fork()) + exit(0); + + setsid(); + + if (fork()) + exit(0); + + /* --------------------------------------------------- */ + /* setup socket */ + /* --------------------------------------------------- */ + + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + value = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value, sizeof(value)); + + ld.l_onoff = ld.l_linger = 0; + setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &ld, sizeof(ld)); + + sin.sin_family = AF_INET; + sin.sin_port = htons(BNNTP_PORT); + sin.sin_addr.s_addr = htonl(INADDR_ANY); + memset((char *) &sin.sin_zero, 0, sizeof(sin.sin_zero)); + + if (bind(fd, (struct sockaddr *) & sin, sizeof(sin)) || + listen(fd, TCP_BACKLOG)) + exit(1); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int n, sock, state; + time_t uptime, tcheck, tfresh; + Agent **FBI, *Scully, *Mulder, *agent; + fd_set rset, wset, xset; + static struct timeval tv = {BNNTP_PERIOD, 0}; + + state = 0; + + while ((n = getopt(argc, argv, "i")) != -1) + { + switch (n) + { + case 'i': + state = 1; + break; + + default: + fprintf(stderr, "Usage: %s [options]\n" + "\t-i start from inetd with wait option\n", + argv[0]); + exit(0); + } + } + + servo_daemon(state); + + setgid(BBSGID); + setuid(BBSUID); + chdir(BBSHOME); + + init_bshm(); + + servo_signal(); + + log_open(); + dns_init(); + + uptime = time(0); + tcheck = uptime + BNNTP_PERIOD; + tfresh = uptime + BNNTP_FRESH; + + Scully = Mulder = NULL; + + for (;;) + { + /* maintain : resource and garbage collection */ + + uptime = time(0); + if (tcheck < uptime) + { + /* ----------------------------------------------- */ + /* agent_audit (uptime - BNNTP_TIMEOUT) */ + /* ----------------------------------------------- */ + + tcheck = uptime - BNNTP_TIMEOUT; + + for (FBI = &Scully; agent = *FBI;) + { + if (agent->uptime < tcheck) + { + agent_fire(agent); + + *FBI = agent->anext; + + agent->anext = Mulder; + Mulder = agent; + } + else + { + FBI = &(agent->anext); + } + } + + /* ----------------------------------------------- */ + /* maintain SPAM & server log */ + /* ----------------------------------------------- */ + + if (tfresh < uptime) + { + tfresh = uptime + BNNTP_FRESH; +#ifdef SERVER_USAGE + servo_usage(); +#endif + log_fresh(); + } + else + { + fflush(flog); + } + + tcheck = uptime + BNNTP_PERIOD; + } + + /* ------------------------------------------------- */ + /* check servo operation state */ + /* ------------------------------------------------- */ + + n = 0; + + if (state = servo_state) + { + if (state & SS_CONFIG) + { + state ^= SS_CONFIG; + } + + if (state & SS_SHUTDOWN) /* graceful shutdown */ + { + n = -1; + close(0); + } + + servo_state = state; + } + + /* ------------------------------------------------- */ + /* Set up the fdsets */ + /* ------------------------------------------------- */ + + FD_ZERO(&rset); + FD_ZERO(&wset); + FD_ZERO(&xset); + + if (n == 0) + FD_SET(0, &rset); + + for (agent = Scully; agent; agent = agent->anext) + { + sock = agent->sock; + state = agent->state; + + if (n < sock) + n = sock; + + if (state == CS_RECV) + { + FD_SET(sock, &rset); + } + else + { + FD_SET(sock, &wset); + } + + FD_SET(sock, &xset); + } + + /* no active agent and ready to die */ + + if (n < 0) + { + break; + } + + { + struct timeval tv_tmp = tv; + /* Thor.981221: for future reservation bug */ + n = select(n + 1, &rset, &wset, &xset, &tv_tmp); + } + + if (n == 0) + { + continue; + } + + if (n < 0) + { + n = errno; + if (n != EINTR) + { + logit("SELECT", strerror(n)); + } + continue; + } + + /* ------------------------------------------------- */ + /* serve active agents */ + /* ------------------------------------------------- */ + + uptime = time(0); + + for (FBI = &Scully; agent = *FBI;) + { + sock = agent->sock; + + if (FD_ISSET(sock, &wset)) + { + state = agent_send(agent); + } + else if (FD_ISSET(sock, &rset)) + { + state = agent_recv(agent); + } + else if (FD_ISSET(sock, &xset)) + { + state = 0; + } + else + { + state = -1; + } + + if (state == 0) /* fire this agent */ + { + agent_fire(agent); + + *FBI = agent->anext; + + agent->anext = Mulder; + Mulder = agent; + + continue; + } + + if (state > 0) + { + agent->uptime = uptime; + } + + FBI = &(agent->anext); + } + + /* ------------------------------------------------- */ + /* serve new connection */ + /* ------------------------------------------------- */ + + /* Thor.000209: ¦Ò¼{²¾«e¦¹³¡¤À, §K±o¥d¦b accept() */ + if (FD_ISSET(0, &rset)) + { + /* Thor.990319: check maximum connection number */ + unsigned int ip_addr; + sock = agent_accept(); + + if (sock > 0) + { + if (agent = Mulder) + { + Mulder = agent->anext; + } + else + { + agent = (Agent *) malloc(sizeof(Agent)); + if (!agent) /* Thor.990205: °O¿ýªÅ¶¡¤£°÷ */ + logit("ERROR", "Not enough space in main()"); + } + + *FBI = agent; + + /* variable initialization */ + + memset(agent, 0, sizeof(Agent)); + + agent->sock = sock; + agent->sno = ++servo_sno; + agent->state = CS_SEND; + agent->tbegin = agent->uptime = uptime; + + /* Thor.990319: check maximum connection number */ + agent->ip_addr = ip_addr; + + agent->data = (char *) malloc(MIN_DATA_SIZE); + if (!agent->data) /* Thor.990205: °O¿ýªÅ¶¡¤£°÷ */ + logit("ERROR", "Not enough space in agent->data"); + sprintf(agent->data, "200 MapleBBS NNTP server ready (read only)\r\n"); + agent->used = strlen(agent->data); + agent->size = MIN_DATA_SIZE; + } + } + + /* ------------------------------------------------- */ + /* tail of main loop */ + /* ------------------------------------------------- */ + } + + logit("EXIT", "shutdown"); + fclose(flog); + + exit(0); +} diff --git a/daemon/bpop3d.c b/daemon/bpop3d.c new file mode 100644 index 0000000..3b76e8c --- /dev/null +++ b/daemon/bpop3d.c @@ -0,0 +1,1871 @@ +/*-------------------------------------------------------*/ +/* util/bpop3d.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : Simple POP3 server for BBS user */ +/* create : 96/05/10 */ +/* update : 96/11/15 */ +/*-------------------------------------------------------*/ +/* notice : single process concurrent server */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#undef DEBUG +#define WATCH_DOG +#define SERVER_USAGE + + +#include <netinet/tcp.h> +#include <sys/wait.h> +#include <sys/resource.h> + + +#ifdef HAVE_DNS_LOOKUP +#include "dns.ic" +#endif + + +#define POP3_HOME (BBSHOME "/usr") +#define POP3_TIMEOUT (60 * 30) + +#define POP3_LOGFILE (BBSHOME "/run/pop3.log") +#define POP3_PIDFILE (BBSHOME "/run/pop3.pid") +#define POP3_DEBUGFILE (BBSHOME "/run/pop3.debug") + +#define POP3_FQDN (".bbs@" MYHOSTNAME) + +#define SOCK_BACKLOG 3 + + +#define SNDBUFSIZ (256 * 14) +#define SNDLINSIZ 256 /* Thor.990522: µù¸Ñ: °e¥X¨C¦æ³Ìªø */ +#define RCVBUFSIZ 128 /* Thor.990522: µù¸Ñ: ¦¬¨ì¨C¦æ³Ìªø */ + + +/* ----------------------------------------------------- */ +/* MapleBBS pop3d message strings */ +/* ----------------------------------------------------- */ + + +#define POP3_BYE_MSG "+OK POP3 server sign off\r\n" +#define POP3_BYE_LEN (sizeof(POP3_BYE_MSG) - 1) + + +#define POP3_ERRCMD_MSG "-ERR invalid command\r\n" +#define POP3_ERRARG_MSG "-ERR invalid argument\r\n" +#define POP3_ERRNUM_MSG "-ERR message number out of range\r\n" +#define POP3_DELETE_MSG "-ERR message has been deleted\r\n" + + +/* ----------------------------------------------------- */ +/* POPH : pop3header extended from HDR */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + time_t chrono; /* timestamp */ + int xmode; + + int xid; /* reserved */ + + char xname[24]; /* ÀɮצWºÙ */ + int pmode; /* Thor.990522: ¬O§_§R«H µ¥ */ + int psize; /* Thor.990522: ¥»«H¶Ç°eÁ`¤j¤p */ + + char owner[80]; /* §@ªÌ (E-mail address) */ + char nick[50]; /* ¼ÊºÙ */ + + char date[9]; /* [96/12/01] */ + char title[TTLEN + 1]; /* ¥DÃD */ +} POPH; + + +/* ----------------------------------------------------- */ +/* client connection structure */ +/* ----------------------------------------------------- */ + + +typedef struct Client +{ + struct Client *next; + int sno; /* serial number */ + + int sock; + int state; + time_t tbirth; + time_t uptime; + + int mode; +#ifdef DEBUG + int debug; +#endif + int pcount; /* Thor.990522: «H¥ó¼Æ */ + int pbytes; /* Thor.990522: Á`¤j¤p */ + POPH *cache; /* Thor.990522: ¦s .DIR */ + + char userid[IDLEN + 1]; + char passwd[PASSLEN + 1]; + char home[IDLEN + 4]; /* Thor.990122: 4Ó¦r¤¸¤¤, 2Ó¬O'/', 1Ó¬O^¤å¦r 1Ó¬O'\0' */ + + char pool[SNDBUFSIZ]; /* output pool */ + int locus; /* Thor.990522: output pool ¤º¥i°edata¤§¶q */ + + char *body; /* mail body */ + char *bptr; /* Thor.990522: body pointer, ¤w°e¦h¤Ö */ + + int lcur; /* Thor.990522: ¥Ø«e°e¦Üþ¦æ */ + int lmax; /* Thor.990522: ³Ì¤j¦æ¼Æ */ + + int xbytes; /* Thor.990522: ¶Ç°eÁ`¶q */ +} Client; + + +/* ----------------------------------------------------- */ +/* connection state */ +/* ----------------------------------------------------- */ + + +#define CS_FREE 0x00 /* Thor.990522: ¥Ø«e¥¼¥Î */ +#define CS_READ 0x01 /* Thor.990522: µ¥«Ýuser¿é¤J */ +#define CS_INDEX 0x02 /* Thor.990522: «H½c±ø¦C */ +#define CS_UIDL 0x03 /* Thor.990522: uniq id±ø¦C */ +#define CS_FILE 0x04 /* Thor.990522: «H¥ó¶Ç°e¤¤ */ +#define CS_WRITE 0x05 /* Thor.990522: ¶Ç°e¤¤ */ +#define CS_FLUSH 0x06 /* Thor.990522: ³Ì²×¤@¦¸¶Ç°e */ + + +#define CM_LOGIN 1 +#define CM_DIRTY 2 /* ¦³§R°£«H¥ó */ + + +/* ----------------------------------------------------- */ +/* operation log and debug information */ +/* ----------------------------------------------------- */ + + +static FILE *flog; /* log file descriptor */ +static int gline; + + +#ifdef WATCH_DOG +# define MYDOG gline = __LINE__ +#else +# define MYDOG /* NOOP */ +#endif + + +static void +logit(key, msg) + char *key; + char *msg; +{ + time_t now; + struct tm *p; + + time(&now); + p = localtime(&now); + fprintf(flog, "%02d/%02d %02d:%02d:%02d %-8s%s\n", + p->tm_mon + 1, p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec, key, msg); +} + + +static void +log_init() +{ + FILE *fp; + + if (fp = fopen(POP3_PIDFILE, "w")) + { + fprintf(fp, "%d\n", getpid()); + fclose(fp); + } + + flog = fopen(POP3_LOGFILE, "a"); + logit("START", "pop3 daemon"); +} + + +/* ----------------------------------------------------- */ +/* parse string token */ +/* ----------------------------------------------------- */ + + +#define LOWER 1 + + +static char *trail_token; + + +static char * +parse_token(str, lower) + char *str; + int lower; +{ + char *token; + int ch; + + if (str == NULL) + { + str = trail_token; + if (str == NULL) + return NULL; + } + + token = NULL; + while (ch = *str) + { + if (ch == ' ' /* || ch == '\t' || ch == '\r' || ch == '\n' */ ) + { + if (token) + { + *str++ = '\0'; + break; + } + } + else + { + if (token == NULL) + token = str; + + if (lower && ch >= 'A' && ch <= 'Z') + *str = ch | 0x20; + } + str++; + } + + trail_token = str; + return token; +} + + +/* ----------------------------------------------------- */ +/* server side stuff */ +/* ----------------------------------------------------- */ + + +static void +mbox_open(cn) + Client *cn; +{ + int fd, fsize, pbytes, pad; + struct stat st; + char fpath[80], *fname; + POPH *hdr; + + cn->pcount = cn->pbytes = 0; + /* Thor.990522: cache, body µ¥, ¤w¦b accept®Éinitial */ + + sprintf(fpath, "%s"FN_DIR, cn->home); + fd = open(fpath, O_RDONLY); + + if (fd < 0) + return; + + if (fstat(fd, &st) || (fsize = st.st_size) < sizeof(HDR)) + { + close(fd); + return; + } + + hdr = (POPH *) malloc(fsize); + fsize = read(fd, hdr, fsize) / sizeof(HDR); + close(fd); + + if (fsize <= 0) + { + free(hdr); + return; + } + + cn->cache = hdr; + cn->pcount = fsize; + pbytes = 0; + fname = strchr(fpath, '.'); + *fname++ = '@'; + *fname++ = '/'; + + pad = 10 + strlen(cn->userid) + strlen(POP3_FQDN) + 9 + 44; + for (;;) + { + char *author; + int psize; + + strcpy(fname, hdr->xname); + psize = 0; + if (!stat(fpath, &st)) + psize = st.st_size; + + author = hdr->owner; + if (!strchr(author, '@')) + strcat(author, POP3_FQDN); + + psize += pad + strlen(author) + strlen(hdr->title) + 10 + 40 + 80; + + hdr->pmode = 0; + hdr->psize = psize; + pbytes += psize; + + if (--fsize == 0) + break; + + hdr++; + } + cn->pbytes = pbytes; +} + + +static void +mbox_read(cn, phdr, lmax) + Client *cn; + POPH *phdr; + int lmax; /* Thor.990522: ¤¹³\¤§Á`¦æ¼Æ */ +{ + char *pool, *head, *body, buf[80]; + /* struct tm *mytm; */ + int fd; + + /* mytm = localtime(&phdr->chrono); + strftime(buf, 46, "%a, %e %h %Y %T +0800 (%Z)", mytm); */ + + + pool = cn->pool; + sprintf(pool, "+OK %d octets\r\nFrom: %s\r\nTo: %s%s\r\n" + "Subject: %s\r\nDate: %s\r\n%s\r\n", + phdr->psize, phdr->owner, cn->userid, POP3_FQDN, + phdr->title, Atime(&phdr->chrono), (phdr->xmode & MAIL_READ ? "Status: RO\r\n" : "")); + + head = pool + strlen(pool); + if (!lmax) + { + *head++ = '.'; + *head++ = '\r'; + *head++ = '\n'; + cn->locus = head - pool; + cn->state = CS_WRITE; + return; + } + + cn->locus = head - pool; + cn->state = CS_FILE; + + if (body = cn->body) + { + /* Thor.990522: ¦³°õ¦æªº¾÷·|¶Ü? */ + free(body); + } + body = NULL; + + sprintf(buf, "%s@/%s", cn->home, phdr->xname); + fd = open(buf, O_RDONLY); + if (fd >= 0) + { + int size; + struct stat st; + + if (!fstat(fd, &st) && ((size = st.st_size) > 0)) + { + if (body = (char *) malloc(size + 1)) + { + size = read(fd, body, size); + if (size > 0) + { + body[size] = '\0'; + } + else + { + free(body); + body = NULL; + } + } + } +#if 0 + else + { + phdr->pmode = MAIL_DELETE; + *head++ = '.'; + *head++ = '\r'; + *head++ = '\n'; + cn->locus = head - pool; + cn->state = CS_WRITE; + lmax = 0; + } +#endif + close(fd); + } + + if (!body) /* Thor.991220: for open fail, size==0, and read fail */ + { + phdr->pmode = MAIL_DELETE; + cn->mode = CM_DIRTY; /* Thor.991221: for incorrect mail delete */ + *head++ = '.'; + *head++ = '\r'; + *head++ = '\n'; + cn->locus = head - pool; + cn->state = CS_WRITE; + lmax = 0; + } + + cn->bptr = cn->body = body; + cn->lcur = 0; + cn->lmax = lmax; +} + + +static void +mbox_close(cn) + Client *cn; +{ + int n, max, saved; + FILE *fpr, *fpw; + char fpath[80], fold[80], fnew[80], *fname; + HDR mhdr; + POPH *phdr; + + sprintf(fold, "%s"FN_DIR, cn->home); + if ((fpr = fopen(fold, "r")) == NULL) + return; + + fpw = f_new(fold, fnew); + if (fpw == NULL) + { + fclose(fpr); + return; + } + + strcpy(fpath, fold); + fname = strchr(fpath, '.'); + *fname++ = '@'; + *fname++ = '/'; + + n = saved = 0; + max = cn->pcount; + phdr = cn->cache; + + while (fread(&mhdr, sizeof(mhdr), 1, fpr) == 1) + { + if (n >= max || !phdr->pmode) + { + saved = fwrite(&mhdr, sizeof(mhdr), 1, fpw); + if (saved <= 0) + { + saved = -1; + break; + } + } + else + { + strcpy(fname, mhdr.xname); + unlink(fpath); + } + n++; + phdr++; + } + fclose(fpr); + fclose(fpw); + + if (saved < 0) + { + unlink(fnew); + } + else if (saved) + { + rename(fnew, fold); + } + else + { + unlink(fnew); + unlink(fold); + } +} + + +static void +mbox_index(cn, state) + Client *cn; + int state; +{ + char *pool, *head, *tail; + int cur, max; + POPH *hdr; + + pool = cn->pool; + tail = pool + SNDBUFSIZ - 32; + + cur = cn->lcur; + if (cur) + { + head = pool + cn->locus; + } + else + { + memcpy(pool, "+OK\r\n", 5); + head = pool + 5; + } + + hdr = &cn->cache[cur]; + max = cn->pcount; + do + { + cur++; + + MYDOG; + + if (cur > max) + { + *head++ = '.'; + *head++ = '\r'; + *head++ = '\n'; + cn->state = CS_WRITE; + break; + } + + if (!hdr->pmode) + { + if (state == CS_UIDL) + sprintf(head, "%d %s\r\n", cur, hdr->xname + 1); + else + sprintf(head, "%d %d\r\n", cur, hdr->psize); + head += strlen(head); + } + hdr++; + + } while (head < tail); + + MYDOG; + + cn->locus = head - pool; + cn->lcur = cur; +} + + +static void +mbox_file(cn) + Client *cn; +{ + int lcur, lmax, ch, cx, cc; /* Thor.990522: ±±¨î³æ¦æ³Ì¤j¶Ç°e¶q, Char Count */ + char *bptr, *pool, *head, *tail; + + /* send out a text file in MIME mode */ + + bptr = cn->bptr; + if (!bptr) + return; + + MYDOG; + + pool = cn->pool; + head = pool + cn->locus; + tail = pool + SNDBUFSIZ - SNDLINSIZ - 4 - 3; /* Thor.991129: µ²§Àªº.\r\n 3¦r */ + + lcur = cn->lcur; + lmax = cn->lmax; + cx = '\n'; cc = 0; + + while (ch = *bptr) + { + /* Thor.990522: ±±¨î³æ¦æ³Ì¤j¶Ç°e¶q, Char Count. ¼g±oÁà¤FÂI, ·|¶]´N¦n:p */ + if (cc++ >= SNDLINSIZ) + ch = '\n'; + else + bptr++; + + if (ch == '\r') + continue; + + if (ch == '\n') + { + cc = 0; /* Thor.990522: ±±¨î³æ¦æ³Ì¤j¶Ç°e¶q, Char Count */ + + *head++ = '\r'; + *head++ = '\n'; + if (++lcur >= lmax) + break; + + if (head > tail) + { + cn->state = CS_FILE; + cn->bptr = bptr; + cn->lcur = lcur; + cn->locus = head - pool; + return; + } + cx = ch; + continue; + } + + if (ch == '.' && cx == '\n') + *head++ = ch; + + *head++ = ch; + cx = ch; + } + + /* end of mail body transmission */ + +#if 1 + /* Thor.981206: Odysseus patch: + §@ªÌ Odysseus.bbs@bbs.cs.nccu.edu.tw (¥Ñ°ø¤J»üÃø~~), ¬ÝªO plan + ¼ÐÃD Re: bpop3d? + ®É¶¡ ¬F¤j¿ßªÅ¦æÀ] (Thu Oct 15 01:19:56 1998) +¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w +¡° ¤Þz¡mdreamer.bbs@Rouge.Dorm10.NCTU.edu.tw (¸H¤ß«÷¹Ï)¡n¤§»Ê¨¥¡G +: ¦ý¬O¹ê»Ú¥Î Netscape Messager ¥h¸Õ¸Õ¬Ý, +: ±o¨ìÁ`¦@«H¥ó¼Æ¥Ø¤§«á, +: ·ín¥h retreive ²Ä¤@«Ê«H´N·í¦í¤F....-_- +: ps. Solaris 2.5.1, Maple 3.02 + */ + *head++ = '\r'; + *head++ = '\n'; +#endif + + *head++ = '.'; + *head++ = '\r'; + *head++ = '\n'; + cn->locus = head - pool; + cn->state = CS_WRITE; + + MYDOG; + free(cn->body); + MYDOG; + cn->bptr = cn->body = NULL; +} + + +/* ----------------------------------------------------- */ +/* supporting commands */ +/* ----------------------------------------------------- */ + + +static void cmd_xxxx(); +static void client_flush(); /* Thor.991221: µù¸Ñ: ¤£¥Î¦bmsg¥[ \r\n, µ{¦¡·|¥[ */ + +/* Thor.991221: µù¸Ñ: n¦bmsg¥[ \r\n, µ{¦¡¤£¥[ */ +#define CMD_MSG(cn, msg) \ + cn->state = CS_WRITE; memcpy(cn->pool, msg, cn->locus = sizeof(msg) - 1); + + +static void +do_argument(cn) + Client *cn; +{ + CMD_MSG(cn, POP3_ERRARG_MSG); +} + + +/* return value : -1(all), 0, n */ + + +static int +do_number(cn, n) + Client *cn; + int n; /* 0 ==> exact 1 arg -1 ==> 1 or 0 arg */ +{ + char *cmd; + + if (cn->mode < CM_LOGIN) + { + cmd_xxxx(cn); + return 0; + } + + cmd = parse_token(NULL, 0); + + if (!cmd || !*cmd) + { + if (n == 0) + do_argument(cn); + return n; + } + + n = atoi(cmd); + if (n <= 0 || n > cn->pcount) + { + CMD_MSG(cn, POP3_ERRNUM_MSG); + return 0; + } + + return n; +} + + +/* ----------------------------------------------------- */ +/* main commands */ +/* ----------------------------------------------------- */ + + +static void +cmd_xxxx(cn) + Client *cn; +{ + CMD_MSG(cn, POP3_ERRCMD_MSG); +} + + +static void +cmd_noop(cn) + Client *cn; +{ + CMD_MSG(cn, "+OK\r\n"); +} + + +static void +cmd_user(cn) + Client *cn; +{ + int fd; + ACCT acct; + char *userid, *ptr, fpath[80], msg[128]; + char *msg_no_user = "-ERR no such user in our server"; + + MYDOG; + + if (cn->mode >= CM_LOGIN) + { + cmd_xxxx(cn); + return; + } + + userid = parse_token(NULL, LOWER); + + if (!userid || !*userid) + { + do_argument(cn); + return; + } + + /* userid is "userid.bbs" or "userid" */ + + if (ptr = strchr(userid, '.')) + { + if (strcmp(ptr, ".bbs")) + { + client_flush(cn, msg_no_user); + return; + } + *ptr = '\0'; + } + + /* Thor.981122: chc@gaisnews.iis.sinica.edu.tw patch: + ¥i¯àµo¥Íªº°ÝÃD: + ·í connect ¨ì bpop3d ®É, ¦pªG¿é¤J userid ¤Óªø, ´N·|³y¦¨ overflow, + ª¬ªp»´®É·| disconnect, ÄY«®É·|¨Ï bpop3d segmentation fault. + ¦³¤ß¤H¤h¥i¯à·|¥H¦¹¯}Ãa¨t²Îªº¦w¥þ©Ê. */ + /* Thor.990122: check §¹ *.bbs ¦A¬Ý idlen */ + if (strlen(userid) > IDLEN) + { + client_flush(cn, msg_no_user); + return; + } + +#ifdef DEBUG + if (!strcmp(userid, STR_SYSOP)) /* ¥u¦³ sysop ¨ú«H¤~ debug */ + { + cn->debug = 1; + } +#endif + + ptr = cn->home; + sprintf(ptr, "%c/%s/", *userid, userid); + sprintf(fpath, "%s.ACCT", ptr); + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + read(fd, &acct, sizeof(ACCT)); + close(fd); + + if (acct.userlevel & PERM_DENYLOGIN) + { + sprintf(msg, "-ERR %s denied", acct.userid); + } + else + { + strcpy(cn->userid, acct.userid); + memcpy(cn->passwd, acct.passwd, PASSLEN + 1); + /* SoC: follow the behavior of qpopper */ + /* sprintf(msg, "+OK Password required for %s%s", acct.userid, POP3_FQDN); */ + sprintf(msg, "+OK Password required for %s.", acct.userid); + } + } + else + { + strcpy(msg, msg_no_user); + } + + client_flush(cn, msg); +} + + +static void +cmd_password(cn) + Client *cn; +{ + char *cmd, *passwd, msg[128]; + + MYDOG; + + if (cn->mode >= CM_LOGIN) + { + cmd_xxxx(cn); + return; + } + + passwd = cn->passwd; + MYDOG; + if (!*passwd) + { + CMD_MSG(cn, "-ERR need USER command\r\n"); /* Thor.991221: ¥[¤W \r\n */ + return; + } + + cmd = trail_token; /* to support password with [space] */ + + /* cmd = parse_token(NULL, 0); */ + + if (!cmd || !*cmd) + { + do_argument(cn); + return; + } + + MYDOG; + /* Thor.990214: ²Î¤@¥Î dao library */ + /* if (!checkpasswd(passwd, cmd)) */ + if (chkpasswd(passwd, cmd)) + { + fprintf(flog, "PASS\t[%d]\t%s\n", cn->sno, cn->userid); + + MYDOG; + *passwd = '\0'; + CMD_MSG(cn, "-ERR password incorrect\r\n"); /* Thor.991221: ¥[¤W \r\n */ + return; + } + + MYDOG; + mbox_open(cn); + + MYDOG; + sprintf(msg, "+OK %s has %d messages (%d octets)", + cn->userid, cn->pcount, cn->pbytes); + + MYDOG; + client_flush(cn, msg); + + MYDOG; + fprintf(flog, "ENTER\t[%d]%s\n", cn->sno, msg + 3); + + MYDOG; + cn->mode = CM_LOGIN; +} + + +static void +cmd_stat(cn) + Client *cn; +{ + char *ptr; + + if (cn->mode < CM_LOGIN) + { + cmd_xxxx(cn); + return; + } + + ptr = cn->pool; + sprintf(ptr, "+OK %d %d\r\n", cn->pcount, cn->pbytes); + cn->locus = strlen(ptr); + cn->state = CS_WRITE; +} + + +static void +cmd_last(cn) + Client *cn; +{ + char *ptr; + + if (cn->mode < CM_LOGIN) + { + cmd_xxxx(cn); + return; + } + + ptr = cn->pool; + sprintf(ptr, "+OK %d\r\n", cn->pcount); + cn->locus = strlen(ptr); + cn->state = CS_WRITE; +} + + +static void +cmd_reset(cn) + Client *cn; +{ + int n, max; + POPH *phdr; + char *ptr; + + n = cn->mode; + if (n < CM_LOGIN) + { + cmd_xxxx(cn); + return; + } + + max = cn->pcount; + if (n == CM_DIRTY) + { + for (n = 0, phdr = cn->cache; n < max; phdr++, n++) + phdr->pmode = 0; + } + + ptr = cn->pool; + sprintf(ptr, "+OK mail reset %d messages %d octets\r\n", max, cn->pbytes); + cn->locus = strlen(ptr); + cn->mode = CM_LOGIN; + cn->state = CS_WRITE; +} + + +static void +cmd_retrive(cn) + Client *cn; +{ + int n; + POPH *phdr; + + n = do_number(cn, 0); + if (!n) + return; + + phdr = &cn->cache[n - 1]; + if (phdr->pmode) + { + CMD_MSG(cn, POP3_DELETE_MSG); + return; + } + + mbox_read(cn, phdr, 0x400000); +} + + +static void +cmd_top(cn) + Client *cn; +{ + int n; + POPH *phdr; + char *cmd; + + MYDOG; + + n = do_number(cn, 0); + if (!n) + return; + + phdr = &cn->cache[n - 1]; + if (phdr->pmode) + { + CMD_MSG(cn, POP3_DELETE_MSG); + return; + } + + cmd = parse_token(NULL, 0); + + if (!cmd || !*cmd) + { + do_argument(cn); + return; + } + + n = atoi(cmd); + if (n < 0) + { + CMD_MSG(cn, POP3_ERRNUM_MSG); + return; + } + + mbox_read(cn, phdr, n); +} + + +static void +cmd_delete(cn) + Client *cn; +{ + int n; + POPH *phdr; + + MYDOG; + + if (!(n = do_number(cn, 0))) + return; + + phdr = &cn->cache[n - 1]; + if (phdr->pmode) + { + CMD_MSG(cn, POP3_DELETE_MSG); + return; + } + + phdr->pmode = MAIL_DELETE; + cn->mode = CM_DIRTY; + CMD_MSG(cn, "+OK message deleted\r\n"); +} + + +static void +cmd_list(cn) + Client *cn; +{ + int n; + POPH *phdr; + char buf[80]; + + MYDOG; + + n = do_number(cn, -1); + + MYDOG; + + if (n < 0) + { + cn->lcur = 0; + cn->state = CS_INDEX; + } + else if (n > 0) + { + phdr = &cn->cache[n - 1]; + if (phdr->pmode) + { + CMD_MSG(cn, POP3_DELETE_MSG); + } + else + { + sprintf(buf, "+OK %d %d", n, phdr->psize); + client_flush(cn, buf); + } + } +} + + +static void +cmd_uidl(cn) + Client *cn; +{ + int n; + POPH *phdr; + char buf[80]; + + n = do_number(cn, -1); + + if (n < 0) + { + cn->lcur = 0; + cn->state = CS_UIDL; + } + else if (n > 0) + { + phdr = &cn->cache[n - 1]; + if (phdr->pmode) + { + CMD_MSG(cn, POP3_DELETE_MSG); + } + else + { + sprintf(buf, "+OK %d %s", n, phdr->xname + 1); + client_flush(cn, buf); + } + } +} + + +static void +cmd_quit(cn) + Client *cn; +{ + if (cn->mode >= CM_DIRTY) + { + mbox_close(cn); + } + + fprintf(flog, "QUIT\t[%d] %s S%d T%d\n", + cn->sno, cn->userid, cn->xbytes, time(0) - cn->tbirth); + + cn->state = CS_FLUSH; + strcpy(cn->pool, POP3_BYE_MSG); + cn->locus = POP3_BYE_LEN; +} + + +typedef struct +{ + char *cmd; + void (*fun) (); +} PopCmd; + + +static PopCmd cmdlist[] = +{ + "list", cmd_list, + "uidl", cmd_uidl, + "retr", cmd_retrive, + "dele", cmd_delete, + + "user", cmd_user, + "pass", cmd_password, + "stat", cmd_stat, + "quit", cmd_quit, + + "last", cmd_last, + "top", cmd_top, + + "rset", cmd_reset, + "noop", cmd_noop, + NULL, cmd_xxxx +}; + + +/* ----------------------------------------------------- */ +/* put a line into client's buffer, padding with "\r\n" */ +/* ----------------------------------------------------- */ + + +static void +client_flush(cn, msg) + Client *cn; + char *msg; +{ + char *pool, *head; + + head = pool = cn->pool; + + +#if 0 /* itoc.010606: ¦pªG client ¬O¥H´«¦æ¦r¤¸¨Ó§P§O°T®§µ²§ôªº¸Ü¡A´N·|¥d¦º¤F */ + while (*head++ = *msg++) + ; +#endif + while (*head = *msg++) + head++; + + + /* SoC: Previous trick causes the output msg ending with "00 0D 0A" */ + head--; + + *head++ = '\r'; + *head++ = '\n'; + cn->locus = head - pool; + cn->state = CS_WRITE; +} + + +/* ----------------------------------------------------- */ +/* send data to client */ +/* ----------------------------------------------------- */ + + +static int +client_write(cn) + Client *cn; +{ + int len, cc; + char *data; + + len = cn->locus; + data = cn->pool; + MYDOG; + cc = send(cn->sock, data, len, 0); + MYDOG; + + if (cc <= 0) + { + MYDOG; + cc = errno; + if (cc != EWOULDBLOCK) + { + fprintf(flog, "SEND\t[%d] %s\n", cn->sno, strerror(cc)); + return 0; + } + + return -1; /* would block, so leave it to do later */ + } + +#ifdef DEBUG + if (cn->debug) + { + char msg[SNDBUFSIZ + 10]; + sprintf(msg, "%s\t[%d]bpop3>>>\n", Now(), cn->sno); + f_cat(POP3_DEBUGFILE, msg); + str_ncpy(msg, data, len+1); + f_cat(POP3_DEBUGFILE, msg); + sprintf(msg, "\t[%d]bpop3<<<\n", cn->sno); + f_cat(POP3_DEBUGFILE, msg); + MYDOG; + } +#endif + + MYDOG; + cn->xbytes += cc; + MYDOG; + len -= cc; + MYDOG; + cn->locus = len; + MYDOG; + if (len) + { + MYDOG; + memcpy(data, data + cc, len); + MYDOG; + return cc; + } + + MYDOG; + len = cn->state; + MYDOG; + + if (len == CS_FLUSH) + return 0; + + if (len == CS_WRITE) + cn->state = CS_READ; + + MYDOG; + return cc; +} + + +/* ----------------------------------------------------- */ +/* client's service dispatcher */ +/* ----------------------------------------------------- */ + + +static void +client_serve(cn) + Client *cn; +{ + char *cmd, *str; + PopCmd *pc; + + cn->locus = 0; /* reset buffer pool position */ + + cmd = parse_token(cn->pool, LOWER); + + if (!cmd || !*cmd) + return; + + for (pc = cmdlist; str = pc->cmd; pc++) + { + if (!strcmp(cmd, str)) + break; + } + +#ifdef DEBUG + logit(cmd, cn->userid); +#endif + + MYDOG; + (*pc->fun) (cn); + MYDOG; + +#ifdef DEBUG + { + char buf[80]; + + /* Thor.990222: ©È str§ä¤£¨ìcmd®É ¬° NULL */ + /* sprintf(buf, "%s-", str); */ + sprintf(buf, "%s-", cmd); + logit(buf, cn->userid); + } +#endif +} + + +/* ----------------------------------------------------- */ +/* receive command from client */ +/* ----------------------------------------------------- */ + + +static int +client_read(cn) + Client *cn; +{ + int cc, pos, len; + char *str; + + MYDOG; + + pos = cn->locus; + str = &cn->pool[pos]; + len = recv(cn->sock, str, RCVBUFSIZ, 0); + + if (len <= 0) + { + cc = errno; + if (cc != EWOULDBLOCK) + { + fprintf(flog, "RECV\t[%d] %s\n", cn->sno, strerror(cc)); + return 0; + } + + return -1; + } + + str[len] = '\0'; + +#ifdef DEBUG + if (cn->debug) + { + char msg[80]; + sprintf(msg, "%s\t[%d]peer>>>\n", Now(), cn->sno); + f_cat(POP3_DEBUGFILE, msg); + f_cat(POP3_DEBUGFILE, str); + sprintf(msg, "\t[%d]peer<<<\n", cn->sno); + f_cat(POP3_DEBUGFILE, msg); + } +#endif + + while (cc = *str) + { + switch (cc) + { + case '\r': + case '\n': + *str = '\0'; + client_serve(cn); + return 1; + + case '\t': + *str = ' '; + } + str++; + } + + pos += len; + if (pos >= RCVBUFSIZ) + { + sprintf(str, "[%d] buffer overflow", cn->sno); + logit("HACK", str); + return 0; + } + + cn->locus = pos; + return 1; +} + + +/* ----------------------------------------------------- */ +/* release idle/timeout connections */ +/* ----------------------------------------------------- */ + + +static void +client_close(cn) + Client *cn; +{ + int sock; + char *ptr; + + if (cn->mode >= CM_LOGIN) + { + if (ptr = (char *) cn->cache) + free(ptr); + + if (ptr = cn->body) + free(ptr); + } + + sock = cn->sock; + shutdown(sock, 2); + close(sock); +} + + +/* ----------------------------------------------------- */ +/* server core routines */ +/* ----------------------------------------------------- */ + + +static void +/* start_daemon() */ +servo_daemon(inetd) + int inetd; +{ + int fd, value; + char buf[80]; + struct sockaddr_in sin; + struct linger ld; +#ifdef HAVE_RLIMIT + struct rlimit limit; +#endif + + /* + * More idiot speed-hacking --- the first time conversion makes the C + * library open the files containing the locale definition and time zone. + * If this hasn't happened in the parent process, it happens in the + * children, once per connection --- and it does add up. + */ + + time((time_t *)&value); + gmtime((time_t *)&value); + strftime(buf, 80, "%d/%b/%Y:%H:%M:%S", localtime((time_t *)&value)); + +#ifdef HAVE_RLIMIT + /* --------------------------------------------------- */ + /* adjust the resource limit */ + /* --------------------------------------------------- */ + + limit.rlim_cur = limit.rlim_max = 8 * 1024 * 1024; + setrlimit(RLIMIT_DATA, &limit); + +#ifdef SOLARIS +#define RLIMIT_RSS RLIMIT_AS /* Thor.981206: port for solaris 2.6 */ +#endif + + setrlimit(RLIMIT_RSS, &limit); + + limit.rlim_cur = limit.rlim_max = 0; + setrlimit(RLIMIT_CORE, &limit); +#endif + + /* --------------------------------------------------- */ + /* detach daemon process */ + /* --------------------------------------------------- */ + + close(2); + close(1); + + if (inetd) + return; + + close(0); + + if (fork()) + exit(0); + + setsid(); + + if (fork()) + exit(0); + + /* --------------------------------------------------- */ + /* setup socket */ + /* --------------------------------------------------- */ + + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + value = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value, sizeof(value)); + + ld.l_onoff = ld.l_linger = 0; + setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &ld, sizeof(ld)); + + sin.sin_family = AF_INET; + sin.sin_port = htons(POP3_PORT); + sin.sin_addr.s_addr = INADDR_ANY; + memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); + + if (bind(fd, (struct sockaddr *) & sin, sizeof(sin)) || + listen(fd, SOCK_BACKLOG)) + exit(1); +} + + +static void +abort_server() +{ + fclose(flog); + exit(0); +} + + +static void +reaper() +{ + while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0); +} + + +static void +sig_trap(sig) + int sig; +{ + char buf[32]; + + sprintf(buf, "[%d] at %d (err: %d)", sig, gline, errno); + logit("TRAP", buf); + abort_server(); +} + + +#ifdef SERVER_USAGE +static void +server_usage() +{ + struct rusage ru; + + if (getrusage(RUSAGE_SELF, &ru)) + return; + + fprintf(flog, "\n[Server Usage]\n\n" + "user time: %.6f\n" + "system time: %.6f\n" + "maximum resident set size: %lu P\n" + "integral resident set size: %lu\n" + "page faults not requiring physical I/O: %d\n" + "page faults requiring physical I/O: %d\n" + "swaps: %d\n" + "block input operations: %d\n" + "block output operations: %d\n" + "messages sent: %d\n" + "messages received: %d\n" + "signals received: %d\n" + "voluntary context switches: %d\n" + "involuntary context switches: %d\ngline: %d\n\n", + + (double) ru.ru_utime.tv_sec + (double) ru.ru_utime.tv_usec / 1000000.0, + (double) ru.ru_stime.tv_sec + (double) ru.ru_stime.tv_usec / 1000000.0, + ru.ru_maxrss, + ru.ru_idrss, + ru.ru_minflt, + ru.ru_majflt, + ru.ru_nswap, + ru.ru_inblock, + ru.ru_oublock, + ru.ru_msgsnd, + ru.ru_msgrcv, + ru.ru_nsignals, + ru.ru_nvcsw, + ru.ru_nivcsw, gline); + + fflush(flog); +} +#endif + + +/* ----------------------------------------------------- */ +/* signal routines */ +/* ----------------------------------------------------- */ + + +static void +main_signals() +{ + struct sigaction act; + + /* sigblock(sigmask(SIGPIPE)); */ /* Thor.981206: ²Î¤@ POSIX ¼Ð·Ç¥Îªk */ + + /* act.sa_mask = 0; */ /* Thor.981105: ¼Ð·Ç¥Îªk */ + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + act.sa_handler = sig_trap; + sigaction(SIGBUS, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + + act.sa_handler = reaper; + sigaction(SIGCHLD, &act, NULL); + + act.sa_handler = abort_server; + sigaction(SIGTERM, &act, NULL); + +#ifdef SERVER_USAGE + act.sa_handler = server_usage; + sigaction(SIGPROF, &act, NULL); +#endif + + /* Thor.981206: lkchu patch: ²Î¤@ POSIX ¼Ð·Ç¥Îªk */ + /* ¦b¦¹É¥Î sigset_t act.sa_mask */ + sigaddset(&act.sa_mask, SIGPIPE); + sigprocmask(SIG_BLOCK, &act.sa_mask, NULL); + +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int main_sno, csock, nfds, state; + Client **FBI, *Scully, *Mulder, *cn; + fd_set rset, wset, xset; + struct timeval tv; + time_t uptime, tcheck; + + state = 0; + + while ((nfds = getopt(argc, argv, "hid")) != -1) + { + switch (nfds) + { + case 'i': + state = 1; + break; + + case 'd': + break; + + case 'h': + default: + + fprintf(stderr, "Usage: %s [options]\n" + "\t-i start from inetd with wait option\n" + "\t-d debug mode\n" + "\t-h help\n", + argv[0]); + exit(0); + } + } + + servo_daemon(state); + /* start_daemon(); */ + + setgid(BBSGID); + setuid(BBSUID); + chdir(POP3_HOME); + main_signals(); + + umask(077); + log_init(); + +#if 0 + dns_init(); +#endif + + tv.tv_sec = POP3_TIMEOUT; + tv.tv_usec = 0; + + tcheck = time(0) + POP3_TIMEOUT; + Scully = Mulder = NULL; + main_sno = 0; + + for (;;) + { + /* resource and garbage collection */ + + uptime = time(0); + if (tcheck < uptime) + { + tcheck = uptime - POP3_TIMEOUT; + + for (FBI = &Scully; cn = *FBI;) + { + if (cn->uptime < tcheck) + { + client_close(cn); + + *FBI = cn->next; + + cn->next = Mulder; + Mulder = cn; + } + else + { + FBI = &(cn->next); + } + } + + fflush(flog); + tcheck = uptime + POP3_TIMEOUT; + } + + /* ------------------------------------------------- */ + /* Set up the fdsets */ + /* ------------------------------------------------- */ + + FD_ZERO(&rset); + FD_ZERO(&wset); + FD_ZERO(&xset); + + FD_SET(0, &rset); + nfds = 0; + + for (cn = Scully; cn; cn = cn->next) + { + csock = cn->sock; + state = cn->state; + + if (nfds < csock) + nfds = csock; + + if (state == CS_READ) + { + FD_SET(csock, &rset); + } + else + { + switch (state) + { + case CS_FILE: + mbox_file(cn); + break; + + case CS_INDEX: + case CS_UIDL: + mbox_index(cn, state); + break; + } + + FD_SET(csock, &wset); + } + + FD_SET(csock, &xset); + } + + { + struct timeval tv_tmp = tv; + /* Thor.981221: for future reservation bug */ + nfds = select(nfds + 1, &rset, &wset, &xset, &tv_tmp); + } + + if (nfds == 0) + { + continue; + } + + if (nfds < 0) + { + csock = errno; + if (csock != EINTR) + { + logit("select", strerror(csock)); + } + continue; + } + + /* ------------------------------------------------- */ + /* serve active agents */ + /* ------------------------------------------------- */ + + uptime = time(0); + + for (FBI = &Scully; cn = *FBI;) + { + csock = cn->sock; + + if (FD_ISSET(csock, &wset)) + { + MYDOG; + state = client_write(cn); + MYDOG; + } + else if (FD_ISSET(csock, &rset)) + { + MYDOG; + state = client_read(cn); + MYDOG; + } + else if (FD_ISSET(csock, &xset)) + { + MYDOG; + state = 0; + MYDOG; + } + else + { + state = -1; + } + + if (state == 0) /* fire this agent */ + { + client_close(cn); + + *FBI = cn->next; + + cn->next = Mulder; + Mulder = cn; + + continue; + } + + if (state > 0) + { + MYDOG; + cn->uptime = uptime; + MYDOG; + } + + MYDOG; + FBI = &(cn->next); + MYDOG; + } + + /* ------------------------------------------------- */ + /* serve new connection */ + /* ------------------------------------------------- */ + + if (FD_ISSET(0, &rset)) + { + /* Thor.990222: ¬d¥X¹ï¤è ip */ + int len; + struct sockaddr_in csin; + len = sizeof csin; + + for (;;) + { + /* csock = accept(0, NULL, NULL); */ + /* Thor.990222: ¬d¥X¹ï¤è ip */ + csock = accept(0, (struct sockaddr *)&csin, &len); + + if (csock > 0) + break; + + state = errno; + if (state != EINTR) + { + logit("accept", strerror(state)); + break; + } + + while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0); + } + + if (csock <= 0) + continue; + + if (cn = Mulder) + { + Mulder = cn->next; + } + else + { + cn = (Client *) malloc(sizeof(Client)); + } + + *FBI = cn; + + /* variable initialization */ + + /* sprintf(cn->pool, "[%d]", ++main_sno); */ + /* Thor.990222: ¬d¥X¹ï¤è ip */ + sprintf(cn->pool, "[%d] ip:%08x", ++main_sno, csin.sin_addr.s_addr); + logit("CONN", cn->pool); + + cn->next = NULL; + cn->sock = csock; + cn->sno = main_sno; + +#ifdef DEBUG + cn->debug = 0; +#endif + cn->mode = 0; + cn->passwd[0] = '\0'; + cn->cache = NULL; + cn->body = NULL; + cn->bptr = NULL; + + cn->state = CS_WRITE; + sprintf(cn->pool, "+OK MapleBBS POP3 server ready\r\n"); + cn->locus = strlen(cn->pool); + cn->tbirth = cn->uptime = uptime; + cn->xbytes = 0; + } + + /* ------------------------------------------------- */ + /* tail of main loop */ + /* ------------------------------------------------- */ + } +} diff --git a/daemon/gemd.c b/daemon/gemd.c new file mode 100644 index 0000000..379145a --- /dev/null +++ b/daemon/gemd.c @@ -0,0 +1,1066 @@ +/*-------------------------------------------------------*/ +/* util/gemd.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : BBS gopher daemon */ +/* create : 96/11/20 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ +/* syntax : gemd */ +/*-------------------------------------------------------*/ +/* notice : single process concurrent server */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#include <netinet/tcp.h> +#include <sys/wait.h> +#include <sys/resource.h> + + +#define WATCH_DOG +#define SERVER_USAGE + + +#define GEMD_LOGFILE "run/gemd.log" +#define GEMD_PIDFILE "run/gemd.pid" + + +#define GEMD_PERIOD (60 * 30) +#define GEMD_TIMEOUT (60 * 10) + + +#define TCP_QLEN 3 +#define TCP_BUFSIZ (256 * 14) +#define TCP_LINSIZ 256 +#define TCP_RCVSIZ 512 + + +/* ----------------------------------------------------- */ +/* client connection structure */ +/* ----------------------------------------------------- */ + + +typedef struct Agent +{ + struct Agent *anext; + int state; + int sock; + int sno; + time_t tbegin; /* «Ø¥ß connection ªº®É¶¡ */ + time_t uptime; + + FILE *stream; + char zone[64]; + + char pool[TCP_BUFSIZ]; /* buffered I/O pool */ + int locus; + int xdata; +} Agent; + + +#define ap_log(key, sno, msg) fprintf(flog, "%s\t[%d] %s\n", key, sno, msg); + + +/* ----------------------------------------------------- */ +/* connection state */ +/* ----------------------------------------------------- */ + + +#define CS_FREE 0x00 +#define CS_READ 0x01 /* reading command */ +#define CS_FILE 0x02 /* writing file */ +#define CS_INDEX 0x03 /* writing index */ +#define CS_GPLUS 0x04 /* writing index (gopher 2.0+) */ +#define CS_FLUSH 0x05 /* flush data */ + + +/* ----------------------------------------------------- */ +/* operation log and debug information */ +/* ----------------------------------------------------- */ + + +extern int errno; + + +static FILE *flog; /* log file descriptor */ +static int gline; + + +#ifdef WATCH_DOG +# define MYDOG gline = __LINE__ +#else +# define MYDOG /* NOOP */ +#endif + + +static void +logit(key, msg) + char *key; + char *msg; +{ + time_t now; + struct tm *p; + + time(&now); + p = localtime(&now); + fprintf(flog, "%02d/%02d %02d:%02d:%02d %-7s%s\n", + p->tm_mon + 1, p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec, key, msg); +} + + +static inline void +log_open() +{ + FILE *fp; + + umask(077); + + if (fp = fopen(GEMD_PIDFILE, "w")) + { + fprintf(fp, "%d\n", getpid()); + fclose(fp); + } + + flog = fopen(GEMD_LOGFILE, "w"); + logit("START", "gemd (gopher) daemon"); +} + + +/*-------------------------------------------------------*/ +/* BRD shm ³¡¤À¶·»P cache.c ¬Û®e */ +/*-------------------------------------------------------*/ + + +static BCACHE *bshm; + + +static void +init_bshm() +{ + /* itoc.030727: ¦b¶}±Ò bbsd ¤§«e¡AÀ³¸Ó´Nn°õ¦æ¹L account¡A + ©Ò¥H bshm À³¸Ó¤w³]©w¦n */ + + bshm = shm_new(BRDSHM_KEY, sizeof(BCACHE)); + + if (bshm->uptime <= 0) /* bshm ¥¼³]©w§¹¦¨ */ + exit(0); +} + + +/* itoc.030708: ¥[¤WÀˬd¬ÝªOÅvªº³¡¤À¡A¥H§K¦³¤H¶Ã¿å */ + +static int +allow_brdname(brdname) + char *brdname; +{ + BRD *bhdr, *tail; + + bhdr = bshm->bcache; + tail = bhdr + bshm->number; + + do + { + if (!strcmp(bhdr->brdname, brdname)) + { + if (!bhdr->readlevel) + return 1; + break; + } + } while (++bhdr < tail); + + return 0; +} + + +static int +allow_path(fpath) + char *fpath; +{ + char *brdname, *str; + int ret; + + if (!strncmp(fpath, "brd/", 4)) + { + brdname = fpath + 4; + if (str = strchr(brdname, '/')) + { + *str = '\0'; + ret = allow_brdname(brdname); + *str = '/'; + return ret; + } + } + + return 1; +} + + +/* ----------------------------------------------------- */ +/* server side stuff */ +/* ----------------------------------------------------- */ + + +static char * +str_copy(dst, src) + char *dst; + char *src; +{ + int ch; + + while (ch = *src++) + *dst++ = ch; + return dst; +} + + +static FILE * +gem_open(fpath) + char *fpath; +{ + FILE *fp; + int fd; + struct stat st; + + if (!allow_path(fpath)) + return NULL; + + fp = NULL; + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + if (fstat(fd, &st) || !S_ISREG(st.st_mode) || + (st.st_size <= 0) || !(fp = fdopen(fd, "r"))) + { + close(fd); + } + } + return fp; +} + + +/* ----------------------------------------------------- */ +/* transform ASCII file to text-mail format */ +/* ----------------------------------------------------- */ + + +static void +gem_file(ap) + Agent *ap; +{ + char *pool, *head, *tail; + FILE *fp; + int cc; + + fp = ap->stream; + pool = ap->pool; + head = pool + ap->locus; + tail = pool + TCP_BUFSIZ - TCP_LINSIZ; + + while (head < tail) + { + if (!fgets(head, TCP_LINSIZ, fp)) + { + fclose(fp); + ap->stream = NULL; + ap->state = CS_FLUSH; + + *head++ = '.'; + *head++ = '\r'; + *head++ = '\n'; + break; + } + + while (cc = *head) + { + if (cc == '\n') + { + *head++ = '\r'; + *head++ = '\n'; + break; + } + head++; + } + } + ap->locus = head - pool; +} + + +/* ----------------------------------------------------- */ +/* transform FOLDER to gopher index format */ +/* ----------------------------------------------------- */ + + +static void +gem_index(ap) + Agent *ap; +{ + char *pool, *head, *tail, *xname, *zone; + int cc, state, xmode; + FILE *fp; + HDR hdr; + + fp = ap->stream; + zone = ap->zone; + pool = ap->pool; + head = pool + ap->locus; + tail = pool + TCP_BUFSIZ - TCP_LINSIZ; + state = ap->state; + + while (head < tail) + { + if (fread(&hdr, sizeof(hdr), 1, fp) != 1) + { + fclose(fp); + ap->stream = NULL; + ap->state = CS_FLUSH; + + *head++ = '.'; + *head++ = '\r'; + *head++ = '\n'; + break; + } + + xmode = hdr.xmode; + if ((xmode & GEM_RESTRICT) || (hdr.title[0] == '#')) + continue; + + if (state == CS_GPLUS) + head = str_copy(head, "+INFO: "); + + *head++ = cc = (xmode & GEM_FOLDER) ? '1' : '0'; + + head = str_copy(head, hdr.title); + *head++ = '\t'; + + xname = hdr.xname; + + *head++ = cc; + *head++ = '/'; + + if (xmode & GEM_BOARD) + { + brd_fpath(head, xname, FN_DIR); + head += strlen(head); + } + else + { + head = str_copy(head, zone); + + cc = *xname; + if (cc != '@') + cc = xname[7]; + *head++ = cc; + *head++ = '/'; + + head = str_copy(head, xname); + } + + head = str_copy(head, "\t" MYHOSTNAME "\t70\r\n"); + } + ap->locus = head - pool; +} + + +/* ----------------------------------------------------- */ +/* parse the command, check security & serve it */ +/* ----------------------------------------------------- */ + + +static int +agent_serve(ap) + Agent *ap; +{ + char *data, *str, *zone; + int cc; + FILE *fp; + + data = ap->pool; + if (strstr(data, "..") || strstr(data, "//")) + return CS_FREE; + + switch (*data) + { + case '0': + data += 2; + if (*data == '/') + return CS_FREE; + cc = CS_FILE; + break; + + case '1': + if (data[1]) + { + data += 2; + if (*data == '/') + return CS_FREE; + cc = CS_INDEX; + break; + } + + case 0: + data = ".DIR"; + cc = CS_INDEX; + break; + + case '\t': + data = ".DIR"; + cc = CS_GPLUS; + break; + + default: + return CS_FREE; + } + + fp = gem_open(data); + + zone = ap->zone; + *zone = '\0'; + + if (!fp && cc == CS_INDEX && *data != '.' && strlen(data) <= BNLEN) + { + /* map "xyz" to "brd/xyz/.DIR" and try it once again */ + + strcpy(zone, data); + brd_fpath(data, zone, FN_DIR); + fprintf(flog, "MAP\t[%d] %s -> %s\n", ap->sno, zone, data); + fp = gem_open(data); + } + + if (!fp) + return CS_FREE; + + ap->stream = fp; + if (cc != CS_FILE) + { + ap_log("DIR", ap->sno, data); + if (str = strrchr(data, '/')) + { + if (str[1] != '.') + str--; + else + str++; + + while (data < str) + { + *zone++ = *data++; + } + } + *zone = '\0'; + ap_log("ZONE", ap->sno, ap->zone); + } + else + { + ap_log("FILE", ap->sno, data); + } + return cc; +} + + +/* ----------------------------------------------------- */ +/* send output to client */ +/* ----------------------------------------------------- */ + + +static int +agent_send(ap) + Agent *ap; +{ + int sock, len, cc; + char *data; + + sock = ap->sock; + len = ap->locus; + data = ap->pool; + cc = send(sock, data, len, 0); + + if (cc < 0) + { + cc = errno; + if (cc != EWOULDBLOCK) + { + ap_log("send", ap->sno, strerror(cc)); + return 0; + } + + return -1; /* would block, so leave it to do later */ + } + + if (cc == 0) + return -1; + + len -= cc; + ap->xdata += cc; + ap->locus = len; + + if (len) + { + memcpy(data, data + cc, len); + return cc; + } + + if (ap->state == CS_FLUSH) + { + ap->state = CS_FREE; + return 0; + } + + return cc; +} + + +/* ----------------------------------------------------- */ +/* receive request from client */ +/* ----------------------------------------------------- */ + + +static int +agent_recv(ap) + Agent *ap; +{ + int cc; + char *pool, *data; + + pool = ap->pool; + data = pool + ap->locus; + cc = recv(ap->sock, data, TCP_RCVSIZ, 0); + + if (cc <= 0) + { + cc = errno; + if (cc != EWOULDBLOCK) + { + ap_log("RECV", ap->sno, strerror(cc)); + return 0; + } + + return -1; /* would block, so leave it to do later */ + } + + data[cc] = '\0'; + + while (cc = *data) + { + if (cc == '\r' || cc == '\n') + { + /* remove tailing '/' from path */ + + if ((data > pool + 1) && data[-1] == '/' && data[-2] != '/') + data--; + + *data = '\0'; + + ap_log("CMD", ap->sno, pool); + + ap->state = cc = agent_serve(ap); + + if (cc == CS_FREE) + return 0; + + if (cc == CS_GPLUS) + { + strcpy(pool, "+-1\r\n"); + ap->locus = 5; + } + else + { + ap->locus = 0; + } + + return 1; + } + data++; + } + + if ((ap->locus = data - pool) > TCP_RCVSIZ) + { + ap_log("HACK", ap->sno, "buffer overflow"); + return 0; + } + + return 1; +} + + +/* ----------------------------------------------------- */ +/* close a connection & release its resource */ +/* ----------------------------------------------------- */ + + +static void +agent_fire(ap) + Agent *ap; +{ + int sock; + FILE *fp; + + sock = ap->sock; + shutdown(sock, 2); + close(sock); + + if (fp = ap->stream) + fclose(fp); + + fprintf(flog, "%s\t[%d] T%d D%d\n", + ap->state == CS_FREE ? "BYE" : "END", + ap->sno, time(0) - ap->tbegin, ap->xdata); +} + + +/* ----------------------------------------------------- */ +/* accept a new connection */ +/* ----------------------------------------------------- */ + + +static inline int +agent_accept() +{ + int sock; + int value; + + /* gopher do not care remote host / user name */ + + for (;;) + { + sock = accept(0, NULL, NULL); + if (sock > 0) + break; + + sock = errno; + if (sock != EINTR) + { + logit("ACCEPT", strerror(sock)); + return -1; + } + + while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0); + } + + value = 1; + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &value, sizeof(value)); + return sock; +} + + +/* ----------------------------------------------------- */ +/* server core routines */ +/* ----------------------------------------------------- */ + + +static void +servo_daemon(inetd) + int inetd; +{ + int fd, value; + char buf[80]; + struct sockaddr_in fsin; + struct linger ld; +#ifdef HAVE_RLIMIT + struct rlimit limit; +#endif + + /* + * More idiot speed-hacking --- the first time conversion makes the C + * library open the files containing the locale definition and time zone. + * If this hasn't happened in the parent process, it happens in the + * children, once per connection --- and it does add up. + */ + + time((time_t *) &value); + gmtime((time_t *) &value); + strftime(buf, 80, "%d/%b/%Y:%H:%M:%S", localtime((time_t *) &value)); + +#ifdef HAVE_RLIMIT + /* --------------------------------------------------- */ + /* adjust the resource limit */ + /* --------------------------------------------------- */ + + limit.rlim_cur = limit.rlim_max = 4 * 1024 * 1024; + setrlimit(RLIMIT_FSIZE, &limit); + setrlimit(RLIMIT_DATA, &limit); + +#ifdef SOLARIS +#define RLIMIT_RSS RLIMIT_AS /* Thor.981206: port for solaris 2.6 */ +#endif + + setrlimit(RLIMIT_RSS, &limit); + + limit.rlim_cur = limit.rlim_max = 0; + setrlimit(RLIMIT_CORE, &limit); +#endif + + /* --------------------------------------------------- */ + /* detach process */ + /* --------------------------------------------------- */ + + close(1); + close(2); + + if (inetd) + return; + + close(0); + + if (fork()) + exit(0); + + setsid(); + + if (fork()) + exit(0); + + /* --------------------------------------------------- */ + /* setup socket */ + /* --------------------------------------------------- */ + + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + value = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value, sizeof(value)); + +#if 0 + setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &value, sizeof(value)); +#endif + + ld.l_onoff = ld.l_linger = 0; + setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &ld, sizeof(ld)); + + memset((char *) &fsin, 0, sizeof(fsin)); + fsin.sin_family = AF_INET; + fsin.sin_port = htons(GEMD_PORT); + fsin.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(fd, (struct sockaddr *) & fsin, sizeof(fsin)) || + listen(fd, TCP_QLEN)) + exit(1); +} + + +#ifdef SERVER_USAGE +static void +servo_usage() +{ + struct rusage ru; + + if (getrusage(RUSAGE_SELF, &ru)) + return; + + fprintf(flog, "\n[Server Usage]\n\n" + "user time: %.6f\n" + "system time: %.6f\n" + "maximum resident set size: %lu P\n" + "integral resident set size: %lu\n" + "page faults not requiring physical I/O: %d\n" + "page faults requiring physical I/O: %d\n" + "swaps: %d\n" + "block input operations: %d\n" + "block output operations: %d\n" + "messages sent: %d\n" + "messages received: %d\n" + "signals received: %d\n" + "voluntary context switches: %d\n" + "involuntary context switches: %d\n" + "gline: %d\n\n", + + (double) ru.ru_utime.tv_sec + (double) ru.ru_utime.tv_usec / 1000000.0, + (double) ru.ru_stime.tv_sec + (double) ru.ru_stime.tv_usec / 1000000.0, + ru.ru_maxrss, + ru.ru_idrss, + ru.ru_minflt, + ru.ru_majflt, + ru.ru_nswap, + ru.ru_inblock, + ru.ru_oublock, + ru.ru_msgsnd, + ru.ru_msgrcv, + ru.ru_nsignals, + ru.ru_nvcsw, + ru.ru_nivcsw, + gline); + + fflush(flog); +} +#endif + + +static void +reaper() +{ + while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0); +} + + +static void +sig_trap(sig) + int sig; +{ + char buf[80]; + + sprintf(buf, "[%d] at %d", sig, gline); + logit("EXIT", buf); + fclose(flog); + exit(0); +} + + +/* ----------------------------------------------------- */ +/* signal routines */ +/* ----------------------------------------------------- */ + + +static void +servo_signal() +{ + struct sigaction act; + + /* sigblock(sigmask(SIGPIPE)); */ /* Thor.981206: ²Î¤@ POSIX ¼Ð·Ç¥Îªk */ + + /* act.sa_mask = 0; */ /* Thor.981105: ¼Ð·Ç¥Îªk */ + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + act.sa_handler = sig_trap; + sigaction(SIGBUS, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGTERM, &act, NULL); + + act.sa_handler = reaper; + sigaction(SIGCHLD, &act, NULL); + +#ifdef SERVER_USAGE + act.sa_handler = servo_usage; + sigaction(SIGPROF, &act, NULL); +#endif + + /* Thor.981206: lkchu patch: ²Î¤@ POSIX ¼Ð·Ç¥Îªk */ + /* ¦b¦¹É¥Î sigset_t act.sa_mask */ + sigaddset(&act.sa_mask, SIGPIPE); + sigprocmask(SIG_BLOCK, &act.sa_mask, NULL); + +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int sock, nfds, state, servo_sno; + time_t uptime, tcheck; + Agent **FBI, *Scully, *Mulder, *agent; + fd_set rset, wset, xset; + struct timeval tv; + + state = 0; + + while ((nfds = getopt(argc, argv, "hid")) != -1) + { + switch (nfds) + { + case 'i': + state = 1; + break; + + case 'd': + break; + + case 'h': + default: + + fprintf(stderr, "Usage: %s [options]\n" + "\t-i start from inetd with wait option\n" + "\t-d debug mode\n" + "\t-h help\n", + argv[0]); + exit(0); + } + } + + servo_daemon(state); + + setgid(BBSGID); + setuid(BBSUID); + chdir(BBSHOME); + + log_open(); + init_bshm(); + + chdir("gem"); + servo_signal(); + + tcheck = time(0) + GEMD_PERIOD; + Scully = Mulder = NULL; + servo_sno = 0; + + for (;;) + { + uptime = time(0); + if (tcheck < uptime) + { + tcheck = uptime - GEMD_TIMEOUT; + + for (FBI = &Scully; agent = *FBI;) + { + if (agent->uptime < tcheck) + { + agent_fire(agent); + + *FBI = agent->anext; + + agent->anext = Mulder; + Mulder = agent; + } + else + { + FBI = &(agent->anext); + } + } + + fflush(flog); + tcheck = uptime + GEMD_PERIOD; + } + + /* ------------------------------------------------- */ + /* Set up the fdsets */ + /* ------------------------------------------------- */ + + FD_ZERO(&rset); + FD_ZERO(&wset); + FD_ZERO(&xset); + + FD_SET(0, &rset); + nfds = 0; + + for (agent = Scully; agent; agent = agent->anext) + { + sock = agent->sock; + state = agent->state; + + if (nfds < sock) + nfds = sock; + + if (state == CS_READ) + { + FD_SET(sock, &rset); + } + else + { + FD_SET(sock, &wset); + + if (state == CS_FILE) + gem_file(agent); + else if (state == CS_INDEX || state == CS_GPLUS) + gem_index(agent); + } + + FD_SET(sock, &xset); + } + + /* Thor.981206: for reservation future bug */ + tv.tv_sec = GEMD_PERIOD; + tv.tv_usec = 0; + + nfds = select(nfds + 1, &rset, &wset, &xset, &tv); + + if (nfds == 0) + { + continue; + } + + if (nfds < 0) + { + sock = errno; + if (sock != EINTR) + logit("select", strerror(sock)); + continue; + } + + /* ------------------------------------------------- */ + /* serve active agents */ + /* ------------------------------------------------- */ + + uptime = time(0); + + for (FBI = &Scully; agent = *FBI;) + { + sock = agent->sock; + + if (FD_ISSET(sock, &wset)) + { + state = agent_send(agent); + } + else if (FD_ISSET(sock, &rset)) + { + state = agent_recv(agent); + } + else if (FD_ISSET(sock, &xset)) + { + state = 0; + } + else + { + state = -1; + } + + if (state == 0) /* fire this agent */ + { + agent_fire(agent); + + *FBI = agent->anext; + + agent->anext = Mulder; + Mulder = agent; + + continue; + } + + if (state > 0) + { + agent->uptime = uptime; + } + + FBI = &(agent->anext); + } + + /* ------------------------------------------------- */ + /* serve new connection */ + /* ------------------------------------------------- */ + + if (FD_ISSET(0, &rset)) + { + sock = agent_accept(); + if (sock <= 0) + continue; + + if (agent = Mulder) + { + Mulder = agent->anext; + } + else + { + agent = (Agent *) malloc(sizeof(Agent)); + } + + *FBI = agent; + + /* variable initialization */ + + agent->anext = NULL; + agent->state = CS_READ; + agent->sock = sock; + agent->sno = ++servo_sno; + agent->tbegin = uptime; + agent->uptime = uptime; + agent->stream = NULL; + agent->locus = 0; + agent->xdata = 0; + + fprintf(flog, "CONN\t[%d] %s\n", servo_sno, Btime(&agent->tbegin)); + } + + /* ------------------------------------------------- */ + /* tail of main loop */ + /* ------------------------------------------------- */ + } +} diff --git a/daemon/xchatd.c b/daemon/xchatd.c new file mode 100644 index 0000000..f9a40ea --- /dev/null +++ b/daemon/xchatd.c @@ -0,0 +1,4027 @@ +/*-------------------------------------------------------*/ +/* xchatd.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : super KTV daemon for chat server */ +/* create : 95/03/29 */ +/* update : 97/10/20 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" +#include "xchat.h" + + +#include <sys/wait.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <netdb.h> +#include <sys/resource.h> + + +#define SERVER_USAGE +#define WATCH_DOG +#undef DEBUG /* µ{¦¡°£¿ù¤§¥Î */ +#undef MONITOR /* ºÊ·þ chatroom ¬¡°Ê¥H¸Ñ¨MªÈ¯É */ +#undef STAND_ALONE /* ¤£·f°t BBS ¿W¥ß°õ¦æ */ + + +#ifdef DEBUG +#define MONITOR +#endif + +static int gline; + +#ifdef WATCH_DOG +#define MYDOG gline = __LINE__ +#else +#define MYDOG /* NOOP */ +#endif + + +#define CHAT_PIDFILE "run/chat.pid" +#define CHAT_LOGFILE "run/chat.log" +#define CHAT_INTERVAL (60 * 30) +#define SOCK_QLEN 3 + + +/* name of the main room (always exists) */ + + +#define MAIN_NAME "main" +#define MAIN_TOPIC "¦³½t¤d¨½¨Ó¬Û·|" + + +#define ROOM_LOCKED 1 +#define ROOM_SECRET 2 +#define ROOM_OPENTOPIC 4 +#define ROOM_ALL (NULL) + + +#define LOCKED(room) (room->rflag & ROOM_LOCKED) +#define SECRET(room) (room->rflag & ROOM_SECRET) +#define OPENTOPIC(room) (room->rflag & ROOM_OPENTOPIC) + + +#define RESTRICTED(usr) (usr->uflag == 0) /* guest */ +#define CHATSYSOP(usr) (usr->uflag & PERM_ALLCHAT) +#define PERM_ROOMOP PERM_CHAT /* Thor: É PERM_CHAT ¬° PERM_ROOMOP */ +#define PERM_CHATOP PERM_DENYCHAT /* Thor: É PERM_DENYCHAT ¬° PERM_CHATOP */ +/* #define ROOMOP(usr) (usr->uflag & (PERM_ROOMOP | PERM_ALLCHAT)) */ +/* Thor.980603: PERM_ALLCHAT §ï¬° default ¨S¦³ roomop, ¦ý¥i¥H¦Û¤v¨ú±o chatop */ +#define ROOMOP(usr) (usr->uflag & (PERM_ROOMOP | PERM_CHATOP)) +#define CLOAK(usr) (usr->uflag & PERM_CLOAK) + + +/* ----------------------------------------------------- */ +/* ChatRoom data structure */ +/* ----------------------------------------------------- */ + + +typedef struct ChatRoom ChatRoom; +typedef struct ChatUser ChatUser; +typedef struct UserList UserList; +typedef struct ChatCmd ChatCmd; +typedef struct ChatAction ChatAction; + + +struct ChatUser +{ + ChatUser *unext; + ChatRoom *room; + UserList *ignore; + int sock; /* user socket */ + int userno; + int uflag; + int clitype; /* Xshadow: client type. 1 for common client, + * 0 for bbs only client */ + time_t tbegin; + time_t uptime; + int sno; + int xdata; + int retry; + + int isize; /* current size of ibuf */ + char ibuf[80]; /* buffer for non-blocking receiving */ + char userid[IDLEN + 1]; /* real userid */ + char chatid[9]; /* chat id */ + char rhost[30]; /* host address */ +}; + + +struct ChatRoom +{ + ChatRoom *next, *prev; + UserList *invite; + char name[IDLEN + 1]; + char topic[48]; /* Let the room op to define room topic */ + int rflag; /* ROOM_LOCKED, ROOM_SECRET, ROOM_OPENTOPIC */ + int occupants; /* number of users in room */ +}; + + +struct UserList +{ + UserList *next; + int userno; + char userid[0]; +}; + + +struct ChatCmd +{ + char *cmdstr; + void (*cmdfunc) (); + int exact; +}; + + +static ChatRoom mainroom, *roompool; +static ChatUser *mainuser, *userpool; +static fd_set mainfset; +static int totaluser; /* current number of connections */ +static struct timeval zerotv; /* timeval for selecting */ +static int common_client_command; + + +#ifdef STAND_ALONE +static int userno_inc = 0; /* userno auto-incrementer */ +#endif + + +static char msg_not_op[] = "¡» ±z¤£¬O³o¶¡²á¤Ñ«Çªº Op"; +static char msg_no_such_id[] = "¡» ¥Ø«e¨S¦³¤H¨Ï¥Î [%s] ³oÓ²á¤Ñ¥N¸¹"; +static char msg_not_here[] = "¡» [%s] ¤£¦b³o¶¡²á¤Ñ«Ç"; + + +#define FUZZY_USER ((ChatUser *) -1) + + +/* ----------------------------------------------------- */ +/* operation log and debug information */ +/* ----------------------------------------------------- */ + + +static FILE *flog; + + +static void +logit(key, msg) + char *key; + char *msg; +{ + time_t now; + struct tm *p; + + time(&now); + p = localtime(&now); + fprintf(flog, "%02d/%02d %02d:%02d:%02d %-13s%s\n", + p->tm_mon + 1, p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec, key, msg); +} + + +static inline void +log_init() +{ + FILE *fp; + + /* --------------------------------------------------- */ + /* log daemon's PID */ + /* --------------------------------------------------- */ + + if (fp = fopen(CHAT_PIDFILE, "w")) + { + fprintf(fp, "%d\n", getpid()); + fclose(fp); + } + + flog = fopen(CHAT_LOGFILE, "a"); + logit("START", "chat daemon"); +} + + +#ifdef DEBUG +static char chatbuf[256]; /* general purpose buffer */ + + +static void +debug_list(list) + UserList *list; +{ + char buf[80]; + int i = 0; + + if (!list) + { + logit("DEBUG_L", "NULL"); + return; + } + while (list) + { + sprintf(buf, "%d) list: %p userno: %d next: %p", i++, list, list->userno, list->next); + logit("DEBUG_L", buf); + + list = list->next; + } + logit("DEBUG_L", "end"); +} + + +static void +debug_user() +{ + ChatUser *user; + int i; + char buf[80]; + + sprintf(buf, "mainuser: %p userpool: %p", mainuser, userpool); + logit("DEBUG_U", buf); + for (i = 0, user = mainuser; user; user = user->unext) + { + /* MYDOG; */ + sprintf(buf, "%d) %p %-6d %s %s", ++i, user, user->userno, user->userid, user->chatid); + logit("DEBUG_U", buf); + } +} + + +static void +debug_room() +{ + ChatRoom *room; + int i; + char buf[80]; + + i = 0; + room = &mainroom; + + sprintf(buf, "mainroom: %p roompool: %p", mainroom, roompool); + logit("DEBUG_R", buf); + do + { + MYDOG; + sprintf(buf, "%d) %p %s %d", ++i, room, room->name, room->occupants); + logit("DEBUG_R", buf); + } while (room = room->next); +} + + +static void +log_user(cu) + ChatUser *cu; +{ + static int log_num; + + if (cu) + { + if (log_num > 100 && log_num < 150) + { + sprintf(chatbuf, "%d: %p <%d>", log_num, cu, gline); + logit("travese user ", chatbuf); + } + else if (log_num == 100) + { + sprintf(chatbuf, "BOOM !! at line %d", gline); + logit("travese user ", chatbuf); + } + log_num++; + } + else + log_num = 0; +} +#endif /* DEBUG */ + + +/* ----------------------------------------------------- */ +/* string routines */ +/* ----------------------------------------------------- */ + + +static int +valid_chatid(id) + char *id; +{ + int ch, len; + + for (len = 0; ch = *id; id++) + { /* Thor.980921: ªÅ¥Õ¬°¤£¦X²zchatid, ©Ègetnext§PÂ_¿ù»~µ¥µ¥ */ + if (ch == '/' || ch == '*' || ch == ':' || ch ==' ') + return 0; + if (++len > 8) + return 0; + } + return len; +} + + +/* itoc.µù¸Ñ: ¥Ñ©ó§ï±Ä MUD-like ªº³¡¤À match §Y¥i */ +/* ©Ò¥H MUD-like ªº action ºÉ¶q¤£n¥Î^¤åÁY¼g¡A¨Ã¤£n¦³«ÂЪº */ + +static int /* 0: fit */ +str_belong(s1, s2) /* itoc.010321: Åý mud-like «ü¥O³¡¤À match §Y¥i¡A©M mud ¤@¼Ë */ + uschar *s1; /* ChatAction ¸Ìªº¤p¼g verb */ + uschar *s2; /* user input command ¤j¤p¼g§¡¥i */ +{ + int c1, c2; + int num = 0; + + for (;;) + { + c1 = *s1; + c2 = *s2; + + if (c2 >= 'A' && c2 <= 'Z') + c2 |= 0x20; /* ´«¤p¼g */ + + if (num >= 2) /* ¦Ü¤Ön¦³¤G¦r¤¸¬Û¦P */ + { + if (!c1 || !c2) /* §¹¥þ match ©Î³¡¤À match ¬Ò¥i (s1¥]§ts2 ©Î s2¥]§ts1§¡ºâ) */ + return 0; + } + + if (c1 > c2) /* itoc.010927: ¤£¦Pªº¦^¶ÇÈ */ + return 1; + else if (c1 < c2) + return -1; + + s1++; + s2++; + num++; + } +} + + +/* ----------------------------------------------------- */ +/* match strings' similarity case-insensitively */ +/* ----------------------------------------------------- */ +/* str_match(keyword, string) */ +/* ----------------------------------------------------- */ +/* 0 : equal ("foo", "foo") */ +/* -1 : mismatch ("abc", "xyz") */ +/* ow : similar ("goo", "good") */ +/* ----------------------------------------------------- */ + + +static int +str_match(s1, s2) + uschar *s1; /* lower-case (sub)string */ + uschar *s2; +{ + int c1, c2; + + for (;;) + { + c1 = *s1; + c2 = *s2; + + if (!c1) + return c2; + + if (c2 >= 'A' && c2 <= 'Z') + c2 |= 0x20; /* ´«¤p¼g */ + + if (c1 != c2) + return -1; + + s1++; + s2++; + } +} + + +/* ----------------------------------------------------- */ +/* search user/room by its ID */ +/* ----------------------------------------------------- */ + + +static ChatUser * +cuser_by_userid(userid) + char *userid; +{ + ChatUser *cu; + char buf[80]; /* Thor.980727: ¤@¦¸³Ìªø¤~80 */ + + str_lower(buf, userid); + for (cu = mainuser; cu; cu = cu->unext) + { + if (!cu->userno) + continue; + if (!str_cmp(buf, cu->userid)) + break; + } + return cu; +} + + +static ChatUser * +cuser_by_chatid(chatid) + char *chatid; +{ + ChatUser *cu; + char buf[80]; /* Thor.980727: ¤@¦¸³Ìªø¤~80 */ + + str_lower(buf, chatid); + + for (cu = mainuser; cu; cu = cu->unext) + { + if (!cu->userno) + continue; + if (!str_cmp(buf, cu->chatid)) + break; + } + return cu; +} + + +static ChatUser * +fuzzy_cuser_by_chatid(chatid) + char *chatid; +{ + ChatUser *cu, *xuser; + int mode; + char buf[80]; /* Thor.980727: ¤@¦¸³Ìªø¤~80 */ + + str_lower(buf, chatid); + xuser = NULL; + + for (cu = mainuser; cu; cu = cu->unext) + { + if (!cu->userno) + continue; + + mode = str_match(buf, cu->chatid); + if (mode == 0) + return cu; + + if (mode > 0) + { + if (xuser) + return FUZZY_USER; /* ²Å¦XªÌ¤j©ó 2 ¤H */ + + xuser = cu; + } + } + return xuser; +} + + +static ChatRoom * +croom_by_roomid(roomid) + char *roomid; +{ + ChatRoom *room; + char buf[80]; /* Thor.980727: ¤@¦¸³Ìªø¤~80 */ + + str_lower(buf, roomid); + room = &mainroom; + do + { + if (!str_cmp(buf, room->name)) + break; + } while (room = room->next); + return room; +} + + +/* ----------------------------------------------------- */ +/* UserList routines */ +/* ----------------------------------------------------- */ + + +static void +list_free(list) + UserList **list; +{ + UserList *user, *next; + + for (user = *list, *list = NULL; user; user = next) + { + next = user->next; + free(user); + } +} + + +static void +list_add(list, user) + UserList **list; + ChatUser *user; +{ + UserList *node; + char *userid; + int len; + + len = strlen(userid = user->userid) + 1; + if (node = (UserList *) malloc(sizeof(UserList) + len)) + { + node->next = *list; + node->userno = user->userno; + memcpy(node->userid, userid, len); + *list = node; + } +} + + +static int +list_delete(list, userid) + UserList **list; + char *userid; +{ + UserList *node; + char buf[80]; /* Thor.980727: ¿é¤J¤@¦¸³Ìªø¤~ 80 */ + + str_lower(buf, userid); + + while (node = *list) + { + if (!str_cmp(buf, node->userid)) + { + *list = node->next; + free(node); + return 1; + } + list = &node->next; + } + + return 0; +} + + +static int +list_belong(list, userno) + UserList *list; + int userno; +{ + while (list) + { + if (userno == list->userno) + return 1; + list = list->next; + } + return 0; +} + + +/* ------------------------------------------------------ */ +/* non-blocking socket routines : send message to users */ +/* ------------------------------------------------------ */ + + +static void +do_send(nfds, wset, msg) + int nfds; + fd_set *wset; + char *msg; +{ + int len, sr; + +#if 1 + /* Thor: for future reservation bug */ + zerotv.tv_sec = 0; + zerotv.tv_usec = 0; +#endif + + sr = select(nfds + 1, NULL, wset, NULL, &zerotv); + + if (sr > 0) + { + len = strlen(msg) + 1; + do + { + if (FD_ISSET(nfds, wset)) + { + send(nfds, msg, len, 0); + if (--sr <= 0) + return; + } + } while (--nfds > 0); + } +} + + +static void +send_to_room(room, msg, userno, number) + ChatRoom *room; + char *msg; + int userno; + int number; +{ + ChatUser *cu; + fd_set wset; + int sock, max; + int clitype; /* ¤À¬° bbs client ¤Î common client ¨â¦¸³B²z */ + char *str, buf[256]; + + for (clitype = (number == MSG_MESSAGE || !number) ? 0 : 1; + clitype < 2; clitype++) + { + FD_ZERO(&wset); + max = -1; + + for (cu = mainuser; cu; cu = cu->unext) + { + if (cu->userno && (cu->clitype == clitype) && + (room == ROOM_ALL || room == cu->room) && + (!userno || !list_belong(cu->ignore, userno))) + { + sock = cu->sock; + + FD_SET(sock, &wset); + + if (max < sock) + max = sock; + } + } + + if (max <= 0) + continue; + + if (clitype) + { + str = buf; + + if (*msg) + sprintf(str, "%3d %s", number, msg); + else + sprintf(str, "%3d", number); + } + else + { + str = msg; + } + + do_send(max, &wset, str); + } +} + + +static void +send_to_user(user, msg, userno, number) + ChatUser *user; + char *msg; + int userno; + int number; +{ + int sock; + +#if 0 + if (!user->userno || (!user->clitype && number && number != MSG_MESSAGE)) +#endif + /* Thor.980911: ¦pªG¬duser->userno«h¦blogin_userªºerror message·|µLªk°e¦^ */ + if (!user->clitype && number != MSG_MESSAGE) + return; + + if ((sock = user->sock) <= 0) + return; + + if (!userno || !list_belong(user->ignore, userno)) + { + fd_set wset; + char buf[256]; + + FD_ZERO(&wset); + FD_SET(sock, &wset); + + if (user->clitype) + { + if (*msg) + sprintf(buf, "%3d %s", number, msg); + else + sprintf(buf, "%3d", number); + msg = buf; + } + + do_send(sock, &wset, msg); + } +} + + +/* ----------------------------------------------------- */ + + +static void +room_changed(room) + ChatRoom *room; +{ + if (room) + { + char buf[256]; + + sprintf(buf, "= %s %d %d %s", + room->name, room->occupants, room->rflag, room->topic); + send_to_room(ROOM_ALL, buf, 0, MSG_ROOMNOTIFY); + } +} + + +static void +user_changed(cu) + ChatUser *cu; +{ + if (cu) + { + ChatRoom *room; + char buf[256]; + + room = cu->room; + sprintf(buf, "= %s %s %s %s%s", + cu->userid, cu->chatid, room->name, cu->rhost, + ROOMOP(cu) ? " Op" : ""); + send_to_room(room, buf, 0, MSG_USERNOTIFY); + } +} + + +static void +exit_room(user, mode, msg) + ChatUser *user; + int mode; + char *msg; +{ + ChatRoom *room; + char buf[128]; + + if (!(room = user->room)) + return; + + user->room = NULL; + /* user->uflag &= ~(PERM_ROOMOP | PERM_ALLCHAT); */ + user->uflag &= ~PERM_ROOMOP; + /* Thor.980601: Â÷¶}©Ð¶¡®É¥u²M room op, ¤£²M sysop, chatroom ¦]¤Ñ¥Í¨ã¦³ */ + + if (--room->occupants > 0) + { + char *chatid; + + chatid = user->chatid; + switch (mode) + { + case EXIT_LOGOUT: + + sprintf(buf, "¡» %s Â÷¶}¤F ... %.50s", chatid, (msg && *msg) ? msg : ""); + break; + + case EXIT_LOSTCONN: + + sprintf(buf, "¡» %s ¦¨¤FÂ_½uªº·ºåÅo", chatid); + break; + + case EXIT_KICK: + + sprintf(buf, "¡» «¢«¢¡I%s ³Q½ð¥X¥h¤F", chatid); + break; + } + + if (!CLOAK(user)) + send_to_room(room, buf, 0, MSG_MESSAGE); + + sprintf(buf, "- %s", user->userid); + send_to_room(room, buf, 0, MSG_USERNOTIFY); + room_changed(room); + } + else if (room != &mainroom) + { + ChatRoom *next; + + fprintf(flog, "room-\t[%d] %s\n", user->sno, room->name); + sprintf(buf, "- %s", room->name); + + room->prev->next = next = room->next; + if (next) + next->prev = room->prev; + + list_free(&room->invite); + + /* free(room); */ + + /* ¦^¦¬ */ + room->next = roompool; + roompool = room; + + send_to_room(ROOM_ALL, buf, 0, MSG_ROOMNOTIFY); + } +} + + +/* ----------------------------------------------------- */ +/* chat commands */ +/* ----------------------------------------------------- */ + + +#ifndef STAND_ALONE +/* ----------------------------------------------------- */ +/* BBS server side routines */ +/* ----------------------------------------------------- */ + + +/* static */ +int +acct_load(acct, userid) + ACCT *acct; + char *userid; +{ + int fd; + + usr_fpath((char *) acct, userid, FN_ACCT); + fd = open((char *) acct, O_RDONLY); + if (fd >= 0) + { + read(fd, acct, sizeof(ACCT)); + close(fd); + } + return fd; +} + + +static void +chat_query(cu, msg) + ChatUser *cu; + char *msg; +{ + FILE *fp; + ACCT acct; + char buf[256]; + + /* Thor.980617: ¥i¥ý¬d¬O§_¬°ªÅ¦r¦ê */ + if (*msg && acct_load(&acct, msg) >= 0) + { + sprintf(buf, "%s(%s) ¦@¤W¯¸ %d ¦¸¡A¤å³¹ %d ½g", + acct.userid, acct.username, acct.numlogins, acct.numposts); + send_to_user(cu, buf, 0, MSG_MESSAGE); + + sprintf(buf, "³Ìªñ(%s)±q(%s)¤W¯¸", Btime(&acct.lastlogin), + (acct.lasthost[0] ? acct.lasthost : "¥~¤ÓªÅ")); + send_to_user(cu, buf, 0, MSG_MESSAGE); + + usr_fpath(buf, acct.userid, FN_PLANS); + if (fp = fopen(buf, "r")) + { + int i; + + i = 0; + while (fgets(buf, sizeof(buf), fp)) + { + buf[strlen(buf) - 1] = 0; + send_to_user(cu, buf, 0, MSG_MESSAGE); + if (++i >= MAXQUERYLINES) + break; + } + fclose(fp); + } + } + else + { + sprintf(buf, msg_no_such_id, msg); + send_to_user(cu, buf, 0, MSG_MESSAGE); + } +} +#endif + + +static void +chat_clear(cu, msg) + ChatUser *cu; + char *msg; +{ + if (cu->clitype) + send_to_user(cu, "", 0, MSG_CLRSCR); + else + send_to_user(cu, "/c", 0, MSG_MESSAGE); +} + + +static void +chat_date(cu, msg) + ChatUser *cu; + char *msg; +{ + char buf[128]; + + sprintf(buf, "¡» ¼Ð·Ç®É¶¡: %s", Now()); + send_to_user(cu, buf, 0, MSG_MESSAGE); +} + + +static void +chat_topic(cu, msg) + ChatUser *cu; + char *msg; +{ + ChatRoom *room; + char *topic, buf[128]; + + room = cu->room; + + if (!ROOMOP(cu) && !OPENTOPIC(room)) + { + send_to_user(cu, msg_not_op, 0, MSG_MESSAGE); + return; + } + + if (*msg == '\0') + { + send_to_user(cu, "¡° ½Ð«ü©w¸ÜÃD", 0, MSG_MESSAGE); + return; + } + + topic = room->topic; + str_ncpy(topic, msg, sizeof(room->topic)); + + if (cu->clitype) + { + send_to_room(room, topic, 0, MSG_TOPIC); + } + else + { + sprintf(buf, "/t%s", topic); + send_to_room(room, buf, 0, MSG_MESSAGE); + } + + room_changed(room); + + if (!CLOAK(cu)) + { + sprintf(buf, "¡» %s ±N¸ÜÃD§ï¬° \033[1;32m%s\033[m", cu->chatid, topic); + send_to_room(room, buf, 0, MSG_MESSAGE); + } +} + + +static void +chat_version(cu, msg) + ChatUser *cu; + char *msg; +{ + char buf[80]; + + sprintf(buf, "[Version] MapleBBS-3.10-20040726-PACK.itoc + Xchat-%d.%d", + XCHAT_VERSION_MAJOR, XCHAT_VERSION_MINOR); + send_to_user(cu, buf, 0, MSG_MESSAGE); +} + + +static void +chat_nick(cu, msg) + ChatUser *cu; + char *msg; +{ + char *chatid, *str, buf[128]; + ChatUser *xuser; + + chatid = nextword(&msg); + chatid[8] = '\0'; + if (!valid_chatid(chatid)) + { + send_to_user(cu, "¡° ³oÓ²á¤Ñ¥N¸¹¬O¤£¥¿½Tªº", 0, MSG_MESSAGE); + return; + } + + xuser = cuser_by_chatid(chatid); + if (xuser != NULL && xuser != cu) + { + send_to_user(cu, "¡° ¤w¸g¦³¤H±¶¨¬¥ýµnÅo", 0, MSG_MESSAGE); + return; + } + + /* itoc.010528: ¤£¥i¥H¥Î§O¤Hªº id °µ¬°²á¤Ñ¥N¸¹ */ + usr_fpath(buf, chatid, NULL); + if (dashd(buf) && str_cmp(chatid, cu->userid)) + { + send_to_user(cu, "¡° ©êºp³oÓ¥N¸¹¦³¤Hµù¥U¬° id¡A©Ò¥H±z¤£¯à·í¦¨²á¤Ñ¥N¸¹", 0, MSG_MESSAGE); + return; + } + + str = cu->chatid; + + if (!CLOAK(cu)) + { + sprintf(buf, "¡° %s ±N²á¤Ñ¥N¸¹§ï¬° \033[1;33m%s\033[m", str, chatid); + send_to_room(cu->room, buf, cu->userno, MSG_MESSAGE); + } + + strcpy(str, chatid); + + user_changed(cu); + + if (cu->clitype) + { + send_to_user(cu, chatid, 0, MSG_NICK); + } + else + { + sprintf(buf, "/n%s", chatid); + send_to_user(cu, buf, 0, MSG_MESSAGE); + } +} + + +static void +chat_list_rooms(cuser, msg) + ChatUser *cuser; + char *msg; +{ + ChatRoom *cr, *room; + char buf[128]; + int mode; + + if (RESTRICTED(cuser)) + { + send_to_user(cuser, "¡° ±z¨S¦³Åv¦C¥X²{¦³ªº²á¤Ñ«Ç", 0, MSG_MESSAGE); + return; + } + + mode = common_client_command; + + if (mode) + send_to_user(cuser, "", 0, MSG_ROOMLISTSTART); + else + send_to_user(cuser, "\033[7m ½Í¤Ñ«Ç¦WºÙ ¢x¤H¼Æ¢x¸ÜÃD [/h]»¡©ú [/quit]Â÷¶}\033[m", 0, MSG_MESSAGE); + + room = cuser->room; + cr = &mainroom; + + do + { + if ((cr == room) || !SECRET(cr) || CHATSYSOP(cuser)) + { + if (mode) + { + sprintf(buf, "%s %d %d %s", + cr->name, cr->occupants, cr->rflag, cr->topic); + send_to_user(cuser, buf, 0, MSG_ROOMLIST); + } + else + { + sprintf(buf, " %-12s¢x%4d¢x%s", cr->name, cr->occupants, cr->topic); + if (LOCKED(cr)) + strcat(buf, " [Âê¦í]"); + if (SECRET(cr)) + strcat(buf, " [¯µ±K]"); + if (OPENTOPIC(cr)) + strcat(buf, " [¸ÜÃD]"); + send_to_user(cuser, buf, 0, MSG_MESSAGE); + } + } + } while (cr = cr->next); + + if (mode) + send_to_user(cuser, "", 0, MSG_ROOMLISTEND); +} + + +static void +chat_do_user_list(cu, msg, theroom) + ChatUser *cu; + char *msg; + ChatRoom *theroom; +{ + ChatRoom *myroom, *room; + ChatUser *user; + int start, stop, curr, mode; /* , uflag; */ + char buf[128]; + + curr = 0; /* Thor.980619: initialize curr */ + start = atoi(nextword(&msg)); + stop = atoi(nextword(&msg)); + + mode = common_client_command; + + if (mode) + send_to_user(cu, "", 0, MSG_USERLISTSTART); + else + send_to_user(cu, "\033[7m ²á¤Ñ¥N¸¹¢x¨Ï¥ÎªÌ¥N¸¹ ¢x²á¤Ñ«Ç \033[m", 0, + MSG_MESSAGE); + + myroom = cu->room; + + /* Thor.980717: »Ýn¥ý±Æ°£ cu->userno == 0 ªºª¬ªp¶Ü? */ + for (user = mainuser; user; user = user->unext) + { +#if 0 /* Thor.980717: ¬JµM cu ³£ªÅ¤F¨ºÁÙ¶i¨Ó·F»ò? */ + if (!cu->userno) + continue; +#endif + + if (!user->userno) + continue; + + room = user->room; + if ((theroom != ROOM_ALL) && (theroom != room)) + continue; + + /* Thor.980717: viewer check */ + if ((myroom != room) && (RESTRICTED(cu) || (room && SECRET(room) && !CHATSYSOP(cu)))) + continue; + + /* Thor.980717: viewee check */ + if (CLOAK(user) && (user != cu) && !CHATSYSOP(cu)) + continue; + + curr++; + if (start && curr < start) + continue; + else if (stop && (curr > stop)) + break; + + if (mode) + { + if (!room) + continue; /* Xshadow: ÁÙ¨S¶i¤J¥ô¦ó©Ð¶¡ªº´N¤£¦C¥X */ + + sprintf(buf, "%s %s %s %s", + user->chatid, user->userid, room->name, user->rhost); + + /* Thor.980603: PERM_ALLCHAT §ï¬° default ¨S¦³ roomop, ¦ý¥i¥H¦Û¤v¨ú±o */ + /* if (uflag & (PERM_ROOMOP | PERM_ALLCHAT)) */ + if (ROOMOP(user)) + strcat(buf, " Op"); + } + else + { + sprintf(buf, " %-8s¢x%-12s¢x%s", + user->chatid, user->userid, room ? room->name : "[¦bªù¤f±r«Þ]"); + /* Thor.980603: PERM_ALLCHAT §ï¬° default ¨S¦³ roomop, ¦ý¥i¥H¦Û¤v¨ú±o */ + /* if (uflag & (PERM_ROOMOP | PERM_ALLCHAT)) */ + /* if (uflag & (PERM_ROOMOP | PERM_CHATOP)) */ + if (ROOMOP(user)) /* Thor.980602: ²Î¤@¥Îªk */ + strcat(buf, " [Op]"); + } + + send_to_user(cu, buf, 0, mode ? MSG_USERLIST : MSG_MESSAGE); + } + + if (mode) + send_to_user(cu, "", 0, MSG_USERLISTEND); +} + + +static void +chat_list_by_room(cu, msg) + ChatUser *cu; + char *msg; +{ + ChatRoom *whichroom; + char *roomstr, buf[128]; + + roomstr = nextword(&msg); + if (!*roomstr) + { + whichroom = cu->room; + } + else + { + if (!(whichroom = croom_by_roomid(roomstr))) + { + sprintf(buf, "¡° ¨S¦³ [%s] ³oÓ²á¤Ñ«Ç", roomstr); + send_to_user(cu, buf, 0, MSG_MESSAGE); + return; + } + + if (whichroom != cu->room && SECRET(whichroom) && !CHATSYSOP(cu)) + { + send_to_user(cu, "¡° µLªk¦C¥X¦b¯µ±K²á¤Ñ«Çªº¨Ï¥ÎªÌ", 0, MSG_MESSAGE); + return; + } + } + chat_do_user_list(cu, msg, whichroom); +} + + +static void +chat_list_users(cu, msg) + ChatUser *cu; + char *msg; +{ + chat_do_user_list(cu, msg, ROOM_ALL); +} + + +static void +chat_chatroom(cu, msg) + ChatUser *cu; + char *msg; +{ + if (common_client_command) + send_to_user(cu, "²á¤Ñ«Ç", 0, MSG_CHATROOM); +} + + +static void +chat_map_chatids(cu, whichroom) + ChatUser *cu; /* Thor: ÁÙ¨S¦³§@¤£¦P¶¡ªº */ + ChatRoom *whichroom; +{ + int c; + ChatRoom *myroom, *room; + ChatUser *user; + char buf[128]; + + myroom = cu->room; + + send_to_user(cu, + "\033[7m ²á¤Ñ¥N¸¹ ¨Ï¥ÎªÌ¥N¸¹ ¢x ²á¤Ñ¥N¸¹ ¨Ï¥ÎªÌ¥N¸¹ ¢x ²á¤Ñ¥N¸¹ ¨Ï¥ÎªÌ¥N¸¹ \033[m", 0, MSG_MESSAGE); + + for (c = 0, user = mainuser; user; user = user->unext) + { + if (!cu->userno) + continue; + + room = user->room; + if (whichroom != ROOM_ALL && whichroom != room) + continue; + + if (myroom != room) + { + if (RESTRICTED(cu) || /* Thor: n¥ýcheck room ¬O¤£¬OªÅªº */ + (room && SECRET(room) && !CHATSYSOP(cu))) + continue; + } + + if (CLOAK(user) && (user != cu) && !CHATSYSOP(cu)) /* Thor:Áô¨³N */ + continue; + + sprintf(buf + (c * 24), " %-8s%c%-12s%s", + user->chatid, ROOMOP(user) ? '*' : ' ', + user->userid, (c < 2 ? "¢x" : " ")); + + if (++c == 3) + { + send_to_user(cu, buf, 0, MSG_MESSAGE); + c = 0; + } + } + + if (c > 0) + send_to_user(cu, buf, 0, MSG_MESSAGE); +} + + +static void +chat_map_chatids_thisroom(cu, msg) + ChatUser *cu; + char *msg; +{ + chat_map_chatids(cu, cu->room); +} + + +static void +chat_setroom(cu, msg) + ChatUser *cu; + char *msg; +{ + char *modestr; + ChatRoom *room; + char *chatid; + int sign, flag; + char *fstr, buf[128]; + + if (!ROOMOP(cu)) + { + send_to_user(cu, msg_not_op, 0, MSG_MESSAGE); + return; + } + + modestr = nextword(&msg); + sign = 1; + if (*modestr == '+') + { + modestr++; + } + else if (*modestr == '-') + { + modestr++; + sign = 0; + } + + if (*modestr == '\0') + { + send_to_user(cu, + "¡° ½Ð«ü©wª¬ºA: {[+(³]©w)][-(¨ú®ø)]}{[L(Âê¦í)][s(¯µ±K)][t(¶}©ñ¸ÜÃD)}", 0, MSG_MESSAGE); + return; + } + + room = cu->room; + chatid = cu->chatid; + + while (*modestr) + { + flag = 0; + switch (*modestr) + { + case 'l': + case 'L': + flag = ROOM_LOCKED; + fstr = "Âê¦í"; + break; + + case 's': + case 'S': + flag = ROOM_SECRET; + fstr = "¯µ±K"; + break; + + case 't': + case 'T': + flag = ROOM_OPENTOPIC; + fstr = "¶}©ñ¸ÜÃD"; + break; + + default: + sprintf(buf, "¡° ª¬ºA¿ù»~¡G[%c]", *modestr); + send_to_user(cu, buf, 0, MSG_MESSAGE); + } + + /* Thor: check room ¬O¤£¬OªÅªº, À³¸Ó¤£¬OªÅªº */ + + if (flag && (room->rflag & flag) != sign * flag) + { + room->rflag ^= flag; + + if (!CLOAK(cu)) + { + sprintf(buf, "¡° ¥»²á¤Ñ«Ç³Q %s %s [%s] ª¬ºA", + chatid, sign ? "³]©w¬°" : "¨ú®ø", fstr); + send_to_room(room, buf, 0, MSG_MESSAGE); + } + } + modestr++; + } + + /* Thor.980602: ¤£ã Main room Âê°_ or ¯µ±K¡A§_«hÂ÷¶}ªº´N¶i¤£¨Ó¡An¬Ý¤]¬Ý¤£¨ì¡C + ·Qn½ð¤H¤]½ð¤£¶i main room¡A¤£·|«Ü©_©Ç¶Ü¡H */ + + if (!str_cmp(MAIN_NAME, room->name)) + { + if (room->rflag & (ROOM_LOCKED | ROOM_SECRET)) + { + send_to_room(room, "¡° ¦ý¤Ñ¨Ï¬I¤F¡y´_ì¡zªºÅ]ªk", 0, MSG_MESSAGE); + room->rflag &= ~(ROOM_LOCKED | ROOM_SECRET); + } + } + + room_changed(room); +} + + +static char *chat_msg[] = +{ + "[//]help", "MUD-like ªÀ¥æ°Êµü", + "[/h]elp op", "½Í¤Ñ«ÇºÞ²zû±M¥Î«ü¥O", + "[/a]ct <msg>", "°µ¤@Ӱʧ@", + "[/b]ye [msg]", "¹D§O", + "[/c]lear [/d]ate", "²M°£¿Ã¹õ ¥Ø«e®É¶¡", + "[/i]gnore [user]", "©¿²¤¨Ï¥ÎªÌ", + "[/j]oin <room>", "«Ø¥ß©Î¥[¤J½Í¤Ñ«Ç", + "[/l]ist [start [stop]]", "¦C¥X½Í¤Ñ«Ç¨Ï¥ÎªÌ", + "[/m]sg <id|user> <msg>", "¸ò <id> »¡®¨®¨¸Ü", + "[/n]ick <id>", "±N½Í¤Ñ¥N¸¹´«¦¨ <id>", + "[/p]ager", "¤Á´«©I¥s¾¹", + "[/q]uery <user>", "¬d¸ßºô¤Í", + "[/qui]t [msg]", "¹D§O", + "[/r]oom", "¦C¥X¤@¯ë½Í¤Ñ«Ç", + "[/t]ape", "¶}Ãö¿ýµ¾÷", + "[/u]nignore <user>", "¨ú®ø©¿²¤", + "[/w]ho", "¦C¥X¥»½Í¤Ñ«Ç¨Ï¥ÎªÌ", + "[/w]hoin <room>", "¦C¥X½Í¤Ñ«Ç<room> ªº¨Ï¥ÎªÌ", + NULL +}; + + +static char *room_msg[] = +{ + "[/f]lag [+-][lst]", "³]©wÂê©w¡B¯µ±K¡B¶}©ñ¸ÜÃD", + "[/i]nvite <id>", "ÁܽР<id> ¥[¤J½Í¤Ñ«Ç", + "[/kick] <id>", "±N <id> ½ð¥X½Í¤Ñ«Ç", + "[/o]p [<id>]", "±N Op ªºÅv¤OÂಾµ¹ <id>", + "[/topic] <text>", "´«Ó¸ÜÃD", + "[/w]all", "¼s¼½ (¯¸ªø±M¥Î)", + NULL +}; + + +static void +chat_help(cu, msg) + ChatUser *cu; + char *msg; +{ + char **table, *str, buf[128]; + + if (!str_cmp("op", nextword(&msg))) + { + send_to_user(cu, "½Í¤Ñ«ÇºÞ²zû±M¥Î«ü¥O", 0, MSG_MESSAGE); + table = room_msg; + } + else + { + table = chat_msg; + } + + while (str = *table++) + { + sprintf(buf, " %-20s- %s", str, *table++); + send_to_user(cu, buf, 0, MSG_MESSAGE); + } +} + + +static void +chat_private(cu, msg) + ChatUser *cu; + char *msg; +{ + ChatUser *xuser; + char *recipient, buf[128]; + + recipient = nextword(&msg); + xuser = (ChatUser *) fuzzy_cuser_by_chatid(recipient); + if (xuser == NULL) /* Thor.980724: ¥Î userid¤]¥i¶Ç®¨®¨¸Ü */ + { + xuser = cuser_by_userid(recipient); + } + + if (xuser == NULL) + { + sprintf(buf, msg_no_such_id, recipient); + } + else if (xuser == FUZZY_USER) + { /* ambiguous */ + strcpy(buf, "¡° ½Ð«ü©ú²á¤Ñ¥N¸¹"); + } + else if (*msg) + { + int userno; + + userno = cu->userno; + + sprintf(buf, "\033[1m*%s*\033[m %.50s", cu->chatid, msg); + send_to_user(xuser, buf, userno, MSG_MESSAGE); + + if (xuser->clitype) /* Xshadow: ¦pªG¹ï¤è¬O¥Î client ¤W¨Óªº */ + { + sprintf(buf, "%s %s %.50s", cu->userid, cu->chatid, msg); + send_to_user(xuser, buf, userno, MSG_PRIVMSG); + } + + if (cu->clitype) + { + sprintf(buf, "%s %s %.50s", xuser->userid, xuser->chatid, msg); + send_to_user(cu, buf, 0, MSG_MYPRIVMSG); + } + + sprintf(buf, "%s> %.50s", xuser->chatid, msg); + } + else + { + sprintf(buf, "¡° ±z·Q¹ï %s »¡¤°»ò¸Ü©O¡H", xuser->chatid); + } + + send_to_user(cu, buf, 0, MSG_MESSAGE); +} + + +static void +chat_cloak(cu, msg) + ChatUser *cu; + char *msg; +{ + if (CHATSYSOP(cu)) + { + char buf[128]; + + cu->uflag ^= PERM_CLOAK; + sprintf(buf, "¡» %s", CLOAK(cu) ? MSG_CLOAKED : MSG_UNCLOAK); + send_to_user(cu, buf, 0, MSG_MESSAGE); + } +} + + +/* ----------------------------------------------------- */ + + +static void +arrive_room(cuser, room) + ChatUser *cuser; + ChatRoom *room; +{ + char *rname, buf[256]; + + /* Xshadow: ¤£¥²°eµ¹¦Û¤v, ¤Ï¥¿´«©Ð¶¡´N·|«·s build user list */ + + sprintf(buf, "+ %s %s %s %s", + cuser->userid, cuser->chatid, room->name, cuser->rhost); + if (ROOMOP(cuser)) + strcat(buf, " Op"); + send_to_room(room, buf, 0, MSG_USERNOTIFY); + + room->occupants++; + room_changed(room); + + cuser->room = room; + rname = room->name; + + if (cuser->clitype) + { + send_to_user(cuser, rname, 0, MSG_ROOM); + send_to_user(cuser, room->topic, 0, MSG_TOPIC); + } + else + { + sprintf(buf, "/r%s", rname); + send_to_user(cuser, buf, 0, MSG_MESSAGE); + sprintf(buf, "/t%s", room->topic); + send_to_user(cuser, buf, 0, MSG_MESSAGE); + } + + sprintf(buf, "¡° \033[32;1m%s\033[m ¶i¤J \033[33;1m[%s]\033[m ¥]´[ \033[1;32m[/h]»¡©ú\033[m", + cuser->chatid, rname); + + if (!CLOAK(cuser)) + send_to_room(room, buf, cuser->userno, MSG_MESSAGE); + else + send_to_user(cuser, buf, 0, MSG_MESSAGE); +} + + +static int +enter_room(cuser, rname, msg) + ChatUser *cuser; + char *rname; + char *msg; +{ + ChatRoom *room; + int create; + char buf[256]; + + create = 0; + room = croom_by_roomid(rname); + + if (room == NULL) + { + /* new room */ + +#ifdef DEBUG + logit(cuser->userid, "create new room"); + debug_room(); +#endif + + if (room = roompool) + { + roompool = room->next; + } + else + { + room = (ChatRoom *) malloc(sizeof(ChatRoom)); + } + + if (room == NULL) + { + send_to_user(cuser, "¡° µLªk¦A·sÅP¥]´[¤F", 0, MSG_MESSAGE); + return 0; + } + + memset(room, 0, sizeof(ChatRoom)); + str_ncpy(room->name, rname, sizeof(room->name)); + strcpy(room->topic, "³o¬O¤@Ó·s¤Ñ¦a"); + + sprintf(buf, "+ %s 1 0 %s", room->name, room->topic); + send_to_room(ROOM_ALL, buf, 0, MSG_ROOMNOTIFY); + + if (mainroom.next) + mainroom.next->prev = room; + room->next = mainroom.next; + + mainroom.next = room; + room->prev = &mainroom; + +#ifdef DEBUG + logit(cuser->userid, "create room succeed"); + debug_room(); +#endif + + create = 1; + fprintf(flog, "room+\t[%d] %s\n", cuser->sno, rname); + } + else + { + if (cuser->room == room) + { + sprintf(buf, "¡° ±z¥»¨Ó´N¦b [%s] ²á¤Ñ«ÇÅo :)", rname); + send_to_user(cuser, buf, 0, MSG_MESSAGE); + return 0; + } + + if (!CHATSYSOP(cuser) && LOCKED(room) && + !list_belong(room->invite, cuser->userno)) + { + send_to_user(cuser, "¡° ¤º¦³´c¤ü¡A«D½Ð²ö¤J", 0, MSG_MESSAGE); + return 0; + } + } + + exit_room(cuser, EXIT_LOGOUT, msg); + arrive_room(cuser, room); + + if (create) + cuser->uflag |= PERM_ROOMOP; + + return 0; +} + + +static void +cuser_free(cuser) + ChatUser *cuser; +{ + int sock; + + sock = cuser->sock; + shutdown(sock, 2); + close(sock); + + FD_CLR(sock, &mainfset); + + list_free(&cuser->ignore); + totaluser--; + + if (cuser->room) + { + exit_room(cuser, EXIT_LOSTCONN, NULL); + } + + fprintf(flog, "BYE\t[%d] T%d X%d\n", + cuser->sno, time(0) - cuser->tbegin, cuser->xdata); +} + + +static void +print_user_counts(cuser) + ChatUser *cuser; +{ + ChatRoom *room; + int num, userc, suserc, roomc, number; + char buf[256]; + + userc = suserc = roomc = 0; + + room = &mainroom; + do + { + num = room->occupants; + if (SECRET(room)) + { + suserc += num; + if (CHATSYSOP(cuser)) + roomc++; + } + else + { + userc += num; + roomc++; + } + } while (room = room->next); + + number = (cuser->clitype) ? MSG_MOTD : MSG_MESSAGE; + + sprintf(buf, + "¡ó Åwªï¥úÁ{¡i²á¤Ñ«Ç¡j¡A¥Ø«e¶}¤F \033[1;31m%d\033[m ¶¡¥]´[", roomc); + send_to_user(cuser, buf, 0, number); + + sprintf(buf, "¡ó ¦@¦³ \033[1;36m%d\033[m ¤H¨ÓÂ\\Àsªù°}", userc); + if (suserc) + sprintf(buf + strlen(buf), " [%d ¤H¦b¯µ±K²á¤Ñ«Ç]", suserc); + + send_to_user(cuser, buf, 0, number); +} + + +static int +login_user(cu, msg) + ChatUser *cu; + char *msg; +{ + int utent; + + char *userid; + char *chatid, *passwd; + ChatUser *xuser; + int level; + /* struct hostent *hp; */ + +#ifndef STAND_ALONE + ACCT acct; +#endif + + /* Xshadow.0915: common client support : /-! userid chatid password */ + /* client/server ª©¥»¨Ì¾Ú userid §ì .PASSWDS §PÂ_ userlevel */ + + userid = nextword(&msg); + chatid = nextword(&msg); + +#ifdef DEBUG + logit("ENTER", userid); +#endif + +#ifndef STAND_ALONE + /* Thor.980730: parse space before passwd */ + + passwd = msg; + + /* Thor.980813: ¸õ¹L¤@ªÅ®æ§Y¥i, ¦]¬°¤Ï¥¿¦pªGchatid¦³ªÅ®æ, ±K½X¤]¤£¹ï */ + /* ´Nºâ±K½X¹ï, ¤]¤£·|«ç»ò¼Ë:p */ + /* ¥i¬O¦pªG±K½X²Ä¤@Ó¦r¬OªÅ®æ, ¨º¸õ¤Ó¦hªÅ®æ·|¶i¤£¨Ó... */ + /* Thor.980910: ¥Ñ©ó nextwordקאּ«á±µªÅ®æ¶ñ0, ¶Ç¤JÈ«hª½±µ«á²¾¦Ü0«á, + ©Ò¥H¤£»Ý§@¦¹°Ê§@ */ +#if 0 + if (*passwd == ' ') + passwd++; +#endif + + /* Thor.980729: load acct */ + + if (!*userid || (acct_load(&acct, userid) < 0)) + { + +#ifdef DEBUG + logit("noexist", userid); +#endif + + if (cu->clitype) + send_to_user(cu, "¿ù»~ªº¨Ï¥ÎªÌ¥N¸¹", 0, ERR_LOGIN_NOSUCHUSER); + else + send_to_user(cu, CHAT_LOGIN_INVALID, 0, MSG_MESSAGE); + + return -1; + } + + /* Thor.980813: §ï¥Î¯u¹ê password check, for C/S bbs */ + + /* Thor.990214: ª`·N daolib ¤¤ «D 0 ¥Nªí¥¢±Ñ */ + /* if (!chkpasswd(acct.passwd, passwd)) */ + if (chkpasswd(acct.passwd, passwd)) + { + +#ifdef DEBUG + logit("fake", userid); +#endif + + if (cu->clitype) + send_to_user(cu, "±K½X¿ù»~", 0, ERR_LOGIN_PASSERROR); + else + send_to_user(cu, CHAT_LOGIN_INVALID, 0, MSG_MESSAGE); + + return -1; + } + + level = acct.userlevel; + utent = acct.userno; + +#else /* STAND_ALONE */ + level = 1; + utent = ++userno_inc; +#endif /* STAND_ALONE */ + + /* Thor.980819: for client/server bbs */ + +#ifdef DEBUG + log_user(NULL); +#endif + + for (xuser = mainuser; xuser; xuser = xuser->unext) + { + +#ifdef DEBUG + log_user(xuser); +#endif + + if (xuser->userno == utent) + { + +#ifdef DEBUG + logit("enter", "bogus"); +#endif + + if (cu->clitype) + send_to_user(cu, "½Ð¤Å¬£»º¤À¨¶i¤J²á¤Ñ«Ç¡I", 0, + ERR_LOGIN_USERONLINE); + else + send_to_user(cu, CHAT_LOGIN_BOGUS, 0, MSG_MESSAGE); + return -1; /* Thor: ©Î¬O0µ¥¥¦¦Û¤v¤FÂ_? */ + } + } + + +#ifndef STAND_ALONE + /* Thor.980629: ¼È®ÉɥΠinvalid_chatid Âo°£ ¨S¦³PERM_CHATªº¤H */ + + if (!valid_chatid(chatid) || !(level & PERM_CHAT) || (level & PERM_DENYCHAT)) + { /* Thor.981012: ¹ý©³¤@¨Ç, ³s denychat¤]BAN±¼, §K±o client§@©Ç */ + +#ifdef DEBUG + logit("enter", chatid); +#endif + + if (cu->clitype) + send_to_user(cu, "¤£¦Xªkªº²á¤Ñ«Ç¥N¸¹¡I", 0, ERR_LOGIN_NICKERROR); + else + send_to_user(cu, CHAT_LOGIN_INVALID, 0, MSG_MESSAGE); + return 0; + } +#endif + +#ifdef DEBUG + debug_user(); +#endif + + if (cuser_by_chatid(chatid) != NULL) + { + /* chatid in use */ + +#ifdef DEBUG + logit("enter", "duplicate"); +#endif + + if (cu->clitype) + send_to_user(cu, "³oÓ¥N¸¹¤w¸g¦³¤H¨Ï¥Î", 0, ERR_LOGIN_NICKINUSE); + else + send_to_user(cu, CHAT_LOGIN_EXISTS, 0, MSG_MESSAGE); + return 0; + } + +#ifdef DEBUG /* CHATSYSOP ¤@¶i¨Ó´NÁô¨ */ + cu->uflag = level & ~(PERM_ROOMOP | PERM_CHATOP | (CHATSYSOP(cu) ? 0 : PERM_CLOAK)); +#else + cu->uflag = level & ~(PERM_ROOMOP | PERM_CHATOP | PERM_CLOAK); +#endif + + /* Thor: ¶i¨Ó¥ý²MªÅ ROOMOP (¦PPERM_CHAT) */ + + strcpy(cu->userid, userid); + str_ncpy(cu->chatid, chatid, sizeof(cu->chatid)); + /* Thor.980921: str_ncpy»P¤@¯ë strncpy¦³©Ò¤£¦P, ¯S§Oª`·N */ + + fprintf(flog, "ENTER\t[%d] %s\n", cu->sno, userid); + + /* Xshadow: ¨ú±o client ªº¨Ó·½ */ + + dns_name(cu->rhost, cu->ibuf); + str_ncpy(cu->rhost, cu->ibuf, sizeof(cu->rhost)); +#if 0 + hp = gethostbyaddr(cu->rhost, sizeof(struct in_addr), AF_INET); + str_ncpy(cu->rhost, hp ? hp->h_name : inet_ntoa((struct in_addr *) cu->rhost), sizeof(cu->rhost)); +#endif + + cu->userno = utent; + + if (cu->clitype) + send_to_user(cu, "¶¶§Q", 0, MSG_LOGINOK); + else + send_to_user(cu, CHAT_LOGIN_OK, 0, MSG_MESSAGE); + + arrive_room(cu, &mainroom); + + send_to_user(cu, "", 0, MSG_MOTDSTART); + print_user_counts(cu); + send_to_user(cu, "", 0, MSG_MOTDEND); + +#ifdef DEBUG + logit("enter", "OK"); +#endif + + return 0; +} + + +static void +chat_act(cu, msg) + ChatUser *cu; + char *msg; +{ + if (*msg) + { + char buf[256]; + + sprintf(buf, "%s \033[36m%s\033[m", cu->chatid, msg); + send_to_room(cu->room, buf, cu->userno, MSG_MESSAGE); + } +} + + +static void +chat_ignore(cu, msg) + ChatUser *cu; + char *msg; +{ + char *str, buf[256]; + + if (RESTRICTED(cu)) + { + str = "¡° ±z¨S¦³ ignore §O¤HªºÅv§Q"; + } + else + { + char *ignoree; + + str = buf; + ignoree = nextword(&msg); + if (*ignoree) + { + ChatUser *xuser; + + xuser = cuser_by_userid(ignoree); + + if (xuser == NULL) + { + sprintf(str, msg_no_such_id, ignoree); + } + else if (xuser == cu || CHATSYSOP(xuser) || + (ROOMOP(xuser) && (xuser->room == cu->room))) + { + sprintf(str, "¡» ¤£¥i¥H ignore [%s]", ignoree); + } + else + { + if (list_belong(cu->ignore, xuser->userno)) + { + sprintf(str, "¡° %s ¤w¸g³Qáµ²¤F", xuser->chatid); + } + else + { + list_add(&(cu->ignore), xuser); + sprintf(str, "¡» ±N [%s] ¥´¤J§N®c¤F :p", xuser->chatid); + } + } + } + else + { + UserList *list; + + if (list = cu->ignore) + { + int len; + char userid[16]; + + send_to_user(cu, "¡» ³o¨Ç¤H³Q¥´¤J§N®c¤F¡G", 0, MSG_MESSAGE); + len = 0; + do + { + sprintf(userid, "%-13s", list->userid); + strcpy(str + len, userid); + len += 13; + if (len >= 78) + { + send_to_user(cu, str, 0, MSG_MESSAGE); + len = 0; + } + } while (list = list->next); + + if (len == 0) + return; + } + else + { + str = "¡» ±z¥Ø«e¨Ã¨S¦³ ignore ¥ô¦ó¤H"; + } + } + } + + send_to_user(cu, str, 0, MSG_MESSAGE); +} + + +static void +chat_unignore(cu, msg) + ChatUser *cu; + char *msg; +{ + char *ignoree, *str, buf[80]; + + ignoree = nextword(&msg); + + if (*ignoree) + { + sprintf(str = buf, (list_delete(&(cu->ignore), ignoree)) ? + "¡» [%s] ¤£¦A³Q±z§N¸¨¤F" : + "¡» ±z¨Ã¥¼ ignore [%s] ³o¸¹¤Hª«", ignoree); + } + else + { + str = "¡» ½Ð«ü©ú user ID"; + } + send_to_user(cu, str, 0, MSG_MESSAGE); +} + + +static void +chat_join(cu, msg) + ChatUser *cu; + char *msg; +{ + if (RESTRICTED(cu)) + { + send_to_user(cu, "¡° ±z¨S¦³¥[¤J¨ä¥L²á¤Ñ«ÇªºÅv", 0, MSG_MESSAGE); + } + else + { + char *roomid = nextword(&msg); + + if (*roomid) + enter_room(cu, roomid, msg); + else + send_to_user(cu, "¡° ½Ð«ü©w²á¤Ñ«Ç", 0, MSG_MESSAGE); + } +} + + +static void +chat_kick(cu, msg) + ChatUser *cu; + char *msg; +{ + char *twit, buf[80]; + ChatUser *xuser; + ChatRoom *room; + + if (!ROOMOP(cu)) + { + send_to_user(cu, msg_not_op, 0, MSG_MESSAGE); + return; + } + + twit = nextword(&msg); + xuser = cuser_by_chatid(twit); + + if (xuser == NULL) + { /* Thor.980604: ¥Î userid¤]¹À³q */ + xuser = cuser_by_userid(twit); + } + + if (xuser == NULL) + { + sprintf(buf, msg_no_such_id, twit); + send_to_user(cu, buf, 0, MSG_MESSAGE); + return; + } + + room = cu->room; + if (room != xuser->room || CLOAK(xuser)) + { + sprintf(buf, msg_not_here, twit); + send_to_user(cu, buf, 0, MSG_MESSAGE); + return; + } + + if (CHATSYSOP(xuser)) + { + sprintf(buf, "¡» ¤£¥i¥H kick [%s]", twit); + send_to_user(cu, buf, 0, MSG_MESSAGE); + return; + } + + exit_room(xuser, EXIT_KICK, (char *) NULL); + + if (room == &mainroom) + xuser->uptime = 0; /* logout_user(xuser); */ + else + enter_room(xuser, MAIN_NAME, (char *) NULL); + /* Thor.980602: ¨ä¹ê½ð´N½ð,¤£nshow¥XxxxÂ÷¶}¤Fªº°T®§¤ñ¸û¦n */ +} + + +static void +chat_makeop(cu, msg) + ChatUser *cu; + char *msg; +{ + char *newop, buf[80]; + ChatUser *xuser; + ChatRoom *room; + + /* Thor.980603: PERM_ALLCHAT §ï¬° default ¨S¦³ roomop, ¦ý¥i¥H¦Û¤v¨ú±o */ + + newop = nextword(&msg); + + room = cu->room; + + if (!*newop && CHATSYSOP(cu)) + { + /* Thor.980603: PERM_ALLCHAT §ï¬° default ¨S¦³ roomop, ¦ý¥i¥H¦Û¤v¨ú±o */ + cu->uflag ^= PERM_CHATOP; + + user_changed(cu); + if (!CLOAK(cu)) + { + sprintf(buf,ROOMOP(cu) ? "¡° ¤Ñ¨Ï ±N Op Åv¤O±Â¤© %s" + : "¡° ¤Ñ¨Ï ±N %s ªº Op Åv¤O¦¬¦^", cu->chatid); + send_to_room(room, buf, 0, MSG_MESSAGE); + } + + return; + } + + /* if (!ROOMOP(cu)) */ + if (!(cu->uflag & PERM_ROOMOP)) /* Thor.980603: chat roomÁ`ºÞ¤£¯àÂಾ Op Åv¤O */ + { + send_to_user(cu, "¡» ±z¤£¯àÂಾ Op ªºÅv¤O" /* msg_not_op */, 0, MSG_MESSAGE); + return; + } + + xuser = cuser_by_chatid(newop); + +#if 0 + if (xuser == NULL) + { /* Thor.980604: ¥Î userid ¹À¤]³q */ + xuser = cuser_by_userid(newop); + } +#endif + + if (xuser == NULL) + { + sprintf(buf, msg_no_such_id, newop); + send_to_user(cu, buf, 0, MSG_MESSAGE); + return; + } + + if (cu == xuser) + { + send_to_user(cu, "¡° ±z¦´N¤w¸g¬O Op ¤F°Ú", 0, MSG_MESSAGE); + return; + } + + /* room = cu->room; */ + + if (room != xuser->room || CLOAK(xuser)) + { + sprintf(buf, msg_not_here, xuser->chatid); + send_to_user(cu, buf, 0, MSG_MESSAGE); + return; + } + + cu->uflag &= ~PERM_ROOMOP; + xuser->uflag |= PERM_ROOMOP; + + user_changed(cu); + user_changed(xuser); + + if (!CLOAK(cu)) + { + sprintf(buf, "¡° %s ±N Op Åv¤OÂಾµ¹ %s", + cu->chatid, xuser->chatid); + send_to_room(room, buf, 0, MSG_MESSAGE); + } +} + + +static void +chat_invite(cu, msg) + ChatUser *cu; + char *msg; +{ + char *invitee, buf[80]; + ChatUser *xuser; + ChatRoom *room; + UserList **list; + + if (!ROOMOP(cu)) + { + send_to_user(cu, msg_not_op, 0, MSG_MESSAGE); + return; + } + + invitee = nextword(&msg); + xuser = cuser_by_chatid(invitee); + +#if 0 + if (xuser == NULL) + { /* Thor.980604: ¥Î userid ¹À¤]³q */ + xuser = cuser_by_userid(invitee); + } +#endif + + if (xuser == NULL) + { + sprintf(buf, msg_no_such_id, invitee); + send_to_user(cu, buf, 0, MSG_MESSAGE); + return; + } + + room = cu->room; /* Thor: ¬O§_n check room ¬O§_ NULL ? */ + list = &(room->invite); + + if (list_belong(*list, xuser->userno)) + { + sprintf(buf, "¡° %s ¤w¸g±µ¨ü¹LÁܽФF", xuser->chatid); + send_to_user(cu, buf, 0, MSG_MESSAGE); + return; + } + list_add(list, xuser); + + sprintf(buf, "¡° %s Áܽбz¨ì [%s] ²á¤Ñ«Ç", + cu->chatid, room->name); + send_to_user(xuser, buf, 0, MSG_MESSAGE); + sprintf(buf, "¡° %s ¦¬¨ì±zªºÁܽФF", xuser->chatid); + send_to_user(cu, buf, 0, MSG_MESSAGE); +} + + +static void +chat_broadcast(cu, msg) + ChatUser *cu; + char *msg; +{ + char buf[80]; + + if (!CHATSYSOP(cu)) + { + send_to_user(cu, "¡° ±z¨S¦³¦b²á¤Ñ«Ç¼s¼½ªºÅv¤O!", 0, MSG_MESSAGE); + return; + } + + if (*msg == '\0') + { + send_to_user(cu, "¡° ½Ð«ü©w¼s¼½¤º®e", 0, MSG_MESSAGE); + return; + } + + sprintf(buf, "\033[1m¡° " BBSNAME "½Í¤Ñ«Ç¼s¼½¤¤ [%s].....\033[m", + cu->chatid); + send_to_room(ROOM_ALL, buf, 0, MSG_MESSAGE); + sprintf(buf, "¡» %s", msg); + send_to_room(ROOM_ALL, buf, 0, MSG_MESSAGE); +} + + +static void +chat_bye(cu, msg) + ChatUser *cu; + char *msg; +{ + exit_room(cu, EXIT_LOGOUT, msg); + cu->uptime = 0; + /* logout_user(cu); */ +} + + +/* --------------------------------------------- */ +/* MUD-like social commands : action */ +/* --------------------------------------------- */ + + +#if 0 /* itoc.010816: «·s½פ@¨Ç¤£¤Ó¾A·íªº action ±Ôz */ + 1. ª`·N«ö¦r¥À±Æ¦C¡C + 2. ½Ð·R¥Î¥þ§Î¼ÐÂI²Å¸¹¡C + 3. ¤TÃþ action ¤£¯à¦³«ÂСC + 4. ¥Ñ©ó action ±Ä¥Î¡u³¡¤À¤ñ¹ï¡v¡A¬G³Ì¦n¤£n¦³«ü¥O¥]§t¥t¤@«ü¥O©Ò¦³ÃöÁä¦rªºª¬ªp¡C + ¡]¨Ò¦p fire/fireball¡Akiss/kissbye¡Ano/nod¡Atea/tear/tease¡Adrive/drivel¡Alove/lover¡^ + ¡]¦³³o¼Ëªº±¡§Î¤]¤£·|«ç»ò¼Ë¡A¥u¬O¨Ï¥ÎªÌ®e©ö·d²V¡^ + 5. ¥Ñ©ó action ³¡¤À¤ñ¹ï¦Ü¤Ö 2 bytes¡A¬G¤£n¥Î //1 //2 ³oÃþ¥u¦³¤@Ó¦rªº action¡C + 6. ¥Ñ©ó action ±Ä¥Î³¡¤À¤ñ¹ï¡A¬G«ü¥O¤£¥²¥ÎÁY¼g¡C + 7. ²Î¤@ action message ³Ì«á¤£n¥[¥yÂI¡C + 8. ×¥¿¿ù¦r¡C¡]¬O adore¡A¤£¬O aodre °Ú :p¡^ + 9. ´î¤Ö«ÂЪº¦r²´¡C¡]¤£n¦Ñ¬O¡u¦º¥h¬¡¨Ó¡v°Ú :p¡^ +#endif + + +struct ChatAction +{ + char *verb; /* °Êµü */ + char *chinese; /* ¤¤¤å½Ķ */ + char *part1_msg; /* ¤¶µü */ + char *part2_msg; /* °Ê§@ */ +}; + + +static ChatAction * +action_fit(action, actnum, cmd) /* §ä¬Ý¬Ý¬OþÓ ChatAction */ + ChatAction *action; + int actnum; + char *cmd; +{ + ChatAction *pos, *locus, *mid; /* locus:¥ª«ü¼Ð mid:¤¤«ü¼Ð pos:¥k«ü¼Ð */ + int cmp; + + /* itoc.010927: ¥Ñ©ó ChatAction ³£¬O«ö¦r¥À±Æ§Çªº¡A©Ò¥H¥i¥H¥Î binary search */ + /* itoc.010928.µù¸Ñ:¥Ñ©ó¬O binary search ©Ò¥HÁöµM recline ±Æ¦b recycle «e± + ¦ý¬O¥´ //rec ®É«o¥i¯à¥X²{ //recycle ªº®ÄªG¡A§P©wÀu¥ý¦¸§ÇºÝ¿à binary ªº¶¶§Ç */ + + locus = action; + pos = action + actnum - 1; /* ³Ì«á¤@Ó¬O NULL¡A¦ý¤£¥i¯à³QÀˬd¨ì */ + + while (1) + { + if (pos <= locus + 1) + break; + + mid = locus + ((pos - locus) >> 1); + + if (!(cmp = str_belong(mid->verb, cmd))) /* itoc.010321: MUD-like match */ + return mid; + else if (cmp < 0) + locus = mid; + else + pos = mid; + } + + /* ¯S¨Ò: ¦pªG¥k«ü¼Ð°±¯d¦b 1¡AnÀˬd²Ä 0 Ó */ + if (pos == action + 1) + { + if (!str_belong(action->verb, cmd)) /* itoc.010321: MUD-like match */ + return action; + } + + return NULL; +} + + +/* itoc.010805.µù¸Ñ: //adore sysop itoc ¹ï sysop ªº´º¥õ¦³¦p·Ê·Ê¦¿¤ô¡A³sºø¤£µ´¡K */ + +#define ACTNUM_PARTY 110 + +static ChatAction party_data[ACTNUM_PARTY] = +{ + { + "adore", "´º¥õ", "¹ï", "ªº´º¥õ¦³¦p·Ê·Ê¦¿¤ô¡A³sºø¤£µ´¡K" + }, + { + "aluba", "ªü¾|¤Ú", "§â", "¬[¤W¬W¤lªü¨ì¦º¡I" + }, + { + "aruba", "ªü¾|¤Ú", "§â", "¬[¤W¬W¤lªü¨ì¦º¡I" + }, + { + "bark", "§p¥s", "¨L¨L¡I¹ï", "¤jÁn§p¥s" + }, + { + "bite", "°Ù«r", "§â", "«r±o¦º¥h¬¡¨Ó" + }, + { + "blade", "¤@¤M", "¤@¤M§â", "°e¤W¦è¤Ñ" + }, + { + "bless", "¯¬ºÖ", "¯¬ºÖ", "¤ß·Q¨Æ¦¨" + }, + { + "blink", "¯w²´", "¹ïµÛ", "¯w¯w²´¡A¤£ª¾·t¥ÜµÛ¤°»ò" + }, + { + "board", "¥D¾÷ªO", "§â", "§ì¥h¸÷¥D¾÷ªO" + }, + { + "bokan", "®ð¥\\", "Âù´x·L¦X¡A»W¶Õ«Ýµo¡K¡K¬ðµM¶¡¡A¹q¥ú¥E²{¡A¹ï", "¨Ï¥X¤F¢Ð¢÷--¢Ù¢é¢ö" + }, + { + "bow", "Áù°`", "²¦°`²¦·qªº¦V", "Áù°`" + }, + { + "box", "¹õ¤§¤º", "¶}©l½üÂ\\¦¡²¾¦ì¡A¹ï", "§@¨xŦ§ðÀ»" + }, + { + "bye", "ÙTÙT", "¦V", "»¡ÙTÙT" + }, + { + "cake", "¥á³J¿|", "®³¥X¤@Ó³J¿|¡A©¹", "ªºÁy¤W¯{¥h" + }, + { + "call", "©I³ê", "¤jÁnªº©I³ê¡A°Ú¡ã", "°Ú¡ã¤H¦bþ¸Ì°Ú°Ú¡ã°Ú" + }, + { + "caress", "»´¼¾", "»´»´ªº¼¾ºNµÛ", "" + }, + { + "clap", "¹ª´x", "¦V", "¼ö¯P¹ª´x" + }, + { + "claw", "§ì§ì", "±q¿ß«}¼Ö¶éɤF°¦¿ß¤ö¡A§â", "§ì±o©ü¤Ñ·t¦a" + }, + { + "clock", "¤Á¾xÄÁ", "¤Á±¼", "ªº¾xÄÁ¡A§Ö°_§É°Õ" + }, + { + "cola", "Äé¥i¼Ö", "¹ï", "Äé¤F¤@¥[¨Úªº¥i¼Ö" + }, + { + "comfort", "¦w¼¢", "·Å¨¥¦w¼¢", "" + }, + { + "congratulate", "®¥³ß", "±qI«á®³¥X¤F©Ô¬¶¡AËé¡IËé¡I®¥³ß", "" + }, + { + "cowhide", "Ã@¥´","®³Ã@¤l¹ï", "¬½¬½¦a©â¥´" + }, + { + "cpr", "¤f¹ï¤f", "¹ïµÛ", "°µ¤f¹ï¤f¤H¤u©I§l" + }, + { + "crime", "¹D¼w", "»¡¡G", "ªº¹D¼w«ü¼Æ¤£°÷¡Aº¡Áy©Ñ®ð" + }, + { + "cringe", "¤^¼¦", "¦V", "¨õ°`©}½¥¡A·n§À¤^¼¦" + }, + { + "cry", "¤jú", "¦V", "Àz°Þ¤jú" + }, + { + "curtsy", "¤¤¥j§", "Àu¶®¦a¹ïµÛ", "¦æ¤¤¥j¥@¬öªº©}½¥Â§¡C" + }, + { + "dance", "¸õ»R", "©Ô¤F", "ªº¤â½¡½¡°_»R" + }, + { + "destroy", "·´·À", "²½°_¤F¡y·¥¤j·´·À©G¤å¡z¡AÅF¦V", "" + }, + { + "dogleg", "ª¯»L", "¹ï", "ªü½Û©^©Ó¡A¤j¤jª¯»L¤F¤@µf" + }, + { + "drivel", "¬y¤f¤ô", "¹ïµÛ", "¬y¤f¤ô" + }, + { + "envy", "¸r¼}", "¦V", "¬yÅS¥X¸r¼}ªº²´¥ú" + }, + { + "evening", "±ß¦w", "¹ï", "»¡¡y±ß¦w¡z" + }, + { + "eye", "°e¬îªi", "¹ï", "ÀW°e¬îªi" + }, + { + "fire", "¾R°Ý", "®³µÛ¤õ¬õªºÅK´Î¨«¦V", "" + }, + { + "forgive", "ì½Ì", "±µ¨ü", "ªº¹Dºp¡Aì½Ì¤F¥L" + }, + { + "french", "ªk¦¡§k", "§â¦ÞÀY¦ù¨ì", "³ïÄV¸Ì¡ã¡ã¡ã«z¡I¤@Ó®öº©ªºªk°ê¦¡²`§k" + }, + { + "fuzzy", "¸³¾", "¬£¥X¸³¾¤@¸¹¦V", "½Ä¹L¥h" + }, + { + "gag", "Á_¼L¤Ú", "§â", " ªº¼L¤Ú¥Î°wÁ_°_¨Ó" + }, + { + "giggle", "¶Ì¯º", "¹ïµÛ", "¶Ì¶Ìªº§b¯º" + }, + { + "glare", "Àü¤H", "§N§N¦aÀüµÛ", "" + }, + { + "glue", "¸É¤ß", "¥Î§Ö°®§â", "ªº¤ßÂH¤F°_¨Ó" + }, + { + "goodbye", "§i§O", "²\\²´¨L¨Lªº¦V", "§i§O" + }, + { + "grin", "¦l¯º", "¹ï", "ÅS¥X¨¸´cªº¯º®e" + }, + { + "growl", "©Hý", "¹ï", "©Hý¤£¤w" + }, + { + "hand", "´¤¤â", "¸ò", "´¤¤â" + }, + { + "hide", "¸ú", "¸ú¦b", "I«á" + }, + { + "hospital", "°eÂå°|", "§â", "°e¶iÂå°|" + }, + { + "hrk", "ª@Às®±", "¨IäF¨§Î¡A¶×»E¤F¤º«l¡A¹ï", "¨Ï¥X¤F¤@°O¢Ö¢÷--¢à£B¢ý--¢Ù¢é¢ö" + }, + { + "hug", "¼ö¾Ö", "¼ö±¡ªº¾Ö©ê", "" + }, + { + "hypnoze", "¶Ê¯v", "®³µÛ±¾¿ö®Ì§r®Ìªº¡A¹ï", "®i¶}¶Ê¯v" + }, + { + "jab", "Ѷ¤H", "¥Î¤O¦aѶµÛ", "¡A¦ü¥G¹ï¥L«Ü¬O¤£º¡" + }, + { + "judo", "¬X¹D", "§ì¦í¤F", "ªº¦çÃÌ¡AÂਡK¡K°Ú¡A¬O¤@°O¹LªÓºL" + }, + { + "kick", "½ð¤H", "§â", "½ð±oµhú¬y®÷" + }, + { + "kill", "¬å¤H", "§â", "¶Ã¤M¬å¦º¡ã¡ã" + }, + { + "kiss", "»´§k", "»´§k", "ªºÁyÀU" + }, + { + "laugh", "¼J¯º", "¤jÁn¼J¯º", "" + }, + { + "levis", "µ¹§Ú", "»¡¡Gµ¹§Ú", "¡I¨ä¾l§K½Í¡I" + }, + { + "lick", "»Q", "¨g»Q", "" + }, + { + "listen", "Å¥", "¥s", "³¬¼L¥J²ÓÅ¥" + }, + { + "lobster", "À£¨î", "¬I®i°f½¼§Î©T©w¡A§â", "À£¨î¦b¦aªO¤W" + }, + { + "love", "ªí¥Õ", "¹ï", "²`±¡ªºªí¥Õ" + }, + { + "mail", "¥´¥]", "§â", "¥´¥]»¼°e¨ì¤j³°" + }, + { + "marry", "¨D±B", "±·µÛ¤E¦Ê¤E¤Q¤E¦·ª´ºÀ¦V", "¨D±B" + }, + { + "morning", "¦¦w", "¹ï", "»¡¡y¦¦w¡z" + }, + { + "noon", "¤È¦w", "¹ï", "»¡¡y¤È¦w¡z" + }, + { + "nod", "ÂIÀY", "¦V", "ÂIÀYºÙ¬O" + }, + { + "nudge", "³»¨{¤l", "¥Î¤â¨y³»", "ªºªÎ¨{¤l" + }, + { + "pad", "©çªÓ»H", "»´©ç", "ªºªÓ»H" + }, + { + "pan", "¥©³Áç", "±qI«á®³¥X¤F¥©³Áç¡A§â", "ºV©ü¤F" + }, + { + "pat", "©çÀY", "©ç©ç", "ªºÀY" + }, + { + "pettish", "¼»¼b", "¸ò", "ÜÝÁnÜÝ®ð¦a¼»¼b" + }, + { + "pili", "ÅRÆE", "¨Ï¥X §g¤l· ¤Ñ¦a®Ú ¯ëYÄb ¤T¦¡¦X¤@¥´¦V", "¡ã¡ã" + }, + { + "pinch", "À¾¤H", "¥Î¤Oªº§â", "À¾±o¶Â«C" + }, + { + "poke", "ÂW§Ë", "ÂW¤FÂW", "·Qn¤Þ°_¥Lªºª`·N" + }, + { + "puding", "Ä饬¤B", "¹ï", "Äé¤F¤@¥d¨®¥¬¤B" + }, + { + "roll", "¥´ºu", "©ñ¥X¦hº¸³Oªºµ¼Ö¡A", "¦b¦a¤Wºu¨Óºu¥h" + }, + { + "protect", "«OÅ@", "»}¦º«OÅ@µÛ", "" + }, + { + "pull", "©Ô", "¦º©R¦a©Ô¦í", "¤£©ñ" + }, + { + "punch", "´~¤H", "¬½¬½´~¤F", "¤@¹y" + }, + { + "rascal", "A¿à", "¸ò", "A¿à" + }, + { + "recline", "¤JÃh", "Æp¨ì", "ªºÃh¸ÌºÎµÛ¤F¡K¡K" + }, + { + "recycle", "¦^¦¬±í", "§â", "¥á¨ì¸ê·½¦^¦¬±í" + }, + { + "respond", "t³d", "¦w¼¢", "»¡¡G¡y¤£nú¡A§Ú·|t³dªº¡z" + }, + { + "scratch", "¿i¤ö", "¾ß°_", "¨Ã䪺¥Û¤l¿i¿i¦Û¤vªº§Q¤ö" + }, + { + "sex", "©ÊÄÌÂZ", "¹ï", "©ÊÄÌÂZ" + }, + { + "shit", "³·¯S", "¹ï", "½|¤F¤@Án¡y³·¯S¡z" + }, + { + "shrug", "ÁqªÓ", "µL©`¦a¦V", "Áq¤FÁqªÓ»H" + }, + { + "sigh", "¼Û®ð", "¹ï", "¼Û¤F¤@¤f®ð" + }, + { + "slap", "¥´¦Õ¥ú", "°Ô°Ôªº¤Ú¤F", "¤@¹y¦Õ¥ú" + }, + { + "smooch", "¾Ö§k", "¾Ö§kµÛ", "" + }, + { + "snicker", "Åѯº", "¼K¼K¼K¦a¹ï", "Åѯº" + }, + { + "sniff", "¤£®h", "¹ï", "¶á¤§¥H»ó" + }, + { + "sorry", "¹ï¤£°_", "¦V", "»¡¹ï¤£°_¡I§Ú¹ï¤£°_¤j®a¡A§Ú¹ï¤£°_°ê®aªÀ·|" + }, + { + "spank", "¥´§¾§¾", "¥Î¤Ú´x¥´", "ªºÁv³¡" + }, + { + "squeeze", "ºò¾Ö", "ºòºò¦a¾Ö©êµÛ", "" + }, + { + "thank", "·PÁÂ", "¦V", "·PÁ±o¤Åé§ë¦a" + }, + { + "throw", "¥áÂY", "®³¤F¸}¤U¤@¶ô¤j¥ÛÀY´Â", "¨º¥á¤F¹L¥h" + }, + { + "tickle", "·kÄo", "©B¼T©B¼T¡A·k", "ªºÄo" + }, + { + "wait", "µ¥¤@¤U", "¥s", "µ¥¤@¤U®@¡I" + }, + { + "wake", "·n¿ô", "»´»´¦a§â", "·n¿ô" + }, + { + "wave", "´§¤â", "¹ïµÛ", "´§´§¤â¡Aªí¥Ü§i§O¤§·N" + }, + { + "welcome", "Åwªï", "Åwªï", "¶i¨Ó¤K¨ö¤@¤U" + }, + { + "what", "¤°»ò", "»¡¡G¡y", "ù¤½½M±K«zÃ÷Å¥¬Y?¡H?¡S?¡z" + }, + { + "whip", "Ã@²Ç", "¤â¤W®³µÛÄúÀë¡A¥ÎÃ@¤lµh¥´", "" + }, + { + "wiggle", "§á§¾ªÑ", "¹ïµÛ", "§á§¾ªÑ" + }, + { + "wink", "¯w²´", "¹ï", "¯«¯µªº¯w¯w²´·ú" + }, + { + "zap", "²r§ð", "¹ï", "ºÆ¨gªº§ðÀ»" + }, + { + NULL, NULL, NULL, NULL + } +}; + + +static int +party_action(cu, cmd, party) + ChatUser *cu; + char *cmd; + char *party; +{ + ChatAction *cap; + char buf[256]; + + if ((cap = action_fit(party_data, ACTNUM_PARTY, cmd))) + { + if (*party == '\0') + { + party = "¤j®a"; + } + else + { + ChatUser *xuser; + + xuser = fuzzy_cuser_by_chatid(party); + if (xuser == NULL) + { /* Thor.980724: ¥Î userid¤]¹À³q */ + xuser = cuser_by_userid(party); + } + + if (xuser == NULL) + { + sprintf(buf, msg_no_such_id, party); + send_to_user(cu, buf, 0, MSG_MESSAGE); + return 0; + } + else if (xuser == FUZZY_USER) + { + send_to_user(cu, "¡° ½Ð«ü©ú²á¤Ñ¥N¸¹", 0, MSG_MESSAGE); + return 0; + } + else if (cu->room != xuser->room || CLOAK(xuser)) + { + sprintf(buf, msg_not_here, party); + send_to_user(cu, buf, 0, MSG_MESSAGE); + return 0; + } + else + { + party = xuser->chatid; + } + } + sprintf(buf, "\033[1;32m%s \033[31m%s\033[33m %s \033[31m%s\033[m", + cu->chatid, cap->part1_msg, party, cap->part2_msg); + send_to_room(cu->room, buf, cu->userno, MSG_MESSAGE); + return 0; /* Thor: cu->room ¬O§_¬° NULL? */ + } + return 1; +} + + +/* --------------------------------------------- */ +/* MUD-like social commands : speak */ +/* --------------------------------------------- */ + + +/* itoc.010805.µù¸Ñ: //ask ¤j®a¤µ¤Ñ¹L±o¦n¶Ü¡H itoc °Ý¤j®a¤µ¤Ñ¹L±o¦n¶Ü¡H*/ + +#define ACTNUM_SPEAK 29 + +static ChatAction speak_data[ACTNUM_SPEAK] = +{ + { + "ask", "¸ß°Ý", "°Ý", NULL + }, + { + "broadcast", "¼s¼½", "¼s¼½", NULL + }, + { + "chant", "ºq¹|", "°ªÁnºq¹|", NULL + }, + { + "cheer", "³Üªö", "³Üªö", NULL + }, + { + "chuckle", "»´¯º", "»´¯º", NULL + }, + { + "curse", "¶A©G", "·t·F", NULL + }, + { + "demand", "n¨D", "n¨D", NULL + }, + { + "fuck", "¤½·F", "¤½·F", NULL + }, + { + "groan", "©D§u", "©D§u", NULL + }, + { + "grumble", "µo¨cÄÌ", "µo¨cÄÌ", NULL + }, + { + "guitar", "¼u°Û", "Ãä¼uµÛ¦N¥L¡AÃä°ÛµÛ", NULL + }, + { + "hum", "³ä³ä", "³ä³ä¦Û»y", NULL + }, + { + "moan", "«è¹Ä", "«è¹Ä", NULL + }, + { + "notice", "±j½Õ", "±j½Õ", NULL + }, + { + "order", "©R¥O", "©R¥O", NULL + }, + { + "ponder", "¨H«ä", "¨H«ä", NULL + }, + { + "pout", "äþ¼L", "äþµÛ¼L»¡", NULL + }, + { + "pray", "¬èë", "¬èë", NULL + }, + { + "request", "Àµ¨D", "Àµ¨D", NULL + }, + { + "shout", "¤j½|", "¤j½|", NULL + }, + { + "sing", "°Ûºq", "°Ûºq", NULL + }, + { + "smile", "·L¯º", "·L¯º", NULL + }, + { + "smirk", "°²¯º", "°²¯º", NULL + }, + { + "swear", "µo»}", "µo»}", NULL + }, + { + "tease", "¼J¯º", "¼J¯º", NULL + }, + { + "whimper", "¶ã«|", "¶ã«|ªº»¡", NULL + }, + { + "yawn", "«¢¤í", "Ã䥴«¢¤íÃ仡", NULL + }, + { + "yell", "¤j³Û", "¤j³Û", NULL + }, + { + NULL, NULL, NULL, NULL + } +}; + + +static int +speak_action(cu, cmd, msg) + ChatUser *cu; + char *cmd; + char *msg; +{ + ChatAction *cap; + char buf[256]; + + if ((cap = action_fit(speak_data, ACTNUM_SPEAK, cmd))) + { + sprintf(buf, "\033[1;32m%s \033[31m%s¡G\033[33m %s\033[m", + cu->chatid, cap->part1_msg, msg); + send_to_room(cu->room, buf, cu->userno, MSG_MESSAGE); + return 0; + } + return 1; +} + + +/* ----------------------------------------------------- */ +/* MUD-like social commands : condition */ +/* ----------------------------------------------------- */ + + +/* itoc.010805.µù¸Ñ: //agree itoc ²`ªí¦P·N */ + +#define ACTNUM_CONDITION 73 + +static ChatAction condition_data[ACTNUM_CONDITION] = +{ + { + "agree", "¦P·N", "²`ªí¦P·N", NULL + }, + { + "aha", "ÆF¥ú", "W«ä¨}¤[¡A©¿µMÆF¥ú¤@²{¡A¤£¸T§r«¢ªº¤@Án", NULL + }, + { + "akimbo", "´¡¸y", "¤S®ð¤SµL©`ªº¨â¤â´¡¸y", NULL + }, + { + "alas", "«u§r", "«u§r§r¡ã", NULL + }, + { + "applaud", "©ç¤â", "°Ô°Ô°Ô°Ô°Ô¡K¡K°Ô°Ô", NULL + }, + { + "avert", "®`²Û", "®`²Û¦aÂà¶}µø½u", NULL + }, + { + "ayo", "üËç³Þ", "üËç³Þ¡ã", NULL + }, + { + "back", "§¤¦^¨Ó", "¦^¨Ó§¤¥¿Ä~Äò¾Ä¾Ô", NULL + }, + { + "blood", "¦b¦å¤¤", "˦b¦åªy¤§¤¤", NULL + }, + { + "blush", "Áy¬õ", "Áy³£¬õ¤F", NULL + }, + { + "broke", "¤ß¸H", "ªº¤ß¯}¸H¦¨¤@¤ù¤@¤ùªº", NULL + }, + { + "bug", "¯äÂÎ", "µo²{³o¨t²Î¦³¢Ð¢ý¢ï¡ã", NULL + }, + { + "careles", "¨S¤H²z", "¶ã¡ã¡ã³£¨S¦³¤H²z§Ú ¡G¡ã", NULL + }, + { + "chew", "¶ß¥Ê¤l", "«Ü±y¶¢ªº¶ß°_¥Ê¤l¨Ó¤F", NULL + }, + { + "climb", "ª¦¤s", "¦Û¤vºCºCª¦¤W¤s¨Ó¡K¡K", NULL + }, + { + "cold", "·P«_", "·P«_¤F¡A¶ý¶ý¤£Åý§Ú¥X¥hª± ¡G¡]", NULL + }, + { + "cough", "«y¹Â", "«y¤F´XÁn", NULL + }, + { + "crash", "·í¾÷", "¶ã¡K" BBSNAME "·í¾÷¤F", NULL + }, + { + "die", "¼ÉÀÅ", "·í³õ¼ÉÀÅ", NULL + }, + { + "dive", "¼ç¤ô", "¸õ¨ì¤ô¸Ì¸ú°_¨Ó", NULL + }, + { + "faint", "©üË", "·í³õ©üË", NULL + }, + { + "fart", "©ñ§¾", "¥þ¬O¦b©ñ§¾¡AJ§è¤@³q¡I", NULL + }, + { + "flop", "»¿¼¥Ö", "½ò¨ì»¿¼¥Ö¡K·ÆË¡I", NULL + }, + { + "fly", "ÄÆÄÆµM", "ÄÆÄÆµM¦a¡A¦n¦ü¸¤F°_¨Ó", NULL + }, + { + "frown", "ÂÙ¬Ü", "Â٬ܡA¤£ª¾¬°¤F¤°»ò", NULL + }, + { + "gold", "®³ª÷µP", "°ÛµÛ¡G¡yª÷£|£±£½ª÷£|£±£½¥X°ê¤ñÁÉ¡A±o«ax¡A®³ª÷µP¡A¥úºa˾H¨Ó¡I¡z", NULL + }, + { + "gulu", "¨{¤l¾j", "ªº¨{¤lµo¥X©BÂP©BÂP¡ãªºÁnµ", NULL + }, + { + "haha", "«¢«¢", "«z«¢«¢«¢¡K¤j¯º¤F°_¨Ó", NULL + }, + { + "happy", "°ª¿³", "°ª¿³±o¦b¦a¤W¥´ºu", NULL + }, + { + "hiccup", "¥´ÜÐ", "¥´ÜÐÓ¤£°±", NULL + }, + { + "hoho", "¨þ¨þ", "¨þ¨þ¨þ¯ºÓ¤£°±", NULL + }, + { + "hypnzed", "³Q¶Ê¯v", "²´¯«§bº¢¡A³Q¶Ê¯v¤F¡K¡K£C¢è£Czzz", NULL + }, + { + "idle", "§b¦í", "Àþ¶¡§b¦í¤F", NULL + }, + { + "jacky", "µl¤l", "µl¤l¯ëªº®Ì¨Ó®Ì¥h", NULL + }, + { + "jealous", "¦Y¾L", "®ð¹ª¹ª¦a³Ü¤F¤@¬û¾L", NULL + }, + { + "jump", "¸õ¼Ó", "¸õ¼Ó¦Û±þ", NULL + }, + { + "luck", "©¯¹B", "«z¡IºÖ®ð°Õ¡I", NULL + }, + { + "macarn", "¤@ºØ»R", "¶}©l¸õ°_¤F¢Û¢é¢Ñ¢é¢à¢í¢Ü¢é¡ã¡ã¡ã¡ã", NULL + }, + { + "miou", "ØpØp", "ØpØp¤f]¤f]¡ã¡ã¡ã¡ã¡ã", NULL + }, + { + "money", "ÁÈ¿ú", "®Iº¬ã¨s«ç¼ËÁȤj¿ú", NULL + }, + { + "mouth", "«ó¼L", "«ó¼L¤¤¡I", NULL + }, + { + "mutter", "§C©B", "§CÁn©B¾ºµÛ¬Y¨Ç¨Æ¡C", NULL + }, + { + "nani", "«ç»ò·|", "¡G©`£®°Ú®º??", NULL + }, + { + "nose", "¬y»ó¦å", "¬y»ó¦å", NULL + }, + { + "puke", "¹Ã¦R", "¹Ã¦R¤¤", NULL + }, + { + "rest", "¥ð®§", "¥ð®§¤¤¡A½Ð¤Å¥´ÂZ", NULL + }, + { + "reverse", "½¨{", "½¨{", NULL + }, + { + "room", "¶}©Ð¶¡", "r-o-O-m-r-O-¢Ý-Mmm-rR¢à........", NULL + }, + { + "scream", "¦y¥s", "¤jÁn¦y¥s¡I °Ú~~~~~~~", NULL + }, + { + "shake", "·nÀY", "·n¤F·nÀY", NULL + }, + { + "sleep", "ºÎµÛ", "w¦bÁä½L¤WºÎµÛ¤F¡A¤f¤ô¬y¶iÁä½L¡A³y¦¨·í¾÷¡I", NULL + }, + { + "snore", "¥´ÂM¤¤", "¥´ÂM¤¤¡K", NULL + }, + { + "sob", "½âF", "¢á¢÷¢ö ¢Ý¢î ¢Ð¢ñ¢ü¢ë¢ð¡I¡I", NULL + }, + { + "stare", "¾®µø", "ÀRÀR¦a¾®µøµÛ¤ÑªÅ", NULL + }, + { + "stretch", "¯hÂ", "¦ù¦ùÃi¸y¤S¥´¤FÓ¨þ¤í«Ü¯h¦üªº¡C", NULL + }, + { + "story", "Á¿¥j", "¶}©lÁ¿¥j¤F", NULL + }, + { + "strut", "·nÂ\\¨«", "¤j·n¤jÂ\\¦a¨«", NULL + }, + { + "suicide", "¦Û±þ", "¦Û±þ", NULL + }, + { + "sweat", "¬y¦½", "´§¦½¦p«B¡I", NULL + }, + { + "tear", "¬y²\\", "µhú¬y®÷¤¤.....", NULL + }, + { + "think", "«ä¦Ò", "¬nµÛÀY·Q¤F¤@¤U", NULL + }, + { + "tongue", "¦R¦Þ", "¦R¤F¦R¦ÞÀY", NULL + }, + { + "wall", "¼²Àð", "¶]¥h¼²Àð", NULL + }, + { + "wawa", "«z«z", "«z«z«z~~~~~!!!!! ~~~>_<~~~", NULL + }, + { + "wc", "¬~¤â¶¡", "¥ø¬~¤â¶¡¤@¤U :>", NULL + }, + { + "whine", "¨{¤l¾j", "¨{¤l¾j! :(", NULL + }, + { + "whistle", "§j¤fï", "§j¤fï", NULL + }, + { + "wolf", "¯TÀz", "£±£¹£±£¹¡K£±£¹£±£¹¡K", NULL + }, + { + "www", "¨L¨L", "¨L¨L¨L¡I", NULL + }, + { + "ya", "£¬C", "¾¾¡ã¢ç¢Ï¡I *^_^*", NULL + }, + { + "zzz", "¥´©I", "©IÂP¡ãZZzZz£C¢èZZzzZzzzZZ", NULL + }, + { + NULL, NULL, NULL, NULL + } +}; + + +static int +condition_action(cu, cmd) + ChatUser *cu; + char *cmd; +{ + ChatAction *cap; + char buf[256]; + + if ((cap = action_fit(condition_data, ACTNUM_CONDITION, cmd))) + { + sprintf(buf, "\033[1;32m%s \033[31m%s\033[m", + cu->chatid, cap->part1_msg); + send_to_room(cu->room, buf, cu->userno, MSG_MESSAGE); + return 1; + } + return 0; +} + + +/* --------------------------------------------- */ +/* MUD-like social commands : help */ +/* --------------------------------------------- */ + + +static char *dscrb[] = +{ + "\033[1;37m¡i Verb + Nick¡G °Êµü + ¹ï¤è¦W¦r ¡j\033[36m ¨Ò¡G//kick piggy\033[m", + "\033[1;37m¡i Verb + Message¡G°Êµü + n»¡ªº¸Ü ¡j\033[36m ¨Ò¡G//sing ¤Ñ¤Ñ¤ÑÂÅ\033[m", + "\033[1;37m¡i Verb¡G°Êµü ¡j ¡ô¡õ¡G¸ܫ´£\033[m", NULL +}; + + + +static ChatAction *catbl[] = +{ + party_data, speak_data, condition_data, NULL +}; + + +static void +chat_partyinfo(cu, msg) + ChatUser *cu; + char *msg; +{ + if (common_client_command) + { + send_to_user(cu, "3 °Ê§@ ¥æ½Í ª¬ºA", 0, MSG_PARTYINFO); + } +} + + +static void +chat_party(cu, msg) + ChatUser *cu; + char *msg; +{ + int kind, i; + ChatAction *cap; + char buf[80]; + + if (!common_client_command) + return; + + kind = atoi(nextword(&msg)); + if (kind < 0 || kind > 2) + return; + + sprintf(buf, "%d\t%s", kind, kind == 2 ? "I" : ""); + + /* Xshadow: ¥u¦³ condition ¤~¬O immediate mode */ + send_to_user(cu, buf, 0, MSG_PARTYLISTSTART); + + cap = catbl[kind]; + for (i = 0; cap[i].verb; i++) + { + sprintf(buf, "%-10s %-20s", cap[i].verb, cap[i].chinese); + send_to_user(cu, buf, 0, MSG_PARTYLIST); + } + + sprintf(buf, "%d", kind); + send_to_user(cu, buf, 0, MSG_PARTYLISTEND); +} + + +#define MAX_VERB_LEN 8 +#define VERB_NO 10 + + +static void +view_action_verb(cu, cmd) /* Thor.980726: ·s¥[°Êµü¤ÀÃþÅã¥Ü */ + ChatUser *cu; + int cmd; +{ + int i; + char *p, *q, *data, *expn, buf[256]; + ChatAction *cap; + + send_to_user(cu, "/c", 0, MSG_CLRSCR); + + data = buf; + + if (cmd < '1' || cmd > '3') + { /* Thor.980726: ¼g±o¤£¦n, ·Q¿ìªk§ï¶i... */ + for (i = 0; p = dscrb[i]; i++) + { + sprintf(data, " [//]help %d - MUD-like ªÀ¥æ°Êµü ²Ä %d Ãþ", i + 1, i + 1); + send_to_user(cu, data, 0, MSG_MESSAGE); + send_to_user(cu, p, 0, MSG_MESSAGE); + send_to_user(cu, " ", 0, MSG_MESSAGE); /* Thor.980726: ´«¦æ */ + } + } + else + { + i = cmd - '1'; + + send_to_user(cu, dscrb[i], 0, MSG_MESSAGE); + + expn = buf + 100; /* Thor.980726: À³¸Ó¤£·|overlap§a? */ + + *data = '\0'; + *expn = '\0'; + + cap = catbl[i]; + + for (i = 0; p = cap[i].verb; i++) + { + q = cap[i].chinese; + + strcat(data, p); + strcat(expn, q); + + if (((i + 1) % VERB_NO) == 0) + { + send_to_user(cu, data, 0, MSG_MESSAGE); + send_to_user(cu, expn, 0, MSG_MESSAGE); /* Thor.980726: Åã¥Ü¤¤¤åµù¸Ñ */ + *data = '\0'; + *expn = '\0'; + } + else + { + strncat(data, " ", MAX_VERB_LEN - strlen(p)); + strncat(expn, " ", MAX_VERB_LEN - strlen(q)); + } + } + + if (i % VERB_NO) + { + send_to_user(cu, data, 0, MSG_MESSAGE); + send_to_user(cu, expn, 0, MSG_MESSAGE); /* Thor.980726: Åã¥Ü¤¤¤åµù¸Ñ */ + } + } + /* send_to_user(cu, " ", 0); *//* Thor.980726: ´«¦æ, »Ýn " " ¶Ü? */ +} + + +/* ----------------------------------------------------- */ +/* chat user service routines */ +/* ----------------------------------------------------- */ + + +static ChatCmd chatcmdlist[] = +{ + "act", chat_act, 0, + "bye", chat_bye, 0, + "chatroom", chat_chatroom, 1, /* Xshadow: for common client */ + "clear", chat_clear, 0, + "cloak", chat_cloak, 2, + "date", chat_date, 0, + "flags", chat_setroom, 0, + "help", chat_help, 0, + "ignore", chat_ignore, 1, + "invite", chat_invite, 0, + "join", chat_join, 0, + "kick", chat_kick, 1, + "msg", chat_private, 0, + "nick", chat_nick, 0, + "operator", chat_makeop, 0, + "party", chat_party, 1, /* Xshadow: party data for common client */ + "partyinfo", chat_partyinfo, 1, /* Xshadow: party info for common client */ + +#ifndef STAND_ALONE + "query", chat_query, 0, +#endif + + "quit", chat_bye, 0, + + "room", chat_list_rooms, 0, + "unignore", chat_unignore, 1, + "whoin", chat_list_by_room, 1, + "wall", chat_broadcast, 2, + + "who", chat_map_chatids_thisroom, 0, + "list", chat_list_users, 0, + "topic", chat_topic, 1, + "version", chat_version, 1, + + NULL, NULL, 0 +}; + + +/* Thor: 0 ¤£¥Î exact, 1 n exactly equal, 2 ¯µ±K«ü¥O */ + + +static int +command_execute(cu) + ChatUser *cu; +{ + char *cmd, *msg, buf[128]; + /* Thor.981108: lkchu patch: chatid + msg ¥u¥Î 80 bytes ¤£°÷, §ï¬° 128 */ + ChatCmd *cmdrec; + int match, ch; + + msg = cu->ibuf; + match = *msg; + + /* Validation routine */ + + if (cu->room == NULL) + { + /* MUST give special /! or /-! command if not in the room yet */ + + if (match == '/' && ((ch = msg[1]) == '!' || (ch == '-' && msg[2] == '!'))) + { + if (ch == '-') + fprintf(flog, "cli\t[%d] S%d\n", cu->sno, cu->sock); + + cu->clitype = (ch == '-') ? 1 : 0; + return (login_user(cu, msg + 2 + cu->clitype)); + } + else + { + return -1; + } + } + + /* If not a /-command, it goes to the room. */ + + if (match != '/') + { + if (match) + { + if (cu->room && !CLOAK(cu)) /* Áô¨ªº¤H¤]¤£¯à»¡¸Ü®@ */ + { + char chatid[16]; + + sprintf(chatid, "%s:", cu->chatid); + sprintf(buf, "%-10s%s", chatid, msg); + send_to_room(cu->room, buf, cu->userno, MSG_MESSAGE); + } + } + return 0; + } + + msg++; + cmd = nextword(&msg); + match = 0; + + if (*cmd == '/') + { + cmd++; + /* if (!*cmd || !str_cmp("help", cmd)) */ + if (!*cmd || str_match(cmd, "help") >= 0) /* itoc.010321: ³¡¤À match ´Nºâ */ + { + cmd = nextword(&msg); /* Thor.980726: °Êµü¤ÀÃþ */ + view_action_verb(cu, *cmd); + match = 1; + } + else if (!party_action(cu, cmd, msg)) + match = 1; + else if (!speak_action(cu, cmd, msg)) + match = 1; + else + match = condition_action(cu, cmd); + } + else + { + char *str; + + common_client_command = 0; + if (*cmd == '-') + { + if (cu->clitype) + { + cmd++; /* Xshadow: «ü¥O±q¤U¤@Ó¦r¤¸¤~¶}©l */ + common_client_command = 1; + } + else + { + /* ¤£¬O common client ¦ý°e¥X common client «ü¥O -> °²¸Ë¨S¬Ý¨ì */ + } + } + + str_lower(buf, cmd); + + for (cmdrec = chatcmdlist; str = cmdrec->cmdstr; cmdrec++) + { + switch (cmdrec->exact) + { + case 1: /* exactly equal */ + match = !str_cmp(str, buf); + break; + + case 2: /* Thor: secret command */ + if (CHATSYSOP(cu)) + match = !str_cmp(str, buf); + break; + + default: /* not necessary equal */ + match = str_match(buf, str) >= 0; + break; + } + + if (match) + { + cmdrec->cmdfunc(cu, msg); + break; + } + } + } + + if (!match) + { + sprintf(buf, "¡» «ü¥O¿ù»~¡G/%s", cmd); + send_to_user(cu, buf, 0, MSG_MESSAGE); + } + + return 0; +} + + +/* ----------------------------------------------------- */ +/* serve chat_user's connection */ +/* ----------------------------------------------------- */ + + +static int +cuser_serve(cu) + ChatUser *cu; +{ + int ch, len, isize; + char *str, *cmd, buf[256]; + + str = buf; + len = recv(cu->sock, str, sizeof(buf) - 1, 0); + if (len < 0) + { + ch = errno; + + exit_room(cu, EXIT_LOSTCONN, NULL); + logit("recv", strerror(ch)); + return -1; + } + + if (len == 0) + { + if (++cu->retry > 100) + return -1; + return 0; + } + +#if 0 + /* Xshadow: ±N°e¹Fªº¸ê®Æ©¾¹ê¬ö¿ý¤U¨Ó */ + memcpy(logbuf, buf, sizeof(buf)); + for (ch = 0; ch < sizeof(buf); ch++) + { + if (!logbuf[ch]) + logbuf[ch] = '$'; + } + + logbuf[len + 1] = '\0'; + logit("recv: ", logbuf); +#endif + +#if 0 + logit(cu->userid, str); +#endif + + cu->xdata += len; + + isize = cu->isize; + cmd = cu->ibuf + isize; + while (len--) + { + ch = *str++; + + if (ch == '\r' || !ch) + continue; + + if (ch == '\n') + { + *cmd = '\0'; + + if (command_execute(cu) < 0) + return -1; + + isize = 0; + cmd = cu->ibuf; + + continue; + } + + if (isize < SCR_WIDTH) + { + *cmd++ = ch; + isize++; + } + } + cu->isize = isize; + return 1; +} + + +/* ----------------------------------------------------- */ +/* chatroom server core routines */ +/* ----------------------------------------------------- */ + + +static int +/* start_daemon(mode) + int mode; */ +servo_daemon(inetd) + int inetd; +{ + int fd, value; + char buf[80]; + struct sockaddr_in sin; + struct linger ld; +#ifdef HAVE_RLIMIT + struct rlimit limit; +#endif + + /* + * More idiot speed-hacking --- the first time conversion makes the C + * library open the files containing the locale definition and time zone. + * If this hasn't happened in the parent process, it happens in the + * children, once per connection --- and it does add up. + */ + + time((time_t *) &value); + gmtime((time_t *) &value); + strftime(buf, 80, "%d/%b/%Y:%H:%M:%S", localtime((time_t *) &value)); + + /* --------------------------------------------------- */ + /* speed-hacking DNS resolve */ + /* --------------------------------------------------- */ + + dns_init(); +#if 0 + gethostname(buf, sizeof(buf)); + gethostbyname(buf); +#endif + +#ifdef HAVE_RLIMIT + /* --------------------------------------------------- */ + /* adjust the resource limit */ + /* --------------------------------------------------- */ + + getrlimit(RLIMIT_NOFILE, &limit); + limit.rlim_cur = limit.rlim_max; + setrlimit(RLIMIT_NOFILE, &limit); + + limit.rlim_cur = limit.rlim_max = 4 * 1024 * 1024; + setrlimit(RLIMIT_DATA, &limit); + +#ifdef SOLARIS +#define RLIMIT_RSS RLIMIT_AS /* Thor.981206: port for solaris 2.6 */ +#endif + + setrlimit(RLIMIT_RSS, &limit); + + limit.rlim_cur = limit.rlim_max = 0; + setrlimit(RLIMIT_CORE, &limit); + +#if 0 + limit.rlim_cur = limit.rlim_max = 60 * 20; + setrlimit(RLIMIT_CPU, &limit); +#endif +#endif + + /* --------------------------------------------------- */ + /* detach daemon process */ + /* --------------------------------------------------- */ + + close(2); + close(1); + + /* if (mode > 1) */ + if (inetd) + return 0; + + close(0); + + if (fork()) + exit(0); + + setsid(); + + if (fork()) + exit(0); + + /* --------------------------------------------------- */ + /* bind the service port */ + /* --------------------------------------------------- */ + + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + /* + * timeout ¤è±, ±N socket §ï¦¨ O_NDELAY (no delay, non-blocking), + * ¦pªG¯à¶¶§Q°e¥X¸ê®Æ´N°e¥X, ¤£¯à°e¥X´Nºâ¤F, ¤£¦Aµ¥«Ý TCP_TIMEOUT ®É¶¡¡C + * (default ¬O 120 ¬í, ¨Ã¥B¦³ 3-way handshaking ¾÷¨î, ¦³¥i¯à¤@µ¥¦Aµ¥)¡C + */ + +#if 1 + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NDELAY); +#endif + + value = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value, sizeof(value)); + + value = 1; + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &value, sizeof(value)); + + ld.l_onoff = ld.l_linger = 0; + setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &ld, sizeof(ld)); + + sin.sin_family = AF_INET; + sin.sin_port = htons(CHAT_PORT); + sin.sin_addr.s_addr = htonl(INADDR_ANY); + memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); + + if ((bind(fd, (struct sockaddr *) & sin, sizeof(sin)) < 0) || + (listen(fd, SOCK_QLEN) < 0)) + exit(1); + + return fd; +} + + +#ifdef SERVER_USAGE +static void +server_usage() +{ + struct rusage ru; + + if (getrusage(RUSAGE_SELF, &ru)) + return; + + fprintf(flog, "\n[Server Usage]\n\n" + "user time: %.6f\n" + "system time: %.6f\n" + "maximum resident set size: %lu P\n" + "integral resident set size: %lu\n" + "page faults not requiring physical I/O: %d\n" + "page faults requiring physical I/O: %d\n" + "swaps: %d\n" + "block input operations: %d\n" + "block output operations: %d\n" + "messages sent: %d\n" + "messages received: %d\n" + "signals received: %d\n" + "voluntary context switches: %d\n" + "involuntary context switches: %d\n" + "gline: %d\n\n", + + (double) ru.ru_utime.tv_sec + (double) ru.ru_utime.tv_usec / 1000000.0, + (double) ru.ru_stime.tv_sec + (double) ru.ru_stime.tv_usec / 1000000.0, + ru.ru_maxrss, + ru.ru_idrss, + ru.ru_minflt, + ru.ru_majflt, + ru.ru_nswap, + ru.ru_inblock, + ru.ru_oublock, + ru.ru_msgsnd, + ru.ru_msgrcv, + ru.ru_nsignals, + ru.ru_nvcsw, + ru.ru_nivcsw, + gline); + + fflush(flog); +} +#endif + + +static void +reaper() +{ + while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0) + ; +} + + +static void +sig_trap(sig) + int sig; +{ + char buf[80]; + + sprintf(buf, "signal [%d] at line %d (errno: %d)", sig, gline, errno); + logit("EXIT", buf); + fclose(flog); + exit(1); +} + + +static void +sig_over() +{ + int fd; + + server_usage(); + logit("OVER", ""); + fclose(flog); + for (fd = 0; fd < 64; fd++) + close(fd); + execl("bin/xchatd", NULL); +} + + +static void +main_signals() +{ + struct sigaction act; + + /* sigblock(sigmask(SIGPIPE)); */ + /* Thor.981206: ²Î¤@ POSIX ¼Ð·Ç¥Îªk */ + + /* act.sa_mask = 0; */ /* Thor.981105: ¼Ð·Ç¥Îªk */ + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + act.sa_handler = sig_trap; + sigaction(SIGBUS, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGTERM, &act, NULL); + + act.sa_handler = sig_over; + sigaction(SIGXCPU, &act, NULL); + + act.sa_handler = reaper; + sigaction(SIGCHLD, &act, NULL); + +#ifdef SERVER_USAGE + act.sa_handler = server_usage; + sigaction(SIGPROF, &act, NULL); +#endif + + /* Thor.981206: lkchu patch: ²Î¤@ POSIX ¼Ð·Ç¥Îªk */ + /* ¦b¦¹É¥Î sigset_t act.sa_mask */ + sigaddset(&act.sa_mask, SIGPIPE); + sigprocmask(SIG_BLOCK, &act.sa_mask, NULL); + +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int sock, nfds, maxfds, servo_sno; + ChatUser *cu,/* *userpool,*/ **FBI; + time_t uptime, tcheck; + fd_set rset, xset; + static struct timeval tv = {CHAT_INTERVAL, 0}; + struct timeval tv_tmp; /* Thor.981206: for future reservation bug */ + + sock = 0; + + while ((nfds = getopt(argc, argv, "hid")) != -1) + { + switch (nfds) + { + case 'i': + sock = 1; + break; + + case 'd': + break; + + case 'h': + default: + + fprintf(stderr, "Usage: %s [options]\n" + "\t-i start from inetd with wait option\n" + "\t-d debug mode\n" + "\t-h help\n", + argv[0]); + exit(0); + } + } + + servo_daemon(sock); + /* start_daemon(argc); */ + + setgid(BBSGID); + setuid(BBSUID); + chdir(BBSHOME); + umask(077); + + log_init(); + + main_signals(); + + /* --------------------------------------------------- */ + /* init variable : rooms & users */ + /* --------------------------------------------------- */ + + userpool = NULL; + strcpy(mainroom.name, MAIN_NAME); + strcpy(mainroom.topic, MAIN_TOPIC); + + /* --------------------------------------------------- */ + /* main loop */ + /* --------------------------------------------------- */ + + tcheck = 0; + servo_sno = 0; + + for (;;) + { + uptime = time(0); + if (tcheck < uptime) + { + nfds = maxfds = 0; + FD_ZERO(&mainfset); + FD_SET(0, &mainfset); + + tcheck = uptime - CHAT_INTERVAL; + + for (FBI = &mainuser; cu = *FBI;) + { + if (cu->uptime < tcheck) + { + cuser_free(cu); + + *FBI = cu->unext; + + cu->unext = userpool; + userpool = cu; + } + else + { + nfds++; + sock = cu->sock; + FD_SET(sock, &mainfset); + if (maxfds < sock) + maxfds = sock; + + FBI = &(cu->unext); + } + } + + totaluser = nfds; + fprintf(flog, "MAINTAIN %d user (%d)\n", nfds, maxfds++); + fflush(flog); + + tcheck = uptime + CHAT_INTERVAL; + } + + /* ------------------------------------------------- */ + /* Set up the fdsets */ + /* ------------------------------------------------- */ + + rset = mainfset; + xset = mainfset; + + /* Thor.981206: for future reservation bug */ + tv_tmp = tv; + nfds = select(maxfds, &rset, NULL, &xset, &tv_tmp); + +#if 0 + { + char buf[32]; + static int xxx; + + if ((++xxx & 8191) == 0) + { + sprintf(buf, "%d/%d", nfds, maxfds); + logit("MAIN", buf); + } + } +#endif + + if (nfds == 0) + { + continue; + } + + if (nfds < 0) + { + sock = errno; + if (sock != EINTR) + { + logit("select", strerror(sock)); + } + continue; + } + + /* ------------------------------------------------- */ + /* serve active agents */ + /* ------------------------------------------------- */ + + uptime = time(0); + + for (FBI = &mainuser; cu = *FBI;) + { + sock = cu->sock; + + if (FD_ISSET(sock, &rset)) + { + static int xxx, xno; + + nfds = cuser_serve(cu); + + if ((++xxx & 511) == 0) + { + int sno; + + sno = cu->sno; + fprintf(flog, "rset\t[%d] S%d R%d %d\n", sno, sock, nfds, xxx); + if (sno == xno) + nfds = -1; + else + xno = sno; + } + } + else if (FD_ISSET(sock, &xset)) + { + nfds = -1; + } + else + { + nfds = 0; + } + + if (nfds < 0 || cu->uptime <= 0) /* free this client */ + { + cuser_free(cu); + + *FBI = cu->unext; + + cu->unext = userpool; + userpool = cu; + + continue; + } + + if (nfds > 0) + { + cu->uptime = uptime; + } + + FBI = &(cu->unext); + } + + /* ------------------------------------------------- */ + /* accept new connection */ + /* ------------------------------------------------- */ + + if (FD_ISSET(0, &rset)) + { + + { + static int yyy; + + if ((++yyy & 2047) == 0) + fprintf(flog, "conn\t%d\n", yyy); + } + + for (;;) + { + int value; + struct sockaddr_in sin; + + value = sizeof(sin); + sock = accept(0, (struct sockaddr *) &sin, &value); + if (sock > 0) + { + if (cu = userpool) + { + userpool = cu->unext; + } + else + { + cu = (ChatUser *) malloc(sizeof(ChatUser)); + } + + *FBI = cu; + + /* variable initialization */ + + memset(cu, 0, sizeof(ChatUser)); + cu->sock = sock; + cu->tbegin = uptime; + cu->uptime = uptime; + cu->sno = ++servo_sno; + cu->xdata = 0; + cu->retry = 0; + memcpy(cu->rhost, &sin.sin_addr, sizeof(struct in_addr)); + + totaluser++; + + FD_SET(sock, &mainfset); + if (sock >= maxfds) + maxfds = sock + 1; + + { + int value; + + value = 1; + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + (char *) &value, sizeof(value)); + } + +#if 1 + fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NDELAY); +#endif + + fprintf(flog, "CONN\t[%d] %d %s\n", + servo_sno, sock, Btime(&cu->tbegin)); + break; + } + + nfds = errno; + if (nfds != EINTR) + { + logit("accept", strerror(nfds)); + break; + } + +#if 0 + while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0); +#endif + } + } + + /* ------------------------------------------------- */ + /* tail of main loop */ + /* ------------------------------------------------- */ + + } +} diff --git a/game/Makefile b/game/Makefile new file mode 100644 index 0000000..a2c5848 --- /dev/null +++ b/game/Makefile @@ -0,0 +1,64 @@ +# ------------------------------------------------------ # +# Makefile ( NTHU CS MapleBBS Ver 2.36 ) # +# ------------------------------------------------------ # +# author : opus.bbs@bbs.cs.nthu.edu.tw # +# target : Makefile for MapleBBS main programs # +# create : 95/03/29 # +# update : 95/12/15 # +# ------------------------------------------------------ # + + +# ------------------------------------------------------ # +# ¤U¦Cªº make rules ¤£»Ý×§ï # +# ------------------------------------------------------ # + + +SO = bar.so bingo.so bj.so bwboard.so chessmj.so dice.so dragon.so dict.so fantan.so \ + gp.so gray.so guessnum.so km.so liteon.so marie.so mine.so nine.so \ + pushbox.so race.so recall.so seven.so tetris.so + + +.SUFFIXES: +.SUFFIXES: .c .o .so + +.c.o: ; $(CC) $(CFLAGS) -c $*.c +.o.so: ; ld -s -G $*.o -o $*.so -L../lib -ldao + + +all: + @echo "Please enter 'make sys-type', " + @echo " make sun : for Sun-OS 4.x and maybe some BSD systems, cc or gcc" + @echo " make linux : for Linux" + @echo " make solaris : for Sun-OS 5.x gcc" + @echo " make sol-x86 : for Solaris 7 x86" + @echo " make freebsd : for BSD 4.4 systems" + @echo " make bsd : for BSD systems, cc or gcc, if not in the above lists" + @echo " make cygwin : for Microsoft Windows and Cygwin gcc" + +sun: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -fomit-frame-pointer -Wunused -I../include" $(SO) + +linux: + @$(MAKE) CC=gcc CFLAGS="-DLINUX -O2 -pipe -fomit-frame-pointer -Wunused -I../include" $(SO) + +solaris: + @$(MAKE) CC=gcc CFLAGS="-DSOLARIS -DSYSV -O2 -pipe -fomit-frame-pointer -Wunused -I../include" $(SO) + +sol-x86: + @$(MAKE) CC=gcc CFLAGS="-DSOLARIS -DSYSV -O2 -fomit-frame-pointer -Wunused -I../include" $(SO) + +freebsd: + @$(MAKE) CC=gcc CFLAGS="-DBSD44 -O2 -pipe -fomit-frame-pointer -Wunused -I../include" $(SO) + +bsd: + @$(MAKE) CC=gcc CFLAGS="-DBSD44 -O2 -pipe -fomit-frame-pointer -Wunused -I../include" $(SO) + +cygwin: + @cd ../maple; make cygwin + + +install: $(SO) + install -m 0700 $? $(HOME)/bin + +clean: + rm -f *.so *.o *~ diff --git a/game/bar.c b/game/bar.c new file mode 100644 index 0000000..aeb4a26 --- /dev/null +++ b/game/bar.c @@ -0,0 +1,387 @@ +/*-------------------------------------------------------*/ +/* bar.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : BAR ¥x¹CÀ¸ */ +/* create : / / */ +/* update : 01/04/27 */ +/* author : unknown */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + + +#if 0 + ¢~¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢¡ + ¢x¡ñ¢x£Y¢x¡º¢x¡À¢x¡¸¢x77¢x¡ð¢x¡ñ¢x¡µ¢x¡º¢x£Y¢x£[¢x¡º¢x77¢x¡¸¢x¡ñ¢x¡ð¢x¡º¢x + ¢u¢w¢q¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢q¢w¢t + ¢x£Y¢x ¢x¡À¢x + ¢u¢w¢t ¢u¢w¢t + ¢x¡µ¢x ¢x¡µ¢x + ¢u¢w¢t ¢u¢w¢t + ¢x£[¢x ¢x£[¢x + ¢u¢w¢t ¢u¢w¢t + ¢x£Y¢x ¢x¡ð¢x + ¢u¢w¢t ¢u¢w¢t + ¢x77¢x ¢x¡¸¢x + ¢u¢w¢t ùþ¤j ¡¼¤p ¢u¢w¢t + ¢x¡º¢x ¢x£Y¢x + ¢u¢w¢q¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢q¢w¢t + ¢x¡À¢x¡ð¢x77¢x£Y¢x¡º¢x¡µ¢x¡ñ¢x¡¸¢x¡ð¢x£Y¢x¡À¢x£[¢x¡º¢x77¢x£Y¢x¡ñ¢x¡µ¢x77¢x + ¢¢¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢£ +#endif + +static char *itemlist[10] = {" ", "£[", "¡ð", "¡ñ", "¡À", "¡µ", "¡¸", "77", "¡º", "£Y"}; /* ¶µ¥Ø¦W */ + +static int bar[49] = /* ¤W¹Ï 48 ®æ¤¤(¥Ñ¥ª¤W"¡ñ"¶}©l¶¶®É°w¶)©Ò¹ïÀ³ªº itemlist[] */ +{ + 0, 3, 9, 8, 4, 6, 7, 2, 3, 5, + 8, 9, 1, 8, 7, 6, 3, 2, 8, 4, + 5, 1, 2, 6, 9, 7, 5, 3, 9, 7, + 8, 1, 4, 9, 2, 6, 3, 5, 8, 9, + 7, 2, 4, 8, 7, 9, 1, 5, 9 +}; /* ªO±¦ì§} */ + +static int money[10]; /* ©ãª÷ */ + + +static int +total_money() /* ¬O§_¦³¤Uª` */ +{ + if (money[1] || money[2] || money[3] || money[4] || money[5] || + money[6] || money[7] || money[8] || money[9]) + { + return 1; + } + return 0; +} + + +static int +run(step, last, freq) + int step; /* ¦ì¸m */ + int last; /* 1: ³Ì«á¤@¨B 0: ¤¤¶¡¨B */ + int freq; /* frequency: Hz */ +{ + int x1, y1, x2, y2; + + if (step == 1) + { + x1 = 6; + y1 = 4; + x2 = 4; + y2 = 4; + } + + else if (step > 1 && step < 19) + { + x1 = 4; + y1 = 4 * step - 4; + x2 = 4; + y2 = 4 * step; + } + + else if (step > 18 && step < 26) + { + x1 = 2 * step - 34; + y1 = 72; + x2 = 2 * step - 32; + y2 = 72; + } + + else if (step > 25 && step < 43) + { + x1 = 18; + y1 = 176 - 4 * step; + x2 = 18; + y2 = 172 - 4 * step; + } + + else if (step > 42 && step < 49) + { + x1 = 104 - 2 * step; + y1 = 4; + x2 = 102 - 2 * step; + y2 = 4; + } + + move(x1, y1); + if (step == 1) + outs(itemlist[9]); + else + outs(itemlist[bar[step - 1]]); + + move(x2, y2); + if (last) + outs(itemlist[bar[step]]); + else + outs("ùþ"); + + refresh(); + usleep(1000000 / freq); /* µ¥«Ý */ +} + + +static inline int +get_item() /* ¶Ã¼Æ¿ï¨ún¤¤ªº¶µ¥Ø */ +{ + +#if 0 +½s¸¹¡G 1 2 3 4 5 6 7 8 9 +¶µ¥Ø¡G "£[", "¡ð", "¡ñ", "¡À", "¡µ", "¡¸", "77", "¡º", "£Y" +¾÷²v¡G 13 16 21 26 32 43 64 127 308 /650 +½ß²v¡G 50 40 30 25 20 15 10 5 2 +#endif + + int randnum = rnd(650); /* ½ß²v * ¾÷²v = ´Á±æÈ (¨C©ã 1 ¤¸©Ò¦^¦¬ªºª÷ÃB) */ + + if (randnum < 308) /* 2 * 308 / 650 = 0.948 */ + return 9; + if (randnum < 435) /* 5 * 127 / 650 = 0.978 */ + return 8; + if (randnum < 499) /* 10 * 64 / 650 = 0.985 */ + return 7; + if (randnum < 542) /* 15 * 43 / 650 = 0.992 */ + return 6; + if (randnum < 574) /* 20 * 32 / 650 = 0.985 */ + return 5; + if (randnum < 600) /* 25 * 26 / 650 = 1.000 */ + return 4; + if (randnum < 621) /* 30 * 21 / 650 = 0.969 */ + return 3; + if (randnum < 637) /* 40 * 16 / 650 = 0.985 */ + return 2; + + return 1; /* 50 * 13 / 650 = 1.000 */ +} + + +static inline int /* ¶Ç¦^ map ¤Wªº 1~48 ¨ä¤¤¤@ӼƦr */ +get_dst(item) /* ¶Ç¤J¤¤ªº¶µ¥Ø¿ï¨ú³Ì«á°±¯dªº¦ì¸m */ + int item; +{ + int dst, randnum; + + randnum = rnd(48) + 1; /* ±q¤¤¶¡©¹«e«á¿ï¨ú¡AÁ×§K¨C¦¸³£±q 1 ¿ï·|³£¤¤¥k¤W¨¤ªº³¡¤À */ + + for (dst = randnum; dst <= 48; dst++) + { + if (bar[dst] == item) + return dst; + } + + for (dst = randnum; dst >= 1; dst--) + { + if (bar[dst] == item) + return dst; + } +} + + +static inline void +print_total() +{ + outs("\n\n"); + outs(" ¢~¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢¡\n"); + outs(" ¢x¡ñ¢x£Y¢x¡º¢x¡À¢x¡¸¢x77¢x¡ð¢x¡ñ¢x¡µ¢x¡º¢x£Y¢x£[¢x£Y¢x77¢x¡¸¢x¡ñ¢x¡ð¢x¡º¢x\n"); + outs(" ¢u¢w¢q¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢q¢w¢t\n"); + outs(" ¢x£Y¢x ¢x¡À¢x\n"); + outs(" ¢u¢w¢t ¢u¢w¢t\n"); + outs(" ¢x¡µ¢x ¢x¡µ¢x\n"); + outs(" ¢u¢w¢t ¢u¢w¢t\n"); + outs(" ¢x£[¢x ¢x£[¢x\n"); + outs(" ¢u¢w¢t ¢u¢w¢t\n"); + outs(" ¢x£Y¢x ¢x¡ð¢x\n"); + outs(" ¢u¢w¢t ¢u¢w¢t\n"); + outs(" ¢x77¢x ¢x¡¸¢x\n"); + outs(" ¢u¢w¢t ùþ¤j ¡¼¤p ¢u¢w¢t\n"); + outs(" ¢x¡º¢x ¢x£Y¢x\n"); + outs(" ¢u¢w¢q¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢q¢w¢t\n"); + outs(" ¢x¡À¢x¡ð¢x77¢x£Y¢x¡º¢x¡µ¢x¡ñ¢x¡¸¢x¡ð¢x£Y¢x¡À¢x£[¢x¡º¢x77¢x£Y¢x¡ñ¢x¡µ¢x77¢x\n"); + outs(" ¢¢¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢£\n"); + outs(" \033[1;31m¢x£[¢x \033[32m¢x¡ð¢x \033[33m¢x¡ñ¢x \033[34m¢x¡À¢x \033[35m¢x¡µ¢x \033[36m¢x¡¸¢x \033[37m¢x77¢x \033[0;36m¢x¡º¢x \033[33m¢x£Y¢x \033[m\n"); + outs(" \033[1;31m¢x50¢x \033[32m¢x40¢x \033[33m¢x30¢x \033[34m¢x25¢x \033[35m¢x20¢x \033[36m¢x15¢x \033[37m¢x10¢x \033[0;36m¢x 5¢x \033[33m¢x 2¢x \033[m"); +} + + +int +main_bar() +{ + int price[10] = {0, 50, 40, 30, 25, 20, 15, 10, 5, 2}; /* ¿²v */ + + int item; /* ¶µ¥Ø½s¸¹ */ + int ogn, dst; /* OriGiN: °_ÂI DeStinaTion: ²×ÂI */ + int ch, i, j; + char buf[80]; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + vs_bar("BAR ¥x"); + print_total(); /* ¦LªO± */ + ogn = 1; /* °_ÂI¦b²Ä¤@®æ */ + + while (1) + { + for (i = 1; i < 10; i++) /* money Âk¹s */ + money[i] = 0; + + for (;;) + { + /* ¨M©w¦U¶µ½äª` */ + + ch = vget(2, 0, "±zn©ãþ¶µ(1-9)¡H[S]¶}©l [Q]Â÷¶}¡G", buf, 3, DOECHO); + if (!ch || ch == 's') + { + if (total_money()) + break; + addmoney(money[1] + money[2] + money[3] + money[4] + money[5] + money[6] + money[7] + money[8] + money[9]); /* ÁÙ¿ú */ + goto abort_game; + } + else if (ch < '1' || ch > '9') + { + addmoney(money[1] + money[2] + money[3] + money[4] + money[5] + money[6] + money[7] + money[8] + money[9]); /* ÁÙ¿ú */ + goto abort_game; + } + + if (!(vget(2, 0, "n©ã¦h¤Ö½äª÷¡H", buf, 6, DOECHO))) + { + if (total_money()) + break; + addmoney(money[1] + money[2] + money[3] + money[4] + money[5] + money[6] + money[7] + money[8] + money[9]); /* ÁÙ¿ú */ + goto abort_game; + } + + j = atoi(buf); + if (j < 1 || j > cuser.money) + { + addmoney(money[1] + money[2] + money[3] + money[4] + money[5] + money[6] + money[7] + money[8] + money[9]); /* ÁÙ¿ú */ + goto abort_game; + } + + cuser.money -= j; + money[ch - '0'] += j; + + move(b_lines - 1, 0); + clrtoeol(); + outs("\033[1m "); + for (i = 1; i < 10; i++) + prints("\033[3%dm%6d ", i, money[i]); + prints("\n\033[m Äw½XÁÙ¦³ %d ¤¸ ", cuser.money); + } + + /* ¶}©l¶]¤F */ + + item = get_item(); /* ¶Ã¼Æ¿ï¨ú¤¤ªº¶µ¥Ø */ + dst = get_dst(item); /* ¥Ñ©Ò¤¤ªº¶µ¥Ø¨Ó¨M©w³Ì«á°±¯dªº¦ì¸m */ + + for (i = ogn; i <= 48; i++) /* ²Ä¤@°é */ + { + run(i, 0, 10 + i / 10); /* °_©l¥[³t¡A¨C¬í 10 - 14 ¦¸¡A¶V¶]¶V§Ö */ + } + + for (j = 0; j < 2; j++) /* ¤¤¶¡¶]¤G°é´N¦n¤F */ + { + for (i = 1; i < 49; i++) /* ¤¤¶¡ªº°é */ + { + run(i, 0, 15); /* ¤¤¬q°ª³t¡Aºû«ù¨C¬í 15 ¦¸ */ + } + } + + for (i = 1; i <= dst; i++) /* ³Ì«á¤@°é */ + { + run(i, 0, 14 - i / 10); /* ³Ì«á´î³t¡A¨C¬í 14 - 10 ¦¸ */ + } + + for (j = 0; j < 2; j++) /* ¦b³Ì«á°±¯dªº¦ì¸m°{¤G¦¸ */ + { + run(dst, 0, 2); + run(dst, 1, 2); + } + + move(2, 0); + clrtoeol(); + prints("¤¤¼úªº¬O \033[37m%s\033[m¡A", itemlist[item]); + + if (!money[item]) + { + outs("Ý¢Àt +_+"); + } + else + { + money[0] = money[item] * price[item]; + prints("®¥³ß±z©ã¤¤¤F¡AÀò±o¼úª÷ \033[32m%d\033[m", money[0]); + + for (;;) /* ¥i¥H¤@ª½¤ñ¤j¤p¤ñ¨ì²n */ + { + sprintf(buf, "¥Ø«e¼úª÷: %d ±zÁÙn¤ñ¤j¤p¶Ü(Y/N)¡H[N] ", money[0]); + + if (vans(buf) != 'y') /* ¤£¤ñ¤j¤p */ + { + move(2, 0); + clrtoeol(); + prints("±o¼úª÷ %d", money[0]); + break; + } + else /* ¤ñ¤j¤p */ + { + sprintf(buf, "±zn©ã¤°»ò¡H [1]¤j (2)¤p "); + ch = vans(buf) - '1'; /* ch = 0:¤j 1:¤p */ + + for (i = 16; i <= 20; i++) + { + move(15, 30); + outs("ùþ¤j ¡¼¤p"); + refresh(); + usleep(6000 * (i ^ 2)); + + move(15, 30); + outs("¡¼¤j ùþ¤p"); + usleep(6000 * (i ^ 2)); + refresh(); + } + + price[0] = rnd(2); + move(15, 30); + if (price[0]) + outs("ùþ¤j ¡¼¤p"); + else + outs("¡¼¤j ùþ¤p"); + + if (price[0] == ch) + { + money[0] *= 2; + move(2, 0); + clrtoeol(); + outs("°Ú¡I©ã¤¤¤F¡I¼úª÷Åܦ¨¤G¿¡I"); + } + else + { + money[0] = 0; + move(2, 0); + clrtoeol(); + outs("µª¿ù¤F¡I¹s¤À¡I"); + break; /* ¤ñ¤j¤pµ²§ô */ + } + } + } + addmoney(money[0]); + } /* ¤ñ¤j¤pµ²§ô */ + + vmsg("Ä~Äò¤U¤@½L¤jÁÉ"); + move(b_lines, 0); + clrtoeol(); /* ²M°£½Ð«ö¥ô·NÁäÄ~Äò */ + + ogn = dst; /* ¤U¦¸°_ÂI¬O¤W¦¸ªº²×ÂI */ + } + +abort_game: + return 0; +} +#endif /* HAVE_GAME */ diff --git a/game/bingo.c b/game/bingo.c new file mode 100644 index 0000000..e22ec8e --- /dev/null +++ b/game/bingo.c @@ -0,0 +1,186 @@ +/*-------------------------------------------------------*/ +/* bingo.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : »«ªG¹CÀ¸ */ +/* create : / / */ +/* update : 01/04/21 */ +/* author : unknown */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + + +static void +out_song() +{ + static int count = 0; + + /* ±i¾Ç¤Í & °ª¼z§g£»§A³Ì¬Ã¶Q */ + uschar *msg[9] = + { + "©ú¦~³oӮɶ¡ ¬ù¦b³oÓ¦aÂI", + "°O±o±aµÛª´ºÀ ¥´¤W»â±aô¤W«ä©À", + "°Ê±¡®É¨è³Ì¬ü ¯u±¡ªºµ¹¤£²Ö", + "¤Ó¦hªº·R©È¾K ¨S¤H¯k·R¦A¬üªº¤H ¤]·|¼¬±|", + "§Ú·|°e§A¬õ¦âª´ºÀ §A§O®³¤@¥Í²´²\\¬Û¹ï", + "¥¼¨Óªº¤é¤l¦³§A¤~¬ü ¹Ú¤~·|¯u¤@ÂI", + "§Ú¾ÇµÛ ¦b§A·R¸Ì¨I¾K §A¦uÅ@µÛ§Ú¬ï¹L¶Â©]", + "§Ú¤£ºM°h §ÚÄ@·N", + "³o±ø±¡¸ô ¬Û¦u¬ÛÀH §A³Ì¬Ã¶Q" + }; + move(b_lines - 2, 0); + prints("\033[1;3%dm%s\033[m Äw½XÁÙ¦³ %d ¤¸", time(0) % 7, msg[count], cuser.money); + clrtoeol(); + if (++count == 9) + count = 0; +} + + +int +main_bingo() +{ + /* 25Ó {x§¤¼Ð, y§¤¼Ð, È} */ + int place[5][5][3] = + { + {{3, 2, 0}, {3, 6, 0}, {3, 10, 0}, {3, 14, 0}, {3, 18, 0}}, + {{5, 2, 0}, {5, 6, 0}, {5, 10, 0}, {5, 14, 0}, {5, 18, 0}}, + {{7, 2, 0}, {7, 6, 0}, {7, 10, 0}, {7, 14, 0}, {7, 18, 0}}, + {{9, 2, 0}, {9, 6, 0}, {9, 10, 0}, {9, 14, 0}, {9, 18, 0}}, + {{11, 2, 0}, {11, 6, 0}, {11, 10, 0}, {11, 14, 0}, {11, 18, 0}} + }; + + /* ½ß²v : ²q 5 ¦¸´N¦¨¥\½ß 20 ¿¡A²q 6 ¦¸´N¦¨¥\½ß 15 ¿ ... ¦Ü¤Ön²q 5 ¦¸¤~¥i¯à¦¨¥\ */ + int rate[13 + 1] = {0, 1, 2, 3, 5, 7, 10, 15, 20, 0, 0, 0, 0, 0}; + + char used[25]; /* 25 ӼƦr¬O§_¥Î¹L */ + int money; /* ©ãª÷ */ + int account; /* ÁÙ¦³´X¦¸¥i²q */ + int success; /* ³s¦¨¤@ª½½u¤F¶Ü */ + + int row, col, i; + char buf[60]; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + while (1) + { + vs_bar("»«ªG¤j¾Ô"); + out_song(); + + vget(2, 0, "½Ð°Ýn¤Uª`¦h¤Ö©O¡H(1 ~ 50000) ", buf, 6, DOECHO); + money = atoi(buf); + if (money < 1 || money > 50000 || money > cuser.money) + break; /* Â÷¶}½ä³õ */ + cuser.money -= money; + + /* initialize */ + + for (i = 0; i < 25; i++) /* 25 ӼƦr³£ÁÙ¨S³Q¿ï */ + used[i] = 0; + + for (row = 0; row < 5; row++) /* ´Ñ½Lªº 25 ®æ¥ýÂk¹s */ + { + for (col = 0; col < 5; col++) + place[row][col][2] = 0; + } + + /* µe´Ñ½L */ + + move(4, 0); + for (i = 0; i < 5; i++) + { + outs(" \033[1;44m \033[m\n" + " \033[44m \033[42m \033[44m \033[42m \033[44m \033[42m " + "\033[44m \033[42m \033[44m \033[42m \033[44m \033[m\n"); + } + outs(" \033[44m \033[m\n"); + + /* game start */ + + for (account = 13, success = 0; account && !success; account--) + { + move(b_lines - 7, 0); + outs("\033[1;37;44m©|¥¼¶}¥Xªº¸¹½X\033[m\n"); + for (i = 1; i <= 25; i++) + { + if (!used[i - 1]) + prints(" %2d", i); + } + + prints("\n©|¦³\033[1;33;41m %2d \033[m¦¸¾÷·|¥i²q ¤U¦¸²q¤¤¥i±o\033[1;37;44m %d \033[m¿\n", + account, rate[account]); + + do + { + vget(b_lines - 4, 0, "½Ð¿é¤J±zªº¸¹½X¡G", buf, 3, DOECHO); + i = atoi(buf); + } while (i <= 0 || i > 25 || used[i - 1]); + + /* ¨Ã¤£¬O¤@¶}©l´N¨M©w´Ñ½L¤W 25 Ó¦ì¸mªºÈ¡A¦Ó¬O user ¨C²q¤@ӼƦr + ¦A¥h¨M©wn§â³oӼƦr©ñ¦b´Ñ½L¤WªºþÓ¦ì¸m */ + do + { + row = rnd(5); + col = rnd(5); + } while (place[row][col][2]); + + place[row][col][2] = i; + used[i - 1] = 1; + + /* §â·sªºÂI¨º¾ã¦Cµe¤W´Ñ½L */ + + move(5 + row * 2, 0); + clrtoeol(); + outs(" \033[1m"); + for (i = 0; i < 5; i++) + { + outs("\033[44m "); + if (place[row][i][2]) + prints("\033[40m%2d", place[row][i][2]); + else + outs("\033[42m "); + } + outs("\033[44m \033[m\n"); + + if (account >= 13 - 5) /* ¦Ü¤Ön²q 5 ¦¸«á¤~»ÝnÀˬd¬O§_³s¦¨¤@ª½½u */ + continue; + + /* Àˬd¬O§_³s¦¨¤@ª½½u */ + /* Y¦b¤G±ø¹ï¨¤½u¤W¡An¯S§OÀˬd¹ï¨¤½u¡A§_«h¥unÀˬd¸Ó¦æ¦C§Y¥i */ + + if ((row == col && place[0][0][2] && place[1][1][2] && place[2][2][2] && place[3][3][2] && place[4][4][2]) || + (row + col == 4 && place[0][4][2] && place[1][3][2] && place[2][2][2] && place[3][1][2] && place[4][0][2]) || + (place[row][0][2] && place[row][1][2] && place[row][2][2] && place[row][3][2] && place[row][4][2]) || + (place[0][col][2] && place[1][col][2] && place[2][col][2] && place[3][col][2] && place[4][col][2])) + { + success = 1; + break; + } + + } /* for °j°éµ²§ô¡A¥i¯à¬O²q§¹ 13 ¦¸©Î¬O¦¨¥\¤F */ + + if (success) + { + money *= rate[account]; + sprintf(buf, "®¥³ß±z...ŤF %d ¤¸ ", money); + addmoney(money); + } + else + { + strcpy(buf, "¹B®ð¤£¨Î...¦A¨Ó¤@½L§a¡I"); + } + vmsg(buf); + + } /* while °j°éµ²§ô¡AÂ÷¶}¹CÀ¸ */ + + return 0; +} +#endif /* HAVE_GAME */ diff --git a/game/bj.c b/game/bj.c new file mode 100644 index 0000000..9fe2eb1 --- /dev/null +++ b/game/bj.c @@ -0,0 +1,389 @@ +/*-------------------------------------------------------*/ +/* bj.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¶Â³Ç§J¤G¤Q¤@ÂI¹CÀ¸ */ +/* create : / / */ +/* update : 01/04/23 */ +/* author : unknown */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#ifdef HAVE_GAME + + +enum +{ /* ¿²v */ + + SEVEN = 5, /* 777 */ + SUPERAJ = 5, /* spade A+J */ + AJ = 4, /* A+J */ + FIVE = 3, /* ¹L¤Ãö */ + JACK = 3, /* ¬°«e¨â±i´N 21 ÂI */ + WIN = 2 /* Ĺ */ +}; + + +static char *flower[4] = {"¢á", "¢Ö", "¢Ò", "¢Ñ"}; +static char *poker[53] = +{ + "¢Ï", "¢Ï", "¢Ï", "¢Ï", "¢±", "¢±", "¢±", "¢±", "¢²", "¢²", "¢²", "¢²", + "¢³", "¢³", "¢³", "¢³", "¢´", "¢´", "¢´", "¢´", "¢µ", "¢µ", "¢µ", "¢µ", + "¢¶", "¢¶", "¢¶", "¢¶", "¢·", "¢·", "¢·", "¢·", "¢¸", "¢¸", "¢¸", "¢¸", + "¢â", "¢â", "¢â", "¢â", "¢Ø", "¢Ø", "¢Ø", "¢Ø", "¢ß", "¢ß", "¢ß", "¢ß", + "¢Ù", "¢Ù", "¢Ù", "¢Ù", " " +}; + + +static void +out_song() +{ + static int count = 0; + + /* ³\¯øªå£»·R¥u³Ñ¤@¬í */ + uschar *msg[9] = + { + "½t¥÷§Ö·À¤F ²´«e¬O®ü¨¤ ÁÙ©¹«e¸õ ¤âÀ¹¤W¤â¾R", + "¤£·QÅý¾Ö©ê¡@¦A©ñ±¼ §A¤@±Ã¤ã §Ú´Nµh¨ì ©I§l¤£¤F", + "·R´¿¨º»ò¦n ¤£¯à¨ì¦Ñ §A¦óW¡@³s°²À¸¯u§@§A³£°µ¤£¨ì", + "²´¬Ý ©¯ºÖ¥u³Ñ¤@¬í §AÁÙ¸¨²\\¨DÄÇ", + "n¨D§Ú©ñ±¼¡@¤£ª¾¸Ó»¡¤°»ò¤~¦n", + "¦Û¤v²`·Rªº¤H ³º¹³¤p«Ä¡@µL²z¨ú¾x", + "¥Í©R¡@¦pªG¥u³Ñ¤@¬í §Ú¥u·Qn§ë¾a", + "¦º¦b§AÃh©ê ¹Ú¸Ì¦Û´M¤Ñ¯î¦a¦Ñ¡@¹j¥@§â¤ß¸®±¼", + "§Aªººp·N¡@¦A¶Ë¤£¤F¡@§Úªº¦n" + }; + move(b_lines - 2, 0); + prints("\033[1;3%dm%s\033[m Äw½XÁÙ¦³ %d ¤¸", time(0) % 7, msg[count], cuser.money); + clrtoeol(); + if (++count == 9) + count = 0; +} + + +static void +print_card(int card, int x, int y) +{ + + move(x, y); + outs("¢~¢w¢w¢w¢¡"); + move(x + 1, y); + prints("¢x%s ¢x", poker[card]); + move(x + 2, y); + prints("¢x%s ¢x", card != 52 ? flower[card % 4] : " "); + move(x + 3, y); + outs("¢x ¢x"); + move(x + 4, y); + outs("¢x ¢x"); + move(x + 5, y); + outs("¢x ¢x"); + move(x + 6, y); + outs("¢¢¢w¢w¢w¢£"); +} + + +static char +get_newcard(mode) + int mode; /* 0:«·s¬~µP 1:µoµP */ +{ + static char card[10]; /* ³Ì¦h¥u·|¥Î¨ì 10 ±iµP */ + static int now; /* µo¥X²Ä now ±iµP */ + char num; + int i; + + if (!mode) /* «·s¬~µP */ + { + now = 0; + return -1; + } + +rand_num: /* random ¥X¤@±i©M¤§«e³£¤£¦PªºµP */ + num = rnd(52); + for (i = 0; i < now; i++) + { + if (num == card[i]) /* ³o±iµP¥H«e random ¹L¤F */ + goto rand_num; + } + + card[now] = num; + now++; + + return num; +} + + +int +main_bj() +{ + int money; /* ©ãª÷ */ + + /* ¹q¸£¬O²ø®a */ + char host_card[12]; /* ¹q¸£ªºµP±i */ + char guest_card[12]; /* ª±®aªºµP±i */ + + int host_count; /* ¹q¸£®³¤F´X±iµP */ + int guest_count; /* ª±®a®³¤F´X±iµP */ + + int host_A; /* ¹q¸£®³ A ªº±i¼Æ */ + int guest_A; /* ª±®a®³ A ªº±i¼Æ */ + int host_point; /* ¹q¸£®³ªºÁ`ÂI¼Æ */ + int guest_point; /* ª±®a®³ªºÁ`ÂI¼Æ */ + + int doub; /* ¬O§_¤w¸g¥[¿©ãª÷ */ + int ch; /* «öÁä */ + + int card; + char buf[60]; + + int num[52] = /* ¦U±iµPªºÂI¼Æ */ + { + 11, 11, 11, 11, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10 + }; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + while (1) + { + vs_bar("¶Â³Ç§J¤j¾Ô"); + out_song(); + + vget(2, 0, "½Ð°Ýn¤Uª`¦h¤Ö©O¡H(1 ~ 50000) ", buf, 6, DOECHO); + money = atoi(buf); + if (money < 1 || money > 50000 || money > cuser.money) + break; /* Â÷¶}½ä³õ */ + + cuser.money -= money; + doub = 0; + + move(3, 0); + outs("(«ö y ÄòµP, n ¤£ÄòµP, d double)"); + + out_song(); + + get_newcard(0); /* ¬~µP */ + + guest_card[0] = get_newcard(1); + guest_card[1] = get_newcard(1); + host_card[0] = get_newcard(1); + host_card[1] = get_newcard(1); + + host_count = 2; /* ¦¹®É¡AÂù¤è¦U¦³¤G±iµP */ + guest_count = 2; + host_A = 0; /* ¦¹®É¡AÂù¤è³£¨S¦³ Ace */ + guest_A = 0; + + /* Àˬd A ªº±i¼Æ¡A¨Ó¨M©w¬O§_¦³ Black Jack ©Î¬O§â A ·í 11 ÂI */ + + if (host_card[0] < 4) + host_A++; + if (host_card[1] < 4) + host_A++; + if (guest_card[0] < 4) + guest_A++; + if (guest_card[1] < 4) + guest_A++; + + print_card(52, 5, 0); /* ¦L¥X¹q¸£ªº²Ä¤@±iµP(¦ýÅã¥ÜªÅ¥Õ) */ + print_card(host_card[1], 5, 4); /* ¦L¥X¹q¸£ªº²Ä¤G±iµP */ + print_card(guest_card[0], 14, 0); /* ¦L¥Xª±®aªº²Ä¤@±iµP */ + print_card(guest_card[1], 14, 4); /* ¦L¥Xª±®aªº²Ä¤G±iµP */ + + host_point = num[host_card[1]]; /* ¹q¸£ªº²Ä¤@±iµP¼È®É¤£ºâÂI(¥H§K¼ÉÅSµª®×) */ + guest_point = num[guest_card[0]] + num[guest_card[1]]; + + move(12, 0); + prints("\033[1;32mÂI¼Æ¡G\033[33m%2d\033[m", host_point); + + for (;;) + { + /* ÀˬdµP«¬ */ +check_condition: + + /* itoc.011025: ª±®a¨C¨ú¤@±iµP´Nn«Ã¸¤@¦¸ÂI¼Æ */ + move(13, 0); + prints("\033[1;35mÂI¼Æ¡G\033[36m%2d\033[m", guest_point); + + if (guest_count == 3 && /* nÀˬd guest_count ¥H§K²Ä¤T±iµP¬O¤W¦¸µP */ + (guest_card[0] >= 24 && guest_card[0] <= 27) && + (guest_card[1] >= 24 && guest_card[1] <= 27) && + (guest_card[2] >= 24 && guest_card[2] <= 27)) + { + money *= SEVEN; + sprintf(buf, "\033[1;41;33m ¢¶¢¶¢¶ ±o¼úª÷ %d »È¨â \033[m", money); + goto next_game; + } + + else if ((guest_card[0] == 40 && guest_card[1] == 0) || + (guest_card[0] == 0 && guest_card[1] == 40)) + { + money *= SUPERAJ; + sprintf(buf, "\033[1;41;33m¥¿²Î BLACK JACK ±o¼úª÷ %d »È¨â \033[m", money); + goto next_game; + } + + else if (((guest_card[0] <= 3 && guest_card[0] >= 0) && + (guest_card[1] <= 43 && guest_card[1] >= 40)) || + ((guest_card[1] <= 3 && guest_card[1] >= 0) && + (guest_card[0] <= 43 && guest_card[0] >= 40))) + { + money *= AJ; + sprintf(buf, "\033[1;41;33m BLACK JACK ±o¼úª÷ %d »È¨â \033[m", money); + goto next_game; + } + + else if (guest_point == 21 && guest_count == 2) /* «e¨â±i´N 21 ÂI */ + { + money *= JACK; + sprintf(buf, "\033[1;41;33m JACK ±o¼úª÷ %d »È¨â \033[m", money); + goto next_game; + } + + else if (guest_count == 5 && guest_point <= 21) + { + money *= FIVE; + sprintf(buf, "\033[1;41;33m ¹L¤Ãö ±o¼úª÷ %d »È¨â \033[m", money); + goto next_game; + } + + else if (guest_point > 21 && guest_A) + { + guest_point -= 10; + guest_A--; + move(13, 0); + prints("\033[1;35mÂI¼Æ¡G\033[36m%2d\033[m", guest_point); + goto check_condition; + } + + /* ¤@¯ëµP«¬ */ + + else + { + /* Ãz¤F */ + + if (guest_point > 21) + { + money = 0; + strcpy(buf, "\033[1;41;33m Ãz¤F ¿ú³Q¦Y¥ú¤F \033[m"); + goto next_game; + } + + /* ¨SÃz */ + + do + { + ch = igetch(); + + if (ch == 'd' && !doub && guest_count == 2) /* ¥u¯à¦b²Ä¤G±iµP¯à®É double */ + { + doub = 1; /* ¤w double¡A¤£¯à¦A double */ + + if (cuser.money >= money) + { + cuser.money -= money; + money *= 2; + } + else + { + money += cuser.money; /* ¿ú¤£°÷¤G¿¡A´N¥þ±ô¤F */ + cuser.money = 0; + } + out_song(); + } + } while (ch != 'y' && ch != 'n'); + + if (ch == 'y' && guest_point != 21) /* ª±®aÄòµP */ + { + card = get_newcard(1); + guest_card[guest_count] = card; + if (card < 4) + guest_A++; + + guest_point += num[card]; + print_card(card, 14, 4 * guest_count); + guest_count++; + move(13, 0); + prints("\033[1;35mÂI¼Æ¡G\033[36m%2d\033[m", guest_point); + goto check_condition; + } + else /* ª±®a¤£ÄòµP */ + { + /* ¥ýÅã¥Ü²ø®aªº²Ä¤@±iµP */ + move(6, 2); + outs(poker[host_card[0]]); + move(7, 2); + outs(flower[host_card[0] % 4]); + host_point += num[host_card[0]]; /* §âè¶}©l¨S¥[ªº²Ä¤@±iµPÂI¥[¦^¨Ó */ + + /* ½ü¨ì¹q¸£(²ø®a)¨úµP */ + + if (host_A == 2) /* ¯S¨Ò: ¹q¸£¤G±i©³µP«ê¦n³£¬O A ®É·|§PÂ_¿ù»~ */ + { + /* §â¤@±i A ±q 11 ÂI´«¦¨ 1 ÂI */ + host_point -= 10; + host_A--; + } + + while (host_point < guest_point) /* ²ø®a¦pªGÂI¤ñ¸û¤Ö¡A´N±j¢¨úµP */ + { + card = get_newcard(1); + host_card[host_count] = card; + if (card < 4) + host_A++; + + host_point += num[card]; + print_card(card, 5, 4 * host_count); + host_count++; + + if (host_point > 21) + { + if (host_A) + { + host_point -= 10; + host_A--; + continue; /* Ä~Äò¨ú¤U¤@±iµP */ + } + + move(12, 0); + prints("\033[1;32mÂI¼Æ¡G\033[33m%2d\033[m", host_point); + + /* ¹q¸£(²ø®a)Ãz¤F */ + + money *= WIN; + sprintf(buf, "\033[1;41;33m WINNER ±o¼úª÷ %d »È¨â \033[m", money); + goto next_game; + } + } + + /* ¹q¸£(²ø®a)¨úµPµ²§ô¡A¥B¨S¦³Ãz±¼¡A¹q¸£Àò³Ó */ + + move(12, 0); + prints("\033[1;32mÂI¼Æ¡G\033[33m%2d\033[m", host_point); + + money = 0; + strcpy(buf, "\033[1;41;33m ¿é¤F ¿ú³Q¦Y¥ú¤F \033[m"); + goto next_game; + } + + } /* if ÀˬdµP«¬µ²§ô */ + + } /* for °j°éµ²§ô¡Aµ²§ô³o¦^¦X */ + +next_game: + move(18, 3); + outs(buf); + addmoney(money); + vmsg(NULL); + } /* while °j°éµ²§ô¡AÂ÷¶}¹CÀ¸ */ + + return 0; +} +#endif /* HAVE_GAME */ diff --git a/game/bwboard.c b/game/bwboard.c new file mode 100644 index 0000000..bb18d0e --- /dev/null +++ b/game/bwboard.c @@ -0,0 +1,2408 @@ +/*-------------------------------------------------------*/
+/* bwboard.c ( NTHU CS MapleBBS Ver 3.10 ) */
+/*-------------------------------------------------------*/
+/* target : B/W & Chinese Chess Board */
+/* create : 02/08/05 */
+/* update : / / */
+/*-------------------------------------------------------*/
+
+
+#include "bbs.h"
+
+#ifdef HAVE_GAME
+
+
+/*-------------------------------------------------------*/
+/* ©Ò¦³´Ñ½L¤½¥Îªº°Ñ¼Æ */
+/*-------------------------------------------------------*/
+
+/* lantw44: ±q ch_printmsg() ·h¥X¨Óªº¨ç¦¡«Å§i */
+
+static char *ch_brdline(int);
+
+extern char lastcmd[MAXLASTCMD][80];
+
+
+enum
+{
+ DISCONNECT = -2, LEAVE = -1, NOTHING = 0
+};
+
+
+enum
+{
+ Binit = 0, Bupdate = 1, Ballow = 2
+};
+
+
+enum
+{
+ Empty = 0, Black = 1, White = 2, Red = 2
+};
+
+
+static int msgline; /* Where to display message now */
+static int cfd; /* socket number */
+static int myColor; /* my chess color */
+static int Choose; /* -3:¶Â¥Õ´Ñ -2:¤¤l´Ñ -1:³ò´Ñ 0:x´Ñ 1:·t´Ñ */
+static int dark_choose; /* ·t´Ñ¬O§_¤w½¶}²Ä¤@¤l */
+
+static int (**rule) ();
+
+static int bwRow, bwCol;
+static char Board[19][19];
+static char forspace[61];
+
+
+static char *ruleStrSet[] = {"¶Â¥Õ´Ñ", "¤¤l´Ñ", "³ò´Ñ", "x´Ñ", "·t´Ñ"};
+static char *ruleStr;
+
+static KeyFunc *mapTalk, *mapTurn;
+
+static int cmdCol, cmdPos;
+static char talkBuf[42] = "T";
+static char *cmdBuf = &talkBuf[1];
+static KeyFunc Talk[];
+
+
+static void bw_printmsg();
+static void ch_printmsg();
+static void do_init();
+
+
+static int
+do_send(buf)
+ char *buf;
+{
+ int len;
+
+ len = strlen(buf) + 1; /* with trail 0 */
+ return (send(cfd, buf, len, 0) == len);
+}
+
+
+#ifdef EVERY_BIFF
+static void
+check_biff()
+{
+ /* Thor.980805: ¦³¤H¦b®ÇÃä«öenter¤~»Ýncheck biff */
+ static int old_biff;
+ int biff;
+ char *msg = "¡» ¾´! ¶l®t¨Ó«ö¹a¤F!";
+
+ biff = cutmp->status & STATUS_BIFF;
+ if (biff && !old_biff)
+ (Choose < 0) ? bw_printmsg(msg) : ch_printmsg(1, msg);
+ old_biff = biff;
+}
+#endif
+
+
+static int
+fTAB()
+{
+ mapTalk = mapTalk ? NULL : Talk;
+ return NOTHING;
+}
+
+
+static int
+fNoOp()
+{
+ return NOTHING;
+}
+
+
+static int
+fCtrlD()
+{
+ /* send Q.....\0 cmd */
+ if (!do_send("Q"))
+ return DISCONNECT;
+ return LEAVE;
+}
+
+
+static int
+ftkCtrlC()
+{
+ *cmdBuf = '\0';
+ cmdCol = 0;
+ move(b_lines - 2, 35);
+ clrtoeol();
+ return NOTHING;
+}
+
+
+static int
+ftkCtrlH()
+{
+ if (cmdCol)
+ {
+ int ch = cmdCol--;
+ memcpy(&cmdBuf[cmdCol], &cmdBuf[ch], sizeof(talkBuf) - ch - 1);
+ move(b_lines - 2, cmdCol + 35);
+ outs(&cmdBuf[cmdCol]);
+ clrtoeol();
+ }
+ return NOTHING;
+}
+
+
+static int
+ftkEnter()
+{
+ char msg[80];
+
+#ifdef EVERY_BIFF
+ check_biff();
+#endif
+
+ if (*cmdBuf)
+ {
+ for (cmdPos = MAXLASTCMD - 1; cmdPos; cmdPos--)
+ strcpy(lastcmd[cmdPos], lastcmd[cmdPos - 1]);
+ strcpy(lastcmd[0], cmdBuf);
+
+ if (!do_send(talkBuf))
+ return DISCONNECT;
+
+ sprintf(msg, "\033[1;36m¡¸%s\033[m", cmdBuf);
+ (Choose < 0) ? bw_printmsg(msg) : ch_printmsg(1, msg);
+
+ *cmdBuf = '\0';
+ cmdCol = 0;
+ cmdPos = -1;
+ move(b_lines - 2, 35);
+ clrtoeol();
+ }
+ return NOTHING;
+}
+
+
+static int
+ftkLEFT()
+{
+ if (cmdCol)
+ --cmdCol;
+ return NOTHING;
+}
+
+
+static int
+ftkRIGHT()
+{
+ if (cmdBuf[cmdCol])
+ ++cmdCol;
+ return NOTHING;
+}
+
+
+static int
+ftkUP()
+{
+ cmdPos++;
+ cmdPos %= MAXLASTCMD;
+ str_ncpy(cmdBuf, lastcmd[cmdPos], 41);
+ move(b_lines - 2, 35);
+ outs(cmdBuf);
+ clrtoeol();
+ cmdCol = strlen(cmdBuf);
+ return NOTHING;
+}
+
+
+static int
+ftkDOWN()
+{
+ cmdPos += MAXLASTCMD - 2;
+ return ftkUP();
+}
+
+
+static int
+ftkDefault(ch)
+ int ch;
+{
+ if (isprint2(ch))
+ {
+ if (cmdCol < 40)
+ {
+ if (cmdBuf[cmdCol])
+ { /* insert */
+ int i;
+ for (i = cmdCol; cmdBuf[i] && i < 39; i++);
+ cmdBuf[i + 1] = '\0';
+ for (; i > cmdCol; i--)
+ cmdBuf[i] = cmdBuf[i - 1];
+ }
+ else
+ { /* append */
+ cmdBuf[cmdCol + 1] = '\0';
+ }
+ cmdBuf[cmdCol] = ch;
+ move(b_lines - 2, cmdCol + 35);
+ outs(&cmdBuf[cmdCol++]);
+ }
+ return NOTHING;
+ }
+}
+
+
+static KeyFunc Talk[] =
+{
+ Ctrl('C'), ftkCtrlC,
+ Ctrl('D'), fCtrlD,
+ Ctrl('H'), ftkCtrlH,
+ '\n', ftkEnter,
+ KEY_LEFT, ftkLEFT,
+ KEY_RIGHT, ftkRIGHT,
+ KEY_UP, ftkUP,
+ KEY_DOWN, ftkDOWN,
+ KEY_TAB, fTAB,
+ 0, ftkDefault
+};
+
+
+/*-------------------------------------------------------*/
+/* target : ¾ÔÁZ°O¿ýµ{¦¡ */
+/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */
+/*-------------------------------------------------------*/
+
+
+static void
+play_count(userid, total, win) /* ¦^¶Ç userid ªºÁ`³õ¼Æ¡B³Ó³õ¼Æ */
+ char *userid;
+ int *total, *win;
+{
+ char fpath[64];
+ int fd;
+ int grade[32]; /* «O¯d 32 Ó int */
+
+ *total = 0;
+ *win = 0;
+
+ usr_fpath(fpath, userid, "bwboard");
+ if ((fd = open(fpath, O_RDONLY)) >= 0)
+ {
+ read(fd, grade, sizeof(grade));
+ close(fd);
+
+ /* ¨Ì§ÇÀx¦s ¶Â¥ÕÁ`,¶Â¥Õ³Ó; ¤¤lÁ`,¤¤l³Ó; ³òÁ`,³ò³Ó; xÁ`,x³Ó; ·tÁ`,·t³Ó */
+ fd = (Choose + 3) << 1;
+ *total = grade[fd];
+ *win = grade[fd + 1];
+ }
+}
+
+
+static void
+play_add(win) /* §ÚªºÁ`/³Ó³õ¼Æ +1 */
+ int win;
+{
+ char fpath[64];
+ int fd, kind;
+ int grade[32]; /* «O¯d 32 Ó int */
+
+ usr_fpath(fpath, cuser.userid, "bwboard");
+ if ((fd = open(fpath, O_RDWR | O_CREAT, 0600)) >= 0)
+ {
+ if (read(fd, grade, sizeof(grade)) != sizeof(grade))
+ memset(grade, 0, sizeof(grade));
+
+ /* ¨Ì§ÇÀx¦s ¶Â¥ÕÁ`,¶Â¥Õ³Ó; ¤¤lÁ`,¤¤l³Ó; ³òÁ`,³ò³Ó; xÁ`,x³Ó; ·tÁ`,·t³Ó */
+ kind = (Choose + 3) << 1;
+ grade[kind]++;
+ if (win)
+ grade[kind + 1]++;
+
+ lseek(fd, (off_t) 0, SEEK_SET);
+ write(fd, grade, sizeof(grade));
+ close(fd);
+ }
+}
+
+
+/*-------------------------------------------------------*/
+/* target : Black & White Chess Board ¶Â¥Õ´Ñ/¤¤l´Ñ/³ò´Ñ */
+/* create : 99/02/20 */
+/* update : 02/08/05 */
+/* author : thor.bbs@bbs.cs.nthu.edu.tw */
+/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */
+/*-------------------------------------------------------*/
+
+
+enum
+{
+ Deny = 3
+};
+
+
+static KeyFunc myRound[], yourRound[];
+
+static char *bw_icon[] = {"¢q", "¡´", "¡³", " "}; /* Empty, Black, White, Deny */
+
+
+/* 19 * 19, standard chess board */
+static char Allow[19][19];
+static int numWhite, numBlack;
+static int rulerRow, rulerCol;
+
+static int yourPass, myPass;
+static int yourStep, myStep;
+
+static int GameOver; /* end game */
+
+
+#if 0
+
+ % rules util include
+ 0. Board initialize
+ (happen before start, and clear board action)
+ 1. Board update by "color" down a "chess pos"(without update screen)
+ (screen by a main redraw routine, after call this)
+ return value, represent win side to end(for both turn)
+ (happen when state change)
+ 2. Board allow step checking by "color"(for my turn)
+ return value, represent
+
+ % possible step
+ (happen when state change)
+ if Game is over, won''t allow any step
+
+#endif
+
+
+/* numWhite, numBlack maintained by rule, 0&1 */
+/* Board[19][19] Allow[19][19] maintained by rule */
+
+
+static inline void
+countBWnum()
+{
+ int i, j;
+
+ numWhite = numBlack = 0;
+ for (i = 0; i < 19; i++)
+ {
+ for (j = 0; j < 19; j++)
+ {
+ if (Board[i][j] == White)
+ numWhite++;
+ else if (Board[i][j] == Black)
+ numBlack++;
+ }
+ }
+}
+
+
+ /*-----------------------------------------------------*/
+ /* ¶Â¥Õ´Ñ 8 x 8 */
+ /*-----------------------------------------------------*/
+
+static int
+othInit()
+{
+ int i, j;
+ for (i = 0; i < 19; i++)
+ for (j = 0; j < 19; j++)
+ Board[i][j] = i < 8 && j < 8 ? Empty : Deny;
+ Board[3][3] = Board[4][4] = Black;
+ Board[3][4] = Board[4][3] = White;
+ numWhite = numBlack = 2;
+ rulerRow = rulerCol = 8;
+
+ return 0;
+}
+
+
+static inline int
+othEatable(Color, row, col, rowstep, colstep)
+ int Color, row, col, rowstep, colstep;
+{
+ int eat = 0;
+ do
+ {
+ row += rowstep;
+ col += colstep;
+ /* check range */
+ if (row < 0 || row >= 8 || col < 0 || col >= 8)
+ return 0;
+ if (Board[row][col] == Color)
+ return eat;
+ eat = 1;
+ } while (Board[row][col] == Deny - Color);
+ return 0;
+}
+
+
+static int othAllow();
+
+
+static int
+othUpdate(Color, row, col)
+ int Color, row, col;
+{
+ int i, j, p, q;
+ int winside = Empty;
+
+ Board[row][col] = Color;
+ for (i = -1; i <= 1; i++)
+ {
+ for (j = -1; j <= 1; j++)
+ {
+ if (i != 0 || j != 0)
+ {
+ if (othEatable(Color, row, col, i, j))
+ {
+ p = row + i;
+ q = col + j;
+ for (;;)
+ {
+ if (Board[p][q] == Color)
+ break;
+ Board[p][q] = Color;
+ p += i;
+ q += j;
+ }
+ }
+ }
+ }
+ }
+
+ /* count numWhite & numBlack */
+ countBWnum();
+
+ /* Thor.990329.µù¸Ñ: ¤Uº¡®É */
+ {
+ int my = myColor; /* Thor.990331: ¼È¦smyColor */
+ int allowBlack, allowWhite;
+ myColor = Black;
+ allowBlack = othAllow();
+ myColor = White;
+ allowWhite = othAllow();
+ myColor = my;
+ if (allowBlack == 0 && allowWhite == 0)
+ {
+ if (numWhite > numBlack)
+ winside = White;
+ else if (numWhite < numBlack)
+ winside = Black;
+ else
+ winside = Deny;
+ }
+ }
+
+ return winside;
+}
+
+
+static void
+do_othAllow(i, j, num)
+ int i, j;
+ int *num;
+{
+ int p, q;
+
+ Allow[i][j] = 0;
+ if (Board[i][j] == Empty)
+ {
+ for (p = -1; p <= 1; p++)
+ {
+ for (q = -1; q <= 1; q++)
+ {
+ if (p != 0 || q != 0)
+ {
+ if (othEatable(myColor, i, j, p, q))
+ {
+ Allow[i][j] = 1;
+ (*num)++;
+ return;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+static int
+othAllow()
+{
+ int i, j, num;
+
+ num = 0;
+ for (i = 0; i < 8; i++)
+ {
+ for (j = 0; j < 8; j++)
+ {
+ do_othAllow(i, j, &num);
+ }
+ }
+
+ return num;
+}
+
+
+static int (*othRule[]) () =
+{
+ othInit, othUpdate, othAllow
+};
+
+
+ /*-----------------------------------------------------*/
+ /* ¤¤l´Ñ 15 x 15 */
+ /*-----------------------------------------------------*/
+
+static int
+fivInit()
+{
+ int i, j;
+ for (i = 0; i < 19; i++)
+ {
+ for (j = 0; j < 19; j++)
+ Board[i][j] = i < 15 && j < 15 ? Empty : Deny;
+ }
+ numWhite = numBlack = 0;
+ rulerRow = rulerCol = 15;
+ return 0;
+}
+
+
+static int
+fivCount(Color, row, col, rowstep, colstep)
+ int Color, row, col, rowstep, colstep;
+{
+ int count = 0;
+ for (;;)
+ {
+ row += rowstep;
+ col += colstep;
+ /* check range */
+ if (row < 0 || row >= 15 || col < 0 || col >= 15)
+ return count;
+
+ if (Board[row][col] != Color)
+ return count;
+ count++;
+ }
+}
+
+
+static int
+fivUpdate(Color, row, col)
+ int Color, row, col;
+{
+#if 0
+ int cnt[4], n3, n4, n5, nL, i;
+#endif
+
+ int winside = Empty;
+ Board[row][col] = Color;
+ if (Color == Black)
+ numBlack++;
+ else if (Color == White)
+ numWhite++;
+
+
+ /* ¶Â´Ñ¡]¥ýµÛªÌ¡^¦³¤U¦C¤TµÛ¸TµÛ(¤SºÙ¸T¤â)ÂI¡G¤T¤T(Âù¬¡¤T)¡B¥|¥|¡Bªø³s¡C */
+ /* ¦b³s¤¤§«e§Î¦¨¸TµÛªÌ¡Aµô©w¬°¸TµÛt¡C */
+ /* ¥Õ´Ñ¨S¦³¸TµÛÂI¡Aªø³s©ÎªÌ¤T¤T¤]³£¥i¥H³Ó¡C */
+
+#if 0
+ cnt[0] = fivCount(Color, row, col, -1, -1) + fivCount(Color, row, col, +1, +1) + 1;
+ cnt[1] = fivCount(Color, row, col, -1, 0) + fivCount(Color, row, col, +1, 0) + 1;
+ cnt[2] = fivCount(Color, row, col, 0, -1) + fivCount(Color, row, col, 0, +1) + 1;
+ cnt[3] = fivCount(Color, row, col, -1, +1) + fivCount(Color, row, col, +1, -1) + 1;
+
+ n3 = 0; /* Âù¬¡¤T */
+ n4 = 0; /* Âù¥| */
+ n5 = 0; /* ¤ */
+ nL = 0; /* ªø³s */
+
+ for (i = 0; i < 4; i++)
+ {
+ if (cnt[i] == (3 | (LIVE_SIDE + LIVE_SIDE)))
+ n3++;
+ if ((cnt[i] % LIVE_SIDE) == 4)
+ n4++;
+ if ((cnt[i] % LIVE_SIDE) == 5)
+ n5++;
+ if ((cnt[i] % LIVE_SIDE) > 5)
+ nL++;
+ }
+
+ if (n5 > 0)
+ winside = Color;
+ else
+ {
+ if (Color == Black)
+ {
+ if (n3 >= 2)
+ {
+ bw_printmsg("¡» ¶Â¤èÂù¤T¸TµÛ");
+ winside = White;
+ }
+ if (n4 >= 2)
+ {
+ bw_printmsg("¡» ¶Â¤èÂù¥|¸TµÛ");
+ winside = White;
+ }
+ if (nL > 0)
+ {
+ bw_printmsg("¡» ¶Â¤èªø³s¸TµÛ");
+ winside = White;
+ }
+ }
+ else
+ {
+ if (nL > 0)
+ winside = Color;
+ }
+ }
+#endif
+
+#if 0 /* Thor.990415: ¤W±¨º¬q¤S¼g¿ù¤F, ¯d«Ý¦³¤ß¤H¤h¦AºCºC¼g§a :p */
+
+ (¤@)¡´ ¡´ ¡´ ¡´
+ ¡ô
+ ¦A©ñ¶i¥h´Nºâ¥|¥|
+ ¡õ
+ (¤G)¡´¡´¡´ ¡´¡´¡´(¤¤¶¡ªÅ¤T®æ)
+
+ (¤T)¡´ ¡´¡´¡³
+ ¡ô©ñ³o¸Ì¤]ºâ
+ ¡´
+ ¡´
+ ¡´
+
+ (¥|)¡´¡´ ¡´ ¡´¡´
+ ¡ô¦A©ñ´N¬O¥|¥|
+
+
+ ªø³sªº¸Ü,¥un¤¤l¥H¤W´Nºâ,¤£ºÞ¦º¬¡
+
+#endif
+
+#if 1
+ if (fivCount(Color, row, col, -1, -1) + fivCount(Color, row, col, +1, +1) >= 4 ||
+ fivCount(Color, row, col, -1, 0) + fivCount(Color, row, col, +1, 0) >= 4 ||
+ fivCount(Color, row, col, 0, -1) + fivCount(Color, row, col, 0, +1) >= 4 ||
+ fivCount(Color, row, col, -1, +1) + fivCount(Color, row, col, +1, -1) >= 4)
+ winside = Color;
+#endif
+
+ return winside;
+}
+
+
+static int
+fivAllow()
+{
+ int i, j, num = 0;
+ for (i = 0; i < 19; i++)
+ {
+ for (j = 0; j < 19; j++)
+ num += Allow[i][j] = (Board[i][j] == Empty);
+ }
+ return num;
+}
+
+
+static int (*fivRule[]) () =
+{
+ fivInit, fivUpdate, fivAllow
+};
+
+
+ /*-----------------------------------------------------*/
+ /* ³ò´Ñ 19 x 19 */
+ /*-----------------------------------------------------*/
+
+static int
+blkInit()
+{
+ memset(Board, 0, sizeof(Board));
+ numWhite = numBlack = 0;
+ rulerRow = rulerCol = 18;
+ return 0;
+}
+
+
+/* borrow Allow for traversal, and return region */
+/* a recursive procedure, clear Allow before call it */
+/* with row,col range check, return false if out */
+static int
+blkLive(Color, row, col)
+ int Color, row, col;
+{
+ if (row < 0 || row >= 19 || col < 0 || col >= 19)
+ return 0;
+ if (Board[row][col] == Empty)
+ return 1;
+ if (Board[row][col] != Color)
+ return 0;
+ if (Allow[row][col])
+ return 0;
+ Allow[row][col] = 1;
+ return blkLive(Color, row - 1, col) |
+ blkLive(Color, row + 1, col) |
+ blkLive(Color, row, col - 1) |
+ blkLive(Color, row, col + 1);
+}
+
+
+static inline void
+blkClear()
+{
+ int i, j;
+
+ for (i = 0; i < 19; i++)
+ {
+ for (j = 0; j < 19; j++)
+ {
+ if (Allow[i][j])
+ Board[i][j] = Empty;
+ }
+ }
+}
+
+
+static int
+blkUpdate(Color, row, col)
+ int Color, row, col;
+{
+ Board[row][col] = Color;
+
+ memset(Allow, 0, sizeof(Allow));
+ if (!blkLive(Deny - Color, row - 1, col))
+ blkClear();
+
+ memset(Allow, 0, sizeof(Allow));
+ if (!blkLive(Deny - Color, row + 1, col))
+ blkClear();
+
+ memset(Allow, 0, sizeof(Allow));
+ if (!blkLive(Deny - Color, row, col - 1))
+ blkClear();
+
+ memset(Allow, 0, sizeof(Allow));
+ if (!blkLive(Deny - Color, row, col + 1))
+ blkClear();
+
+ /* check for suiside */
+ memset(Allow, 0, sizeof(Allow));
+ if (!blkLive(Color, row, col))
+ blkClear();
+
+ /* count numWhite & numBlack */
+ countBWnum();
+
+ return Empty; /* Please check win side by your own */
+}
+
+
+static int (*blkRule[]) () =
+{
+ blkInit, blkUpdate, fivAllow /* borrow fivAllow as blkAllow */
+};
+
+
+ /*-----------------------------------------------------*/
+ /* board util */
+ /*-----------------------------------------------------*/
+
+#if 0 /* screen */
+
+ [maple BWboard]
+ xxxx vs yyyy
+ ++++++++ talkline(you color, yellow) (40 chars)
+ ++++++++ talkline(my color, cryn)
+ ++++++++
+ ++++++++
+ ++++++++
+
+ one line for simple help, press key to......
+ one line for nth turn, myColor, num, pass < -youcolor, num, pass(35), input talk
+ two line for write msg
+
+#endif
+
+
+static char *
+bw_brdline(row)
+ int row;
+{
+ static char buf[80] = "\033[30;43m";
+ static char rTxtY[] = " A B C D E F G H I J K L M N O P Q R S";
+ static char rTxtX[] = " 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9";
+ char txt[3];
+ char *ptr = buf + 8, *t;
+ int i;
+
+ for (i = 0; i < 19; i++)
+ {
+ t = bw_icon[Board[row][i]];
+ if (t == bw_icon[Empty])
+ {
+ if (row == 0)
+ {
+ if (i == 0)
+ t = "ùÝ";
+ else if (i >= 18 || Board[row][i + 1] == Deny)
+ t = "ùß";
+ else
+ t = "ùç";
+ }
+ else if (row >= 18 || Board[row + 1][i] == Deny)
+ {
+ if (i == 0)
+ t = "ùã";
+ else if (i >= 18 || Board[row][i + 1] == Deny)
+ t = "ùå";
+ else
+ t = "ùí";
+ }
+ else
+ {
+ if (i == 0)
+ t = "ùò";
+ else if (i >= 18 || Board[row][i + 1] == Deny)
+ t = "ùô";
+ }
+ }
+ if (t != bw_icon[Black] && t != bw_icon[White])
+ {
+ if (row == rulerRow && i < rulerCol)
+ {
+ str_ncpy(txt, rTxtX + 2 * i, 3);
+ t = txt;
+ }
+ else if (i == rulerCol && row < rulerRow)
+ {
+ str_ncpy(txt, rTxtY + 2 * row, 3);
+ t = txt;
+ }
+ }
+ strcpy(ptr, t);
+ ptr += 2;
+ }
+ strcpy(ptr, "\033[m");
+ return buf;
+}
+
+
+static char *
+bw_coorstr(row, col)
+ int row;
+ int col;
+{
+ static char coor[10];
+ sprintf(coor, "(%c,%d)", row + 'A', col + 1);
+ return coor;
+}
+
+
+static void
+bw_printmsg(msg)
+ char *msg;
+{
+ int line;
+
+ line = msgline;
+ move(line, 0);
+ outs(bw_brdline(line - 1));
+ outs(msg);
+ clrtoeol();
+ if (++line == b_lines - 3) /* stop line */
+ line = 1;
+ move(line, 0);
+ outs(bw_brdline(line - 1));
+ outs("¡÷");
+ clrtoeol();
+ msgline = line;
+}
+
+
+static void
+bw_draw()
+{
+ int i, myNum, yourNum;
+ for (i = 0; i < 19; i++)
+ {
+ move(1 + i, 0);
+ outs(bw_brdline(i));
+ }
+ myNum = (myColor == Black) ? numBlack : numWhite;
+ yourNum = (myColor == Black) ? numWhite : numBlack;
+
+ move(b_lines - 2, 0);
+ prints("²Ä%d¦^ %s%d¤l%dÅý (%s) %s%d¤l%dÅý",
+ BMIN(myStep, yourStep) + 1, bw_icon[Deny - myColor], myNum, myPass,
+ (mapTurn == myRound ? "¡ö" : "¡÷"), bw_icon[myColor], yourNum, yourPass);
+ /* Thor.990219: ¯S§Oª`·N, ¦b¦¹¦]ÃC¦âÃö«Y, ¬G¥Î¤lªºicon, è¦n»P쥻¬Û¤Ï */
+ /* nth turn,myColor,num,pass <- youcolor, num,pass */
+}
+
+
+static void
+bw_init()
+{
+ yourPass = myPass = yourStep = myStep = 0;
+
+ /* ¶Â¥Õ´Ñ/¤¤l´Ñ/³ò´Ñ¬°¶Â¤l¥ý¦æ */
+ if (myColor == Black)
+ {
+ (*rule[Ballow]) ();
+ mapTurn = myRound;
+ }
+ else
+ {
+ mapTurn = yourRound;
+ }
+
+ move(b_lines - 1, 0);
+ outs(COLOR1 " ¹ï«³¼Ò¦¡ " COLOR2 " (Enter)¸¨¤l (TAB)¤Á´«´Ñ½L/¥æ½Í (^P)Åý¤â (^C)«ª± (^D)Â÷¶} \033[m");
+
+ bw_draw();
+}
+
+
+static inline void
+bw_overgame()
+{
+ if (GameOver == Black)
+ bw_printmsg("\033[1;32m¡» ¶Â¤èÀò³Ó\033[m");
+ else if (GameOver == White)
+ bw_printmsg("\033[1;32m¡» ¥Õ¤èÀò³Ó\033[m");
+ else if (GameOver == Deny)
+ bw_printmsg("\033[1;32m¡» Âù¤è¥¤â\033[m");
+
+ play_add(myColor == GameOver);
+}
+
+
+#if 0 /* communication protocol */
+
+ Ctrl('O'):
+
+ enter BWboard mode, (pass to another)
+ first hand specify rule set(pass Rule later)
+ then start
+
+ clear chess board, C.....\ 0
+ talk line by line, T.....\ 0
+ specify down pos, Dxxx \ 0, y = xxx / 19, x = xxx % 19
+ pass one turn, P.....\ 0
+ leave BWboard mode, Q.....\ 0
+
+#endif
+
+
+static inline int
+bw_recv()
+{
+ static char buf[512];
+ static int bufstart = 0;
+ int cc, len;
+ char *bptr, *str;
+ char msg[80];
+ int i;
+
+ bptr = buf;
+ cc = bufstart;
+ len = sizeof(buf) - cc - 1;
+
+ if ((len = recv(cfd, bptr + cc, len, 0)) <= 0)
+ return DISCONNECT;
+
+ cc += len;
+
+ for (;;)
+ {
+ len = strlen(bptr);
+
+ if (len >= cc)
+ { /* wait for trailing data */
+ memcpy(buf, bptr, len);
+ bufstart = len;
+ break;
+ }
+ str = bptr + 1;
+ switch (*bptr)
+ {
+ /* clear chess board, C.....\0 */
+ case 'C':
+ do_init();
+ break;
+
+ /* talk line by line, T.....\0 */
+ case 'T':
+ sprintf(msg, "\033[1;33m¡¹%s\033[m", str);
+ bw_printmsg(msg);
+ break;
+
+ /* specify down pos, Dxxx\0 , y = xxx / 19, x = xxx % 19 */
+ case 'D':
+ yourStep++;
+ /* get pos */
+ i = atoi(str);
+ sprintf(msg, "¡» ¹ï¤è¸¨¤l %s", bw_coorstr(i / 19, i % 19));
+ /* update board */
+ GameOver = (*rule[Bupdate]) (Deny - myColor, i / 19, i % 19);
+
+ mapTurn = myRound;
+
+ bw_draw();
+
+ bw_printmsg(msg);
+
+ if (GameOver)
+ {
+ bw_overgame();
+ memset(Allow, 0, sizeof(Allow));
+ }
+ else
+ {
+ if ((*rule[Ballow]) () <= 0)
+ bw_printmsg("¡» ±z¨«§ëµL¸ô¤F");
+ }
+ break;
+
+ /* pass one turn, P.....\0 */
+ case 'P':
+ yourPass++;
+ yourStep++;
+
+ mapTurn = myRound;
+ bw_draw();
+ bw_printmsg("¡» ¹ï¤èÅý¤â");
+ if (GameOver)
+ {
+ memset(Allow, 0, sizeof(Allow));
+ }
+ else
+ {
+ if ((*rule[Ballow]) () <= 0)
+ bw_printmsg("¡» ±z¨«§ëµL¸ô¤F"); /* Thor.990329: ending game? */
+ }
+ break;
+
+ /* leave BWboard mode, Q.....\0 */
+ case 'Q':
+ return LEAVE;
+ }
+
+ cc -= ++len;
+ if (cc <= 0)
+ {
+ bufstart = 0;
+ break;
+ }
+ bptr += len;
+ }
+
+ return NOTHING;
+}
+
+
+static int
+ftnCtrlC()
+{
+ if (!do_send("C"))
+ return DISCONNECT;
+ do_init();
+ return NOTHING;
+}
+
+
+static int
+ftnUP()
+{
+ if (bwRow)
+ bwRow--;
+ return NOTHING;
+}
+
+
+static int
+ftnDOWN()
+{
+ if (bwRow < 18)
+ if (Board[bwRow + 1][bwCol] != Deny)
+ bwRow++;
+ return NOTHING;
+}
+
+
+static int
+ftnLEFT()
+{
+ if (bwCol)
+ bwCol--;
+ return NOTHING;
+}
+
+
+static int
+ftnRIGHT()
+{
+ if (bwCol < 18)
+ if (Board[bwRow][bwCol + 1] != Deny)
+ bwCol++;
+ return NOTHING;
+}
+
+
+static int
+ftnPass()
+{
+ /* Thor.990220: for chat mode to enter ^P pass */
+ if (mapTurn == myRound && !GameOver)
+ {
+ myPass++;
+ myStep++;
+ if (!do_send("P"))
+ return DISCONNECT;
+ mapTurn = yourRound;
+ bw_draw();
+ bw_printmsg("¡» §Ú¤èÅý¤â");
+ }
+ return NOTHING;
+}
+
+
+static int
+ftnEnter()
+{
+ char msg[80];
+ char buf[20];
+
+ if (!Allow[bwRow][bwCol])
+ return NOTHING;
+
+ sprintf(msg, "¡» §Ú¤è¸¨¤l %s", bw_coorstr(bwRow, bwCol));
+
+ myStep++;
+ sprintf(buf, "D%d", bwRow * 19 + bwCol);
+
+ if (!do_send(buf))
+ return DISCONNECT;
+
+ /* update board */
+ GameOver = (*rule[Bupdate]) (myColor, bwRow, bwCol);
+
+ mapTurn = yourRound;
+
+ bw_draw();
+
+ bw_printmsg(msg);
+
+ if (GameOver)
+ bw_overgame();
+
+ return NOTHING;
+}
+
+
+static KeyFunc yourRound[] =
+{
+ Ctrl('C'), ftnCtrlC,
+ Ctrl('D'), fCtrlD,
+ KEY_LEFT, ftnLEFT,
+ KEY_RIGHT, ftnRIGHT,
+ KEY_UP, ftnUP,
+ KEY_DOWN, ftnDOWN,
+ KEY_TAB, fTAB,
+ 0, fNoOp
+};
+
+
+static KeyFunc myRound[] =
+{
+ Ctrl('C'), ftnCtrlC,
+ ' ', ftnEnter,
+ '\n', ftnEnter,
+ Ctrl('P'), ftnPass,
+ Ctrl('D'), fCtrlD,
+ KEY_LEFT, ftnLEFT,
+ KEY_RIGHT, ftnRIGHT,
+ KEY_UP, ftnUP,
+ KEY_DOWN, ftnDOWN,
+ KEY_TAB, fTAB,
+ 0, fNoOp
+};
+
+
+/*-------------------------------------------------------*/
+/* target : Chinese Chess Board x´Ñ/·t´Ñ */
+/* create : 99/12/14 */
+/* update : 02/08/05 */
+/* author : weichung.bbs@bbs.ntit.edu.tw */
+/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */
+/*-------------------------------------------------------*/
+
+
+enum
+{
+ Cover = 1
+};
+
+
+static KeyFunc myTurn[], yourTurn[];
+
+static int sideline;
+static int Totalch; /* ¥[³t¥Î :p */
+static int Focus;
+static int youreat_index;
+static int myeat_index;
+
+static char MyEat[16], YourEat[16];
+static char Appear[14];
+static char dstr[19][200];
+
+static char *ch_icon[] =
+{
+ " ", "¡´", /* Empty, Cover */
+ "\033[1;31m«Ó\033[m", "\033[1;31m¥K\033[m", "\033[1;31m¬Û\033[m",
+ "\033[1;31mÚÏ\033[m", "\033[1;31mØX\033[m", "\033[1;31m¬¶\033[m", "\033[1;31m§L\033[m",
+ "\033[1;32m±N\033[m", "\033[1;32m¤h\033[m", "\033[1;32m¶H\033[m",
+ "\033[1;32m¨®\033[m", "\033[1;32m°¨\033[m", "\033[1;32m¥]\033[m", "\033[1;32m¨ò\033[m"
+};
+
+
+ /*-----------------------------------------------------*/
+ /* x´Ñ 10 x 9 */
+ /*-----------------------------------------------------*/
+
+static int
+armyInit()
+{
+ int i, j;
+
+ for (i = 0; i < 10; i++)
+ {
+ for (j = 0; j < 9; j++)
+ Board[i][j] = Empty;
+ }
+
+ Board[0][4] = 2; /* «Ó */
+ Board[0][3] = Board[0][5] = 3; /* ¥K */
+ Board[0][2] = Board[0][6] = 4; /* ¬Û */
+ Board[0][1] = Board[0][7] = 6; /* ØX */
+ Board[0][0] = Board[0][8] = 5; /* ÚÏ */
+ Board[2][1] = Board[2][7] = 7; /* ¦ */
+ Board[3][0] = Board[3][2] = Board[3][4] = Board[3][6] = Board[3][8] = 8; /* §L */
+
+ Board[9][4] = 9; /* ±N */
+ Board[9][3] = Board[9][5] = 10; /* ¤h */
+ Board[9][2] = Board[9][6] = 11; /* ¶H */
+ Board[9][1] = Board[9][7] = 13; /* °¨ */
+ Board[9][0] = Board[9][8] = 12; /* ¨® */
+ Board[7][1] = Board[7][7] = 14; /* ¥] */
+ Board[6][0] = Board[6][2] = Board[6][4] = Board[6][6] = Board[6][8] = 15; /* ¨ò */
+
+ memset(MyEat, Empty, sizeof(MyEat));
+ memset(YourEat, Empty, sizeof(YourEat));
+
+ sideline = 19;
+ return 0;
+}
+
+
+static int (*armyRule[]) () =
+{
+ armyInit
+};
+
+
+ /*-----------------------------------------------------*/
+ /* ·t´Ñ 4 x 8 */
+ /*-----------------------------------------------------*/
+
+static int
+darkInit()
+{
+ int i, j;
+
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 8; j++)
+ Board[i][j] = Cover;
+
+ memset(Appear, Empty, sizeof(Appear));
+ memset(MyEat, Empty, sizeof(MyEat));
+ memset(YourEat, Empty, sizeof(YourEat));
+
+ sideline = 9;
+ return 0;
+}
+
+
+static int (*darkRule[]) () =
+{
+ darkInit
+};
+
+
+ /*-----------------------------------------------------*/
+ /* board util */
+ /*-----------------------------------------------------*/
+
+
+static void
+ch_printmsg(type, msg)
+ int type;
+ char *msg;
+{
+/* char *ch_brdline();
+ *
+ * lantw44: ³oÓ¥ýµù¸Ñ±¼¡A§ï«Å§i¦bÀÉ®×¶}ÀY
+ * ¦]¬°³o·|³y¦¨ gcc 4 ½sĶ¥¢±Ñ
+ */
+ char buf[100];
+ int tmp;
+
+ switch (type)
+ {
+ case 1: /* for move uncover eat */
+ /*move(msgline + 9, 37);
+ outs(msg);*/
+ tmp=msgline + 8;
+ strcpy(dstr[tmp], msg);
+ outs(ch_brdline(tmp));
+ clrtoeol();
+ if (++msgline >= 11)
+ msgline = 1;
+ /*move(msgline + 9, 37);
+ outs("¡÷");*/
+ tmp=msgline + 8;
+ strcpy(dstr[tmp], "¡÷");
+ outs(ch_brdline(tmp));
+ clrtoeol();
+ break;
+
+ case 2: /* for select */
+ sprintf(buf, "\033[1;33m¡»±z¿ï¨ú¤F %s\033[1;33m(%d, %c)\033[m",
+ ch_icon[Focus / 256], bwCol, bwRow + 'A');
+ /*move(1, 37);
+ outs(buf);*/
+ strcpy(dstr[0], buf);
+ outs(ch_brdline(0));
+ clrtoeol();
+ break;
+
+ case 3: /* for disable select */
+ /*move(1, 37);*/
+ strcpy(dstr[0], "");
+ outs(ch_brdline(0));
+ clrtoeol();
+ break;
+ }
+}
+
+
+static void
+ch_printeat()
+{
+ int i;
+ char buf[200];
+ buf[0]=0;
+ /* my:4, your:7 */
+
+ if (myeat_index)
+ {
+ /* sprintf(buf, "%d ", myeat_index); */
+ for (i = 0; i < myeat_index; i++)
+ {
+ /*move(4, 37 + i * 2);
+ outs(ch_icon[MyEat[i]]);*/
+ strcat(buf,ch_icon[MyEat[i]]);
+ }
+ strcpy(dstr[3], buf);
+ outs(ch_brdline(3));
+ }
+
+ buf[0]=0;
+
+ if (youreat_index)
+ {
+ for (i = 0; i < youreat_index; i++)
+ {
+ /*move(7, 37 + i * 2);
+ outs(ch_icon[YourEat[i]]);*/
+ strcat(buf,ch_icon[YourEat[i]]);
+ }
+ strcpy(dstr[6], buf);
+ outs(ch_brdline(6));
+ }
+}
+
+
+static void
+ch_overgame(win)
+ int win;
+{
+ char buf[80];
+
+ GameOver = 1;
+ sprintf(buf, "%s¤èÀò³Ó¡I½Ð«ö Ctrl-C «ª±", win == myColor ? "§Ú" : "¹ï");
+ ch_printmsg(1, buf);
+
+ play_add(win == myColor);
+}
+
+
+static char *
+ch_brdline(row)
+ int row;
+{
+ char *t, *str, ch;
+ static char buf[350];
+ static char river[] = "¢x·¡ ªe º~ ¬É¢x";
+ static char side[] = " A B C D E F G H I J";
+ int i,col;
+
+ move(row + 1, 0);
+ if (row == 9 && Choose) {
+ strcpy(buf, " ¢Ý ¢° ¢± ¢² ¢³ ¢´ ¢µ ¢¶ ");
+ strcat(buf, dstr[row]);
+ return buf;
+ }
+ else if (row > 8 && Choose) { /* ·t´Ñªº row ³Ì¦h¨ì 8 */
+ strncpy(buf, forspace, 37);
+ buf[37] = 0;
+ strcat(buf, dstr[row]);
+ return buf;
+ }
+
+ if (row == 9) { /* x´Ñªº row 9 ¬O ·¡ªeº~¬É */
+ strcpy(buf, river);
+ strcat(buf, " ");
+ strcat(buf, dstr[9]);
+ return buf;
+ }
+
+ str = buf;
+
+ /* µe®æ¤l¤Î®æ¤l¤Wªº´Ñ¤l */
+
+ for (i = 0; i < 17; i++)
+ {
+ col = 2;
+ if (!Choose && (row % 2 || i % 2))
+ ch = Empty;
+ else
+ ch = Board[row / 2][i / 2];
+
+ if (Choose || (ch == Empty))
+ {
+ if (row == 0) /* ¢z¢w¢s¢w¢{ */
+ {
+ if (i == 0)
+ t = "¢z";
+ else if (i == 16)
+ t = "¢{";
+ else if (i % 2)
+ t = "¢w";
+ else
+ t = "¢s";
+ }
+ else if (row == 18 || (row == 8 && Choose)) /* ¢|¢w¢r¢w¢} */
+ {
+ if (i == 0)
+ t = "¢|";
+ else if (i == 16)
+ t = "¢}";
+ else if (i % 2)
+ t = "¢w";
+ else
+ t = "¢r";
+ }
+ else if (row % 2) /* ¢x ¢x ¢x */
+ {
+ if (i % 2) {
+ t = ch_icon[ch];
+ if(ch > 1) col = 12;
+ }
+ else
+ t = "¢x";
+ }
+ else /* ¢u¢w¢q¢w¢t */
+ {
+ if (i == 0)
+ t = "¢u";
+ else if (i == 16)
+ t = "¢t";
+ else if (i % 2)
+ t = "¢w";
+ else
+ t = "¢q";
+ }
+ }
+ else
+ {
+ t = ch_icon[ch];
+ if(ch > 1) col = 12;
+ }
+ strcpy(str, t); /* color */
+ str += col;
+ } /* end for loop */
+
+ if ((Choose && (row % 2 == 1)) || (!Choose && (row % 2 == 0)))
+ {
+ i = row / 2;
+ strncpy(str, side + i * 2, 2);
+ str += 2;
+ *str = 0;
+ }
+ else
+ {
+ strcpy(str, " ");
+ str += 2;
+ *str = 0;
+ }
+ strcpy(str, " ");
+ str++;
+ strcpy(str, dstr[row]);
+ return buf;
+}
+
+
+static void
+ch_draw()
+{
+ int i;
+
+ for (i = 0; i < sideline; i++)
+ {
+ /*move(1 + i, 0);*/
+ outs(ch_brdline(i));
+ }
+ /*move(3, 37);
+ outs("¡¸§Ú¤è©Ò¦Y¤§¤l");
+ move(6, 37);
+ outs("¡¹¹ï¤è©Ò¦Y¤§¤l");
+ move(9, 37);
+ outs("====================================");*/
+
+ move(sideline + 1, 0);
+ if (Choose) {
+ outs(ch_brdline(sideline));
+ }
+ else
+ outs("¢Ý ¢° ¢± ¢² ¢³ ¢´ ¢µ ¢¶ ¢·");
+
+ move(b_lines - 2, 0);
+ prints("§Ú¬O \033[47;%s¤l\033[m [½ü¨ì%s]",
+ dark_choose ? (myColor == Black ? "30m¶Â" : "31m¬õ") : "30m¥Õ",
+ mapTurn == myTurn ? "§Ú¤F" : "¹ï¤è");
+}
+
+
+static void
+ch_init()
+{
+ int i;
+ Totalch = youreat_index = myeat_index = Focus = 0;
+
+ /* ·t´Ñªº«ù¤lÃC¦â¥¼©w */
+ dark_choose = (Choose == 1) ? 0 : 1;
+
+ /* x´Ñ/·t´Ñ¬°¶Â¤l¥ý¦æ (·t´Ñ: ¯u¥¿ªº«ù¤lÃC¦â·|¦b²Ä¤@¦¸Â½¤l®É¨M©w) */
+ mapTurn = (myColor == Black) ? myTurn : yourTurn;
+
+ move(b_lines - 1, 0);
+ outs(COLOR1 " ¹ï«³¼Ò¦¡ " COLOR2 " (Enter)½¤l/²¾°Ê (TAB)¤Á´«´Ñ½L/¥æ½Í (^S)»{¿é (^C)«ª± (^D)Â÷¶} \033[m");
+
+ for(i = 0; i < 19; i++) strcpy(dstr[i], forspace);
+ strcpy(dstr[2],"¡¸§Ú¤è©Ò¦Y¤§¤l");
+ strcpy(dstr[5],"¡¹¹ï¤è©Ò¦Y¤§¤l");
+ strcpy(dstr[8],"====================================");
+
+ ch_draw();
+}
+
+
+static inline int
+ch_recv()
+{
+ static char buf[256];
+ char msg[80];
+ int len, ch, row, col, ch2, row2, col2;
+
+ len = sizeof(buf) + 1;
+ if ((len = recv(cfd, buf, len, 0)) <= 0)
+ return DISCONNECT;
+
+ switch (*buf)
+ {
+ /* clear chess board, C.....\0 */
+ case 'C':
+ do_init();
+ break;
+
+ case 'D':
+ ch = atoi(buf + 1);
+ row = (ch / 16) % 16;
+ col = ch % 16;
+ ch = ch / 256;
+
+ Board[row][col] = ch;
+ Appear[ch - 2]++;
+ Totalch++;
+ mapTurn = myTurn;
+ sprintf(msg, "\033[1;32m¡µ¹ï¤è½¶} %s\033[1;32m(%d, %c)\033[m", ch_icon[ch], col, row + 'A');
+ ch_draw();
+ ch_printmsg(1, msg);
+ break;
+
+ case 'T':
+ sprintf(msg, "\033[1;33m¡¹%s\033[m", buf + 1);
+ ch_printmsg(1, msg);
+ break;
+
+ case 'E':
+ ch = atoi(strtok(buf + 1, ":"));
+ row = (ch / 16) % 16;
+ col = ch % 16;
+ ch = ch / 256;
+ ch2 = atoi(strtok(NULL, ":"));
+ row2 = (ch2 / 16) % 16;
+ col2 = ch2 % 16;
+ ch2 = ch2 / 256;
+
+ Board[row][col] = Empty;
+ Board[row2][col2] = ch;
+ YourEat[youreat_index++] = ch2;
+ mapTurn = myTurn;
+ sprintf(msg, "\033[1;32m¡¾¹ï¤è²¾°Ê %s\033[1;32m(%d, %c) ¦Y %s\033[1;32m(%d, %c)\033[m",
+ ch_icon[ch], col, row + 'A',
+ ch_icon[ch2], col2, row2 + 'A');
+ ch_draw();
+ ch_printmsg(1, msg);
+ ch_printeat();
+
+ if (Choose)
+ {
+ if (youreat_index == 16)
+ ch_overgame((myColor == Black) ? Red : Black);
+ }
+ else
+ {
+ if (ch2 == 2 || ch2 == 9)
+ ch_overgame((myColor == Black) ? Red : Black);
+ }
+ break;
+
+ case 'M':
+ ch = atoi(strtok(buf + 1, ":"));
+ row = (ch / 16) % 16;
+ col = ch % 16;
+ ch = ch / 256;
+ ch2 = atoi(strtok(NULL, ":"));
+ row2 = (ch2 / 16) % 16;
+ col2 = ch2 % 16;
+ ch2 = ch2 / 256;
+
+ Board[row][col] = Empty;
+ Board[row2][col2] = ch;
+ mapTurn = myTurn;
+ sprintf(msg, "\033[1;37m¡¾¹ï¤è²¾°Ê %s\033[1;37m(%d, %c) ¦Ü (%d, %c)\033[m",
+ ch_icon[ch], col, row + 'A', col2, row2 + 'A');
+ ch_draw();
+ ch_printmsg(1, msg);
+ break;
+
+ case 'F':
+ dark_choose = 1;
+ myColor = (atoi(buf + 1) == Black) ? Red : Black;
+ ch_draw();
+ break;
+
+ case 'S':
+ ch_overgame(myColor);
+ break;
+
+ case 'Q':
+ return LEAVE;
+ }
+
+ return NOTHING;
+}
+
+
+static int
+ch_rand()
+{
+ int rd, i;
+ char *index[] = {"1", "2", "2", "2", "2", "2", "5", "1", "2", "2", "2", "2", "2", "5"};
+
+ if (Totalch == 31) /* Á×§K³Ñ³Ì«á¤@Ó®ÉÁÙn random */
+ {
+ for (i = 0; i < 14; i++)
+ {
+ if (Appear[i] < atoi(index[i]))
+ {
+ i += 2;
+ return i;
+ }
+ }
+ }
+
+ for (;;)
+ {
+ rd = rnd(16);
+
+ if (rd < 2)
+ continue;
+ if (Appear[rd - 2] < atoi(index[rd - 2]))
+ {
+ Appear[rd - 2] += 1;
+ Totalch++;
+ break;
+ }
+ else
+ continue;
+ }
+ return rd;
+}
+
+
+static int
+ch_count(row, col) /* ¦^¶Ç¥]/¬¶»P«Ý¦Yª«¤¤¶¡¦³´X¤@¤l */
+ int row, col;
+{
+ int count, start, end;
+
+ if (bwRow != row && bwCol != col) /* ¥²¶·¦b¦P¤@¦æ©Î¦P¤@¦C¸õ */
+ return -1;
+
+ count = 0;
+ if (bwRow != row)
+ {
+ if (bwRow > row)
+ {
+ start = row + 1;
+ end = bwRow;
+ }
+ else
+ {
+ start = bwRow + 1;
+ end = row;
+ }
+ for (; start < end; start++)
+ {
+ if (Board[start][bwCol] != Empty)
+ count++;
+ }
+ }
+ else
+ {
+ if (bwCol > col)
+ {
+ start = col + 1;
+ end = bwCol;
+ }
+ else
+ {
+ start = bwCol + 1;
+ end = col;
+ }
+ for (; start < end; start++)
+ {
+ if (Board[bwRow][start] != Empty)
+ count++;
+ }
+ }
+
+ return count;
+}
+
+
+static int /* 0:¬Û¦PÃC¦â 1:¤£¦PÃC¦â */
+ch_check(ch)
+ char ch;
+{
+ if ((myColor == Red && ch < 9) ||
+ (myColor == Black && ch > 8))
+ return 0;
+
+ return 1;
+}
+
+
+static int
+ch_Mv0() /* for x´Ñ */
+{
+ int mych, yourch, way; /* way: 0:NOTHING 1:move 2:eat */
+ int row, col, Rdis, Cdis;
+ char buf[120];
+
+ if(GameOver) return NOTHING;
+
+ row = (Focus / 16) % 16;
+ col = Focus % 16;
+ mych = Focus / 256;
+ yourch = Board[bwRow][bwCol];
+
+ Rdis = abs(row - bwRow); /* displayment */
+ Cdis = abs(col - bwCol);
+ way = NOTHING;
+
+ switch (mych)
+ {
+ case 2: /* «Ó±N */
+ case 9:
+ if (((bwCol >= 3 && bwCol <= 5) && (bwRow <= 2 || bwRow >= 7) && (Rdis + Cdis == 1)) || /* ¨î¦b¤E®c®æ¤¤¡A¨«¤@®æ */
+ (bwCol == col && abs(mych - yourch) == 7 && !ch_count(row, col))) /* ¤ý¨£¤ý */
+ {
+ if (yourch == Empty)
+ way = 1;
+ else if (ch_check(yourch))
+ way = 2;
+ }
+ break;
+
+ case 3: /* ¥K¤h */
+ case 10:
+ if ((bwCol >= 3 && bwCol <= 5) && (bwRow <= 2 || bwRow >= 7) && /* ¨î¦b¤E®c®æ¤¤ */
+ (Rdis == 1 && Cdis == 1)) /* ¨«¤@±× */
+ {
+ if (yourch == Empty)
+ way = 1;
+ else if (ch_check(yourch))
+ way = 2;
+ }
+ break;
+
+ case 4: /* ¬Û¶H */
+ case 11:
+ if (((bwRow <= 4 && myColor == Red) || (bwRow >= 5 && myColor == Black)) && /* ¨î¤£¯à¹Lªe */
+ (Rdis == 2 && Cdis == 2) && /* ¨«¤@¥Ð */
+ (Board[(bwRow + row) / 2][(bwCol + col) / 2] == Empty)) /* ¤£¯à©ä¶H¸} */
+ {
+ if (yourch == Empty)
+ way = 1;
+ else if (ch_check(yourch))
+ way = 2;
+ }
+ break;
+
+ case 5: /* ÚϨ® */
+ case 12:
+ if (!ch_count(row, col) && (row == bwRow || col == bwCol)) /* ¨«¤@½u */
+ {
+ if (yourch == Empty)
+ way = 1;
+ else if (ch_check(yourch))
+ way = 2;
+ }
+ break;
+
+ case 6: /* ØX°¨ */
+ case 13:
+ if ((Rdis == 2 && Cdis == 1 && Board[(bwRow + row) / 2][col] == Empty) || /* ¨«¤@©ä */
+ (Rdis == 1 && Cdis == 2 && Board[row][(bwCol + col) / 2] == Empty)) /* ¤£¯à©ä°¨¸} */
+ {
+ if (yourch == Empty)
+ way = 1;
+ else if (ch_check(yourch))
+ way = 2;
+ }
+ break;
+
+ case 7: /* ¬¶¥] */
+ case 14:
+ if (row == bwRow || col == bwCol) /* ¨«¤@½u */
+ {
+ Rdis = ch_count(row, col); /* ɥΠRdis */
+ if (Rdis == 0 && yourch == Empty)
+ way = 1;
+ else if (Rdis == 1 && yourch != Empty && ch_check(yourch))
+ way = 2;
+ }
+ break;
+
+ case 8: /* §L¨ò */
+ case 15:
+ if (Rdis + Cdis != 1) /* ¨«¤@®æ */
+ break;
+
+ if (myColor == Red)
+ {
+ if ((bwRow < row) || /* ¤£¯à¨«¦^ÀY¨B */
+ (row <= 4 && col != bwCol)) /* ¦b°ê¤º¥u¯à¨«ª½ªº */
+ break;
+ }
+ else
+ {
+ if ((bwRow > row) || /* ¤£¯à¨«¦^ÀY¨B */
+ (row >= 5 && col != bwCol)) /* ¦b°ê¤º¥u¯à¨«ª½ªº */
+ break;
+ }
+
+ if (yourch == Empty)
+ way = 1;
+ else if (ch_check(yourch))
+ way = 2;
+ break;
+ } /* end switch */
+ if (way == 1)
+ {
+ sprintf(buf, "M%d:%d", Focus, bwRow * 16 + bwCol);
+ if (!do_send(buf))
+ return DISCONNECT;
+ sprintf(buf, "\033[1;36m¡¿§Ú¤è²¾°Ê %s\033[1;36m(%d, %c) ¦Ü (%d, %c)\033[m",
+ ch_icon[mych], col, row + 'A', bwCol, bwRow + 'A');
+ strcpy(dstr[0], forspace);
+ outs(ch_brdline(0));
+ }
+ else if (way == 2)
+ {
+ sprintf(buf, "E%d:%d", Focus, yourch * 256 + bwRow * 16 + bwCol);
+ if (!do_send(buf))
+ return DISCONNECT;
+ sprintf(buf, "\033[1;32m¡¿§Ú¤è²¾°Ê %s\033[1;32m(%d, %c) ¦Y %s\033[1;32m(%d, %c)\033[m",
+ ch_icon[mych], col, row + 'A', ch_icon[yourch], bwCol, bwRow + 'A');
+ MyEat[myeat_index++] = yourch;
+ strcpy(dstr[0], forspace);
+ outs(ch_brdline(0));
+ ch_printeat();
+ }
+
+ if (way)
+ {
+ Board[bwRow][bwCol] = mych;
+ Board[row][col] = Empty;
+ mapTurn = yourTurn;
+ Focus = Empty;
+ ch_draw();
+ ch_printmsg(1, buf);
+
+ if (yourch == 2 || yourch == 9)
+ ch_overgame(myColor);
+ }
+
+ return NOTHING;
+}
+
+
+static int
+ch_Mv1() /* for ·t´Ñ */
+{
+ int row, col;
+ char mych, yourch;
+ char buf[120];
+
+ row = (Focus / 16) % 16;
+ col = Focus % 16;
+ mych = Focus / 256;
+ yourch = Board[bwRow][bwCol];
+
+ if (yourch == Empty) /* ²¾¶iªÅ¦a */
+ {
+ if (abs(bwRow - row) + abs(bwCol - col) != 1) /* n¦b¹j¾À¤~¯à²¾¹L¥h */
+ return NOTHING;
+
+ sprintf(buf, "M%d:%d", Focus, bwRow * 16 + bwCol);
+ if (!do_send(buf))
+ return DISCONNECT;
+ sprintf(buf, "\033[1;36m¡¿§Ú¤è²¾°Ê %s\033[1;36m(%d, %c) ¦Ü (%d, %c)\033[m",
+ ch_icon[mych], col, row + 'A', bwCol, bwRow + 'A');
+ strcpy(dstr[0], forspace);
+ outs(ch_brdline(0));
+ }
+ else /* ²¾¶i¦³¤lªº¦a */
+ {
+ if (!ch_check(yourch)) /* ¤£¦P¦â¤~¥i¥H¦Y */
+ return NOTHING;
+
+ if (mych == 7 || mych == 14) /* ¥]/¬¶¥Î¸õªº¤~¯à¦Y */
+ {
+ if (ch_count(row, col) != 1)
+ return NOTHING;
+ }
+ else
+ {
+ if (abs(bwRow - row) + abs(bwCol - col) != 1) /* ¤@¯ë¤ln¦b¹j¾À¤~¯à¦Y¹L¥h */
+ return NOTHING;
+
+ if (myColor == Black)
+ {
+ if (mych != 15 || yourch != 2) /* ¨ò¥i¥H¦Y«Ó */
+ {
+ if (mych - 7 > yourch) /* ¤p¤£¯à¦Y¤j */
+ return NOTHING;
+ if (mych == 9 && yourch == 8) /* ±N¤£¯à¦Y§L */
+ return NOTHING;
+ }
+ }
+ else
+ {
+ if (mych != 8 || yourch != 9) /* §L¥i¥H¦Y±N */
+ {
+ if (mych + 7 > yourch) /* ¤p¤£¯à¦Y¤j */
+ return NOTHING;
+ if (mych == 2 && yourch == 15) /* «Ó¤£¯à¦Y§L */
+ return NOTHING;
+ }
+ }
+ }
+
+ sprintf(buf, "E%d:%d", Focus, yourch * 256 + bwRow * 16 + bwCol);
+ if (!do_send(buf))
+ return DISCONNECT;
+ MyEat[myeat_index++] = yourch;
+ sprintf(buf, "\033[1;32m¡¿§Ú¤è²¾°Ê %s\033[1;32m(%d, %c) ¦Y %s\033[1;32m(%d, %c)\033[m",
+ ch_icon[mych], col, row + 'A', ch_icon[yourch], bwCol, bwRow + 'A');
+ strcpy(dstr[0], forspace);
+ outs(ch_brdline(0));
+ ch_printeat();
+ }
+
+ Board[bwRow][bwCol] = mych;
+ Board[row][col] = Empty;
+ mapTurn = yourTurn;
+ Focus = Empty;
+
+ ch_draw();
+ ch_printmsg(1, buf);
+
+ if (myeat_index == 16)
+ ch_overgame(myColor);
+
+ return NOTHING;
+}
+
+
+static int
+chCtrlS()
+{
+ if(!GameOver) {
+ if (!do_send("S"))
+ return DISCONNECT;
+ ch_overgame((myColor == Black) ? Red : Black);
+ }
+ return NOTHING;
+}
+
+
+static int
+chLEFT()
+{
+ if (bwCol > 0)
+ bwCol--;
+ return NOTHING;
+}
+
+
+static int
+chRIGHT()
+{
+ if (bwCol < 8 - Choose)
+ bwCol++;
+ return NOTHING;
+}
+
+
+static int
+chUP()
+{
+ if (bwRow > 0)
+ bwRow--;
+ return NOTHING;
+}
+
+
+static int
+chDOWN()
+{
+ if (bwRow < 9 - Choose * 6)
+ bwRow++;
+ return NOTHING;
+}
+
+
+static int
+chEnter()
+{
+ char buf[40], ch;
+
+ if(GameOver) return NOTHING;
+
+ ch = Board[bwRow][bwCol];
+ if (ch == Cover) /* ·t´Ñ½¤l */
+ {
+ ch = ch_rand();
+ Board[bwRow][bwCol] = ch;
+ sprintf(buf, "D%d", ch * 256 + bwRow * 16 + bwCol);
+ if (!do_send(buf))
+ return DISCONNECT;
+
+ if (!dark_choose) /* ·t´Ñ²Ä¤@¦¸Â½¤l¨M©wÃC¦â */
+ {
+ dark_choose = 1;
+ myColor = (ch < 9) ? Red : Black;
+ sprintf(buf, "F%d", myColor);
+ if (!do_send(buf))
+ return DISCONNECT;
+ }
+
+ mapTurn = yourTurn;
+ Focus = Empty;
+ sprintf(buf, "\033[1;32m¡¶§Ú¤è½¶} %s\033[1;32m(%d, %c)\033[m",
+ ch_icon[ch], bwCol, bwRow + 'A');
+ strcpy(dstr[0], forspace);
+ outs(ch_brdline(0));
+ ch_draw();
+ ch_printmsg(1, buf);
+ }
+ else
+ {
+ if (Focus) /* x/·t´Ñ²¾°Ê */
+ {
+ if (Focus == ch * 256 + bwRow * 16 + bwCol) /* ¦A¿ï¤@¹Mªí¥Ü¨ú®ø¿ï¨ú */
+ {
+ Focus = 0;
+ ch_printmsg(3, NULL);
+ }
+ else
+ return Choose ? ch_Mv1() : ch_Mv0();
+ }
+ else /* x/·t´Ñ¿ï¨ú */
+ {
+ if (ch != Empty && !ch_check(ch))
+ {
+ Focus = ch * 256 + bwRow * 16 + bwCol;
+ ch_printmsg(2, NULL);
+ }
+ }
+ }
+ return NOTHING;
+}
+
+
+static KeyFunc yourTurn[] =
+{
+ Ctrl('C'), ftnCtrlC,
+ Ctrl('D'), fCtrlD,
+ KEY_LEFT, chLEFT,
+ KEY_RIGHT, chRIGHT,
+ KEY_UP, chUP,
+ KEY_DOWN, chDOWN,
+ KEY_TAB, fTAB,
+ 0, fNoOp
+};
+
+
+static KeyFunc myTurn[] =
+{
+ Ctrl('C'), ftnCtrlC,
+ Ctrl('D'), fCtrlD,
+ Ctrl('S'), chCtrlS,
+ ' ', chEnter,
+ '\n', chEnter,
+ KEY_LEFT, chLEFT,
+ KEY_RIGHT, chRIGHT,
+ KEY_UP, chUP,
+ KEY_DOWN, chDOWN,
+ KEY_TAB, fTAB,
+ 0, fNoOp
+};
+
+
+/*-------------------------------------------------------*/
+/* ©Ò¦³´Ñ½L¤½¥Î¥Dµ{¦¡ */
+/*-------------------------------------------------------*/
+
+
+/* rule set */
+static int (**ruleSet[]) () =
+{
+ othRule, fivRule, blkRule, armyRule, darkRule
+};
+
+
+static void
+do_init()
+{
+ char *t, *mateid, msg[160], buf[80];
+ int i, myTotal, yourTotal, myWin, yourWin;
+
+ /* Initialize forspace */
+ memset(forspace, 32, 60);
+ forspace[60] = 0;
+
+ /* Initialize state */
+ (*rule[Binit]) ();
+ mapTalk = NULL; /* ¤@¶}©l¶i¤J¬O¦b´Ñ½L¤W */
+ GameOver = 0;
+
+ bwRow = bwCol = 0;
+ msgline = 1;
+
+ cmdCol = 0;
+ *cmdBuf = 0;
+ cmdPos = -1;
+
+ /* Initialize screen */
+ clear();
+
+ t = cuser.userid;
+ mateid = cutmp->mateid;
+
+ /* ¨ú±o¾ÔÁZ */
+ play_count(t, &myTotal, &myWin);
+ play_count(mateid, &yourTotal, &yourWin);
+
+ sprintf(buf, "¡¸%s(%d¾Ô%d³Ó) vs ¡¹%s(%d¾Ô%d³Ó) \033[m",
+ t, myTotal, myWin, mateid, yourTotal, yourWin);
+
+ sprintf(msg, "\033[1;33;44m¡i ¹ï«³%s ¡j", ruleStr);
+ i = 80 - strlen(buf) + 3 - strlen(msg) + 10;
+ t = str_tail(msg);
+ for (; i; i--)
+ *t++ = ' ';
+ strcpy(t, buf);
+ outs(msg);
+
+ (Choose < 0) ? bw_init() : ch_init();
+}
+
+
+static int
+main_board(sock, later)
+ int sock, later;
+{
+ screenline sl[T_LINES];
+ char c;
+ int ch;
+ KeyFunc *k;
+
+ vs_save(sl);
+ cfd = sock;
+
+ if (!later)
+ {
+ /* ask for which rule set */
+ /* assume: peer won't send char until setup */
+ c = vans("·Q¤UþºØ´Ñ (1)¶Â¥Õ´Ñ (2)¤¤l´Ñ (3)³ò´Ñ (4)x´Ñ (5)·t´Ñ (Q)¨ú®ø¡H[Q] ");
+ if (c >= '1' && c <= '5')
+ {
+ c -= '1';
+ }
+ else
+ {
+ c = -1;
+ vs_restore(sl); /* lkchu.990428: §â foot restore ¦^¨Ó */
+ }
+
+ /* transmit rule set */
+ if (send(cfd, &c, 1, 0) != 1)
+ return DISCONNECT;
+
+ /* ±Ò°Ê¹CÀ¸ªÌ¬°¶Â¤l */
+ myColor = Black;
+ }
+ else
+ {
+ /* prompt for waiting rule set */
+ outz("¡¹ ¹ï¤èn¨D¶i¤J¹ï«³¼Ò¦¡¿ï¾Ü¤¤¡A½ÐµyÔ \033[5m...\033[m");
+ refresh();
+ /* receive rule set */
+ if (recv(cfd, &c, 1, 0) != 1)
+ return DISCONNECT;
+
+ vs_restore(sl); /* lkchu.990428: §â foot restore ¦^¨Ó */
+
+ /* ³Q±Ò°Ê¹CÀ¸ªÌ¬°¬õ(¥Õ)¤l */
+ myColor = White; /* White == Red */
+ }
+
+ if (c < 0)
+ return LEAVE;
+ rule = ruleSet[c];
+ ruleStr = ruleStrSet[c];
+
+ Choose = c - 3; /* -3:¶Â¥Õ´Ñ -2:¤¤l´Ñ -1:³ò´Ñ 0:x´Ñ 1:·t´Ñ */
+
+ /* initialize all */
+ do_init();
+
+ for (;;)
+ {
+ if (mapTalk)
+ {
+ move(b_lines - 2, cmdCol + 35);
+ k = mapTalk;
+ }
+ else
+ {
+ if (Choose < 0)
+ move(bwRow + 1, bwCol * 2 + 1);
+ else if (Choose == 0)
+ move(bwRow * 2 + 1, bwCol * 4 + 1);
+ else
+ move(bwRow * 2 + 2, bwCol * 4 + 3);
+
+ k = mapTurn;
+ }
+
+ ch = vkey();
+ if (ch == I_OTHERDATA)
+ { /* incoming */
+ ch = (Choose < 0) ? bw_recv() : ch_recv();
+ if (ch >= NOTHING) /* -1 for exit bwboard, -2 for exit talk */
+ continue;
+ vs_restore(sl);
+ return ch;
+ }
+
+#ifdef EVERY_Z
+ /* Thor: Chat ¤¤«ö ctrl-z */
+ else if (ch == Ctrl('Z'))
+ {
+ char buf[IDLEN + 1];
+ screenline slt[T_LINES];
+
+ /* Thor.980731: ¼È¦s mateid, ¦]¬°¥X¥h®É¥i¯à·|¥Î±¼ mateid */
+ strcpy(buf, cutmp->mateid);
+
+ vio_save(); /* Thor.980727: ¼È¦s vio_fd */
+ vs_save(slt);
+ every_Z(0);
+ vs_restore(slt);
+ vio_restore(); /* Thor.980727: ÁÙì vio_fd */
+
+ /* Thor.980731: ÁÙì mateid, ¦]¬°¥X¥h®É¥i¯à·|¥Î±¼ mateid */
+ strcpy(cutmp->mateid, buf);
+ continue;
+ }
+#endif
+
+ for (;; k++)
+ {
+ if (!k->key || ch == k->key)
+ break;
+ }
+
+ /* -1 for exit bwboard, -2 for exit talk */
+ if ((ch = k->key ? (*k->func) () : (*k->func) (ch)) >= NOTHING)
+ continue;
+ vs_restore(sl);
+ return ch;
+ }
+}
+
+#include <stdarg.h>
+
+int
+vaBWboard(pvar)
+ va_list pvar;
+{
+ int sock, later;
+ sock = va_arg(pvar, int);
+ later = va_arg(pvar, int);
+ return main_board(sock, later);
+}
+#endif /* HAVE_GAME */
diff --git a/game/chessmj.c b/game/chessmj.c new file mode 100644 index 0000000..afca8a7 --- /dev/null +++ b/game/chessmj.c @@ -0,0 +1,1023 @@ +/*-------------------------------------------------------*/ +/* chessmj.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¶H´Ñ³Â±N¹CÀ¸ */ +/* create : 98/07/29 */ +/* update : 01/04/25 */ +/* author : weiren@mail.eki.com.tw */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#ifdef HAVE_GAME + + +static int host_card[5]; /* ¹q¸£(²ø®a) ªºµP */ +static int guest_card[5]; /* ª±®aªºµP */ +static int throw[32]; /* ³Q¥á±óªºµP */ + +static int flag; +static int tflag; +static int tflagA; +static int tflagB; +static int selftouch; /* ¦ÛºN */ + +static int cnum[32] = +{ + 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 7, 7, 7, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 13, 13, + 14, 14, 14, 14, 14 +}; + +static int group[32] = +{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6 +}; + + +static void +out_song() +{ + static int count = 0; + + /* Ĭ¼zÛ£»¤£n¦A»¡·R§Ú */ + uschar *msg[8] = + { + "§Ñ±¼§a§Úªº¦Ñ±¡¤H §O¦b·N¤]§O»¡¥X¨Ó", + " ®É¶¡¤w¨R²H¤@¤Á ¤ß±¡¤]¨S¦³©u¸` §â¹L¥h©ñ¦^§A¤ß¤¤", + "¤£n°Ý§Ú½Ö¹ï½Ö¿ù §Aªº·R¦b§Ú¦^¾Ð¤¤ ³o¨Ç¦~²ßºD¦Û¥Ñ", + "¤]¨S¦³¤Ó¦h·Ð¼~ ¨º¹L¥h´N¹³¤@°}·", + "¤£n¦A»¡·R§Ú ¤£n¦A»¡·R§Ú", + "²{¦b§Ṳ́§¶¡ ¥u¯à·í·íªB¤Í", + "¸¨¤U¤Ó¦h²´²\\ µ¥¹L¤Ó¦h¶Â©]", + "²{¦b§Ú¤@Ó¤H ·R±¡§Ú¤£·Q°Ý" + }; + move(b_lines - 2, 0); + prints("\033[1;3%dm%s\033[m Äw½XÁÙ¦³ %d ¤¸", time(0) % 7, msg[count], cuser.money); + clrtoeol(); + if (++count == 8) + count = 0; +} + + +static void +print_Sign(x, y) + int x, y; +{ + move(x, y); + outs("¢~¡´¢¡"); +} + + +static void +print_Schess(card, x, y) + int card, x, y; +{ + char *chess[33] = + { + "«Ó", "¥K", "¥K", "¬Û", "¬Û", "ÚÏ", "ÚÏ", "ØX", "ØX", "¬¶", "¬¶", + "§L", "§L", "§L", "§L", "§L", + "±N", "¤h", "¤h", "¶H", "¶H", "¨®", "¨®", "°¨", "°¨", "¥]", "¥]", + "¨ò", "¨ò", "¨ò", "¨ò", "¨ò", "¢æ" + }; + + move(x, y); + outs("¢~¢w¢¡"); + move(x + 1, y); + prints("¢x%2s¢x", chess[card]); + move(x + 2, y); + outs("¢¢¢w¢£"); +} + + +static inline void +clear_5card() +{ + move(15, 24); + outs(" "); + move(16, 24); + outs(" "); + move(17, 24); + outs(" "); +} + + +static inline void +Phost5() +{ + move(4, 24); + outs("¢~¢w¢¡"); + move(5, 24); + outs("¢x ¢x"); + move(6, 24); + outs("¢¢¢w¢£"); +} + + +static inline void +Chost5() +{ + move(4, 24); + outs(" "); + move(5, 24); + outs(" "); + move(6, 24); + outs(" "); +} + + +static inline void +P_allchess() +{ + char *chess[33] = { + "«Ó", "¥K", "¥K", "¬Û", "¬Û", "ÚÏ", "ÚÏ", "ØX", "ØX", "¬¶", "¬¶", + "§L", "§L", "§L", "§L", "§L", + "±N", "¤h", "¤h", "¶H", "¶H", "¨®", "¨®", "°¨", "°¨", "¥]", "¥]", + "¨ò", "¨ò", "¨ò", "¨ò", "¨ò", "" + }; + + int i; + + for (i = 0; i < 4; i++) + { + move(16, 2 + 6 * i); + outs(chess[guest_card[i]]); + } +} + + +static inline void +sortchess() +{ + int i, j, x; + for (i = 0; i < 4; i++) + { + for (j = 0; j < (3 - i); j++) + { + if (guest_card[j] > guest_card[j + 1]) + { + x = guest_card[j]; + guest_card[j] = guest_card[j + 1]; + guest_card[j + 1] = x; + } + if (host_card[j] > host_card[j + 1]) + { + x = host_card[j]; + host_card[j] = host_card[j + 1]; + host_card[j + 1] = x; + } + } + } +} + + +static int +testpair(a, b) + int a, b; +{ + if (cnum[a] == cnum[b]) + return 1; + if (cnum[a] == 1 && cnum[b] == 8) + return 1; + if (cnum[a] == 8 && cnum[b] == 1) + return 1; + return 0; +} + + +static int +testthree(a, b, c) + int a, b, c; +{ + int tmp; + if (a > b) + { + tmp = a; + a = b; + b = tmp; + } + if (b > c) + { + tmp = b; + b = c; + c = tmp; + } + if (a > b) + { + tmp = a; + a = b; + b = tmp; + } + if (cnum[a] == 1 && cnum[b] == 2 && cnum[c] == 3) + return 1; /* «Ó¥K¬Û */ + if (cnum[a] == 4 && cnum[b] == 5 && cnum[c] == 6) + return 1; /* ÚÏØX¬¶ */ + if (cnum[a] == 8 && cnum[b] == 9 && cnum[c] == 10) + return 1; /* ±N¤h¶H */ + if (cnum[a] == 11 && cnum[b] == 12 && cnum[c] == 13) + return 1; /* ¨®°¨¥] */ + if (cnum[a] == 7 && cnum[b] == 7 && cnum[c] == 7) + return 1; /* §L§L§L */ + if (cnum[a] == 14 && cnum[b] == 14 && cnum[c] == 14) + return 1; /* ¨ò¨ò¨ò */ + return 0; +} + + +static int +testall(set) + int set[5]; +{ + int i, j, k, m, p[3]; + for (i = 0; i < 4; i++) + { + for (j = i + 1; j < 5; j++) + { + m = 0; + for (k = 0; k < 5; k++) + { + if (k != i && k != j) + { + p[m] = set[k]; + m++; + } + } + if (testpair(set[i], set[j]) != 0 && testthree(p[0], p[1], p[2]) != 0) + return 1; + } + } + return 0; +} + + +static void +printhostall() +{ + int i; + for (i = 0; i < 5; i++) + print_Schess(host_card[i], 4, 6 * i); +} + + +static void +printhostfour() +{ + int i; + for (i = 0; i < 4; i++) + print_Schess(host_card[i], 4, 6 * i); +} + + +static int +testlisten(set) + int set[4]; +{ + int i, j, k, p[2] = {0}, m = 0, mm = 0; + + j = 0; + for (i = 0; i < 4; i++) + { + if (group[set[i]] != 3) + j++; + } if (j == 0) + return 1; /* ¥|¤ä§L */ + j = 0; + for (i = 0; i < 4; i++) + { + if (group[set[i]] != 6) + j++; + } if (j == 0) + return 1; /* ¥|¤ä¨ò */ + + if (testthree(set[1], set[2], set[3]) != 0) + return 1; + if (testthree(set[0], set[2], set[3]) != 0) + return 1; + if (testthree(set[0], set[1], set[3]) != 0) + return 1; + if (testthree(set[0], set[1], set[2]) != 0) + return 1; /* ¤T¤ä¦¨§Î«hÅ¥ */ + for (i = 0; i < 3; i++) + { + for (j = i + 1; j < 4; j++) + { + if (testpair(set[i], set[j])) + { /* ¨â¤ä¦³F¬Ý¥t¨â¤ä¦³¨S¦³Å¥ */ + m = 0; + for (k = 0; k < 4; k++) + { + if (k != i && k != j) + { + p[m] = set[k]; + m++; + } + if (group[set[i]] == 3 || group[set[i]] == 6) + mm = 1; /* ¦³Fªº¬O§L©Î¨ò */ + } + } + } + } + if (m != 0) + { + if ((group[p[0]] == group[p[1]]) && (cnum[p[0]] != cnum[p[1]])) + return 1; /* ¨â¤ä¬O pair ¥t¨â¤ä¦³Å¥ */ + if ((group[p[0]] == group[p[1]] == 3) || (group[p[0]] == group[p[1]] == 6)) + return 1; + if (testpair(p[0], p[1]) && mm == 1) + return 1; + } + return 0; +} + + +static inline void +host_hula() +{ + print_Sign(11, (tflagB - 1) * 4); /* ¦L¾ßµP²Å¸¹ */ + printhostall(); +} + + +static inline void +host_self() +{ + printhostall(); +} + + +static int +diecard(a) /* ¶Ç¶i¤@±iµP, ¬Ý¬O§_µ´±i */ + int a; +{ + int i, k = 0; + for (i = 0; i < tflag; i++) + { + if (cnum[throw[i]] == cnum[a]) + k++; + if (cnum[throw[i]] == 1 && cnum[a] == 8) + return 1; + if (cnum[throw[i]] == 8 && cnum[a] == 1) + return 1; + } + if ((cnum[a] == 7 || cnum[a] == 14) && k == 4) + return 1; /* §L¨òµ´±i */ + if (k == 1 && (cnum[a] != 7 && cnum[a] != 14)) + return 1; + return 0; +} + + +static inline int +any_throw() +{ + int i, j, k, set[5] = {0}, tmp[4] = {0}; + int point[5] = {0}; /* point[5] ¬°µû¤À¨t²Î, ¬Ý¥áþ±iµP¤ñ¸û¦n, ¤À¼Æ°ªªºÀu¥ý¥á */ + + /* ´ú¸Õ±N¤â¤W¤¤ä®³±¼¤@¤ä */ + for (i = 0; i < 5; i++) + { + k = 0; + for (j = 0; j < 5; j++) + { + if (i != j) + { + tmp[k] = host_card[j]; + k++; + } + } + if (testlisten(tmp)) /* Y³Ñ¾lªº¥|¤ä¤wÅ¥µP, ¥á¦hªº¨º±i */ + { + point[i] += 10; /* ¦³Å¥´N¥[ 10 ¤À */ + if (diecard(host_card[i])) + point[i] += 5; /* µ´±i§ó¸Ó¥á */ + for (k = 0; k < 4; k++) + { + if (((cnum[host_card[i]] == cnum[tmp[k]]) || + (cnum[tmp[k]] == 1 && cnum[host_card[i]] == 8) || + (cnum[tmp[k]] == 8 && cnum[host_card[i]] == 1)) && + cnum[host_card[i]] != 7 && cnum[host_card[i]] != 14) + point[i] += 10; + } + /* ¨®°¨¥]¥], ¥]¸Ó¥á */ + } + } + + k = 0; + for (i = 0; i < 5; i++) + { + if (cnum[host_card[i]] == 7) + k++; /* ºâ¦³´X¤ä§L */ + } + if (k == 3) /* ¦³¤T¤ä§L: ³Ñ¤U¤G¤ä¤£¬O§Lªº¦U¥[ 5 ¤À */ + { + for (i = 0; i < 5; i++) + { + if (cnum[host_card[i]] != 7) + point[i] += 5; + } + } + else if (k == 4) /* ¦³¥|¤ä§L */ + { + if (diecard(12)) /* ¦ý³Ì«á¤@¤ä§L¤wµ´±i: ¥á§L */ + { + for (i = 0; i < 5; i++) + { + if (cnum[host_card[i]] == 7) + point[i] += 9999; + } + } + else /* ³Ì«á¤@¤ä§L©|¥¼µ´±i: ¥á¤£¬O§Lªº¨º¤ä */ + { + for (i = 0; i < 5; i++) + { + if (cnum[host_card[i]] != 7) + point[i] += 9999; + } + } + } + + k = 0; + for (i = 0; i < 5; i++) + { + if (cnum[host_card[i]] == 14) + k++; /* ºâ¦³´X¤ä¨ò */ + } + if (k == 3) /* ¦³¤T¤ä¨ò: ³Ñ¤U¤G¤ä¤£¬O¨òªº¦U¥[ 5 ¤À */ + { + for (i = 0; i < 5; i++) + { + if (cnum[host_card[i]] != 14) + point[i] += 5; + } + } + else if (k == 4) /* ¦³¥|¤ä¨ò */ + { + if (diecard(28)) /* ¦ý³Ì«á¤@¤ä¨ò¤wµ´±i: ¥á¨ò */ + { + for (i = 0; i < 5; i++) + { + if (cnum[host_card[i]] == 14) + point[i] += 9999; + } + } + else /* ³Ì«á¤@¤ä¨ò©|¥¼µ´±i: ¥á¤£¬O¨òªº¨º¤ä */ + { + for (i = 0; i < 5; i++) + { + if (cnum[host_card[i]] != 14) + point[i] += 9999; + } + } + } + + for (i = 0; i < 4; i++) + { + for (j = i + 1; j < 5; j++) + { + if (group[host_card[i]] == group[host_card[j]]) + { + point[i] -= 2; + point[j] -= 2; /* ®t¤@¤ä¦¨¤Tªº¤£¥á */ + } + if (testpair(host_card[i], host_card[j])) + { + point[i] -= 2; + point[j] -= 2; /* ¦³Fªº¤£¥á */ + } + } + } + +#if 1 /* A½â, ¦pªG¥á¤F·|³QJ´N¦º³£¤£¥á, A½â¾÷²v 5/6 */ + for (i = 0; i < 4; i++) + set[i] = guest_card[i]; + for (i = 0; i < 5; i++) + { + set[4] = host_card[i]; + if (testall(set) && rnd(6)) + point[i] = -9999; + } +#endif + + /* §ä¥X¤À¼Æ³Ì°ªªº */ + j = 0; + k = point[0]; + for (i = 1; i < 5; i++) + { + if (point[i] >= k) + { + k = point[i]; + j = i; + } + } + return j; +} + + +static int +count_tai(set) + int set[5]; /* Ĺªº¤±iµP */ +{ + char *name[10] = + { + "±N«Ó¹ï", "±N¤h¶H", "«Ó¥K¬Û", + "¤§L¦XÁa", "¤¨ò³s¾î", "¤T§L¤J¦C", "¤T¨ò¤J¦C", + "®ü©³", "¤ÑJ", "¦ÛºN" + }; + + int tai[10] = /* ¥x¼Æ¹ïÀ³¤W±ªº±Ôz */ + { + 2, 1, 1, + 5, 5, 2, 2, + 3, 5, 1 + }; + + int yes[10] = {0}; + int i, j, k, sum; + + if (selftouch) + yes[9] = 1; /* ¦ÛºN */ + + if (flag == 32) + yes[7] = 1; /* ®ü©³ */ + else if (tflag <= 1) + yes[8] = 1; /* ¤ÑJ */ + + for (i = 0, j = 0, k = 0; i < 5; i++) + { + /* ºâ «Ó/±N ªº¤ä¼Æ */ + if (cnum[set[i]] == 1) + j++; + if (cnum[set[i]] == 8) + k++; + } + if (j) + { + if (k) + yes[0] = 1; /* ¦³«Ó¤S¦³±N´N¬O ±N«Ó¹ï */ + else + yes[2] = 1; /* ¦³«Ó¨S¦³±N´N¬O «Ó¥K¬Û */ + } + else if (k) + { + yes[1] = 1; /* ¦³±N¨S¦³«Ó´N¬O ±N¤h¶H */ + } + + for (i = 0, j = 0; i < 5; i++) + { + /* ºâ §L ªº¤ä¼Æ */ + if (cnum[set[i]] == 7) + j++; + } + if (j == 5) + yes[3] = 1; /* ¤§L¦XÁa */ + else if (j == 3) + yes[5] = 1; /* ¤T§L¤J¦C */ + + for (i = 0, j = 0; i < 5; i++) + { + /* ºâ ¨ò ªº¤ä¼Æ */ + if (cnum[set[i]] == 14) + j++; + } + if (j == 5) + yes[4] = 1; /* ¤¨ò³s¾î */ + else if (j == 3) + yes[6] = 1; /* ¤T¨ò¤J¦C */ + + /* ºâ¥x¼Æ */ + sum = 0; + for (i = 0; i < 10; i++) + { + if (yes[i]) + sum += tai[i]; + } + + /* ¦C¦L¥X¼ú¶µ */ + move(b_lines - 5, 0); + outs("¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\n"); + for (i = 0; i < 5; i++) + { + if (yes[i]) + prints(" %8s [%d ¥x]", name[i], tai[i]); + } + move(b_lines - 3, 0); + for (i = 5; i < 10; i++) + { + if (yes[i]) + prints(" %8s [%d ¥x]", name[i], tai[i]); + } + move(b_lines - 2, 0); + clrtoeol(); /* ²M°£ out_song() */ + prints(" ©³ [2 ¥x] ¦Xp [%d ¥x]\n", sum += 2); + outs("¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}"); + + return sum; +} + + +int +main_chessmj() +{ + int money; /* ©ãª÷ */ + int mo; /* 1:¤wºNµP 0:¥¼ºNµP */ + int picky; /* 1:¾ß§O¤HªºµP 0:¦Û¤vºNªº */ + int pickup; + int listen; /* 1:Å¥µP 0:¨S¦³Å¥µP */ + int chesslist[32]; /* 32 ±iµP²Õ */ + + int i, j, k, m; + int jp, x, xx, ch, z; + + char ans[10], *msg; + int tmp[4]; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + while (1) + { + vs_bar("¶H´Ñ³Â±N"); + + out_song(); + + vget(2, 0, "½Ð°Ýn¤Uª`¦h¤Ö©O¡H(1 ~ 50000) ", ans, 6, DOECHO); + money = atoi(ans); + if (money < 1 || money > 50000 || money * 10 > cuser.money) + { + vmsg("n¦³¤Q¿ªº½äª÷¤~¥i¥H¶i¨Ó³á...¡I"); /* ½ß¿ú³Ì¦h½ß¤Q¿ */ + break; /* Â÷¶}½ä³õ */ + } + cuser.money -= money; /* ¦©¤@¥÷½äª÷¡Aª±®a¦pªG¤¤³~Â÷¶}±N®³¤£¦^½äª÷ */ + + move(2, 0); + clrtoeol(); /* ²M±¼¡u½Ð°Ýn¤Uª`¦h¤Ö¡v */ + outs("(«ö ¡ö¡÷¿ïµP, ¡ô¥áµP, «ö ENTER JµP)"); + + for (i = 0; i < 32; i++) /* µP¥ý¤@±i¤@±i±Æ¦n¡A·Ç³Æ¬~µP */ + chesslist[i] = i; + + for (i = 0; i < 31; i++) + { + j = rnd(32 - i) + i; + + /* chesslist[j] ©M chesslist[i] ¥æ´« */ + m = chesslist[i]; + chesslist[i] = chesslist[j]; + chesslist[j] = m; + } + + for (i = 0; i < 32; i++) /* ÁÙ¨S¦³µP³Q¥á±ó */ + throw[i] = 32; + + selftouch = 0; /* Âk¹s */ + mo = 0; + pickup = 0; + picky = 0; + listen = 0; + flag = 0; + tflag = 0; + tflagA = 0; + tflagB = 0; + + for (i = 0; i < 4; i++) /* µo«e¥|±iµP */ + { + host_card[i] = chesslist[flag]; + flag++; + guest_card[i] = chesslist[flag]; + flag++; + } + + for (i = 0; i < 4; i++) /* ±Æ§Ç */ + { + for (j = 0; j < (3 - i); j++) + { + if (guest_card[j] > guest_card[j + 1]) + { + m = guest_card[j]; + guest_card[j] = guest_card[j + 1]; + guest_card[j + 1] = m; + } + if (host_card[j] > host_card[j + 1]) + { + m = host_card[j]; + host_card[j] = host_card[j + 1]; + host_card[j + 1] = m; + } + } + } + + move(4, 0); + outs("¢~¢w¢¡¢~¢w¢¡¢~¢w¢¡¢~¢w¢¡"); + move(5, 0); + outs("¢x ¢x¢x ¢x¢x ¢x¢x ¢x"); + move(6, 0); + outs("¢¢¢w¢£¢¢¢w¢£¢¢¢w¢£¢¢¢w¢£"); + + for (i = 0; i < 4; i++) + print_Schess(guest_card[i], 15, 6 * i); /* ¦L¥X«e¥|±iµP */ + + for (;;) + { + jp = 5; + x = 0; + z = 1; + move(18, 26); + do + { + if (!mo) + { + move(14, 24); + outs("«ö¥ô¤@ÁäºNµP(©Î ¡õ ¾ßµP)"); + } + else + { + move(14, 0); + clrtoeol(); + } + move(18, 2 + (jp - 1) * 6); + outs("¡¶"); + move(18, 3 + (jp - 1) * 6); /* Á×§K¥þ§Î°»´ú */ + + ch = vkey(); + + if (ch != '\n' && flag == 32) + { + msg = "¬y§½"; + goto next_game; + } + if (!mo && ch != KEY_DOWN && ch != '\n') + { + ch = 'p'; /* ¥|±iµP«h±j¨îºNµP */ + } + + switch (ch) + { + case KEY_RIGHT: + move(18, 2 + (jp - 1) * 6); + outs(" "); + jp += 1; + if (jp > 5) + jp = 5; + move(18, 2 + (jp - 1) * 6); + outs("¡¶"); + move(18, 3 + (jp - 1) * 6); /* Á×§K¥þ§Î°»´ú */ + break; + + case KEY_LEFT: + move(18, 2 + (jp - 1) * 6); + outs(" "); + jp -= 1; + if (jp < 1) + jp = 1; + move(18, 2 + (jp - 1) * 6); + outs("¡¶"); + move(18, 3 + (jp - 1) * 6); /* Á×§K¥þ§Î°»´ú */ + break; + + case KEY_UP: /* ¥XµP */ + move(18, 2 + (jp - 1) * 6); + outs(" "); + throw[tflag] = guest_card[jp - 1]; + tflag++; + tflagB++; + z = 0; + mo = 0; + guest_card[jp - 1] = guest_card[4]; + guest_card[4] = 0; + sortchess(); + clear_5card(); + P_allchess(); + print_Schess(throw[tflag - 1], 11, (tflagB - 1) * 4); + picky = 0; + break; + + case 'p': /* ºNµP */ + if (!mo) + { + move(18, 2 + (jp - 1) * 6); + outs(" "); + guest_card[4] = chesslist[flag]; + flag++; + print_Schess(guest_card[4], 15, 24); + mo = 1; + } + break; + + case KEY_DOWN: + if (tflag > 0 && !mo) + { + guest_card[4] = throw[tflag - 1]; + print_Sign(8, (tflagA - 1) * 4); + print_Schess(guest_card[4], 15, 24); + mo = 1; + picky = 1; + } + break; + + case 'q': + return 0; + goto abort_game; + break; + + case '\n': + if (testall(guest_card) && mo && !picky) + { + printhostfour(); + msg = "«z«¨¦ÛºN°Õ¡I"; + addmoney(money * count_tai(guest_card)); + goto next_game; + } + else if (picky && testall(guest_card)) + { + printhostfour(); + msg = "¬Ý§Úªº¼F®`¡AJ°Õ¡I"; + addmoney(money * count_tai(guest_card)); + goto next_game; + } + + if (tflag > 0 && !mo) + { + i = guest_card[4]; + guest_card[4] = throw[tflag - 1]; + if (testall(guest_card) == 1) + { + print_Sign(8, (tflagA - 1) * 4); + print_Schess(guest_card[4], 15, 24); + printhostfour(); + msg = "J¡I"; + addmoney(money * count_tai(guest_card)); + goto next_game; + } + guest_card[4] = i; + } + break; + + default: + break; + } + } while (z == 1); + + host_card[4] = throw[tflag - 1]; + if (testall(host_card)) + { + host_hula(); + msg = "¹q¸£J°Õ¡I"; + cuser.money -= money * count_tai(host_card); /* ¹q¸£¥x¼Æ¶V¦h´N½ß¶V¦h¡A¥B©ãª÷¨S¦¬ */ + if (cuser.money < 0) + cuser.money = 0; + goto next_game; + } + + if (tflag == 32) + { + msg = "¬y§½"; + goto next_game; + } + + host_card[4] = chesslist[flag]; + if (testall(host_card)) + { + host_self(); + msg = "¹q¸£¦ÛºN¡I"; + cuser.money -= money * count_tai(host_card); /* ¹q¸£¥x¼Æ¶V¦h´N½ß¶V¦h¡A¥B©ãª÷¨S¦¬ */ + if (cuser.money < 0) + cuser.money = 0; + goto next_game; + } + + for (i = 0; i < 4; i++) + tmp[i] = host_card[i]; + + if (!testlisten(tmp)) + { /* ¨SÅ¥ªº¸Ü */ + for (i = 0; i < 4; i++) + { + k = 0; + for (j = 0; j < 4; j++) + { + if (i != j) + { + tmp[k] = host_card[j]; + k++; + } + } + tmp[3] = throw[tflag - 1]; /* §â¾ß°_¨º±i¸ò¤â¤WªºµP¤ñ¹ï */ + if (testlisten(tmp)) + { /* ¾ßµP¦³Å¥ªº¸Ü */ + listen = 1; + host_card[4] = throw[tflag - 1]; + tflag--; + print_Sign(11, (tflagB - 1) * 4); /* ¦L¾ßµP²Å¸¹ */ + xx = i; /* ¬ö¿ý¤Un¥áªº¨º±iµP */ + pickup = 1; + break; /* ¸õ¥X i loop */ + } + } + } + + for (i = 0; i < 4; i++) + tmp[i] = host_card[i]; + if (testlisten(tmp) && !pickup) + { /* ¦³Å¥¥Bèè¨S¾ß */ + m = 0; + for (i = 0; i < 4; i++) + if (cnum[tmp[i]] == 7) + m++; + if (m == 2 && cnum[throw[tflag - 1]] == 7) + pickup = 1; + if (m == 3 && cnum[throw[tflag - 1]] == 7) + { + pickup = 1; + for (i = 0; i < tflag - 1; i++) + if (cnum[throw[i]] == 7) + pickup = 0; + } + m = 0; + for (i = 0; i < 4; i++) + if (cnum[tmp[i]] == 14) + m++; + if (m == 2 && cnum[throw[tflag - 1]] == 14) + pickup = 1; + if (m == 3 && cnum[throw[tflag - 1]] == 14) + { + pickup = 1; + for (i = 0; i < tflag - 1; i++) + if (cnum[throw[i]] == 14) + pickup = 0; + } + if (pickup) + { + host_card[4] = throw[tflag - 1]; + tflag--; + print_Sign(11, (tflagB - 1) * 4); /* ¦L¾ßµP²Å¸¹ */ + } + } + + + if (!pickup) + { + host_card[4] = chesslist[flag]; + flag++; + } + /* èè¨S¾ßµP²{¦b´NºNµP */ + Phost5(); + Chost5(); + + if (!pickup) + { + for (i = 0; i < 4; i++) + { + k = 0; + for (j = 0; j < 4; j++) + { + if (i != j) + { + tmp[k] = host_card[j]; + k++; + } + } + tmp[3] = host_card[4]; + if (testlisten(tmp)) + { /* ºNµP¦³Å¥ªº¸Ü */ + listen = 1; + xx = i; /* ¬ö¿ý¤Un¥áªº¨º±iµP */ + break; /* ¸õ¥X i loop */ + } + } + } + + for (i = 0; i < 4; i++) + tmp[i] = host_card[i]; + + xx = any_throw(); + + throw[tflag] = host_card[xx]; + tflag++; + tflagA++; + host_card[xx] = host_card[4]; /* ¥á¥X¨SÅ¥¨º±i */ + print_Schess(throw[tflag - 1], 8, (tflagA - 1) * 4); + + pickup = 0; + listen = 0; + + } /* for °j°éµ²§ô */ + +next_game: + vmsg(msg); + + } /* while °j°éµ²§ô */ + +abort_game: + return 0; +} +#endif /* HAVE_GAME */ diff --git a/game/dice.c b/game/dice.c new file mode 100644 index 0000000..3bd949a --- /dev/null +++ b/game/dice.c @@ -0,0 +1,178 @@ +/*-------------------------------------------------------*/ +/* dice.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ÂY»ë¤l¹CÀ¸ */ +/* create : 01/02/15 */ +/* update : 01/04/20 */ +/* author : wsyfish */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + + +static char *pic[6][3] = +{ + " ", + " ¡´ ", /* 1 */ + " ", + + " ¡´ ", + " ", /* 2 */ + " ¡´ ", + + "¡´ ", + " ¡´ ", /* 3 */ + " ¡´", + + "¡´ ¡´", + " ", /* 4 */ + "¡´ ¡´", + + "¡´ ¡´", + " ¡´ ", /* 5 */ + "¡´ ¡´", + + "¡´ ¡´", + "¡´ ¡´", /* 6 */ + "¡´ ¡´" +}; + + +static void +out_song() +{ + static int count = 0; + + /* ¶O¥É²M£»¶}¤@®°¤ßµ¡ */ + uschar *msg[11] = + { + "¶}¤@®°¤ßµ¡ ¼µÛ¹Úªº¯Í»H¸µ¾", + "ÂàÀþ¶¡´N¯à¨ì¹F", + "¶}¤@®°¤ßµ¡ ¤£n¦b¶Â·t¤¤·K´a", + "´§§O¤FµhW¤ß»Ä", + "Åý¥Í¬¡±q¦¹¹L±o²³æ ³¬¤W²´·ú´N¥i¥H·Q¹³", + "¾C¹CµLÃäµL»Ú¯EÃv®ü¬v ¬Ý¨£ÂŤѤ£¦A°g±¦", + "n¦h«º¦h±m¦Û¥Ñ©b©ñ", + "¶§¥ú »´»´¦a¶}¤@®°¤ßµ¡", + "¥^¥^¦a±a§Ų́«¥X¶Â·t ¾ãÓ¥@¬É³£ÀéÄê½÷·×", + "¶§¥ú »´»´¦a¶}¤@®°¤ßµ¡", + "¬X¬X¦a°{Ä£µÛ¬üÄR¹Ú·Q ©Ò¦³Åw¼ÖÄ@»P§A¤À¨É" + }; + move(b_lines - 2, 0); + prints("\033[1;3%dm%s\033[m Äw½XÁÙ¦³ %d ¤¸", time(0) % 7, msg[count], cuser.money); + clrtoeol(); + if (++count == 11) + count = 0; +} + + +int +main_dice() +{ + int money; /* ©ãª÷ */ + int i; /* ¶Ã¼Æ */ + char choice; /* °O¿ý¿ï¶µ */ + char dice[3]; /* ¤TÓ»ë¤lªºÈ */ + char total; /* ¤TÓ»ë¤lªº©M */ + char buf[60]; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + vs_bar("£££¸ £t£« £{£« ¤Uª`"); + outs("\n\n\n" + "¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\n" + "¢x 2¿ 1. ¤j 2. ¤p ¢x\n" + "¢x 14¿ 3. ¤TÂI 4. ¥|ÂI 5. ¤ÂI 6. ¤»ÂI 7. ¤CÂI ¢x\n" + "¢x 8¿ 8. ¤KÂI 9. ¤EÂI 10. ¤QÂI 11. ¤Q¤@ÂI 12. ¤Q¤GÂI 13. ¤Q¤TÂI¢x\n" + "¢x 14¿ 14. ¤Q¥|ÂI 15. ¤Q¤ÂI 16. ¤Q¤»ÂI 17. ¤Q¤CÂI 18. ¤Q¤KÂI ¢x\n" + "¢x216¿ 19. ¤@¤@¤@ 20. ¤G¤G¤G 21. ¤T¤T¤T 22. ¥|¥|¥| 23. ¤¤¤ 24. ¤»¤»¤»¢x\n" + "¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\n"); + +#if 0 /* ÂY»ë¤l¨C 216 ¦¸¦UÁ`¼Æ¥X²{ªº¦¸¼Æ¾÷²v */ +¢z¢w¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢{ +¢xÁ`¼Æ¢x3 ¢x4 ¢x5 ¢x6 ¢x7 ¢x8 ¢x9 ¢x10¢x11¢x12¢x13¢x14¢x15¢x16¢x17¢x18¢x +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x¦¸¼Æ¢x1 ¢x3 ¢x6 ¢x10¢x15¢x21¢x25¢x27¢x27¢x25¢x21¢x15¢x10¢x6 ¢x3 ¢x1 ¢x / 216 ¦¸ +¢|¢w¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢} +#endif + + out_song(0); + + while (1) + { + vget(2, 0, "½Ð°Ýn¤Uª`¦h¤Ö©O¡H(1 ~ 50000) ", buf, 6, DOECHO); + money = atoi(buf); + if (money < 1 || money > 50000 || money > cuser.money) + break; /* Â÷¶}½ä³õ */ + + vget(12, 0, "n©ãþ¤@¶µ©O¡H(½Ð¿é¤J¸¹½X) ", buf, 3, DOECHO); + choice = atoi(buf); + if (choice < 1 || choice > 24) + break; /* Â÷¶}½ä³õ */ + + outs("\n«ö¥ô¤@ÁäÂY¥X»ë¤l \033[5m....\033[m\n"); + igetch(); + + /* ¨M©w¤TÓ»ë¤lÂI¼Æ */ + total = 0; + for (i = 0; i < 3; i++) + { + dice[i] = rnd(6) + 1; + total += dice[i]; + } + + /* ³B²zµ²ªG */ + if ((choice == 1 && total > 10) || (choice == 2 && total <= 10)) /* ³B²z¤j¤p */ + { + sprintf(buf, "¤¤¤F¡I±o¨ì¢±¿¼úª÷ %d ¤¸", money * 2); + addmoney(money); + } + else if (choice <= 18 && total == choice) /* ³B²zÁ`©M */ + { + if (choice >= 8 && choice <= 13) + { + sprintf(buf, "¤¤¤F¡I±o¨ì¢·¿¼úª÷ %d ¤¸", money * 8); + addmoney(money * 7); + } + else + { + sprintf(buf, "¤¤¤F¡I±o¨ì¢°¢³¿¼úª÷ %d ¤¸", money * 14); + addmoney(money * 13); + } + } + else if ((choice - 18) == dice[0] && (dice[0] == dice[1]) && (dice[1] == dice[2]))/* ³B²z¤TÓ¤@¼Ë */ + { + sprintf(buf, "¤¤¤F¡I±o¨ì¢±¢°¢µ¿¼úª÷ %d ¤¸", money * 216); + addmoney(money * 215); + } + else /* ³B²z¨S¤¤ */ + { + strcpy(buf, "«Ü¥i±¤¨S¦³©ã¤¤¡I"); + cuser.money -= money; + } + + /* ¦L¥X»ë¤lµ²ªG */ + outs("¢~¢w¢w¢w¢w¢¡¢~¢w¢w¢w¢w¢¡¢~¢w¢w¢w¢w¢¡\n"); + for (i = 0; i < 3; i++) + { + prints("¢x%s¢x¢x%s¢x¢x%s¢x\n", pic[dice[0] - 1][i], + pic[dice[1] - 1][i], pic[dice[2] - 1][i]); + } + outs("¢¢¢w¢w¢w¢w¢£¢¢¢w¢w¢w¢w¢£¢¢¢w¢w¢w¢w¢£\n\n"); + + out_song(); + vmsg(buf); + } + + return 0; +} + +#endif /* HAVE_GAME */ diff --git a/game/dict.c b/game/dict.c new file mode 100644 index 0000000..1732c80 --- /dev/null +++ b/game/dict.c @@ -0,0 +1,338 @@ +/*-------------------------------------------------------*/ +/* target : Yahoo ½u¤W¦r¨å */ +/* create : 01/07/09 */ +/* update : 06/01/16 */ +/* author : statue.bbs@bbs.yzu.edu.tw */ +/* change : kyo@cszone.tw */ +/*-------------------------------------------------------*/ + +#if 0 + + ´¶³q + http://tw.dictionary.yahoo.com/search?ei=big5&p=hello + + ¦P¸q¦r/¤Ï¸q¦r + http://tw.dictionary.yahoo.com/search?ei=big5&p=hello&type=t + + ÅܤƧΠ+ http://tw.dictionary.yahoo.com/search?ei=big5&p=hello&type=v + +#endif + + +#include "bbs.h" + +#ifdef HAVE_NETTOOL + +#define mouts(y,x,s) { move(y, x); outs(s); } + +#define HTTP_PORT 80 +#define SERVER_yahoo "tw.dictionary.yahoo.com" +#define CGI_yahoo "/search?ei=big5&p=" +#define CGI_yahoo2 "&type=" +#define REF "http://tw.dictionary.yahoo.com/" +#define Dict_Name "Yahoo! ½u¤W¦r¨å" + +static void +url_encode(dst, src) /* URL encoding */ + uschar *dst; /* Thor.990331: n src ªº¤T¿ªÅ¶¡ */ + uschar *src; +{ + for (; *src; src++) + { + if (*src == ' ') + *dst++ = '+'; + else if (is_alnum(*src)) + *dst++ = *src; + else + { + register cc = *src; + *dst++ = '%'; + *dst++ = radix32[cc >> 4]; + *dst++ = radix32[cc & 0xf]; + } + } + *dst = '\0'; +} + + +static int +write_file(type, sockfd, fp, ftmp) + char type; + int sockfd; + FILE *fp; + char *ftmp; +{ + static char pool[2048]; + int cc, i, j, fsize; + char *xhead, *fimage; + int show, start_show; + int space; /* ¦b html ¤¤¡A³sÄòªº space ¥u·|ºâ¤@¦¸ */ + + char *start_str[] = + { + "d", "<div class=pcixin>", + "d", "<div class=chinese>", + "t", "<h4>", + "v", "<h4>", + NULL + }; + + char *stop_str[] = + { + "d", "</h2>", + "A", "<h4>", + "A", "</blockquote>", + NULL + }; + + char *newline_str[] = /* ¨ú¥N´«¦æ¦r¤¸ªº²Å¸¹ */ + { + "<br>", + "</div>", + "</li>", + NULL + }; + + char *other_str[] = /* ¨ä¥L¦r¤¸²Å¸¹ */ + { + "A", " ", " ", + "d", "<li><div class=pexplain>", "\033[m\n \033[1;33m£»\033[32m", + "d", "<li>\n<div class=pexplain>", "\033[m\n \033[1;33m£»\033[32m", + "d", "<li>", "\033[m\n \033[1;33m£»\033[32m", + "d", "<div class=pexplain>", "\033[m\n ", + "d", "<div class=pcixin>", "\033[1;31m", + "d", "<span id=dropdownid>", "\033[m \033[1;37m", + "d", "<div class=ptitle>", "\033[1;36m", + "t", "<div class=ptitle>", "\033[m\n\n\033[1;36m", + "t", "<div class=pexplain>", "\033[m\n", + "v", "<div class=ptitle>", "\033[m\n\n\033[1;36m", + "v", "<div class=pexplain>", "\033[m\n", + NULL + }; + + FILE *fpw; + + fpw = fopen(ftmp, "w"); + + while ((cc = read(sockfd, &pool, sizeof(pool))) > 0) + fwrite(&pool, cc, 1, fpw); + + fclose(fpw); + close(sockfd); + + sprintf(pool, "/usr/local/bin/autob5 -i utf8 -o big5 < %s > %s.big5", + ftmp, ftmp); + system(pool); + unlink(ftmp); + strcat(ftmp, ".big5"); + + fimage = f_map(ftmp, &fsize); + if (fimage == (char *) -1) + { + fclose(fp); + vmsg("¥Ø«eµLªk¶}±Ò Yahoo ½u¤W¦r¨å¼È¦sÀÉ"); + return -1; + } + + /* parser return message from web server */ + show = 1; + start_show = 0; + space = 0; + + for (xhead = fimage; *xhead; xhead++) + { + if (!start_show) + { + for (i = 0; start_str[i] != NULL; i += 2) + { + j = strlen(start_str[i + 1]); + if ((start_str[i][0] == type || start_str[i][0] == 'A') && + str_ncmp(xhead, start_str[i + 1], j) == 0) + { + fputs("\033[m\n\n\033[1;31m", fp); + start_show = 1; + xhead += j; + break; + } + } + } + else if (start_show) + { + for (i = 0; stop_str[i] != NULL; i += 2) + { + j = strlen(stop_str[i + 1]); + if ((stop_str[i][0] == type || stop_str[i][0] == 'A') && + str_ncmp(xhead, stop_str[i + 1], j) == 0) + { + start_show = 0; + xhead += j; + break; + } + } + } + + if (!start_show) + continue; + + for (i = 0; newline_str[i] != NULL; i++) + { + j = strlen(newline_str[i]); + if (str_ncmp(xhead, newline_str[i], j) == 0) + { + fputs("\033[m\n", fp); + xhead += j; + space = 0; + break; + } + } + + + for (i = 0; other_str[i] != NULL; i += 3) + { + j = strlen(other_str[i + 1]); + if ((other_str[i][0] == type || other_str[i][0] == 'A') && + str_ncmp(xhead, other_str[i + 1], j) == 0) + { + fputs(other_str[i + 2], fp); + xhead += j; + space = 0; + break; + } + } + + /* ¼ÐÅÒ²¤¹L */ + + cc = *xhead; + switch(cc) + { + case '<': + show = 0; + continue; + case '>': + show = 1; + continue; + case '\n': + case '\r': + continue; + case ' ': + if (space) + continue; + space = 1; + } + + if (show) + fputc(cc, fp); + + if (cc != ' ') + space = 0; + } + fputc('\n', fp); + + munmap(fimage, fsize); + unlink(ftmp); + + return 1; +} + + +static int +http_conn(server, word, type, s) + char *server; + char *word; + char type; + char *s; +{ + int sockfd; + FILE *fp; + char fname[64], ftmp[64], *str; + + if ((sockfd = dns_open(server, HTTP_PORT)) < 0) + { + vmsg("µLªk»P¦øªA¾¹¨ú±o³sµ²¡A¬d¸ß¥¢±Ñ"); + return 0; + } + else + { + mouts(22, 0, "¥¿¦b³s±µ¦øªA¾¹¡A½Ðµy«á(«ö¥ô·NÁäÂ÷¶})............."); + refresh(); + } + write(sockfd, s, strlen(s)); + shutdown(sockfd, 1); + + sprintf(fname, "tmp/%s.yahoo_dict", cuser.userid); + + fp = fopen(fname, "w"); + sprintf(ftmp, "tmp/%s.yahoo_dict.tmp", cuser.userid); + str = strchr(s + 4, ' '); + + if (str) + *str = '\0'; + + fprintf(fp, "%-24s\033[1;37;44m " Dict_Name " \033[m\n%s\n", + "", msg_seperator); + fprintf(fp, "¸Ó¶³sµ²¡Ghttp://%s%s\n\n", server, s + 4); + fprintf(fp, "%s", word); + + outz("Â^¨ú¸ê®Æ¤¤¡A½Ðµy«á..."); + refresh(); + + if (write_file(type, sockfd, fp, ftmp) >= 0) + fprintf(fp, "\n\n%s\n%-26s\033[1;36;40mYahoo! \033[37m½u¤W¦r¨å\033[m\n", + msg_seperator, ""); + + fclose(fp); + + more(fname, (char *) -1); + unlink(fname); + return 0; +} + + +static void +yahoo_dict(word, type) + char *word; + char type; +{ + char sendform[512]; + char ue_word[90]; + + url_encode(ue_word, word); + + if (type == 'd') + sprintf(sendform, "GET " CGI_yahoo "%s HTTP/1.0\n\n", ue_word); + else + sprintf(sendform, "GET " CGI_yahoo "%s" CGI_yahoo2 "%c HTTP/1.0\n\n", + ue_word, type); + + http_conn(SERVER_yahoo, word, type, sendform); +} + + +int +main_yahoo() +{ + char word[30]; + char *menu[] = {"DD", + "D ÄÀ¸q", + "T ¦P¸q¦r/¤Ï¸q¦r", + "V ÅܤƧÎ", NULL}; + + while (1) + { + clear(); + move(0, 25); + outs("\033[1;37;44m¡· " Dict_Name " ¡·\033[m"); + move(3, 0); + outs("¦¹¦r¨å¨Ó·½¬° " Dict_Name "¡C\n\n"); + outs("ºô§}¡G" REF); + + if (!vget(8, 0, "¬d¸ß¦r·J¡G", word, 30, DOECHO)) + break; + + yahoo_dict(word, pans(-1, -1, "¬d¸ß¿ï¶µ", menu)); + } + + return 0; +} +#endif /* HAVE_NETTOOL */
\ No newline at end of file diff --git a/game/dragon.c b/game/dragon.c new file mode 100644 index 0000000..f029520 --- /dev/null +++ b/game/dragon.c @@ -0,0 +1,315 @@ +/*-------------------------------------------------------*/ +/* dragon.c ( YZU WindTopBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : ±µÀs¹CÀ¸ */ +/* create : 01/01/12 */ +/* update : 03/07/23 */ +/* author : verit.bbs@bbs.yzu.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +static int cards[52]; +static int seven[7]; /* ¨C°ïµP¼[¦UÁÙ¦³´X±iµP */ +static int points[7]; + + +/*-------------------------------------------------------*/ +/* µe¥XµP */ +/*-------------------------------------------------------*/ + + +static void +draw_card(x, y, card) + int x, y; + int card; /* >=0:¦L¥X¾ã±iµP¤Î¦¹±iµPªº¸¹½X -1:¥u¦LµP¥~´ß */ +{ + char flower[4][3] = {"¢Ñ", "¢Ò", "¢Ö", "¢á"}; + char number[13][3] = {"¢Ï", "¢±", "¢²", "¢³", "¢´", "¢µ", "¢¶", "¢·", "¢¸", "¢â", "¢Ø", "¢ß", "¢Ù"}; + + move(x, y); + outs("¢~¢w¢w¢w¢¡"); + + if (card < 0) + return; + + move(x + 1, y); + prints("¢x%s¡@¡@¢x", number[card % 13]); + move(x + 2, y); + prints("¢x%s¡@¡@¢x", flower[card % 4]); + move(x + 3, y); + outs("¢x¡@¡@¡@¢x"); + move(x + 4, y); + outs("¢x¡@¡@¡@¢x"); + move(x + 5, y); + outs("¢¢¢w¢w¢w¢£"); +} + + +/*-------------------------------------------------------*/ +/* ¹CÀ¸»¡©ú */ +/*-------------------------------------------------------*/ + + +static int +draw_explain() +{ + vs_bar("±µÀs¹CÀ¸"); + + move(4, 10); + outs("¡i¹CÀ¸»¡©ú¡j"); + move(6, 15); + outs("(1) ¦b¿Ã¹õ¤W¤è¬°µP¼[¡A¥i¥H§Q¥Î ¡ö¡B¡÷ ¤Á´«¡C"); + move(8, 15); + outs("(2) ¦b¿Ã¹õ¥ª¤U¤è¬°«ùµP , ¥i¥H§Q¥Î c ¤Á´«¡C"); + move(10, 15); + outs("(3) ·íµP¼[ªºµP¬O«ùµPªº¤U¤@±i©Î¤W¤@±i¡A§Y¥i§Q¥Î Enter ¦YµP¡C"); + move(11, 15); + outs(" (¥u¬ÝÂI¼Æ¡A¤£¬Ýªá¦â)"); + move(13, 15); + outs("(4) ·íµP¼[ªºµP³£¦Y§¹¡A¤Î¹CÀ¸Àò³Ó¡C"); + move(15, 15); + outs("(5) ·í«ùµP¤Á´«§¹¥B©|¥¼¦Y§¹µP¼[ªºµP¡A§Y¹CÀ¸¥¢±Ñ¡C"); + vmsg(NULL); +} + + +/*-------------------------------------------------------*/ +/* µe¥X¹CÀ¸µPªº°t¸m */ +/*-------------------------------------------------------*/ + + +static void +draw_screen() +{ + int i, j; + vs_bar("±µÀs¹CÀ¸"); + + for (i = 0; i < 7; i++) + { + for (j = 0; j <= i; j++) + draw_card(4 + j, 5 + i * 10, (i == j) ? cards[i] : -1); + } +} + + +/*-------------------------------------------------------*/ +/* µe¥X´å¼Ð */ +/*-------------------------------------------------------*/ + + +static void +draw_cursor(location, mode) + int location; + int mode; /* 1:¤W¦â 0:²M°£ */ +{ + int x, y; + + x = 8 + seven[location]; + y = 9 + location * 10; + move(x, y); + outs(mode ? "¡´" : "¡@"); + if (mode) + move(x, y + 1); /* Á×§K¦Û°Ê°»´ú¥þ§Î */ +} + + +/*-------------------------------------------------------*/ +/* ²M°£¿Ã¹õ¤WªºµP */ +/*-------------------------------------------------------*/ + + +static void +clear_card(location) + int location; +{ + move(9 + seven[location], 5 + location * 10); + outs(" "); +} + + +/*-------------------------------------------------------*/ +/* ¹CÀ¸°Ñ¼Æªì©l¤Æ */ +/*-------------------------------------------------------*/ + + +static int +init_dragon() +{ + int i, j, num; + + for (i = 0; i < 52; i++) /* µP¥ý¤@±i¤@±i±Æ¦n¡A·Ç³Æ¬~µP */ + cards[i] = i; + + for (i = 0; i < 51; i++) + { + j = rnd(52 - i) + i; + + /* cards[j] ©M cards[i] ¥æ´« */ + num = cards[i]; + cards[i] = cards[j]; + cards[j] = num; + } + + for (i = 0; i < 7; i++) + { + seven[i] = i; + points[i] = cards[i]; + } + + return 0; +} + + +/*-------------------------------------------------------*/ +/* §PÂ_¹CÀ¸¬O§_µ²§ô */ +/*-------------------------------------------------------*/ + + +static int /* 1:¦¨¥\ */ +gameover() +{ + int i; + + for (i = 0; i < 7; i++) + { + if (seven[i] != -1) + return 0; + } + return 1; +} + + +/*-------------------------------------------------------*/ +/* ¹CÀ¸¥Dµ{¦¡ */ +/*-------------------------------------------------------*/ + + +int /* >=0:¦¨¥\ -1:¥¢±Ñ -2:Â÷¶} */ +play_dragon() +{ + int i; + int location = 0; /* ¥Ø«e´å¼Ðªº¦ì¸m */ + int now = 7; /* ¥Ø«e¥Î¨ì cards[] ²Ä´X±iµP */ + int have_card = 22; /* 22 ¦¸´«µP¾÷·| */ + int point; /* ¥Ø«e¤â¤Wªº³o±iµP */ + + clear(); + + draw_screen(); + draw_cursor(location, 1); + point = cards[now]; + draw_card(14, 5, cards[now++]); + move(19, 40); + prints("±zÁÙ¦³ %2d ¦¸¾÷·|¥i¥H´«µP", have_card); + move(b_lines, 0); + outs("¡¹ ¾Þ§@»¡©ú¡G(¡ö)¥ª²¾ (¡÷)¥k²¾ (Enter)¦YµP (c)´«µP (q)Â÷¶}"); + + for (;;) + { + switch (vkey()) + { + case 'c': + if (have_card <= 0) + return -1; + have_card--; + move(19, 47); + prints("%2d", have_card); + point = cards[now]; + draw_card(14, 5, cards[now++]); + break; + + case KEY_RIGHT: + draw_cursor(location, 0); + do + { + location = (location + 1) % 7; + } while (seven[location] == -1); + draw_cursor(location, 1); + break; + + case KEY_LEFT: + draw_cursor(location, 0); + do + { + location = (location == 0) ? 6 : location - 1; + } while (seven[location] == -1); + draw_cursor(location, 1); + break; + + case '\n': + case ' ': + if (points[location] % 13 - point % 13 == 1 || + points[location] % 13 - point % 13 == -1 || + points[location] % 13 - point % 13 == 12 || + points[location] % 13 - point % 13 == -12) + { + point = points[location]; + draw_card(14, 5, point); + clear_card(location); + draw_cursor(location, 0); + seven[location]--; + if (seven[location] >= 0) + { + points[location] = cards[now]; + draw_card(4 + seven[location], 5 + location * 10, cards[now++]); + draw_cursor(location, 1); + } + else + { + for (i = 0; i < 5; i++) + { + move(4 + i, 5 + location * 10); + outs(" "); + } + if (gameover() == 1) + return have_card; + do + { + location = (location + 1) % 7; + } while (seven[location] == -1); + draw_cursor(location, 1); + } + } + break; + + case 'q': + return -2; + } + } +} + + +int +main_dragon() +{ + draw_explain(); + + while (1) + { + init_dragon(); + + switch (play_dragon()) + { + case -1: + vmsg("¬D¾Ô¥¢±Ñ¡I"); + break; + + case -2: + vmsg(MSG_QUITGAME); + return 0; + + default: + vmsg("®¥³ß±z¹LÃö°Õ¡I"); + } + + if (vans("¬O§_nÄ~Äòª±(Y/N)¡H[N] ") != 'y') + break; + } + + return 0; +} +#endif /* HAVE_GAME */ diff --git a/game/fantan.c b/game/fantan.c new file mode 100644 index 0000000..7571ab7 --- /dev/null +++ b/game/fantan.c @@ -0,0 +1,413 @@ +/*-------------------------------------------------------*/ +/* fantan.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ±µÀs¹CÀ¸ */ +/* create : 98/08/04 */ +/* update : 01/03/01 */ +/* author : dsyan.bbs@Forever.twbbs.org */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +enum +{ + SIDE_UP = 1, /* ¦b¤W± */ + SIDE_DOWN = 0 /* ¦b¤U± */ +}; + + +static inline int +cal_kind(card) /* ºâªá¦â */ + int card; +{ + /* card: 1 - 13 ²Ä¡³ºØªá¦â ¡¸ + 14 - 26 ²Ä¤@ºØªá¦â ¡¹ + 27 - 39 ²Ä¤GºØªá¦â ¡³ + 40 - 52 ²Ä¤TºØªá¦â ¡´ */ + + return (card - 1) / 13; +} + + +static inline int +cal_num(card) /* ºâÂI¼Æ */ + int card; +{ + card %= 13; + return card ? card : 13; +} + + +static void +move_cur(a, b, c, d) /* ²¾°Ê½b¸¹ */ + int a, b; /* ì¦ì¸m */ + int c, d; /* ·s¦ì¸m */ +{ + move(a, b); + outs(" "); + move(c, d); + outs("¡÷"); + move(c, d + 1); /* Á×§K¦Û°Ê°»´ú¥þ§Î */ +} + + +static inline int +ycol(y) /* ºâ®y¼Ð */ + int y; +{ + return y * 11 - 8; +} + + +static void +draw(x, y, card) /* µeµP */ + int x, y; + int card; +{ + char kind[4][3] = {"¡¸", "¡¹", "¡³", "¡´"}; /* ªá¦â */ + char num[13][3] = {"¢Ï", "¢±", "¢²", "¢³", "¢´", "¢µ", "¢¶", /* ÂI¼Æ */ + "¢·", "¢¸", "¢â", "¢Ø", "¢ß", "¢Ù"}; + + move(x, y); + + if (card > 0) + prints("¢u%s%s¢t", kind[cal_kind(card)], num[cal_num(card) - 1]); + else if (!card) + outs("¢u¢w¢w¢t"); + else + outs(" "); +} + + +static inline void +out_prompt() /* ´£¥Ü¦r²´ */ +{ + move(b_lines - 1, 0); + outs(COLOR2 " (q)Â÷¶} (r)«ª± (¡ö¡÷¡ô¡õ)²¾°Ê (¡ô)½Âà (Enter)°ïÅ| (Space)«ü©w/²¾°Ê/½µP \033[m"); +} + + +static char +get_newcard(mode) + int mode; /* 0:«·s¬~µP 1:µoµP */ +{ + static char card[52]; /* ³Ì¦h¥u·|¥Î¨ì 52 ±iµP */ + static int now; /* µo¥X²Ä now ±iµP */ + int i, num; + char tmp; + + if (!mode) /* «·s¬~µP */ + { + for (i = 0; i < 52; i++) + card[i] = i + 1; + + for (i = 0; i < 51; i++) + { + num = rnd(52 - i) + i; + + /* card[num] ©M card[i] ¥æ´« */ + tmp = card[i]; + card[i] = card[num]; + card[num] = tmp; + } + + now = 0; + return -1; + } + + tmp = card[now]; + now++; + return tmp; +} + + +int +main_fantan() +{ + char max[9]; /* ¨C°ïªºµP¼Æ¡A²Ä¤K°ï¬O¥ª¤W¨¤ªºµP */ + char rmax[8]; /* ¨C°ï¥¼©|³Q½¶}ªºµP¼Æ */ + + char left_stack[25]; /* ¥ª¤W¨¤ªº 24 ±iµP */ + char up_stack[5]; /* ¥k¤W¨¤ªº 4 ±iµP (¥un°O¿ý³Ì¤jµP§Y¥i) */ + char down_stack[8][21]; /* ¤U±¤CÓ°ïÅ|ªº©Ò¦³µP */ + + int level; /* ¤@¦¸Â½´X±iµP */ + int side; /* ´å¼Ð¦b¤W±ÁÙ¬O¤U± */ + + int cx, cy; /* ¥Ø«e©Ò¦b (x, y) ®y¼Ð */ + int xx, yy; /* ¹L¥h©Ò¦b (x, y) ®y¼Ð */ + int star_c, star_x, star_y; /* ¥´ '*' ³Bªº µP¡B®y¼Ð */ + int left; /* ¥ª¤W¨¤°ïÅ|½¨ì²Ä´X±i */ + + int i, j; + + time_t init_time; /* ¹CÀ¸¶}©lªº®É¶¡ */ + + level = vans("½Ð¿ï¾Ü¤@¦¸Â½ [1~3] ¤@¡ã¤T ±iµP¡A©Î«ö [Q] Â÷¶}¡G"); + if (level > '0' && level < '4') + level -= '0'; + else + return XEASY; + +game_start: + vs_bar("±µÀs"); + out_prompt(); + + side = SIDE_DOWN; + star_c = 0; + star_x = 2; + star_y = 79; + + for (i = 0; i <= 4; i++) /* ¤W±ªº¥|Ó°ïÅ|Âk¹s */ + up_stack[i] = 0; + + get_newcard(0); /* ¬~µP */ + + for (i = 1; i <= 7; i++) + { + max[i] = i; /* ²Ä i °ïè¶}©l¦³ i ±iµP */ + rmax[i] = i - 1; /* ²Ä i °ïè¶}©l¦³ i-1 ±i¥¼¥´¶} */ + for (j = 1; j <= i; j++) + { + down_stack[i][j] = get_newcard(1); /* °t¸m¤U±ªºµP */ + draw(j + 2, ycol(i), i != j ? 0 : down_stack[i][j]); /* ¨C°ï¥´¶}³Ì«á¤@±iµP */ + } + } + + max[8] = 24; /* ¥ª¤W¨¤è¶}©l¦³ 24 ±iµP */ + for (i = 1; i <= 24; i++) + left_stack[i] = get_newcard(1); /* °t¸m¥ª¤W¨¤ªºµP */ + draw(1, 1, 0); + + left = 0; + cx = 1; + cy = 1; + xx = 1; + yy = 1; + + init_time = time(0); /* ¶}©l°O¿ý®É¶¡ */ + + for (;;) + { + if (side == SIDE_DOWN) + { + move_cur(xx + 2, ycol(yy) - 2, cx + 2, ycol(cy) - 2); + xx = cx; + yy = cy; + + switch (vkey()) + { + case 'q': + vmsg(MSG_QUITGAME); + return; + + case 'r': + goto game_start; + + case KEY_LEFT: + cy--; + if (!cy) + cy = 7; + if (cx > max[cy] + 1) + cx = max[cy] + 1; + break; + + case KEY_RIGHT: + cy++; + if (cy == 8) + cy = 1; + if (cx > max[cy] + 1) + cx = max[cy] + 1; + break; + + case KEY_DOWN: + cx++; + if (cx == max[cy] + 2) + cx--; + break; + + case KEY_UP: + cx--; + if (!cx) /* ¶]¨ì¤W±¥h¤F */ + { + side = SIDE_UP; + move_cur(xx + 2, ycol(yy) - 2, 1, 9); + } + break; + + case '\n': /* ®³µP¨ì¥k¤W¨¤ */ + j = down_stack[cy][cx]; + if ((cal_num(j) == up_stack[cal_kind(j)] + 1) && cx == max[cy] && cx > rmax[cy]) + { + up_stack[cal_kind(j)]++; + max[cy]--; + draw(1, cal_kind(j) * 10 + 40, j); + draw(cx + 2, ycol(cy), -1); + if (star_c == j) /* ¦pªG¦³°O¸¹´N®ø±¼ */ + { + move(star_x, star_y); + outc(' '); + } + } + /* ¯}Ãö±ø¥ó: ¥k¤W¨¤¥|Ó³£¬O 13 */ + if (up_stack[0] & up_stack[1] & up_stack[2] & up_stack[3] == 13) + { + char buf[80]; + sprintf(buf, "±zªá¤F %.0lf ¬í ¯}²Ä %d Ãö ¦n±R«ô ^O^", + difftime(time(0), init_time), level); + vmsg(buf); + addmoney(level * 100); + return; + } + break; + + case ' ': + if (cx == max[cy] && cx == rmax[cy]) /* ½·sµP */ + { + rmax[cy]--; + draw(cx + 2, ycol(cy), down_stack[cy][cx]); + break; + } + else if (cx > rmax[cy] && cx <= max[cy]) /* °Å¤U */ + { + move(star_x, star_y); + outc(' '); + star_c = down_stack[cy][cx]; + star_x = cx + 2; + star_y = cy * 11; + move(star_x, star_y); + outc('*'); + break; + } + else if (cx != max[cy] + 1) + break; /* ¶K¤W */ + + if ((max[cy] && (cal_num(down_stack[cy][max[cy]]) == cal_num(star_c) + 1) && + (cal_kind(down_stack[cy][max[cy]]) + cal_kind(star_c)) % 2) || + (max[cy] == 0 && cal_num(star_c) == 13)) + { + if (star_x == 1) /* ±q¤W±¶K¤U¨Óªº */ + { + max[cy]++; + max[8]--; + star_x = 2; + left--; + for (i = left + 1; i <= max[8]; i++) + left_stack[i] = left_stack[i + 1]; + down_stack[cy][max[cy]] = star_c; + draw(max[cy] + 2, ycol(cy), star_c); + move(1, 19); + outc(' '); + draw(1, 11, left ? left_stack[left] : -1); + } + else if (star_x > 2) /* ¦b¤U±¶K¨Ó¶K¥hªº */ + { + int tmp;; + j = star_y / 11; + tmp = max[j]; + for (i = star_x - 2; i <= tmp; i++) + { + max[cy]++; + max[j]--; + down_stack[cy][max[cy]] = down_stack[j][i]; + draw(max[cy] + 2, ycol(cy), down_stack[cy][max[cy]]); + draw(i + 2, ycol(j), -1); + } + move(star_x, star_y); + outc(' '); + star_x = 2; + } + } + break; + } + + } + else /* side == SIDE_UP */ /* ¦b¤W± */ + { + draw(1, 11, left ? left_stack[left] : -1); + + switch (vkey()) + { + case 'q': + vmsg(MSG_QUITGAME); + return; + + case 'r': + goto game_start; + + case '\n': /* ®³µP¨ì¥k¤W¨¤ */ + j = left_stack[left]; + if (cal_num(j) == up_stack[cal_kind(j)] + 1) + { + up_stack[cal_kind(j)]++; + max[8]--; + left--; + draw(1, cal_kind(j) * 10 + 40, j); + + for (i = left + 1; i <= max[8]; i++) + left_stack[i] = left_stack[i + 1]; + + draw(1, 11, left ? left_stack[left] : -1); + + if (star_x == 1) /* ¦pªG¦³°O¸¹´N²M±¼ */ + { + star_x = 2; + move(1, 19); + outc(' '); + } + /* ¯}Ãö±ø¥ó: ¥k¤W¨¤¥|Ó³£¬O 13 */ + if (up_stack[0] & up_stack[1] & up_stack[2] & up_stack[3] == 13) + { + char buf[80]; + sprintf(buf, "±zªá¤F %.0lf ¬í ¯}²Ä %d Ãö ¦n±R«ô ^O^", + difftime(time(0), init_time), level); + vmsg(buf); + } + } + break; + + case KEY_DOWN: + side = SIDE_DOWN; + cx = 1; + move_cur(1, 9, cx + 2, ycol(cy) - 2); + break; + + case KEY_UP: + if (left == max[8]) + left = 0; + else + left += level; /* ¤@¦¸µo level ±iµP */ + if (left > max[8]) + left = max[8]; + + if (star_x == 1) + { + star_x = 2; + move(1, 19); + outc(' '); + } + + draw(1, 1, left == max[8] ? -1 : 0); + break; + + case ' ': + if (left > 0) + { + move(star_x, star_y); + outc(' '); + star_c = left_stack[left]; + star_x = 1; + star_y = 19; + move(1, 19); + outc('*'); + } + break; + } + } + } +} +#endif /* HAVE_GAME */ diff --git a/game/gp.c b/game/gp.c new file mode 100644 index 0000000..fbda59c --- /dev/null +++ b/game/gp.c @@ -0,0 +1,643 @@ +/*-------------------------------------------------------*/ +/* gp.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ª÷¼³§J±ô«¢¹CÀ¸ */ +/* create : 98/10/24 */ +/* update : 01/04/21 */ +/* author : dsyan.bbs@forever.twbbs.org */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + -=== ª÷¼³§J±ô«¢¹CÀ¸ ===- + + 1. ª±ªkÃþ¦ü±ô«¢¡A¸ò¹q¸£¤ñ¤j¡A¥i¥[¿¡I + 2. ¥i¥H±N¼úª÷·í¤U¤@¦¸ªº½äª`¡C + + ¤j¤p¡G + ¦Pªá¶¶¡ÖÅKªK¡Ö¸¬Äª¡Ö¦Pªá¡Ö¶¶¤l¡Ö¤T±ø¡Ö¨ßF¡Ö³æF¡Ö³æ±i + + ¯S®í¥[¤À¡G + ¦Pªá¶¶ ¢°¢´¿ + ¥| ±i ¢°¢¯¿ + ¸¬¡@Ī¡@¡@¢´¿ + +#endif + + +#include "bbs.h" + + +#ifdef HAVE_GAME + +#define MAX_CHEAT 2 /* ¹q¸£§@¹ú¦h´«µP¦¸¼Æ (0:¤£§@¹ú¡A³Ì¦h¥i§@¹ú 6 ¦¸) */ + +static char mycard[5]; /* §Úªº 5 ±iµP */ +static char cpucard[5]; /* ¹q¸£ 5 ±iµP */ + + +static void +out_song() +{ + static int count = 0; + + /* ©PµØ°·£»ªB¤Í */ + uschar *msg[7] = + { + "³o¨Ç¦~ ¤@Ó¤H ·¤]¹L «B¤]¨«", + "¦³¹L²\\ ¦³¹L¿ù ÁÙ°O±o°í«ù¤°»ò", + "¯u·R¹L ¤~·|À´ ·|±I¹æ ·|¦^º", + "²×¦³¹Ú ²×¦³§A ¦b¤ß¤¤", + "ªB¤Í¤@¥Í¤@°_¨« ¨º¨Ç¤é¤l¤£¦A¦³", + "¤@¥y¸Ü ¤@½ú¤l ¤@¥Í±¡ ¤@ªM°s", + "ªB¤Í¤£´¿©t³æ¹L ¤@ÁnªB¤Í§A·|À´" + }; + move(b_lines - 2, 0); + prints("\033[1;3%dm%s\033[m Äw½XÁÙ¦³ %d ¤¸", time(0) % 7, msg[count], cuser.money); + clrtoeol(); + if (++count == 7) + count = 0; +} + + +static void +show_card(isDealer, c, x) + int isDealer; /* 1:¹q¸£ 2:ª±®a */ + char c; /* µP±i */ + int x; /* ²Ä´X±iµP */ +{ + int beginL; + char *suit[4] = {"¢Ñ", "¢Ò", "¢Ö", "¢á"}; + char *num[13] = {"¢Ù", "¢Ï", "¢±", "¢²", "¢³", "¢´", "¢µ", "¢¶", "¢·", "¢¸", "¢â", "¢Ø", "¢ß"}; + + beginL = (isDealer) ? 2 : 12; + move(beginL, x * 4); + outs("¢~¢w¢w¢w¢¡"); + move(beginL + 1, x * 4); + prints("¢x%2s ¢x", num[c % 13]); + move(beginL + 2, x * 4); + prints("¢x%2s ¢x", suit[c / 13]); + move(beginL + 3, x * 4); + outs("¢x ¢x"); + move(beginL + 4, x * 4); + outs("¢x ¢x"); + move(beginL + 5, x * 4); + outs("¢x ¢x"); + move(beginL + 6, x * 4); + outs("¢¢¢w¢w¢w¢£"); +} + + +/* ¦Pªá¶¶¡BÅKªK¡B¸¬¡B¦Pªá¡B¶¶¡B¤T±ø¡B¨ßF¡BF¡B¤@°¦ */ +static void +show_style(my, cpu) + int my, cpu; +{ + char *style[9] = {"¦Pªá¶¶", "¥|±i", "¸¬Äª", "¦Pªá", "¶¶¤l", "¤T±ø", "¨ßF", "³æF", "¤@±i"}; + + move(5, 26); + prints("\033[41;37;1m%s\033[m", style[cpu - 1]); + move(15, 26); + prints("\033[41;37;1m%s\033[m", style[my - 1]); +} + + +static int +card_cmp(a, b) + char *a, *b; +{ + /* 00~12: C, KA23456789TJQ + 13~25: D, KA23456789TJQ + 26~38: H, KA23456789TJQ + 39~51: S, KA23456789TJQ */ + + char c = (*a) % 13; + char d = (*b) % 13; + + if (c == 0) + c = 13; + else if (c == 1) + c = 14; + if (d == 0) + d = 13; + else if (d == 1) + d = 14; + + /* ¥ý¤ñÂI¼Æ¡A¦A¤ñªá¦â */ + if (c == d) + return *a - *b; + return c - d; +} + + +/* a ¬OÂI¼Æ .. b ¬Oªá¦â */ +static void +tran(a, b, c) + char *a, *b, *c; +{ + int i; + for (i = 0; i < 5; i++) + { + a[i] = c[i] % 13; + if (!a[i]) + a[i] = 13; + } + + for (i = 0; i < 5; i++) + b[i] = c[i] / 13; +} + + +static void +check(p, q, r, cc) + char *p, *q, *r, *cc; +{ + char i; + + for (i = 0; i < 13; i++) + p[i] = 0; + for (i = 0; i < 5; i++) + q[i] = 0; + for (i = 0; i < 4; i++) + r[i] = 0; + + for (i = 0; i < 5; i++) + p[cc[i] % 13]++; + + for (i = 0; i < 13; i++) + q[p[i]]++; + + for (i = 0; i < 5; i++) + r[cc[i] / 13]++; +} + + +/* ¦Pªá¶¶¡BÅKªK¡B¸¬¡B¦Pªá¡B¶¶¡B¤T±ø¡B¨ßF¡BF¡B¤@°¦ */ +static int +complex(cc, x, y) + char *cc, *x, *y; +{ + char p[13], q[5], r[4]; + char a[5], b[5], c[5], d[5]; + int i, j, k; + + tran(a, b, cc); + check(p, q, r, cc); + + /* ¦Pªá¶¶ */ + if ((a[0] == a[1] - 1 && a[1] == a[2] - 1 && a[2] == a[3] - 1 && a[3] == a[4] - 1) && + (b[0] == b[1] && b[1] == b[2] && b[2] == b[3] && b[3] == b[4])) + { + *x = a[4]; + *y = b[4]; + return 1; + } + + if (a[4] == 1 && a[0] == 2 && a[1] == 3 && a[2] == 4 && a[3] == 5 && + (b[0] == b[1] && b[1] == b[2] && b[2] == b[3] && b[3] == b[4])) + { + *x = a[3]; + *y = b[4]; + return 1; + } + + if (a[4] == 1 && a[0] == 10 && a[1] == 11 && a[2] == 12 && a[3] == 13 && + (b[0] == b[1] && b[1] == b[2] && b[2] == b[3] && b[3] == b[4])) + { + *x = 1; + *y = b[4]; + return 1; + } + + /* ÅKªK */ + if (q[4] == 1) + { + for (i = 0; i < 13; i++) + { + if (p[i] == 4) + *x = i ? i : 13; + } + return 2; + } + + /* ¸¬Äª */ + if (q[3] == 1 && q[2] == 1) + { + for (i = 0; i < 13; i++) + { + if (p[i] == 3) + *x = i ? i : 13; + } + return 3; + } + + /* ¦Pªá */ + for (i = 0; i < 4; i++) + { + if (r[i] == 5) + { + *x = i; + return 4; + } + } + + /* ¶¶¤l */ + memcpy(c, a, 5); + memcpy(d, b, 5); + for (i = 0; i < 4; i++) + { + for (j = i; j < 5; j++) + { + if (c[i] > c[j]) + { + k = c[i]; + c[i] = c[j]; + c[j] = k; + k = d[i]; + d[i] = d[j]; + d[j] = k; + } + } + } + + if (10 == c[1] && c[1] == c[2] - 1 && c[2] == c[3] - 1 && c[3] == c[4] - 1 && c[0] == 1) + { + *x = 1; + *y = d[0]; + return 5; + } + + if (c[0] == c[1] - 1 && c[1] == c[2] - 1 && c[2] == c[3] - 1 && c[3] == c[4] - 1) + { + *x = c[4]; + *y = d[4]; + return 5; + } + + /* ¤T±ø */ + if (q[3] == 1) + { + for (i = 0; i < 13; i++) + { + if (p[i] == 3) + { + *x = i ? i : 13; + return 6; + } + } + } + + /* ¨ßF */ + if (q[2] == 2) + { + for (*x = 0, i = 0; i < 13; i++) + { + if (p[i] == 2) + { + if ((i > 1 ? i : i + 13) > (*x == 1 ? 14 : *x)) + { + *x = i ? i : 13; + *y = 0; + for (j = 0; j < 5; j++) + { + if (a[j] == i && b[j] > *y) + *y = b[j]; + } + } + } + } + return 7; + } + + /* ³æF */ + if (q[2] == 1) + { + for (i = 0; i < 13; i++) + { + if (p[i] == 2) + { + *x = i ? i : 13; + *y = 0; + for (j = 0; j < 5; j++) + if (a[j] == i && b[j] > *y) + *y = b[j]; + return 8; + } + } + } + + /* ¤@±i */ + *x = 0; + *y = 0; + for (i = 0; i < 5; i++) + { + if ((a[i] = a[i] ? a[i] : 13 > *x || a[i] == 1) && *x != 1) + { + *x = a[i]; + *y = b[i]; + } + } + return 9; +} + + +static int /* <0:ª±®aŵP <-1000:ª±®a¯S®íŵP >0:¹q¸£Ä¹µP */ +gp_win(my, cpu) + int *my, *cpu; /* ¶Ç¦^ª±®a©M¹q¸£ªºµP²Õ */ +{ + int ret; + char myX, myY, cpuX, cpuY; + + *my = complex(mycard, &myX, &myY); + *cpu = complex(cpucard, &cpuX, &cpuY); + + if (*my != *cpu) /* ¦pªGµP«¬¤£¦P¡Aª½±µ¤ñ¸ûµP«¬¤j¤p */ + ret = *my - *cpu; + else if (myX == 1 && cpuX != 1) + ret = -1; + else if (myX != 1 && cpuX == 1) + ret = 1; + else if (myX != cpuX) + ret = cpuX - myX; + else if (myY != cpuY) + ret = cpuY - myY; + + if (ret < 0) /* ¦pªGª±®aŵP */ + { + switch (*my) + { + case 1: /* ¦Pªá¶¶ */ + ret = -1001; + break; + case 2: /* ÅKªK */ + ret = -1002; + break; + case 3: /* ¸¬Äª */ + ret = -1003; + break; + } + } + + return ret; +} + + +static char +get_newcard(mode) + int mode; /* 0:«·s¬~µP 1:µoµP */ +{ + static char card[20 + 5 * MAX_CHEAT]; /* ³Ì¦h¥u·|¥Î¨ì 20+5*MAX_CHEAT ±iµP */ + static int now; /* µo¥X²Ä now ±iµP */ + char num; + int i; + + if (!mode) /* «·s¬~µP */ + { + now = 0; + return -1; + } + +rand_num: /* random ¥X¤@±i©M¤§«e³£¤£¦PªºµP */ + num = rnd(52); + for (i = 0; i < now; i++) + { + if (num == card[i]) /* ³o±iµP¥H«e random ¹L¤F */ + goto rand_num; + } + + card[now] = num; + now++; + + return num; +} + + +static int +cpu_doing() +{ + int my, cpu; + int i, j, k; + char hold[5]; + char p[13], q[5], r[4]; + char a[5], b[5]; + + for (i = 0; i < 5; i++) + { + cpucard[i] = get_newcard(1); + hold[i] = 0; + } + qsort(cpucard, 5, sizeof(char), card_cmp); + for (i = 0; i < 5; i++) + show_card(1, cpucard[i], i); + + tran(a, b, cpucard); + check(p, q, r, cpucard); + + /* Y¦³¯S®íµP«¬¡A«h«O¯d */ + k = 0; /* 1:¦³¯S®íµP«¬ */ + for (j = 0; j < 13; j++) + { + if (p[j] > 1) + { + for (i = 0; i < 5; i++) + { + if (j == cpucard[i] % 13) + { + hold[i] = 1; + k = 1; + } + } + } + } + + for (i = 0; i < 5; i++) + { + /* ¦pªG¨S¦³¯S®íµP«¬¡A¨º»ò«O¯d A¡BK¡A§_«h¥þ³¡¤£«O¯d */ + if (!k && (a[i] == 13 || a[i] == 1)) + hold[i] = 1; + + move(6, i * 4 + 2); + outs(hold[i] ? "«O" : " "); + move(7, i * 4 + 2); + outs(hold[i] ? "¯d" : " "); + } + + vmsg("¹q¸£´«µP«e.."); + + for (j = 0; j < 1 + MAX_CHEAT; j++) /* ´«µP¤@¦¸¡B§@¹ú MAX_CHEAT ¦¸ */ + { + /* ¹q¸£´«µP */ + for (i = 0; i < 5; i++) + { + if (!hold[i]) + cpucard[i] = get_newcard(1); + } + qsort(cpucard, 5, sizeof(char), card_cmp); + + if ((k = gp_win(&my, &cpu)) > 0) /* Y¹q¸£Ä¹¡AÂ÷¶}§@¹ú°j°é */ + break; + } + + for (i = 0; i < 5; i++) + show_card(1, cpucard[i], i); + + show_style(my, cpu); + + return k; +} + + +int +main_gp() +{ + int money; /* À£ª`ª÷ÃB */ + int cont; /* Ä~ÄòÀ£ª`ªº¦¸¼Æ */ + int doub; /* ¬O§_½ä¿ */ + char hold[5]; /* ±ý«O¯dªºµP */ + + char buf[60]; + int i, x, xx; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + cont = 0; /* À£ª`¦¸¼ÆÂk¹s */ + + while (1) + { + vs_bar("ª÷¼³§J±ô«¢"); + out_song(); + + if (!cont) /* ²Ä¤@¦¸À£ª` */ + { + vget(b_lines - 3, 0, "½Ð°Ýn¤Uª`¦h¤Ö©O¡H(1 ~ 50000) ", buf, 6, DOECHO); + money = atoi(buf); + if (money < 1 || money > 50000 || money > cuser.money) + break; /* Â÷¶}½ä³õ */ + cuser.money -= money; + move(b_lines - 4, 0); + prints(COLOR1 " (¡ö)(¡÷)§ïÅÜ¿ïµP (d)Double (SPCAE)§ïÅÜ´«µP (Enter)½T©w \033[m"); + } + else /* Ä~Äò¤W¤@½LĹªº©ãª÷¡A´N¤£¥i¥H¦A double ¤F */ + { + move(b_lines - 4, 0); + prints(COLOR1 " (¡ö)(¡÷)§ïÅÜ¿ïµP (SPCAE)§ïÅÜ´«µP (Enter)½T©w \033[m"); + } + + out_song(); + + get_newcard(0); /* ¬~µP */ + + doub = 0; + for (i = 0; i < 5; i++) + { + mycard[i] = get_newcard(1); + hold[i] = 1; + } + qsort(mycard, 5, sizeof(char), card_cmp); + + for (i = 0; i < 5; i++) + show_card(0, mycard[i], i); + + x = xx = 0; + do + { + for (i = 0; i < 5; i++) + { + move(16, i * 4 + 2); + outs(hold[i] < 0 ? "«O" : " "); + move(17, i * 4 + 2); + outs(hold[i] < 0 ? "¯d" : " "); + } + move(11, xx * 4 + 2); + outs(" "); + move(11, x * 4 + 2); + outs("¡õ"); + move(11, x * 4 + 3); /* Á×§K¥þ§Î°»´ú */ + xx = x; + + switch (i = vkey()) + { + case KEY_LEFT: + x = x ? x - 1 : 4; + break; + + case KEY_RIGHT: + x = (x == 4) ? 0 : x + 1; + break; + + case ' ': + hold[x] *= -1; + break; + + case 'd': + if (!cont && !doub && cuser.money >= money) + { + doub = 1; + cuser.money -= money; + money *= 2; + move(b_lines - 4, 0); + prints(COLOR1 " (¡ö)(¡÷)§ïÅÜ¿ïµP (SPCAE)§ïÅÜ´«µP (Enter)½T©w \033[m"); + out_song(); + } + break; + } + } while (i != '\n'); + + for (i = 0; i < 5; i++) + { + if (hold[i] == 1) + mycard[i] = get_newcard(1); + } + qsort(mycard, 5, sizeof(char), card_cmp); + for (i = 0; i < 5; i++) + show_card(0, mycard[i], i); + move(11, x * 4 + 2); + outs(" "); + + i = cpu_doing(); + + if (i < 0) /* ª±®aŵP */ + { + switch (i) + { + /* ¯S®íµP«¬¦³¯S§Oªº½ß²v */ + case -1001: + money *= 16; + break; + case -1002: + money *= 11; + break; + case -1003: + money *= 6; + break; + default: + money <<= 1; + break; + } + sprintf(buf, "«z¡I¦n´Î³á¡I±o¨ì %d ¤¸«¨ :)", money); + vmsg(buf); + + if (vans("±zn§â¼úª÷Ä~ÄòÀ£ª`¶Ü(Y/N)¡H[N] ") == 'y') + { + cont++; + } + else + { + cont = 0; + addmoney(money); /* ¤@¯ëµP«¬¦hŤ@¿¡A¯S®íµP«¬¦h 15/10/5 ¿ */ + } + } + else /* ¿éµP */ + { + vmsg("¿é¤F..:~~~"); + cont = 0; + } + } + return 0; +} +#endif /* HAVE_GAME */ diff --git a/game/gray.c b/game/gray.c new file mode 100644 index 0000000..21ea4e9 --- /dev/null +++ b/game/gray.c @@ -0,0 +1,785 @@ +/*-------------------------------------------------------*/ +/* gray.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¶Â¥Õ´Ñ¹CÀ¸ */ +/* create : 01/07/24 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +enum +{ + /* GRAY_XPOS + MAP_X n¤p©ó b_lines - 2 = 21 * + * GRAY_YPOS + MAP_Y * 2 n¤p©ó STRLEN - 1 = 79 * + * GRAY_YPOS n¨¬°÷¨Ï out_prompt() ©ñ¤J */ + + GRAY_XPOS = 2, /* ¡õ x ¤è¦V */ + GRAY_YPOS = 17, /* ¡÷ y ¤è¦V */ + + MAP_X = 8, /* n¬O°¸¼Æ */ + MAP_Y = 8, /* n¬O°¸¼Æ */ + + /* These are flags for "map, tile" bitwise operators */ + TILE_BLANK= 0, /* ¨S¦³¼Ð°O */ + TILE_CPU = 1, /* ¹q¸£¾Ö¦³ */ + TILE_USR = 2, /* ª±®a¾Ö¦³ */ + + /* These are flags for "level" bitwise operators */ + LEVEL_USR_FIRST = 1, /* ª±®a¥ý¤U */ + LEVEL_1 = 2, /* ¤@¯Å */ + LEVEL_2 = 4, /* ¤G¯Å */ + LEVEL_3 = 8 /* ¤T¯Å */ +}; + + +static char piece[3][3] = {"¡¼", "¡´", "¡³"}; +static char map[MAP_X][MAP_Y]; /* ¦a¹Ï¤W¨C®æªº¾Ö¦³ªÌ */ +static int cx, cy; /* current (x, y) */ +static int EndGame; /* -1: Â÷¶}¹CÀ¸ 1: ¹CÀ¸µ²§ô 0: ÁÙ¦bª± */ + +#define mouts(x,y,t) { move(GRAY_XPOS + x, GRAY_YPOS + (y) * 2); outs(piece[t]); } + + +/* int count##(x, y, tile) */ +/* ## : ´ú¸Õªº¤è¦V N E W S */ +/* x, y : ©ñ¸mªº (x,y) ®y¼Ð */ +/* tile : ½Ö¤Uªº¤l */ +/* return : ¯à¦Y´X¤l */ + + +static int +countN(x, y, tile) + int x, y; + int tile; +{ + int i; + + for (i = x - 1; i > 0;) + { + if (map[i][y] == TILE_BLANK || map[i][y] & tile) + break; + i--; + } + + if (i != x - 1 && map[i][y] & tile) + return x - i - 1; + return 0; +} + + +static int +countS(x, y, tile) + int x, y; + int tile; +{ + int i; + + for (i = x + 1; i < MAP_X - 1;) + { + if (map[i][y] == TILE_BLANK || map[i][y] & tile) + break; + i++; + } + + if (i != x + 1 && map[i][y] & tile) + return i - x - 1; + return 0; +} + + +static int +countE(x, y, tile) + int x, y; + int tile; +{ + int j; + + for (j = y + 1; j < MAP_Y - 1;) + { + if (map[x][j] == TILE_BLANK || map[x][j] & tile) + break; + j++; + } + + if (j != y + 1 && map[x][j] & tile) + return j - y - 1; + return 0; +} + + +static int +countW(x, y, tile) + int x, y; + int tile; +{ + int j; + + for (j = y - 1; j > 0;) + { + if (map[x][j] == TILE_BLANK || map[x][j] & tile) + break; + j--; + } + + if (j != y - 1 && map[x][j] & tile) + return y - j - 1; + return 0; +} + + +static int +countNE(x, y, tile) + int x, y; + int tile; +{ + int i, j; + + for (i = x - 1, j = y + 1; i > 0 && j < MAP_Y - 1;) + { + if (map[i][j] == TILE_BLANK || map[i][j] & tile) + break; + i--; + j++; + } + + if (i != x - 1 && map[i][j] & tile) + return x - i - 1; + return 0; +} + + +static int +countNW(x, y, tile) + int x, y; + int tile; +{ + int i, j; + + for (i = x - 1, j = y - 1; i > 0 && j > 0;) + { + if (map[i][j] == TILE_BLANK || map[i][j] & tile) + break; + i--; + j--; + } + + if (i != x - 1 && map[i][j] & tile) + return x - i - 1; + return 0; +} + + +static int +countSE(x, y, tile) + int x, y; + int tile; +{ + int i, j; + + for (i = x + 1, j = y + 1; i < MAP_X - 1 && j < MAP_Y - 1;) + { + if (map[i][j] == TILE_BLANK || map[i][j] & tile) + break; + i++; + j++; + } + + if (i != x + 1 && map[i][j] & tile) + return i - x - 1; + return 0; +} + + +static int +countSW(x, y, tile) + int x, y; + int tile; +{ + int i, j; + + for (i = x + 1, j = y - 1; i < MAP_X - 1 && j > 0;) + { + if (map[i][j] == TILE_BLANK || map[i][j] & tile) + break; + i++; + j--; + } + + if (i != x + 1 && map[i][j] & tile) + return i - x - 1; + return 0; +} + + +static int /* Á`¦@¥i¥H¦Y´X¤l 0: ¤£¯à¦Y */ +do_count(x, y, tile) +{ + if (map[x][y] != TILE_BLANK) + return 0; + + return countN(x, y, tile) + countS(x, y, tile) + countE(x, y, tile) + countW(x, y, tile) + + countNE(x, y, tile) + countNW(x, y, tile) + countSE(x, y, tile) + countSW(x, y, tile); +} + + +/* void eat##(x, y, tile, num) */ +/* ## : ±ý¦Yªº¤è¦V N E W S */ +/* x, y : ©ñ¸mªº (x,y) ®y¼Ð */ +/* tile : ½Ö¤Uªº¤l */ +/* num : ¦Y´X¤l */ + + +static inline void +eatN(x, y, tile, num) + int x, y; + int tile; + int num; +{ + int i; + + for (i = x - 1; i >= x - num; i--) + { + map[i][y] = tile; + mouts(i, y, tile); + } +} + + +static inline void +eatS(x, y, tile, num) + int x, y; + int tile; + int num; +{ + int i; + + for (i = x + 1; i <= x + num; i++) + { + map[i][y] = tile; + mouts(i, y, tile); + } +} + + +static inline void +eatE(x, y, tile, num) + int x, y; + int tile; + int num; +{ + int j; + + for (j = y + 1; j <= y + num; j++) + { + map[x][j] = tile; + mouts(x, j, tile); + } +} + + +static inline void +eatW(x, y, tile, num) + int x, y; + int tile; + int num; +{ + int j; + + for (j = y - 1; j >= y - num; j--) + { + map[x][j] = tile; + mouts(x, j, tile); + } +} + + +static inline void +eatNE(x, y, tile, num) + int x, y; + int tile; + int num; +{ + int i, j; + + for (i = x - 1, j = y + 1; i >= x - num; i--, j++) + { + map[i][j] = tile; + mouts(i, j, tile); + } +} + + +static inline void +eatNW(x, y, tile, num) + int x, y; + int tile; + int num; +{ + int i, j; + + for (i = x - 1, j = y - 1; i >= x - num; i--, j--) + { + map[i][j] = tile; + mouts(i, j, tile); + } +} + + +static inline void +eatSE(x, y, tile, num) + int x, y; + int tile; + int num; +{ + int i, j; + + for (i = x + 1, j = y + 1; i <= x + num; i++, j++) + { + map[i][j] = tile; + mouts(i, j, tile); + } +} + + +static inline void +eatSW(x, y, tile, num) + int x, y; + int tile; + int num; +{ + int i, j; + + for (i = x + 1, j = y - 1; i <= x + num; i++, j--) + { + map[i][j] = tile; + mouts(i, j, tile); + } +} + + +static void +do_eat(x, y, tile) +{ + /* ¦Y¦U¤è¦V¯à¦Yªº */ + eatN(x, y, tile, countN(x, y, tile)); + eatS(x, y, tile, countS(x, y, tile)); + eatE(x, y, tile, countE(x, y, tile)); + eatW(x, y, tile, countW(x, y, tile)); + eatNE(x, y, tile, countNE(x, y, tile)); + eatNW(x, y, tile, countNW(x, y, tile)); + eatSE(x, y, tile, countSE(x, y, tile)); + eatSW(x, y, tile, countSW(x, y, tile)); + + /* ¦Y©Ò¤Uªº³o®æ */ + map[x][y] = tile; + mouts(x, y, tile); +} + + +/* µû¤À¨î«×¡A«Ü²Ê²Lªº¤H¤u´¼¼z¡A«Ý§ïµ½ */ + +/* ºâ¯à¦Y¨ì´XÓÃä */ +static int +count_edge(x, y, tile) + int x, y; + int tile; +{ + /* ¥»¨¬OÃä¡A¤~¤]¥i¯à¦Y¨ì¤W¤U©Î¥ª¥kªºÃä */ + if (x == 0 || x == MAP_X - 1) + { + return 1 + countE(x, y, tile) + countW(x, y, tile); /* ¥]¬A¦Û¤v¤@ÓÃä */ + } + if (y == 0 || y == MAP_Y - 1) + { + return 1 + countN(x, y, tile) + countS(x, y, tile); /* ¥]¬A¦Û¤v¤@ÓÃä */ + } + return 0; +} + + +static inline int +find_best(x, y, level) /* ¶Ç¦^ (x, y) ¹q¸£©Ò©ñ¸m³Ì¦nªº¦ì¸m */ + int *x, *y; + int level; +{ + int i, j, bestx, besty, tmp; + int score = 0; + + if (level & LEVEL_1) /* ¤@¯Å: ¦Y¶V¦h¶V¦n */ + { + for (i = 0; i < MAP_X; i++) + { + for (j = 0; j < MAP_Y; j++) + { + if (tmp = do_count(i, j, TILE_CPU)) + { + if (tmp > score) + { + score = tmp; + bestx = i; + besty = j; + } + } + } + } + } + else if (level & LEVEL_2) /* ¤G¯Å: ²¤Æªºª÷¨¤»ÈÃä */ + { + for (i = 0; i < MAP_X; i++) + { + for (j = 0; j < MAP_Y; j++) + { + if (tmp = do_count(i, j, TILE_CPU)) + { + /* ¨¤ +100 Ãä +50 ¤@¯ë +1*/ + if (i == 0 || i == MAP_X - 1) + { + if (j == 0 || j == MAP_Y - 1) + tmp += 100; + else + tmp += 50; + } + else if (j == 0 || j == MAP_Y - 1) + { + tmp += 50; + } + + if (tmp > score) + { + score = tmp; + bestx = i; + besty = j; + } + } + } + } + } + else /* if (level & LEVEL_3) */ /* ¤T¯Å: ª÷¨¤»ÈÃä */ + { + for (i = 0; i < MAP_X; i++) + { + for (j = 0; j < MAP_Y; j++) + { + if (tmp = do_count(i, j, TILE_CPU)) + { + /* ¨¤ +100 ¤@ÓÃä +10 ¤@¯ë +1 */ + if (i == 0 || i == MAP_X - 1) + { + if (j == 0 || j == MAP_Y - 1) + tmp += 100; + else + tmp += 10 * count_edge(i, j, TILE_CPU); + } + else if (j == 0 || j == MAP_Y - 1) + { + tmp += 10 * count_edge(i, j, TILE_CPU); + } + + if (tmp > score) + { + score = tmp; + bestx = i; + besty = j; + } + } + } + } + } + + *x = bestx; + *y = besty; + return score; +} + + +/* ³]©w´Ñ½L */ + +static inline void +init_map() +{ + int i, j; + + for (i = 0; i < MAP_X; i++) + { + for (j = 0; j < MAP_Y; j++) + { + map[i][j] = TILE_BLANK; + } + } + + map[MAP_X / 2 - 1][MAP_Y / 2 - 1] = TILE_CPU; + map[MAP_X / 2][MAP_Y / 2] = TILE_CPU; + map[MAP_X / 2 - 1][MAP_Y / 2] = TILE_USR; + map[MAP_X / 2][MAP_Y / 2 - 1] = TILE_USR; +} + + + +/* ¿Ã¹õ±±¨î */ + +static inline void +out_prompt() +{ + /* ¤£±o¶W¹L GRAY_YPOS¡A§_«h·|¿ù¶Ã */ + move(3, 0); + outs("«öÁ仡©ú¡G"); + move(5, 0); + outs("²¾°Ê ¤è¦VÁä"); + move(6, 0); + outs("¦û»â ªÅ¥ÕÁä"); + move(7, 0); + outs("¦û»â Enter"); + move(8, 0); + outs("Â÷¶} Esc / q"); + move(10, 0); + outs("ª±®a "); + outs(piece[TILE_USR]); + move(11, 0); + outs("¹q¸£ "); + outs(piece[TILE_CPU]); +} + + +static inline void +out_song() +{ + uschar *msg[5] = + { + "¤G°¦¦Ñªê ¤G°¦¦Ñªê", + "¶]±o§Ö ¶]±o§Ö", + "¤@°¦¨S¦³²´·ú", + "¤@°¦¨S¦³§À¤Ú", + "¯u©_©Ç ¯u©_©Ç" + }; + move(b_lines - 2, 0); + prints("\033[1;3%dm%s\033[m", time(0) % 7, msg[time(0) % 5]); + clrtoeol(); +} + + +static inline void +out_map() +{ + int i, j; + + vs_bar("¶Â¥Õ´Ñ"); + + out_prompt(); + out_song(); + + for (i = 0; i < MAP_X; i++) + { + move(GRAY_XPOS + i, GRAY_YPOS); + for (j = 0; j < MAP_Y; j++) + outs(piece[TILE_BLANK]); + } + + mouts(MAP_X / 2 - 1, MAP_Y / 2 - 1, TILE_CPU); + mouts(MAP_X / 2, MAP_Y / 2, TILE_CPU); + mouts(MAP_X / 2 - 1, MAP_Y / 2, TILE_USR); + mouts(MAP_X / 2, MAP_Y / 2 - 1, TILE_USR); + + move(GRAY_XPOS + cx, GRAY_YPOS + cy * 2 + 1); /* move to (0, 0) */ +} + + +/* ¹CÀ¸¥Dµ{¦¡ */ + +static inline void +result(msg) + char *msg; +{ + int i, j; + int sumCPU, sumUSR; + + sumCPU = sumUSR = 0; + for (i = 0; i < MAP_X; i++) + { + for (j = 0; j < MAP_Y; j++) + { + if (map[i][j] & TILE_CPU) + sumCPU++; + else if(map[i][j] & TILE_USR) + sumUSR++; + } + } + + sprintf(msg, "[%s] ª±®a¡G¹q¸£ = %d¡G%d", + (sumUSR > sumCPU) ? "³Ó§Q" : (sumUSR < sumCPU ? "¸¨±Ñ" : "¥¤â"), + sumUSR, sumCPU); +} + + +static inline void +play_gray(level) + int level; +{ + int i, j; + int ch; + int usr_turn; /* 1: ¸Óª±®a 0: ¸Ó¹q¸£ */ + int pass; /* 0: ¨S¦³¤Hpass 1: ¤@Ó¤Hpass 2:³sÄò¤GÓ¤Hpass */ + int bestx, besty; /* ¹q¸£³Ì¨Î¤U¤l³B */ + + pass = 0; + if (!(level & LEVEL_USR_FIRST)) + goto cpu_first; + + while (!EndGame) + { + /* ¥ýºâª±®aÁÙ¦³¨S¦³¤l¥i¥H¤U */ + for (i = 0; i < MAP_X; i++) + { + for (j = 0; j < MAP_Y; j++) + { + if (do_count(i, j, TILE_USR)) + { + usr_turn = 1; + i = MAP_X; /* Â÷¶} for °j°é */ + j = MAP_Y; + } + } + } + + if (!usr_turn) + { + pass++; + + /* Àˬd¬O§_¦³¤G¤H passout */ + if (pass == 2) + { + EndGame = 1; /* ¹CÀ¸µ²§ô */ + return; + } + } + else if (pass) + { + vmsg("¹q¸£µL¤l¥i¤U¡A½ü¨ì±z¤F"); + move(b_lines, 0); + clrtoeol(); /* ®ø±¼ vmsg() */ + } + + while (usr_turn && (ch = vkey())) /* ¸Óª±®a¤U */ + { + switch (ch) + { + case KEY_ESC: + case 'q': + case 'Q': + EndGame = -1; + return; + + case KEY_UP: + if (cx) + { + cx--; + move(GRAY_XPOS + cx, GRAY_YPOS + cy * 2 + 1); + } + break; + + case KEY_DOWN: + if (cx < MAP_X - 1) + { + cx++; + move(GRAY_XPOS + cx, GRAY_YPOS + cy * 2 + 1); + } + break; + + case KEY_LEFT: + if (cy) + { + cy--; + move(GRAY_XPOS + cx, GRAY_YPOS + cy * 2 + 1); + } + break; + + case KEY_RIGHT: + if (cy < MAP_Y - 1) + { + cy++; + move(GRAY_XPOS + cx, GRAY_YPOS + cy * 2 + 1); + } + break; + + case '\n': + case ' ': + if (do_count(cx, cy, TILE_USR)) + { + do_eat(cx, cy, TILE_USR); + usr_turn = 0; + pass = 0; + } + break; + + default: + break; + } + } /* ª±®a¤U while °j°éµ²§ô */ + +cpu_first: + + /* ¸Ó CPU ¤U */ + if (!find_best(&bestx, &besty, level)) + { + pass++; + } + else + { + do_eat(bestx, besty, TILE_CPU); + pass = 0; + cx = bestx; /* ²¾¨ì CPU ©Ò¤Uªº¦ì¸m */ + cy = besty; + } + move(GRAY_XPOS + cx, GRAY_YPOS + cy * 2 + 1); + + /* Àˬd¬O§_¦³¤G¤H passout */ + if (pass == 2) + EndGame = 1; /* ¹CÀ¸µ²§ô */ + + } /* while (!EndGame) °j°éµ²§ô */ +} + + +int +main_gray() +{ + int level; + + level = vans("½Ð¿ï¾Ü [1] ©ö¦p¤Ï´x [2] «D±`²³æ [3] ´¶³qÃø«×¡A©Î«ö [Q] Â÷¶}¡G") - '1'; + if (level >= 0 && level <= 2) + { + level = LEVEL_1 << level; /* ³]©wÃø«× */ + if (vans("ª±®a¥ý¤U¶Ü(Y/N)¡H[Y] ") != 'n') + level |= LEVEL_USR_FIRST; + } + else + { + /* vmsg(MSG_QUITGAME); */ /* itoc.010312: ¤£n¤F */ + return XEASY; + } + + cx = MAP_X / 2 - 1; + cy = MAP_Y / 2 - 1; + EndGame = 0; + + init_map(); + out_map(); + play_gray(level); + + if (EndGame < 0) + { + vmsg(MSG_QUITGAME); + } + else + { + char buf[60]; + result(buf); + vmsg(buf); + } + return 0; +} +#endif /* HAVE_GAME */ diff --git a/game/guessnum.c b/game/guessnum.c new file mode 100644 index 0000000..9b42ed1 --- /dev/null +++ b/game/guessnum.c @@ -0,0 +1,293 @@ +/*-------------------------------------------------------*/ +/* guessnum.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* author : thor.bbs@bbs.cs.nthu.edu.tw */ +/* target : Guess Number tool dynamic link module */ +/* create : 99/02/16 */ +/* update : / / */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#ifdef HAVE_GAME + + +typedef char Num[4]; + +typedef struct +{ + Num n; + int A, B; +} His; + +static int hisNum; +static His *hisList; + +static int numNum; +static char *numSet; + + +static void +AB(p, q, A, B) + Num p, q; + int *A, *B; +{ /* compare p and q, return ?A?B */ + int i, j; + + *A = *B = 0; + for (i = 0; i < 4; i++) + { + for (j = 0; j < 4; j++) + { + if (p[i] == q[j]) + { + if (i == j) + ++*A; + else + ++*B; + } + } + } +} + + +static int +getth(o, a) + int o; + char *a; +{ /* return "o"th element index in a[], base 0 */ + int i = -1; + + o++; + while (o) + { + if (a[++i]) + continue; + else + o--; + } + return i; +} + + +static void +ord2Num(o, p) + int o; + Num p; +{ /* return "o"th filtered number */ + char digit[10]; + int i, j, k; + + memset(digit, 0, sizeof digit); + + for (j = 0, k = 10; j < 4; j++, k--) + { + i = o % k; + o /= k; + i = getth(i, digit); + p[j] = i; + digit[i] = 1; + } +} + + +static int +matchHis(n) + Num n ; +{ + int i, A, B; + + for (i = 0; i < hisNum; i++) + { + AB(n, hisList[i].n, &A, &B); + if (A != hisList[i].A || B != hisList[i].B) + return 0; + } + return 1; +} + + +static void +finish(msg) + char *msg; +{ + free(hisList); + free(numSet); + + vmsg(msg); +} + + +static int +valid_guess(num) + char *num; +{ + const char n0 = num[0]; + const char n1 = num[1]; + const char n2 = num[2]; + const char n3 = num[3]; + + if (n0 >= '0' && n0 <= '9' && n1 >= '0' && n1 <= '9' && + n2 >= '0' && n2 <= '9' && n3 >= '0' && n3 <= '9' && + n0 != n1 && n0 != n2 && n0 != n3 && n1 != n2 && n1 != n3 && n2 != n3) + { + return 1; + } + return 0; +} + + +static int +mainNum(fighting) + int fighting; /* Thor.990317: ¹ï¾Ô¼Ò¦¡ */ +{ + Num myNumber; + + if (vans("·Q¦n±zªº¼Æ¦r¤F¶Ü(Y/N)¡H[N] ") != 'y') + { + /* vmsg(MSG_QUITGAME); */ /* itoc.010312: ¤£n¤F */ + return XEASY; + } + + /* initialize variables */ + + hisList = (His *) malloc(sizeof(His)); /* pseudo */ + numSet = (char *)malloc(10 * 9 * 8 * 7 * sizeof(char)); + + hisNum = 0; + numNum = 10 * 9 * 8 * 7; + memset(numSet, 0, 10 * 9 * 8 * 7 * sizeof(char)); + + /* Thor.990317:¹ï¾Ô¼Ò¦¡ */ + vs_bar(fighting ? "²q¼Æ¦r¤j¾Ô" : "¶Ì¥Ê²q¼Æ¦r"); + + if (fighting) + ord2Num(rnd(numNum), myNumber); /* Thor.990317:¹ï¾Ô¼Ò¦¡ */ + + /* while there is possibility */ + for (;;) + { + Num myGuess, yourGuess; + int youA, youB, myA, myB; + + if (fighting) /* Thor.990317:¹ï¾Ô¼Ò¦¡ */ + { + int i; + char tmp[50]; + vget(b_lines - 3, 0, "±z²q§Úªº¼Æ¦r¬O[????]¡G", tmp, 5, DOECHO); + if (!valid_guess(tmp)) + goto abort_game; + + for (i = 0; i < 4; i++) + yourGuess[i] = tmp[i] - '0'; + AB(myNumber, yourGuess, &myA, &myB); + move(b_lines - 2, 0); + prints("§Ú»¡ \033[1m%dA%dB \033[m", myA, myB); + + if (myA == 4) + { + /* you win */ + finish("±zŤF! ¦n±R«ô ^O^"); + return 0; + } + } + + /* pickup a candidate number */ + for (;;) + { + int i; + /* pickup by random */ + if (numNum <= 0) + goto foolme; + i = rnd(numNum); + i = getth(i, numSet); /* i-th ordering num */ + numSet[i] = 1; + numNum--; /* filtered out */ + ord2Num(i, myGuess); /* convert ordering num to Num */ + + /* check history */ + if (matchHis(myGuess)) + break; + } + + /* show the picked number */ + move(b_lines - 1, 0); + prints("§Ú²q±zªº¼Æ¦r¬O \033[1;37m%d%d%d%d\033[m", myGuess[0], myGuess[1], myGuess[2], myGuess[3]); + + /* get ?A?B */ + for (;;) + { + char buf[5]; + /* get response */ + vget(b_lines, 0, "±zªº¦^µª[?A?B]¡G", buf, 5, DOECHO); + + if (!buf[0]) + { + abort_game: + finish(MSG_QUITGAME); + return 0; + } + if (isdigit(buf[0]) && (buf[1] | 0x20) == 'a' + && isdigit(buf[2]) && (buf[3] | 0x20) == 'b') + { + youA = buf[0] - '0'; + youB = buf[2] - '0'; + /* check legimate */ + if (youA >= 0 && youA <= 4 + && youB >= 0 && youB <= 4 + && youA + youB <= 4) + { + /* if 4A, end the game */ + if (youA == 4) + { + /* I win */ + finish("§ÚŤF! ¼F®`§a ^O^"); + return 0; + } + else + { + break; + } + } + } + /* err A B */ + zmsg("¿é¤J®æ¦¡¦³»~"); + } + /* put in history */ + hisNum++; + hisList = (His *) realloc(hisList, hisNum * sizeof(His)); /* assume must succeeded */ + memcpy(hisList[hisNum - 1].n, myGuess, sizeof(Num)); + hisList[hisNum - 1].A = youA; + hisList[hisNum - 1].B = youB; + + move(hisNum + 2, 0); + if (fighting) /* Thor.990317: ¹ï¾Ô¼Ò¦¡ */ + prints("²Ä \033[1;37m%d\033[m ¦¸, ±z²q \033[1;36m%d%d%d%d\033[m, §Ú»¡ \033[1;33m%dA%dB\033[m; §Ú²q \033[1;33m%d%d%d%d\033[m, ±z»¡ \033[1;36m%dA%dB\033[m", hisNum, yourGuess[0], yourGuess[1], yourGuess[2], yourGuess[3], myA, myB, myGuess[0], myGuess[1], myGuess[2], myGuess[3], youA, youB); + else + prints("²Ä \033[1;37m%d\033[m ¦¸, §Ú²q \033[1;33m%d%d%d%d\033[m, ±z»¡ \033[1;36m%dA%dB\033[m", hisNum, myGuess[0], myGuess[1], myGuess[2], myGuess[3], youA, youB); + } + +foolme: + /* there is no posibility, show "you fool me" */ + finish("±zÄF§Ú¡I¤£¸ò±zª±¤F ~~~>_<~~~"); + + return 0; +} + + +int +guessNum() +{ + mainNum(0); +} + + +int +fightNum() +{ + mainNum(1); +} + +#endif /* HAVE_GAME */ diff --git a/game/km.c b/game/km.c new file mode 100644 index 0000000..0014c99 --- /dev/null +++ b/game/km.c @@ -0,0 +1,532 @@ +/*-------------------------------------------------------*/ +/* km.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : KongMing Chess routines */ +/* create : 01/02/08 */ +/* update : 01/05/09 */ +/* author : einstein@bbs.tnfsh.tn.edu.tw */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#ifdef HAVE_GAME + +#define LOG_KM /* ¬O§_´£¨Ñ°O¿ý´ÑÃЪº¥\¯à */ +#define RETRACT_CHESS /* ¬O§_´£¨Ñ®¬´Ñ¥\¯à */ + + +#if 0 + +´Ñ½L¦b etc/game/km ®æ¦¡¦p¤U¡G + +²Ä¤@¦æ©ñÁ`¦@¦³´X½L´Ñ½L(¤T¦ì¼Æ)¡A±q²Ä¤T¦æ¶}©l«h¬O¤@½L¤@½Lªº´ÑÃСC + +TILE_NOUSE 0 ªí¥Ü¤£¯à²¾°Êªº®æ¤l +TILE_BLANK 1 ªí¥ÜªÅ®æ +TILE_CHESS 2 ªí¥Ü´Ñ¤l + +#123²V¤@¦t¤º +0 0 2 2 2 0 0 +0 0 2 2 2 0 0 +2 2 2 2 2 2 2 +2 2 2 1 2 2 2 +2 2 2 2 2 2 2 +0 0 2 2 2 0 0 +0 0 2 2 2 0 0 + +#endif + + +enum +{ + KM_XPOS = 5, + KM_YPOS = 5, + MAX_X = 7, /* n¬O©_¼Æ */ + MAX_Y = 7, /* n¬O©_¼Æ */ + + /* ¥Î bitwise operators & ¨Ó¨ú¥N == */ + TILE_NOUSE = 0, /* ¤£¯à²¾°Êªº®æ¤l */ + TILE_BLANK = 1, /* ªÅ®æ */ + TILE_CHESS = 2 /* ´Ñ¤l */ +}; + + +static int board[MAX_X][MAX_Y]; +static int cx, cy; +static int stage, NUM_TABLE; +static char piece[4][3] = {"¡@", "¡³", "¡´", "¡¸"}; +static char title[20]; /* ´ÑÃЦWºÙ */ + +#ifdef RETRACT_CHESS +static int route[MAX_X * MAX_Y][4]; /* °O¿ý (fx, fy) -> (tx, ty)¡A®¬´Ñ¨B¼Æ¤£¥i¯à¶W¹L´Ñ½L¤j¤p */ +static int step; +#endif + + +static void +out_song() +{ + /* itoc.µù¸Ñ: ¨C¥y¸Ü³£§Ë¦¨¤@¼Ëªø«×¡A´N¤£¥Î clrtoeol() :p */ + uschar *msg[8] = + { + "±z¤Ó±j¤F¡A´N¬O³o¼Ë¡I", + "±z«ç»ò¥i¯à·Q¨ì³o¤@¨B", + "³o¯u¬O¤Ó¯«©_¤F¡A³Ç§J", + "§Ú¤£ª¾¹D¸Ó»¡¨Ç¤°»ò¤F", + "³o¤@µÛ¯u¬O¤Ñ¤H¤âµ§§r", + "¤Ó¨ØªA±z¤F¡A³o¼Ë¤]¦æ", + "§Ö§¹¦¨¤F¡I¥[ªo¥[ªo¡I", + "¦nªº´ÑÃÐn§i¶D¯¸ªø³á" + }; + move(21, 0); + prints("\033[1;3%dm%s\033[m", time(0) % 7, msg[time(0) % 8]); +} + + +static void +show_board() +{ + int i, j; + + vs_bar("¤Õ©ú´Ñ"); + move(2, KM_YPOS + MAX_Y - 6); /* ¸m¤¤Åã¥Ü´ÑÃЦWºÙ */ + outs(title); + + for (i = 0; i < MAX_X; i++) + { + for (j = 0; j < MAX_Y; j++) + { + move(KM_XPOS + i, KM_YPOS + j * 2); + outs(piece[board[i][j]]); + } + } + + move(3, 40); + outs("¡ô¡õ¡ö¡÷ ¤è¦VÁä"); + move(5, 40); + outs("[Enter] ¿ï¨ú/¤Ï¿ï¨ú"); + move(7, 40); + outs("Q/q Â÷¶}"); + move(9, 40); + outs("h Ū¨ú´ÑÃнd¨Ò"); + +#ifdef RETRACT_CHESS + move(11, 40); + outs("r ®¬´Ñ"); +#endif + + move(13, 40); + outs("¡³ ªÅ¦ì"); + move(14, 40); + outs("¡´ ´Ñ¤l"); + move(15, 40); + outs("¡¸ ¿ï¨ú"); + + out_song(); + move(KM_XPOS + MAX_X / 2, KM_YPOS + MAX_Y / 2 * 2 + 1); /* ¤@¶}©l±N´å¼Ð¸m¤¤ */ +} + + +static int +read_board() +{ + int i, j, count; + FILE *fp; + char buf[40], ans[4]; + + if (!(fp = fopen("etc/game/km", "r"))) + return 0; + + if (stage < 0) /* ²Ä¤@¦¸¶i¤J¹CÀ¸ */ + { + fgets(buf, 4, fp); + NUM_TABLE = atoi(buf); /* etc/game/km ²Ä¤@¦æ°O¿ý´ÑÃÐ¼Æ */ + sprintf(buf, "½Ð¿ï¾Ü½s¸¹ [1-%d]¡A[0] ÀH¾÷¥XÃD¡A©Î«ö [Q] Â÷¶}¡G", NUM_TABLE); + if (vget(b_lines, 0, buf, ans, 4, DOECHO) == 'q') + { + fclose(fp); + return 0; + } + + stage = atoi(ans) - 1; + if (stage < 0 || stage >= NUM_TABLE) /* ÀH¾÷¥XÃD */ + stage = time(0) % NUM_TABLE; + } + + fseek(fp, 4 + stage * (2 * MAX_X * MAX_Y + 14), SEEK_SET); + /* 4: ²Ä¤@¦æªº¤T¦ì¼Æ´ÑÃмƥØ\n 14: \n#999´ÑÃЦWºÙ\n */ + + fscanf(fp, "%s", &title); /* ´ÑÃЦWºÙ */ + + count = 0; + for (i = 0; i < MAX_X; i++) + { + for (j = 0; j < MAX_Y; j++) + { + fscanf(fp, "%d", &board[i][j]); + if (board[i][j] & TILE_CHESS) + { + count++; + } + } + } + fclose(fp); + return count; +} + + +static inline int +valid_pos(x, y) + int x, y; +{ + if (x < 0 || x >= MAX_X || y < 0 || y >= MAX_Y || + board[x][y] == TILE_NOUSE) /* TILE_NOUSE = 0 ¤£¯à¥Î & operation */ + { + return 0; + } + return 1; +} + + +static void +get_pos(x, y) + int *x, *y; +{ + int ch; + while (1) + { + ch = vkey(); + if (ch == KEY_UP && valid_pos(cx - 1, cy)) + { + cx--; + move(KM_XPOS + cx, KM_YPOS + cy * 2 + 1); + } + else if (ch == KEY_DOWN && valid_pos(cx + 1, cy)) + { + cx++; + move(KM_XPOS + cx, KM_YPOS + cy * 2 + 1); + } + else if (ch == KEY_LEFT && valid_pos(cx, cy - 1)) + { + cy--; + move(KM_XPOS + cx, KM_YPOS + cy * 2 + 1); + } + else if (ch == KEY_RIGHT && valid_pos(cx, cy + 1)) + { + cy++; + move(KM_XPOS + cx, KM_YPOS + cy * 2 + 1); + } + else if (ch == 'h') + { + more("etc/game/km.hlp", NULL); + show_board(); + move(KM_XPOS + cx, KM_YPOS + cy * 2 + 1); + } + else if (ch == 'q' || ch == 'Q') + { + vmsg(MSG_QUITGAME); + *x = -1; + break; + } + else if (ch == '\n') + { + *x = cx; + *y = cy; + break; + } +#ifdef RETRACT_CHESS + else if (ch == 'r') + { + *x = -2; + break; + } +#endif + } +} + + +static inline void +jump(fx, fy, tx, ty) + int fx, fy, tx, ty; /* From (fx, fy) To (tx, ty) */ +{ + out_song(); + + board[fx][fy] = TILE_BLANK; + move(KM_XPOS + fx, KM_YPOS + fy * 2); + outs(piece[1]); + + board[(fx + tx) / 2][(fy + ty) / 2] = TILE_BLANK; + move(KM_XPOS + (fx + tx) / 2, KM_YPOS + (fy + ty)); + outs(piece[1]); + + board[tx][ty] = TILE_CHESS; + move(KM_XPOS + tx, KM_YPOS + ty * 2); + outs(piece[2]); + move(KM_XPOS + tx, KM_YPOS + ty * 2 + 1); + +#ifdef RETRACT_CHESS + route[step][0] = fx; + route[step][1] = fy; + route[step][2] = tx; + route[step][3] = ty; + step++; +#endif +} + + +#ifdef RETRACT_CHESS +static inline void +retract() +{ + int fx, fy, tx, ty; + + out_song(); + + step--; + ty = route[step][3]; + tx = route[step][2]; + fy = route[step][1]; + fx = route[step][0]; + + board[tx][ty] = TILE_BLANK; + move(KM_XPOS + tx, KM_YPOS + ty * 2); + outs(piece[1]); + + board[(fx + tx) / 2][(fy + ty) / 2] = TILE_CHESS; + move(KM_XPOS + (fx + tx) / 2, KM_YPOS + (fy + ty)); + outs(piece[2]); + + board[fx][fy] = TILE_CHESS; + move(KM_XPOS + fx, KM_YPOS + fy * 2); + outs(piece[2]); + move(KM_XPOS + fx, KM_YPOS + fy * 2); + cx = fx; + cy = fy; +} +#endif + + +static inline int +check(fx, fy, tx, ty) + int fx, fy, tx, ty; +{ + if ((board[(fx + tx) / 2][(fy + ty) / 2] & TILE_CHESS) && + ((abs(fx - tx) == 2 && fy == ty) || (fx == tx && abs(fy - ty) == 2))) + { + return 1; + } + return 0; +} + + +static inline int +live() +{ + int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1}; + int i, j, k, nx, ny, nx2, ny2; + for (i = 0; i < MAX_X; i++) + { + for (j = 0; j < MAX_Y; j++) + { + for (k = 0; k < 4; k++) + { + nx = i + dir[k][0]; + ny = j + dir[k][1]; + nx2 = nx + dir[k][0]; + ny2 = ny + dir[k][1]; + if (valid_pos(nx2, ny2) && (board[i][j] & TILE_CHESS) && + (board[nx][ny] & TILE_CHESS) && (board[nx2][ny2] & TILE_BLANK)) + { + return 1; + } + } + } + } + return 0; +} + + +#ifdef LOG_KM +static void +log_km(fp) + FILE *fp; +{ + int i, j; + + for (i = 0; i < MAX_X; i++) + { + for (j = 0; j < MAX_Y; j++) + { + fprintf(fp, "%s", piece[board[i][j]]); + } + fprintf(fp, "\n"); + } + fprintf(fp, "\n"); +} +#endif + + +int +main_km() +{ + int fx, fy, tx, ty, count; + +#ifdef LOG_KM + char fpath[64]; + FILE *fp; +#endif + + stage = -1; + +start_game: + + if (!(count = read_board())) + return 0; + +#ifdef LOG_KM + usr_fpath(fpath, cuser.userid, "km.log"); + fp = fopen(fpath, "w"); + fprintf(fp, "%s %s (%s)\n", str_author1, cuser.userid, cuser.username); + fprintf(fp, "¼ÐÃD: ¤Õ©ú´ÑÃÐ %s ¯}¸Ñ¹Lµ{\n®É¶¡: %s\n\n", title, Now()); + fprintf(fp, "%s\n\n", title); + log_km(fp); +#endif + +#ifdef RETRACT_CHESS + step = 0; +#endif + + show_board(); + cx = MAX_X / 2; + cy = MAX_Y / 2; + + while (1) + { + if (count == 1 && board[MAX_X / 2][MAX_Y / 2] & TILE_CHESS) + { /* ³Ì«á¤@¤ln¦b¥¿¤¤¶¡ */ + vmsg("®¥³ß±z¦¨¥\\¤F"); + +#ifdef LOG_KM + ve_banner(fp, 0); + fclose(fp); + + if (vans("±z¬O§_n§â§¹¦¨ªº´ÑÃЫO¦s¦b«H½c¤¤(Y/N)¡H[Y] ") != 'n') + { + char buf[60]; + + sprintf(buf, "¤Õ©ú´ÑÃÐ %s ¯}¸Ñ¹Lµ{", title); + mail_self(fpath, cuser.userid, buf, MAIL_READ); + } + unlink(fpath); +#endif + + switch (vans("½Ð¿ï¾Ü (1)Ä~Äò¤U¤@Ãö (2)«·s¬D¾Ô¦¹Ãö (Q)Â÷¶} ¡H[1] ")) + { + case 'q': + goto abort_game; + case '2': + stage--; + default: + if (++stage >= NUM_TABLE) + stage = 0; + goto start_game; + } + } + if (!live()) + { +#ifdef LOG_KM + unlink(fpath); +#endif + + vmsg("ÁV¿|...¨S´Ñ¤F...@@"); + + switch (vans("½Ð¿ï¾Ü (1)Ä~Äò¤U¤@Ãö (2)«·s¬D¾Ô¦¹Ãö (Q)Â÷¶} ¡H[2] ")) + { + case 'q': + goto abort_game; + case '1': + if (++stage >= NUM_TABLE) + stage = 0; + default: + goto start_game; + } + } + + while (1) /* ²Ä¤@¦¸ */ + { + get_pos(&fx, &fy); + if (fx < 0) + { +#ifdef RETRACT_CHESS + if (fx == -2) + { + if (step) /* ¤@¨B³£ÁÙ¨S¨«¡A¤£¯à®¬´Ñ */ + { + retract(); + count++; +#ifdef LOG_KM + fprintf(fp, "®¬´Ñ¡A¦^¨ì¤W¤@¨B\n"); + log_km(fp); +#endif + } + continue; + } +#endif + goto abort_game; + } + if (!(board[fx][fy] & TILE_CHESS)) + { + continue; + } + else /* ¿ï¤l */ + { + move(KM_XPOS + fx, KM_YPOS + fy * 2); + outs(piece[3]); + move(KM_XPOS + fx, KM_YPOS + fy * 2 + 1); + break; + } + } + + while (1) /* ²Ä¤G¦¸ */ + { + get_pos(&tx, &ty); + if (tx < 0) + { +#ifdef RETRACT_CHESS + if (tx == -2) + { + continue; /* n¨ú®ø¿ï¤l¤~¯à®¬´Ñ */ + } +#endif + goto abort_game; + } + if (fx == tx && fy == ty) /* ©ñ±ó¿ï¤l */ + { + move(KM_XPOS + tx, KM_YPOS + ty * 2); + outs(piece[2]); + move(KM_XPOS + tx, KM_YPOS + ty * 2 + 1); + break; + } + else if (!(board[tx][ty] & TILE_BLANK) || !check(fx, fy, tx, ty)) /* ¿ï¸õªº¦a¤è¤£¯à¸õ */ + { + continue; + } + else /* ¸õ¨ì¸Ó¦a¤è */ + { + jump(fx, fy, tx, ty); + count--; +#ifdef LOG_KM + log_km(fp); +#endif + break; + } + } + } +abort_game: + return 0; +} + +#endif /* HAVE_GAME */ diff --git a/game/liteon.c b/game/liteon.c new file mode 100644 index 0000000..c81b269 --- /dev/null +++ b/game/liteon.c @@ -0,0 +1,216 @@ +/*-------------------------------------------------------*/ +/* liteon.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¶}¿O¹CÀ¸ */ +/* create : 02/05/23 */ +/* update : / / */ +/* author : Gein.bbs@csdc.twbbs.org */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#ifdef HAVE_GAME + +#define MAX_LEVEL (b_lines - 3) + +enum +{ + TL_XPOS = 2, + TL_YPOS = 5, + + /* ¥Î bitwise operators */ + TILE_BLANK = 0, /* ·t°Ï */ + TILE_LIGHT = 1 /* «G°Ï */ +}; + + +static int cx, cy; /* ¥Ø«e©Ò¦b´å¼Ð */ +static int level; /* µ¥¯Å¡A¦P®É¤]¬O board ªºÃäªø */ +static int onturn; /* ¦³´XÓ¿O¥´¶}¤F */ +static int candle; /* ÂI¤F´X¦¸ÄúÀë */ +static int tl_board[T_LINES - 4][T_LINES - 4]; + + +static void +tl_setb() /* set board all 0 */ +{ + int i, j; + + move(1, 0); + clrtobot(); + + for (i = 0; i < level; i++) + { + move(i + TL_XPOS, TL_YPOS); + for (j = 0; j < level; j++) + { + tl_board[i][j] = TILE_BLANK; + outs("¡³"); + } + } + + cx = cy = onturn = candle = 0; + move(TL_XPOS, TL_YPOS + 1); /* move back to (0, 0) */ +} + + +static void +tl_draw(x, y) /* set/reset and draw a tile */ + int x, y; +{ + tl_board[x][y] ^= TILE_LIGHT; + move(x + TL_XPOS, y * 2 + TL_YPOS); + if (tl_board[x][y] == TILE_BLANK) /* on-turn -> off-turn */ + { + onturn--; + outs("¡³"); + } + else /* off-turn -> on-turn */ + { + onturn++; + outs("¡´"); + } +} + + +static void +tl_turn() /* turn light and light arround it */ +{ + tl_draw(cx, cy); + + if (cx > 0) + tl_draw(cx - 1, cy); + + if (cx < level - 1) + tl_draw(cx + 1, cy); + + if (cy > 0) + tl_draw(cx, cy - 1); + + if (cy < level - 1) + tl_draw(cx, cy + 1); +} + + +static void +tl_candle() /* cheat: use candle */ +{ + /* itoc.µù¸Ñ: ¦]¬°¤j®a³£¯}¤£¤F³o¹CÀ¸¡A©Ò¥H´£¨Ñ¤@¤U§@¹ú¥ÎªºÂIÄúÀë */ + tl_draw(cx, cy); + candle++; +} + +static int /* 1:win 0:lose */ +tl_play() /* play turn_light */ +{ + tl_setb(); + + while (onturn != level * level) + { + switch (vkey()) + { + case KEY_LEFT: + cy--; + if (cy < 0) + cy = level - 1; + break; + + case KEY_RIGHT: + cy++; + if (cy == level) + cy = 0; + break; + + case KEY_UP: + cx--; + if (cx < 0) + cx = level - 1; + break; + + case KEY_DOWN: + cx++; + if (cx == level) + cx = 0; + break; + + case 'c': + tl_candle(); + break; + + case ' ': + case '\n': + tl_turn(); + break; + + case 'r': + tl_setb(); + break; + + case 'q': + return 0; + } + move(cx + TL_XPOS, cy * 2 + TL_YPOS + 1); /* move back to current (x, y) */ + } + return 1; +} + + +int +main_liteon() +{ + char ans[5], buf[80]; + + sprintf(buf, "½Ð¿ï¾Üµ¥¯Å(1¡ã%d)¡A©Î«ö [Q] Â÷¶}¡G", MAX_LEVEL); + level = vget(b_lines, 0, buf, ans, 3, DOECHO); + if (level == 'q' || level == 'Q') + { + return XEASY; + } + else + { + level = atoi(ans); + if (level < 1 || level > MAX_LEVEL) + return XEASY; + } + + vs_bar("¶}¿O¹CÀ¸"); + move(4, 13); + outs("«e±¡´£n¡G"); + move(5, 15); + outs("¦³¤@¤Ñ¡A¤p«Ø¦^¨ì®aµo²{¿O³£³QÃö¤F¡C"); + move(6, 15); + outs("¥i¬O¥L®aªº¿O¦³¤@Ó¯S©Ê¡A¨º´N¬O¡G"); + move(7, 15); + outs("·í¤@·ø¿O³Q«ö¤U¶}Ãö¥H«á¡A¥L©P³òªº¿O"); + move(8, 15); + outs("쥻«Gªº¡A´N·|ÅÜ·t¡A쥻·tªº¡A´N·|ÅÜ«G¡C -____-#"); + move(9, 15); + outs("²{¦b´N½ÐÁo©úªº±zÀ°¥L§â©Ò¦³¿O¥´¶}§a¡I"); + + move(11, 13); + outs("«öÁ仡©ú¡G"); + move(12, 15); + outs("¡ô¡õ¡ö¡÷ ²¾°Ê¤è¦V"); + move(13, 15); + outs("Enter/Space ¤Á´«¶}Ãö"); + move(14, 15); + outs("c ÂI¿UÄúÀë [±K§Þ]"); + move(15, 15); + outs("r «·s¨Ó¹L"); + move(16, 15); + outs("q Â÷¶}¹CÀ¸"); + + vmsg(NULL); + + if (tl_play()) /* if win */ + { + sprintf(buf, "®¥³ß±z¦¨¥\\¤F (¥Î¤F %d ®ÚÄúÀë)", candle); + vmsg(buf); + } + + return 0; +} +#endif /* HAVE_GAME */ diff --git a/game/marie.c b/game/marie.c new file mode 100644 index 0000000..8ffbb4b --- /dev/null +++ b/game/marie.c @@ -0,0 +1,189 @@ +/*-------------------------------------------------------*/ +/* marie.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¤pº¿²ú¼Ö¶é¹CÀ¸ */ +/* create : / / */ +/* update : 01/04/26 */ +/* author : unknown */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#define MAX_MARIEBET 50000 /* ³Ì¦h©ã¨ì 50000 ¤¸ */ + + +static inline int +get_item() /* ¶Ã¼Æ¿ï¨ún¤¤ªº¶µ¥Ø */ +{ + +#if 0 +½s¸¹¡G 0 1 2 3 4 5 6 7 8 9 +¾÷²v¡G 200 2 5 10 1 20 40 100 500 122 /1000 +½ß²v¡G 5 500 200 100 1000 50 25 10 2 0 +#endif + + int randnum = rnd(1000); /* ½ß²v * ¾÷²v = ´Á±æÈ (¨C©ã 1 ¤¸©Ò¦^¦¬ªºª÷ÃB) */ + + if (randnum < 500) /* 2 * 0.500 = 1 */ + return 8; + if (randnum < 700) /* 5 * 0.200 = 1 */ + return 0; + if (randnum < 800) /* 10 * 0.100 = 1 */ + return 7; + if (randnum < 840) /* 25 * 0.040 = 1 */ + return 6; + if (randnum < 860) /* 50 * 0.020 = 1 */ + return 5; + if (randnum < 870) /* 100 * 0.010 = 1 */ + return 3; + if (randnum < 875) /* 200 * 0.005 = 1 */ + return 2; + if (randnum < 877) /* 500 * 0.002 = 1 */ + return 1; + if (randnum < 878) /* 1000 * 0.001 = 1 */ + return 4; + + return 9; /* »ÊÁ´fÅU¾÷²v¬O 0.122 */ +} + + +int +main_marie() +{ + int c_flag[7] = {1, 5, 10, 50, 100, 500, 1000}; /* ¿²v */ + int price[10] = {5, 500, 200, 100, 1000, 50, 25, 10, 2, 0}; /* ½ä²v */ + int x[9] = {0}; /* ¦U¶µ©ãª÷ */ + + int w; /* ¿²vªººØÃþ */ + int flag; /* flag = c_flag[w] */ + int item; /* ¤¤¼úªº¶µ¥Ø */ + int xtotal; /* Á`©ãª÷ */ + int i, ch; + FILE *fp; + char buf[STRLEN]; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + if (!(fp = fopen("etc/game/marie", "r"))) + return XEASY; + + vs_bar("¤pº¿²ú¼Ö¶é"); + move(1, 0); + while (fgets(buf, STRLEN, fp)) /* ¦L¥X½ä³õ¤º³¡Â\³] */ + outs(buf); + fclose(fp); + + w = 0; /* ²Ä¤@¦¸¶i¤J¿ï¾Ü¤@¿¡A²Ä¤G¦¸¥H«á«h¸ò¤W¦¸ª±¤@¼Ë */ + flag = c_flag[w]; + item = 0; + xtotal = 0; + + while (1) + { + move(9, 44); + prints("\033[1m±z¨¤WÁÙ¦³Äw½X %8d ¤¸\033[m", cuser.money); + move(10, 44); + prints("\033[1m¥Ø«e©ãª`ªº¿²v¬O \033[46m%6d ¿\033[m", flag); + + move(b_lines - 3, 0); + for (i = 0; i < 9; i++) + prints(" %5d", x[i]); + + ch = igetch(); /* ¤£»Ý¥Î¨ì vkey() */ + switch (ch) + { + case 'w': /* ¤Á´«¿²v */ + w = (w + 1) % 7; + flag = c_flag[w]; /* ¤Á´«¿²v®É¤~»Ýn«³] flag */ + break; + + case 'a': /* ¥þÀ£ */ + i = 9 * flag; + if ((xtotal + i <= MAX_MARIEBET) && (cuser.money >= i)) + { + cuser.money -= i; + xtotal += i; + for (i = 0; i <= 8; i++) + x[i] += flag; + } + break; + + case '1': /* ¤À§O¤Uª` */ + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if ((xtotal + flag <= MAX_MARIEBET) && (cuser.money >= flag)) + { + cuser.money -= flag; + xtotal += flag; + x[ch - '1'] += flag; + } + break; + + case 's': /* ¶}©l¹CÀ¸ */ + case '\n': + if (x[0] || x[1] || x[2] || x[3] || x[4] || x[5] || x[6] || x[7] || x[8]) + { /* ¦³¤Uª`¤~¯à¶}©lª± */ + move(15, 5 + 7 * item); + outs(" "); /* ²M°£¤W¦¸¤¤ªº¶µ¥Ø */ + item = get_item(); + if (item != 9) /* item=9 ¬O»ÊÁ´fÅU */ + { + move(15, 5 + 7 * item); + outs("¡´"); /* ø¤W³o¦¸¤¤ªº¶µ¥Ø */ + + if (x[item]) + { + i = x[item] * price[item]; + addmoney(i); + sprintf(buf, "±z¥i±o %d ¤¸", i); + vmsg(buf); + } + else + { + vmsg("«Ü©êºp¡A±z¨S¦³©ã¤¤"); + } + } + else + { + vmsg("«Ü©êºp¡A»ÊÁ´fÅU"); + } + + move(b_lines, 0); + clrtoeol(); /* ²M°£ vmsg() */ + + /* ¦U¶µ½äª÷Âk¹s */ + xtotal = 0; + for (i = 0; i < 9; i++) + x[i] = 0; + } + else + { + goto abort_game; + } + break; + + case 'q': /* Â÷¶} */ + goto abort_game; + + } /* switch µ²§ô */ + + } /* while °j°éµ²§ô */ + +abort_game: + return 0; +} +#endif /* HAVE_GAME */ diff --git a/game/mine.c b/game/mine.c new file mode 100644 index 0000000..550f85e --- /dev/null +++ b/game/mine.c @@ -0,0 +1,474 @@ +/*-------------------------------------------------------*/ +/* mine.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ½ò¦a¹p¹CÀ¸ */ +/* create : 01/02/15 */ +/* update : 01/03/01 */ +/* author : piaip.bbs@sob.twbbs.org */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#define _CHINESE_ /* ¤¤¤å¦r symbol */ + +enum +{ + /* MINE_XPOS + MAP_MAX_X n¤p©ó b_lines - 2 = 21 * + * MINE_YPOS + MAP_MAX_Y * 2 n¤p©ó STRLEN - 1 = 79 * + * MINE_YPOS n¨¬°÷¨Ï out_prompt() ©ñ¤J */ + + MINE_XPOS = 0, + MINE_YPOS = 17, + MAP_MAX_X = 20, /* ¡õ x ¤è¦V */ + MAP_MAX_Y = 30, /* ¡÷ y ¤è¦V */ + + /* These are flags for bitwise operators */ + TILE_BLANK = 0, /* ¨S¦³¦a¹p */ + TILE_MINE = 1, /* ¦³¦a¹p */ + TILE_TAGGED = 0x10, /* ³Q¼Ð°O */ + TILE_EXPAND = 0x20 /* ¤w³Q®i¶} */ +}; + + +static char MineMap[MAP_MAX_X + 2][MAP_MAX_Y + 2]; /* ¦a¹Ï¤W¨C®æªºÄÝ©Ê */ +static char MineNei[MAP_MAX_X + 2][MAP_MAX_Y + 2]; /* ¦a¹Ï¤W¨C®æ¾F©~¦³¦h¤Ö¦a¹p */ + +static int MAP_X, MAP_Y; /* ´Ñ½L¤j¤p */ +static int cx, cy; /* current (x, y) */ +static int TotalMines; /* ¤w¼Ð°Oªº¦a¹p¼Æ */ +static int TaggedMines; /* ¤w¼Ð°Oªº¦a¹p¼Æ */ +static time_t InitTime; /* ¶}©lª±ªº®É¶¡ */ +static int LoseGame; /* 1: ¿é¤F 0: ÁÙ¦bª± */ +static int EndGame; /* 1: Â÷¶}¹CÀ¸ 0: ÁÙ¦bª± */ + + +#ifdef _CHINESE_ +static char symTag[3] = "¡°"; /* ¼Ð°O¦a¹p/¦¹³B¦³¦a¹p¥B¦³³Q¼Ð¥Ü */ +static char symMine[3] = "¡ó"; /* /¦¹³B¦³¦a¹p¦ý¨S³Q¼Ð¥Ü */ +static char symWrong[3] = "¢æ"; /* /¦¹³B¨S¦a¹p¦ý¦³³Q¼Ð¥Ü */ +static char symBlank[3] = "¡½"; /* ¥¼³Q®i¶}/¦¹³B¨S¦a¹p¥B¨S³Q®i¶} */ +static char *strMines[9] = {"¡@", "¢°", "¢±", "¢²", "¢³", "¢´", "¢µ", "¢¶", "¢·"}; /* ®ÇÃ䦳´XÁû¦a¹p */ +#else +static char symTag[3] = " M"; +static char symMine[3] = " m"; +static char symWrong[3] = " X"; +static char symBlank[3] = " o"; +static char *strMines[9] = {" _", " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8"}; +#endif + + +static inline int +count_neighbor(x, y, bitmask) + int x, y, bitmask; +{ + return (((MineMap[x - 1][y - 1] & bitmask) + (MineMap[x - 1][y] & bitmask) + + (MineMap[x - 1][y + 1] & bitmask) + (MineMap[x][y - 1] & bitmask) + + (MineMap[x][y] & bitmask) + (MineMap[x][y + 1] & bitmask) + + (MineMap[x + 1][y - 1] & bitmask) + (MineMap[x + 1][y] & bitmask) + + (MineMap[x + 1][y + 1] & bitmask)) / bitmask); +} + + +static void +init_map() +{ + int x, y, i; + + /* ³]©w¦³®Ä´Ñ½L */ + + for (x = 0; x < MAP_X + 2; x++) + { + for (y = 0; y < MAP_Y + 2; y++) + { + MineMap[x][y] = TILE_BLANK; + if (x == 0 || y == 0 || x == MAP_X + 1 || y == MAP_Y + 1) + MineMap[x][y] |= TILE_EXPAND; + } + } + + /* ³]©w¦a¹p©Ò¦b */ + + for (i = 0; i < TotalMines;) + { + x = rnd(MAP_X) + 1; + y = rnd(MAP_Y) + 1; + + if (MineMap[x][y] == TILE_BLANK) + { + MineMap[x][y] = TILE_MINE; + i++; + } + } + + /* ºâ¥X©Ò¦³®æªº¾F©~¦³¦h¤Ö¦a¹p */ + + for (x = 1; x <= MAP_X; x++) + { + for (y = 1; y <= MAP_Y; y++) + { + MineNei[x][y] = count_neighbor(x, y, TILE_MINE); + } + } + + /* ²{¦b¶}©lp®É¡A¦]¬° out_map() ªº out_info() n¥Î¨ì */ + InitTime = time(0); +} + + +static void +out_prompt() +{ + /* outs() ¸Ì±ªº±Ôz¤£±o¶W¹L MINE_YPOS¡A§_«h·|¿ù¶Ã */ + move(3, 0); + outs("«öÁ仡©ú¡G"); + move(5, 0); + outs("²¾°Ê ¤è¦VÁä"); + move(7, 0); + outs("½¶} ªÅ¥ÕÁä"); + move(9, 0); + outs("¼Ð°O¦a¹p ¢î"); + move(11, 0); + outs("±½¹p ¢ì"); + move(13, 0); + outs("Â÷¶} ¢ù"); +} + + +static inline void +out_song() +{ + uschar *msg[8] = + { + "«D¿FªyµL¥H©ú§Ó¡A«D¹çÀRµL¥HP»·", /* ½Ñ¸¯«G»|¤l®Ñ */ + "¤@µ°¤@¶º¡A·í«ä±o¨Ó¤£©ö¡F¥bµ·¥bÁ\\¡A«í©Àª«¤OºûÁ}", /* ¦¶¤lP®a®æ¨¥ */ + "©y¥¼«B¦Óº÷Á[¡A¤ðÁ{´÷¦Ó±¸¤«", /* ¦¶¤lP®a®æ¨¥ */ + "µL©Àº¸¯ª¡A¦Ö²ç³Ö¼w", /* ¤j¶® */ + "¤j¾Ç¤§¹D¡A¦b©ú©ú¼w¡A¦b¿Ë¥Á¡A¦b¤î©ó¦Üµ½", /* ¤j¾Ç */ + "¤Ñ©R¤§¿×©Ê¡A²v©Ê¤§»w¹D¡A²ç¹D¤§¿×±Ð", /* ¤¤±e */ + "¤£±w¤H¤§¤£ª¾¤v¡A±w¤£ª¾¤H¤]", /* ½×»y£»¾Ç¦Ó */ + "´Â»D¹D¡A¤i¦º¥i¨o" /* ½×»y£»¨½¤¯ */ + }; + move(b_lines - 2, 0); + prints("\033[1;3%dm%s\033[m", time(0) % 7, msg[time(0) % 8]); + clrtoeol(); +} + + +static void +out_info() +{ + move(b_lines - 1, 0); + prints("©Òªá®É¶¡: %.0lf ¬í¡A³Ñ¤U %d Ó¦a¹p¥¼¼Ð°O¡C", + difftime(time(0), InitTime), TotalMines - TaggedMines); + clrtoeol(); + + out_song(); +} + + +static inline void +out_map() +{ + int x, y; + + vs_bar("«lÃz½ò¦a¹p"); + + for (x = 1; x <= MAP_X; x++) + { + move(MINE_XPOS + x, MINE_YPOS + 2); + for (y = 1; y <= MAP_Y; y++) + outs(symBlank); + } + + out_prompt(); + out_info(); + move(MINE_XPOS + cx, MINE_YPOS + cy * 2 + 1); /* move to (0, 0) */ +} + + +static void +draw_map() /* µe¥X§¹¾ãµª®× */ +{ + int x, y; + + vs_bar("«lÃz½ò¦a¹p"); + + for (x = 1; x <= MAP_X; x++) + { + move(MINE_XPOS + x, MINE_YPOS + 2); + for (y = 1; y <= MAP_Y; y++) + { + if (MineMap[x][y] & TILE_TAGGED) + { + if (!(MineMap[x][y] & TILE_MINE)) + outs(symWrong); + else + outs(symTag); + } + else if (MineMap[x][y] & TILE_EXPAND) + outs(strMines[MineNei[x][y]]); + else if (MineMap[x][y] & TILE_MINE) + outs(symMine); + else + outs(symBlank); + } + } +} + + +static void +expand_map(x, y) + int x, y; +{ + if (MineMap[x][y] & TILE_TAGGED || MineMap[x][y] & TILE_EXPAND) + return; + + if (MineMap[x][y] & TILE_MINE && !(MineMap[x][y] & TILE_TAGGED)) + { + LoseGame = 1; + return; + } + + MineMap[x][y] |= TILE_EXPAND; + move(MINE_XPOS + x, MINE_YPOS + y * 2); + outs(strMines[MineNei[x][y]]); + + if (MineNei[x][y] == 0) + { + if ((MineMap[x - 1][y] & TILE_EXPAND) == 0) + expand_map(x - 1, y); + if ((MineMap[x][y - 1] & TILE_EXPAND) == 0) + expand_map(x, y - 1); + if ((MineMap[x + 1][y] & TILE_EXPAND) == 0) + expand_map(x + 1, y); + if ((MineMap[x][y + 1] & TILE_EXPAND) == 0) + expand_map(x, y + 1); + if ((MineMap[x - 1][y - 1] & TILE_EXPAND) == 0) + expand_map(x - 1, y - 1); + if ((MineMap[x + 1][y - 1] & TILE_EXPAND) == 0) + expand_map(x + 1, y - 1); + if ((MineMap[x - 1][y + 1] & TILE_EXPAND) == 0) + expand_map(x - 1, y + 1); + if ((MineMap[x + 1][y + 1] & TILE_EXPAND) == 0) + expand_map(x + 1, y + 1); + } +} + + +static inline void +trace_map(x, y) + int x, y; +{ + if (MineMap[x][y] & TILE_EXPAND && + MineNei[x][y] == count_neighbor(x, y, TILE_TAGGED)) + { + expand_map(x - 1, y); + expand_map(x, y - 1); + expand_map(x + 1, y); + expand_map(x, y + 1); + expand_map(x - 1, y - 1); + expand_map(x + 1, y - 1); + expand_map(x - 1, y + 1); + expand_map(x + 1, y + 1); + } +} + + +static inline void +play_mine() +{ + int ch; + + LoseGame = 0; + EndGame = 0; + + while (!LoseGame && (ch = vkey())) + { + switch (ch) + { + case KEY_ESC: + case 'q': + EndGame = 1; + return; + + /* °µ¥ô¦ó°Ê§@³£n§â´å¼Ð¦^´_¨ìì¨Óªº¦ì¸m */ + + case KEY_UP: + if (cx > 1) + { + cx--; + move(MINE_XPOS + cx, MINE_YPOS + cy * 2 + 1); + } + break; + + case KEY_DOWN: + if (cx < MAP_X) + { + cx++; + move(MINE_XPOS + cx, MINE_YPOS + cy * 2 + 1); + } + break; + + case KEY_LEFT: + if (cy > 1) + { + cy--; + move(MINE_XPOS + cx, MINE_YPOS + cy * 2 + 1); + } + break; + + case KEY_RIGHT: + if (cy < MAP_Y) + { + cy++; + move(MINE_XPOS + cx, MINE_YPOS + cy * 2 + 1); + } + break; + + case 'd': + case '\n': + trace_map(cx, cy); + out_info(); + move(MINE_XPOS + cx, MINE_YPOS + cy * 2 + 1); + break; + + case ' ': + expand_map(cx, cy); + out_info(); + move(MINE_XPOS + cx, MINE_YPOS + cy * 2 + 1); + break; + + case 'f': + if (MineMap[cx][cy] & TILE_EXPAND) + { + if (MineMap[cx][cy] & TILE_TAGGED) /* ¥»¨Ó³Q¼Ð°O, ¨ú®ø */ + { + TaggedMines--; + MineMap[cx][cy] ^= TILE_EXPAND; + MineMap[cx][cy] ^= TILE_TAGGED; + move(MINE_XPOS + cx, MINE_YPOS + cy * 2); + outs(symBlank); + } + } + else /* ¥»¨Ó¨S¼Ð°O, ¤W¼Ð°O */ + { + TaggedMines++; + MineMap[cx][cy] ^= TILE_EXPAND; + MineMap[cx][cy] ^= TILE_TAGGED; + move(MINE_XPOS + cx, MINE_YPOS + cy * 2); + outs(symTag); + if (TaggedMines == TotalMines) + return; + } + out_info(); + move(MINE_XPOS + cx, MINE_YPOS + cy * 2 + 1); + break; + + default: + break; + } + } +} + + +static inline int +win() +{ + int x, y; + + for (x = 1; x <= MAP_X; x++) + { + for (y = 1; y <= MAP_Y; y++) + { + if (((MineMap[x][y] & TILE_TAGGED) && !(MineMap[x][y] & TILE_MINE)) || + (!(MineMap[x][y] & TILE_TAGGED) && (MineMap[x][y] & TILE_MINE))) + { + return 0; /* ¼Ð¿ù¦a¤è */ + } + } + } + return 1; +} + + +int +main_mine() +{ + int level; + char ans[4]; + + level = vans("½Ð¿ï¾Ü [1-5] µ¥¯Å¡A[0] ¦Û©w¡A©Î«ö [Q] Â÷¶}¡G"); + if (level == 'q') + { + return XEASY; + } + else if (level < '1' || level > '5') /* ¦Û©w´Ñ½L¤£±o¤j©ó 60 * 20 */ + { + vget(b_lines, 0, "½Ð¿é¤J¦a¹Ïªºªø¡G", ans, 3, DOECHO); + MAP_Y = atoi(ans) > MAP_MAX_Y ? MAP_MAX_Y : atoi(ans); + + vget(b_lines, 0, "½Ð¿é¤J¦a¹Ïªº¼e¡G", ans, 3, DOECHO); + MAP_X = atoi(ans) > MAP_MAX_X ? MAP_MAX_X : atoi(ans); + + vget(b_lines, 0, "½Ð¿é¤J¦a¹p¼Æ¡G", ans, 3, DOECHO); + level = atoi(ans); + TotalMines = MAP_Y * MAP_X / 3; + if (TotalMines > level) + TotalMines = level; + /* ¨î¦a¹p¼Æ¤£±o¶W¹L MAP_Y * MAP_X / 3¡A¥H§K init_map() ¶Ã¼Æ¨ú¤Ó¤[ */ + + if (MAP_Y < 1 || MAP_X < 1 || TotalMines < 1) + return 0; + level = 0; + } + else + { + level -= '0'; + MAP_Y = 5 * level; /* ¤£±o¶W¹L MAP_MAX_Y */ + MAP_X = (level < 4) ? 5 * level : MAP_MAX_X; /* ¤£±o¶W¹L MAP_MAX_X */ + TotalMines = MAP_Y * MAP_X / 10; + } + + TaggedMines = 0; + cx = MAP_X / 2 + 1; + cy = MAP_Y / 2 + 1; + + init_map(); + out_map(); + play_mine(); + + if (!EndGame) + { + if (LoseGame) + { + draw_map(); + vmsg("¸I¡I½ò¨ì¦a¹p¤F¡I"); + } + else /* ¼Ð°O¼Æ == ¦a¹p¼Æ */ + { + if (win()) /* itoc.010711: nÀˬd¬O§_¯}Ãö¡A¥H§KÀH«K¶Ã¼Ð°O¡A·í¼Ð°O¼Æ=¦a¹p¼Æ´N»¡¹LÃö¤F */ + { + char buf[STRLEN]; + sprintf(buf, "±zªá¤F %.0lf ¬í ¯}²Ä %d Ãö ¦n±R«ô ^O^", difftime(time(0), InitTime), level); + vmsg(buf); + addmoney(level * 75); + } + else + { + draw_map(); + vmsg("±z¼Ð¿ù¦a¹p¤F³á =.="); + } + } + } + else + { + vmsg(MSG_QUITGAME); + } + + return 0; +} +#endif /* HAVE_GAME */ diff --git a/game/nine.c b/game/nine.c new file mode 100644 index 0000000..2eb584a --- /dev/null +++ b/game/nine.c @@ -0,0 +1,601 @@ +/*-------------------------------------------------------*/ +/* nine.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¤Ñ¦a¤E¤E¹CÀ¸ */ +/* create : 98/11/26 */ +/* update : 01/04/24 */ +/* author : dsyan.bbs@Forever.twbbs.org */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#ifdef HAVE_GAME + + +#undef NINE_DEBUG + + +static char AI_score[13] = {7, 6, 5, 4,10, 9, 3, 2, 1, 0,11, 8,12}; +/* ¹q¸£ AI ©Ò¦b : K A 2 3 4 5 6 7 8 9 T J Q ¨CÂIµP©Ò¹ïÀ³ªº¤À¼Æ */ +/* AI_score 6 ¥H¤Uªº¬O¼Æ¦rµP¡A7 ¥H¤Wªº¬O¯S®íµP */ +/* ¹q¸£¶É¦V§â AI_score ¤pªºµP¥á¥X¥h */ + +static char str_dir[4][3] = {"¡õ", "¡÷", "¡ô", "¡ö"}; + +/* hand[] ¸Ì±ªºÈ©Ò¥NªíªºµP±i 0~12:CK~CQ 13~25:DK~DQ 26~38:HK~KQ 39~51:SK~SQ */ +static char str_suit[4][3] = {"¢Ñ", "¢Ò", "¢Ö", "¢á"}; +static char str_num[13][3] = {"¢Ù", "¢Ï", "¢±", "¢²", "¢³", "¢´", "¢µ", "¢¶", "¢·", "¢¸", "¢â", "¢Ø", "¢ß"}; + +static char hand[4][5]; /* ªF¦è«n¥_¥|®aªºµP±i */ +static char now; /* ²{¦b®à¤WÂI¼Æ */ +static char dir; /* ¥Ø«e±ÛÂ઺¤è¦V 1:°f®É°w -1:¶¶®É°w */ +static char turn; /* ¥Ø«e½ü¨ìþ¤@®a 0:¦Û¤v 1-3:¹q¸£ */ +static char live; /* ¹q¸£ÁÙ¦³´X®a¬¡µÛ 0~3 0:ª±®a³Ó§Q */ +static int sum; /* ®à¤W¤w¸g¦³´X±iµP¤F */ + + +static void +out_song() +{ + static int count = 0; + + /* ¼BY^£»«Ü·R«Ü·R§A */ + uschar *msg[12] = + { + "·Q¬°§A°µ¥ó¨Æ Åý§A§ó§Ö¼Öªº¨Æ", + "¦n¦b§Aªº¤ß¤¤ ®I¤U§Úªº¦W¦r", + "¨D®É¶¡ ¶XµÛ§A ¤£ª`·Nªº®ÉÔ", + "®¨®¨¦a §â³oºØ¤l ÆC¦¨ªG¹ê", + "§Ú·Q¦oªº½T¬O §ó¾A¦X§Aªº¤k¤l", + "§Ú¤Ó¤£°÷·Å¬XÀu¶®¦¨¼ôÀ´¨Æ", + "¦pªG§Ú °h¦^¨ì ¦nªB¤Íªº¦ì¸m", + "§A¤]´N ¤£¦A»Ýn ¬°Ãø¦¨³o¼Ë¤l", + "«Ü·R«Ü·R§A ©Ò¥HÄ@·N ±Ë±oÅý§A", + "©¹§ó¦h©¯ºÖªº¦a¤è¸¥h", + "«Ü·R«Ü·R§A ¥u¦³Åý§A ¾Ö¦³·R±¡", + "§Ú¤~¦w¤ß" + }; + move(b_lines - 2, 0); + prints("\033[1;3%dm%s\033[m Äw½XÁÙ¦³ %d ¤¸", time(0) % 7, msg[count], cuser.money); + clrtoeol(); + if (++count == 12) + count = 0; +} + + +static int +score_cmp(a, b) + char *a, *b; +{ + return AI_score[(*a) % 13] - AI_score[(*b) % 13]; +} + + +static void +show_mycard() /* ¨q¥X§Ú¤â¤Wªº¤±iµP */ +{ + int i; + char t; + + for (i = 0; i < 5; i++) + { + t = hand[0][i]; + move(16, 30 + i * 4); + outs(str_num[t % 13]); + move(17, 30 + i * 4); + outs(str_suit[t / 13]); + } +} + + +static void +show_seacard(t) /* ¨q¥X®ü©³ªºµP */ + char t; /* ¥X¤Fþ±iµP */ +{ + char x, y; + + /* ªF«n¦è¥_¥|®aªº¥XµP¸m©ñ (x, y) §¤¼Ð */ + /* «n ªF ¥_ ¦è */ + char coorx[4] = { 8, 6, 4, 6}; + char coory[4] = {30, 38, 30, 22}; + +#ifdef NINE_DEBUG + /* ¨q¥X¹q¸£ªºµP */ + move(b_lines - 1, 5); + for (x = 3; x > 0; x--) + { + if (hand[x][0] == -1) /* ³o®a¤w¸gºG¾D²^¨O¡A¤£¥²¦L¥X */ + continue; + qsort(hand[x], 5, sizeof(char), score_cmp); + for (y = 0; y < 5; y++) + outs(str_num[hand[x][y] % 13]); + outs(" "); + } +#endif + + x = coorx[turn]; + y = coory[turn]; + move(x, y); + outs("¢~¢w¢w¢w¢¡"); + move(x + 1, y); + prints("¢x%s ¢x", str_num[t % 13]); + move(x + 2, y); + prints("¢x%s ¢x", str_suit[t / 13]); + move(x + 3, y); + outs("¢x ¢x"); + move(x + 4, y); + outs("¢x ¢x"); + move(x + 5, y); + outs("¢x ¢x"); + move(x + 6, y); + outs("¢¢¢w¢w¢w¢£"); + + move(8, 50); + prints("%s %s", dir == 1 ? "¡ú" : "¡ù", dir == 1 ? "¡ø" : "¡û"); + move(10, 50); + prints("%s %s", dir == 1 ? "¡û" : "¡ø", dir == 1 ? "¡ù" : "¡ú"); + + move(13, 46); + prints("ÂI¼Æ¡G%-2d", now); + /* prints("ÂI¼Æ¡G%c%c%c%c", (now / 10) ? 162 : 32, (now / 10) ? (now / 10 + 175) : 32, 162, now % 10 + 175); */ /* µL»Ý´«¦¨¥þ§Î */ + + move(14, 46); + prints("±i¼Æ¡G%d", sum); + + refresh(); + + sleep(1); /* Åýª±®a¬Ý²M·¡¥XµPª¬ªp */ +} + + +static void +ten_or_twenty(t) /* ¥[©Î´î 10/20 */ + char t; +{ + if (now < t) /* ª½±µ¥[ */ + { + now += t; + } + else if (now > 99 - t) /* ª½±µ´î */ + { + now -= t; + } + else /* ¸ß°Ýn¥[ÁÙ¬On´î */ + { + int ch; + + move(b_lines - 4, 0); + clrtoeol(); + prints(" (¡ö)(+)¥[%d (¡÷)(-)´î%d ", t, t); + + while (1) + { + if (turn) /* ¹q¸£ */ + ch = rnd(2) + KEY_LEFT; /* KEY_RIGHT == KEY_LEFT + 1 */ + else /* ª±®a */ + ch = vkey(); + + switch (ch) + { + case KEY_LEFT: + case '+': + now += t; + prints("\033[32;1m¥[ %d\033[m", t); + return; + + case KEY_RIGHT: + case '-': + now -= t; + prints("\033[32;1m´î %d\033[m", t); + return; + } + } + } +} + + +static void +next_turn() +{ + while (1) + { + turn = (turn + 4 + dir) % 4; + if (hand[turn][0] >= 0) /* ¦pªG¤U¤@®a¤w¾D²^¨O¡A¸õ¦A¤U¤@®a */ + break; + } +} + + +static char +get_newcard() +{ + /* 0~12:C)KA23456789TJQ 13~25:D))KA23456789TJQ 26~38:H))KA23456789TJQ 39~51:S)KA23456789TJQ */ + + /* itoc.020929: ¬°¨Dµ{¦¡Â²³æ¡AµP§Y¨Ï«ÂÐ¥X²{¤]µL§«¡A¤Ï¥¿¤Ñ¦a¤E¤E³o¹CÀ¸ + À³¸Ó¬O®³«Ü¦h°Æ¾ë§JµP²V°_¨Óª± */ + + return rnd(52); + + /* itoc.µù¸Ñ: ¦pªGı±o¤Ñ¦a¤[¤[Ãø«×¤Ó°ª¡A¨º»ò¥i¥H¦b¦¹¶Ã¼Æ°µ½Õ¾ã¡A + ¹³¬O now ±µªñ 99 ®É¡Aª±®aªºµP·|Åܦn¡F©Î¬O¹q¸£¨ú¨ì¯S®íµPªº¾÷²vÅܤp */ +} + + +static int /* -1:Ãz±¼ */ +lead_card(t) /* ¥XµP */ + char *t; /* ¶Ç¤J¥X¤Fþ±iµP¡A¤]n¶Ç¥X¤@±i·sªºµP´À¥N³o±iµP */ +{ + int ch; + char m; + + m = *t % 13; + switch (m) + { + case 4: /* °jÂà */ + dir = -dir; + break; + + case 5: /* «ü©w */ + move(b_lines - 4, 0); + clrtoeol(); + outs(" «ü©w¨º¤@®a¡H"); + for (ch = 3; ch >= 0; ch--) + { + if (turn != ch && hand[ch][0] >= 0) + prints("(%s) ", str_dir[ch]); + } + + /* «ü©w¤@®a©|¥¼²^¨Oªº */ + while (1) + { + +#if 0 /* from global.h */ +#define KEY_UP -1 +#define KEY_DOWN -2 +#define KEY_RIGHT -3 +#define KEY_LEFT -4 +#endif + + if (turn || live == 1) /* ¦pªG¬O¹q¸£¥XªºµP©Î¬O¥u³Ñ¤U¤@Ó¹q¸£¹ï¤â¡A´N¦Û°Ê«ü©w */ + ch = rnd(4) + KEY_LEFT; + else + ch = vkey(); + + /* ³Q«ü©wªº¨º®a¤£¯à¤w¸g¾D²^¨O */ + if (turn != 3 && hand[3][0] >= 0 && ch == KEY_LEFT) + ch = 3; + else if (turn != 2 && hand[2][0] >= 0 && (ch == KEY_UP || ch == KEY_DOWN)) + ch = 2; + else if (turn != 1 && hand[1][0] >= 0 && ch == KEY_RIGHT) + ch = 1; + else if (turn != 0 && hand[0][0] >= 0) + ch = 0; + else + continue; + + break; + } + + prints("\033[32;1m(%s)\033[m", str_dir[ch]); + break; + + case 10: /* ¥[©Î´î10 */ + ten_or_twenty(10); + break; + + case 11: /* Pass */ + break; + + case 12: /* ¥[©Î´î20 */ + ten_or_twenty(20); + break; + + case 0: /* °¨¤WÅÜ99 */ + now = 99; + break; + + default: /* ¤@¯ë¼Æ¦rµP */ + if (now + m > 99) + return -1; + else + now += m; + break; + } + + show_seacard(*t); + + /* ®³¤@±i·sªºµP */ + *t = get_newcard(); + + /* ½ü¨ì¤U¤@®a */ + if (m == 5) + turn = ch; + else + next_turn(); + + return 0; +} + + +static void +cpu_die() +{ + char buf[20]; + + switch (turn) + { + case 1: + move(9, 55); + break; + case 2: + move(7, 52); + break; + case 3: + move(9, 49); + break; + } + outs(" "); + live--; + + sprintf(buf, "¹q¸£ %d Ãz¤F", turn); + vmsg(buf); + sleep(1); /* Åýª±®a¬Ý²M·¡¥XµPª¬ªp */ + + hand[turn][0] = -1; /* Ãz±¼ªº¨º®aªº hand[turn][0] ³]¬° -1 */ + next_turn(); +} + + +static void +online_help(t) + char t; +{ + char m; + + move(b_lines - 4, 0); + clrtoeol(); + + m = t % 13; + switch (m) + { + case 0: + outs(" ¤E¤E¡GÂI¼Æ°¨¤WÅܦ¨¢¸¢¸"); + break; + + case 4: + outs(" °jÂà¡G¹CÀ¸¶i¦æ¤è¦V¬Û¤Ï"); + break; + + case 5: + outs(" «ü©w¡G¦Û¥Ñ«ü©w¤U¤@Óª±®a"); + break; + + case 11: + outs(" PASS¡G¥i pass ¤@¦¸"); + break; + + case 10: + outs(" ÂI¼Æ¥[©Î´î 10"); + break; + + case 12: + outs(" ÂI¼Æ¥[©Î´î 20"); + break; + + default: + prints(" ÂI¼Æ¥[ %d", m); + break; + } +} + + +int +main_nine() +{ + int money; /* ©ãª÷ */ + + int i, j; + char m; + char buf[STRLEN]; + FILE *fp; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + while (1) + { + vs_bar("¤Ñ¦a¤E¤E"); + out_song(); + + vget(2, 0, "½Ð°Ýn¤Uª`¦h¤Ö©O¡H(1 ~ 50000) ", buf, 6, DOECHO); + money = atoi(buf); + if (money < 1 || money > 50000 || money > cuser.money) + break; /* Â÷¶}½ä³õ */ + + /* ¦L¥X½ä³õ¤º³¡Â\³] */ + + if (!(fp = fopen("etc/game/99", "r"))) + break; /* Â÷¶}½ä³õ */ + + move(2, 0); + clrtoeol(); /* ²M±¼¡u½Ð°Ýn¤Uª`¦h¤Ö©O¡H¡vªº´Ý¾l */ + + move(1, 0); + while (fgets(buf, STRLEN, fp)) + outs(buf); + + fclose(fp); + + cuser.money -= money; /* ¥ý½T©w¯à¶}ÀɦA¦©¿ú */ + + for (i = 0; i < 4; i++) + { + for (j = 0; j < 5; j++) + hand[i][j] = get_newcard(); + } + + sum = 0; /* ¥Ø«eµP®à¤¤¶¡¨S¦³µP */ + now = 0; /* ¥Ø«eµP®à¤¤¶¡ªºÂI¼Æ¬O 0 */ + turn = 0; /* ª±®a¶}©l²Ä¤@¨B */ + dir = 1; /* ¤@¶}©l¹w³] °f®É°w */ + live = 3; /* ©|¦³¤T®a¹q¸£¬¡µÛ */ + + /* ª±®aªºµPn±Æ§Ç¡A¹q¸£ªºµPµ¥½ü¨ì¹q¸£®É¦A±Æ§Ç */ + qsort(hand[0], 5, sizeof(char), score_cmp); + show_mycard(); + + /* ¹CÀ¸¶}©l */ + for (;;) + { + move(9, 52); + outs(str_dir[turn]); + + /* ½ü¨ì¹q¸£¥XµP */ + + if (turn) + { + qsort(hand[turn], 5, sizeof(char), score_cmp); + + for (i = 0; i < 5; i++) + { + m = hand[turn][i] % 13; + if (AI_score[m] >= 7) /* ¥Î AI_score[] ¨Ó§PÂ_¬O§_¬°¯S®íµP */ + break; + if (now + m <= 99) + break; + } + + if (i == 5) /* ¨S¦³¥ô¦ó¤@±iµP¯à¥X */ + { + cpu_die(); + } + else + { + /* ¥Ñ©ó qsort ·|§â AI_score ªºµP©ñ¦b³Ì¥ªÃä¡A´Nª½±µ©ß¥X³Ì¥ªÃä³o±iµP§Y¥i */ + sum++; + lead_card(&(hand[turn][i])); + } + + if (rnd(5) == 0) + out_song(); + + continue; + } + + /* ½ü¨ìª±®a¥XµP */ + + if (!live) /* ¤T®a¹q¸£³£¦º¥ú¤F */ + { + if (sum < 25) + money *= 15; + else if (sum < 50) + money *= 10; + else if (sum < 100) + money *= 5; + else if (sum < 150) + money *= 3; + else if (sum < 200) + money *= 2; + /* ¶W¹L 200 ¦¸¤~Ĺ¡A¥uÁÙì©ãª÷ */ + + addmoney(money); + sprintf(buf, "¦b¸g¹L %d ¦^¦Xªº¼r±þ¡A±z²æ¿o¦Ó¥X¡AÀò±o¼úª÷ %d", sum, money); + vmsg(buf); + break; + } + + /* ¸û¤pªºµP/¯S®íµP©ñ¦b¥kÃä¡AY³Ì«á¤@±i¤£¬O¯S®íµP¥B¥[¤W¥h·|¶W¹L 99¡A´N¬OÃz¤F */ + m = hand[0][4] % 13; + if (AI_score[m] < 7 && now + m > 99) + { + sprintf(buf, "¶ã¶ã¶ã..¦b %d ±iµP³Q¹q¸£¹qÃz±¼¤F.. :~", sum); + vmsg(buf); + break; + } + + i = 0; /* ¦b¥H¤U while(j) °j°é¤¤¡A®³ i ¨Ó·í²Ä´X±iµP */ + while (1) /* ª½¨ì vkey() == '\n' ©Î ' ' ®É¤~Â÷¶}°j°é */ + { + m = hand[0][i] % 13; + move(18, i * 4 + 30); + + if (AI_score[m] < 7) /* ¥Î AI_score[] ¨Ó§PÂ_¬O§_¬°¯S®íµP */ + { + if (now + m > 99) + outs("¡I"); /* ĵ§i·|Ãz±¼ */ + else + outs("¡³"); /* ¤@¯ëµP */ + } + else + { + outs("¡¹"); /* ¯S®íµP */ + } + + move(18, i * 4 + 31); /* Á×§K°»´ú¥ª¥kÁä¥þ§Î */ + + j = vkey(); + + if (j == KEY_LEFT) + { + move(18, i * 4 + 30); + outs(" "); + i = i ? i - 1 : 4; + } + else if (j == KEY_RIGHT) + { + move(18, i * 4 + 30); + outs(" "); + i = (i == 4) ? 0 : i + 1; + } +#ifdef NINE_DEBUG + else if (j == KEY_UP) + { + if (vget(b_lines - 4, 5, "§âµP´«¦¨¡G", buf, 3, DOECHO)) + { + m = atoi(buf); + if (m >= 0 && m < 52) + { + hand[0][i] = m; + qsort(hand[0], 5, sizeof(char), score_cmp); + show_mycard(); + } + } + } +#endif + else if (j == KEY_DOWN) + { + online_help(hand[0][i]); + } + else if (j == '\n' || j == ' ') + { + move(18, i * 4 + 30); + outs(" "); + sum++; + break; + } + else if (j == 'q') + { + return 0; + } + } + + if (lead_card(&(hand[0][i])) < 0) + { + vmsg("¶ã¶ã¶ã..¥ÕÄêÃz¤F!!.. :~"); + break; + } + + qsort(hand[0], 5, sizeof(char), score_cmp); + show_mycard(); + } + } + return 0; +} + +#endif /* HAVE_GAME */ diff --git a/game/pushbox.c b/game/pushbox.c new file mode 100644 index 0000000..10414db --- /dev/null +++ b/game/pushbox.c @@ -0,0 +1,321 @@ +/*-------------------------------------------------------*/ +/* pushbox.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : Ü®wµf */ +/* create : 98/11/11 */ +/* update : 02/09/05 */ +/* author : period.bbs@smth.org */ +/* cityhunter.bbs@smth.org */ +/* modify : zhch.bbs@bbs.nju.edu.cn */ +/* hightman.bbs@bbs.hightman.net */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#define MAX_MAP_WIDTH 20 +#define MAX_MAP_HEIGHT 16 +#define MAX_MOVE_TIMES 1000 /* ³Ì¦h²¾°Ê´X¨B */ + +#define move2(x, y) move(x+6, y*2) +#define move3(x, y) move(x+6, y*2+1) /* Á×§K¥þ§Î°»´ú */ + +static int cx, cy; /* ¥Ø«e©Ò¦b¦ì¸m */ +static int stage; /* ²Ä´XÃö */ +static int NUM_TABLE; /* Á`¦@¦³´XÃö */ +static int total_line; /* ¥»Ãö¦³´X¦C */ +static usint map[MAX_MAP_HEIGHT][MAX_MAP_WIDTH]; + + +static char * +map_char(n) + usint n; +{ + if (n & 8) + return "¡½"; + if (n & 4) + return "¡¼"; + if (n & 2) + return "¡ó"; + if (n & 1) + return "¡O"; + return " "; +} + + +static usint +map_item(item) + char *item; +{ + if (!str_ncmp(item, map_char(1), 2)) + return 1; + if (!str_ncmp(item, map_char(2), 2)) + return 2; + if (!str_ncmp(item, map_char(4), 2)) + return 4; + if (!str_ncmp(item, map_char(8), 2)) + return 8; + return 0; +} + + +static int /* 0:¥¢±Ñ !=0:¦@¦³´X¦C */ +map_init(fp) + FILE *fp; +{ + int i, j; + char buf[80], level[8]; + + sprintf(level, "--%03d", stage); + while (fgets(buf, 10, fp)) + { + if (!str_ncmp(buf, level, 5)) /* §ä¨ì¥¿½TªºÃö¥d */ + break; + } + + memset(map, 0, sizeof(map)); + + i = 0; + while (fgets(buf, 80, fp)) + { + /* ¸ü¤J¦a¹Ï */ + if (buf[0] == '-') + break; + + for (j = 0; j < MAX_MAP_WIDTH; j++) + map[i][j] = map_item(buf + j * 2); + + if (++i >= MAX_MAP_HEIGHT) + break; + + memset(buf, 0, sizeof(buf)); + } + + return i; +} + + +static int +map_line(x) /* ¦L¥X²Ä x ¦C */ + int x; +{ + int j; + usint n; + + move2(x, 0); + clrtoeol(); + for (j = 0; j < MAX_MAP_WIDTH; j++) + { + n = map[x][j]; + if (n & 5) /* ¥[±jÃC¦â¨Ï²M·¡ */ + prints("\033[1;32m%s\033[m", map_char(n)); + else + outs(map_char(n)); + } +} + + +static void +map_show() +{ + int i; + + for (i = 0; i < total_line; i++) + map_line(i); + + move3(cx, cy); +} + + +static void +map_move(x0, y0, x1, y1) /* (x0, y0) -> (x1, y1) */ + int x0, y0, x1, y1; +{ + usint m; + + m = map[x0][y0]; + + map[x1][y1] = (m & 6) | (map[x1][y1] & 1); /* ¥Øªº®æ¥[¤J '¡ó' ¤Î '¡¼' */ + map[x0][y0] = m & 1; /* ©Ò¦b®æ²MªÅ '¡ó' ¤Î '¡¼' */ + + map_line(x0); + if (x1 != x0) + map_line(x1); +} + + +static int /* 1:¦¨¥\ */ +check_win() +{ + int i, j; + for (i = 0; i < total_line; i++) + { + for (j = 0; j < MAX_MAP_WIDTH; j++) + { + if ((map[i][j] & 1) && !(map[i][j] & 4)) /* ÁÙ¦³ '¡O' ¤W¨S¦³ '¡¼' */ + return 0; + } + } + return 1; +} + + +static int +find_cxy() /* §äªì©l¦ì¸m */ +{ + int i, j; + for (i = 0; i < total_line; i++) + { + for (j = 0; j < MAX_MAP_WIDTH; j++) + { + if (map[i][j] & 2) + { + cx = i; + cy = j; + return 1; + } + } + } + return 0; +} + + +static int +select_stage() +{ + int count; + char buf[80], ans[4]; + FILE *fp; + + if (!(fp = fopen("etc/game/pushbox.map", "r"))) + return 0; + + if (stage < 0) /* ²Ä¤@¦¸¶i¤J¹CÀ¸ */ + { + fgets(buf, 4, fp); + NUM_TABLE = atoi(buf); /* etc/game/pushbox.map ²Ä¤@¦æ°O¿ýÃö¥d¼Æ */ + sprintf(buf, "½Ð¿ï¾Ü½s¸¹ [1-%d]¡A[0] ÀH¾÷¥XÃD¡A©Î«ö [Q] Â÷¶}¡G", NUM_TABLE); + if (vget(b_lines, 0, buf, ans, 4, DOECHO) == 'q') + { + fclose(fp); + return 0; + } + stage = atoi(ans); + if (stage <= 0 || stage > NUM_TABLE) /* ÀH¾÷¥XÃD */ + stage = 1 + time(0) % NUM_TABLE; + } + + count = map_init(fp); + fclose(fp); + + return count; +} + + +int +main_pushbox() +{ + int dx, dy; /* ¤U¤@¨B©Ò¦æ¦ì¬í */ + int valid; + usint n; + + stage = -1; + +start_game: + + if (!(total_line = select_stage())) + return XEASY; + + vs_bar("Ü®wµf"); + move(2, 0); + prints("²Ä \033[1;32m%03d\033[m Ãö¡G§â©Ò¦³ªº '¡¼' ³£±À¨ì '¡O' ¤W±¥h(·|Åܦ¨\033[1;32mºñ¦â\033[m)´N¹LÃö¤F\n", stage); + outs("«öÁ仡©ú¡G(¡ô¡õ¡ö¡÷)²¾°Ê (s)«ª± (q)Â÷¶} (^L)¿Ã¹õ«Ã¸"); + + if (!find_cxy()) + { + vmsg("³o±i¦a¹Ï¦ü¥G¤£¹ï«l¡I"); + return 0; + } + + map_show(); + + while (1) + { + dx = dy = 0; + + switch (vkey()) + { + case KEY_UP: + dx = -1; + break; + + case KEY_DOWN: + dx = 1; + break; + + case KEY_LEFT: + dy = -1; + break; + + case KEY_RIGHT: + dy = 1; + break; + + case Ctrl('L'): + map_show(); + break; + + case 'q': + goto game_over; + + case 's': + goto start_game; + } + + if (!dx && !dy) + continue; + + /* ¶}©l²¾°Ê */ + valid = 0; + n = map[cx + dx][cy + dy]; /* ¥Øªº®æ */ + + if (n <= 1) /* ¥Øªº®æ¬OªÅªº¡Aª½±µ²¾¤J§Y¥i */ + { + map_move(cx, cy, cx + dx, cy + dy); + valid = 1; + } + else if (n & 4) /* ¥Øªº®æ¦³ '¡¼'¡A±À¥h¤U¤U®æ */ + { + if (map[cx + dx * 2][cy + dy * 2] <= 1) /* ¤U¤U®æ¬OªÅªº */ + { + map_move(cx + dx, cy + dy, cx + dx * 2, cy + dy * 2); + map_move(cx, cy, cx + dx, cy + dy); + valid = 1; + } + } + + if (valid) /* ¦³®Ä²¾°Ê */ + { + if (check_win()) + break; + + cx += dx; + cy += dy; + move3(cx, cy); + } + } + + vmsg("¯¬¶P±z¡I¦¨¥\\¹LÃö"); + + if (++stage > NUM_TABLE) + stage = 1; + + goto start_game; + +game_over: + return 0; +} +#endif /* HAVE_GAME */ diff --git a/game/race.c b/game/race.c new file mode 100644 index 0000000..b4d18d4 --- /dev/null +++ b/game/race.c @@ -0,0 +1,357 @@ +/*-------------------------------------------------------*/ +/* race.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : Áɰ¨³õ¹CÀ¸ */ +/* create : 98/12/17 */ +/* update : 01/04/21 */ +/* author : SugarII (u861838@Oz.nthu.edu.tw) */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#ifdef HAVE_GAME + + +static int pace[5]; /* ¤¤Ç°¨¶]¤F¦h»· */ + + +static void +out_song() +{ + static int count = 0; + + /* ±i«B£»¤@¨¥ÃøºÉ */ + uschar *msg[13] = + { + "©pµ¹§Ú¤@³õÀ¸ ©p¬ÝµÛ§Ú¤J°g", + "³Q©p±q¤ß¸Ì鸨ªº·P±¡ µhªº¤£ª¾«ç»ò±Ë¥h", + "¿ð¿ð¤£¯à¬Û«H³o·Pı ¹³¦Û¤v©M¦Û¤v¤ÀÂ÷", + "¦Ó«H»}¥¹¥¹ªº·R±¡ ¦b¨º¸Ì", + "§Ú¤@¨¥ÃøºÉ §Ô¤£¦í¶Ë¤ß", + "¿Å¶q¤£¥X·R©Î¤£·R¤§¶¡ªº¶ZÂ÷", + "©p»¡©pªº¤ß ¤£¦A·Å¼ö¦p©õ", + "±q¨º¸Ì¶}©l ±q¨º¸Ì¥¢¥h", + "§Ú¤@¨¥ÃøºÉ §Ô¤£¦í¶Ë¤ß", + "¿Å¶q¤£¥X·R©Î¤£·R¤§¶¡ªº¶ZÂ÷", + "ÁôÁô¬ù¬ù¤¤ ©ú¥Õ©pªº¨M©w", + "¤£´±«j±j©p ¥u¦n¬°Ãø¦Û¤v", + "§Ú¬°Ãø§Ú¦Û¤v §Ú¬°Ãø§Ú¦Û¤v" + }; + move(b_lines - 2, 0); + prints("\033[1;3%dm%s\033[m Äw½XÁÙ¦³ %d ¤¸", time(0) % 7, msg[count], cuser.money); + clrtoeol(); + if (++count == 13) + count = 0; +} + + +static int /* -1: ÁÙ¨S¤À¥X³Ót 0~4:Ĺªº¨º¤Ç°¨ */ +race_path(run, j, step) + int run, j, step; +{ + int i; + + if (!step) + { + return -1; + } + else if (step < 0) + { + if (j + step < 0) + j = -step; + move(run + 9, (j + step) * 2 + 8); + clrtoeol(); + pace[run] += step * 100; + if (pace[run] < 1) + pace[run] = 1; + return -1; + } + + /* step > 0 */ + move(run + 9, j * 2 + 8); + for (i = 0; i < step; i++) + outs("¡½"); + + if (pace[run] + step * 100 > 3000) + return run; + return -1; +} + + +int +main_race() +{ + int money[5]; /* ¤¤Ç°¨ªº©ãª÷ */ + int speed[5]; /* ¤¤Ç°¨ªº³t«× */ + int stop[5]; /* ¤¤Ç°¨ªº¼È°± */ + int bomb; /* ¬O§_¨Ï¥Î¬µ¼u */ + int run; /* ¥Ø«e¦bpºâªº¨º¤Ç */ + int win; /* þ¤Ç°¨Ä¹¤F */ + int flag; /* ¨Æ¥óµo¥Í¦¸¼Æ */ + int i, j, ch; + char buf[60]; + char *racename[5] = {"¨ª¨ß", "ªº¿c", "¤ö¶À", "¸¹q", "¦½¦å"}; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + while (1) + { + vs_bar("Áɰ¨³õ"); + out_song(); + bomb = 0; + win = -1; + flag = 0; + for (i = 0; i < 5; i++) + { + pace[i] = 1; + stop[i] = money[i] = 0; + speed[i] = 100; + } + move(5, 0); + outs(" \033[1m°¨¦W¡G\033[m"); + for (i = 0; i < 5; i++) + prints(" %d. \033[1;3%dm%s\033[m", i + 1, i + 1, racename[i]); + outs("\n \033[1m³t«×¡G\033[m\n \033[1m½äª÷¡G\033[m\n\n"); + + for (i = 0; i < 5; i++) + prints("%d.\033[1;3%dm%s\033[mùø\n", i + 1, i + 1, racename[i]); + outs("¢w¢w¢wùö¢w¢w¢r¢w¢w¢r¢w¢w¢r¢w¢w¢r¢w¢w¢r¢w¢w¢r¢w¢w¢r¢w¢w¢r¢w¢w¢r¢w¢wù÷"); + + while (1) + { + /* ¨M©w¦U¤Ç°¨½äª` */ + ch = vget(2, 0, "±zn©ãþ¤Ç°¨(1-5)¡H[S]¶}©l [Q]Â÷¶}¡G", buf, 3, DOECHO); + i = buf[0]; + if (!ch || i == 's') + { + if (money[0] || money[1] || money[2] || money[3] || money[4]) + break; + addmoney(money[0] + money[1] + money[2] + money[3] + money[4]); /* ÁÙ¿ú */ + goto abort_game; + } + else if (i < '1' || i > '5') + { + addmoney(money[0] + money[1] + money[2] + money[3] + money[4]); /* ÁÙ¿ú */ + goto abort_game; + } + + ch = vget(3, 0, "n©ã¦h¤Ö½äª÷¡H", buf, 6, DOECHO); + j = atoi(buf); + if (!ch) + { + if (money[0] || money[1] || money[2] || money[3] || money[4]) + break; + addmoney(money[0] + money[1] + money[2] + money[3] + money[4]); /* ÁÙ¿ú */ + goto abort_game; + } + if (j < 1 || j > cuser.money) + { + addmoney(money[0] + money[1] + money[2] + money[3] + money[4]); /* ÁÙ¿ú */ + goto abort_game; + } + + money[i - '1'] += j; + cuser.money -= j; + + move(7, 15); + clrtoeol(); + outs("\033[1m"); + for (i = 0; i < 5; i++) + prints(" \033[3%dm%7d", i + 1, money[i]); + outs("\033[m"); + out_song(); + } + + /* ¶}©l¹CÀ¸ */ + move(3, 0); + clrtoeol(); + move(2, 0); + clrtoeol(); + outs("-== ½Ð«ö \033[1;36mk\033[m ¬°±z¿ïªº«l¾s¥[ªo¡A«ö \033[1;36mz\033[m ¥i¥á¥X¬µ¼u(¥u¦³¤@¦¸¾÷·|) ==-"); + + while (win < 0) + { + move(6, 15); + clrtoeol(); + outs("\033[1m"); + for (i = 0; i < 5; i++) + { + if (stop[i] < 1) + speed[i] += rnd(20) - (speed[i] + 170) / 30; + if (speed[i] < 0) + speed[i] = 0; + prints(" \033[3%dm%7d", i + 1, speed[i]); + } + outs("\033[m"); + + do + { + ch = igetch(); + } while (ch != 'k' && (ch != 'z' || bomb)); + + run = rnd(5); /* ¿ï¾Ü¨Æ¥óµo¥Í¹ï¶H */ + flag %= 5; /* ¦C¦L¨Æ¥ó©ó¿Ã¹õ¤W */ + move(15 + flag, 0); + clrtoeol(); + + if (ch == 'z') /* ¥á¬µ¼u */ + { + stop[run] = 3; + prints("\033[1m«OÄÖ²y¯{¨ì\033[3%dm%s\033[37m°±¤î«e¶i¤T¦¸¡A³t«× = 0\033[m", + run + 1, racename[run]); + speed[run] = 0; + flag++; + bomb = 1; + } + else if (rnd(12) == 0) /* ¯S®í¨Æ¥ó */ + { + prints("\033[1;3%dm%s\033[36m", run + 1, racename[run]); + + switch (rnd(14)) + { + case 0: + outs("ªA¤U«Â¦Óè¡A³t«× x1.5\033[m"); + speed[run] *= 1.5; + break; + case 1: + outs("¨Ï¥XºµªºÃzµo¤O¡A«e¶i¤®æ\033[m"); + win = race_path(run, pace[run] / 100, 5); + pace[run] += 500; + break; + case 2: + outs("½ò¨ì¦a¹p¡A³t«×´î¥b\033[m"); + speed[run] /= 2; + break; + case 3: + outs("½ò¨ì»¿¼¥Ö·ÆË¡A¼È°±¤G¦¸\033[m"); + stop[run] += 2; + break; + case 4: + outs("½Ð¯«¤W¨¡A¼È°±¥|¦¸¡A³t«×¥[¿\033[m"); + stop[run] += 4; + speed[run] *= 2; + break; + case 5: + outs("°Û¥X¤jÅ]ªk©G¡A¨Ï¨ä¥L¤H¼È°±¤T¦¸\033[m"); + for (i = 0; i < 5 && i != run; i++) + stop[i] += 3; + break; + case 6: + outs("Å¥¨£ badboy ªº¥[ªoÁn¡A³t«× +100\033[m"); + speed[run] += 100; + break; + case 7: + outs("¨Ï¥X¿ûÅKÅܨ¡A«e¶i¤T®æ¡A³t«× +30\033[m"); + win = race_path(run, pace[run] / 100, 3); + speed[run] += 30; + break; + case 8: + outs("°I¯«¤W¨³t«×´î¥b¡A®ÇÃä¼È°±¤G¦¸\033[m"); + speed[run] /= 2; + if (run > 0) + stop[run - 1] += 2; + if (run < 4) + stop[run + 1] += 2; + break; + case 9: + outs("³Q¶A©G¡A¦^¨ì°_ÂI\033[m"); + win = race_path(run, pace[run] / 100, -30); + break; + case 10: + if (pace[0] + pace[1] + pace[2] + pace[3] + pace[4] > 6000) + { + outs("\033[5m¨Ï¥X³Í¤ÆÂȳ³¡A©Ò¦³¤H¦^¨ì°_ÂI\033[m"); + for (i = 0; i < 5; i++) + win = race_path(i, pace[i] / 100, -30); + } + else + { + outs("¨Ï¥X¥øÃZ¼u¸õ¡A³t«× x1.3¡A¨ä¥L¤H´î¥b\033[m"); + for (i = 0; i < 5 && i != run; i++) + speed[i] /= 2; + speed[run] *= 1.3; + } + break; + case 11: + if (money[run]) + { + outs("¾ß¨ì«Ü¦h¿ú¡A¼È°±¤@¦¸\033[m"); + addmoney(money[run]); + out_song(); + stop[run]++; + } + else + { + outs("¾ã¤Ç°¨²n°_¨Ó¤F¡A³t«× +50\033[m"); + speed[run] += 50; + } + break; + case 12: + j = rnd(5); + prints("·R¤W¤F[3%dm%s[36m¡A³t«×¸ò¨e¤@¼Ë", j + 1, racename[j]); + speed[run] = speed[j]; + break; + case 13: + if (money[run] > 0) + { + outs("ªº½äª÷ x1.5¡AÁȰաI\033[m"); + money[run] *= 1.5; + move(7, 15); + clrtoeol(); + outs("\033[1m"); + for (i = 0; i < 5; i++) + prints(" \033[3%dm%7d ", i + 1, money[i]); + outs("\033[m"); + } + else + { + outs("¾c¤l±¼¤F¡A°h«á¤T®æ\033[m"); + race_path(run, pace[run] / 100, -3); + } + break; + } + } + else /* ©¹«e¶] */ + { + if (stop[run]) + { + prints("\033[1;3%dm%s\033[37m ª¦¤£°_¨Ó\033[m", run + 1, racename[run]); + stop[run]--; + } + else + { + prints("\033[1;3%dm%s\033[37m ©é©R©b¶]\033[m", run + 1, racename[run]); + i = pace[run] / 100; + win = race_path(run, i, (pace[run] + speed[run]) / 100 - i); + pace[run] += speed[run]; + } + } + flag++; + } + move(b_lines - 1, 0); + prints("\033[1;35m¡¹ \033[37m¹CÀ¸µ²§ô \033[35m¡¹ \033[37mÀò³Óªº¬O\033[3%dm %s \033[m", + win + 1, racename[win]); + if (money[win]) + { + money[win] += money[win] * (pace[win] - (pace[0] + pace[1] + pace[2] + pace[3] + pace[4]) / 5) / 500; + sprintf(buf, "®¥³ß±z©ã¤¤¤F¡AÀò±o¼úª÷ %d ¤¸", money[win]); + addmoney(money[win]); + } + else + { + strcpy(buf, "©êºp...±z¨S©ã¤¤£¬~~~"); + } + vmsg(buf); + } + +abort_game: + return 0; +} +#endif /* HAVE_GAME */ diff --git a/game/recall.c b/game/recall.c new file mode 100644 index 0000000..db7b5c7 --- /dev/null +++ b/game/recall.c @@ -0,0 +1,231 @@ +/*-------------------------------------------------------*/ +/* recall.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : Memory Game routines */ +/* create : 01/07/19 */ +/* update : / / */ +/* author : einstein@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + +#include "bbs.h" + +#ifdef HAVE_GAME + +enum +{ + MG_XPOS = 4, + MG_YPOS = 4, + + /* MAX_X * MAX_Y ¥²¶·¬O°¸¼Æ */ + MAX_X = 10, + MAX_Y = 10, +}; + + +static int cx, cy; +static int board[MAX_X][MAX_Y], isopen[MAX_X][MAX_Y]; +static char card[52][3] = {"¢Ï", "¢Ð", "¢Ñ", "¢Ò", "¢Ó", "¢Ô", "¢Õ", "¢Ö", "¢×", "¢Ø", + "¢Ù", "¢Ú", "¢Û", "¢Ü", "¢Ý", "¢Þ", "¢ß", "¢à", "¢á", "¢â", + "¢ã", "¢ä", "¢å", "¢æ", "¢ç", "¢è", "¢é", "¢ê", "¢ë", "¢ì", + "¢í", "¢î", "¢ï", "¢ð", "¢ñ", "¢ò", "¢ó", "¢ô", "¢õ", "¢ö", + "¢÷", "¢ø", "¢ù", "¢ú", "¢û", "¢ü", "¢ý", "¢þ", "£@", "£A", + "£B", "£C"}; + + + +static inline void +init_board() +{ + int i, j, rx, ry, temp, count = 0; + + for (i = 0; i < MAX_X; i++) + { + for (j = 0; j < MAX_Y; j++) + { + board[i][j] = (count++) / 2; + isopen[i][j] = 0; + } + } + + for (i = 0; i < MAX_X; i++) + { + for (j = 0; j < MAX_Y; j++) + { + rx = rnd(MAX_X); + ry = rnd(MAX_Y); + temp = board[i][j]; + board[i][j] = board[rx][ry]; + board[rx][ry] = temp; + } + } + + cx = 0; + cy = 0; +} + + +static void +show_board() +{ + int i, j; + + vs_bar("°O¾Ð¹CÀ¸"); + + for (i = 0; i < MAX_X; i++) + { + for (j = 0; j < MAX_Y; j++) + { + move(MG_XPOS + i, MG_YPOS + j * 2); + if (isopen[i][j]) + { + outs(card[board[i][j]]); + } + else + { + outs("¡½"); + } + } + } + + move(3, 40); + outs("¡ô¡õ¡ö¡÷ ¤è¦VÁä"); + move(5, 40); + outs("[Space][Enter] ½¶}"); + move(7, 40); + outs("Q/q Â÷¶}"); + + move(MG_XPOS + cx, MG_YPOS + cy * 2 + 1); +} + + +static inline int +valid_pos(x, y) + int x, y; +{ + if (x < 0 || x >= MAX_X || y < 0 || y >= MAX_Y) + { + return 0; + } + return 1; +} + + +static void +get_pos(x, y) + int *x, *y; +{ + char ch; + while (1) + { + ch = vkey(); + if (ch == KEY_UP && valid_pos(cx - 1, cy)) + { + cx -= 1; + move(MG_XPOS + cx, MG_YPOS + cy * 2 + 1); + } + else if (ch == KEY_DOWN && valid_pos(cx + 1, cy)) + { + cx += 1; + move(MG_XPOS + cx, MG_YPOS + cy * 2 + 1); + } + else if (ch == KEY_LEFT && valid_pos(cx, cy - 1)) + { + cy -= 1; + move(MG_XPOS + cx, MG_YPOS + cy * 2 + 1); + } + else if (ch == KEY_RIGHT && valid_pos(cx, cy + 1)) + { + cy += 1; + move(MG_XPOS + cx, MG_YPOS + cy * 2 + 1); + } + else if (ch == 'q' || ch == 'Q') + { + vmsg(MSG_QUITGAME); + *x = -1; + break; + } + else if (ch == '\n' || ch == ' ') + { + *x = cx; + *y = cy; + break; + } + } +} + + +int +main_recall() +{ + int fx, fy, sx, sy, count = 0; + + init_board(); + show_board(); + + while (1) + { + + while (1) /* ²Ä¤@¦¸ */ + { + get_pos(&fx, &fy); + if (fx < 0) + { + goto abort_game; + } + if (isopen[fx][fy]) + { + continue; + } + move(MG_XPOS + fx, MG_YPOS + 2 * fy); + outs(card[board[fx][fy]]); + move(MG_XPOS + fx, MG_YPOS + 2 * fy + 1); + isopen[fx][fy] = 1; + break; + } + + while (1) /* ²Ä¤G¦¸ */ + { + get_pos(&sx, &sy); + if (sx < 0) + { + goto abort_game; + } + if (isopen[sx][sy]) + { + continue; + } + move(MG_XPOS + sx, MG_YPOS + 2 * sy); + outs(card[board[sx][sy]]); + move(MG_XPOS + sx, MG_YPOS + 2 * sy + 1); + isopen[sx][sy] = 1; + if (board[fx][fy] == board[sx][sy]) + { + count += 2; + } + else + { + vmsg("¬Ý²M·¡¤F¨S¡H"); + move(b_lines, 0); + clrtoeol(); + move(MG_XPOS + fx, MG_YPOS + 2 * fy); + outs("¡½"); + isopen[fx][fy] = 0; + move(MG_XPOS + sx, MG_YPOS + 2 * sy); + outs("¡½"); + move(MG_XPOS + sx, MG_YPOS + 2 * sy + 1); + isopen[sx][sy] = 0; + } + break; + } + + if (count == MAX_X * MAX_Y) + { + vmsg("®¥³ß±z¦¨¥\\¤F"); + break; + } + + } +abort_game: + return 0; +} +#endif /* HAVE_GAME */ diff --git a/game/seven.c b/game/seven.c new file mode 100644 index 0000000..b876a65 --- /dev/null +++ b/game/seven.c @@ -0,0 +1,967 @@ +/*-------------------------------------------------------*/ +/* seven.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ½ä«°¤C±i¹CÀ¸ */ +/* create : 98/07/29 */ +/* update : 01/04/26 */ +/* author : weiren@mail.eki.com.tw */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#ifdef HAVE_GAME + + +static char *kind[9] = {"¯QÀs", "³æF", "¨ßF", "¤T±ø", "¶¶¤l", "¦Pªá", "¸¬Äª","ÅK¤ä", "¬h¤B"}; +static char *poker[52] = +{ + "¢±", "¢±", "¢±", "¢±", "¢²", "¢²", "¢²", "¢²", "¢³", "¢³", "¢³", "¢³", + "¢´", "¢´", "¢´", "¢´", "¢µ", "¢µ", "¢µ", "¢µ", "¢¶", "¢¶", "¢¶", "¢¶", + "¢·", "¢·", "¢·", "¢·", "¢¸", "¢¸", "¢¸", "¢¸", "¢â", "¢â", "¢â", "¢â", + "¢Ø", "¢Ø", "¢Ø", "¢Ø", "¢ß", "¢ß", "¢ß", "¢ß", "¢Ù", "¢Ù", "¢Ù", "¢Ù", + "¢Ï", "¢Ï", "¢Ï", "¢Ï" +}; + + +static void +out_song() +{ + static int count = 0; + + /* ³¯Ä¶½å£»¤ß¸õ */ + uschar *msg[8] = + { + "§A¤Sªñ¤S»· ¸ÜÁôÁô¬ù¬ù §Ú²q¤£¥X ¤]±´¤£¨ì§Aªº¤@¤Á", + "©]¥b¿ô¥bºÎ ¤ßWW²¢²¢ §Ú¨¾¤£¨ì ¤w¨«¶i¬Y¤@ºØ¦MÀI", + "¦å²GºCºCµo¼öÁyµo¿S ©I§l§Ï©»n°±¤F", + "©ú©ú¥Õ¥Õ¤£¬O³æ¯Â³ßÅw ¨º¬O·R ¨º¬O·R¶Ü", + "Å¥¨ì¦Û¤v¤ß¸õ ¬°½Ö¤ß¸õ ¹ªÁn¯ëªº¾_Àú ºòÄñµÛ§Ú¤£¯à©ñ", + "¦h·Q §â¤ß¥æ´« §A´N¯à¼Æºâ §A´N·|©úÁA ¤ß¸õ ¤À¤À¬í", + "¦å²GºCºCµo¼öÁyµo¿S ©I§l§Ï©»n°±¤F", + "©ú©ú¥Õ¥Õ¤£¬O³æ¯Â³ßÅw ²ö«D´N¬O·R ²ö«D¬O·R" + }; + move(b_lines - 2, 0); + prints("\033[1;3%dm%s\033[m Äw½XÁÙ¦³ %d ¤¸", time(0) % 7, msg[count], cuser.money); + clrtoeol(); + if (++count == 8) + count = 0; +} + + +static inline int +find_pair(set) /* ¦³ Pair ´N¶Ç¦^ 1 */ + int set[6]; +{ + int i, j; + + for (i = 0; i < set[5] - 1; i++) + { + for (j = i + 1; j < set[5]; j++) + { + if (set[j] / 4 == set[i] / 4) + return 1; + } + } + return 0; +} + + +static inline int +find_tpair(set) /* Two Pair ¶Ç¦^ 1 */ + int set[6]; +{ + int i, j, k; + int z[13] = {0}; + + for (i = 0; i < 13; i++) + { + for (j = 0; j < 5; j++) + { + if (set[j] / 4 == i) + z[i]++; + } + } + k = 0; + for (i = 0; i < 13; i++) + { + if (z[i] >= 2) + k++; + } + if (k == 2) + return 1; + return 0; +} + + +static inline int +find_triple(set) /* ¤T±ø¶Ç¦^ 3, ÅK¤ä¶Ç¦^ 4 */ + int set[6]; +{ + int i, j, k; + + for (i = 0; i < 13; i++) + { + k = 0; + for (j = 0; j < 5; j++) + { + if (set[j] / 4 == i) + k++; + } + if (k == 4) + return 4; + if (k == 3) + return 3; + } + return 0; +} + + +static inline int +find_dragon(set) /* ¶¶¶Ç¦^ 1, §_«h¶Ç¦^ 0 */ + int set[6]; +{ + int i; + int test[6]; + + for (i = 0; i < 5; i++) + test[i] = set[i] / 4; + + for (i = 0; i < 3; i++) + { + if (test[i] + 1 != test[i + 1]) + return 0; + } + + if (test[4] == 12 && test[0] == 0) + return 1; /* A2345 ¶¶ */ + + if (test[3] + 1 == test[4]) + return 1; /* ¤@¯ë¶¶ */ + return 0; +} + + +static inline int +find_flush(set) /* ¦Pªá¶Ç¦^ 1, §_«h¶Ç¦^ 0 */ + int set[6]; +{ + int i; + int test[6]; + + for (i = 0; i < 5; i++) + test[i] = set[i] % 4; + + for (i = 1; i < 5; i++) + { + if (test[0] != test[i]) + return 0; + } + + return 1; +} + + +static int +find_all(set) + int set[6]; +{ + int i; + int a[9]; /* ¯QÀs, F , ¨ßF, ¤T±ø, ¶¶, ¦Pªá, J¿c, ÅK¤ä, ¦Pªá¶¶ */ + + a[0] = 1; /* a[0] 1 2 3 4 5 6 7 a[8] */ + + for (i = 1; i < 9; i++) + a[i] = 0; + + a[1] = find_pair(set); + a[2] = find_tpair(set); + + switch (find_triple(set)) + { + case 3: + a[3] = 1; + break; + + case 4: + a[7] = 1; + break; + } + + a[4] = find_dragon(set); + a[5] = find_flush(set); + + if (a[2] && a[3]) + a[6] = 1; /* ¨ßF + ¤T±ø = J¿c */ + if (a[4] && a[5]) + a[8] = 1; /* ¦Pªá + ¶¶ = ¦Pªá¶¶ */ + + for (i = 8; i >= 0; i--) + if (a[i]) + return i; +} + + +static inline int +diedragon(set, a, b) + int set[6]; + int a, b; +{ + int card[13] = {0}; + int first[2]; + int i, z; + + first[0] = a; + first[1] = b; + z = find_all(set); + + if (!z) + { /* ²Ä¤G°ô¯QÀs */ + if (first[0] / 4 == first[1] / 4) + return 1; + if (first[1] / 4 > set[4] / 4) + return 1; + if (first[1] / 4 == set[4] / 4) + { + if (first[0] / 4 > set[3] / 4) + return 1; + } /* ËÀs */ + } + + else if (z == 1) /* F */ + { + for (i = 0; i < 5; i++) + card[set[i] / 4]++; + + for (i = 0; i < 13; i++) + { + if (card[i] == 2 && first[0] / 4 == first[1] / 4 && first[0] / 4 > i) + return 1; /* ¨â°ô³£³æF¥BËÀs */ + } + } + return 0; +} + + +static inline int +bigsmall(h, g, key, gm) + int h[7], g[7], key, gm[2]; +{ + int hm[2]; + int i, j, k = 0, tmp = 0, tmp2 = 0, x, a, b; + int duA = 0, duB = 0; /* duA duB ¬O¨â°ô§P©w¿éĹ°Ñ¼Æ, 1 ¬O¹q¸£Ä¹ */ + int hset[6], gset[6]; /* host, guest */ + int gc[13] = {0}, hc[13] = {0}; + + for (i = 0; i < 6; i++) + { + for (j = i + 1; j < 7; j++) + { + if (key == k) + { + hm[0] = i; + hm[1] = j; + }; + k++; + } + } + + if (hm[1] < hm[0]) + { + k = hm[1]; + hm[1] = hm[0]; + hm[0] = k; + } + + if (gm[1] < gm[0]) + { + k = gm[1]; + gm[1] = gm[0]; + gm[0] = k; + } + + if (h[hm[0]] / 4 == h[hm[1]] / 4) + tmp = 1; + if (g[gm[0]] / 4 == g[gm[1]] / 4) + tmp2 = 1; + if (tmp == tmp2) + { + if (h[hm[1]] / 4 > g[gm[1]] / 4) + duA = 1; /* duA=1 ªí¥Ü²Ä¤@°ô²ø®aĹ */ + if (h[hm[1]] / 4 == g[gm[1]] / 4 && tmp == 1) + duA = 1; /* ²Ä¤@°ô³£F¥B¥¤â, ²ø®aĹ */ + if (h[hm[1]] / 4 == g[gm[1]] / 4 && tmp == 0 && h[hm[0]] / 4 >= g[gm[0]] / 4) + duA = 1; + } + if (tmp > tmp2) + duA = 1; + if (tmp < tmp2) + duA = 0; + k = 0; + j = 0; + + for (i = 0; i < 7; i++) + { + if (i != hm[0] && i != hm[1]) + { + hset[j] = h[i]; + j++; + } + if (i != gm[0] && i != gm[1]) + { + gset[k] = g[i]; + k++; + } + } + + hset[5] = 5; + gset[5] = 5; + tmp = find_all(hset); + tmp2 = find_all(gset); + + if (tmp > tmp2) + { + duB = 1; + } + else if (tmp == tmp2) + { + for (i = 0; i < 5; i++) + { + gc[gset[i] / 4]++; + hc[hset[i] / 4]++; + } + switch (tmp) + { + case 0: + i = 12; + x = 0; + duB = 1; /* ¨â¤è³£¬O¯QÀs */ + do + { + if (hc[i] > gc[i]) + { + duB = 1; + x = 1; + } + if (hc[i] < gc[i]) + { + duB = 0; + x = 1; + } + i--; + if (i < 0) + x = 1; + } while (x == 0); + break; + + case 1: + for (i = 0; i < 12; i++) + { + if (hc[i] == 2) + a = i; + if (gc[i] == 2) + b = i; + } + if (a > b) + { + duB = 1; /* ¨â¤è³£¬OF */ + } + else if (a == b) + { + i = 12; + j = 12; + x = 0; + duB = 1; + do + { + if (hc[i] == 2) + i--; + if (hc[j] == 2) + j--; + if (hc[i] > gc[j]) + { + duB = 1; + x = 1; + } + if (hc[i] < gc[j]) + { + duB = 0; + x = 1; + } + i--; + j--; + if (i < 0 || j < 0) + x = 1; + } while (x == 0); + } + break; + + case 2: + i = 12; + x = 0; + duB = 2; /* ¨â¤è³£¬O¨ßF */ + do + { + if (hc[i] > gc[i] && hc[i] != 1) + { + duB = 1; + x = 1; + }; + if (hc[i] < gc[i] && gc[i] != 1) + { + duB = 0; + x = 1; + }; + i--; + if (i < 0) + x = 1; + } while (x == 0); + if (duB == 2) + { + for (i = 0; i < 12; i++) + { + if (hc[i] == 1) + a = i; + if (gc[i] == 1) + b = i; + } + duB = 1; + if (a < b) + duB = 0; + } + break; + + case 3: + case 6: + for (i = 0; i < 12; i++) + { + if (hc[i] == 3) + a = i; + if (gc[i] == 3) + b = i; + } + if (a > b) + duB = 1; /* ¨â¤è³£¬O¤T±ø(J¿c) */ + else if (a < b) + duB = 0; + break; + + case 4: + i = 12; + x = 0; + a = 0; + b = 0; /* ¨â¤è³£¬O¶¶¤l */ + do + { + if (hc[i] > gc[i]) + { + duB = 1; + x = 1; + } + if (hc[i] < gc[i]) + { + duB = 0; + x = 1; + } + i--; + if (i < 0) + { + duB = 1; + x = 1; + } + } while (x == 0); + + if (hc[12] == hc[0] && hc[0] == 1) + a = 1; + if (gc[12] == gc[0] && gc[0] == 1) + b = 1; + if (a > b) + duB = 0; + if (a < b) + duB = 1; + if (a == b && b == 1) + duB = 1; + break; + + case 5: + if (hset[0] % 4 > gset[0] % 4) + duB = 1; /* ¨â¤è³£¬O¦Pªá */ + if (hset[0] % 4 < gset[0] % 4) + duB = 0; + if (hset[0] % 4 == gset[0] % 4) + { + if (hset[4] > gset[4]) + duB = 1; + if (hset[4] < gset[4]) + duB = 0; + } + break; + + case 7: + for (i = 0; i < 12; i++) + { + if (hc[i] == 4) + a = i; + if (gc[i] == 4) + b = i; + } + if (a > b) + duB = 1; /* ¨â¤è³£¬OÅK¤ä */ + if (a < b) + duB = 0; + break; + + case 8: + if (hset[0] % 4 > gset[0] % 4) + duB = 1; /* ¨â¤è³£¬O¦Pªá¶¶ */ + if (hset[0] % 4 < gset[0] % 4) + duB = 0; + if (hset[0] % 4 == gset[0] % 4) + { + i = 12; + x = 0; + do + { + if (hc[i] > gc[i]) + { + duB = 1; + x = 1; + } + if (hc[i] < gc[i]) + { + duB = 0; + x = 1; + } + i--; + if (i < 0) + { + duB = 1; + x = 1; + } + } while (x == 0); + } + break; + } + } + return 2 * duA + duB; +} + + +static void +print_Scard(card, x, y) + int card, x, y; +{ + char *flower[4] = {"¢Ñ", "¢Ò", "¢Ö", "¢á"}; + + move(x, y); + outs("¢~¢w¢w¢w¢¡"); + move(x + 1, y); + prints("¢x%s ¢x", poker[card]); + move(x + 2, y); + prints("¢x%s ¢x", flower[card % 4]); + move(x + 3, y); + outs("¢x ¢x"); + move(x + 4, y); + outs("¢x ¢x"); + move(x + 5, y); + outs("¢x ¢x"); + move(x + 6, y); + outs("¢¢¢w¢w¢w¢£"); +} + + +static inline void +print_hostcard(card, x) /* x ¬°¨â±iªº²Õ¦X key */ + int card[7]; + int x; +{ + int i, j, k = 0; + int tmp, tmp2; + int set[6]; + + for (i = 1; i < 6; i++) + { + move(5 + i, 0); + clrtoeol(); + } + + for (i = 0; i < 6; i++) + { + for (j = i + 1; j < 7; j++) + { + if (x == k) + { + tmp = i; + tmp2 = j; + }; + k++; + } + } + + print_Scard(card[tmp], 3, 0); + print_Scard(card[tmp2], 3, 4); + + j = 0; + for (i = 0; i < 7; i++) + { + if (i != tmp && i != tmp2) + { + print_Scard(card[i], 3, 16 + j * 4); + set[j] = card[i]; + j++; + } + } + set[5] = 5; + move(7, 4); + if (card[tmp] / 4 == card[tmp2] / 4) + x = 1; + prints("\033[1;44;33m %s%s \033[m ¢x ¢x \033[1;44;33m %s \033[m", + poker[card[tmp]], x == 1 ? "F" : poker[card[tmp2]] ,kind[find_all(set)]); +} + + +static inline int +score(first, set) /* ¦^¶Ç¤À¨â°ô«áªºµû¤À(AI), ¹q¸£·|§â 21 ºØµP«¬³£©î¥X¨Ó, ¨úµû¤À°ªªÌ */ + int first[2], set[6]; +{ + int i, z; + int points = 0; + int card[13] = {0}; + + z = find_all(set); + if (z == 0) + { + if (first[0] / 4 == first[1] / 4) + return 0; + if (first[1] / 4 >= set[4] / 4) + return 0; /* ËÀs */ + } + else if (z == 1) + { + for (i = 0; i < 5; i++) + card[set[i] / 4]++; + for (i = 0; i < 13; i++) + { + if (card[i] == 2 && first[0] / 4 == first[1] / 4 && first[0] / 4 >= i) + return 0; /* ¨â°ô³£³æF¥BËÀs */ + } + } + + points = z + 2; /* ²Ä¤G°ô¯QÀs´Nºâ¨â¤À, ¥H¤W»¼¼W */ + if (points >= 5) + points ++; /* ²Ä¤G°ôY¦³¶¶¥H¤W¦A¥[¤@¤À */ + if (first[0] / 4 == first[1] / 4) + points += 3; /* ²Ä¤@°ô¦³F¤À¼Æ¥[¤T */ + if (first[0] / 4 != first[1] / 4 && first[1] / 4 >= 10) + points++; + /* ²Ä¤@°ôµLF¦³ Q ¥H¤W¥[¤@¤À */ + if (first[0] / 4 == 12 || first[1] / 4 == 12) + points += 1; /* ²Ä¤@°ô¦³ A ¤À¼Æ¦A¥[¤@ */ + return points; +} + + +static inline int +find_host(h) /* ¶Ç¦^¨â±iªº²Õ¦X key */ + int h[7]; +{ + int i, j, k, x = 0, z = 0; + int tmp = 0, tmp2 = 0; + int result[21] = {0}, set[6] = {0}, first[2]; + + for (i = 0; i < 6; i++) + { + for (j = i + 1; j < 7; j++) + { + first[0] = h[i]; + first[1] = h[j]; + x = 0; + for (k = 0; k < 7; k++) + { + if (i != k && j != k) + { + set[x] = h[k]; + x++; + } + } + set[5] = 5; + result[z] = score(first, set); + z++; + } + } + for (i = 0; i < 21; i++) + { + if (result[i] >= tmp) + { + tmp = result[i]; + tmp2 = i; + } + } + return tmp2; +} + + +static int +get_newcard(mode) + int mode; /* 0:«·s¬~µP 1:µoµP */ +{ + static int card[14]; /* ³Ì¦h¥u·|¥Î¨ì 14 ±iµP */ + static int now; /* µo¥X²Ä now ±iµP */ + char num; + int i; + + if (!mode) /* «·s¬~µP */ + { + now = 0; + return -1; + } + +rand_num: /* random ¥X¤@±i©M¤§«e³£¤£¦PªºµP */ + num = rnd(52); + for (i = 0; i < now; i++) + { + if (num == card[i]) /* ³o±iµP¥H«e random ¹L¤F */ + goto rand_num; + } + + card[now] = num; + now++; + + return num; +} + + +int +main_seven() +{ + int money; /* ©ãª÷ */ + int host_card[7]; /* ¹q¸£ªº 7 ±iµP±i */ + int guest_card[7]; /* ª±®aªº 7 ±iµP±i */ + int mark[2]; /* ª±®a¼Ð°O¥Î */ + int set[6]; + + int i, j, win; + char buf[10]; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + while (1) + { + vs_bar("½ä«°¤C±i"); + out_song(); + + vget(2, 0, "½Ð°Ýn¤Uª`¦h¤Ö©O¡H(1 ~ 50000) ", buf, 6, DOECHO); + money = atoi(buf); + if (money < 1 || money > 50000 || money > cuser.money) + break; /* Â÷¶}½ä³õ */ + + cuser.money -= money; + + out_song(); + + move(2, 0); + clrtoeol(); /* ²M±¼¡u½Ð°Ýn¤Uª`¦h¤Ö¡v */ + outs("(«ö ¡ö¡÷ ²¾°Ê¡A«ö ¡ô¡õ ¿ï¨ú¤G±iµP¡A¿ï¦n«ö enter ÅuµP)"); + + get_newcard(0); /* ¬~µP */ + + mark[0] = mark[1] = 123; /* mark[?] = 123 ªí¥Ü¨S¦³ mark */ + + /* µo¤Q¥|±iµP */ + for (i = 0; i < 7; i++) + { + host_card[i] = get_newcard(1); + guest_card[i] = get_newcard(1); + } + + /* ±Æ§Ç */ + for (i = 0; i < 7; i++) + { + for (j = 0; j < (6 - i); j++) + { + /* ɥΠwin */ + if (guest_card[j] > guest_card[j + 1]) + { + win = guest_card[j]; + guest_card[j] = guest_card[j + 1]; + guest_card[j + 1] = win; + } + if (host_card[j] > host_card[j + 1]) + { + win = host_card[j]; + host_card[j] = host_card[j + 1]; + host_card[j + 1] = win; + } + } + } + + /* ¦L¥X¤â¤WªºµP */ + move(3, 0); + outs("¢~¢w¢~¢w¢~¢w¢~¢w¢~¢w¢~¢w¢~¢w¢w¢w¢¡\n"); + outs("¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x\n"); + outs("¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x\n"); + outs("¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x\n"); + outs("¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x\n"); + outs("¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x\n"); + outs("¢¢¢w¢¢¢w¢¢¢w¢¢¢w¢¢¢w¢¢¢w¢¢¢w¢w¢w¢£"); + for (i = 0; i < 7; i++) + print_Scard(guest_card[i], 11, 0 + 4 * i); + + i = j = 0; + for (;;) /* ¿ï¥X¤G±iµP */ + { + /* ¦b¦¹°j°é¤º¡Ai ¬O²Ä´X±iµP¡Aj ¬O¤w¿ï¨ú¤F´X±iµP */ + move(15, 1 + i * 4); + switch (vkey()) + { + case KEY_RIGHT: + if (i < 6) + i++; + break; + + case KEY_LEFT: + if (i > 0) + i--; + break; + + case KEY_UP: /* ¿ï¨ú³o±iµP */ + if (j < 2 && mark[0] != i && mark[1] != i) /* ¤£¯à«ÂÐ mark ¥B³Ì¦h mark ¤G±i */ + { + if (mark[0] == 123) + mark[0] = i; + else + mark[1] = i; + j++; + move(15, 2 + i * 4); + outs("¡´"); + } + break; + + case KEY_DOWN: /* ¨ú®ø¿ï¨ú³o±iµP */ + if (mark[0] == i) + { + mark[0] = 123; + j--; + move(15, 2 + i * 4); + outs(" "); + } + else if (mark[1] == i) + { + mark[1] = 123; + j--; + move(15, 2 + i * 4); + outs(" "); + } + break; + + case '\n': /* ¿ï¥X¨â±i«á«ö enter */ + if (j == 2) + goto end_choose; + break; + } + } + end_choose: + + if (mark[0] > mark[1]) + { + i = mark[0]; + mark[0] = mark[1]; + mark[1] = i; + } + + /* ¦L¥Xª±®a¤À¦n¨â°ô«áªºµP */ + for (i = 1; i < 18; i++) + { + move(i, 0); + clrtoeol(); + } + print_Scard(guest_card[mark[0]], 11, 0); + print_Scard(guest_card[mark[1]], 11, 4); + + j = 0; + for (i = 0; i < 7; i++) + { + if (i != mark[0] && i != mark[1]) + { + print_Scard(guest_card[i], 11, 16 + j * 4); + set[j] = guest_card[i]; + j++; + } + } + + /* §PÂ_¬O§_ËÀs¡AYËÀs«hµ²§ô */ + set[5] = 5; + if (diedragon(set, guest_card[mark[0]], guest_card[mark[1]])) + { + vmsg("ËÀs"); + continue; + } + + /* §PÂ_³Ót */ + i = find_host(host_card); + print_hostcard(host_card, i); + win = bigsmall(host_card, guest_card, i, mark); + + /* ¨q¥Xµ²ªG */ + switch (win) + { + /* ɥΠi ¨Ó·í°µ color1; ɥΠj ¨Ó·í°µ color2 */ + + case 0: /* ª±®a duA duB ¬ÒĹ */ + win = 2; + i = 41; + j = 41; + break; + + case 1: /* ª±®a duA Ĺ duB ¿é */ + win = 1; + i = 41; + j = 47; + break; + + case 2: /* ª±®a duA ¿é duB Ĺ */ + win = 1; + i = 47; + j = 41; + break; + + case 3: /* ª±®a duA duB ¬Ò¿é */ + win = 0; + i = 47; + j = 47; + break; + } + + move(15, 4); + prints("\033[1;%d;%dm %s%s \033[m ¢x ¢x \033[1;%d;%dm %s \033[m", + i, i == 41 ? 33 : 30, poker[guest_card[mark[0]]], + (guest_card[mark[0]] / 4 == guest_card[mark[1]] / 4) ? "F" : poker[guest_card[mark[1]]], + j, j == 41 ? 33 : 30, kind[find_all(set)]); + + switch (win) + { + case 2: + vmsg("±zŤF"); + money *= 2; + break; + + case 1: + vmsg("¥¤â"); + break; + + case 0: + vmsg("±z¿é¤F"); + money = 0; + break; + } + addmoney(money); + } + return 0; +} +#endif /* HAVE_GAME */ diff --git a/game/tetris.c b/game/tetris.c new file mode 100644 index 0000000..817b028 --- /dev/null +++ b/game/tetris.c @@ -0,0 +1,446 @@ +/*-------------------------------------------------------*/ +/* tetris.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : «Xù´µ¤è¶ô */ +/* create : / / */ +/* update : 02/10/15 */ +/* author : zhch.bbs@bbs.nju.edu.cn */ +/* modify : hightman.bbs@bbs.hightman.net */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#define MAX_MAP_WIDTH 10 /* ´Ñ½Lªº¼e«×¦@ 10 ¦æ */ +#define MAX_MAP_HEIGHT 20 /* ´Ñ½Lªº°ª«×¦@ 20 ¦C */ +#define MAX_STYLE 7 /* Á`¦@¦³ 7 ºØÃþ«¬ªº¤è¶ô */ + + +/* ¨CºØ¤è¶ô³£¬O 4*4 ªº¡AµM«á¥i¥HÂà 4 Ó¤è¦V */ + +static int style_x[MAX_STYLE][4][4] = +{ + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 2, 3, 1, 1, 1, 1, 0, 1, 2, 3, 1, 1, 1, 1, + 0, 1, 1, 2, 1, 0, 1, 0, 0, 1, 1, 2, 1, 0, 1, 0, + 1, 2, 0, 1, 0, 0, 1, 1, 1, 2, 0, 1, 0, 0, 1, 1, + 0, 1, 2, 0, 0, 1, 1, 1, 2, 0, 1, 2, 0, 0, 0, 1, + 0, 1, 2, 2, 1, 1, 0, 1, 0, 0, 1, 2, 0, 1, 0, 0, + 0, 1, 2, 1, 1, 0, 1, 1, 1, 0, 1, 2, 0, 0, 1, 0 +}; + +static int style_y[MAX_STYLE][4][4] = +{ + 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, + 1, 1, 1, 1, 0, 1, 2, 3, 1, 1, 1, 1, 0, 1, 2, 3, + 0, 0, 1, 1, 0, 1, 1, 2, 0, 0, 1, 1, 0, 1, 1, 2, + 0, 0, 1, 1, 0, 1, 1, 2, 0, 0, 1, 1, 0, 1, 1, 2, + 0, 0, 0, 1, 0, 0, 1, 2, 0, 1, 1, 1, 0, 1, 2, 2, + 0, 0, 0, 1, 0, 1, 2, 2, 0, 1, 1, 1, 0, 0, 1, 2, + 0, 0, 0, 1, 0, 1, 1, 2, 0, 1, 1, 1, 0, 1, 1, 2 +}; + + +static int map[MAX_MAP_HEIGHT + 1][MAX_MAP_WIDTH + 2]; + +static int my_lines; /* Á`®ø¥h±ø¼Æ */ +static int my_scores; /* Á`±o¤À */ +static int level; /* Ãö¥d */ +static int delay; /* ¤è¶ô¦Û°Ê¤U¶^ªº®É¶¡¶¡¶Z (³æ¦ì:usec) */ +static int cx, cy; /* ¥Ø«e©Ò¦b (x, y) */ +static int style; /* ¥Ø«e¤è¶ôªºÃþ«¬ */ +static int dir; /* ¥Ø«e¤è¶ôªº¤è¦V */ +static int last_dir; /* ¤W¦¸¤è¦Vªº¤è¦V */ + + +static void +move_map(x, y) + int x, y; +{ + move(x + 2, 2 * y); +} + + +static void +tetris_welcome() +{ + move(4, 33); + outs("«öÁ仡©ú¡G"); + move(5, 35); + outs("¡õ¡ö¡÷ ²¾°Ê¤è¦V"); + move(6, 35); + outs("Space §Ö³t°¤U"); + move(7, 35); + outs("¡ô 180 «×±ÛÂà"); + move(8, 35); + outs("k ¶¶®É°w±ÛÂà"); + move(9, 35); + outs("j °f®É°w±ÛÂà"); + move(10, 35); + outs("^S ¼È°±¹CÀ¸"); + move(11, 35); + outs("q Â÷¶}¹CÀ¸"); + + move(13, 35); + outs("Y´å¼Ð¦³²¾°Ê¿ù»~ªº²{¶H"); + move(14, 35); + outs("¼È®É±N°»´ú¤è¦VÁä¥þ§ÎÃö³¬§Y¥i"); + + move(16, 33); + outs("¨C®ø¢²¢¯±ø¤É¤@¯Å"); + move(17, 33); + outs("®ø¤@¦æ±o¢°¤À¡B¤G¦æ¢²¤À¡B¤T¦æ¢¶¤À¡B¥|¦æ¢°¢´¤À"); + + vmsg(NULL); +} + + +static void +tetris_init() /* initialize map[][] */ +{ + int i, j, line; + + line = MAX_MAP_HEIGHT - level; /* ¨Ìµ¥¯Å¨Ó¨M©w¦³´X¦æ¦³ªF¦è */ + + /* map[][] ¸Ì±ªºÈ 0:ªÅ¥Õ( ) 1:¦ûº¡(¢i) 2:¥ª¥k¬É(¢x) 3:©³¬É(¢w) 4:¥ª¨¤¸¨¬É(¢|) 5:¥k¨¤¸¨¬É(¢}) */ + + for (i = 0; i < MAX_MAP_HEIGHT; i++) + { + for (j = 1; j <= MAX_MAP_WIDTH; j++) + { + if (i >= line) + map[i][j] = rnd(2); /* ¦ûº¡ */ + else + map[i][j] = 0; /* ªÅ¥Õ */ + } + map[i][0] = map[i][MAX_MAP_WIDTH + 1] = 2; /* ¥ª¥k¬É */ + } + + for (j = 1; j <= MAX_MAP_WIDTH; j++) + map[MAX_MAP_HEIGHT][j] = 3; /* ©³¬É */ + + map[MAX_MAP_HEIGHT][0] = 4; /* ¥ª¨¤¸¨¬É */ + map[MAX_MAP_HEIGHT][MAX_MAP_WIDTH + 1] = 5; /* ¥ª¨¤¸¨¬É */ +} + + +static void +tetris_mapshow() +{ + int i, j; + char piece[6][3] = {" ", "¢i", "¢x", "¢w", "¢|", "¢}"}; + + /* map[][] ¸Ì±ªºÈ 0:ªÅ¥Õ( ) 1:¦ûº¡(¢i) 2:¥ª¥k¬É(¢x) 3:©³¬É(¢w) 4:¥ª¨¤¸¨¬É(¢|) 5:¥k¨¤¸¨¬É(¢}) */ + + for (i = 0; i <= MAX_MAP_HEIGHT; i++) + { + move_map(i, 0); + for (j = 0; j <= MAX_MAP_WIDTH + 1; j++) + outs(piece[map[i][j]]); + } +} + + +static void +tetris_blineshow() +{ + move(b_lines, 0); + clrtoeol(); + prints("µ¥¯Å¡G\033[1;32m%d\033[m Á`®ø¥h±ø¼Æ¡G\033[1;32m%d\033[m Á`±o¤À¡G\033[1;32m%d\033[m", + level, my_lines, my_scores); +} + + +static void +block_show(x, y, s, d, f) + int x, y; /* (x, y) */ + int s; /* style */ + int d; /* dir */ + int f; /* 1:¥[¤W¤è¶ô 0:²¾°£¤è¶ô */ +{ + int n; + + if (d == -1) + return; + + for (n = 0; n <= 3; n++) + { + move_map(x + style_x[s][d][n], y + style_y[s][d][n]); + if (f) + outs("¢i"); /* piece[1] */ + else + outs(" "); /* piece[0] */ + } + move(1, 0); +} + + +static void +block_move() +{ + static int last_x = -1; + static int last_y = -1; + static int last_style = -1; + + if (last_x == cx && last_y == cy && last_style == style && last_dir == dir) + return; + + block_show(last_x, last_y, last_style, last_dir, 0); + last_x = cx; + last_y = cy; + last_style = style; + last_dir = dir; + block_show(cx, cy, style, dir, 1); +} + + +static void +tune_delay() +{ + /* delay n¦b 1 ~ 999999 ¤§¶¡ */ + delay = 999999 / (level + 1); +} + + +static void +check_lines() /* Àˬd¬Ý¬O§_¯à®ø¥h¤@±ø */ +{ + int i, j, s; + + s = 1; + for (i = 0; i < MAX_MAP_HEIGHT; i++) + { + for (j = 1; j <= MAX_MAP_WIDTH; j++) + { + if (map[i][j] == 0) /* ªÅ¥Õ */ + break; + } + + if (j == MAX_MAP_WIDTH + 1) + { + int n; + + s *= 2; + /* ®ø¥h±ø¤W³¡¥þ³¡¤U²¾ */ + for (n = i; n > 0; n--) + { + for (j = 1; j <= MAX_MAP_WIDTH; j++) + map[n][j] = map[n - 1][j]; + } + for (j = 1; j <= MAX_MAP_WIDTH; j++) + map[0][j] = 0; + + if (++my_lines % 30 == 0) /* ¨C®ø 30 ±øÃö¥d¥[¤@ */ + { + level++; + tune_delay(); + } + } + } + + if (--s > 0) /* ¦³®ø¥h¦Ü¤Ö¤@±ø */ + { + s = s * (10 + level) / 10; + my_scores += s; + tetris_mapshow(); + tetris_blineshow(); + } +} + + +static int /* 1:¸I¨ì»Ùꪫ 0:³q¦æµLªý */ +crash(x, y, s, d) + int x, y; /* (x, y) */ + int s; /* style */ + int d; /* dir */ +{ + int n; + + for (n = 0; n <= 3; n++) + { + if (map[x + style_x[s][d][n]][y + style_y[s][d][n]]) /* ¤w¦ûº¡ */ + return 1; + } + return 0; +} + + +static void +arrived() +{ + int n; + + for (n = 0; n <= 3; n++) + map[cx + style_x[style][dir][n]][cy + style_y[style][dir][n]] = 1; /* ¦ûº¡ */ + + check_lines(); +} + + +static int +getkey() +{ + int fd; + struct timeval tv; + + fd = 1; + tv.tv_sec = 0; + tv.tv_usec = delay; + + /* Y¦³«öÁä¡A¦^¶Ç©Ò«öªºÁä¡FY delay ªº®É¶¡¨ì¤F¤´¨S¦³«öÁä¡A¦^¶Ç 0 */ + + if (select(1, (fd_set *) &fd, NULL, NULL, &tv) > 0) + return vkey(); + + return 0; +} + + +int +main_tetris() +{ + int ch; + int next_style; + + vs_bar("«Xù´µ¤è¶ô"); + tetris_welcome(); + +start_game: + + level = vans("±q²Ä´X¯Å¶}©lª±(0-9)¡H[0] ") - '0'; + if (level < 0 || level > 9) + level = 0; + + tetris_init(); + tetris_mapshow(); + + vmsg("¹CÀ¸¶}©l"); + tetris_blineshow(); + + style = 0; + next_style = rnd(MAX_STYLE); + my_lines = my_scores = 0; + tune_delay(); + + while (1) + { + style = next_style; + next_style = rnd(MAX_STYLE);/* ¶Ã¼Æ¨M©w¤U¤@Ó¥X¨Óªº¤è¶ôÃþ«¬ */ + last_dir = -1; /* ¨C¦¸·s¤è¶ô¥X¨Ó³£n«³]¬° -1 */ + dir = 0; /* ¤è¶ô¤@¥X¨Ó¬O´Â¤Wªº */ + cx = 0; /* ¤è¶ô¤@¥X¨Óªº¦ì¸m */ + cy = MAX_MAP_WIDTH / 2; + + /* §â¤W¤@Ó¤w¥X¨Óªº²M°£¡A§â¤U¤@Ón¥X¨Óªºµe¦b¥k¤W¨¤ */ + block_show(0, MAX_MAP_WIDTH + 2, style, dir, 0); + block_show(0, MAX_MAP_WIDTH + 2, next_style, dir, 1); + + block_move(); + + if (crash(cx, cy, style, dir)) /* ·s¤è¶ô¤@¥X¨Ó´N crash¡Agame over */ + break; + + for (;;) + { + switch (ch = getkey()) + { + case Ctrl('S'): + vmsg("¹CÀ¸¼È°±¡A«ö¥ô·NÁäÄ~Äòª±"); + tetris_blineshow(); + break; + + case KEY_LEFT: + if (!crash(cx, cy - 1, style, dir)) + { + cy--; + block_move(); + } + break; + + case KEY_RIGHT: + if (!crash(cx, cy + 1, style, dir)) + { + cy++; + block_move(); + } + break; + + case KEY_DOWN: + if (!crash(cx + 1, cy, style, dir)) + { + cx++; + block_move(); + } + else + { + arrived(); + ch = '#'; + } + break; + + case KEY_UP: + if (!crash(cx, cy, style, (dir + 2) % 4)) + { + dir = (dir + 2) % 4; + block_move(); + } + break; + + case 'k': + if (!crash(cx, cy, style, (dir + 1) % 4)) + { + dir = (dir + 1) % 4; + block_move(); + } + break; + + case 'j': + if (!crash(cx, cy, style, (dir + 3) % 4)) + { + dir = (dir + 3) % 4; + block_move(); + } + break; + + case ' ': + while (!crash(cx + 1, cy, style, dir)) + cx++; + block_move(); + arrived(); + ch = '#'; + break; + + case 0: /* ÀH delay ®É¶¡¤@¨ì·|¦Û°Ê©¹¤U¸õ */ + if (!crash(cx + 1, cy, style, dir)) + { + cx++; + block_move(); + } + else + { + arrived(); + ch = '#'; + break; + } + break; + } + + if (ch == 'q' || ch == '#') + break; + + refresh(); + } /* end of for (;;) */ + + if (ch == 'q') + break; + } /* end of while (1) */ + + if (vans("¥»§½µ²§ô¡I±zÁÙnÄ~Äòª±¶Ü(Y/N)¡H[N] ") == 'y') + goto start_game; + + return 0; +} +#endif /* HAVE_GAME */ diff --git a/include/attr.h b/include/attr.h new file mode 100644 index 0000000..8905a48 --- /dev/null +++ b/include/attr.h @@ -0,0 +1,30 @@ +/*-------------------------------------------------------*/ +/* attr.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : dynamic attribute database */ +/* create : 99/03/11 */ +/* update : / / */ +/*-------------------------------------------------------*/ + + +#ifndef _ATTR_H_ +#define _ATTR_H_ + +#if 0 + int key; + key < 0 is reserved. + key & 0xff == 0 is reserved. + 0x000000?? < key < 0x0000ff?? is reserved by maple.org + sizeof(attr): key & 0xff + + file: $userhome/.ATTR +#endif + +#define ATTR_OTHELLO_TOTAL 0x00001004 +#define ATTR_FIVE_TOTAL 0x00001104 +#define ATTR_BLOCK_TOTAL 0x00001204 +#define ATTR_OTHELLO_WIN 0x00001404 +#define ATTR_FIVE_WIN 0x00001504 +#define ATTR_BLOCK_WIN 0x00001604 + +#endif diff --git a/include/battr.h b/include/battr.h new file mode 100644 index 0000000..1f4aff4 --- /dev/null +++ b/include/battr.h @@ -0,0 +1,104 @@ +/*-------------------------------------------------------*/ +/* battr.h ( NTHU CS MapleBBS Ver 2.36 ) */ +/*-------------------------------------------------------*/ +/* target : Board Attribution */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ + + +#ifndef _BATTR_H_ +#define _BATTR_H_ + + +/* ----------------------------------------------------- */ +/* Board Attribution : flags in BRD.battr */ +/* ----------------------------------------------------- */ + + +#define BRD_NOZAP 0x01 /* ¤£¥i zap */ +#define BRD_NOTRAN 0x02 /* ¤£Âà«H */ +#define BRD_NOCOUNT 0x04 /* ¤£p¤å³¹µoªí½g¼Æ */ +#define BRD_NOSTAT 0x08 /* ¤£¯Ç¤J¼öªù¸ÜÃD²Îp */ +#define BRD_NOVOTE 0x10 /* ¤£¤½§G§ë²¼µ²ªG©ó [record] ªO */ +#define BRD_ANONYMOUS 0x20 /* °Î¦W¬ÝªO */ +#define BRD_NOSCORE 0x40 /* ¤£µû¤À¬ÝªO */ +#define BRD_NOPHONETIC 0x80 /* ¤Ïª`µ¤å¬ÝªO */ + +#define BRD_LOCAL 0x00000100 /* ¤£¦¬¯¸¥~«H */ +#define BRD_A10 0x00000200 +#define BRD_A11 0x00000400 +#define BRD_A12 0x00000800 +#define BRD_A13 0x00001000 +#define BRD_A14 0x00002000 +#define BRD_A15 0x00004000 +#define BRD_A16 0x00008000 + +#define BRD_A17 0x00010000 +#define BRD_A18 0x00020000 +#define BRD_A19 0x00040000 +#define BRD_A20 0x00080000 +#define BRD_A21 0x00100000 +#define BRD_A22 0x00200000 +#define BRD_A23 0x00400000 +#define BRD_A24 0x00800000 + +#define BRD_A25 0x01000000 +#define BRD_A26 0x02000000 +#define BRD_A27 0x04000000 +#define BRD_A28 0x08000000 +#define BRD_A29 0x10000000 +#define BRD_A30 0x20000000 +#define BRD_A31 0x40000000 +#define BRD_A32 0x80000000 +/* ----------------------------------------------------- */ +/* ¦UºØºX¼Ðªº¤¤¤å·N¸q */ +/* ----------------------------------------------------- */ + + +#define NUMBATTRS 32 + +#define STR_BATTR "zTcsvA%PL-----------------------" +/* itoc: ·s¼WºX¼Ðªº®ÉÔ§O§Ñ¤F§ï³o¸Ì°Ú */ + + +#ifdef _ADMIN_C_ +static char *battr_tbl[NUMBATTRS] = +{ + "¤£¥i Zap", /* BRD_NOZAP */ + "¤£Âà«H¥X¥h", /* BRD_NOTRAN */ + "¤£°O¿ý½g¼Æ", /* BRD_NOCOUNT */ + "¤£°µ¼öªù¸ÜÃD²Îp", /* BRD_NOSTAT */ + "¤£¤½¶}§ë²¼µ²ªG", /* BRD_NOVOTE */ + "°Î¦W¬ÝªO", /* BRD_ANONYMOUS */ + "¤£µû¤À¬ÝªO", /* BRD_NOSCORE */ + "¤£¨Ï¥Îª`µ¤å", /* BRD_NOPHONETIC */ + "¤£¦¬¯¸¥~«H", /* BRD_LOCAL */ + "«O¯d", /* BRD_A10 */ + "«O¯d", /* BRD_A11 */ + "«O¯d", /* BRD_A12 */ + "«O¯d", /* BRD_A13 */ + "«O¯d", /* BRD_A14 */ + "«O¯d", /* BRD_A15 */ + "«O¯d", /* BRD_A16 */ + "«O¯d", /* BRD_A17 */ + "«O¯d", /* BRD_A18 */ + "«O¯d", /* BRD_A19 */ + "«O¯d", /* BRD_A20 */ + "«O¯d", /* BRD_A21 */ + "«O¯d", /* BRD_A22 */ + "«O¯d", /* BRD_A23 */ + "«O¯d", /* BRD_A24 */ + "«O¯d", /* BRD_A25 */ + "«O¯d", /* BRD_A26 */ + "«O¯d", /* BRD_A27 */ + "«O¯d", /* BRD_A28 */ + "«O¯d", /* BRD_A29 */ + "«O¯d", /* BRD_A30 */ + "«O¯d", /* BRD_A31 */ + "«O¯d" /* BRD_A32 */ +}; + +#endif + +#endif /* _BATTR_H_ */ diff --git a/include/bbs.h b/include/bbs.h new file mode 100644 index 0000000..f690d51 --- /dev/null +++ b/include/bbs.h @@ -0,0 +1,65 @@ +/*-------------------------------------------------------*/ +/* bbs.h ( NTHU CS MapleBBS Ver 2.36 ) */ +/*-------------------------------------------------------*/ +/* target : all header files */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ + + +#ifndef _BBS_H_ +#define _BBS_H_ + + +#include <stdio.h> +#include <stdlib.h> +#include <setjmp.h> +#include <signal.h> +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <sys/time.h> + + +#ifdef SYSV + +#ifndef LOCK_EX +#define LOCK_EX F_LOCK +#define LOCK_UN F_ULOCK +#endif + +#define getdtablesize() (64) + +#define usleep(usec) { \ + struct timeval t; \ + t.tv_sec = usec / 1000000; \ + t.tv_usec = usec % 1000000; \ + select( 0, NULL, NULL, NULL, &t); \ +} + +#endif /* SYSV */ + + +#define BMIN(a,b) ((a<b)?a:b) +#define BMAX(a,b) ((a>b)?a:b) + + +#include "config.h" /* User-configurable stuff */ +#include "dao.h" +#include "perm.h" /* user/board permission */ +#include "ufo.h" /* user flag option */ +#include "battr.h" /* board attribution */ +#include "modes.h" /* The list of valid user modes */ +#include "struct.h" /* data structure */ +#include "global.h" /* global variable & definition */ +#include "theme.h" /* custom theme */ +#include "proto.h" /* prototype of functions */ + +#endif /* _BBS_H_ */ diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..376e71f --- /dev/null +++ b/include/config.h @@ -0,0 +1,433 @@ +/*-------------------------------------------------------*/ +/* config.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : site-configurable settings */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ + + +/*--------------------------------------------------------------------*/ +/* MapleBridge Bulletin Board System Version: 2.36 */ +/* Copyright (C) 1994-1995 Jeng-Hermes Lin, Hung-Pin Chen, */ +/* SoC, Xshadow */ +/*--------------------------------------------------------------------*/ +/* MapleBridge Bulletin Board System Version: 3.10 */ +/* Copyright (C) 1997-1998 Jeng-Hermes Lin */ +/*--------------------------------------------------------------------*/ + + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + + +/* ----------------------------------------------------- */ +/* ©w¸q BBS ¯¸¦W¦ì§} */ +/* ------------------------------------------------------*/ + +#define SCHOOLNAME "¥x«n¤@¤¤" /* ²Õ´¦WºÙ */ +#define BBSNAME "¯Á¥§¤p¯¸" /* ¤¤¤å¯¸¦W */ +#define BBSNAME2 "SonyBBS" /* ^¤å¯¸¦W */ +#define SYSOPNICK "¤u¤Í¥_¥_" /* sysop ªº¼ÊºÙ */ +#define TAG_VALID "["BBSNAME2"]To" /* ¨¤À»{ÃÒ¨ç token */ + +#define MYIPADDR "210.70.137.212" /* IP address */ +#define MYHOSTNAME "sony.tfcis.org" /* ºô¸ô¦a§} FQDN */ + +#define HOST_ALIASES {MYHOSTNAME, MYIPADDR, \ + "sony.twbbs.org", "sony.twbbs.org.tw", \ + "bbs.tfcis.org", \ + NULL} + +#define MYCHARSET "big5" /* BBS ©Ò¨Ï¥Îªº¦r¶° */ + +#define BBSHOME "/home/bbs" /* BBS ªº®a */ +#define BAKPATH "/home/bbsbak" /* ³Æ¥÷Àɪº¸ô®| */ + +#define BBSUID 9999 +#define BBSGID 99 /* Linux ½Ð³]¬° 999 */ + + +/* ----------------------------------------------------- */ +/* ²ÕºA³W¹º */ +/* ----------------------------------------------------- */ + + /* ------------------------------------------------- */ + /* ²ÕºA³W¹º£»¨t²Î°lÂÜ */ + /* ------------------------------------------------- */ + +#define HAVE_SEM /* ¨Ï¥Î semaphore */ + +#define HAVE_MMAP /* ±Ä¥Î mmap(): memory mapped I/O */ + +#ifndef CYGWIN +#define HAVE_RLIMIT /* ±Ä¥Î resource limit¡ACygwin ¤£¯à¥Î */ +#endif + +#define MODE_STAT /* Æ[¹î¤Î²Îp user ªº¥ÍºA¡A¥H°µ¬°¸gÀç¤è°w */ + +#undef SYSOP_CHECK_MAIL /* itoc.001029: ¯¸ªø¥i¥HŪ¨ú¨Ï¥ÎªÌ«H½c */ + +#undef SYSOP_SU /* itoc.001102: ¥H sysop µn¤J¥i¥HÅܧó¨Ï¥ÎªÌ¨¤À */ + +#define HAVE_MULTI_BYTE /* hightman.060504: ¤ä´©Âù¦r¸`º~¦r³B²z */ + + /* ------------------------------------------------- */ + /* ²ÕºA³W¹º£»µù¥U»{ÃÒ */ + /* ------------------------------------------------- */ + +#define LOGINASNEW /* ±Ä¥Î¤W¯¸¥Ó½Ð±b¸¹¨î«× */ + +#ifdef LOGINASNEW +#undef HAVE_GUARANTOR /* itoc.000319: ±Ä¥Î«OÃÒ¤H¨î«× */ +#endif + +#undef HAVE_LOGIN_DENIED /* itoc.000319: ¾×±¼¬Y¨Ç¨Ó·½ªº³sµ²¡A°Ñ·Ó etc/bbs.acl */ + +#undef NEWUSER_LIMIT /* ·s¤â¤W¸ôªº¤T¤Ñ¨î */ + +#define JUSTIFY_PERIODICAL /* ©w´Á¨¤À»{ÃÒ */ + +#undef EMAIL_JUSTIFY /* µo¥X Internet Email ¨¤À»{ÃÒ«H¨ç */ + +#ifdef EMAIL_JUSTIFY +#define HAVE_POP3_CHECK /* itoc.000315: POP3 ¨t²Î»{ÃÒ */ +#define HAVE_REGKEY_CHECK /* itoc.010112: »{ÃÒ½XÅçÃÒ */ +#endif + +#define HAVE_REGISTER_FORM /* µù¥U³æ»{ÃÒ */ + + /* ------------------------------------------------- */ + /* ²ÕºA³W¹º£»µ²¥æªB¤Í */ + /* ------------------------------------------------- */ + +#define HAVE_MODERATED_BOARD /* ´£¨Ñ¦n¤Í¯µ±KªO */ /* ¯µ±K¬ÝªOªº¾\ŪÅvn¬O PERM_SYSOP ¤~·|³Q·í¦¨¯µ±K¬ÝªO */ + /* ¦n¤Í¬ÝªOªº¾\ŪÅvn¬O PERM_BOARD ¤~·|³Q·í¦¨¦n¤Í¬ÝªO */ +#define CHECK_ONLINE /* itoc.010306: ¤å³¹¦Cªí¤¤¥i¥HÅã¥Ü¨Ï¥ÎªÌ¬O§_¦b¯¸¤W */ + +#define HAVE_BADPAL /* itoc.010302: ´£¨ÑÃa¤Hªº¥\¯à */ + +#define HAVE_LIST /* itoc.010923: ¸s²Õ¦W³æ */ + +#define HAVE_ALOHA /* itoc.001202: ¤W¯¸³qª¾ */ + +#undef LOGIN_NOTIFY /* ¨t²Î¨ó´Mºô¤Í */ + +#if (defined(HAVE_ALOHA) || defined(LOGIN_NOTIFY)) +#define HAVE_NOALOHA /* itoc.010716: ¤W¯¸¤£³qª¾/¨ó´M */ +#endif + +#define LOG_BMW /* lkchu.981201: ¤ô²y°O¿ý³B²z */ + +#ifdef LOG_BMW +#define RETAIN_BMW /* itoc.021102: ¤ô²y¦sÃÒ */ +#endif + +#define LOG_TALK /* lkchu.981201: ²á¤Ñ°O¿ý³B²z */ + +#define HAVE_NOBROAD /* itoc.010716: ©Ú¦¬¼s¼½ */ + +#define BMW_COUNT /* itoc.010312: pºâ¤¤¤F´XÓ¤ô²y */ + +#define BMW_DISPLAY /* itoc.010313: Åã¥Ü¤§«eªº¤ô²y */ + +#define HAVE_CHANGE_NICK /* ¨Ï¥ÎªÌ¦W³æ ^N ¥Ã¤[§ó§ï¼ÊºÙ */ + +#define HAVE_CHANGE_FROM /* ¨Ï¥ÎªÌ¦W³æ ^F ¼È®É§ó§ï¬G¶m */ + +#define HAVE_CHANGE_ID /* ¨Ï¥ÎªÌ¦W³æ ^D ¼È®É§ó§ï ID */ + +#define HAVE_WHERE /* itoc.001102: ¨Ï¥ÎªÌ¦W³æ¬G¶m¿ëÃÑ¡A°Ñ·Ó etc/host fqdn */ + +#ifdef HAVE_WHERE +#define GUEST_WHERE /* itoc.010208: guest ¶Ã¼Æ¨ú¬G¶m */ +#endif + +#define GUEST_NICK /* itoc.000319: guest ¶Ã¼Æ¨ú¼ÊºÙ */ + +#define DETAIL_IDLETIME /* itoc.020316: ®É±`§ó·s¶¢¸m®É¶¡ */ + +#define TIME_KICKER /* itoc.030514: ¬O§_¦Û°Êñ°h idle ¹L¤[ªº¨Ï¥ÎªÌ */ + +#define HAVE_BRDMATE /* itoc.020602: ªO¦ñ (¾\Ū¦P¤@¬ÝªO) */ + +#define HAVE_SUPERCLOAK /* itoc.020602: µµÁô¡A¯¸ªø¶W¯ÅÁô§Î */ + + /* ------------------------------------------------- */ + /* ²ÕºA³W¹º£»¬ÝªO«H½c */ + /* ------------------------------------------------- */ + +#define HAVE_ANONYMOUS /* ´£¨Ñ anonymous ªO */ + +#ifdef HAVE_ANONYMOUS +#undef HAVE_UNANONYMOUS_BOARD /* itoc.020602: ¤Ï°Î¦WªO¡A¥²¶·¦³¶} BN_UNANONYMOUS */ +#endif + +#define SHOW_USER_IN_TEXT /* ¦b¤å¥ó¤¤ Ctrl+Q ¥iÅã¥Ü User ªº¦W¦r */ + +#define ANTI_PHONETIC /* itoc.030503: ¸T¥Îª`µ¤å */ + +#define ENHANCED_VISIT /* itoc.010407: ¤wŪ/¥¼ÅªÀˬd¬O¸Ó¬ÝªOªº³Ì«á¤@½g¨M©w */ + +#define SLIDE_SHOW /* itoc.030411: ¦Û°Ê¼½©ñ¤å³¹ */ + +#undef COLOR_HEADER /* lkchu.981201: ÅÜ´«±m¦â¼ÐÀY */ + +#define CURSOR_BAR /* itoc.010113: ¿ï³æ¥ú´Î¡AY¶}±Ò¿ï³æ¥ú´Î¡A¿ï³æ´N¤£¯à¦³ÃC¦â±±¨î½X */ + +#define HAVE_DECLARE /* ¨Ï title ¤¤¦³ [] §ó©úÅã¡A¥B¤é´Á¤W¦â */ + +#define HAVE_POPUPMENU /* ÂÛ¥X¦¡¿ï³æ */ + +#ifdef HAVE_POPUPMENU +#define POPUP_ANSWER /* ÂÛ¥X¦¡¿ï³æ -- ¸ß°Ý¿ï¶µ */ +#define POPUP_MESSAGE /* ÂÛ¥X¦¡¿ï³æ -- °T®§µøµ¡ */ +#endif + +#define AUTHOR_EXTRACTION /* ´M§ä¦P¤@§@ªÌ¤å³¹ */ + +#undef HAVE_TERMINATOR /* ²×µ²¤å³¹¤jªk --- ©Ø·¬¸¨¸±Ù */ + +#define HAVE_XYNEWS /* itoc.010822: ·s»D¾\Ū¼Ò¦¡ */ + +#define HAVE_SCORE /* itoc.020114: ¤å³¹µû¤À¥\¯à */ + +#define HAVE_DETECT_CROSSPOST /* cross-post ¦Û°Ê°»´ú */ + +#define AUTO_JUMPBRD /* itoc.010910: ¬ÝªO¦Cªí¦Û°Ê¸õ¥h¤U¤@Ó¥¼Åª¬ÝªO */ + +#undef AUTO_JUMPPOST /* itoc.010910: ¤å³¹¦Cªí¦Û°Ê¸õ¥h³Ì«á¤@½g¥¼Åª */ + +#define ENHANCED_BSHM_UPDATE /* itoc.021101: ¬ÝªO¦Cªí§R°£/¼Ð°O¤å³¹¤£¦C¤J¥¼Åªªº¿O */ + +#define EVERY_Z /* ctrl-z Everywhere (°£¤F¼g¤å³¹) */ + +#define EVERY_BIFF /* Thor.980805: ¶l®t¨ì³B¨Ó«ö¹a */ + +#define HAVE_SIGNED_MAIL /* Thor.990409: ¥~°e«H¥ó¥[ñ¦W */ + +#define INPUT_TOOLS /* itoc.000319: ²Å¸¹¿é¤J¤u¨ã */ + +#define HAVE_FORCE_BOARD /* itoc.000319: ±j¢ user login ®ÉÔŪ¨ú¬Y¤½§i¬ÝªO */ + /* itoc.010726: ¸Ó¤½§i¬ÝªOn¤£¥i zap¡A§_«h zap «á¤£·|°O¿ý brh */ + +#define MY_FAVORITE /* itoc.001202: ´£¨Ñ§Úªº³Ì·R¬ÝªO */ + +#define HAVE_COSIGN /* itoc.010108: ´£¨Ñ¬ÝªO³s¸p */ + +#ifdef HAVE_COSIGN +#undef SYSOP_START_COSIGN /* itoc.030613: ·sªO³s¸pn¥ý¸g¯¸ªø¼f®Ö¤~¯à¶}©l */ +#endif + +#define HAVE_REFUSEMARK /* itoc.010602: ´£¨Ñ¬ÝªO¤å³¹¥[±K */ + +#define HAVE_LABELMARK /* itoc.020307: ´£¨Ñ¬ÝªO¤å³¹¥[«Ý¬å¼Ð°O */ + +#define POST_PREFIX /* itoc.020113: µoªí¤å³¹®É¼ÐÃD¥i¿ï¾ÜºØÃþ */ + +#define MULTI_MAIL /* ¸s²Õ±H«H¥\¯à */ + +#define HAVE_MAIL_ZIP /* itoc.010228: ´£¨Ñ§â«H¥ó/ºëµØ°ÏÀ£ÁYÂà±Hªº¥\¯à */ + +#undef OVERDUE_MAILDEL /* itoc.020217: ²M°£¹L´Á«H¥ó */ + + /* ------------------------------------------------- */ + /* ²ÕºA³W¹º£»¥~±¾µ{¦¡ */ + /* ------------------------------------------------- */ + +#define HAVE_EXTERNAL /* Xyz ¿ï³æ */ + +#ifdef HAVE_EXTERNAL +# define HAVE_SONG /* itoc.010205: ´£¨ÑÂIºq¥\¯à */ +# define HAVE_NETTOOL /* itoc.010209: ´£¨Ñºô¸ôªA°È¤u¨ã */ +# define HAVE_GAME /* itoc.010208: ´£¨Ñ¹CÀ¸ */ +# define HAVE_BUY /* itoc.010716: ´£¨ÑÁʶRÅv */ +# define HAVE_TIP /* itoc.010301: ´£¨Ñ¨C¤é¤p¯µ³Z */ +# define HAVE_CLASSTABLE /* itoc.010907: ´£¨Ñ¥\½Òªí */ +# define HAVE_CREDIT /* itoc.020125: ´£¨Ñ°O±b¥» */ +# define HAVE_LOVELETTER /* itoc.020602: ´£¨Ñ±¡®Ñ²£¥Í¾¹ */ +# define HAVE_CALENDAR /* itoc.020831: ´£¨Ñ¸U¦~¾ä */ +#endif + +#ifdef HAVE_SONG +# define HAVE_SONG_CAMERA /* itoc.010207: ´£¨ÑÂIºq¨ì°ÊºA¬ÝªO¥\¯à */ +# define LOG_SONG_USIES /* itoc.010928: ÂIºq°O¿ý */ +#endif + + +/* ----------------------------------------------------- */ +/* ²ÕºA³]©w */ +/* ------------------------------------------------------*/ + +#ifdef HAVE_MMAP +#include <sys/mman.h> +#endif + +#ifdef HAVE_SIGNED_MAIL +#define PRIVATE_KEY_PERIOD 0 /* ¥§¡´X¤Ñ´«¤@¦¸key¡A0 ªí¥Ü¤£´«key¡A¦Û°Ê²£¥Í */ +#endif + +#ifndef SHOW_USER_IN_TEXT +#define outx outs +#endif + + +/* ----------------------------------------------------- */ +/* ¨t²Î°Ñ¼Æ£»ÀH BBS ¯¸³W¼Ò¦¨ªø¦ÓÂX¼W */ +/* ----------------------------------------------------- */ + +#define MAXBOARD 1024 /* ³Ì¤j¶}ªOÓ¼Æ */ + +#define MAXACTIVE 512 /* ³Ì¦h¦P®É¤W¯¸¤H¼Æ */ + +/* ----------------------------------------------------- */ +/* ¨t²Î°Ñ¼Æ£»¨ä¥L±`¥Î°Ñ¼Æ */ +/* ----------------------------------------------------- */ + +/* bbsd.c ¤W¯¸µn¤J */ + +#define LOGINATTEMPTS 3 /* ³Ì¤j¶i¯¸±K½X¥´¿ù¦¸¼Æ */ +#define MULTI_MAX 2 /* ¤@¯ë¨Ï¥ÎªÌ³Ì¤j multi-login Ó¼Æ */ + +/* bbsd.c user.c admutil.c ©w´Á¨¤À»{ÃÒ¡A°O±o¦P¨B×§ï gem/@/@re-reg */ + +#ifdef JUSTIFY_PERIODICAL +#define VALID_PERIOD (86400 * 365) /* ¨¤À»{ÃÒ¦³®Ä´Á(¬í) */ +#define INVALID_NOTICE_PERIOD (86400 * 10) /* ¨¤À»{ÃÒ¥¢®Ä«e¦h¤[®É¶¡´£¿ô¨Ï¥ÎªÌ(¬í) */ +#endif + +/* talk.c ªB¤Í¦W³æ/¤ô²y¦Cªí */ + +/* itoc.010825: ª`·N BMW_LOCAL_MAX >= BMW_PER_USER */ + +#define PAL_MAX 400 /* ªB¤Í¦W³æ¤W(¤H) */ +#define BMW_EXPIRE 60 /* ¤ô²y³B²z®É¶¡(¬í) */ +#define BMW_PER_USER 5 /* ¤ô²y³B²z®É¶¡¤º¡A¤¹³\¥á´XÓ¤ô²y */ +#define BMW_MAX 128 /* UCACHE ¤¤ pool ¤W */ +#define BMW_LOCAL_MAX 8 /* Ctrl+R ¤W¤U©Ò¯àÂsÄý¤§«e¤ô²yÓ¼Æ */ + +/* aloha.c ¤W¯¸³qª¾ */ + +#ifdef HAVE_ALOHA +#define ALOHA_MAX 64 /* ¤W¯¸³qª¾¤W(¤H) */ +#endif + +/* menu.c ¯d¨¥ªO */ + +#define NOTE_MAX 100 /* ¯d¨¥ªO«O¯d½g¼Æ */ +#define NOTE_DUE 48 /* ¯d¨¥ªO«O¯d®É¶¡(¤Ñ) */ + +/* mail.c ¥Î¨ÓÀˬd«H½c¤j¤p¡A¶W¹L«h´£¥Ü¡A°O±o¦P¨B×§ï etc/justified gem/@/@mailover */ + +#define MAX_BBSMAIL 1000 /* PERM_MBOX ¦¬«H¤W(«Ê) */ +#define MAX_VALIDMAIL 300 /* »{ÃÒ user ¦¬«H¤W(«Ê) */ +#define MAX_NOVALIDMAIL 100 /* ¥¼»{ÃÒ user ¦¬«H¤W(«Ê) */ + +/* bquota.c mail.c ¥Î¨Ó²M¹L´ÁÀÉ®×/«H¥óªº®É¶¡¡A°O±o¦P¨B×§ï etc/justified */ + +#ifdef OVERDUE_MAILDEL +#define MARK_DUE 180 /* ¼Ð°O«O¦s¤§«H¥ó«O¯d®É¶¡(¤Ñ) */ +#define MAIL_DUE 60 /* ¤@¯ë«H¥ó«O¯d®É¶¡(¤Ñ) */ +#define FILE_DUE 30 /* ¨ä¥LÀɮ׫O¯d®É¶¡(¤Ñ) */ +#endif + +/* newbrd.c ¬ÝªO³s¸p */ + +#ifdef HAVE_COSIGN +#define NBRD_NUM_BRD 10 /* ¶}ªO»Ýn³s¸p¤H¼Æ */ +#define NBRD_DAY_BRD 3 /* ¶}ªO¥i³s¸p¤Ñ¼Æ */ +#endif + +/* post.c °»´ú cross-post */ + +#ifdef HAVE_DETECT_CROSSPOST +#define MAX_CROSS_POST 3 /* cross post ³Ì¤j¼Æ¶q(½g) */ +#define CROSSPOST_DENY_DAY 1 /* cross post °±Åv®É¶¡(¤Ñ) */ +#endif + +/* visio.c bguard.c ¦Û°Ê½ð¤H */ + +#ifdef TIME_KICKER +#define IDLE_TIMEOUT 30 /* visio.c bguard.c µo§b¹L¤[¦Û°Êñ°h(¤À) */ +#define IDLE_WARNOUT 3 /* visio.c µo§b¹L¤[´£¿ô(¤À) -- ¦Û°Êñ°h«e¤T¤ÀÄÁ«e */ +#endif + +/* more.c edit.c ½¶ */ + +#define PAGE_SCROLL (b_lines - 1) /* «ö PgUp/PgDn n±²°Ê´X¦C */ + +#define MAXLASTCMD 8 /* line input buffer */ +#define BLK_SIZ 4096 /* disk I/O block size */ +#define MAXSIGLINES 6 /* edit.c ñ¦WÀɤޤJ³Ì¤j¦æ¼Æ */ +#define MAXQUERYLINES 17 /* talk.c xchatd.c Åã¥Ü Query/Plan °T®§³Ì¤j¦æ¼Æ */ +#define MAX_CHOICES 32 /* vote.c §ë²¼®É³Ì¦h¦³ 32 ºØ¿ï¾Ü */ +#define TAG_MAX 256 /* xover.c TagList ¼ÐÅҼƥؤ§¤W */ +#define LINE_HEADER 3 /* more.c bhttpd.c ÀÉÀY¦³¤T¦C */ + +/* bbsd.c mail.c ¾ã²z¶g´Á */ + +#define CHECK_PERIOD (86400 * 20) /* ¾ã²z«H½c/ªB¤Í¦W³æªº¶g´Á(¬í) */ + +/* camera.c °ÊºA¬ÝªO */ + +#define MOVIE_MAX 180 /* °Êµe±i¼Æ */ +#define MOVIE_SIZE (108 * 1024) /* °Êµe cache size */ + + +/* ----------------------------------------------------- */ +/* chat.c & xchatd.c ¤¤±Ä¥Îªº protocol */ +/* ------------------------------------------------------*/ + +#define CHAT_SECURE /* ¦w¥þªº²á¤Ñ«Ç */ + +#define EXIT_LOGOUT 0 +#define EXIT_LOSTCONN -1 +#define EXIT_CLIERROR -2 +#define EXIT_TIMEDOUT -3 +#define EXIT_KICK -4 + +#define CHAT_LOGIN_OK "OK" +#define CHAT_LOGIN_EXISTS "EX" +#define CHAT_LOGIN_INVALID "IN" +#define CHAT_LOGIN_BOGUS "BG" + + +/* ----------------------------------------------------- */ +/* BBS ªA°È©Ò¥Îªº port */ +/* ------------------------------------------------------*/ + +/* itoc.030512: ¦pªGn¦b¦P¤@¥x¾÷¾¹¤W¬[¤GÓ bbs ¯¸¡A¨º»òn¡G + + 1) ¦b OS ¶}¤@Ó·sªº user (¨Ò¦p¥s bbs2)¡A¨ä uid n©M¥t¤@Ó bbs ¤£¦P + 2) §ï BBSHOME¡BBAKPATH¡BBBSUID¡BBBSGID ¬° bbs2 ªº¸ô®|¤ÎUID¡BGID + 3) §ï¥H¤Uªº *_PORT ¤Î *_KEY ©M¥t¤@Ó bbs ¤£¦P (¨Ò¦p³£¥[¤W 10000) +*/ + +#define MAX_BBSDPORT 1 /* bbsd n¶}´XÓ port¡AÀH BBSD_PORT ¦ÓÅÜ */ +#define BBSD_PORT {23} /* bbsd ©Ò¥Îªº port (bbsd.c) */ +#define BMTA_PORT 25 /* SMTP ©Ò¥Îªº port (bmtad.c) */ +#define GEMD_PORT 70 /* Gopher ©Ò¥Îªº port (gemd.c) */ +#define FINGER_PORT 79 /* Finger ©Ò¥Îªº port (bguard.c) */ +#define BHTTP_PORT 80 /* HTTP ©Ò¥Îªº port (bhttpd.c) */ +#define POP3_PORT 110 /* POP3 ©Ò¥Îªº port (bpop3d.c) */ +#define BNNTP_PORT 119 /* NNTP ©Ò¥Îªº port (bnntp.c) */ +#define CHAT_PORT 3838 /* ²á¤Ñ«Ç ©Ò¥Îªº port (chat.c xchatd.c) */ +#define INNBBS_PORT 7777 /* Âà«H ©Ò¥Îªº port (channel.c) */ + + +/* ----------------------------------------------------- */ +/* SHM ¤Î SEM ©Ò¥Îªº key */ +/* ----------------------------------------------------- */ + +#define BRDSHM_KEY 2997 /* ¬ÝªO */ +#define UTMPSHM_KEY 1998 /* ¨Ï¥ÎªÌ */ +#define FILMSHM_KEY 2999 /* °ÊºA¬ÝªO */ +#define PIPSHM_KEY 4998 /* ¹q¤lÂû¹ï¾Ô */ + +#define BSEM_KEY 2000 /* semaphore key */ +#define BSEM_FLG 0600 /* semaphore mode */ +#define BSEM_ENTER -1 /* enter semaphore */ +#define BSEM_LEAVE 1 /* leave semaphore */ +#define BSEM_RESET 0 /* reset semaphore */ + +#endif /* _CONFIG_H_ */ diff --git a/include/dao.h b/include/dao.h new file mode 100644 index 0000000..b460ab5 --- /dev/null +++ b/include/dao.h @@ -0,0 +1,39 @@ +/*-------------------------------------------------------*/ +/* lib/dao.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : data abstract object */ +/* create : 96/11/20 */ +/* update : 96/12/15 */ +/*-------------------------------------------------------*/ + + +#ifndef _DAO_H_ +#define _DAO_H_ + + +#ifndef NULL +#define NULL 0 /* ((char *) 0) */ +#endif + + +#ifndef BLK_SIZ +#define BLK_SIZ 4096 /* disk I/O block size */ +#endif + + +#ifndef REC_SIZ +#define REC_SIZ 512 /* disk I/O record size */ +#endif + + +/* Thor.981206: lkchu patch */ +extern char radix32[]; + + +#include "hdr.h" /* prototype */ +#include "dns.h" /* dns type */ +#include "splay.h" /* splay type */ +#include "../lib/dao.p" /* prototype */ + + +#endif /* _DAO_H_ */ diff --git a/include/dns.h b/include/dns.h new file mode 100644 index 0000000..df571f7 --- /dev/null +++ b/include/dns.h @@ -0,0 +1,88 @@ +/*-------------------------------------------------------*/ +/* lib/dns.h ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : header file for DNS routines */ +/* create : 96/11/20 */ +/* update : 96/12/15 */ +/*-------------------------------------------------------*/ + + +#ifndef _DNS_H_ +#define _DNS_H_ + + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <ctype.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <resolv.h> + + +//#undef HAVE_RELAY_SERVER /* ±Ä¥Î relay server ¨Ó¥~±H«H¥ó */ + +#define HAVE_RELAY_SERVER /* ±Ä¥Î relay server ¨Ó¥~±H«H¥ó */ + +#ifdef HAVE_RELAY_SERVER +//#define RELAY_SERVER "mail.tnfsh.tn.edu.tw" /* outbound mail server */ +#define RELAY_SERVER "localhost" /* outbound mail server */ +#endif + + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + +#define INADDR_FMT "%u.%u.%u.%u" + + +typedef union +{ + unsigned char d[4]; + unsigned long addr; +} ip_addr; + + +#if 0 + The standard udp packet size PACKETSZ (512) is not sufficient for some + nameserver answers containing very many resource records. The resolver may + switch to tcp and retry if it detects udp packet overflow. Also note that + the resolver routines res_query and res_search return the size of the + un*truncated answer in case the supplied answer buffer it not big enough + to accommodate the entire answer. +#endif + + +#if PACKETSZ > 1024 +#define MAXPACKET PACKETSZ +#else +#define MAXPACKET 1024 /* max packet size used internally by BIND */ +#endif + + +/* MAX_MXLIST n¤ñ MAX_DNAME ¤j±o¦h */ +#define MAX_DNAME 128 /* maximum domain name */ +#define MAX_MXLIST 1024 /* maximum dx list */ + + +typedef union +{ + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf; /* response of DNS query */ + + +static inline unsigned short +getshort(c) + unsigned char *c; +{ + unsigned short u; + + u = c[0]; + return (u << 8) + c[1]; +} + + +#endif /* _DNS_H_ */ diff --git a/include/global.h b/include/global.h new file mode 100644 index 0000000..c1b4431 --- /dev/null +++ b/include/global.h @@ -0,0 +1,503 @@ +/*-------------------------------------------------------*/ +/* global.h ( NTHU CS MapleBBS Ver 2.36 ) */ +/*-------------------------------------------------------*/ +/* target : global definitions & variables */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ + + +#ifndef _GLOBAL_H_ +#define _GLOBAL_H_ + + +#ifdef _MAIN_C_ +# define VAR +# define INI(x) = x +#else +# define VAR extern +# define INI(x) +#endif + + +/* ----------------------------------------------------- */ +/* GLOBAL DEFINITION */ +/* ----------------------------------------------------- */ + + +/* itoc.010821: ©R¦Wì«h: Ó¤H¾Ö¦³ªÌ(¦pÓ¤H/¬ÝªO/ºëµØ°Ï©Ò¿W¦Û¾Ö¦³ªº)¿×¤§ FN_XXXX + ¨t²Î¾Ö¦³ªÌ¡AY¬O¤£Åܰʪº¤å¥ó¡A¿×¤§ FN_ETC_XXXX¡FY¬OÅܰÊÀɮסA¿×¤§ FN_RUN_XXXX */ + + +/* ----------------------------------------------------- */ +/* Ó¤H¥Ø¿ýÀɦW³]©w */ +/* ----------------------------------------------------- */ + + +#define FN_ACCT ".ACCT" /* User account */ +#define FN_BRH ".BRH" /* board reading history */ +#define FN_CZH ".CZH" /* class zap history */ + +#define FN_PLANS "plans" /* pµeÀÉ */ +#define FN_SIGN "sign" /* ñ¦WÀÉ.? */ + +#define FN_LOG "log" /* ¤W¯¸¨Ó·½°O¿ý */ +#define FN_JUSTIFY "justify" /* ¾ú¦¸»{ÃÒ¸ê®Æ */ +#define FN_EMAIL "email" /* »{ÃÒ§¹¾ã¦^«H°O¿ý */ +#define FN_ACL "acl" /* ¤W¯¸¦aÂI³]©w */ + +#define FN_BMW "bmw" /* ¤ô²y°O¿ý Binary Message Write */ +#define FN_AMW "amw" /* ¤ô²y°O¿ý ASCII Message Write */ +#define FN_PAL "friend" /* ªB¤Í¦W³æ (Àx¦s¦b¦Û¤v¥Ø¿ý¡A°O¿ý¦³þ¨Ç¤H) */ + +#ifdef HAVE_LIST +#define FN_LIST "list" /* ¯S®í¦W³æ.? */ +#endif + +#ifdef LOGIN_NOTIFY +#define FN_BENZ "benz" /* ¨t²Î¨ó´M¤W¯¸³qª¾ */ +#endif + +#ifdef HAVE_ALOHA +#define FN_ALOHA "aloha" /* ¤W¯¸³qª¾ (Àx¦s¦b¦Û¤v¥Ø¿ý¡A°O¿ý¦³þ¨Ç¤H) */ +#define FN_FRIENZ "frienz" /* ¤W¯¸³qª¾ (Àx¦s¦b¹ï¤è¥Ø¿ý¡A¹ï¤è¤W¯¸®ÉIJµo) */ +#endif + +#define FN_PAYCHECK "paycheck" /* ¤ä²¼ */ + +#ifdef LOG_TALK +#define FN_TALK_LOG "talk.log" /* ²á¤Ñ°O¿ýÀÉ */ +#endif + +#ifdef MY_FAVORITE +#define FN_MF "@MyFavorite" /* §Úªº³Ì·R */ +#endif + +#ifdef HAVE_CLASSTABLE +#define FN_CLASSTBL "classtable" /* ¥\½Òªí */ +#define FN_CLASSTBL_LOG "classtable.log"/* ¥\½Òªí */ +#endif + +#ifdef HAVE_CREDIT +#define FN_CREDIT "credit" /* °O±b¥» */ +#endif + +#ifdef HAVE_CALENDAR +#define FN_TODO "todo" /* ¦æ¨Æ¾ä */ +#endif + + +/* ----------------------------------------------------- */ +/* ¬ÝªO/ºëµØ°Ï/«H½cÀɦW³]©w */ +/* ----------------------------------------------------- */ + + +#define FN_DIR ".DIR" /* index */ +#define FN_VCH ".VCH" /* vote control header */ +#define FN_LOCK "lock" /* ¬ÝªOÂê©w */ +#define FN_NOTE "note" /* ¶iªOµe± */ +#define FN_POSTLAW "postlaw" /* µo¤åºõ»â */ + +/* ----------------------------------------------------- */ +/* ¨t²ÎÀɦW³]©w */ +/* ----------------------------------------------------- */ + + /* --------------------------------------------------- */ + /* ®Ú¥Ø¿ý¤U¨t²ÎÀÉ®× */ + /* --------------------------------------------------- */ + + +#define FN_BRD ".BRD" /* board list */ +#define FN_SCHEMA ".USR" /* userid schema */ + + + /* --------------------------------------------------- */ + /* run/ ¥Ø¿ý¤U¨t²ÎÀÉ®× */ + /* --------------------------------------------------- */ + + +#define FN_RUN_USIES "run/usies" /* BBS log */ +#define FN_RUN_NOTE_ALL "run/note.all" /* ¯d¨¥ªO */ +#define FN_RUN_PAL "run/pal.log" /* ªB¤Í¶W¹L¤W°O¿ý */ + +#define FN_RUN_ADMIN "run/admin.log" /* ¯¸ªø¦æ¬°°O¿ý */ + +#ifdef LOG_SONG_USIES +#define FN_RUN_SONGUSIES "run/song_usies" /* ÂIºq°O¿ý */ +#endif + +#ifdef HAVE_REGISTER_FORM +#define FN_RUN_RFORM "run/rform" /* µù¥Uªí³æ */ +#define FN_RUN_RFORM_LOG "run/rform.log" /* µù¥Uªí³æ¼f®Ö°O¿ýÀÉ */ +#endif + +#ifdef MODE_STAT +#define FN_RUN_MODE_LOG "run/mode.log" /* ¨Ï¥ÎªÌ°ÊºA²Îp - record per hour */ +#define FN_RUN_MODE_CUR "run/mode.cur" +#define FN_RUN_MODE_TMP "run/mode.tmp" +#endif + +#ifdef HAVE_ANONYMOUS +#define FN_RUN_ANONYMOUS "run/anonymous" /* °Î¦Wµoªí¤å³¹°O¿ý */ +#endif + +#ifdef HAVE_BUY +#define FN_RUN_BANK_LOG "run/bank.log" /* ¶×¿ú°O¿ý */ +#endif + +#ifdef HAVE_SIGNED_MAIL +#define FN_RUN_PRIVATE "run/prikey" /* ¹q¤lñ³¹ */ +#endif + +#define FN_RUN_EMAILREG "run/emailreg" /* °O¿ý¥Î¨Ó»{ÃÒªº«H½c */ +#define FN_RUN_MAIL_LOG "run/mail.log" /* ±H«Hªº°O¿ý */ + +#define FN_RUN_POST "run/post" /* ¤å³¹½g¼Æ²Îp */ +#define FN_RUN_POST_LOG "run/post.log" /* ¤å³¹½g¼Æ²Îp */ + +/* reaper ©Ò²£¥Íªº log */ +#define FN_RUN_LAZYBM "run/lazybm" /* °½ÃiªO¥D²Îp */ +#define FN_RUN_MANAGER "run/manager" /* ¯S®íÅv¨Ï¥ÎªÌ¦Cªí */ +#define FN_RUN_REAPER "run/reaper" /* ªø´Á¥¼¤W¯¸³Q²M°£ªº¨Ï¥ÎªÌ¦Cªí */ +#define FN_RUN_EMAILADDR "run/emailaddr" /* ¦P¤@ email »{ÃÒ¦h¦¸¦Cªí */ + +#define BMTA_LOGFILE "run/bmta.log" /* ¦¬¥~³¡«Hªº°O¿ý */ + + + /* --------------------------------------------------- */ + /* etc/ ¥Ø¿ý¤U¨t²ÎÀÉ®× */ + /* --------------------------------------------------- */ + + +#define FN_ETC_EXPIRE "etc/expire.conf" /* ¬ÝªO¤å³¹½g¼Æ¤W³]©w */ + +#define FN_ETC_VALID "etc/valid" /* ¨¤À»{ÃÒ«H¨ç (Email »{ÃҮɡA±H¥hµ¹¯¸¥~«H½c) */ +#define FN_ETC_JUSTIFIED "etc/justified" /* »{ÃÒ³q¹L³qª¾ (»{ÃÒ³q¹L®É¡A±H¨ì¯¸¤º«H½c) */ +#define FN_ETC_REREG "etc/re-reg" /* «·s»{ÃÒ³qª¾ (»{ÃÒ¹L´Á®É¡A±H¨ì¯¸¤º«H½c) */ + +#define FN_ETC_CROSSPOST "etc/cross-post" /* ¸ó¶K°±Åv³qª¾ (Cross-Post ®É¡A±H¨ì¯¸¤º«H½c) */ + +#define FN_ETC_BADID "etc/badid" /* ¤£¶®¦W³æ (©Úµ´µù¥U ID) */ +#define FN_ETC_SYSOP "etc/sysop" /* ¯¸°È¦W³æ */ + +#define FN_ETC_FEAST "etc/feast" /* ¸`¤é */ + +#define FN_ETC_IDHOME "etc/idhome" /* ¬G¶m ID */ +#define FN_ETC_HOST "etc/host" /* ¬G¶m IP */ +#define FN_ETC_FQDN "etc/fqdn" /* ¬G¶m FQDN */ + +#define FN_ETC_TIP "etc/tip" /* ¨C¤é¤p¯µ³Z */ + +#define FN_ETC_LOVELETTER "etc/loveletter" /* ±¡®Ñ²£¥Í¾¹¤å®w */ + + + /* --------------------------------------------------- */ + /* etc/ ¥Ø¿ý¤U access crontrol list (ACL) */ + /* --------------------------------------------------- */ + +#define TRUST_ACLFILE "etc/trust.acl" /* »{ÃÒ¥Õ¦W³æ */ +#define UNTRUST_ACLFILE "etc/untrust.acl" /* »{ÃҶ¦W³æ */ + +#define MAIL_ACLFILE "etc/mail.acl" /* ¦¬«H¥Õ¦W³æ */ +#define UNMAIL_ACLFILE "etc/unmail.acl" /* ¦¬«H¶Â¦W³æ */ + +#define BBS_ACLFILE "etc/bbs.acl" /* ©Úµ´ telnet ³s½u¦W³æ */ + + +/* ----------------------------------------------------- */ +/* ¦UÓªOªºÀɦW³]©w */ +/* ----------------------------------------------------- */ + + +#if 0 /* itoc.000512: ¨t²Î¬ÝªO¡A¹w³]¤p¼g¡A¤j¼gµL§« */ +¬ÝªO ¤¤ ¤å ±Ô z ¾\ŪÅv µoªíÅv +sysop ¯¸°È ³ø§i¯¸ªø¡Eµ¹§Ú³ø³ø 0 0 +0announce ¯¸°È ©^¤Ñ©Ó¹B¡E¯¸ªø¶@¤ê 0 PERM_ALLADMIN +test ¯¸°È ´ú¸Õ±M°Ï¡E·s¤â¸ÕÃz 0 PERM_BASIC +note ¯¸°È °ÊºA¬ÝªO¡E¯]¾÷¸Ü»y 0 PERM_POST +newboard ¯¸°È ¶}ÅP±MÄæ¡E³s¸p«¦a 0 PERM_POST +ktv ¯¸°È ÂIºq°O¿ý¡E¯u±¡¹ï¸Ü 0 PERM_SYSOP +record ¯¸°È »Ä²¢W»¶¡E¨t²Î°O¿ý 0 PERM_SYSOP +deleted ¯¸°È ¤å³¹¬@±Ï¡E¸ê·½¦^¦¬ PERM_BM PERM_SYSOP +bm ¯¸°È ±M·~°Q½×¡EªO¥D¥æ½Ë PERM_BM 0 +admin ¯¸°È ´c·d¤Ñ¦a¡E¯¸ªø¦ÛºN PERM_ALLADMIN 0 +log ¯¸°È ¨t²Î«OÀI¡E¦w¥þ°O¿ý PERM_ALLADMIN PERM_SYSOP +junk ¯¸°È ¤å³¹²M²z¡E©U§£±»®I PERM_ALLBOARD PERM_SYSOP +UnAnonymous ¯¸°È ¶Â¨çº¡¤Ñ¡E°Î¦W²{¨ PERM_ALLBOARD PERM_SYSOP + +¨ä¤¤¨îŪ¨úªº¬ÝªO¦b Class ¤ÀÃþ¤¤n³]©w ¸ê®Æ«O±K +#endif + +/* ¥H¤U¬O¤@©wn¦³ªº¨t²Î¬ÝªO¡A¦ý¬O¤@ÓªO¥i¥H«ÂШϥΦh¦¸¡A¨Ò¦p§ë½Zºq¥»ªº©M°ÊºA¬ÝªO¦@¥Î note ªO */ + +#define BN_CAMERA "note" /* °ÊºA¬ÝªO©ñ¦b³oªOªººëµØ°Ï */ +#define BN_ANNOUNCE "0announce" /* ¤½§i¬ÝªO¡A±j¢¾\Ū */ +#define BN_JUNK "junk" /* ¦Û¤v§R°£ªº¤å³¹©ñ¦b¦¹ */ +#define BN_DELETED "deleted" /* ªO¥D§R°£ªº¤å³¹©ñ¦b¦¹ */ +#define BN_SECURITY "log" /* ¨t²Î¦w¥þ°O¿ý */ +#define BN_RECORD "record" /* ¨t²Îªº¤@¯ë°O¿ý */ +#define BN_UNANONYMOUS "UnAnonymous" /* °Î¦WªOªº¤å³¹·|½Æ»s¤@¥÷¦b³o¸Ì */ +#define BN_KTV "ktv" /* ÂIºq°O¿ý©ñ¦b³oªO¡Aºq¥»©ñ¦b³oªOªººëµØ°Ï */ +#define BN_REQUEST BN_CAMERA /* ºq¥»§ë½Z³B */ + +#define BN_NULL "©|¥¼¿ï©w" /* ¶i¯¸«áÁÙ¨S¶i¤J¥ô¦ó¬ÝªO¡A©ÒÅã¥Üªº¬ÝªO¦WºÙ */ + + +/* ----------------------------------------------------- */ +/* Áä½L³]©w */ +/* ----------------------------------------------------- */ + + +#define KEY_BKSP 8 /* ©M Ctrl('H') ¬Û¦P */ +#define KEY_TAB 9 /* ©M Ctrl('I') ¬Û¦P */ +#define KEY_ENTER 10 /* ©M Ctrl('J') ¬Û¦P */ +#define KEY_ESC 27 +#define KEY_UP -1 +#define KEY_DOWN -2 +#define KEY_RIGHT -3 +#define KEY_LEFT -4 +#define KEY_HOME -21 +#define KEY_INS -22 +#define KEY_DEL -23 +#define KEY_END -24 +#define KEY_PGUP -25 +#define KEY_PGDN -26 + + +#define I_TIMEOUT -31 +#define I_OTHERDATA -32 + + +#define Ctrl(c) (c & '\037') +#define Esc(c) (c) /* itoc.030824: ¤£ TRAP_ESC */ +#define isprint2(c) (c >= ' ') + + +#if 0 /* itoc.020108: «öÁä¹ïÀ³ªí */ + + int HEX = vkey('KEY'); + ³oªí¬O¥Ñ vkey() ¿é¤JÁä½L¡A¶Ç¥Xªº¾ã¼ÆÈ¹ïÀ³ªí¡C + + +/* ȬOtªº */ + +KEY_INS ffffffea KEY_DEL ffffffe9 +KEY_HOME ffffffeb KEY_END ffffffe8 +KEY_PGUP ffffffe7 KEY_PGDN ffffffe6 + +KEY_UP ffffffff KEY_DOWN fffffffe +KEY_RIGHT fffffffd KEY_LEFT fffffffc + +/* ȬO¥¿ªº */ + +¢z¢w¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢{ +¢x HEX¢x00¢x01¢x02¢x03¢x04¢x05¢x06¢x07¢x08¢x09¢x0a¢x0b¢x0c¢x0d¢x0e¢x0f¢x +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x KEY¢x ¢x^A¢x^B¢x^C¢x^D¢x^E¢x^F¢x^G¢x^H¢x^I¢x^J¢x^K¢x^L¢x^M¢x^N¢x^O¢x +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x HEX¢x10¢x11¢x12¢x13¢x14¢x15¢x16¢x17¢x18¢x19¢x1a¢x1b¢x1c¢x1d¢x1e¢x1f¢x +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x KEY¢x^P¢x^Q¢x^R¢x^S¢x^T¢x^U¢x^V¢x^W¢x^X¢x^Y¢x^Z¢xEs¢x ¢x ¢x ¢x ¢x +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x HEX¢x20¢x21¢x22¢x23¢x24¢x25¢x26¢x27¢x28¢x29¢x2a¢x2b¢x2c¢x2d¢x2e¢x2f¢x /* 0x22 ¬OÂù¤Þ¸¹¡AÁ×§K compile ¿ù»~ */ +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x KEY¢x ¢x !¢xXX¢x #¢x $¢x %¢x &¢xXX¢x (¢x )¢x *¢x ¢x ,¢x -¢x .¢x /¢x /* 0x27 ¬O³æ¤Þ¸¹¡AÁ×§K compile ¿ù»~ */ +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x HEX¢x30¢x31¢x32¢x33¢x34¢x35¢x36¢x37¢x38¢x39¢x3a¢x3b¢x3c¢x3d¢x3e¢x3f¢x +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x KEY¢x 0¢x 1¢x 2¢x 3¢x 4¢x 5¢x 6¢x 7¢x 8¢x 9¢x :¢x ;¢x <¢x ¢x >¢x ?¢x +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x HEX¢x40¢x41¢x42¢x43¢x44¢x45¢x46¢x47¢x48¢x49¢x4a¢x4b¢x4c¢x4d¢x4e¢x4f¢x +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x KEY¢x @¢x A¢x B¢x C¢x D¢x E¢x F¢x G¢x H¢x I¢x J¢x K¢x L¢x M¢x N¢x O¢x +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x HEX¢x50¢x51¢x52¢x53¢x54¢x55¢x56¢x57¢x58¢x59¢x5a¢x5b¢x5c¢x5d¢x5e¢x5f¢x +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x KEY¢x P¢x Q¢x R¢x S¢x T¢x U¢x V¢x W¢x X¢x Y¢x Z¢x [¢x \¢x ]¢x ^¢x _¢x +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x HEX¢x60¢x61¢x62¢x63¢x64¢x65¢x66¢x67¢x68¢x69¢x6a¢x6b¢x6c¢x6d¢x6e¢x6f¢x +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x KEY¢x `¢x a¢x b¢x c¢x d¢x e¢x f¢x g¢x h¢x i¢x j¢x k¢x l¢x m¢x n¢x o¢x +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x HEX¢x70¢x71¢x72¢x73¢x74¢x75¢x76¢x77¢x78¢x79¢x7a¢x7b¢x7c¢x7d¢x7e¢x7f¢x +¢u¢w¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t +¢x KEY¢x p¢x q¢x r¢x s¢x t¢x u¢x v¢x w¢x x¢x y¢x z¢x {¢x |¢x }¢x ¢x ¢x +¢|¢w¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢} + +/* È«ÂÐ */ + +KEY_BKSP == Ctrl('H') == 0x08 +'\t' == Ctrl('I') == 0x09 +'\n' == Ctrl('J') == 0x0a +'\r' == Ctrl('M') == 0x0d + +#endif + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡G¿W¥ß¥X¨Ó¡A¥H§Q¤ä´©¦UºØ»y¨¥ */ +/* ----------------------------------------------------- */ + + +#define QUOTE_CHAR1 '>' +#define QUOTE_CHAR2 ':' + +#define STR_SPACE " \t\n\r" + +#define STR_AUTHOR1 "§@ªÌ:" +#define STR_AUTHOR2 "µo«H¤H:" +#define STR_POST1 "¬ÝªO:" +#define STR_POST2 "¯¸¤º:" +#define STR_REPLY "Re: " +#define STR_FORWARD "Fw: " + +#define STR_LINE "\n\ +> -------------------------------------------------------------------------- <\n\n" + +#define LEN_AUTHOR1 (sizeof(STR_AUTHOR1) - 1) +#define LEN_AUTHOR2 (sizeof(STR_AUTHOR2) - 1) + +#define STR_SYSOP "sysop" +#define STR_GUEST "guest" +#define STR_NEW "new" + +#define STR_ANONYMOUS "«Ó®ðªº¸ô¤H¥Ì" /* nµu©ó IDLEN Ó¦r */ + +#define MSG_SEPERATOR "\ +¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w" + +#define MSG_CANCEL "¨ú®ø" +#define MSG_USR_LEFT "¹ï¤è¤w¸gÂ÷¥h" +#define MSG_XY_NONE "ªÅµL¤@ª«" + +#define MSG_USERPERM "Åvµ¥¯Å¡G" +#define MSG_READPERM "¾\\ŪÅv¡G" +#define MSG_POSTPERM "µoªíÅv¡G" +#define MSG_BRDATTR "¬ÝªOÄݩʡG" +#define MSG_USERUFO "²ßºDºX¼Ð¡G £¾ / ¡@ £¾ / ¡@" + +#define MSG_XYPOST1 "¼ÐÃDÃöÁä¦r¡G" +#define MSG_XYPOST2 "§@ªÌÃöÁä¦r¡G" + +#define MSG_DEL_OK "§R°£§¹²¦" +#define MSG_DEL_CANCEL "¨ú®ø§R°£" +#define MSG_DEL_ERROR "§R°£¿ù»~" +#define MSG_DEL_NY "½Ð½T©w§R°£(Y/N)¡H[N] " + +#define MSG_SURE_NY "½Ð±z½T©w(Y/N)¡H[N] " +#define MSG_SURE_YN "½Ð±z½T©w(Y/N)¡H[Y] " + +#define MSG_MULTIREPLY "±z½T©wn¸s²Õ¦^«H(Y/N)¡H[N] " + +#define MSG_BID "½Ð¿é¤J¬ÝªO¦WºÙ¡G" +#define MSG_UID "½Ð¿é¤J¥N¸¹¡G" +#define MSG_PASSWD "½Ð¿é¤J±K½X¡G" + +#define ERR_BID "¿ù»~ªº¬ÝªO¦WºÙ" +#define ERR_UID "¿ù»~ªº¨Ï¥ÎªÌ¥N¸¹" +#define ERR_PASSWD "±K½X¿é¤J¿ù»~" +#define ERR_EMAIL "¤£¦X®æªº E-mail address" + +#define MSG_SENT_OK "«H¤w±H¥X" + +#define MSG_LIST_OVER "±zªº¦W³æ¤Ó¦h¡A½Ðµ½¥[¾ã²z" + +#define MSG_COINLOCK "±z¤£¯à¥H¤À¨¶i¦æ³o¼ËªºªA°È" +#define MSG_REG_VALID "±z¤w¸g³q¹L¨¤À»{ÃÒ¡A½Ð«·s¤W¯¸" + +#define MSG_LL "\033[32m[¸s²Õ¦W³æ]\033[m\n" +#define MSG_DATA_CLOAK "<¸ê®Æ«O±K>\n" + +#define MSG_CHKDATA "¡¹ ¸ê®Æ¾ã²z½]®Ö¤¤¡A½ÐµyÔ \033[5m...\033[m" +#define MSG_QUITGAME "¤£ª±¤F°Ú¡H¤U¦¸¦A¨Ó®@¡I ^_^" + +#define MSG_CHAT_ULIST \ +"\033[7m ¨Ï¥ÎªÌ¥N¸¹ ¥Ø«eª¬ºA ¢x ¨Ï¥ÎªÌ¥N¸¹ ¥Ø«eª¬ºA ¢x ¨Ï¥ÎªÌ¥N¸¹ ¥Ø«eª¬ºA \033[m" + + +/* ----------------------------------------------------- */ +/* GLOBAL VARIABLE */ +/* ----------------------------------------------------- */ + + +VAR int bbsmode; /* bbs operating mode, see modes.h */ +VAR usint bbstate; /* bbs operatine state */ + +VAR ACCT cuser; /* current user structure */ +VAR UTMP *cutmp; /* current user temporary */ + +VAR time_t ap_start; /* ¶i¯¸®É¨è */ +VAR int total_user; /* ¨Ï¥ÎªÌ¦Û¥H¬°ªº¯¸¤W¤H¼Æ */ + +VAR int b_lines; /* bottom line */ +VAR int b_cols; /* bottom columns */ +VAR int d_cols; /* difference columns from standard */ + +VAR char fromhost[48]; /* from FQDN */ + +VAR char ve_title[80]; /* edited title */ +VAR char quote_file[80]; +VAR char quote_user[80]; +VAR char quote_nick[80]; + +VAR char hunt[32]; /* hunt keyword */ + +VAR int curredit; /* current edit mode */ +VAR time_t currchrono; /* current file timestamp */ +VAR char currtitle[80]; /* currently selected article title */ + +VAR int currbno; /* currently selected board bno */ +VAR usint currbattr; /* currently selected board battr */ +VAR char currboard[BNLEN + 1]; /* currently selected board brdname */ +VAR char currBM[BMLEN + 7]; /* currently selected board BM */ /* BMLEN + 1 + strlen("ªO¥D¡G") */ + +/* filename */ + +VAR char *fn_acct INI(FN_ACCT); +VAR char *fn_dir INI(FN_DIR); +VAR char *fn_bmw INI(FN_BMW); +VAR char *fn_amw INI(FN_AMW); +VAR char *fn_pal INI(FN_PAL); +VAR char *fn_plans INI(FN_PLANS); +VAR char *fn_note INI(FN_NOTE); +VAR char *fn_lock INI(FN_LOCK); + + +/* message */ + +VAR char *msg_seperator INI(MSG_SEPERATOR); + +VAR char *msg_cancel INI(MSG_CANCEL); + +VAR char *msg_sure_ny INI(MSG_SURE_NY); + +VAR char *msg_uid INI(MSG_UID); + +VAR char *msg_del_ny INI(MSG_DEL_NY); + +VAR char *err_bid INI(ERR_BID); +VAR char *err_uid INI(ERR_UID); +VAR char *err_email INI(ERR_EMAIL); + +VAR char *msg_sent_ok INI(MSG_SENT_OK); + +VAR char *msg_list_over INI(MSG_LIST_OVER); + +VAR char *msg_reg_valid INI(MSG_REG_VALID); +VAR char *msg_coinlock INI(MSG_COINLOCK); + +VAR char *str_sysop INI(STR_SYSOP); +VAR char *str_author1 INI(STR_AUTHOR1); +VAR char *str_author2 INI(STR_AUTHOR2); +VAR char *str_post1 INI(STR_POST1); +VAR char *str_post2 INI(STR_POST2); +VAR char *str_host INI(MYHOSTNAME); +VAR char *str_site INI(BBSNAME); +VAR char *str_line INI(STR_LINE); + +VAR char *str_ransi INI("\033[m"); + +#undef VAR +#undef INI + +#endif /* _GLOBAL_H_ */ diff --git a/include/hdr.h b/include/hdr.h new file mode 100644 index 0000000..f02e965 --- /dev/null +++ b/include/hdr.h @@ -0,0 +1,114 @@ +/*-------------------------------------------------------*/ +/* lib/hdr.h ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : header file for HDR routines */ +/* create : 96/11/20 */ +/* update : 96/12/15 */ +/*-------------------------------------------------------*/ + + +#ifndef _HDR_H_ +#define _HDR_H_ + + +#include <sys/types.h> + + +/* ----------------------------------------------------- */ +/* DIR of post / mail struct : 256 bytes */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + time_t chrono; /* timestamp */ + int xmode; + + int xid; /* reserved */ + + char xname[32]; /* ÀɮצWºÙ */ + char owner[80]; /* §@ªÌ (E-mail address) */ + char nick[49]; /* ¼ÊºÙ */ + char score; /* ¤å³¹µû¤ñ¤À¼Æ */ + + char date[9]; /* 96/12/31 */ + /* Thor.990329:¯S§Oª`·N, date¥u¨ÑÅã¥Ü¥Î, ¤£§@¤ñ¸û, ¥HÁ×§K y2k °ÝÃD, + ©w¸q 2000¬° 00, 2001¬°01 */ + + char title[73]; /* ¥DÃD TTLEN + 1 */ +} HDR; + + +/* gopher url ¦r¦ê¡Gxname + owner + nick + date */ + +#define GEM_URLEN (32 + 80 + 50 + 9 - 1) + + +/* ----------------------------------------------------- */ +/* post.xmode ªº©w¸q */ +/* ----------------------------------------------------- */ + + +#define POST_READ 0x00000001 /* already read */ +#define POST_MARKED 0x00000002 /* marked */ +#define POST_RECORDED 0x00000004 /* ¦³³Q°O¿ý (¦³µ¹¿ú) */ +#define POST_4 0x00000008 +#define POST_5 0x00000010 +#define POST_6 0x00000020 +#define POST_BOTTOM 0x00000040 /* ¸m©³ */ +#define POST_DELETE 0x00000080 /* ¼Ð°O«Ý¬åªº */ +#define POST_INCOME 0x00000100 /* Âà«H¶i¨Óªº */ +#define POST_10 0x00000200 +#define POST_OUTGO 0x00000400 /* ¶·Âà«H¥X¥h */ +#define POST_RESTRICT 0x00000800 /* ¨î¯Å¤å³¹¡A¶· manager/owner ¤~¯à¬Ý */ +#define POST_RESERVED 0x00001000 /* ¨î¯Å¤å³¹¡A¶· sysop ¤~¯à§ó§ï */ +#define POST_14 0x00002000 +#define POST_SCORE 0x00004000 /* ¼Ð°Oµû¤À¹Lªº */ +#define POST_16 0x00008000 + + +/* ----------------------------------------------------- */ +/* mail.xmode ªº©w¸q */ +/* ----------------------------------------------------- */ + + +#define MAIL_READ 0x00000001 /* already read */ +#define MAIL_MARKED 0x00000002 /* marked */ +#define MAIL_REPLIED 0x00000004 /* ¤w¸g¦^¹L«H¤F */ +#define MAIL_MULTI 0x00000008 /* mail list */ +#define MAIL_5 0x00000010 +#define MAIL_NOREPLY 0x00000020 /* ¤£¥i¦^«H */ +#define MAIL_BOTTOM 0x00000040 /* ¸m©³ */ +#define MAIL_DELETE 0x00000080 /* ±N¾D§R°£ */ +#define MAIL_INCOME 0x00000100 /* bbsmail ¶i¨Óªº */ +#define MAIL_10 0x00000200 +#define MAIL_11 0x00000400 +#define MAIL_RESTRICT 0x00000800 /* ¨î¯Å«H¥ó¡A¶· manager/owner ¤~¯à¬Ý */ +#define MAIL_RESERVED 0x00001000 /* ¨î¯Å«H¥ó¡A¶· sysop ¤~¯à§ó§ï */ +#define MAIL_14 0x00002000 +#define MAIL_15 0x00004000 +#define MAIL_16 0x00008000 + + +/* ----------------------------------------------------- */ +/* gem(gopher).xmode ªº©w¸q */ +/* ----------------------------------------------------- */ + + +/* itoc.010602.µù¸Ñ: GEM_RESTRICT/RESERVED ©M POST_RESTRICT/RESERVED n¤Ç°t */ +#define GEM_RESTRICT 0x00000800 /* ¨î¯ÅºëµØ°Ï¡A¶· manager/owner ¤~¯à¬Ý */ +#define GEM_RESERVED 0x00001000 /* ¨î¯ÅºëµØ°Ï¡A¶· sysop ¤~¯à§ó§ï */ + +#define GEM_FOLDER 0x00010000 /* folder / article */ +#define GEM_BOARD 0x00020000 /* ¬ÝªOºëµØ°Ï */ +#define GEM_LINE 0x00080000 /* ¤À¹j½u */ + +/* ----------------------------------------------------- */ +/* hdr_stamp() ªº©w¸q */ +/* ----------------------------------------------------- */ + + +#define HDR_LINK 0x400 /* link() */ +#define HDR_COPY 0x800 /* copy */ + +#endif /* _HDR_H_ */ diff --git a/include/modes.h b/include/modes.h new file mode 100644 index 0000000..92af120 --- /dev/null +++ b/include/modes.h @@ -0,0 +1,253 @@ +/*-------------------------------------------------------*/ +/* modes.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : user operating mode & status */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ + + +#ifndef _MODES_H_ +#define _MODES_H_ + + +/* ----------------------------------------------------- */ +/* user ¾Þ§@ª¬ºA»P¼Ò¦¡ */ +/* ----------------------------------------------------- */ + +/* itoc.010329.µù¸Ñ: §â 0 «O¯d¡A®³¨Ó°µ¯S®í¥Î³~ */ + +#define M_0MENU 1 /* main MENU */ +#define M_AMENU 2 /* admin MENU */ +#define M_MMENU 3 /* mail MENU */ +#define M_TMENU 4 /* talk MENU */ +#define M_UMENU 5 /* user MENU */ +#define M_XMENU 6 /* tool MENU */ + /* M_XMENU ¬O menu ªº³Ì«á¤@Ó */ + /* M_XMENU ¤§«e¦³°ÊºA¬ÝªO */ + +#define M_LOGIN 7 /* login */ + +#define M_GEM 8 /* announce */ +#define M_BOARD 9 /* board list */ +#define M_MF 10 /* my favorite */ +#define M_READA 11 /* read article */ +#define M_RMAIL 12 /* read mail */ + +#define M_PAL 13 /* set pal/aloha list */ +#define M_LUSERS 14 /* user list */ +#define M_VOTE 15 +#define M_BMW 16 +#define M_SONG 17 +#define M_COSIGN 18 + +#define M_SYSTEM 19 /* ¡÷ M_SYSTEM(§t) »P M_CHAT(§t) ¶¡¤£±µ¨ü talk request */ + +#define M_XFILES 20 /* admin set system files */ +#define M_UFILES 21 /* user set user files */ + +#define M_BMW_REPLY 22 +#define M_GAME 23 +#define M_POST 24 +#define M_SMAIL 25 +#define M_TRQST 26 + +#define M_TALK 27 /* ¡ö M_TALK(§t) »P M_IDLE(§t) ¶¡±µ mateid */ +#define M_CHAT 28 /* ¡÷ M_BBTP(§t) »P M_CHAT(§t) ¶¡¤£±µ¨ü talk request */ +#define M_PAGE 29 +#define M_QUERY 30 +#define M_IDLE 31 /* ¡ö M_TALK(§t) »P M_IDLE(§t) ¶¡±µ mateid */ + +#define M_XMODE 32 +#define M_MAX M_XMODE + + +#ifdef _MODES_C_ +static char *ModeTypeTable[] = +{ + "«O¯d", + + "¥D¿ï³æ", /* M_0MENU */ + "¨t²ÎºûÅ@", /* M_AMENU */ + "¶l¥ó¿ï³æ", /* M_MMENU */ + "¥æ½Í¿ï³æ", /* M_TMENU */ + "¨Ï¥ÎªÌ¿ï³æ", /* M_UMENU */ + "Xyz ¿ï³æ", /* M_XMENU */ + + "¤W¯¸³~¤¤", /* M_LOGIN */ + + "ºëµØ°Ï", /* M_GEM */ + "¬ÝªO¦Cªí", /* M_BOARD */ + "§Úªº³Ì·R", /* M_MF */ + "¾\\ۤ峹", /* M_READA */ + "Ū«H", /* M_RMAIL */ + + "µ²¥æªB¤Í", /* M_PAL */ + "¨Ï¥ÎªÌ¦W³æ", /* M_LUSERS */ + "§ë²¼¤¤", /* M_VOTE */ + "¹î¬Ý¤ô²y", /* M_BMW */ + "ÂIºq", /* M_SONG */ + "¬ÝªO³s¸p", /* M_COSIGN */ + + "¨t²ÎºÞ²z", /* M_SYSTEM */ + + "½s¨t²ÎÀÉ®×", /* M_XFILES */ + "½sÓ¤HÀÉ®×", /* M_UFILES */ + + "¤ô²y·Ç³Æ¤¤", /* M_BMW_REPLY */ + "ª±¹CÀ¸", /* M_GAME */ + "µoªí¤å³¹", /* M_POST */ + "¼g«H", /* M_SMAIL */ + "«Ý¾÷", /* M_TRQST */ + + "¥æ½Í", /* M_TALK */ /* ±µ mateid ªº°ÊºA¤¤¤å¦r¤£¥i¤Óªø */ + "²á¤Ñ", /* M_CHAT */ + "©I¥s", /* M_PAGE */ + "¬d¸ß", /* M_QUERY */ + "µo§b", /* M_IDLE */ + + "¨ä¥L" /* M_XMODE */ +}; +#endif /* _MODES_C_ */ + + +/* ----------------------------------------------------- */ +/* menu.c ¤¤ªº¼Ò¦¡ */ +/* ----------------------------------------------------- */ + + +#define XEASY 0x333 /* Return value to un-redraw screen */ + + +/* ----------------------------------------------------- */ +/* pal.c ¤¤ªº¼Ò¦¡ */ +/* ----------------------------------------------------- */ + + +#define PALTYPE_PAL 0 /* ªB¤Í¦W³æ */ +#define PALTYPE_LIST 1 /* ¸s²Õ¦W³æ */ +#define PALTYPE_BPAL 2 /* ªO¤Í¦W³æ */ +#define PALTYPE_VOTE 3 /* ¨î§ë²¼¦W³æ */ + + +/* ----------------------------------------------------- */ +/* visio.c ¤¤ªº¼Ò¦¡ */ +/* ----------------------------------------------------- */ + + +/* Flags to getdata input function */ + +#define NOECHO 0x0000 /* ¤£Åã¥Ü¡A¥Î©ó±K½X¨ú±o */ +#define DOECHO 0x0100 /* ¤@¯ëÅã¥Ü */ +#define LCECHO 0x0200 /* low case echo¡A´«¦¨¤p¼g */ +#define GCARRY 0x0400 /* ·|Åã¥Ü¤W¤@¦¸/¥Ø«eªºÈ */ + +#define GET_LIST 0x1000 /* ¨ú±o Link List */ +#define GET_USER 0x2000 /* ¨ú±o user id */ +#define GET_BRD 0x4000 /* ¨ú±o board id */ + + +/* ----------------------------------------------------- */ +/* read.c ¤¤ªº¼Ò¦¡ */ +/* ----------------------------------------------------- */ + +/* for tag */ + +#define TAG_NIN 0 /* ¤£ÄÝ©ó TagList */ +#define TAG_TOGGLE 1 /* ¤Á´« Taglist */ +#define TAG_INSERT 2 /* ¥[¤J TagList */ + + +/* for bbstate : bbs operating state */ + +#define STAT_POST 0x0010000 /* ¬O§_¥i¥H¦b currboard µoªí¤å³¹ */ +#define STAT_BOARD 0x0020000 /* ¬O§_¥i¥H¦b currboard §R°£¡Bmark¤å³¹ (ªO¥D¡B¬ÝªOÁ`ºÞ) */ +#define STAT_BM 0x0040000 /* ¬O§_¬° currboard ªºªO¥D */ +#define STAT_LOCK 0x0100000 /* ¬O§_¬°Âê©w¿Ã¹õ */ +#define STAT_STARTED 0x8000000 /* ¬O§_¤w¸g¶i¤J¨t²Î */ + + +/* for user's board permission level & state record */ + +#define BRD_L_BIT 0x0001 /* ¥i¦C¡Alist */ +#define BRD_R_BIT 0x0002 /* ¥iŪ¡Aread */ +#define BRD_W_BIT 0x0004 /* ¥i¼g¡Awrite */ +#define BRD_X_BIT 0x0008 /* ¥iºÞ¡Aexecute¡AªO¥D¡B¬ÝªOÁ`ºÞ */ +#define BRD_M_BIT 0x0010 /* ¥i²z¡Amanage¡AªO¥D */ + +#define BRD_V_BIT 0x0020 /* ¤w¸g³}¹L¤F¡Avisit ==> ¬Ý¹L¡u¶iªOµe±¡v */ +#define BRD_H_BIT 0x0040 /* .BRH ¤¤¦³¾\Ū°O¿ý (history) */ +#define BRD_Z_BIT 0x0080 /* .BRH zap ±¼¤F */ + + +/* for user's gem permission level record */ + +#define GEM_W_BIT 0x0001 /* ¥i¼g¡Awrite¡AªO¥D¡A¬ÝªOÁ`ºÞ */ +#define GEM_X_BIT 0x0002 /* ¥iºÞ¡Aexecute¡A¯¸ªø */ +#define GEM_M_BIT 0x0004 /* ¥i²z¡Amanage¡AªO¥D */ + + +/* for curredit */ + +#define EDIT_MAIL 0x0001 /* ¥Ø«e¬O mail/board ? */ +#define EDIT_LIST 0x0002 /* ¬O§_¬° mail list ? */ +#define EDIT_BOTH 0x0004 /* both reply to author/board ? */ +#define EDIT_OUTGO 0x0008 /* «ÝÂà«H¥X¥h */ +#define EDIT_ANONYMOUS 0x0010 /* °Î¦W¼Ò¦¡ */ +#define EDIT_RESTRICT 0x0020 /* ¥[±K¦sÀÉ */ +#define EDIT_BOTTOM 0x0040 /* ¸m©³¦sÀÉ */ + +/* ----------------------------------------------------- */ +/* xover.c ¤¤ªº¼Ò¦¡ */ +/* ----------------------------------------------------- */ + + +#define XO_DL 0x80000000 + +#define XO_MODE 0x10000000 + + +#define XO_NONE (XO_MODE + 0) +#define XO_INIT (XO_MODE + 1) +#define XO_LOAD (XO_MODE + 2) +#define XO_HEAD (XO_MODE + 3) +#define XO_NECK (XO_MODE + 4) +#define XO_BODY (XO_MODE + 5) +#define XO_FOOT (XO_MODE + 6) /* itoc.µù¸Ñ: ²M°£ b_lines */ +#define XO_LAST (XO_MODE + 7) +#define XO_QUIT (XO_MODE + 8) + + +#define XO_RSIZ 256 /* max record length */ +#define XO_TALL (b_lines - 3) /* page size = b_lines - 3 (¦©¥h head/neck/foot ¦@¤T¦æ) */ + + +#define XO_MOVE 0x20000000 /* cursor movement */ +#define XO_WRAP 0x08000000 /* cursor wrap in movement */ +#define XO_TAIL (XO_MOVE - 999) /* init cursor to tail */ + + +#define XO_ZONE 0x40000000 /* ¶i¤J¬Y¤@Ó zone */ +#define XZ_BACK 0x100 + + +#define XZ_CLASS (XO_ZONE + 0) /* ¬ÝªO¦Cªí */ +#define XZ_ULIST (XO_ZONE + 1) /* ½u¤W¨Ï¥ÎªÌ¦W³æ */ +#define XZ_PAL (XO_ZONE + 2) /* ªB¤Í¦W³æ */ +#define XZ_ALOHA (XO_ZONE + 3) /* ¤W¯¸³qª¾¦W³æ */ +#define XZ_VOTE (XO_ZONE + 4) /* §ë²¼ */ +#define XZ_BMW (XO_ZONE + 5) /* ¤ô²y */ +#define XZ_MF (XO_ZONE + 6) /* §Úªº³Ì·R */ +#define XZ_COSIGN (XO_ZONE + 7) /* ³s¸p */ +#define XZ_SONG (XO_ZONE + 8) /* ÂIºq */ +#define XZ_NEWS (XO_ZONE + 9) /* ·s»D¾\Ū¼Ò¦¡ */ + +/* ¥H¤Uªº¦³ thread ¥DÃD¦¡¾\Ūªº¥\¯à */ +/* ¥H¤Uªº¦³ tag ¥\¯à */ + +#define XZ_XPOST (XO_ZONE + 10) /* ·j´M¤å³¹¼Ò¦¡ */ +#define XZ_MBOX (XO_ZONE + 11) /* «H½c */ +#define XZ_POST (XO_ZONE + 12) /* ¬ÝªO */ +#define XZ_GEM (XO_ZONE + 13) /* ºëµØ°Ï */ + +#endif /* _MODES_H_ */ diff --git a/include/perm.h b/include/perm.h new file mode 100644 index 0000000..6c73e31 --- /dev/null +++ b/include/perm.h @@ -0,0 +1,160 @@ +/*-------------------------------------------------------*/ +/* perm.h ( NTHU CS MapleBBS Ver 2.36 ) */ +/*-------------------------------------------------------*/ +/* target : permission levels of user & board */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ + + +#ifndef _PERM_H_ +#define _PERM_H_ + + +/* ----------------------------------------------------- */ +/* These are the 32 basic permission bits. */ +/* ----------------------------------------------------- */ + +#define PERM_BASIC 0x00000001 /* 1-8 : °ò¥»Åv */ +#define PERM_CHAT 0x00000002 +#define PERM_PAGE 0x00000004 +#define PERM_POST 0x00000008 +#define PERM_VALID 0x00000010 /* LOGINOK */ +#define PERM_MBOX 0x00000020 +#define PERM_CLOAK 0x00000040 +#define PERM_XEMPT 0x00000080 + +#define PERM_CHANGEID 0x00000100 +#define PERM_ELDER 0x00000200 +#define PERM_ROBOT 0x00000400 +#define PERM_MSCORE 0x00000800 +#define PERM_13 0x00001000 +#define PERM_14 0x00002000 +#define PERM_15 0x00004000 +#define PERM_16 0x00008000 + +#define PERM_DENYPOST 0x00010000 /* 17-24 : ¸T¨îÅv */ +#define PERM_DENYTALK 0x00020000 +#define PERM_DENYCHAT 0x00040000 +#define PERM_DENYMAIL 0x00080000 +#define PERM_DENY5 0x00100000 +#define PERM_DENY6 0x00200000 +#define PERM_DENYLOGIN 0x00400000 +#define PERM_PURGE 0x00800000 + +#define PERM_BM 0x01000000 /* 25-32 : ºÞ²zÅv */ +#define PERM_SEECLOAK 0x02000000 +#define PERM_CAST 0x04000000 +#define PERM_REGISTRAR 0x08000000 +#define PERM_ACCOUNTS 0x10000000 +#define PERM_CHATROOM 0x20000000 +#define PERM_BOARD 0x40000000 +#define PERM_SYSOP 0x80000000 + + +/* ----------------------------------------------------- */ +/* These permissions are bitwise ORs of the basic bits. */ +/* ----------------------------------------------------- */ + + +/* This is the default permission granted to all new accounts. */ +#define PERM_DEFAULT PERM_BASIC + +/* ¦³ PERM_VALID ¤~¥i¥H«O¤H¶i¨Ó¥»¯¸µù¥U */ +#ifdef HAVE_GUARANTOR +#define PERM_GUARANTOR PERM_VALID +#endif + +#if 0 /* itoc.»¡©ú: Ãö©ó¯¸°ÈÅv */ + + ©Ò¦³µ{¦¡ªºÃö©ó¯¸°ÈªºÅv³£§ï¦¨ PERM_ALLXXXX + ¦b¦¹µe¤@ӹϨӴyz¯¸°ÈÅvªº³]©w¡C + + ¢z µù¥UÁ`ºÞ PERM_REGISTRAR : ¥i¥H¼fµù¥U³æ¡C + ¢x + ¢u ±b¸¹Á`ºÞ PERM_ACCOUNTS : ¥i¥H×§ïÅv¡B½ð½u¤W¨Ï¥ÎªÌ¡B¼fµù¥U³æ¡C + ¢x + ¯¸ªø PERM_SYSOP ¢q ²á¤Ñ«ÇÁ`ºÞ PERM_CHATROOM : ¦b²á¤Ñ«Ç¬O roomop¡C + ¢x + ¢u ¬ÝªOÁ`ºÞ PERM_BOARD : ¥i¥H×§ï¬ÝªO³]©w¡B¶i¤J¯µ±K¤Î¦n¤Í¬ÝªO¡C + ¢x + ¢| ¥þÅ鯸°È PERM_ALLADMIN : ¥H¤W¥|ÓÁ`ºÞ¡A³£¦³¥H¤U¥\¯à¡G + ¤W¯¸¨Ó·½³]©w¡BÁô¨³N¡BµµÁô¡B¬Ý¨£«O±KªººëµØ°Ï¡B + ¤£¥²©w´Á»{ÃÒ¡BµL¶··s¤â¨£²ß¤T¤Ñ¡Bmulti-login¡B + קﯸ¤W¤å¥ó¡B§ó·s¨t²Î¡B¤Þ¨¥¥i¥H¹L¦h¡B + ±H«Hµ¹¥þ¯¸¨Ï¥ÎªÌ¡B«H½cµL¤W¡C + + ¯¸ªø PERM_SYSOP °£¤F¥H¤W©Ò¦³¥\¯à¡AÁÙ¾Ö¦³¥H¤U¥\¯à¡G + ºëµØ°Ï«Ø¸mµ·¸ô¤Î¸ê®Æ¡B¾\Ū©Ò¦³¤Hªº«H¥ó¡B±oª¾©Ò¦³¤H¦b¬ÝþÓªO¡B¶}±Ò¯¸°ÈÅv¡C + +#endif + +#define PERM_ALLADMIN (PERM_REGISTRAR | PERM_BOARD | PERM_ACCOUNTS | PERM_SYSOP) /* ¯¸°È */ +#define PERM_ALLREG (PERM_SYSOP | PERM_ACCOUNTS | PERM_REGISTRAR) /* ¼fµù¥U³æ */ +#define PERM_ALLACCT (PERM_SYSOP | PERM_ACCOUNTS) /* ±b¸¹ºÞ²z */ +#define PERM_ALLCHAT (PERM_SYSOP | PERM_CHATROOM) /* ²á¤ÑºÞ²z */ +#define PERM_ALLBOARD (PERM_SYSOP | PERM_BOARD) /* ¬ÝªOºÞ²z */ + +#define PERM_ALLVALID (PERM_VALID | PERM_POST | PERM_PAGE | PERM_CHAT) /* »{ÃÒ³q¹L«áÀ³¦³ªº§¹¾ãÅv */ +#define PERM_ALLDENY (PERM_DENYPOST | PERM_DENYTALK | PERM_DENYCHAT | PERM_DENYMAIL) /* ©Ò¦³°±Åv */ + +#define PERM_LOCAL PERM_BASIC /* ¤£¬O guest ´N¯à±H«H¨ì¯¸¤º¨ä¥L¨Ï¥ÎªÌ */ +#define PERM_INTERNET PERM_VALID /* ¨¤À»{ÃÒ¹LÃöªº¤~¯à±H«H¨ì Internet */ + +/* #define HAS_PERM(x) ((x)?cuser.userlevel&(x):1) */ +/* #define HAVE_PERM(x) (cuser.userlevel&(x)) */ +/* itoc.001217: µ{¦¡¤¤¤£·|¦³ HAS_PERM(0) ªº¼gªk¡AHAVE_PERM ¤£·|¥Î¨ì */ +#define HAS_PERM(x) (cuser.userlevel&(x)) + + +/* ----------------------------------------------------- */ +/* ¦UºØÅvªº¤¤¤å·N¸q */ +/* ----------------------------------------------------- */ + +#define NUMPERMS 32 + +#define STR_PERM "bctpjm#xecrs---@PTCM--L*B#ERACBS" /* itoc: ·s¼WÅvªº®ÉÔ§O§Ñ¤F§ï³o¸Ì°Ú */ + +#ifdef _ADMIN_C_ + +static char *perm_tbl[NUMPERMS] = +{ + "°ò¥»Åv¤O", /* PERM_BASIC */ + "¶i¤J²á¤Ñ«Ç", /* PERM_CHAT */ + "§ä¤H²á¤Ñ", /* PERM_PAGE */ + "µoªí¤å³¹", /* PERM_POST */ + "¨¤À»{ÃÒ", /* PERM_VALID */ + "«H¥óµL¤W", /* PERM_MBOX */ + "Áô¨³N", /* PERM_CLOAK */ + "¥Ã¤[«O¯d±b¸¹", /* PERM_XEMPT */ + + "¥i¥H§ïID", /* PERM_CHANGEID */ + "¦Ñ¤H", /* PERM_ELDER */ + "¾÷¾¹", /* PERM_ROBOT */ + "ªO¥D§ï±À¤å¼Æ", /* PERM_MSCORE */ + "«O¯d", /* PERM_13 */ + "«O¯d", /* PERM_14 */ + "«O¯d", /* PERM_15 */ + "«O¯d", /* PERM_16 */ + + "¸T¤îµoªí¤å³¹", /* PERM_DENYPOST */ + "¸T¤î talk", /* PERM_DENYTALK */ + "¸T¤î chat", /* PERM_DENYCHAT */ + "¸T¤î mail", /* PERM_DENYMAIL */ + "«O¯d", /* PERM_DENY5 */ + "«O¯d", /* PERM_DENY6 */ + "¸T¤î login", /* PERM_DENYLOGIN */ + "²M°£±b¸¹", /* PERM_PURGE */ + + "ªO¥D", /* PERM_BM */ + "¬Ý¨£§ÔªÌ", /* PERM_SEECLOAK */ + "¥þ¯¸¼s¼½", /* PERM_CAST */ + "µù¥UÁ`ºÞ", /* PERM_REGISTRAR */ + "±b¸¹Á`ºÞ", /* PERM_ACCOUNTS */ + "²á¤Ñ«ÇÁ`ºÞ", /* PERM_CHATCLOAK */ + "¬ÝªOÁ`ºÞ", /* PERM_BOARD */ + "¯¸ªø" /* PERM_SYSOP */ +}; + +#endif +#endif /* _PERM_H_ */ diff --git a/include/proto.h b/include/proto.h new file mode 100644 index 0000000..d5c36da --- /dev/null +++ b/include/proto.h @@ -0,0 +1,52 @@ +/*-------------------------------------------------------*/ +/* proto.h ( NTHU CS MapleBBS Ver 2.36 ) */ +/*-------------------------------------------------------*/ +/* target : prototype and macros */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ + + +#ifndef _PROTO_H_ +#define _PROTO_H_ + + +/* ----------------------------------------------------- */ +/* External function declarations */ +/* ----------------------------------------------------- */ + +/* OS */ + +char *genpasswd(); + + +/* ----------------------------------------------------- */ +/* prototypes */ +/* ----------------------------------------------------- */ + + +#include "../maple/maple.p" + + +/* ----------------------------------------------------- */ +/* macros */ +/* ----------------------------------------------------- */ + + +#define dashd(fpath) S_ISDIR(f_mode(fpath)) +#define dashf(fpath) S_ISREG(f_mode(fpath)) + + +#define STR4(x) ((x[0] << 24) + (x[1] << 16) + (x[2] << 8) + x[3]) + /* Thor.980913: «OÃÒprecedence */ + +#define IS_ZHC_LO is_zhc_low +#define IS_ZHC_HI(x) (x & 0x80) + +#if 0 +#define rnd(x) (rand() % (x)) /* using lower-order bits */ +#endif + +#define rnd(x) ((int) (((x) + 0.0) * rand() / (RAND_MAX + 1.0))) /* using high-order bits */ + +#endif /* _PROTO_H_ */ diff --git a/include/splay.h b/include/splay.h new file mode 100644 index 0000000..f8c552b --- /dev/null +++ b/include/splay.h @@ -0,0 +1,16 @@ +#ifndef _SPLAY_H_ +#define _SPLAY_H_ + + +typedef struct SplayNode +{ + void *data; + struct SplayNode *left; + struct SplayNode *right; +} SplayNode; + + +SplayNode *splay_in(SplayNode *top, void *data, int (*compare)()); + + +#endif /* _SPLAY_H_ */ diff --git a/include/struct.h b/include/struct.h new file mode 100644 index 0000000..ea9cccb --- /dev/null +++ b/include/struct.h @@ -0,0 +1,710 @@ +/*-------------------------------------------------------*/ +/* struct.h ( NTHU CS MapleBBS Ver 2.36 ) */ +/*-------------------------------------------------------*/ +/* target : all definitions about data structure */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ + + +#ifndef _STRUCT_H_ +#define _STRUCT_H_ + + +/* screen control */ + +#define STRLEN 80 /* Length of most string data */ +#define ANSILINELEN 250 /* Maximum Screen width in chars */ + +/* itoc.031123: ¿Ã¹õªº¼e«×³]¬° 80 ¤]µL§«¡A¥u¬O¦³¨Ç telnet term ¦b¶K¤W¤å¦r¤Óªø®É¡A + ·|¦Û°ÊÂ_¦æ¦b 79¡A©Ò¥H¦b¦¹´N±q¨ä³]©w */ +#define SCR_WIDTH 79 /* edit/more/talk/visio screen width */ + +#define TAB_STOP 4 /* «ö TAB ´«¦¨´X®æªÅ¥Õ (n¬O 2 ªº¦¸¤è) */ +#define TAB_WIDTH (TAB_STOP - 1) + +#define T_LINES 50 /* maximum total lines */ +#define T_COLS 120 /* maximum total columns¡An¤ñ ANSILINELEN ¤p */ + +/* board structure */ + +#define BNLEN 12 /* Length of board name */ +#define BCLEN 4 /* Length of board class */ +#define BTLEN 43 /* Length of board title */ +#define BMLEN 36 /* Length of board managers */ + +/* file structure */ + +#define TTLEN 72 /* Length of title */ +#define FNLEN 28 /* Length of filename */ + +/* user structure */ +/* DES ½s½Xªk¡A±µ¨ü 8 Ó¦r¤¸ªø«×ªº¦r¦ê¡A²£¥ÍªºÁäȬ° 13 ¦ì¤¸²Õ */ + +#define IDLEN 12 /* Length of user id */ +#define PASSLEN 13 /* Length of encrypted passwd field */ +#define PSWDLEN 8 /* Length of passwd (¥¼¥[±Kªºªø«×) */ +#define RNLEN 19 /* Length of real name */ +#define UNLEN 23 /* Length of user name */ + + +typedef char const *STRING; +typedef unsigned char uschar; /* length = 1 */ +typedef unsigned int usint; /* length = 4 */ +typedef struct UTMP UTMP; + + +/* ----------------------------------------------------- */ +/* ¨Ï¥ÎªÌ±b¸¹ .ACCT struct : 512 bytes */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + int userno; /* unique positive code */ + + char userid[IDLEN + 1]; /* ID */ + char passwd[PASSLEN + 1]; /* ±K½X */ + char realname[RNLEN + 1]; /* ¯u¹ê©m¦W */ + char username[UNLEN + 1]; /* ¼ÊºÙ */ + + usint userlevel; /* Åv */ + usint ufo; /* habit */ + uschar signature; /* ¹w³]ñ¦WÀÉ */ + + unsigned char year; /* ¥Í¤é(¥Á°ê¦~) */ + unsigned char month; /* ¥Í¤é(¤ë) */ + unsigned char day; /* ¥Í¤é(¤é) */ + char sex; /* ©Ê§O 0:¤¤©Ê ©_¼Æ:¨k©Ê °¸¼Æ:¤k©Ê */ + int money; /* »È¹ô */ + int gold; /* ª÷¹ô */ + + int numlogins; /* ¤W¯¸¦¸¼Æ */ + int numposts; /* µoªí¦¸¼Æ */ + int numemails; /* ±Hµo Inetrnet E-mail ¦¸¼Æ */ + + time_t firstlogin; /* ²Ä¤@¦¸¤W¯¸®É¶¡ */ + time_t lastlogin; /* ¤W¤@¦¸¤W¯¸®É¶¡ */ + time_t tcheck; /* ¤W¦¸ check «H½c/ªB¤Í¦W³æªº®É¶¡ */ + time_t tvalid; /* Y°±Åv¡A°±Åv´Áº¡ªº®É¶¡¡F + Y¥¼°±Åv¥B³q¹L»{ÃÒ¡A³q¹L»{ÃÒªº®É¶¡¡F + Y¥¼°±Åv¥B¥¼³q¹L»{ÃÒ¡A»{ÃҨ窺 time-seed */ + + char lasthost[30]; /* ¤W¦¸µn¤J¨Ó·½ */ + char email[60]; /* ¥Ø«eµn°Oªº¹q¤l«H½c */ +} ACCT; + + +typedef struct /* 16 bytes */ +{ + time_t uptime; + char userid[IDLEN]; +} SCHEMA; + + +#ifdef HAVE_REGISTER_FORM + +/* itoc.041025: RFROM ¤£À³¥X²{©M ACCT ¤@¼Ë¦ýÈ¥i¯à¤£¦PªºÄæ¦ì + RFORM ©M ACCT °ß¤G¬Û¦PªºÄæ¦ì¬O userno¡Buserid */ + +typedef struct /* µù¥Uªí³æ (Register From) 256 bytes */ +{ + int userno; + time_t rtime; + char userid[IDLEN + 1]; + char agent[IDLEN + 1]; + char nouse[20]; + char career[50]; + char address[60]; + char phone[20]; + char reply[72]; +} RFORM; + +#endif + + +#include "hdr.h" + + +/* ----------------------------------------------------- */ +/* control of board vote : 256 bytes */ +/* ----------------------------------------------------- */ + + +/* itoc.041101.µù¸Ñ: VCH ©M HDR ªº xname ¦ì¸m¡Bªø«×n¤Ç°t */ + +typedef struct VoteControlHeader +{ + time_t chrono; /* §ë²¼¶}¿ì®É¶¡ */ /* Thor: ¬° key ¦Ó¥B match HDR chrono */ + time_t bstamp; /* ¬ÝªO¿ëÃÑ¥N½X */ /* Thor: ¬° key */ + time_t vclose; /* §ë²¼µ²§ô®É¶¡ */ + + char xname[32]; /* ¥DÀɦW */ /* Thor: match HDR ªº xname */ + char date[9]; /* ¶}©l¤é´Á */ /* Thor: match HDR ªº date */ + char cdate[9]; /* µ²§ô¤é´Á */ /* Thor: ¥u¨ÑÅã¥Ü¡A¤£°µ¤ñ¸û */ + char owner[IDLEN + 1]; /* Á|¿ì¤H */ + char title[TTLEN + 1]; /* §ë²¼¥DÃD */ + + char vgamble; /* ¬O§_¬°½ä½L '$':½ä½L ' ':¤@¯ë§ë²¼ */ + char vsort; /* ¶}²¼µ²ªG¬O§_±Æ§Ç 's':±Æ§Ç ' ':¤£±Æ§Ç */ + char vpercent; /* ¬O§_Åã¥Ü¦Ê¤À¤ñ¨Ò '%':¦Ê¤À ' ':¤@¯ë */ + char vprivate; /* ¬O§_¬°¨p¤H§ë²¼ ')':¨p¤H ' ':¤½¶} */ + + int maxblt; /* ¨C¤H¥i§ë´X²¼ */ + int price; /* ¨C±i½ä²¼ªº°â»ù */ + + char nouse[96]; +} VCH; + + +typedef char vitem_t[32]; /* §ë²¼¿ï¶µ */ + + +typedef struct +{ + char userid[IDLEN + 1]; + char numvotes; /* §ë´X±i */ + usint choice; +} VLOG; + + +/* filepath : brd/<board>/.VCH, brd/<board>/@/... */ + + +/* ----------------------------------------------------- */ +/* Mail-Queue struct : 256 bytes */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + time_t mailtime; /* ±H«H®É¶¡ */ + char method; + char sender[IDLEN + 1]; + char username[UNLEN + 1]; + char subject[TTLEN + 1]; + char rcpt[60]; + char filepath[77]; + char *niamod; /* reverse domain */ +} MailQueue; + + +#define MQ_JUSTIFY 0x01 /* ¨¤À»{ÃÒ«H¨ç */ +#define MQ_ATTACH 0x02 /* ¦³ attachment ªº«H¨ç */ + + +/* ----------------------------------------------------- */ +/* PAL : friend struct : 64 bytes */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + char userid[IDLEN + 1]; + char ftype; + char ship[46]; + int userno; +} PAL; + +#define PAL_BAD 0x02 /* ¦n¤Í vs Ãa¤H */ + + +/* ----------------------------------------------------- */ +/* structure for call-in message : 100 bytes */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + time_t btime; + UTMP *caller; /* who call-in me ? */ + int sender; /* calling userno */ + int recver; /* called userno */ + char userid[IDLEN + 1 + 2]; /* itoc.010529: «O¯d 2 byte µ¹¼s¼½²Å¸¹ > */ + char msg[69]; /* ¤ô²y */ +} BMW; /* bbs message write */ + + +#ifdef LOGIN_NOTIFY + +/* ----------------------------------------------------- */ +/* BENZ : ¨t²Î¨ó´M¦W³æ : 20 bytes */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + int userno; + char userid[IDLEN + 1]; +} BENZ; + +#endif /* LOGIN_NOTIFY */ + + +#ifdef HAVE_ALOHA + +/* ----------------------------------------------------- */ +/* ALOHA : ¤W¯¸³qª¾¦W³æ : 20 bytes */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + char userid[IDLEN + 1]; + int userno; +} ALOHA; + + +/* ----------------------------------------------------- */ +/* FRIENZ : ¤W¯¸³qª¾¦W³æ : 100 bytes */ +/* ----------------------------------------------------- */ + + +/* itoc.041011.µù¸Ñ: ®Ú¥»¨S¥²n¥Î³o»ò¤j */ + +typedef struct +{ + int nouse1; + int nouse2; + int nouse3; + int userno; + char userid[IDLEN + 1]; + char nouse4[71]; +} FRIENZ; + +#endif /* HAVE_ALOHA */ + + +/* ----------------------------------------------------- */ +/* PAYCHECK : ¤ä²¼ : 32 bytes */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + time_t tissue; /* µo¤ä²¼®É¶¡ */ + int money; + int gold; + char reason[20]; +} PAYCHECK; + + +/* ----------------------------------------------------- */ +/* Structure used in UTMP file : 128 bytes */ +/* lantw44: ¥[¤J realid ©Ò¥H¼W¬° 141 bytes */ +/* ----------------------------------------------------- */ + + +struct UTMP +{ + pid_t pid; /* process ID */ + int userno; /* user number */ + + int mode; /* bbsmode */ + usint userlevel; /* the save as ACCT.userlevel */ + usint ufo; /* the same as ACCT.ufo */ + usint status; /* status */ + + time_t idle_time; /* active time for last event */ + u_long in_addr; /* Internet address */ + int sockport; /* socket port for talk */ + UTMP *talker; /* who talk-to me ? */ + + BMW *mslot[BMW_PER_USER]; + + char userid[IDLEN + 1]; /* user's ID */ + char realid[IDLEN + 1]; /* user's real ID */ + char mateid[IDLEN + 1]; /* partner's ID */ + char username[UNLEN + 1]; /* user's nickname */ + char from[34]; /* remote host */ +#ifdef HAVE_BRDMATE + char reading[BNLEN + 1]; /* reading board */ +#endif + + int pal_max; /* ¦³´XÓªB¤Í */ + int pal_spool[PAL_MAX]; /* ©Ò¦³ªB¤Íªº userno */ + +#ifdef BMW_COUNT + int bmw_count; /* °O¿ý¤¤¤F´XÓ¤ô²y */ +#endif +}; + + +/* ----------------------------------------------------- */ +/* BOARDS struct : 128 bytes */ +/* ----------------------------------------------------- */ + + +typedef struct BoardHeader +{ + char brdname[BNLEN + 1]; /* board name */ + char class[BCLEN + 1]; + char title[BTLEN + 1]; + char BM[BMLEN + 1]; /* BMs' uid, token '/' */ + + char bvote; /* 0:µL§ë²¼ -1:¦³½ä½L(¥i¯à¦³§ë²¼) 1:¦³§ë²¼ */ + + time_t bstamp; /* «Ø¥ß¬ÝªOªº®É¶¡, unique */ + usint readlevel; /* ¾\ۤ峹ªºÅv */ + usint postlevel; /* µoªí¤å³¹ªºÅv */ + usint battr; /* ¬ÝªOÄÝ©Ê */ + time_t btime; /* -1:bpost/blast »Ýn§ó·s */ + int bpost; /* ¦@¦³´X½g post */ + time_t blast; /* ³Ì«á¤@½g post ªº®É¶¡ */ +} BRD; + + +typedef struct +{ + int pal_max; /* ¦³´XÓªO¤Í */ + int pal_spool[PAL_MAX]; /* ©Ò¦³ªO¤Íªº userno */ +} BPAL; + + +/* ----------------------------------------------------- */ +/* Class image */ +/* ----------------------------------------------------- */ + + +#define CLASS_INIFILE "Class" + +/* itoc.010413: §â class.img ¤À¦¨¤GÓ */ +#define CLASS_IMGFILE_NAME "run/classname.img" +#define CLASS_IMGFILE_TITLE "run/classtitle.img" + + +#define CH_MAX 100 /* ³Ì¤j¤ÀÃþ¼Æ¥Ø */ +#define CH_END -1 +#define CH_TTLEN 64 + + +typedef struct +{ + int count; + char title[CH_TTLEN]; + short chno[0]; +} ClassHeader; + + +#ifdef MY_FAVORITE + +/* ----------------------------------------------------- */ +/* favor.c ¤¤¹B¥Îªº¸ê®Æµ²ºc */ +/* ----------------------------------------------------- */ + + +typedef struct MF +{ + time_t chrono; /* «Ø¥ß®É¶¡ */ + int mftype; /* type */ + char xname[BNLEN + 1]; /* ªO¦W©ÎÀɦW */ + char class[BCLEN + 1]; /* ¤ÀÃþ */ + char title[BTLEN + 1]; /* ¥DÃD */ +} MF; + +#define MF_MARK 0x01 /* ³Q mark °_¨Óªº */ +#define MF_BOARD 0x02 /* ¬ÝªO±¶®| */ +#define MF_FOLDER 0x04 /* ¨÷©v */ +#define MF_GEM 0x08 /* ºëµØ°Ï±¶®| */ +#define MF_LINE 0x10 /* ¤À¹j½u */ + +#endif /* MY_FAVORITE */ + + +#ifdef HAVE_COSIGN + +/* ----------------------------------------------------- */ +/* newbrd.c ¤¤¹B¥Îªº¸ê®Æµ²ºc */ +/* ----------------------------------------------------- */ + + +typedef struct NewBoardHeader +{ + char brdname[BNLEN + 1]; + char class[BCLEN + 1]; + char title[BTLEN + 1]; + time_t btime; + time_t etime; + char xname[32]; + char owner[IDLEN + 1]; + char date[9]; + usint mode; + int total; +} NBRD; + + +#define NBRD_FINISH 0x00001 /* ¤wµ²®× */ +#define NBRD_END 0x00002 /* ³s¸pµ²§ô */ +#define NBRD_START 0x00004 /* ³s¸p¶}©l */ +#define NBRD_ANONYMOUS 0x00100 /* °Î¦W */ +#define NBRD_NEWBOARD 0x10000 /* ·sªO³s¸p */ +#define NBRD_OTHER 0x20000 /* ¨ä¥L³s¸p */ + +#endif /* HAVE_COSIGN */ + + +#ifdef LOG_SONG_USIES + +/* ----------------------------------------------------- */ +/* SONG log ¤¤¹B¥Îªº¸ê®Æµ²ºc */ +/* ----------------------------------------------------- */ + +typedef struct SONGDATA +{ + time_t chrono; + int count; /* ³QÂI¦¸¼Æ */ + char title[80]; +} SONGDATA; + +#endif /* LOG_SONG_USIES */ + + +/* ----------------------------------------------------- */ +/* cache.c ¤¤¹B¥Îªº¸ê®Æµ²ºc */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + int shot[MOVIE_MAX]; /* Thor.980805: ¦X²z½d³ò¬° 0..MOVIE_MAX - 1 */ + char film[MOVIE_SIZE]; + char today[16]; +} FCACHE; + + +#define FILM_SIZ 4000 /* max size for each film */ + + +#define FILM_OPENING0 0 /* ¶}ÀYµe±(¢¯) */ +#define FILM_OPENING1 1 /* ¶}ÀYµe±(¢°) */ +#define FILM_OPENING2 2 /* ¶}ÀYµe±(¢±) */ +#define FILM_GOODBYE 3 /* ¦A¨£µe± */ +#define FILM_NOTIFY 4 /* ©|¥¼³q¹L»{ÃÒ³qª¾ */ +#define FILM_MQUOTA 5 /* «H¥ó¶W¹L«O¦s´Á³qª¾ */ +#define FILM_MAILOVER 6 /* «H¥ó«Ê¼Æ¹L¦h³qª¾ */ +#define FILM_MGEMOVER 7 /* Ó¤HºëµØ°Ï¹L¦h³qª¾ */ +#define FILM_BIRTHDAY 8 /* ¥Í¤é·í¤Ñªº¤W¯¸µe± */ +#define FILM_APPLY 9 /* µù¥U´£¥Üµe± */ +#define FILM_JUSTIFY 10 /* ¨¥÷»{ÃÒªº¤èªk */ +#define FILM_REREG 11 /* «·s»{ÃÒ»¡©ú */ +#define FILM_EMAIL 12 /* ¶l¥ó«H½c»{ÃÒ»¡©ú */ +#define FILM_NEWUSER 13 /* ·s¤â¤W¸ô¶·ª¾ */ +#define FILM_TRYOUT 14 /* ±K½X¿ù»~ */ +#define FILM_POST 15 /* ¤å³¹µoªíºõ»â */ +#define FILM_MOVIE 16 /* °ÊºA¬ÝªO FILM_MOVIE n©ñ¦b³Ì«á± */ + + +typedef struct +{ + UTMP uslot[MAXACTIVE]; /* UTMP slots */ + usint count; /* number of active session */ + usint offset; /* offset for last active UTMP */ + + double sysload[3]; + int avgload; + + BMW *mbase; /* sequential pointer for BMW */ + BMW mpool[BMW_MAX]; +} UCACHE; + + +typedef struct +{ + BRD bcache[MAXBOARD]; + BPAL pcache[MAXBOARD]; + int mantime[MAXBOARD]; /* ¦UªO¥Ø«e¥¿¦³¦h¤Ö¤H¦b¾\Ū */ + int number; /* ¥þ³¡¬ÝªOªº¼Æ¥Ø */ + int numberOld; /* è¶}¯¸®É¬ÝªOªº¼Æ¥Ø */ + int min_chn; /* °O¿ýÁ`¦@¦³´XÓ¤ÀÃþ */ + time_t uptime; +} BCACHE; + + +/* ----------------------------------------------------- */ +/* visio.c ¤¤¹B¥Îªº¸ê®Æµ²ºc */ +/* ----------------------------------------------------- */ + + +/* Screen Line buffer modes */ + + +#define SL_MODIFIED (1) /* if line has been modifed, screen output */ +#define SL_STANDOUT (2) /* if this line contains standout code */ +#define SL_ANSICODE (4) /* if this line contains ANSI code */ + + +typedef struct screenline +{ + uschar oldlen; /* previous line length */ + uschar len; /* current length of line */ + uschar width; /* padding length of ANSI codes */ + uschar smod; /* start of modified data */ + uschar emod; /* end of modified data */ + uschar sso; /* start of standout data */ + uschar eso; /* end of standout data */ + uschar mode; /* status of line, as far as update */ + uschar data[ANSILINELEN]; +} screenline; + + +typedef struct LinkList +{ + struct LinkList *next; + char data[0]; +} LinkList; + + +/* ----------------------------------------------------- */ +/* xover.c ¤¤¹B¥Îªº¸ê®Æµ²ºc */ +/* ----------------------------------------------------- */ + + +typedef struct OverView +{ + int pos; /* current position */ + int top; /* top */ + int max; /* max */ + int key; /* key */ + char *xyz; /* staff */ + struct OverView *nxt; /* next */ + char dir[0]; /* data path */ +} XO; + + +typedef struct +{ + int key; + int (*func) (); +} KeyFunc; + + +typedef struct +{ + XO *xo; + KeyFunc *cb; + int mode; + char *feeter; +} XZ; + + +typedef struct +{ + time_t chrono; + int recno; +} TagItem; + + +/* ----------------------------------------------------- */ +/* poststat.c ¤¤¹B¥Îªº¸ê®Æµ²ºc */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + char author[IDLEN + 1]; + char board[BNLEN + 1]; + char title[66]; + time_t date; /* last post's date */ + int number; /* post number */ +} POSTLOG; + + +#ifdef MODE_STAT + +/* ----------------------------------------------------- */ +/* modestat.c ¤¤¹B¥Îªº¸ê®Æµ²ºc */ +/* ----------------------------------------------------- */ + +typedef struct +{ + time_t logtime; + time_t used_time[M_MAX + 1]; /* itoc.010901: depend on mode.h */ +} UMODELOG; + + +typedef struct +{ + time_t logtime; + time_t used_time[M_MAX + 1]; /* itoc.010901: depend on mode.h */ + int count[30]; + int usercount; +} MODELOG; + +#endif /* MODE_STAT */ + + +/* ----------------------------------------------------- */ +/* innbbsd ¤¤¹B¥Îªº¸ê®Æµ²ºc */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + time_t chrono; /* >=0:stamp -1:cancel */ + char board[BNLEN + 1]; + + /* ¥H¤UÄæ¦ìªº¤j¤p»P HDR ¬Û¦P */ + char xname[32]; + char owner[80]; + char nick[49]; + char title[TTLEN + 1]; +} bntp_t; + + +#define INN_USEIHAVE 0x0001 +#define INN_USEPOST 0x0002 +#define INN_FEEDED 0x0010 + +typedef struct +{ + char name[13]; /* ¸Ó¯¸ªº short-name */ + char host[83]; /* ¸Ó¯¸ªº host */ + int port; /* ¸Ó¯¸ªº port */ + usint xmode; /* ¸Ó¯¸ªº xmode */ + char blank[20]; /* «O¯d */ + int feedfd; /* bbslink.c ¨Ï¥Î */ +} nodelist_t; + + +#define INN_NOINCOME 0x0001 +#define INN_ERROR 0x0004 + +typedef struct +{ + char path[13]; /* ¸Ó¸s²Õ©Ò¹ïÂ઺¯¸¥x */ + char newsgroup[83]; /* ¸Ó¸s²Õªº¦WºÙ */ + char board[BNLEN + 1];/* ¸Ó¸s²Õ©Ò¹ïÀ³ªº¬ÝªO */ + char charset[11]; /* ¸Ó¸s²Õªº¦r¶° */ + usint xmode; /* ¸Ó¸s²Õªº xmode */ + int high; /* ¥Ø«e§ì¨ì¸Ó¸s²Õªºþ¤@½g */ +} newsfeeds_t; + + +typedef struct +{ + char issuer[128]; /* NCM message ªºµo«H¤H */ + char type[64]; /* NCM message ªººØÃþ¦WºÙ */ + int perm; /* ¤¹³\¦¹ NCM message §R«H (1:¶} 0:Ãö) */ + char blank[60]; /* «O¯d */ +} ncmperm_t; + + +#define INN_SPAMADDR 0x0001 +#define INN_SPAMNICK 0x0002 +#define INN_SPAMSUBJECT 0x0010 +#define INN_SPAMPATH 0x0020 +#define INN_SPAMMSGID 0x0040 +#define INN_SPAMBODY 0x0100 +#define INN_SPAMSITE 0x0200 +#define INN_SPAMPOSTHOST 0x0400 + +typedef struct +{ + char detail[80]; /* ¸Ó³W«hªº ¤º®e */ + usint xmode; /* ¸Ó³W«hªº xmode */ + char board[BNLEN + 1];/* ¸Ó³W«h¾A¥Îªº¬ÝªO */ + char path[13]; /* ¸Ó³W«h¾A¥Îªº¯¸¥x */ + char blank[18]; /* «O¯d */ +} spamrule_t; + +#endif /* _STRUCT_H_ */ diff --git a/include/theme.h b/include/theme.h new file mode 100644 index 0000000..241597c --- /dev/null +++ b/include/theme.h @@ -0,0 +1,257 @@ +/*-------------------------------------------------------*/ +/* theme.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : custom theme */ +/* create : 02/08/17 */ +/* update : / / */ +/*-------------------------------------------------------*/ + + +#ifndef _THEME_H_ +#define _THEME_H_ + + +/* ----------------------------------------------------- */ +/* °ò¥»ÃC¦â©w¸q¡A¥H§Q¤¶±×§ï */ +/* ----------------------------------------------------- */ + +#define COLOR1 "\033[1;37;43m" /* footer/feeter ªº«e¬qÃC¦â */ +#define COLOR2 "\033[33;42m" /* footer/feeter ªº«á¬qÃC¦â */ +#define COLOR3 "\033[1;37;42m" /* neck ªºÃC¦â */ +#define COLOR4 "\033[1;33;42m" /* ¥ú´Î ªºÃC¦â */ +#define COLOR5 "\033[32;47m" /* more ÀÉÀYªº¼ÐÃDÃC¦â */ +#define COLOR6 "\033[37;42m" /* more ÀÉÀYªº¤º®eÃC¦â */ +#define COLOR7 "\033[32m" /* §@ªÌ¦b½u¤WªºÃC¦â */ + +/* ----------------------------------------------------- */ +/* ¨Ï¥ÎªÌ¦W³æÃC¦â */ +/* ----------------------------------------------------- */ + +#define COLOR_NORMAL "" /* ¤@¯ë¨Ï¥ÎªÌ */ +#define COLOR_MYBAD "\033[1;31m" /* Ãa¤H */ +#define COLOR_MYGOOD "\033[1;32m" /* §Úªº¦n¤Í */ +#define COLOR_OGOOD "\033[1;33m" /* »P§Ú¬°¤Í */ +#define COLOR_CLOAK "\033[1;35m" /* Áô§Î */ /* itoc.µù¸Ñ: ¨S¥Î¨ì¡Anªº¤H½Ð¦Û¦æ¥[¤J ulist_body() */ +#define COLOR_SELF "\033[1;36m" /* ¦Û¤v */ +#define COLOR_BOTHGOOD "\033[1;37m" /* ¤¬³]¦n¤Í */ +#define COLOR_BRDMATE "\033[36m" /* ªO¦ñ */ + + +/* ----------------------------------------------------- */ +/* ¿ï³æ¦ì¸m */ +/* ----------------------------------------------------- */ + +/* itoc.µù¸Ñ: ª`·N MENU_XPOS n >= MENU_XNOTE + MOVIE_LINES */ + +#define MENU_XNOTE 1 /* °ÊºA¬ÝªO¥Ñ (2, 0) ¶}©l */ +#define MOVIE_LINES 12 /* °Êµe³Ì¦h¦³ 10 ¦C */ + +#define MENU_XPOS 13 /* ¿ï³æ¶}©lªº (x, y) ®y¼Ð */ +#define MENU_YPOS ((d_cols >> 1) + 18) + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡G*_neck() ®Éªº necker ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* necker ªº¦æ¼Æ³£¬O¤G¦æ¡A±q (1, 0) ¨ì (2, 80) */ + +/* ©Ò¦³ªº XZ_* ³£¦³ necker¡A¥u¬O¦³¨Ç¦b *_neck()¡A¦³¨ÇÂæb *_head() */ + +/* ulist_neck() ¤Î xpost_head() ªº²Ä¤@¦æ¤ñ¸û¯S§O¡A¤£¦b¦¹©w¸q */ + +#define NECKER_CLASS "[¡ö]¥D¿ï³æ [¡÷]¾\\Ū [¡ô¡õ]¿ï¾Ü [W]¬d¸ß [y]¸ü¤J [/?]·j´M [s]¬ÝªO [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H ªO ¥D%*s \033[m" + +#define NECKER_ULIST "\n" \ + COLOR3 " ½s¸¹ ¥N¸¹ ¼ÊºÙ%*s %-*s °ÊºA ¶¢¸m \033[m" + +#define NECKER_PAL "[¡ö]Â÷¶} [a]·s¼W [c]×§ï [d]§R°£ [m]±H«H [w]¤ô²y [s]¾ã²z [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤Í ½Ë%*s \033[m" + +#define NECKER_ALOHA "[¡ö]Â÷¶} [a]·s¼W [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [w]¤ô²y [s]«¾ã [f]¤Þ¤J [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤W ¯¸ ³q ª¾ ¦W ³æ%*s \033[m" + +#define NECKER_VOTE "[¡ö]Â÷¶} [R]µ²ªG [^P]Á|¦æ [E]×§ï [V]¹wÄý [^Q]§ï´Á [o]¦W³æ [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¶}²¼¤é ¥D¿ì¤H §ë ²¼ ©v ¦®%*s \033[m" + +#define NECKER_BMW "[¡ö]Â÷¶} [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [M]Àx¦s [w]¤ô²y [s]§ó·s [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤º ®e%*s ®É¶¡ \033[m" + +#define NECKER_MF "[¡ö]Â÷¶} [¡÷]¶i¤J [W]¬d¸ß [m]²¾°Ê [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H ªO ¥D%*s \033[m" + +#define NECKER_COSIGN "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]¥Ó½Ð [d]§R°£ [o]¶}ªO [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á Á|¿ì¤H ¬Ý ªO ¼Ð ÃD%*s \033[m" + +#define NECKER_SONG "[¡ö]Â÷¶} [¡÷]ÂsÄý [o]ÂIºq¨ì¬ÝªO [m]ÂIºq¨ì«H½c [Enter]ÂsÄý [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +#define NECKER_NEWS "[¡ö]Â÷¶} [¡÷]¾\\Ū [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ·s »D ¼Ð ÃD%*s \033[m" + +#define NECKER_XPOST "\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s £t:%s µû:%s \033[m" + +#define NECKER_MBOX "[¡ö]Â÷¶} [¡÷,r]Ū«H [d]§R°£ [R,y](¸s²Õ)¦^«H [s]±H«H [x]Âà¿ý [X]Âà¹F [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ «H ¥ó ¼Ð ÃD%*s \033[m" + +#define NECKER_POST "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]µoªí [b]¶iªOµe± [d]§R°£ [I,W]¬d¸ß [TAB]ºëµØ°Ï [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s £t:%s µû:%s ¤H®ð:%-4d \033[m" + +#define NECKER_GEM "[¡ö]Â÷¶} [¡÷]ÂsÄý [B]¼Ò¦¡ [C]¼È¦s [F]Âà±H [d]§R°£ [h]»¡©ú %s\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +/* ¥H¤U³o¨Ç«h¬O¤@¨ÇÃþ XZ_* µ²ºcªº necker */ + +#define NECKER_VOTEALL "[¡ô/¡õ]¤W¤U [PgUp/PgDn]¤W¤U¶ [Home/End]º§À [¡÷]§ë²¼ [¡ö][q]Â÷¶}\n" \ + COLOR3 " ½s¸¹ ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ªO ¥D%*s \033[m" + +#define NECKER_CREDIT "[¡ö]Â÷¶} [C]´«¶ [1]·s¼W [2]§R°£ [3]¥þ§R [4]Á`p\n" \ + COLOR3 " ½s¸¹ ¤é ´Á ¦¬¤ä ª÷ ÃB ¤ÀÃþ »¡ ©ú%*s \033[m" + +#define NECKER_HELP "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]·s¼W [d]§R°£ [T]¼ÐÃD [E]½s¿è [m]²¾°Ê\n" \ + COLOR3 " ½s¸¹ ÀÉ ®× ¼Ð ÃD%*s \033[m" + +#define NECKER_INNBBS "[¡ö]Â÷¶} [^P]·s¼W [d]§R°£ [E]½s¿è [/]·j´M [Enter]¸Ô²Ó\n" \ + COLOR3 " ½s¸¹ ¤º ®e%*s \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gmore() ®Éªº footer ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* itoc.010914.µù¸Ñ: ³æ¤@½g¡A©Ò¥H¥s FOOTER¡A³£¬O 78 char */ + +/* itoc.010821: ª`·N \\ ¬O \¡A³Ì«á§Oº|¤F¤@ӪťÕÁä :p */ + +#define FOOTER_POST \ +COLOR1 " ¤å³¹¿ïŪ " COLOR2 " (ry)¦^À³ (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (C)¼È¦s " + +#define FOOTER_MAILER \ +COLOR1 " ³½¶©¹ªð " COLOR2 " (ry)¦^«H/¸s²Õ (X)Âà¹F (d)§R°£ (m)¼Ð°O (C)¼È¦s (=\\[]<>-+;'`|?QAkj) " + +#define FOOTER_GEM \ +COLOR1 " ºëµØ¿ïŪ " COLOR2 " (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} " + +#ifdef HAVE_GAME +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^O)¹ï«³¼Ò¦¡ (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í " +#else +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í (^Y)²M°£ " +#endif + +#define FOOTER_COSIGN \ +COLOR1 " ³s¸p¾÷¨î " COLOR2 " (ry)¥[¤J³s¸p (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} (h)»¡©ú " + +#define FOOTER_MORE \ +COLOR1 " ÂsÄý P.%d (%d%%) " COLOR2 " (h)»¡©ú [PgUp][PgDn][0][$]²¾°Ê (/n)·j´M (C)¼È¦s (¡öq)µ²§ô " + +#define FOOTER_VEDIT \ +COLOR1 " %s " COLOR2 " (^Z)»¡©ú(^W)²Å¸¹(^L)«Ã¸(^X)ÀÉ®×(^G)¥þ«¬ùø%s¢x%sùø%5d:%3d \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gxo_foot() ®Éªº feeter ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + + +/* itoc.010914.µù¸Ñ: ¦Cªí¦h½g¡A©Ò¥H¥s FEETER¡A³£¬O 78 char */ + +#define FEETER_CLASS \ +COLOR1 " ¬ÝªO¿ï¾Ü " COLOR2 " (c)·s¤å³¹ (vV)¼Ð°O¤wŪ¥¼Åª (y)¥þ³¡¦C¥X (z)¿ïq (A)¥þ°ì·j´M (S)±Æ§Ç " + +#define FEETER_ULIST \ +COLOR1 " ºô¤Í¦Cªí " COLOR2 " (f)¦n¤Í (T)²á¤Ñ (q)¬d¸ß (ad)¥æ¤Í (m)±H«H (w)¤ô²y (s)§ó·s (TAB)¤Á´« " + +#define FEETER_PAL \ +COLOR1 " ©IªB¤Þ¦ñ " COLOR2 " (a)·s¼W (d)§R°£ (c)¤Í½Ë (m)±H«H (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_ALOHA \ +COLOR1 " ¤W¯¸³qª¾ " COLOR2 " (a)·s¼W (d)§R°£ (D)°Ï¬q§R°£ (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_VOTE \ +COLOR1 " ¬ÝªO§ë²¼ " COLOR2 " (¡÷/r/v)§ë²¼ (R)µ²ªG (^P)·s¼W§ë²¼ (E)×§ï (V)¹wÄý (b)¶}²¼ (o)¦W³æ " + +#define FEETER_BMW \ +COLOR1 " ¤ô²y¦^ÅU " COLOR2 " (d)§R°£ (D)°Ï¬q§R°£ (m)±H«H (w)¤ô²y (^R)¦^°T (^Q)¬d¸ß (s)§ó·s " + +#define FEETER_MF \ +COLOR1 " ³Ì·R¬ÝªO " COLOR2 " (^P)·s¼W (Cg)½Æ»s (p^V)¶K¤W (d)§R°£ (c)·s¤å³¹ (vV)¼Ð°O¤wŪ/¥¼Åª " + +#define FEETER_COSIGN \ +COLOR1 " ³s¸p¤p¯¸ " COLOR2 " (r)Ū¨ú (y)¦^À³ (^P)µoªí (d)§R°£ (o)¶}ªO (c)Ãö³¬ (E)½s¿è (B)³]©w " + +#define FEETER_SONG \ +COLOR1 " ÂIºq¨t²Î " COLOR2 " (r)Ū¨ú (o)ÂIºq¨ì¬ÝªO (m)ÂIºq¨ì«H½c (E)½s¿èÀÉ®× (T)½s¿è¼ÐÃD " + +#define FEETER_NEWS \ +COLOR1 " ·s»DÂI¿ï " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)¿ï¨ú (¡ö)(q)Â÷¶} " + +#define FEETER_XPOST \ +COLOR1 " ¦ê¦C·j´M " COLOR2 " (y)¦^À³ (x)Âà¿ý (m)¼Ð°O (d)§R°£ (^P)µoªí (^Q)¬d¸ß§@ªÌ (t)¼ÐÅÒ " + +#define FEETER_MBOX \ +COLOR1 " «H«H¬Û±¤ " COLOR2 " (y)¦^«H (F/X/x)Âà±H/Âà¹F/Âà¿ý (d)§R°£ (D)°Ï¬q§R°£ (m)¼Ð°O (E)½s¿è " + +#define FEETER_POST \ +COLOR1 " ¤å³¹¦Cªí " COLOR2 " (ry)¦^«H (S/a)·j´M/¼ÐÃD/§@ªÌ (~G)¦ê¦C·j´M (x)Âà¿ý (V)§ë²¼ (u)·s»D " + +#define FEETER_GEM \ +COLOR1 " ¬ÝªOºëµØ " COLOR2 " (^P/a/f)·s¼W/¤å³¹/¥Ø¿ý (E)½s¿è (T)¼ÐÃD (m)²¾°Ê (c)½Æ»s (p^V)¶K¤W " + +#define FEETER_VOTEALL \ +COLOR1 " §ë²¼¤¤¤ß " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷)§ë²¼ (¡ö)(q)Â÷¶} " + +#define FEETER_HELP \ +COLOR1 " »¡©ú¤å¥ó " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)ÂsÄý (¡ö)(q)Â÷¶} " + +#define FEETER_INNBBS \ +COLOR1 " Âà«H³]©w " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡ö)(q)Â÷¶} " + + +/* ----------------------------------------------------- */ +/* ¯¸¥x¨Ó·½Ã±¦W */ +/* ----------------------------------------------------- */ + +/* itoc: «ØÄ³ banner ¤£n¶W¹L¤T¦æ¡A¹Lªøªº¯¸Ã±¥i¯à·|³y¦¨¬Y¨Ç¨Ï¥ÎªÌªº¤Ï·P */ + + +#if 0 +#define EDIT_BANNER "\n--\n" \ + " \033[1;41m¡÷\033[44m¡õ\033[m O\033[1mri\033[30mgi\033[mn: \033[1;43m "SCHOOLNAME"£»"BBSNAME" \033[47m "MYHOSTNAME" \033[m\n" \ + " \033[1;45m¡ô\033[42m¡ö\033[m Au\033[1mt\033[30mho\033[mr: \033[1;33m%s\033[m ±q \033[1;34m%s\033[m µoªí\n" + +#define MODIFY_BANNER " \033[1;43m¡ù\033[46m¡ø\033[m \033[1mMo\033[30mdi\033[mfy: %s ©ó \033[1;33m%s\033[m ×§ï\n" +#endif + +/* ·s¯¸Ã± by hppy.bbs@sony.tfcis.org */ +#define EDIT_BANNER "\n--\n" \ +"\033[1m \033[42m¢q\033[40m¢w¢¡ ¢~¢w¢w¢w¢w¢w¢w¢w¢¡\033[m\n" \ +"\033[1m ¢x ¢x\033[1m¥\033[mx«\033[1mn¤@¤\033[m¤¡D¯\033[1mÁ¥§¤\033[mp¯\033[1m¸\033[m¡ý\033[1msony.TFcis.org¢x ¢x\033[m\n" \ +"\033[1m ¢¢¢w¢w¢w¢w¢w¢w¢w¢w¢w¢£ ¢¢¢w\033[42m¢q\033[m\n" \ +"\033[1m by %s from \033[m \033[1m%s (%s)\033[m\n\n" + +#define MODIFY_BANNER "¡¶ \033[1;30m%s \033[;33m§ï\033[m@\033[m%s\033[m\n" + +/* ----------------------------------------------------- */ +/* ¨ä¥L°T®§¦r¦ê */ +/* ----------------------------------------------------- */ + +#define VMSG_NULL " \033[1;32;45m ¡´ ½Ð«ö¥ô·NÁäÄ~Äò ¡´ \033[m" + +#define ICON_UNREAD_BRD "\033[0;32m£¾" /* ¥¼Åª¬ÝªO */ +#define ICON_READ_BRD " " /* ¤wŪ¬ÝªO */ + +#define ICON_GAMBLED_BRD "\033[1;31m½ä\033[m" /* Á|¦æ½ä½L¤¤ªº¬ÝªO */ +#define ICON_VOTED_BRD "\033[1;33m§ë\033[m" /* Á|¦æ§ë²¼¤¤ªº¬ÝªO */ +#define ICON_NOTRAN_BRD "¡·" /* ¤£Âà«HªO */ +#define ICON_TRAN_BRD "¡´" /* Âà«HªO */ + +#define TOKEN_ZAP_BRD '-' /* zap ªO */ +#define TOKEN_FRIEND_BRD '.' /* ¦n¤ÍªO */ +#define TOKEN_SECRET_BRD ')' /* ¯µ±KªO */ + +#endif /* _THEME_H_ */ + diff --git a/include/theme/theme_blue.h b/include/theme/theme_blue.h new file mode 100644 index 0000000..73ff28a --- /dev/null +++ b/include/theme/theme_blue.h @@ -0,0 +1,246 @@ +/*-------------------------------------------------------*/ +/* theme.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : custom theme */ +/* create : 02/08/17 */ +/* update : / / */ +/*-------------------------------------------------------*/ + + +#ifndef _THEME_H_ +#define _THEME_H_ + + +/* ----------------------------------------------------- */ +/* °ò¥»ÃC¦â©w¸q¡A¥H§Q¤¶±×§ï */ +/* ----------------------------------------------------- */ + +#define COLOR1 "\033[34;46m" /* footer/feeter ªº«e¬qÃC¦â */ +#define COLOR2 "\033[37;44m" /* footer/feeter ªº«á¬qÃC¦â */ +#define COLOR3 "\033[37;44m" /* neck ªºÃC¦â */ +#define COLOR4 "\033[1;44m" /* ¥ú´Î ªºÃC¦â */ +#define COLOR5 "\033[34;47m" /* more ÀÉÀYªº¼ÐÃDÃC¦â */ +#define COLOR6 "\033[37;44m" /* more ÀÉÀYªº¤º®eÃC¦â */ +#define COLOR7 "\033[1;34m" /* §@ªÌ¦b½u¤WªºÃC¦â */ + + +/* ----------------------------------------------------- */ +/* ¨Ï¥ÎªÌ¦W³æÃC¦â */ +/* ----------------------------------------------------- */ + +#define COLOR_NORMAL "" /* ¤@¯ë¨Ï¥ÎªÌ */ +#define COLOR_MYBAD "\033[1;31m" /* Ãa¤H */ +#define COLOR_MYGOOD "\033[1;32m" /* §Úªº¦n¤Í */ +#define COLOR_OGOOD "\033[1;33m" /* »P§Ú¬°¤Í */ +#define COLOR_CLOAK "\033[1;35m" /* Áô§Î */ /* itoc.µù¸Ñ: ¨S¥Î¨ì¡Anªº¤H½Ð¦Û¦æ¥[¤J ulist_body() */ +#define COLOR_SELF "\033[1;36m" /* ¦Û¤v */ +#define COLOR_BOTHGOOD "\033[1;37m" /* ¤¬³]¦n¤Í */ +#define COLOR_BRDMATE "\033[36m" /* ªO¦ñ */ + + +/* ----------------------------------------------------- */ +/* ¿ï³æ¦ì¸m */ +/* ----------------------------------------------------- */ + +/* itoc.µù¸Ñ: ª`·N MENU_XPOS n >= MENU_XNOTE + MOVIE_LINES */ + +#define MENU_XNOTE 2 /* °ÊºA¬ÝªO¥Ñ (2, 0) ¶}©l */ +#define MOVIE_LINES 10 /* °Êµe³Ì¦h¦³ 10 ¦C */ + +#define MENU_XPOS 13 /* ¿ï³æ¶}©lªº (x, y) ®y¼Ð */ +#define MENU_YPOS ((d_cols >> 1) + 18) + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡G*_neck() ®Éªº necker ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* necker ªº¦æ¼Æ³£¬O¤G¦æ¡A±q (1, 0) ¨ì (2, 80) */ + +/* ©Ò¦³ªº XZ_* ³£¦³ necker¡A¥u¬O¦³¨Ç¦b *_neck()¡A¦³¨ÇÂæb *_head() */ + +/* ulist_neck() ¤Î xpost_head() ªº²Ä¤@¦æ¤ñ¸û¯S§O¡A¤£¦b¦¹©w¸q */ + +#define NECKER_CLASS "[¡ö]¥D¿ï³æ [¡÷]¾\\Ū [¡ô¡õ]¿ï¾Ü [c]½g¼Æ [y]¸ü¤J [/?]·j´M [s]¬ÝªO [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_ULIST "\n" \ + COLOR3 " ½s¸¹ ¥N¸¹ ¼ÊºÙ%*s %-*s °ÊºA ¶¢¸m \033[m" + +#define NECKER_PAL "[¡ö]Â÷¶} [a]·s¼W [c]×§ï [d]§R°£ [m]±H«H [w]¤ô²y [s]¾ã²z [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤Í ½Ë%*s \033[m" + +#define NECKER_ALOHA "[¡ö]Â÷¶} [a]·s¼W [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [w]¤ô²y [s]«¾ã [f]¤Þ¤J [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤W ¯¸ ³q ª¾ ¦W ³æ%*s \033[m" + +#define NECKER_VOTE "[¡ö]Â÷¶} [R]µ²ªG [^P]Á|¦æ [E]×§ï [V]¹wÄý [^Q]§ï´Á [o]¦W³æ [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¶}²¼¤é ¥D¿ì¤H §ë ²¼ ©v ¦®%*s \033[m" + +#define NECKER_BMW "[¡ö]Â÷¶} [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [M]Àx¦s [w]¤ô²y [s]§ó·s [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤º ®e%*s ®É¶¡ \033[m" + +#define NECKER_MF "[¡ö]Â÷¶} [¡÷]¶i¤J [^P]·s¼W [d]§R°£ [c]¤Á´« [C]½Æ»s [^V]¶K¤W [m]²¾°Ê [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_COSIGN "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]¥Ó½Ð [d]§R°£ [o]¶}ªO [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á Á|¿ì¤H ¬Ý ªO ¼Ð ÃD%*s \033[m" + +#define NECKER_SONG "[¡ö]Â÷¶} [¡÷]ÂsÄý [o]ÂIºq¨ì¬ÝªO [m]ÂIºq¨ì«H½c [Enter]ÂsÄý [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +#define NECKER_NEWS "[¡ö]Â÷¶} [¡÷]¾\\Ū [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ·s »D ¼Ð ÃD%*s \033[m" + +#define NECKER_XPOST "\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s \033[m" + +#define NECKER_MBOX "[¡ö]Â÷¶} [¡÷,r]Ū«H [d]§R°£ [R,y](¸s²Õ)¦^«H [s]±H«H [x]Âà¿ý [X]Âà¹F [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ «H ¥ó ¼Ð ÃD%*s \033[m" + +#define NECKER_POST "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]µoªí [b]¶iªOµe± [d]§R°£ [V]§ë²¼ [TAB]ºëµØ°Ï [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s ¤H®ð:%-4d \033[m" + +#define NECKER_GEM "[¡ö]Â÷¶} [¡÷]ÂsÄý [B]¼Ò¦¡ [C]¼È¦s [F]Âà±H [d]§R°£ [h]»¡©ú %s\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +/* ¥H¤U³o¨Ç«h¬O¤@¨ÇÃþ XZ_* µ²ºcªº necker */ + +#define NECKER_VOTEALL "[¡ô/¡õ]¤W¤U [PgUp/PgDn]¤W¤U¶ [Home/End]º§À [¡÷]§ë²¼ [¡ö][q]Â÷¶}\n" \ + COLOR3 " ½s¸¹ ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ªO ¥D%*s \033[m" + +#define NECKER_CREDIT "[¡ö]Â÷¶} [C]´«¶ [1]·s¼W [2]§R°£ [3]¥þ§R [4]Á`p\n" \ + COLOR3 " ½s¸¹ ¤é ´Á ¦¬¤ä ª÷ ÃB ¤ÀÃþ »¡ ©ú%*s \033[m" + +#define NECKER_HELP "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]·s¼W [d]§R°£ [T]¼ÐÃD [E]½s¿è [m]²¾°Ê\n" \ + COLOR3 " ½s¸¹ ÀÉ ®× ¼Ð ÃD%*s \033[m" + +#define NECKER_INNBBS "[¡ö]Â÷¶} [^P]·s¼W [d]§R°£ [E]½s¿è [/]·j´M [Enter]¸Ô²Ó\n" \ + COLOR3 " ½s¸¹ ¤º ®e%*s \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gmore() ®Éªº footer ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* itoc.010914.µù¸Ñ: ³æ¤@½g¡A©Ò¥H¥s FOOTER¡A³£¬O 78 char */ + +/* itoc.010821: ª`·N \\ ¬O \¡A³Ì«á§Oº|¤F¤@ӪťÕÁä :p */ + +#define FOOTER_POST \ +COLOR1 " ¤å³¹¿ïŪ " COLOR2 " (ry)¦^À³ (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (C)¼È¦s " + +#define FOOTER_MAILER \ +COLOR1 " ³½¶©¹ªð " COLOR2 " (ry)¦^«H/¸s²Õ (X)Âà¹F (d)§R°£ (m)¼Ð°O (C)¼È¦s (=\\[]<>-+;'`|?QAkj) " + +#define FOOTER_GEM \ +COLOR1 " ºëµØ¿ïŪ " COLOR2 " (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} " + +#ifdef HAVE_GAME +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^O)¹ï«³¼Ò¦¡ (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í " +#else +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í (^Y)²M°£ " +#endif + +#define FOOTER_COSIGN \ +COLOR1 " ³s¸p¾÷¨î " COLOR2 " (ry)¥[¤J³s¸p (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} (h)»¡©ú " + +#define FOOTER_MORE \ +COLOR1 " ÂsÄý P.%d (%d%%) " COLOR2 " (h)»¡©ú [PgUp][PgDn][0][$]²¾°Ê (/n)·j´M (C)¼È¦s (¡öq)µ²§ô " + +#define FOOTER_VEDIT \ +COLOR1 " %s " COLOR2 " (^Z)»¡©ú (^W)²Å¸¹ (^L)«Ã¸ (^X)Àɮ׳B²z ùø%s¢x%sùø%5d:%3d \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gxo_foot() ®Éªº feeter ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + + +/* itoc.010914.µù¸Ñ: ¦Cªí¦h½g¡A©Ò¥H¥s FEETER¡A³£¬O 78 char */ + +#define FEETER_CLASS \ +COLOR1 " ¬ÝªO¿ï¾Ü " COLOR2 " (c)·s¤å³¹ (vV)¼Ð°O¤wŪ¥¼Åª (y)¥þ³¡¦C¥X (z)¿ïq (A)¥þ°ì·j´M (S)±Æ§Ç " + +#define FEETER_ULIST \ +COLOR1 " ºô¤Í¦Cªí " COLOR2 " (f)¦n¤Í (t)²á¤Ñ (q)¬d¸ß (ad)¥æ¤Í (m)±H«H (w)¤ô²y (s)§ó·s (TAB)¤Á´« " + +#define FEETER_PAL \ +COLOR1 " ©IªB¤Þ¦ñ " COLOR2 " (a)·s¼W (d)§R°£ (c)¤Í½Ë (m)±H«H (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_ALOHA \ +COLOR1 " ¤W¯¸³qª¾ " COLOR2 " (a)·s¼W (d)§R°£ (D)°Ï¬q§R°£ (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_VOTE \ +COLOR1 " ¬ÝªO§ë²¼ " COLOR2 " (¡÷/r/v)§ë²¼ (R)µ²ªG (^P)·s¼W§ë²¼ (E)×§ï (V)¹wÄý (b)¶}²¼ (o)¦W³æ " + +#define FEETER_BMW \ +COLOR1 " ¤ô²y¦^ÅU " COLOR2 " (d)§R°£ (D)°Ï¬q§R°£ (m)±H«H (w)¤ô²y (^R)¦^°T (^Q)¬d¸ß (s)§ó·s " + +#define FEETER_MF \ +COLOR1 " ³Ì·R¬ÝªO " COLOR2 " (^P)·s¼W (Cg)½Æ»s (p^V)¶K¤W (d)§R°£ (c)·s¤å³¹ (vV)¼Ð°O¤wŪ/¥¼Åª " + +#define FEETER_COSIGN \ +COLOR1 " ³s¸p¤p¯¸ " COLOR2 " (r)Ū¨ú (y)¦^À³ (^P)µoªí (d)§R°£ (o)¶}ªO (c)Ãö³¬ (E)½s¿è (B)³]©w " + +#define FEETER_SONG \ +COLOR1 " ÂIºq¨t²Î " COLOR2 " (r)Ū¨ú (o)ÂIºq¨ì¬ÝªO (m)ÂIºq¨ì«H½c (E)½s¿èÀÉ®× (T)½s¿è¼ÐÃD " + +#define FEETER_NEWS \ +COLOR1 " ·s»DÂI¿ï " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)¿ï¨ú (¡ö)(q)Â÷¶} " + +#define FEETER_XPOST \ +COLOR1 " ¦ê¦C·j´M " COLOR2 " (y)¦^À³ (x)Âà¿ý (m)¼Ð°O (d)§R°£ (^P)µoªí (^Q)¬d¸ß§@ªÌ (t)¼ÐÅÒ " + +#define FEETER_MBOX \ +COLOR1 " «H«H¬Û±¤ " COLOR2 " (y)¦^«H (F/X/x)Âà±H/Âà¹F/Âà¿ý (d)§R°£ (D)°Ï¬q§R°£ (m)¼Ð°O (E)½s¿è " + +#define FEETER_POST \ +COLOR1 " ¤å³¹¦Cªí " COLOR2 " (ry)¦^«H (S/a)·j´M/¼ÐÃD/§@ªÌ (~G)¦ê¦C·j´M (x)Âà¿ý (V)§ë²¼ (u)·s»D " + +#define FEETER_GEM \ +COLOR1 " ¬ÝªOºëµØ " COLOR2 " (^P/a/f)·s¼W/¤å³¹/¥Ø¿ý (E)½s¿è (T)¼ÐÃD (m)²¾°Ê (c)½Æ»s (p^V)¶K¤W " + +#define FEETER_VOTEALL \ +COLOR1 " §ë²¼¤¤¤ß " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷)§ë²¼ (¡ö)(q)Â÷¶} " + +#define FEETER_HELP \ +COLOR1 " »¡©ú¤å¥ó " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)ÂsÄý (¡ö)(q)Â÷¶} " + +#define FEETER_INNBBS \ +COLOR1 " Âà«H³]©w " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡ö)(q)Â÷¶} " + + +/* ----------------------------------------------------- */ +/* ¯¸¥x¨Ó·½Ã±¦W */ +/* ----------------------------------------------------- */ + +/* itoc: «ØÄ³ banner ¤£n¶W¹L¤T¦æ¡A¹Lªøªº¯¸Ã±¥i¯à·|³y¦¨¬Y¨Ç¨Ï¥ÎªÌªº¤Ï·P */ + +#define EDIT_BANNER "\n--\n" \ + " \033[1;43m¢«\033[46m¢ª\033[m Or\033[1mig\033[30min\033[m: \033[1;44m "SCHOOLNAME"£»"BBSNAME" \033[42m "MYHOSTNAME" \033[m\n" \ + " \033[1;44m¢©\033[41m¢¨\033[m A\033[1mut\033[30mho\033[mr: \033[1;34m%s\033[m ±q \033[1;31m%s\033[m µoªí\n" + +#define MODIFY_BANNER " \033[1;45m¢c\033[42m¢i\033[m \033[1mMo\033[30mdi\033[mfy: %s ©ó \033[1;34m%s\033[m ×§ï\n" + + +/* ----------------------------------------------------- */ +/* ¨ä¥L°T®§¦r¦ê */ +/* ----------------------------------------------------- */ + +#define VMSG_NULL " \033[1;33;46m ¡´ ½Ð«ö¥ô·NÁäÄ~Äò ¡´ \033[m" + +#define ICON_UNREAD_BRD "\033[1;33m£»\033[m" /* ¥¼Åª¬ÝªO */ +#define ICON_READ_BRD " " /* ¤wŪ¬ÝªO */ + +#define ICON_GAMBLED_BRD "\033[1;31m½ä\033[m" /* Á|¦æ½ä½L¤¤ªº¬ÝªO */ +#define ICON_VOTED_BRD "\033[1;33m§ë\033[m" /* Á|¦æ§ë²¼¤¤ªº¬ÝªO */ +#define ICON_NOTRAN_BRD " " /* ¤£Âà«HªO */ +#define ICON_TRAN_BRD "Âà" /* Âà«HªO */ + +#define TOKEN_ZAP_BRD '-' /* zap ªO */ +#define TOKEN_FRIEND_BRD '.' /* ¦n¤ÍªO */ +#define TOKEN_SECRET_BRD ')' /* ¯µ±KªO */ + +#endif /* _THEME_H_ */ diff --git a/include/theme/theme_cyan.h b/include/theme/theme_cyan.h new file mode 100644 index 0000000..8766d14 --- /dev/null +++ b/include/theme/theme_cyan.h @@ -0,0 +1,246 @@ +/*-------------------------------------------------------*/ +/* theme.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : custom theme */ +/* create : 02/08/17 */ +/* update : / / */ +/*-------------------------------------------------------*/ + + +#ifndef _THEME_H_ +#define _THEME_H_ + + +/* ----------------------------------------------------- */ +/* °ò¥»ÃC¦â©w¸q¡A¥H§Q¤¶±×§ï */ +/* ----------------------------------------------------- */ + +#define COLOR1 "\033[1;33;45m" /* footer/feeter ªº«e¬qÃC¦â */ +#define COLOR2 "\033[37;46m" /* footer/feeter ªº«á¬qÃC¦â */ +#define COLOR3 "\033[1;33;46m" /* neck ªºÃC¦â */ +#define COLOR4 "\033[1;46m" /* ¥ú´Î ªºÃC¦â */ +#define COLOR5 "\033[1;33;46m" /* more ÀÉÀYªº¼ÐÃDÃC¦â */ +#define COLOR6 "\033[m" /* more ÀÉÀYªº¤º®eÃC¦â */ +#define COLOR7 "\033[36m" /* §@ªÌ¦b½u¤WªºÃC¦â */ + + +/* ----------------------------------------------------- */ +/* ¨Ï¥ÎªÌ¦W³æÃC¦â */ +/* ----------------------------------------------------- */ + +#define COLOR_NORMAL "" /* ¤@¯ë¨Ï¥ÎªÌ */ +#define COLOR_MYBAD "\033[1;31m" /* Ãa¤H */ +#define COLOR_MYGOOD "\033[1;32m" /* §Úªº¦n¤Í */ +#define COLOR_OGOOD "\033[1;33m" /* »P§Ú¬°¤Í */ +#define COLOR_CLOAK "\033[1;35m" /* Áô§Î */ /* itoc.µù¸Ñ: ¨S¥Î¨ì¡Anªº¤H½Ð¦Û¦æ¥[¤J ulist_body() */ +#define COLOR_SELF "\033[1;36m" /* ¦Û¤v */ +#define COLOR_BOTHGOOD "\033[1;37m" /* ¤¬³]¦n¤Í */ +#define COLOR_BRDMATE "\033[36m" /* ªO¦ñ */ + + +/* ----------------------------------------------------- */ +/* ¿ï³æ¦ì¸m */ +/* ----------------------------------------------------- */ + +/* itoc.µù¸Ñ: ª`·N MENU_XPOS n >= MENU_XNOTE + MOVIE_LINES */ + +#define MENU_XNOTE 2 /* °ÊºA¬ÝªO¥Ñ (2, 0) ¶}©l */ +#define MOVIE_LINES 10 /* °Êµe³Ì¦h¦³ 10 ¦C */ + +#define MENU_XPOS 13 /* ¿ï³æ¶}©lªº (x, y) ®y¼Ð */ +#define MENU_YPOS ((d_cols >> 1) + 18) + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡G*_neck() ®Éªº necker ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* necker ªº¦æ¼Æ³£¬O¤G¦æ¡A±q (1, 0) ¨ì (2, 80) */ + +/* ©Ò¦³ªº XZ_* ³£¦³ necker¡A¥u¬O¦³¨Ç¦b *_neck()¡A¦³¨ÇÂæb *_head() */ + +/* ulist_neck() ¤Î xpost_head() ªº²Ä¤@¦æ¤ñ¸û¯S§O¡A¤£¦b¦¹©w¸q */ + +#define NECKER_CLASS "[¡ö]¥D¿ï³æ [¡÷]¾\\Ū [¡ô¡õ]¿ï¾Ü [c]½g¼Æ [y]¸ü¤J [/?]·j´M [s]¬ÝªO [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_ULIST "\n" \ + COLOR3 " ½s¸¹ ¥N¸¹ ¼ÊºÙ%*s %-*s °ÊºA ¶¢¸m \033[m" + +#define NECKER_PAL "[¡ö]Â÷¶} [a]·s¼W [c]×§ï [d]§R°£ [m]±H«H [w]¤ô²y [s]¾ã²z [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤Í ½Ë%*s \033[m" + +#define NECKER_ALOHA "[¡ö]Â÷¶} [a]·s¼W [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [w]¤ô²y [s]«¾ã [f]¤Þ¤J [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤W ¯¸ ³q ª¾ ¦W ³æ%*s \033[m" + +#define NECKER_VOTE "[¡ö]Â÷¶} [R]µ²ªG [^P]Á|¦æ [E]×§ï [V]¹wÄý [^Q]§ï´Á [o]¦W³æ [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¶}²¼¤é ¥D¿ì¤H §ë ²¼ ©v ¦®%*s \033[m" + +#define NECKER_BMW "[¡ö]Â÷¶} [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [M]Àx¦s [w]¤ô²y [s]§ó·s [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤º ®e%*s ®É¶¡ \033[m" + +#define NECKER_MF "[¡ö]Â÷¶} [¡÷]¶i¤J [^P]·s¼W [d]§R°£ [c]¤Á´« [C]½Æ»s [^V]¶K¤W [m]²¾°Ê [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_COSIGN "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]¥Ó½Ð [d]§R°£ [o]¶}ªO [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á Á|¿ì¤H ¬Ý ªO ¼Ð ÃD%*s \033[m" + +#define NECKER_SONG "[¡ö]Â÷¶} [¡÷]ÂsÄý [o]ÂIºq¨ì¬ÝªO [m]ÂIºq¨ì«H½c [Enter]ÂsÄý [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +#define NECKER_NEWS "[¡ö]Â÷¶} [¡÷]¾\\Ū [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ·s »D ¼Ð ÃD%*s \033[m" + +#define NECKER_XPOST "\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s \033[m" + +#define NECKER_MBOX "[¡ö]Â÷¶} [¡÷,r]Ū«H [d]§R°£ [R,y](¸s²Õ)¦^«H [s]±H«H [x]Âà¿ý [X]Âà¹F [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ «H ¥ó ¼Ð ÃD%*s \033[m" + +#define NECKER_POST "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]µoªí [b]¶iªOµe± [d]§R°£ [V]§ë²¼ [TAB]ºëµØ°Ï [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s ¤H®ð:%-4d \033[m" + +#define NECKER_GEM "[¡ö]Â÷¶} [¡÷]ÂsÄý [B]¼Ò¦¡ [C]¼È¦s [F]Âà±H [d]§R°£ [h]»¡©ú %s\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +/* ¥H¤U³o¨Ç«h¬O¤@¨ÇÃþ XZ_* µ²ºcªº necker */ + +#define NECKER_VOTEALL "[¡ô/¡õ]¤W¤U [PgUp/PgDn]¤W¤U¶ [Home/End]º§À [¡÷]§ë²¼ [¡ö][q]Â÷¶}\n" \ + COLOR3 " ½s¸¹ ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ªO ¥D%*s \033[m" + +#define NECKER_CREDIT "[¡ö]Â÷¶} [C]´«¶ [1]·s¼W [2]§R°£ [3]¥þ§R [4]Á`p\n" \ + COLOR3 " ½s¸¹ ¤é ´Á ¦¬¤ä ª÷ ÃB ¤ÀÃþ »¡ ©ú%*s \033[m" + +#define NECKER_HELP "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]·s¼W [d]§R°£ [T]¼ÐÃD [E]½s¿è [m]²¾°Ê\n" \ + COLOR3 " ½s¸¹ ÀÉ ®× ¼Ð ÃD%*s \033[m" + +#define NECKER_INNBBS "[¡ö]Â÷¶} [^P]·s¼W [d]§R°£ [E]½s¿è [/]·j´M [Enter]¸Ô²Ó\n" \ + COLOR3 " ½s¸¹ ¤º ®e%*s \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gmore() ®Éªº footer ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* itoc.010914.µù¸Ñ: ³æ¤@½g¡A©Ò¥H¥s FOOTER¡A³£¬O 78 char */ + +/* itoc.010821: ª`·N \\ ¬O \¡A³Ì«á§Oº|¤F¤@ӪťÕÁä :p */ + +#define FOOTER_POST \ +COLOR1 " ¤å³¹¿ïŪ " COLOR2 " (ry)¦^À³ (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (C)¼È¦s " + +#define FOOTER_MAILER \ +COLOR1 " ³½¶©¹ªð " COLOR2 " (ry)¦^«H/¸s²Õ (X)Âà¹F (d)§R°£ (m)¼Ð°O (C)¼È¦s (=\\[]<>-+;'`|?QAkj) " + +#define FOOTER_GEM \ +COLOR1 " ºëµØ¿ïŪ " COLOR2 " (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} " + +#ifdef HAVE_GAME +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^O)¹ï«³¼Ò¦¡ (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í " +#else +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í (^Y)²M°£ " +#endif + +#define FOOTER_COSIGN \ +COLOR1 " ³s¸p¾÷¨î " COLOR2 " (ry)¥[¤J³s¸p (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} (h)»¡©ú " + +#define FOOTER_MORE \ +COLOR1 " ÂsÄý P.%d (%d%%) " COLOR2 " (h)»¡©ú [PgUp][PgDn][0][$]²¾°Ê (/n)·j´M (C)¼È¦s (¡öq)µ²§ô " + +#define FOOTER_VEDIT \ +COLOR1 " %s " COLOR2 " (^Z)»¡©ú (^W)²Å¸¹ (^L)«Ã¸ (^X)Àɮ׳B²z ùø%s¢x%sùø%5d:%3d \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gxo_foot() ®Éªº feeter ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + + +/* itoc.010914.µù¸Ñ: ¦Cªí¦h½g¡A©Ò¥H¥s FEETER¡A³£¬O 78 char */ + +#define FEETER_CLASS \ +COLOR1 " ¬ÝªO¿ï¾Ü " COLOR2 " (c)·s¤å³¹ (vV)¼Ð°O¤wŪ¥¼Åª (y)¥þ³¡¦C¥X (z)¿ïq (A)¥þ°ì·j´M (S)±Æ§Ç " + +#define FEETER_ULIST \ +COLOR1 " ºô¤Í¦Cªí " COLOR2 " (f)¦n¤Í (t)²á¤Ñ (q)¬d¸ß (ad)¥æ¤Í (m)±H«H (w)¤ô²y (s)§ó·s (TAB)¤Á´« " + +#define FEETER_PAL \ +COLOR1 " ©IªB¤Þ¦ñ " COLOR2 " (a)·s¼W (d)§R°£ (c)¤Í½Ë (m)±H«H (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_ALOHA \ +COLOR1 " ¤W¯¸³qª¾ " COLOR2 " (a)·s¼W (d)§R°£ (D)°Ï¬q§R°£ (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_VOTE \ +COLOR1 " ¬ÝªO§ë²¼ " COLOR2 " (¡÷/r/v)§ë²¼ (R)µ²ªG (^P)·s¼W§ë²¼ (E)×§ï (V)¹wÄý (b)¶}²¼ (o)¦W³æ " + +#define FEETER_BMW \ +COLOR1 " ¤ô²y¦^ÅU " COLOR2 " (d)§R°£ (D)°Ï¬q§R°£ (m)±H«H (w)¤ô²y (^R)¦^°T (^Q)¬d¸ß (s)§ó·s " + +#define FEETER_MF \ +COLOR1 " ³Ì·R¬ÝªO " COLOR2 " (^P)·s¼W (Cg)½Æ»s (p^V)¶K¤W (d)§R°£ (c)·s¤å³¹ (vV)¼Ð°O¤wŪ/¥¼Åª " + +#define FEETER_COSIGN \ +COLOR1 " ³s¸p¤p¯¸ " COLOR2 " (r)Ū¨ú (y)¦^À³ (^P)µoªí (d)§R°£ (o)¶}ªO (c)Ãö³¬ (E)½s¿è (B)³]©w " + +#define FEETER_SONG \ +COLOR1 " ÂIºq¨t²Î " COLOR2 " (r)Ū¨ú (o)ÂIºq¨ì¬ÝªO (m)ÂIºq¨ì«H½c (E)½s¿èÀÉ®× (T)½s¿è¼ÐÃD " + +#define FEETER_NEWS \ +COLOR1 " ·s»DÂI¿ï " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)¿ï¨ú (¡ö)(q)Â÷¶} " + +#define FEETER_XPOST \ +COLOR1 " ¦ê¦C·j´M " COLOR2 " (y)¦^À³ (x)Âà¿ý (m)¼Ð°O (d)§R°£ (^P)µoªí (^Q)¬d¸ß§@ªÌ (t)¼ÐÅÒ " + +#define FEETER_MBOX \ +COLOR1 " «H«H¬Û±¤ " COLOR2 " (y)¦^«H (F/X/x)Âà±H/Âà¹F/Âà¿ý (d)§R°£ (D)°Ï¬q§R°£ (m)¼Ð°O (E)½s¿è " + +#define FEETER_POST \ +COLOR1 " ¤å³¹¦Cªí " COLOR2 " (ry)¦^«H (S/a)·j´M/¼ÐÃD/§@ªÌ (~G)¦ê¦C·j´M (x)Âà¿ý (V)§ë²¼ (u)·s»D " + +#define FEETER_GEM \ +COLOR1 " ¬ÝªOºëµØ " COLOR2 " (^P/a/f)·s¼W/¤å³¹/¥Ø¿ý (E)½s¿è (T)¼ÐÃD (m)²¾°Ê (c)½Æ»s (p^V)¶K¤W " + +#define FEETER_VOTEALL \ +COLOR1 " §ë²¼¤¤¤ß " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷)§ë²¼ (¡ö)(q)Â÷¶} " + +#define FEETER_HELP \ +COLOR1 " »¡©ú¤å¥ó " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)ÂsÄý (¡ö)(q)Â÷¶} " + +#define FEETER_INNBBS \ +COLOR1 " Âà«H³]©w " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡ö)(q)Â÷¶} " + + +/* ----------------------------------------------------- */ +/* ¯¸¥x¨Ó·½Ã±¦W */ +/* ----------------------------------------------------- */ + +/* itoc: «ØÄ³ banner ¤£n¶W¹L¤T¦æ¡A¹Lªøªº¯¸Ã±¥i¯à·|³y¦¨¬Y¨Ç¨Ï¥ÎªÌªº¤Ï·P */ + +#define EDIT_BANNER "\n--\n" \ + " \033[1;41m¢~\033[44m¢q\033[m Or\033[1mig\033[30min\033[m: \033[1;46m "SCHOOLNAME"£»"BBSNAME" \033[44m "MYHOSTNAME" \033[m\n" \ + " \033[1;42m¢q\033[45m¢}\033[m A\033[1mut\033[30mho\033[mr: \033[1;36m%s\033[m ±q \033[1;33m%s\033[m µoªí\n" + +#define MODIFY_BANNER " \033[1;43m¢|\033[46m¢w\033[m \033[1mMo\033[30mdi\033[mfy: %s ©ó \033[1;36m%s\033[m ×§ï\n" + + +/* ----------------------------------------------------- */ +/* ¨ä¥L°T®§¦r¦ê */ +/* ----------------------------------------------------- */ + +#define VMSG_NULL "\033[1;46m ¡¹ ½Ð«ö (Space/Return) Ä~Äò ¡¹ \033[m" + +#define ICON_UNREAD_BRD "\033[36m¡á" /* ¥¼Åª¬ÝªO */ +#define ICON_READ_BRD " " /* ¤wŪ¬ÝªO */ + +#define ICON_GAMBLED_BRD "\033[1;31m½ä\033[m" /* Á|¦æ½ä½L¤¤ªº¬ÝªO */ +#define ICON_VOTED_BRD "\033[1;33m§ë\033[m" /* Á|¦æ§ë²¼¤¤ªº¬ÝªO */ +#define ICON_NOTRAN_BRD "¡³" /* ¤£Âà«HªO */ +#define ICON_TRAN_BRD "¡´" /* Âà«HªO */ + +#define TOKEN_ZAP_BRD '-' /* zap ªO */ +#define TOKEN_FRIEND_BRD '.' /* ¦n¤ÍªO */ +#define TOKEN_SECRET_BRD ')' /* ¯µ±KªO */ + +#endif /* _THEME_H_ */ diff --git a/include/theme/theme_green.h b/include/theme/theme_green.h new file mode 100644 index 0000000..2370a66 --- /dev/null +++ b/include/theme/theme_green.h @@ -0,0 +1,246 @@ +/*-------------------------------------------------------*/ +/* theme.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : custom theme */ +/* create : 02/08/17 */ +/* update : / / */ +/*-------------------------------------------------------*/ + + +#ifndef _THEME_H_ +#define _THEME_H_ + + +/* ----------------------------------------------------- */ +/* °ò¥»ÃC¦â©w¸q¡A¥H§Q¤¶±×§ï */ +/* ----------------------------------------------------- */ + +#define COLOR1 "\033[1;37;43m" /* footer/feeter ªº«e¬qÃC¦â */ +#define COLOR2 "\033[33;42m" /* footer/feeter ªº«á¬qÃC¦â */ +#define COLOR3 "\033[1;37;42m" /* neck ªºÃC¦â */ +#define COLOR4 "\033[1;33;42m" /* ¥ú´Î ªºÃC¦â */ +#define COLOR5 "\033[32;47m" /* more ÀÉÀYªº¼ÐÃDÃC¦â */ +#define COLOR6 "\033[37;42m" /* more ÀÉÀYªº¤º®eÃC¦â */ +#define COLOR7 "\033[32m" /* §@ªÌ¦b½u¤WªºÃC¦â */ + + +/* ----------------------------------------------------- */ +/* ¨Ï¥ÎªÌ¦W³æÃC¦â */ +/* ----------------------------------------------------- */ + +#define COLOR_NORMAL "" /* ¤@¯ë¨Ï¥ÎªÌ */ +#define COLOR_MYBAD "\033[1;31m" /* Ãa¤H */ +#define COLOR_MYGOOD "\033[1;32m" /* §Úªº¦n¤Í */ +#define COLOR_OGOOD "\033[1;33m" /* »P§Ú¬°¤Í */ +#define COLOR_CLOAK "\033[1;35m" /* Áô§Î */ /* itoc.µù¸Ñ: ¨S¥Î¨ì¡Anªº¤H½Ð¦Û¦æ¥[¤J ulist_body() */ +#define COLOR_SELF "\033[1;36m" /* ¦Û¤v */ +#define COLOR_BOTHGOOD "\033[1;37m" /* ¤¬³]¦n¤Í */ +#define COLOR_BRDMATE "\033[36m" /* ªO¦ñ */ + + +/* ----------------------------------------------------- */ +/* ¿ï³æ¦ì¸m */ +/* ----------------------------------------------------- */ + +/* itoc.µù¸Ñ: ª`·N MENU_XPOS n >= MENU_XNOTE + MOVIE_LINES */ + +#define MENU_XNOTE 2 /* °ÊºA¬ÝªO¥Ñ (2, 0) ¶}©l */ +#define MOVIE_LINES 10 /* °Êµe³Ì¦h¦³ 10 ¦C */ + +#define MENU_XPOS 13 /* ¿ï³æ¶}©lªº (x, y) ®y¼Ð */ +#define MENU_YPOS ((d_cols >> 1) + 18) + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡G*_neck() ®Éªº necker ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* necker ªº¦æ¼Æ³£¬O¤G¦æ¡A±q (1, 0) ¨ì (2, 80) */ + +/* ©Ò¦³ªº XZ_* ³£¦³ necker¡A¥u¬O¦³¨Ç¦b *_neck()¡A¦³¨ÇÂæb *_head() */ + +/* ulist_neck() ¤Î xpost_head() ªº²Ä¤@¦æ¤ñ¸û¯S§O¡A¤£¦b¦¹©w¸q */ + +#define NECKER_CLASS "[¡ö]¥D¿ï³æ [¡÷]¾\\Ū [¡ô¡õ]¿ï¾Ü [c]½g¼Æ [y]¸ü¤J [/?]·j´M [s]¬ÝªO [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_ULIST "\n" \ + COLOR3 " ½s¸¹ ¥N¸¹ ¼ÊºÙ%*s %-*s °ÊºA ¶¢¸m \033[m" + +#define NECKER_PAL "[¡ö]Â÷¶} [a]·s¼W [c]×§ï [d]§R°£ [m]±H«H [w]¤ô²y [s]¾ã²z [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤Í ½Ë%*s \033[m" + +#define NECKER_ALOHA "[¡ö]Â÷¶} [a]·s¼W [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [w]¤ô²y [s]«¾ã [f]¤Þ¤J [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤W ¯¸ ³q ª¾ ¦W ³æ%*s \033[m" + +#define NECKER_VOTE "[¡ö]Â÷¶} [R]µ²ªG [^P]Á|¦æ [E]×§ï [V]¹wÄý [^Q]§ï´Á [o]¦W³æ [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¶}²¼¤é ¥D¿ì¤H §ë ²¼ ©v ¦®%*s \033[m" + +#define NECKER_BMW "[¡ö]Â÷¶} [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [M]Àx¦s [w]¤ô²y [s]§ó·s [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤º ®e%*s ®É¶¡ \033[m" + +#define NECKER_MF "[¡ö]Â÷¶} [¡÷]¶i¤J [^P]·s¼W [d]§R°£ [c]¤Á´« [C]½Æ»s [^V]¶K¤W [m]²¾°Ê [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_COSIGN "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]¥Ó½Ð [d]§R°£ [o]¶}ªO [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á Á|¿ì¤H ¬Ý ªO ¼Ð ÃD%*s \033[m" + +#define NECKER_SONG "[¡ö]Â÷¶} [¡÷]ÂsÄý [o]ÂIºq¨ì¬ÝªO [m]ÂIºq¨ì«H½c [Enter]ÂsÄý [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +#define NECKER_NEWS "[¡ö]Â÷¶} [¡÷]¾\\Ū [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ·s »D ¼Ð ÃD%*s \033[m" + +#define NECKER_XPOST "\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s \033[m" + +#define NECKER_MBOX "[¡ö]Â÷¶} [¡÷,r]Ū«H [d]§R°£ [R,y](¸s²Õ)¦^«H [s]±H«H [x]Âà¿ý [X]Âà¹F [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ «H ¥ó ¼Ð ÃD%*s \033[m" + +#define NECKER_POST "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]µoªí [b]¶iªOµe± [d]§R°£ [V]§ë²¼ [TAB]ºëµØ°Ï [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s ¤H®ð:%-4d \033[m" + +#define NECKER_GEM "[¡ö]Â÷¶} [¡÷]ÂsÄý [B]¼Ò¦¡ [C]¼È¦s [F]Âà±H [d]§R°£ [h]»¡©ú %s\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +/* ¥H¤U³o¨Ç«h¬O¤@¨ÇÃþ XZ_* µ²ºcªº necker */ + +#define NECKER_VOTEALL "[¡ô/¡õ]¤W¤U [PgUp/PgDn]¤W¤U¶ [Home/End]º§À [¡÷]§ë²¼ [¡ö][q]Â÷¶}\n" \ + COLOR3 " ½s¸¹ ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ªO ¥D%*s \033[m" + +#define NECKER_CREDIT "[¡ö]Â÷¶} [C]´«¶ [1]·s¼W [2]§R°£ [3]¥þ§R [4]Á`p\n" \ + COLOR3 " ½s¸¹ ¤é ´Á ¦¬¤ä ª÷ ÃB ¤ÀÃþ »¡ ©ú%*s \033[m" + +#define NECKER_HELP "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]·s¼W [d]§R°£ [T]¼ÐÃD [E]½s¿è [m]²¾°Ê\n" \ + COLOR3 " ½s¸¹ ÀÉ ®× ¼Ð ÃD%*s \033[m" + +#define NECKER_INNBBS "[¡ö]Â÷¶} [^P]·s¼W [d]§R°£ [E]½s¿è [/]·j´M [Enter]¸Ô²Ó\n" \ + COLOR3 " ½s¸¹ ¤º ®e%*s \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gmore() ®Éªº footer ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* itoc.010914.µù¸Ñ: ³æ¤@½g¡A©Ò¥H¥s FOOTER¡A³£¬O 78 char */ + +/* itoc.010821: ª`·N \\ ¬O \¡A³Ì«á§Oº|¤F¤@ӪťÕÁä :p */ + +#define FOOTER_POST \ +COLOR1 " ¤å³¹¿ïŪ " COLOR2 " (ry)¦^À³ (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (C)¼È¦s " + +#define FOOTER_MAILER \ +COLOR1 " ³½¶©¹ªð " COLOR2 " (ry)¦^«H/¸s²Õ (X)Âà¹F (d)§R°£ (m)¼Ð°O (C)¼È¦s (=\\[]<>-+;'`|?QAkj) " + +#define FOOTER_GEM \ +COLOR1 " ºëµØ¿ïŪ " COLOR2 " (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} " + +#ifdef HAVE_GAME +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^O)¹ï«³¼Ò¦¡ (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í " +#else +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í (^Y)²M°£ " +#endif + +#define FOOTER_COSIGN \ +COLOR1 " ³s¸p¾÷¨î " COLOR2 " (ry)¥[¤J³s¸p (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} (h)»¡©ú " + +#define FOOTER_MORE \ +COLOR1 " ÂsÄý P.%d (%d%%) " COLOR2 " (h)»¡©ú [PgUp][PgDn][0][$]²¾°Ê (/n)·j´M (C)¼È¦s (¡öq)µ²§ô " + +#define FOOTER_VEDIT \ +COLOR1 " %s " COLOR2 " (^Z)»¡©ú (^W)²Å¸¹ (^L)«Ã¸ (^X)Àɮ׳B²z ùø%s¢x%sùø%5d:%3d \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gxo_foot() ®Éªº feeter ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + + +/* itoc.010914.µù¸Ñ: ¦Cªí¦h½g¡A©Ò¥H¥s FEETER¡A³£¬O 78 char */ + +#define FEETER_CLASS \ +COLOR1 " ¬ÝªO¿ï¾Ü " COLOR2 " (c)·s¤å³¹ (vV)¼Ð°O¤wŪ¥¼Åª (y)¥þ³¡¦C¥X (z)¿ïq (A)¥þ°ì·j´M (S)±Æ§Ç " + +#define FEETER_ULIST \ +COLOR1 " ºô¤Í¦Cªí " COLOR2 " (f)¦n¤Í (t)²á¤Ñ (q)¬d¸ß (ad)¥æ¤Í (m)±H«H (w)¤ô²y (s)§ó·s (TAB)¤Á´« " + +#define FEETER_PAL \ +COLOR1 " ©IªB¤Þ¦ñ " COLOR2 " (a)·s¼W (d)§R°£ (c)¤Í½Ë (m)±H«H (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_ALOHA \ +COLOR1 " ¤W¯¸³qª¾ " COLOR2 " (a)·s¼W (d)§R°£ (D)°Ï¬q§R°£ (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_VOTE \ +COLOR1 " ¬ÝªO§ë²¼ " COLOR2 " (¡÷/r/v)§ë²¼ (R)µ²ªG (^P)·s¼W§ë²¼ (E)×§ï (V)¹wÄý (b)¶}²¼ (o)¦W³æ " + +#define FEETER_BMW \ +COLOR1 " ¤ô²y¦^ÅU " COLOR2 " (d)§R°£ (D)°Ï¬q§R°£ (m)±H«H (w)¤ô²y (^R)¦^°T (^Q)¬d¸ß (s)§ó·s " + +#define FEETER_MF \ +COLOR1 " ³Ì·R¬ÝªO " COLOR2 " (^P)·s¼W (Cg)½Æ»s (p^V)¶K¤W (d)§R°£ (c)·s¤å³¹ (vV)¼Ð°O¤wŪ/¥¼Åª " + +#define FEETER_COSIGN \ +COLOR1 " ³s¸p¤p¯¸ " COLOR2 " (r)Ū¨ú (y)¦^À³ (^P)µoªí (d)§R°£ (o)¶}ªO (c)Ãö³¬ (E)½s¿è (B)³]©w " + +#define FEETER_SONG \ +COLOR1 " ÂIºq¨t²Î " COLOR2 " (r)Ū¨ú (o)ÂIºq¨ì¬ÝªO (m)ÂIºq¨ì«H½c (E)½s¿èÀÉ®× (T)½s¿è¼ÐÃD " + +#define FEETER_NEWS \ +COLOR1 " ·s»DÂI¿ï " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)¿ï¨ú (¡ö)(q)Â÷¶} " + +#define FEETER_XPOST \ +COLOR1 " ¦ê¦C·j´M " COLOR2 " (y)¦^À³ (x)Âà¿ý (m)¼Ð°O (d)§R°£ (^P)µoªí (^Q)¬d¸ß§@ªÌ (t)¼ÐÅÒ " + +#define FEETER_MBOX \ +COLOR1 " «H«H¬Û±¤ " COLOR2 " (y)¦^«H (F/X/x)Âà±H/Âà¹F/Âà¿ý (d)§R°£ (D)°Ï¬q§R°£ (m)¼Ð°O (E)½s¿è " + +#define FEETER_POST \ +COLOR1 " ¤å³¹¦Cªí " COLOR2 " (ry)¦^«H (S/a)·j´M/¼ÐÃD/§@ªÌ (~G)¦ê¦C·j´M (x)Âà¿ý (V)§ë²¼ (u)·s»D " + +#define FEETER_GEM \ +COLOR1 " ¬ÝªOºëµØ " COLOR2 " (^P/a/f)·s¼W/¤å³¹/¥Ø¿ý (E)½s¿è (T)¼ÐÃD (m)²¾°Ê (c)½Æ»s (p^V)¶K¤W " + +#define FEETER_VOTEALL \ +COLOR1 " §ë²¼¤¤¤ß " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷)§ë²¼ (¡ö)(q)Â÷¶} " + +#define FEETER_HELP \ +COLOR1 " »¡©ú¤å¥ó " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)ÂsÄý (¡ö)(q)Â÷¶} " + +#define FEETER_INNBBS \ +COLOR1 " Âà«H³]©w " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡ö)(q)Â÷¶} " + + +/* ----------------------------------------------------- */ +/* ¯¸¥x¨Ó·½Ã±¦W */ +/* ----------------------------------------------------- */ + +/* itoc: «ØÄ³ banner ¤£n¶W¹L¤T¦æ¡A¹Lªøªº¯¸Ã±¥i¯à·|³y¦¨¬Y¨Ç¨Ï¥ÎªÌªº¤Ï·P */ + +#define EDIT_BANNER "\n--\n" \ + " \033[1;41mùÝ\033[44mùß\033[m O\033[1mri\033[30mgi\033[mn: \033[1;42m "SCHOOLNAME"£»"BBSNAME" \033[44m "MYHOSTNAME" \033[m\n" \ + " \033[1;42mùã\033[45mùå\033[m Au\033[1mt\033[30mho\033[mr: \033[1;32m%s\033[m ±q \033[1;35m%s\033[m µoªí\n" + +#define MODIFY_BANNER " \033[1;43m¢¬\033[46m¢\033[m \033[1mMo\033[30mdi\033[mfy: %s ©ó \033[1;32m%s\033[m ×§ï\n" + + +/* ----------------------------------------------------- */ +/* ¨ä¥L°T®§¦r¦ê */ +/* ----------------------------------------------------- */ + +#define VMSG_NULL " \033[1;32;45m¡´ ½Ð«ö¥ô·NÁäÄ~Äò ¡´\033[m" + +#define ICON_UNREAD_BRD "\033[32m£¾" /* ¥¼Åª¬ÝªO */ +#define ICON_READ_BRD " " /* ¤wŪ¬ÝªO */ + +#define ICON_GAMBLED_BRD "\033[1;31m½ä\033[m" /* Á|¦æ½ä½L¤¤ªº¬ÝªO */ +#define ICON_VOTED_BRD "\033[1;33m§ë\033[m" /* Á|¦æ§ë²¼¤¤ªº¬ÝªO */ +#define ICON_NOTRAN_BRD "¡·" /* ¤£Âà«HªO */ +#define ICON_TRAN_BRD "¡´" /* Âà«HªO */ + +#define TOKEN_ZAP_BRD '-' /* zap ªO */ +#define TOKEN_FRIEND_BRD '.' /* ¦n¤ÍªO */ +#define TOKEN_SECRET_BRD ')' /* ¯µ±KªO */ + +#endif /* _THEME_H_ */ diff --git a/include/theme/theme_neck.h b/include/theme/theme_neck.h new file mode 100644 index 0000000..7ca15d3 --- /dev/null +++ b/include/theme/theme_neck.h @@ -0,0 +1,246 @@ +/*-------------------------------------------------------*/ +/* theme.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : custom theme */ +/* create : 02/08/17 */ +/* update : / / */ +/*-------------------------------------------------------*/ + + +#ifndef _THEME_H_ +#define _THEME_H_ + + +/* ----------------------------------------------------- */ +/* °ò¥»ÃC¦â©w¸q¡A¥H§Q¤¶±×§ï */ +/* ----------------------------------------------------- */ + +#define COLOR1 "\033[1;37;44m" /* footer/feeter ªº«e¬qÃC¦â */ +#define COLOR2 "\033[0;30;47m" /* footer/feeter ªº«á¬qÃC¦â */ +#define COLOR3 "\033[30;47m" /* neck ªºÃC¦â */ +#define COLOR4 "\033[1;44m" /* ¥ú´Î ªºÃC¦â */ +#define COLOR5 "\033[34;47m" /* more ÀÉÀYªº¼ÐÃDÃC¦â */ +#define COLOR6 "\033[37;44m" /* more ÀÉÀYªº¤º®eÃC¦â */ +#define COLOR7 "\033[1m" /* §@ªÌ¦b½u¤WªºÃC¦â */ + + +/* ----------------------------------------------------- */ +/* ¨Ï¥ÎªÌ¦W³æÃC¦â */ +/* ----------------------------------------------------- */ + +#define COLOR_NORMAL "" /* ¤@¯ë¨Ï¥ÎªÌ */ +#define COLOR_MYBAD "\033[1;31m" /* Ãa¤H */ +#define COLOR_MYGOOD "\033[1;32m" /* §Úªº¦n¤Í */ +#define COLOR_OGOOD "\033[1;33m" /* »P§Ú¬°¤Í */ +#define COLOR_CLOAK "\033[1;35m" /* Áô§Î */ /* itoc.µù¸Ñ: ¨S¥Î¨ì¡Anªº¤H½Ð¦Û¦æ¥[¤J ulist_body() */ +#define COLOR_SELF "\033[1;36m" /* ¦Û¤v */ +#define COLOR_BOTHGOOD "\033[1;37m" /* ¤¬³]¦n¤Í */ +#define COLOR_BRDMATE "\033[36m" /* ªO¦ñ */ + + +/* ----------------------------------------------------- */ +/* ¿ï³æ¦ì¸m */ +/* ----------------------------------------------------- */ + +/* itoc.µù¸Ñ: ª`·N MENU_XPOS n >= MENU_XNOTE + MOVIE_LINES */ + +#define MENU_XNOTE 2 /* °ÊºA¬ÝªO¥Ñ (2, 0) ¶}©l */ +#define MOVIE_LINES 10 /* °Êµe³Ì¦h¦³ 10 ¦C */ + +#define MENU_XPOS 13 /* ¿ï³æ¶}©lªº (x, y) ®y¼Ð */ +#define MENU_YPOS ((d_cols >> 1) + 18) + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡G*_neck() ®Éªº necker ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* necker ªº¦æ¼Æ³£¬O¤G¦æ¡A±q (1, 0) ¨ì (2, 80) */ + +/* ©Ò¦³ªº XZ_* ³£¦³ necker¡A¥u¬O¦³¨Ç¦b *_neck()¡A¦³¨ÇÂæb *_head() */ + +/* ulist_neck() ¤Î xpost_head() ªº²Ä¤@¦æ¤ñ¸û¯S§O¡A¤£¦b¦¹©w¸q */ + +#define NECKER_CLASS "\033[40m¢¨\033[30;47m¬ÝªO\033[37;46m¢©¤å³¹¢@ºëµØ\033[36;40m¢©\033[37m S)±Æ§Ç c)·s¤å³¹¼Ò¦¡ v|V)¼Ð°O¤wŪ|¥¼Åª h)»¡©ú\033[m\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_ULIST "\n" \ + COLOR3 " ½s¸¹ ¥N¸¹ ¼ÊºÙ%*s %-*s °ÊºA ¶¢¸m \033[m" + +#define NECKER_PAL "\033[30;46m¢«\033[37m¤ô²y¢¨\033[30;47m¦n¤Í\033[37;46m¢©¤W¯¸\033[36;40m¢©\033[37m a)·s¼W c)×§ï d)§R°£ s)¾ã²z m)±H«H w)¤ô²y h)»¡©ú\033[m\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤Í ½Ë%*s \033[m" + +#define NECKER_ALOHA "\033[30;46m¢«\033[37m¤ô²y¢@¦n¤Í¢¨\033[30;47m¤W¯¸\033[37;40m¢© a)·s¼W c)×§ï d|D)§R°£ f)¤Þ¤J m)±H«H w)¤ô²y h)»¡©ú\033[m\n" \ + COLOR3 " ½s¸¹ ¤W ¯¸ ³q ª¾ ¦W ³æ%*s \033[m" + +#define NECKER_VOTE "\033[40m¢¨\033[30;47m§ë²¼\033[37;46m¢©¤¤¤ß¢@³s¸p\033[36;40m¢©\033[37m R)µ²ªG ^P|^Q)Á|¿ì|§ï´Á V)¹wÄý E)½s¿è h)»¡©ú\033[m\n" \ + COLOR3 " ½s¸¹ ¶}²¼¤é ¥D¿ì¤H §ë ²¼ ©v ¦®%*s \033[m" + +#define NECKER_BMW "\033[40m¢¨\033[30;47m¤ô²y\033[37;46m¢©¦n¤Í¢@¤W¯¸\033[36;40m¢©\033[37m s)§ó·s w)¤ô²y m)±H«H d|D)§R°£ ¡÷)¬d¸ß h)»¡©ú\033[m\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤º ®e%*s ®É¶¡ \033[m" + +#define NECKER_MF "\033[40m¢¨\033[30;47m³Ì·R\033[37;46m¢©·s»D¢@ÂIºq\033[36;40m¢©\033[37m ^P)·s¼W d)§R°£ c)¤Á´« C|^V)½Æ»s|¶K¤W m)²¾°Ê h)»¡©ú\033[m\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_COSIGN "\033[30;46m¢«\033[37m§ë²¼¢@¤¤¤ß¢¨\033[30;47m³s¸p\033[37;40m¢© ^P)µoªí d)§R°£ y)¥[¤J h)»¡©ú\033[m\n" \ + COLOR3 " ½s¸¹ ¤é ´Á Á|¿ì¤H ¬Ý ªO ¼Ð ÃD%*s \033[m" + +#define NECKER_SONG "\033[30;46m¢«\033[37m³Ì·R¢@·s»D¢¨\033[30;47mÂIºq\033[37;40m¢© o|m)ÂIºq|¬ÝªO|«H½c ¡÷)ÂsÄý h)»¡©ú\033[m\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +#define NECKER_NEWS "\033[30;46m¢«\033[37m³Ì·R¢¨\033[30;47m·s»D\033[37;46m¢©ÂIºq\033[36;40m¢©\033[37m ¡÷)ÂsÄý h)»¡©ú\033[m\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ·s »D ¼Ð ÃD%*s \033[m" + +#define NECKER_XPOST "\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s \033[m" + +#define NECKER_MBOX "\033[40m¢¨\033[30;47m¶l§½\033[37;46m¢©»È¦æ¢@±b¤á\033[36;40m¢©\033[37m d)§R°£ R|y)¸s²Õ|¦^«H s)±H«H x|X)Âà¿ý|Âà¹F h)»¡©ú\033[m\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ «H ¥ó ¼Ð ÃD%*s \033[m" + +#define NECKER_POST "\033[30;46m¢«\033[37m¬ÝªO¢¨\033[30;47m¤å³¹\033[37;46m¢©ºëµØ\033[36;40m¢©\033[37m S|a|/)·j´M|§@ªÌ|¼ÐÃD ^P)µoªí z)ºëµØ°Ï h)»¡©ú\033[m\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s ¤H®ð:%-4d \033[m" + +#define NECKER_GEM "\033[30;46m¢«\033[37m¬ÝªO¢@¤å³¹¢¨\033[30;47mºëµØ\033[37;40m¢© %21.21s B)¼Ò¦¡ C)¼È¦s F)Âà±H h)»¡©ú\033[m\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +/* ¥H¤U³o¨Ç«h¬O¤@¨ÇÃþ XZ_* µ²ºcªº necker */ + +#define NECKER_VOTEALL "\033[30;46m¢«\033[37m§ë²¼¢¨\033[30;47m¤¤¤ß\033[37;46m¢©³s¸p\033[36;40m¢©\033[37m ¡÷)§ë²¼ h)»¡©ú\033[m\n" \ + COLOR3 " ½s¸¹ ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ªO ¥D%*s \033[m" + +#define NECKER_CREDIT "\033[30;46m¢«\033[37m¶l§½¢@»È¦æ¢¨\033[30;47m±b¤á\033[37;40m¢©\033[m\n" \ + COLOR3 " ½s¸¹ ¤é ´Á ¦¬¤ä ª÷ ÃB ¤ÀÃþ »¡ ©ú%*s \033[m" + +#define NECKER_HELP "\033[30;46m¢«\033[37m»¡©ú¢¨\033[30;47mªA°È\033[37;46m¢©´©§U\033[36;40m¢©\033[37m T)¼ÐÃD E)½s¿è m)²¾°Ê ^P)·s¼W d)§R°£\033[m\n" \ + COLOR3 " ½s¸¹ ÀÉ ®× ¼Ð ÃD%*s \033[m" + +#define NECKER_INNBBS "\033[30;46m¢«\033[37mÂà«H¢¨\033[30;47mÂà«H\033[37;46m¢©Âà«H\033[36;40m¢©\033[37m ^P)·s¼W d)§R°£ E½s¿è /)·j´M Enter)¸Ô²Ó\033[m\n" \ + COLOR3 " ½s¸¹ ¤º ®e%*s \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gmore() ®Éªº footer ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* itoc.010914.µù¸Ñ: ³æ¤@½g¡A©Ò¥H¥s FOOTER¡A³£¬O 78 char */ + +/* itoc.010821: ª`·N \\ ¬O \¡A³Ì«á§Oº|¤F¤@ӪťÕÁä :p */ + +#define FOOTER_POST \ +COLOR1 " ¤å³¹¿ïŪ " COLOR2 " (ry)¦^À³ (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (C)¼È¦s " + +#define FOOTER_MAILER \ +COLOR1 " ³½¶©¹ªð " COLOR2 " (ry)¸s²Õ/¦^«H (X)Âà¹F (d)§R°£ (m)¼Ð°O (C)¼È¦s (=\\[]<>-+;'`|?QAkj)" + +#define FOOTER_GEM \ +COLOR1 " ºëµØ¿ïŪ " COLOR2 " (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} " + +#ifdef HAVE_GAME +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^O)¹ï«³ (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í " +#else +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í (^Y)²M°£ " +#endif + +#define FOOTER_COSIGN \ +COLOR1 " ³s¸p¾÷¨î " COLOR2 " (ry)¥[¤J³s¸p (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} (h)»¡©ú " + +#define FOOTER_MORE \ +COLOR1 " ÂsÄý P.%d (%d%%) " COLOR2 " (h)»¡©ú [PgUp][PgDn][0][$]²¾°Ê (/n)·j´M (C)¼È¦s (¡öq)µ²§ô " + +#define FOOTER_VEDIT \ +COLOR1 " %s " COLOR2 " (^Z)»¡©ú (^W)²Å¸¹ (^L)«Ã¸ (^X)Àɮ׳B²z ùø%s¢x%sùø%5d:%3d \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gxo_foot() ®Éªº feeter ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + + +/* itoc.010914.µù¸Ñ: ¦Cªí¦h½g¡A©Ò¥H¥s FEETER¡A³£¬O 78 char */ + +#define FEETER_CLASS \ +COLOR1 " ¬ÝªO¿ï¾Ü " COLOR2 " (c)·s¤å³¹ (vV)¤wŪ¥¼Åª (y)¥þ³¡¦C¥X (z)¿ïq (A)¥þ°ì·j´M (S)±Æ§Ç " + +#define FEETER_ULIST \ +COLOR1 " ºô¤Í¦Cªí " COLOR2 " (f)¦n¤Í (t)²á¤Ñ (q)¬d¸ß (ad)¥æ¤Í (w)¤ô²y (s)§ó·s (TAB)¤Á´« " + +#define FEETER_PAL \ +COLOR1 " ©IªB¤Þ¦ñ " COLOR2 " (a)·s¼W (d)§R°£ (c)¤Í½Ë (m)±H«H (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_ALOHA \ +COLOR1 " ¤W¯¸³qª¾ " COLOR2 " (a)·s¼W (d)§R°£ (D)°Ï¬q§R°£ (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_VOTE \ +COLOR1 " ¬ÝªO§ë²¼ " COLOR2 " (¡÷/r/v)§ë²¼ (R)µ²ªG (^P)·s¼W§ë²¼ (E)×§ï (V)¹wÄý (b)¶}²¼ (o)¦W³æ " + +#define FEETER_BMW \ +COLOR1 " ¤ô²y¦^ÅU " COLOR2 " (d)§R°£ (D)°Ï¬q§R°£ (m)±H«H (w)¤ô²y (^R)¦^°T (^Q)¬d¸ß (s)§ó·s " + +#define FEETER_MF \ +COLOR1 " ³Ì·R¬ÝªO " COLOR2 " (^P)·s¼W (Cg)½Æ»s (p^V)¶K¤W (d)§R°£ (c)·s¤å³¹ (vV)¼Ð°O¤wŪ/¥¼Åª " + +#define FEETER_COSIGN \ +COLOR1 " ³s¸p¤p¯¸ " COLOR2 " (r)Ū¨ú (y)¦^À³ (^P)µoªí (d)§R°£ (o)¶}ªO (c)Ãö³¬ (E)½s¿è (B)³]©w " + +#define FEETER_SONG \ +COLOR1 " ÂIºq¨t²Î " COLOR2 " (r)Ū¨ú (o)ÂIºq¨ì¬ÝªO (m)ÂIºq¨ì«H½c (E)½s¿èÀÉ®× (T)½s¿è¼ÐÃD " + +#define FEETER_NEWS \ +COLOR1 " ·s»DÂI¿ï " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)¿ï¨ú (¡ö)Â÷¶} " + +#define FEETER_XPOST \ +COLOR1 " ¦ê¦C·j´M " COLOR2 " (y)¦^À³ (x)Âà¿ý (m)¼Ð°O (d)§R°£ (^P)µoªí (^Q)¬d¸ß§@ªÌ (t)¼ÐÅÒ " + +#define FEETER_MBOX \ +COLOR1 " «H«H¬Û±¤ " COLOR2 " (y)¦^«H (F/X/x)Âà±H/Âà¹F/Âà¿ý (d)§R°£ (D)°Ï¬q§R°£ (m)¼Ð°O " + +#define FEETER_POST \ +COLOR1 " ¤å³¹¦Cªí " COLOR2 " (ry)¦^«H (S/a)·j´M/¼ÐÃD/§@ªÌ (~G)¦ê¦C (x)Âà¿ý (V)§ë²¼ (u)·s»D " + +#define FEETER_GEM \ +COLOR1 " ¬ÝªOºëµØ " COLOR2 " (^P/a/f)·s¼W/¤å³¹/¥Ø¿ý (E)½s¿è (T)¼ÐÃD (m)²¾°Ê (c)½Æ»s (p^V)¶K¤W " + +#define FEETER_VOTEALL \ +COLOR1 " §ë²¼¤¤¤ß " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷)§ë²¼ (¡ö)Â÷¶} " + +#define FEETER_HELP \ +COLOR1 " »¡©ú¤å¥ó " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)ÂsÄý (¡ö)Â÷¶} " + +#define FEETER_INNBBS \ +COLOR1 " Âà«H³]©w " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡ö)(q)Â÷¶} " + + +/* ----------------------------------------------------- */ +/* ¯¸¥x¨Ó·½Ã±¦W */ +/* ----------------------------------------------------- */ + +/* itoc: «ØÄ³ banner ¤£n¶W¹L¤T¦æ¡A¹Lªøªº¯¸Ã±¥i¯à·|³y¦¨¬Y¨Ç¨Ï¥ÎªÌªº¤Ï·P */ + +#define EDIT_BANNER "\n--\n" \ + " \033[1;41m ¯¸ ¥x \033[40;33m "SCHOOLNAME"£»"BBSNAME" \033[35m¡m"MYHOSTNAME"¡n\033[m\n" \ + " \033[1;42m ¨Ó ·½ \033[40;36m %.0s%s\033[m\n" + +#define MODIFY_BANNER " \033[1;44m ½s ¿è \033[40;37m %.0s%s\033[m\n" + + +/* ----------------------------------------------------- */ +/* ¨ä¥L°T®§¦r¦ê */ +/* ----------------------------------------------------- */ + +#define VMSG_NULL " \033[1;36m ¢j¢k¢l¢m¢n¢o¢p ½Ð«ö¥ô·NÁäÄ~Äò ¢p\033[m" + +#define ICON_UNREAD_BRD "\033[33m¡÷" /* ¥¼Åª¬ÝªO */ +#define ICON_READ_BRD " " /* ¤wŪ¬ÝªO */ + +#define ICON_GAMBLED_BRD "\033[1;31m½ä\033[m" /* Á|¦æ½ä½L¤¤ªº¬ÝªO */ +#define ICON_VOTED_BRD "\033[1;33m§ë\033[m" /* Á|¦æ§ë²¼¤¤ªº¬ÝªO */ +#define ICON_NOTRAN_BRD "¡¸" /* ¤£Âà«HªO */ +#define ICON_TRAN_BRD "¡¹" /* Âà«HªO */ + +#define TOKEN_ZAP_BRD '-' /* zap ªO */ +#define TOKEN_FRIEND_BRD '.' /* ¦n¤ÍªO */ +#define TOKEN_SECRET_BRD ')' /* ¯µ±KªO */ + +#endif /* _THEME_H_ */ diff --git a/include/theme/theme_pack.h b/include/theme/theme_pack.h new file mode 100644 index 0000000..82722a7 --- /dev/null +++ b/include/theme/theme_pack.h @@ -0,0 +1,246 @@ +/*-------------------------------------------------------*/ +/* theme.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : custom theme */ +/* create : 02/08/17 */ +/* update : / / */ +/*-------------------------------------------------------*/ + + +#ifndef _THEME_H_ +#define _THEME_H_ + + +/* ----------------------------------------------------- */ +/* °ò¥»ÃC¦â©w¸q¡A¥H§Q¤¶±×§ï */ +/* ----------------------------------------------------- */ + +#define COLOR1 "\033[34;46m" /* footer/feeter ªº«e¬qÃC¦â */ +#define COLOR2 "\033[0;30;47m" /* footer/feeter ªº«á¬qÃC¦â */ +#define COLOR3 "\033[30;47m" /* neck ªºÃC¦â */ +#define COLOR4 "\033[1;44m" /* ¥ú´Î ªºÃC¦â */ +#define COLOR5 "\033[34;47m" /* more ÀÉÀYªº¼ÐÃDÃC¦â */ +#define COLOR6 "\033[37;44m" /* more ÀÉÀYªº¤º®eÃC¦â */ +#define COLOR7 "\033[36m" /* §@ªÌ¦b½u¤WªºÃC¦â */ + + +/* ----------------------------------------------------- */ +/* ¨Ï¥ÎªÌ¦W³æÃC¦â */ +/* ----------------------------------------------------- */ + +#define COLOR_NORMAL "" /* ¤@¯ë¨Ï¥ÎªÌ */ +#define COLOR_MYBAD "\033[1;31m" /* Ãa¤H */ +#define COLOR_MYGOOD "\033[1;32m" /* §Úªº¦n¤Í */ +#define COLOR_OGOOD "\033[1;33m" /* »P§Ú¬°¤Í */ +#define COLOR_CLOAK "\033[1;35m" /* Áô§Î */ /* itoc.µù¸Ñ: ¨S¥Î¨ì¡Anªº¤H½Ð¦Û¦æ¥[¤J ulist_body() */ +#define COLOR_SELF "\033[1;36m" /* ¦Û¤v */ +#define COLOR_BOTHGOOD "\033[1;37m" /* ¤¬³]¦n¤Í */ +#define COLOR_BRDMATE "\033[36m" /* ªO¦ñ */ + + +/* ----------------------------------------------------- */ +/* ¿ï³æ¦ì¸m */ +/* ----------------------------------------------------- */ + +/* itoc.µù¸Ñ: ª`·N MENU_XPOS n >= MENU_XNOTE + MOVIE_LINES */ + +#define MENU_XNOTE 2 /* °ÊºA¬ÝªO¥Ñ (2, 0) ¶}©l */ +#define MOVIE_LINES 10 /* °Êµe³Ì¦h¦³ 10 ¦C */ + +#define MENU_XPOS 13 /* ¿ï³æ¶}©lªº (x, y) ®y¼Ð */ +#define MENU_YPOS ((d_cols >> 1) + 18) + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡G*_neck() ®Éªº necker ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* necker ªº¦æ¼Æ³£¬O¤G¦æ¡A±q (1, 0) ¨ì (2, 80) */ + +/* ©Ò¦³ªº XZ_* ³£¦³ necker¡A¥u¬O¦³¨Ç¦b *_neck()¡A¦³¨ÇÂæb *_head() */ + +/* ulist_neck() ¤Î xpost_head() ªº²Ä¤@¦æ¤ñ¸û¯S§O¡A¤£¦b¦¹©w¸q */ + +#define NECKER_CLASS "[¡ö]¥D¿ï³æ [¡÷]¾\\Ū [¡ô¡õ]¿ï¾Ü [c]½g¼Æ [y]¸ü¤J [/?]·j´M [s]¬ÝªO [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_ULIST "\n" \ + COLOR3 " ½s¸¹ ¥N¸¹ ¼ÊºÙ%*s %-*s °ÊºA ¶¢¸m \033[m" + +#define NECKER_PAL "[¡ö]Â÷¶} [a]·s¼W [c]×§ï [d]§R°£ [m]±H«H [w]¤ô²y [s]¾ã²z [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤Í ½Ë%*s \033[m" + +#define NECKER_ALOHA "[¡ö]Â÷¶} [a]·s¼W [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [w]¤ô²y [s]«¾ã [f]¤Þ¤J [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤W ¯¸ ³q ª¾ ¦W ³æ%*s \033[m" + +#define NECKER_VOTE "[¡ö]Â÷¶} [R]µ²ªG [^P]Á|¦æ [E]×§ï [V]¹wÄý [^Q]§ï´Á [o]¦W³æ [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¶}²¼¤é ¥D¿ì¤H §ë ²¼ ©v ¦®%*s \033[m" + +#define NECKER_BMW "[¡ö]Â÷¶} [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [M]Àx¦s [w]¤ô²y [s]§ó·s [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤º ®e%*s ®É¶¡ \033[m" + +#define NECKER_MF "[¡ö]Â÷¶} [¡÷]¶i¤J [^P]·s¼W [d]§R°£ [c]¤Á´« [C]½Æ»s [^V]¶K¤W [m]²¾°Ê [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_COSIGN "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]¥Ó½Ð [d]§R°£ [o]¶}ªO [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á Á|¿ì¤H ¬Ý ªO ¼Ð ÃD%*s \033[m" + +#define NECKER_SONG "[¡ö]Â÷¶} [¡÷]ÂsÄý [o]ÂIºq¨ì¬ÝªO [m]ÂIºq¨ì«H½c [Enter]ÂsÄý [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +#define NECKER_NEWS "[¡ö]Â÷¶} [¡÷]¾\\Ū [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ·s »D ¼Ð ÃD%*s \033[m" + +#define NECKER_XPOST "\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s \033[m" + +#define NECKER_MBOX "[¡ö]Â÷¶} [¡÷,r]Ū«H [d]§R°£ [R,y](¸s²Õ)¦^«H [s]±H«H [x]Âà¿ý [X]Âà¹F [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ «H ¥ó ¼Ð ÃD%*s \033[m" + +#define NECKER_POST "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]µoªí [b]¶iªOµe± [d]§R°£ [V]§ë²¼ [TAB]ºëµØ°Ï [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s ¤H®ð:%-4d \033[m" + +#define NECKER_GEM "[¡ö]Â÷¶} [¡÷]ÂsÄý [B]¼Ò¦¡ [C]¼È¦s [F]Âà±H [d]§R°£ [h]»¡©ú %s\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +/* ¥H¤U³o¨Ç«h¬O¤@¨ÇÃþ XZ_* µ²ºcªº necker */ + +#define NECKER_VOTEALL "[¡ô/¡õ]¤W¤U [PgUp/PgDn]¤W¤U¶ [Home/End]º§À [¡÷]§ë²¼ [¡ö][q]Â÷¶}\n" \ + COLOR3 " ½s¸¹ ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ªO ¥D%*s \033[m" + +#define NECKER_CREDIT "[¡ö]Â÷¶} [C]´«¶ [1]·s¼W [2]§R°£ [3]¥þ§R [4]Á`p\n" \ + COLOR3 " ½s¸¹ ¤é ´Á ¦¬¤ä ª÷ ÃB ¤ÀÃþ »¡ ©ú%*s \033[m" + +#define NECKER_HELP "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]·s¼W [d]§R°£ [T]¼ÐÃD [E]½s¿è [m]²¾°Ê\n" \ + COLOR3 " ½s¸¹ ÀÉ ®× ¼Ð ÃD%*s \033[m" + +#define NECKER_INNBBS "[¡ö]Â÷¶} [^P]·s¼W [d]§R°£ [E]½s¿è [/]·j´M [Enter]¸Ô²Ó\n" \ + COLOR3 " ½s¸¹ ¤º ®e%*s \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gmore() ®Éªº footer ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* itoc.010914.µù¸Ñ: ³æ¤@½g¡A©Ò¥H¥s FOOTER¡A³£¬O 78 char */ + +/* itoc.010821: ª`·N \\ ¬O \¡A³Ì«á§Oº|¤F¤@ӪťÕÁä :p */ + +#define FOOTER_POST \ +COLOR1 " ¤å³¹¿ïŪ " COLOR2 " (ry)¦^À³ (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (C)¼È¦s " + +#define FOOTER_MAILER \ +COLOR1 " ³½¶©¹ªð " COLOR2 " (ry)¦^«H/¸s²Õ (X)Âà¹F (d)§R°£ (m)¼Ð°O (C)¼È¦s (=\\[]<>-+;'`|?QAkj) " + +#define FOOTER_GEM \ +COLOR1 " ºëµØ¿ïŪ " COLOR2 " (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} " + +#ifdef HAVE_GAME +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^O)¹ï«³¼Ò¦¡ (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í " +#else +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í (^Y)²M°£ " +#endif + +#define FOOTER_COSIGN \ +COLOR1 " ³s¸p¾÷¨î " COLOR2 " (ry)¥[¤J³s¸p (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} (h)»¡©ú " + +#define FOOTER_MORE \ +COLOR1 " ÂsÄý P.%d (%d%%) " COLOR2 " (h)»¡©ú [PgUp][PgDn][0][$]²¾°Ê (/n)·j´M (C)¼È¦s (¡öq)µ²§ô " + +#define FOOTER_VEDIT \ +COLOR1 " %s " COLOR2 " (^Z)»¡©ú (^W)²Å¸¹ (^L)«Ã¸ (^X)Àɮ׳B²z ùø%s¢x%sùø%5d:%3d \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gxo_foot() ®Éªº feeter ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + + +/* itoc.010914.µù¸Ñ: ¦Cªí¦h½g¡A©Ò¥H¥s FEETER¡A³£¬O 78 char */ + +#define FEETER_CLASS \ +COLOR1 " ¬ÝªO¿ï¾Ü " COLOR2 " (c)·s¤å³¹ (vV)¼Ð°O¤wŪ¥¼Åª (y)¥þ³¡¦C¥X (z)¿ïq (A)¥þ°ì·j´M (S)±Æ§Ç " + +#define FEETER_ULIST \ +COLOR1 " ºô¤Í¦Cªí " COLOR2 " (f)¦n¤Í (t)²á¤Ñ (q)¬d¸ß (ad)¥æ¤Í (m)±H«H (w)¤ô²y (s)§ó·s (TAB)¤Á´« " + +#define FEETER_PAL \ +COLOR1 " ©IªB¤Þ¦ñ " COLOR2 " (a)·s¼W (d)§R°£ (c)¤Í½Ë (m)±H«H (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_ALOHA \ +COLOR1 " ¤W¯¸³qª¾ " COLOR2 " (a)·s¼W (d)§R°£ (D)°Ï¬q§R°£ (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_VOTE \ +COLOR1 " ¬ÝªO§ë²¼ " COLOR2 " (¡÷/r/v)§ë²¼ (R)µ²ªG (^P)·s¼W§ë²¼ (E)×§ï (V)¹wÄý (b)¶}²¼ (o)¦W³æ " + +#define FEETER_BMW \ +COLOR1 " ¤ô²y¦^ÅU " COLOR2 " (d)§R°£ (D)°Ï¬q§R°£ (m)±H«H (w)¤ô²y (^R)¦^°T (^Q)¬d¸ß (s)§ó·s " + +#define FEETER_MF \ +COLOR1 " ³Ì·R¬ÝªO " COLOR2 " (^P)·s¼W (Cg)½Æ»s (p^V)¶K¤W (d)§R°£ (c)·s¤å³¹ (vV)¼Ð°O¤wŪ/¥¼Åª " + +#define FEETER_COSIGN \ +COLOR1 " ³s¸p¤p¯¸ " COLOR2 " (r)Ū¨ú (y)¦^À³ (^P)µoªí (d)§R°£ (o)¶}ªO (c)Ãö³¬ (E)½s¿è (B)³]©w " + +#define FEETER_SONG \ +COLOR1 " ÂIºq¨t²Î " COLOR2 " (r)Ū¨ú (o)ÂIºq¨ì¬ÝªO (m)ÂIºq¨ì«H½c (E)½s¿èÀÉ®× (T)½s¿è¼ÐÃD " + +#define FEETER_NEWS \ +COLOR1 " ·s»DÂI¿ï " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)¿ï¨ú (¡ö)(q)Â÷¶} " + +#define FEETER_XPOST \ +COLOR1 " ¦ê¦C·j´M " COLOR2 " (y)¦^À³ (x)Âà¿ý (m)¼Ð°O (d)§R°£ (^P)µoªí (^Q)¬d¸ß§@ªÌ (t)¼ÐÅÒ " + +#define FEETER_MBOX \ +COLOR1 " «H«H¬Û±¤ " COLOR2 " (y)¦^«H (F/X/x)Âà±H/Âà¹F/Âà¿ý (d)§R°£ (D)°Ï¬q§R°£ (m)¼Ð°O (E)½s¿è " + +#define FEETER_POST \ +COLOR1 " ¤å³¹¦Cªí " COLOR2 " (ry)¦^«H (S/a)·j´M/¼ÐÃD/§@ªÌ (~G)¦ê¦C·j´M (x)Âà¿ý (V)§ë²¼ (u)·s»D " + +#define FEETER_GEM \ +COLOR1 " ¬ÝªOºëµØ " COLOR2 " (^P/a/f)·s¼W/¤å³¹/¥Ø¿ý (E)½s¿è (T)¼ÐÃD (m)²¾°Ê (c)½Æ»s (p^V)¶K¤W " + +#define FEETER_VOTEALL \ +COLOR1 " §ë²¼¤¤¤ß " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷)§ë²¼ (¡ö)(q)Â÷¶} " + +#define FEETER_HELP \ +COLOR1 " »¡©ú¤å¥ó " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)ÂsÄý (¡ö)(q)Â÷¶} " + +#define FEETER_INNBBS \ +COLOR1 " Âà«H³]©w " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡ö)(q)Â÷¶} " + + +/* ----------------------------------------------------- */ +/* ¯¸¥x¨Ó·½Ã±¦W */ +/* ----------------------------------------------------- */ + +/* itoc: «ØÄ³ banner ¤£n¶W¹L¤T¦æ¡A¹Lªøªº¯¸Ã±¥i¯à·|³y¦¨¬Y¨Ç¨Ï¥ÎªÌªº¤Ï·P */ + +#define EDIT_BANNER "\n--\n" \ + " \033[1;42m Site \033[40;31m "SCHOOLNAME"£»"BBSNAME" \033[37m¡i"MYHOSTNAME"¡j\033[m\n" \ + " \033[1;44m From \033[40;33m %.0s%s\033[m\n" + +#define MODIFY_BANNER " \033[1;46m Edit \033[40;35m %.0s%s\033[m\n" + + +/* ----------------------------------------------------- */ +/* ¨ä¥L°T®§¦r¦ê */ +/* ----------------------------------------------------- */ + +#define VMSG_NULL " \033[1;34;44m¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e\033[37;40m ½Ð«ö \033[33m¥ô·NÁä \033[37mÄ~Äò \033[34;44m¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e\033[m" + +#define ICON_UNREAD_BRD "\033[33m£¾" /* ¥¼Åª¬ÝªO */ +#define ICON_READ_BRD " " /* ¤wŪ¬ÝªO */ + +#define ICON_GAMBLED_BRD "\033[1;31m½ä\033[m" /* Á|¦æ½ä½L¤¤ªº¬ÝªO */ +#define ICON_VOTED_BRD "\033[1;33m§ë\033[m" /* Á|¦æ§ë²¼¤¤ªº¬ÝªO */ +#define ICON_NOTRAN_BRD "¡¼" /* ¤£Âà«HªO */ +#define ICON_TRAN_BRD "¡½" /* Âà«HªO */ + +#define TOKEN_ZAP_BRD '-' /* zap ªO */ +#define TOKEN_FRIEND_BRD '.' /* ¦n¤ÍªO */ +#define TOKEN_SECRET_BRD ')' /* ¯µ±KªO */ + +#endif /* _THEME_H_ */ diff --git a/include/theme/theme_purple.h b/include/theme/theme_purple.h new file mode 100644 index 0000000..dc496f8 --- /dev/null +++ b/include/theme/theme_purple.h @@ -0,0 +1,246 @@ +/*-------------------------------------------------------*/ +/* theme.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : custom theme */ +/* create : 02/08/17 */ +/* update : / / */ +/*-------------------------------------------------------*/ + + +#ifndef _THEME_H_ +#define _THEME_H_ + + +/* ----------------------------------------------------- */ +/* °ò¥»ÃC¦â©w¸q¡A¥H§Q¤¶±×§ï */ +/* ----------------------------------------------------- */ + +#define COLOR1 "\033[1;32;45m" /* footer/feeter ªº«e¬qÃC¦â */ +#define COLOR2 "\033[0;35;47m" /* footer/feeter ªº«á¬qÃC¦â */ +#define COLOR3 "\033[37;45m" /* neck ªºÃC¦â */ +#define COLOR4 "\033[1;45m" /* ¥ú´Î ªºÃC¦â */ +#define COLOR5 "\033[1;36;43m" /* more ÀÉÀYªº¼ÐÃDÃC¦â */ +#define COLOR6 "\033[33;45m" /* more ÀÉÀYªº¤º®eÃC¦â */ +#define COLOR7 "\033[1;35m" /* §@ªÌ¦b½u¤WªºÃC¦â */ + + +/* ----------------------------------------------------- */ +/* ¨Ï¥ÎªÌ¦W³æÃC¦â */ +/* ----------------------------------------------------- */ + +#define COLOR_NORMAL "" /* ¤@¯ë¨Ï¥ÎªÌ */ +#define COLOR_MYBAD "\033[1;31m" /* Ãa¤H */ +#define COLOR_MYGOOD "\033[1;32m" /* §Úªº¦n¤Í */ +#define COLOR_OGOOD "\033[1;33m" /* »P§Ú¬°¤Í */ +#define COLOR_CLOAK "\033[1;35m" /* Áô§Î */ /* itoc.µù¸Ñ: ¨S¥Î¨ì¡Anªº¤H½Ð¦Û¦æ¥[¤J ulist_body() */ +#define COLOR_SELF "\033[1;36m" /* ¦Û¤v */ +#define COLOR_BOTHGOOD "\033[1;37m" /* ¤¬³]¦n¤Í */ +#define COLOR_BRDMATE "\033[36m" /* ªO¦ñ */ + + +/* ----------------------------------------------------- */ +/* ¿ï³æ¦ì¸m */ +/* ----------------------------------------------------- */ + +/* itoc.µù¸Ñ: ª`·N MENU_XPOS n >= MENU_XNOTE + MOVIE_LINES */ + +#define MENU_XNOTE 2 /* °ÊºA¬ÝªO¥Ñ (2, 0) ¶}©l */ +#define MOVIE_LINES 10 /* °Êµe³Ì¦h¦³ 10 ¦C */ + +#define MENU_XPOS 13 /* ¿ï³æ¶}©lªº (x, y) ®y¼Ð */ +#define MENU_YPOS ((d_cols >> 1) + 18) + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡G*_neck() ®Éªº necker ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* necker ªº¦æ¼Æ³£¬O¤G¦æ¡A±q (1, 0) ¨ì (2, 80) */ + +/* ©Ò¦³ªº XZ_* ³£¦³ necker¡A¥u¬O¦³¨Ç¦b *_neck()¡A¦³¨ÇÂæb *_head() */ + +/* ulist_neck() ¤Î xpost_head() ªº²Ä¤@¦æ¤ñ¸û¯S§O¡A¤£¦b¦¹©w¸q */ + +#define NECKER_CLASS "[¡ö]¥D¿ï³æ [¡÷]¾\\Ū [¡ô¡õ]¿ï¾Ü [c]½g¼Æ [y]¸ü¤J [/?]·j´M [s]¬ÝªO [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_ULIST "\n" \ + COLOR3 " ½s¸¹ ¥N¸¹ ¼ÊºÙ%*s %-*s °ÊºA ¶¢¸m \033[m" + +#define NECKER_PAL "[¡ö]Â÷¶} [a]·s¼W [c]×§ï [d]§R°£ [m]±H«H [w]¤ô²y [s]¾ã²z [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤Í ½Ë%*s \033[m" + +#define NECKER_ALOHA "[¡ö]Â÷¶} [a]·s¼W [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [w]¤ô²y [s]«¾ã [f]¤Þ¤J [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤W ¯¸ ³q ª¾ ¦W ³æ%*s \033[m" + +#define NECKER_VOTE "[¡ö]Â÷¶} [R]µ²ªG [^P]Á|¦æ [E]×§ï [V]¹wÄý [^Q]§ï´Á [o]¦W³æ [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¶}²¼¤é ¥D¿ì¤H §ë ²¼ ©v ¦®%*s \033[m" + +#define NECKER_BMW "[¡ö]Â÷¶} [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [M]Àx¦s [w]¤ô²y [s]§ó·s [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤º ®e%*s ®É¶¡ \033[m" + +#define NECKER_MF "[¡ö]Â÷¶} [¡÷]¶i¤J [^P]·s¼W [d]§R°£ [c]¤Á´« [C]½Æ»s [^V]¶K¤W [m]²¾°Ê [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_COSIGN "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]¥Ó½Ð [d]§R°£ [o]¶}ªO [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á Á|¿ì¤H ¬Ý ªO ¼Ð ÃD%*s \033[m" + +#define NECKER_SONG "[¡ö]Â÷¶} [¡÷]ÂsÄý [o]ÂIºq¨ì¬ÝªO [m]ÂIºq¨ì«H½c [Enter]ÂsÄý [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +#define NECKER_NEWS "[¡ö]Â÷¶} [¡÷]¾\\Ū [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ·s »D ¼Ð ÃD%*s \033[m" + +#define NECKER_XPOST "\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s \033[m" + +#define NECKER_MBOX "[¡ö]Â÷¶} [¡÷,r]Ū«H [d]§R°£ [R,y](¸s²Õ)¦^«H [s]±H«H [x]Âà¿ý [X]Âà¹F [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ «H ¥ó ¼Ð ÃD%*s \033[m" + +#define NECKER_POST "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]µoªí [b]¶iªOµe± [d]§R°£ [V]§ë²¼ [TAB]ºëµØ°Ï [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s ¤H®ð:%-4d \033[m" + +#define NECKER_GEM "[¡ö]Â÷¶} [¡÷]ÂsÄý [B]¼Ò¦¡ [C]¼È¦s [F]Âà±H [d]§R°£ [h]»¡©ú %s\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +/* ¥H¤U³o¨Ç«h¬O¤@¨ÇÃþ XZ_* µ²ºcªº necker */ + +#define NECKER_VOTEALL "[¡ô/¡õ]¤W¤U [PgUp/PgDn]¤W¤U¶ [Home/End]º§À [¡÷]§ë²¼ [¡ö][q]Â÷¶}\n" \ + COLOR3 " ½s¸¹ ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ªO ¥D%*s \033[m" + +#define NECKER_CREDIT "[¡ö]Â÷¶} [C]´«¶ [1]·s¼W [2]§R°£ [3]¥þ§R [4]Á`p\n" \ + COLOR3 " ½s¸¹ ¤é ´Á ¦¬¤ä ª÷ ÃB ¤ÀÃþ »¡ ©ú%*s \033[m" + +#define NECKER_HELP "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]·s¼W [d]§R°£ [T]¼ÐÃD [E]½s¿è [m]²¾°Ê\n" \ + COLOR3 " ½s¸¹ ÀÉ ®× ¼Ð ÃD%*s \033[m" + +#define NECKER_INNBBS "[¡ö]Â÷¶} [^P]·s¼W [d]§R°£ [E]½s¿è [/]·j´M [Enter]¸Ô²Ó\n" \ + COLOR3 " ½s¸¹ ¤º ®e%*s \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gmore() ®Éªº footer ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* itoc.010914.µù¸Ñ: ³æ¤@½g¡A©Ò¥H¥s FOOTER¡A³£¬O 78 char */ + +/* itoc.010821: ª`·N \\ ¬O \¡A³Ì«á§Oº|¤F¤@ӪťÕÁä :p */ + +#define FOOTER_POST \ +COLOR1 " ¤å³¹¿ïŪ " COLOR2 " (ry)¦^À³ (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (C)¼È¦s " + +#define FOOTER_MAILER \ +COLOR1 " ³½¶©¹ªð " COLOR2 " (ry)¦^«H/¸s²Õ (X)Âà¹F (d)§R°£ (m)¼Ð°O (C)¼È¦s (=\\[]<>-+;'`|?QAkj) " + +#define FOOTER_GEM \ +COLOR1 " ºëµØ¿ïŪ " COLOR2 " (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} " + +#ifdef HAVE_GAME +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^O)¹ï«³¼Ò¦¡ (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í " +#else +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í (^Y)²M°£ " +#endif + +#define FOOTER_COSIGN \ +COLOR1 " ³s¸p¾÷¨î " COLOR2 " (ry)¥[¤J³s¸p (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} (h)»¡©ú " + +#define FOOTER_MORE \ +COLOR1 " ÂsÄý P.%d (%d%%) " COLOR2 " (h)»¡©ú [PgUp][PgDn][0][$]²¾°Ê (/n)·j´M (C)¼È¦s (¡öq)µ²§ô " + +#define FOOTER_VEDIT \ +COLOR1 " %s " COLOR2 " (^Z)»¡©ú (^W)²Å¸¹ (^L)«Ã¸ (^X)Àɮ׳B²z ùø%s¢x%sùø%5d:%3d \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gxo_foot() ®Éªº feeter ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + + +/* itoc.010914.µù¸Ñ: ¦Cªí¦h½g¡A©Ò¥H¥s FEETER¡A³£¬O 78 char */ + +#define FEETER_CLASS \ +COLOR1 " ¬ÝªO¿ï¾Ü " COLOR2 " (c)·s¤å³¹ (vV)¼Ð°O¤wŪ¥¼Åª (y)¥þ³¡¦C¥X (z)¿ïq (A)¥þ°ì·j´M (S)±Æ§Ç " + +#define FEETER_ULIST \ +COLOR1 " ºô¤Í¦Cªí " COLOR2 " (f)¦n¤Í (t)²á¤Ñ (q)¬d¸ß (ad)¥æ¤Í (m)±H«H (w)¤ô²y (s)§ó·s (TAB)¤Á´« " + +#define FEETER_PAL \ +COLOR1 " ©IªB¤Þ¦ñ " COLOR2 " (a)·s¼W (d)§R°£ (c)¤Í½Ë (m)±H«H (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_ALOHA \ +COLOR1 " ¤W¯¸³qª¾ " COLOR2 " (a)·s¼W (d)§R°£ (D)°Ï¬q§R°£ (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_VOTE \ +COLOR1 " ¬ÝªO§ë²¼ " COLOR2 " (¡÷/r/v)§ë²¼ (R)µ²ªG (^P)·s¼W§ë²¼ (E)×§ï (V)¹wÄý (b)¶}²¼ (o)¦W³æ " + +#define FEETER_BMW \ +COLOR1 " ¤ô²y¦^ÅU " COLOR2 " (d)§R°£ (D)°Ï¬q§R°£ (m)±H«H (w)¤ô²y (^R)¦^°T (^Q)¬d¸ß (s)§ó·s " + +#define FEETER_MF \ +COLOR1 " ³Ì·R¬ÝªO " COLOR2 " (^P)·s¼W (Cg)½Æ»s (p^V)¶K¤W (d)§R°£ (c)·s¤å³¹ (vV)¼Ð°O¤wŪ/¥¼Åª " + +#define FEETER_COSIGN \ +COLOR1 " ³s¸p¤p¯¸ " COLOR2 " (r)Ū¨ú (y)¦^À³ (^P)µoªí (d)§R°£ (o)¶}ªO (c)Ãö³¬ (E)½s¿è (B)³]©w " + +#define FEETER_SONG \ +COLOR1 " ÂIºq¨t²Î " COLOR2 " (r)Ū¨ú (o)ÂIºq¨ì¬ÝªO (m)ÂIºq¨ì«H½c (E)½s¿èÀÉ®× (T)½s¿è¼ÐÃD " + +#define FEETER_NEWS \ +COLOR1 " ·s»DÂI¿ï " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)¿ï¨ú (¡ö)(q)Â÷¶} " + +#define FEETER_XPOST \ +COLOR1 " ¦ê¦C·j´M " COLOR2 " (y)¦^À³ (x)Âà¿ý (m)¼Ð°O (d)§R°£ (^P)µoªí (^Q)¬d¸ß§@ªÌ (t)¼ÐÅÒ " + +#define FEETER_MBOX \ +COLOR1 " «H«H¬Û±¤ " COLOR2 " (y)¦^«H (F/X/x)Âà±H/Âà¹F/Âà¿ý (d)§R°£ (D)°Ï¬q§R°£ (m)¼Ð°O (E)½s¿è " + +#define FEETER_POST \ +COLOR1 " ¤å³¹¦Cªí " COLOR2 " (ry)¦^«H (S/a)·j´M/¼ÐÃD/§@ªÌ (~G)¦ê¦C·j´M (x)Âà¿ý (V)§ë²¼ (u)·s»D " + +#define FEETER_GEM \ +COLOR1 " ¬ÝªOºëµØ " COLOR2 " (^P/a/f)·s¼W/¤å³¹/¥Ø¿ý (E)½s¿è (T)¼ÐÃD (m)²¾°Ê (c)½Æ»s (p^V)¶K¤W " + +#define FEETER_VOTEALL \ +COLOR1 " §ë²¼¤¤¤ß " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷)§ë²¼ (¡ö)(q)Â÷¶} " + +#define FEETER_HELP \ +COLOR1 " »¡©ú¤å¥ó " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)ÂsÄý (¡ö)(q)Â÷¶} " + +#define FEETER_INNBBS \ +COLOR1 " Âà«H³]©w " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡ö)(q)Â÷¶} " + + +/* ----------------------------------------------------- */ +/* ¯¸¥x¨Ó·½Ã±¦W */ +/* ----------------------------------------------------- */ + +/* itoc: «ØÄ³ banner ¤£n¶W¹L¤T¦æ¡A¹Lªøªº¯¸Ã±¥i¯à·|³y¦¨¬Y¨Ç¨Ï¥ÎªÌªº¤Ï·P */ + +#define EDIT_BANNER "\n--\n" \ + " \033[1;45mùæ\033[42mùè\033[m O\033[1mri\033[30mgi\033[mn: \033[1;45m "SCHOOLNAME"£»"BBSNAME" \033[43m "MYHOSTNAME" \033[m\n" \ + " \033[1;46mùî\033[43m¢|\033[m Au\033[1mt\033[30mho\033[mr: \033[1;35m%s\033[m ±q \033[1;32m%s\033[m µoªí\n" + +#define MODIFY_BANNER " \033[1;41m¢~\033[44m¢¡\033[m \033[1mMo\033[30mdi\033[mfy: %s ©ó \033[1;35m%s\033[m ×§ï\n" + + +/* ----------------------------------------------------- */ +/* ¨ä¥L°T®§¦r¦ê */ +/* ----------------------------------------------------- */ + +#define VMSG_NULL " \033[1;35m ¢j¢k¢l¢m¢n¢o¢p ½Ð«ö¥ô·NÁäÄ~Äò ¢p\033[m" + +#define ICON_UNREAD_BRD "\033[1;35m¡é" /* ¥¼Åª¬ÝªO */ +#define ICON_READ_BRD " " /* ¤wŪ¬ÝªO */ + +#define ICON_GAMBLED_BRD "\033[1;31m½ä\033[m" /* Á|¦æ½ä½L¤¤ªº¬ÝªO */ +#define ICON_VOTED_BRD "\033[1;33m§ë\033[m" /* Á|¦æ§ë²¼¤¤ªº¬ÝªO */ +#define ICON_NOTRAN_BRD "¡Ñ" /* ¤£Âà«HªO */ +#define ICON_TRAN_BRD "¡ò" /* Âà«HªO */ + +#define TOKEN_ZAP_BRD '-' /* zap ªO */ +#define TOKEN_FRIEND_BRD ']' /* ¦n¤ÍªO */ +#define TOKEN_SECRET_BRD '}' /* ¯µ±KªO */ + +#endif /* _THEME_H_ */ diff --git a/include/theme/theme_red.h b/include/theme/theme_red.h new file mode 100644 index 0000000..8a91b40 --- /dev/null +++ b/include/theme/theme_red.h @@ -0,0 +1,246 @@ +/*-------------------------------------------------------*/ +/* theme.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : custom theme */ +/* create : 02/08/17 */ +/* update : / / */ +/*-------------------------------------------------------*/ + + +#ifndef _THEME_H_ +#define _THEME_H_ + + +/* ----------------------------------------------------- */ +/* °ò¥»ÃC¦â©w¸q¡A¥H§Q¤¶±×§ï */ +/* ----------------------------------------------------- */ + +#define COLOR1 "\033[1;37;41m" /* footer/feeter ªº«e¬qÃC¦â */ +#define COLOR2 "\033[34;47m" /* footer/feeter ªº«á¬qÃC¦â */ +#define COLOR3 "\033[31;47m" /* neck ªºÃC¦â */ +#define COLOR4 "\033[1;41m" /* ¥ú´Î ªºÃC¦â */ +#define COLOR5 "\033[31;47m" /* more ÀÉÀYªº¼ÐÃDÃC¦â */ +#define COLOR6 "\033[37;41m" /* more ÀÉÀYªº¤º®eÃC¦â */ +#define COLOR7 "\033[1;34m" /* §@ªÌ¦b½u¤WªºÃC¦â */ + + +/* ----------------------------------------------------- */ +/* ¨Ï¥ÎªÌ¦W³æÃC¦â */ +/* ----------------------------------------------------- */ + +#define COLOR_NORMAL "" /* ¤@¯ë¨Ï¥ÎªÌ */ +#define COLOR_MYBAD "\033[1;31m" /* Ãa¤H */ +#define COLOR_MYGOOD "\033[1;32m" /* §Úªº¦n¤Í */ +#define COLOR_OGOOD "\033[1;33m" /* »P§Ú¬°¤Í */ +#define COLOR_CLOAK "\033[1;35m" /* Áô§Î */ /* itoc.µù¸Ñ: ¨S¥Î¨ì¡Anªº¤H½Ð¦Û¦æ¥[¤J ulist_body() */ +#define COLOR_SELF "\033[1;36m" /* ¦Û¤v */ +#define COLOR_BOTHGOOD "\033[1;37m" /* ¤¬³]¦n¤Í */ +#define COLOR_BRDMATE "\033[36m" /* ªO¦ñ */ + + +/* ----------------------------------------------------- */ +/* ¿ï³æ¦ì¸m */ +/* ----------------------------------------------------- */ + +/* itoc.µù¸Ñ: ª`·N MENU_XPOS n >= MENU_XNOTE + MOVIE_LINES */ + +#define MENU_XNOTE 2 /* °ÊºA¬ÝªO¥Ñ (2, 0) ¶}©l */ +#define MOVIE_LINES 10 /* °Êµe³Ì¦h¦³ 10 ¦C */ + +#define MENU_XPOS 13 /* ¿ï³æ¶}©lªº (x, y) ®y¼Ð */ +#define MENU_YPOS ((d_cols >> 1) + 18) + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡G*_neck() ®Éªº necker ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* necker ªº¦æ¼Æ³£¬O¤G¦æ¡A±q (1, 0) ¨ì (2, 80) */ + +/* ©Ò¦³ªº XZ_* ³£¦³ necker¡A¥u¬O¦³¨Ç¦b *_neck()¡A¦³¨ÇÂæb *_head() */ + +/* ulist_neck() ¤Î xpost_head() ªº²Ä¤@¦æ¤ñ¸û¯S§O¡A¤£¦b¦¹©w¸q */ + +#define NECKER_CLASS "[¡ö]¥D¿ï³æ [¡÷]¾\\Ū [¡ô¡õ]¿ï¾Ü [c]½g¼Æ [y]¸ü¤J [/?]·j´M [s]¬ÝªO [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_ULIST "\n" \ + COLOR3 " ½s¸¹ ¥N¸¹ ¼ÊºÙ%*s %-*s °ÊºA ¶¢¸m \033[m" + +#define NECKER_PAL "[¡ö]Â÷¶} [a]·s¼W [c]×§ï [d]§R°£ [m]±H«H [w]¤ô²y [s]¾ã²z [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤Í ½Ë%*s \033[m" + +#define NECKER_ALOHA "[¡ö]Â÷¶} [a]·s¼W [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [w]¤ô²y [s]«¾ã [f]¤Þ¤J [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤W ¯¸ ³q ª¾ ¦W ³æ%*s \033[m" + +#define NECKER_VOTE "[¡ö]Â÷¶} [R]µ²ªG [^P]Á|¦æ [E]×§ï [V]¹wÄý [^Q]§ï´Á [o]¦W³æ [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¶}²¼¤é ¥D¿ì¤H §ë ²¼ ©v ¦®%*s \033[m" + +#define NECKER_BMW "[¡ö]Â÷¶} [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [M]Àx¦s [w]¤ô²y [s]§ó·s [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤º ®e%*s ®É¶¡ \033[m" + +#define NECKER_MF "[¡ö]Â÷¶} [¡÷]¶i¤J [^P]·s¼W [d]§R°£ [c]¤Á´« [C]½Æ»s [^V]¶K¤W [m]²¾°Ê [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_COSIGN "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]¥Ó½Ð [d]§R°£ [o]¶}ªO [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á Á|¿ì¤H ¬Ý ªO ¼Ð ÃD%*s \033[m" + +#define NECKER_SONG "[¡ö]Â÷¶} [¡÷]ÂsÄý [o]ÂIºq¨ì¬ÝªO [m]ÂIºq¨ì«H½c [Enter]ÂsÄý [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +#define NECKER_NEWS "[¡ö]Â÷¶} [¡÷]¾\\Ū [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ·s »D ¼Ð ÃD%*s \033[m" + +#define NECKER_XPOST "\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s \033[m" + +#define NECKER_MBOX "[¡ö]Â÷¶} [¡÷,r]Ū«H [d]§R°£ [R,y](¸s²Õ)¦^«H [s]±H«H [x]Âà¿ý [X]Âà¹F [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ «H ¥ó ¼Ð ÃD%*s \033[m" + +#define NECKER_POST "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]µoªí [b]¶iªOµe± [d]§R°£ [V]§ë²¼ [TAB]ºëµØ°Ï [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s ¤H®ð:%-4d \033[m" + +#define NECKER_GEM "[¡ö]Â÷¶} [¡÷]ÂsÄý [B]¼Ò¦¡ [C]¼È¦s [F]Âà±H [d]§R°£ [h]»¡©ú %s\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +/* ¥H¤U³o¨Ç«h¬O¤@¨ÇÃþ XZ_* µ²ºcªº necker */ + +#define NECKER_VOTEALL "[¡ô/¡õ]¤W¤U [PgUp/PgDn]¤W¤U¶ [Home/End]º§À [¡÷]§ë²¼ [¡ö][q]Â÷¶}\n" \ + COLOR3 " ½s¸¹ ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ªO ¥D%*s \033[m" + +#define NECKER_CREDIT "[¡ö]Â÷¶} [C]´«¶ [1]·s¼W [2]§R°£ [3]¥þ§R [4]Á`p\n" \ + COLOR3 " ½s¸¹ ¤é ´Á ¦¬¤ä ª÷ ÃB ¤ÀÃþ »¡ ©ú%*s \033[m" + +#define NECKER_HELP "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]·s¼W [d]§R°£ [T]¼ÐÃD [E]½s¿è [m]²¾°Ê\n" \ + COLOR3 " ½s¸¹ ÀÉ ®× ¼Ð ÃD%*s \033[m" + +#define NECKER_INNBBS "[¡ö]Â÷¶} [^P]·s¼W [d]§R°£ [E]½s¿è [/]·j´M [Enter]¸Ô²Ó\n" \ + COLOR3 " ½s¸¹ ¤º ®e%*s \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gmore() ®Éªº footer ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* itoc.010914.µù¸Ñ: ³æ¤@½g¡A©Ò¥H¥s FOOTER¡A³£¬O 78 char */ + +/* itoc.010821: ª`·N \\ ¬O \¡A³Ì«á§Oº|¤F¤@ӪťÕÁä :p */ + +#define FOOTER_POST \ +COLOR1 " ¤å³¹¿ïŪ " COLOR2 " (ry)¦^À³ (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (C)¼È¦s " + +#define FOOTER_MAILER \ +COLOR1 " ³½¶©¹ªð " COLOR2 " (ry)¦^«H/¸s²Õ (X)Âà¹F (d)§R°£ (m)¼Ð°O (C)¼È¦s (=\\[]<>-+;'`|?QAkj) " + +#define FOOTER_GEM \ +COLOR1 " ºëµØ¿ïŪ " COLOR2 " (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} " + +#ifdef HAVE_GAME +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^O)¹ï«³¼Ò¦¡ (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í " +#else +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í (^Y)²M°£ " +#endif + +#define FOOTER_COSIGN \ +COLOR1 " ³s¸p¾÷¨î " COLOR2 " (ry)¥[¤J³s¸p (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} (h)»¡©ú " + +#define FOOTER_MORE \ +COLOR1 " ÂsÄý P.%d (%d%%) " COLOR2 " (h)»¡©ú [PgUp][PgDn][0][$]²¾°Ê (/n)·j´M (C)¼È¦s (¡öq)µ²§ô " + +#define FOOTER_VEDIT \ +COLOR1 " %s " COLOR2 " (^Z)»¡©ú (^W)²Å¸¹ (^L)«Ã¸ (^X)Àɮ׳B²z ùø%s¢x%sùø%5d:%3d \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gxo_foot() ®Éªº feeter ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + + +/* itoc.010914.µù¸Ñ: ¦Cªí¦h½g¡A©Ò¥H¥s FEETER¡A³£¬O 78 char */ + +#define FEETER_CLASS \ +COLOR1 " ¬ÝªO¿ï¾Ü " COLOR2 " (c)·s¤å³¹ (vV)¼Ð°O¤wŪ¥¼Åª (y)¥þ³¡¦C¥X (z)¿ïq (A)¥þ°ì·j´M (S)±Æ§Ç " + +#define FEETER_ULIST \ +COLOR1 " ºô¤Í¦Cªí " COLOR2 " (f)¦n¤Í (t)²á¤Ñ (q)¬d¸ß (ad)¥æ¤Í (m)±H«H (w)¤ô²y (s)§ó·s (TAB)¤Á´« " + +#define FEETER_PAL \ +COLOR1 " ©IªB¤Þ¦ñ " COLOR2 " (a)·s¼W (d)§R°£ (c)¤Í½Ë (m)±H«H (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_ALOHA \ +COLOR1 " ¤W¯¸³qª¾ " COLOR2 " (a)·s¼W (d)§R°£ (D)°Ï¬q§R°£ (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_VOTE \ +COLOR1 " ¬ÝªO§ë²¼ " COLOR2 " (¡÷/r/v)§ë²¼ (R)µ²ªG (^P)·s¼W§ë²¼ (E)×§ï (V)¹wÄý (b)¶}²¼ (o)¦W³æ " + +#define FEETER_BMW \ +COLOR1 " ¤ô²y¦^ÅU " COLOR2 " (d)§R°£ (D)°Ï¬q§R°£ (m)±H«H (w)¤ô²y (^R)¦^°T (^Q)¬d¸ß (s)§ó·s " + +#define FEETER_MF \ +COLOR1 " ³Ì·R¬ÝªO " COLOR2 " (^P)·s¼W (Cg)½Æ»s (p^V)¶K¤W (d)§R°£ (c)·s¤å³¹ (vV)¼Ð°O¤wŪ/¥¼Åª " + +#define FEETER_COSIGN \ +COLOR1 " ³s¸p¤p¯¸ " COLOR2 " (r)Ū¨ú (y)¦^À³ (^P)µoªí (d)§R°£ (o)¶}ªO (c)Ãö³¬ (E)½s¿è (B)³]©w " + +#define FEETER_SONG \ +COLOR1 " ÂIºq¨t²Î " COLOR2 " (r)Ū¨ú (o)ÂIºq¨ì¬ÝªO (m)ÂIºq¨ì«H½c (E)½s¿èÀÉ®× (T)½s¿è¼ÐÃD " + +#define FEETER_NEWS \ +COLOR1 " ·s»DÂI¿ï " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)¿ï¨ú (¡ö)(q)Â÷¶} " + +#define FEETER_XPOST \ +COLOR1 " ¦ê¦C·j´M " COLOR2 " (y)¦^À³ (x)Âà¿ý (m)¼Ð°O (d)§R°£ (^P)µoªí (^Q)¬d¸ß§@ªÌ (t)¼ÐÅÒ " + +#define FEETER_MBOX \ +COLOR1 " «H«H¬Û±¤ " COLOR2 " (y)¦^«H (F/X/x)Âà±H/Âà¹F/Âà¿ý (d)§R°£ (D)°Ï¬q§R°£ (m)¼Ð°O (E)½s¿è " + +#define FEETER_POST \ +COLOR1 " ¤å³¹¦Cªí " COLOR2 " (ry)¦^«H (S/a)·j´M/¼ÐÃD/§@ªÌ (~G)¦ê¦C·j´M (x)Âà¿ý (V)§ë²¼ (u)·s»D " + +#define FEETER_GEM \ +COLOR1 " ¬ÝªOºëµØ " COLOR2 " (^P/a/f)·s¼W/¤å³¹/¥Ø¿ý (E)½s¿è (T)¼ÐÃD (m)²¾°Ê (c)½Æ»s (p^V)¶K¤W " + +#define FEETER_VOTEALL \ +COLOR1 " §ë²¼¤¤¤ß " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷)§ë²¼ (¡ö)(q)Â÷¶} " + +#define FEETER_HELP \ +COLOR1 " »¡©ú¤å¥ó " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)ÂsÄý (¡ö)(q)Â÷¶} " + +#define FEETER_INNBBS \ +COLOR1 " Âà«H³]©w " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡ö)(q)Â÷¶} " + + +/* ----------------------------------------------------- */ +/* ¯¸¥x¨Ó·½Ã±¦W */ +/* ----------------------------------------------------- */ + +/* itoc: «ØÄ³ banner ¤£n¶W¹L¤T¦æ¡A¹Lªøªº¯¸Ã±¥i¯à·|³y¦¨¬Y¨Ç¨Ï¥ÎªÌªº¤Ï·P */ + +#define EDIT_BANNER "\n--\n" \ + " \033[1;42mùá\033[41mùå\033[m O\033[1mri\033[30mgi\033[mn: \033[1;41m "SCHOOLNAME"£»"BBSNAME" \033[42m "MYHOSTNAME" \033[m\n" \ + " \033[1;44mùö\033[43mùð\033[m Au\033[1mt\033[30mho\033[mr: \033[1;31m%s\033[m ±q \033[1;36m%s\033[m µoªí\n" + +#define MODIFY_BANNER " \033[1;46m¢s\033[45mùö\033[m \033[1mMo\033[30mdi\033[mfy: %s ©ó \033[1;31m%s\033[m ×§ï\n" + + +/* ----------------------------------------------------- */ +/* ¨ä¥L°T®§¦r¦ê */ +/* ----------------------------------------------------- */ + +#define VMSG_NULL " \033[1;31;44m ¡¹ ½Ð«ö¥ô·NÁäÄ~Äò ¡¹ \033[m" + +#define ICON_UNREAD_BRD "\033[1;31m¡Ô\033[m" /* ¥¼Åª¬ÝªO */ +#define ICON_READ_BRD " " /* ¤wŪ¬ÝªO */ + +#define ICON_GAMBLED_BRD "\033[1;31m½ä\033[m" /* Á|¦æ½ä½L¤¤ªº¬ÝªO */ +#define ICON_VOTED_BRD "\033[1;33m§ë\033[m" /* Á|¦æ§ë²¼¤¤ªº¬ÝªO */ +#define ICON_NOTRAN_BRD "¡ã" /* ¤£Âà«HªO */ +#define ICON_TRAN_BRD "¡Û" /* Âà«HªO */ + +#define TOKEN_ZAP_BRD '-' /* zap ªO */ +#define TOKEN_FRIEND_BRD 'P' /* ¦n¤ÍªO */ +#define TOKEN_SECRET_BRD 'X' /* ¯µ±KªO */ + +#endif /* _THEME_H_ */ diff --git a/include/theme/theme_wd.h b/include/theme/theme_wd.h new file mode 100644 index 0000000..b2d7db2 --- /dev/null +++ b/include/theme/theme_wd.h @@ -0,0 +1,246 @@ +/*-------------------------------------------------------*/ +/* theme.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : custom theme */ +/* create : 02/08/17 */ +/* update : / / */ +/*-------------------------------------------------------*/ + + +#ifndef _THEME_H_ +#define _THEME_H_ + + +/* ----------------------------------------------------- */ +/* °ò¥»ÃC¦â©w¸q¡A¥H§Q¤¶±×§ï */ +/* ----------------------------------------------------- */ + +#define COLOR1 "\033[1;33;44m" /* footer/feeter ªº«e¬qÃC¦â */ +#define COLOR2 "\033[37;46m" /* footer/feeter ªº«á¬qÃC¦â */ +#define COLOR3 "\033[1;46m" /* neck ªºÃC¦â */ +#define COLOR4 "\033[1;46m" /* ¥ú´Î ªºÃC¦â */ +#define COLOR5 "\033[1;33;46m" /* more ÀÉÀYªº¼ÐÃDÃC¦â */ +#define COLOR6 "\033[m" /* more ÀÉÀYªº¤º®eÃC¦â */ +#define COLOR7 "\033[36m" /* §@ªÌ¦b½u¤WªºÃC¦â */ + + +/* ----------------------------------------------------- */ +/* ¨Ï¥ÎªÌ¦W³æÃC¦â */ +/* ----------------------------------------------------- */ + +#define COLOR_NORMAL "" /* ¤@¯ë¨Ï¥ÎªÌ */ +#define COLOR_MYBAD "\033[1;31m" /* Ãa¤H */ +#define COLOR_MYGOOD "\033[1;32m" /* §Úªº¦n¤Í */ +#define COLOR_OGOOD "\033[1;33m" /* »P§Ú¬°¤Í */ +#define COLOR_CLOAK "\033[1;35m" /* Áô§Î */ /* itoc.µù¸Ñ: ¨S¥Î¨ì¡Anªº¤H½Ð¦Û¦æ¥[¤J ulist_body() */ +#define COLOR_SELF "\033[1;36m" /* ¦Û¤v */ +#define COLOR_BOTHGOOD "\033[1;37m" /* ¤¬³]¦n¤Í */ +#define COLOR_BRDMATE "\033[36m" /* ªO¦ñ */ + + +/* ----------------------------------------------------- */ +/* ¿ï³æ¦ì¸m */ +/* ----------------------------------------------------- */ + +/* itoc.µù¸Ñ: ª`·N MENU_XPOS n >= MENU_XNOTE + MOVIE_LINES */ + +#define MENU_XNOTE 12 /* °ÊºA¬ÝªO¥Ñ (12, 0) ¶}©l */ +#define MOVIE_LINES 11 /* °Êµe³Ì¦h¦³ 11 ¦C */ + +#define MENU_XPOS 1 /* ¿ï³æ¶}©lªº (x, y) ®y¼Ð */ +#define MENU_YPOS ((d_cols >> 1) + 4) + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡G*_neck() ®Éªº necker ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* necker ªº¦æ¼Æ³£¬O¤G¦æ¡A±q (1, 0) ¨ì (2, 80) */ + +/* ©Ò¦³ªº XZ_* ³£¦³ necker¡A¥u¬O¦³¨Ç¦b *_neck()¡A¦³¨ÇÂæb *_head() */ + +/* ulist_neck() ¤Î xpost_head() ªº²Ä¤@¦æ¤ñ¸û¯S§O¡A¤£¦b¦¹©w¸q */ + +#define NECKER_CLASS "[¡ö]¥D¿ï³æ [¡÷]¾\\Ū [¡ô¡õ]¿ï¾Ü [c]½g¼Æ [y]¸ü¤J [/?]·j´M [s]¬ÝªO [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_ULIST "\n" \ + COLOR3 " ½s¸¹ ¥N¸¹ ¼ÊºÙ%*s %-*s °ÊºA ¶¢¸m \033[m" + +#define NECKER_PAL "[¡ö]Â÷¶} [a]·s¼W [c]×§ï [d]§R°£ [m]±H«H [w]¤ô²y [s]¾ã²z [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤Í ½Ë%*s \033[m" + +#define NECKER_ALOHA "[¡ö]Â÷¶} [a]·s¼W [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [w]¤ô²y [s]«¾ã [f]¤Þ¤J [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤W ¯¸ ³q ª¾ ¦W ³æ%*s \033[m" + +#define NECKER_VOTE "[¡ö]Â÷¶} [R]µ²ªG [^P]Á|¦æ [E]×§ï [V]¹wÄý [^Q]§ï´Á [o]¦W³æ [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¶}²¼¤é ¥D¿ì¤H §ë ²¼ ©v ¦®%*s \033[m" + +#define NECKER_BMW "[¡ö]Â÷¶} [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [M]Àx¦s [w]¤ô²y [s]§ó·s [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤º ®e%*s ®É¶¡ \033[m" + +#define NECKER_MF "[¡ö]Â÷¶} [¡÷]¶i¤J [^P]·s¼W [d]§R°£ [c]¤Á´« [C]½Æ»s [^V]¶K¤W [m]²¾°Ê [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_COSIGN "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]¥Ó½Ð [d]§R°£ [o]¶}ªO [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á Á|¿ì¤H ¬Ý ªO ¼Ð ÃD%*s \033[m" + +#define NECKER_SONG "[¡ö]Â÷¶} [¡÷]ÂsÄý [o]ÂIºq¨ì¬ÝªO [m]ÂIºq¨ì«H½c [Enter]ÂsÄý [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +#define NECKER_NEWS "[¡ö]Â÷¶} [¡÷]¾\\Ū [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ·s »D ¼Ð ÃD%*s \033[m" + +#define NECKER_XPOST "\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s \033[m" + +#define NECKER_MBOX "[¡ö]Â÷¶} [¡÷,r]Ū«H [d]§R°£ [R,y](¸s²Õ)¦^«H [s]±H«H [x]Âà¿ý [X]Âà¹F [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ «H ¥ó ¼Ð ÃD%*s \033[m" + +#define NECKER_POST "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]µoªí [b]¶iªOµe± [d]§R°£ [V]§ë²¼ [TAB]ºëµØ°Ï [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s ¤H®ð:%-4d \033[m" + +#define NECKER_GEM "[¡ö]Â÷¶} [¡÷]ÂsÄý [B]¼Ò¦¡ [C]¼È¦s [F]Âà±H [d]§R°£ [h]»¡©ú %s\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +/* ¥H¤U³o¨Ç«h¬O¤@¨ÇÃþ XZ_* µ²ºcªº necker */ + +#define NECKER_VOTEALL "[¡ô/¡õ]¤W¤U [PgUp/PgDn]¤W¤U¶ [Home/End]º§À [¡÷]§ë²¼ [¡ö][q]Â÷¶}\n" \ + COLOR3 " ½s¸¹ ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ªO ¥D%*s \033[m" + +#define NECKER_CREDIT "[¡ö]Â÷¶} [C]´«¶ [1]·s¼W [2]§R°£ [3]¥þ§R [4]Á`p\n" \ + COLOR3 " ½s¸¹ ¤é ´Á ¦¬¤ä ª÷ ÃB ¤ÀÃþ »¡ ©ú%*s \033[m" + +#define NECKER_HELP "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]·s¼W [d]§R°£ [T]¼ÐÃD [E]½s¿è [m]²¾°Ê\n" \ + COLOR3 " ½s¸¹ ÀÉ ®× ¼Ð ÃD%*s \033[m" + +#define NECKER_INNBBS "[¡ö]Â÷¶} [^P]·s¼W [d]§R°£ [E]½s¿è [/]·j´M [Enter]¸Ô²Ó\n" \ + COLOR3 " ½s¸¹ ¤º ®e%*s \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gmore() ®Éªº footer ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* itoc.010914.µù¸Ñ: ³æ¤@½g¡A©Ò¥H¥s FOOTER¡A³£¬O 78 char */ + +/* itoc.010821: ª`·N \\ ¬O \¡A³Ì«á§Oº|¤F¤@ӪťÕÁä :p */ + +#define FOOTER_POST \ +COLOR1 " ¤å³¹¿ïŪ " COLOR2 " (ry)¦^À³ (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (C)¼È¦s " + +#define FOOTER_MAILER \ +COLOR1 " ³½¶©¹ªð " COLOR2 " (ry)¦^«H/¸s²Õ (X)Âà¹F (d)§R°£ (m)¼Ð°O (C)¼È¦s (=\\[]<>-+;'`|?QAkj) " + +#define FOOTER_GEM \ +COLOR1 " ºëµØ¿ïŪ " COLOR2 " (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} " + +#ifdef HAVE_GAME +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^O)¹ï«³¼Ò¦¡ (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í " +#else +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í (^Y)²M°£ " +#endif + +#define FOOTER_COSIGN \ +COLOR1 " ³s¸p¾÷¨î " COLOR2 " (ry)¥[¤J³s¸p (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} (h)»¡©ú " + +#define FOOTER_MORE \ +COLOR1 " ÂsÄý P.%d (%d%%) " COLOR2 " (h)»¡©ú [PgUp][PgDn][0][$]²¾°Ê (/n)·j´M (C)¼È¦s (¡öq)µ²§ô " + +#define FOOTER_VEDIT \ +COLOR1 " %s " COLOR2 " (^Z)»¡©ú (^W)²Å¸¹ (^L)«Ã¸ (^X)Àɮ׳B²z ùø%s¢x%sùø%5d:%3d \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gxo_foot() ®Éªº feeter ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + + +/* itoc.010914.µù¸Ñ: ¦Cªí¦h½g¡A©Ò¥H¥s FEETER¡A³£¬O 78 char */ + +#define FEETER_CLASS \ +COLOR1 " ¬ÝªO¿ï¾Ü " COLOR2 " (c)·s¤å³¹ (vV)¼Ð°O¤wŪ¥¼Åª (y)¥þ³¡¦C¥X (z)¿ïq (A)¥þ°ì·j´M (S)±Æ§Ç " + +#define FEETER_ULIST \ +COLOR1 " ºô¤Í¦Cªí " COLOR2 " (f)¦n¤Í (t)²á¤Ñ (q)¬d¸ß (ad)¥æ¤Í (m)±H«H (w)¤ô²y (s)§ó·s (TAB)¤Á´« " + +#define FEETER_PAL \ +COLOR1 " ©IªB¤Þ¦ñ " COLOR2 " (a)·s¼W (d)§R°£ (c)¤Í½Ë (m)±H«H (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_ALOHA \ +COLOR1 " ¤W¯¸³qª¾ " COLOR2 " (a)·s¼W (d)§R°£ (D)°Ï¬q§R°£ (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_VOTE \ +COLOR1 " ¬ÝªO§ë²¼ " COLOR2 " (¡÷/r/v)§ë²¼ (R)µ²ªG (^P)·s¼W§ë²¼ (E)×§ï (V)¹wÄý (b)¶}²¼ (o)¦W³æ " + +#define FEETER_BMW \ +COLOR1 " ¤ô²y¦^ÅU " COLOR2 " (d)§R°£ (D)°Ï¬q§R°£ (m)±H«H (w)¤ô²y (^R)¦^°T (^Q)¬d¸ß (s)§ó·s " + +#define FEETER_MF \ +COLOR1 " ³Ì·R¬ÝªO " COLOR2 " (^P)·s¼W (Cg)½Æ»s (p^V)¶K¤W (d)§R°£ (c)·s¤å³¹ (vV)¼Ð°O¤wŪ/¥¼Åª " + +#define FEETER_COSIGN \ +COLOR1 " ³s¸p¤p¯¸ " COLOR2 " (r)Ū¨ú (y)¦^À³ (^P)µoªí (d)§R°£ (o)¶}ªO (c)Ãö³¬ (E)½s¿è (B)³]©w " + +#define FEETER_SONG \ +COLOR1 " ÂIºq¨t²Î " COLOR2 " (r)Ū¨ú (o)ÂIºq¨ì¬ÝªO (m)ÂIºq¨ì«H½c (E)½s¿èÀÉ®× (T)½s¿è¼ÐÃD " + +#define FEETER_NEWS \ +COLOR1 " ·s»DÂI¿ï " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)¿ï¨ú (¡ö)(q)Â÷¶} " + +#define FEETER_XPOST \ +COLOR1 " ¦ê¦C·j´M " COLOR2 " (y)¦^À³ (x)Âà¿ý (m)¼Ð°O (d)§R°£ (^P)µoªí (^Q)¬d¸ß§@ªÌ (t)¼ÐÅÒ " + +#define FEETER_MBOX \ +COLOR1 " «H«H¬Û±¤ " COLOR2 " (y)¦^«H (F/X/x)Âà±H/Âà¹F/Âà¿ý (d)§R°£ (D)°Ï¬q§R°£ (m)¼Ð°O (E)½s¿è " + +#define FEETER_POST \ +COLOR1 " ¤å³¹¦Cªí " COLOR2 " (ry)¦^«H (S/a)·j´M/¼ÐÃD/§@ªÌ (~G)¦ê¦C·j´M (x)Âà¿ý (V)§ë²¼ (u)·s»D " + +#define FEETER_GEM \ +COLOR1 " ¬ÝªOºëµØ " COLOR2 " (^P/a/f)·s¼W/¤å³¹/¥Ø¿ý (E)½s¿è (T)¼ÐÃD (m)²¾°Ê (c)½Æ»s (p^V)¶K¤W " + +#define FEETER_VOTEALL \ +COLOR1 " §ë²¼¤¤¤ß " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷)§ë²¼ (¡ö)(q)Â÷¶} " + +#define FEETER_HELP \ +COLOR1 " »¡©ú¤å¥ó " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)ÂsÄý (¡ö)(q)Â÷¶} " + +#define FEETER_INNBBS \ +COLOR1 " Âà«H³]©w " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡ö)(q)Â÷¶} " + + +/* ----------------------------------------------------- */ +/* ¯¸¥x¨Ó·½Ã±¦W */ +/* ----------------------------------------------------- */ + +/* itoc: «ØÄ³ banner ¤£n¶W¹L¤T¦æ¡A¹Lªøªº¯¸Ã±¥i¯à·|³y¦¨¬Y¨Ç¨Ï¥ÎªÌªº¤Ï·P */ + +#define EDIT_BANNER "\n--\n" \ + "\033[36m¡° ¨Ó¦Û¡G"BBSNAME" ("MYHOSTNAME")\033[m\n" \ + "\033[1;31m¡À \033[36mPost by \033[37m%-12s \033[36mfrom \033[33m%s\033[m\n" + +#define MODIFY_BANNER "\033[1;31m¡À \033[36mEdit by \033[37m%-12s \033[36mat \033[33m%s\033[m\n" + + +/* ----------------------------------------------------- */ +/* ¨ä¥L°T®§¦r¦ê */ +/* ----------------------------------------------------- */ + +#define VMSG_NULL "\033[1;46m ¡¹ ½Ð«ö (Space/Return) Ä~Äò ¡¹ \033[m" + +#define ICON_UNREAD_BRD "\033[36m¡´" /* ¥¼Åª¬ÝªO */ +#define ICON_READ_BRD " " /* ¤wŪ¬ÝªO */ + +#define ICON_GAMBLED_BRD "\033[1;31m½ä\033[m" /* Á|¦æ½ä½L¤¤ªº¬ÝªO */ +#define ICON_VOTED_BRD "\033[1;33m§ë\033[m" /* Á|¦æ§ë²¼¤¤ªº¬ÝªO */ +#define ICON_NOTRAN_BRD "¡¸" /* ¤£Âà«HªO */ +#define ICON_TRAN_BRD "¡¹" /* Âà«HªO */ + +#define TOKEN_ZAP_BRD '-' /* zap ªO */ +#define TOKEN_FRIEND_BRD '-' /* ¦n¤ÍªO */ +#define TOKEN_SECRET_BRD ')' /* ¯µ±KªO */ + +#endif /* _THEME_H_ */ diff --git a/include/theme/theme_yellow.h b/include/theme/theme_yellow.h new file mode 100644 index 0000000..f0742cd --- /dev/null +++ b/include/theme/theme_yellow.h @@ -0,0 +1,246 @@ +/*-------------------------------------------------------*/ +/* theme.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : custom theme */ +/* create : 02/08/17 */ +/* update : / / */ +/*-------------------------------------------------------*/ + + +#ifndef _THEME_H_ +#define _THEME_H_ + + +/* ----------------------------------------------------- */ +/* °ò¥»ÃC¦â©w¸q¡A¥H§Q¤¶±×§ï */ +/* ----------------------------------------------------- */ + +#define COLOR1 "\033[1;33;45m" /* footer/feeter ªº«e¬qÃC¦â */ +#define COLOR2 "\033[0;30;43m" /* footer/feeter ªº«á¬qÃC¦â */ +#define COLOR3 "\033[1;33;41m" /* neck ªºÃC¦â */ +#define COLOR4 "\033[1;43m" /* ¥ú´Î ªºÃC¦â */ +#define COLOR5 "\033[1;33;46m" /* more ÀÉÀYªº¼ÐÃDÃC¦â */ +#define COLOR6 "\033[37;43m" /* more ÀÉÀYªº¤º®eÃC¦â */ +#define COLOR7 "\033[1;33m" /* §@ªÌ¦b½u¤WªºÃC¦â */ + + +/* ----------------------------------------------------- */ +/* ¨Ï¥ÎªÌ¦W³æÃC¦â */ +/* ----------------------------------------------------- */ + +#define COLOR_NORMAL "" /* ¤@¯ë¨Ï¥ÎªÌ */ +#define COLOR_MYBAD "\033[1;31m" /* Ãa¤H */ +#define COLOR_MYGOOD "\033[1;32m" /* §Úªº¦n¤Í */ +#define COLOR_OGOOD "\033[1;33m" /* »P§Ú¬°¤Í */ +#define COLOR_CLOAK "\033[1;35m" /* Áô§Î */ /* itoc.µù¸Ñ: ¨S¥Î¨ì¡Anªº¤H½Ð¦Û¦æ¥[¤J ulist_body() */ +#define COLOR_SELF "\033[1;36m" /* ¦Û¤v */ +#define COLOR_BOTHGOOD "\033[1;37m" /* ¤¬³]¦n¤Í */ +#define COLOR_BRDMATE "\033[36m" /* ªO¦ñ */ + + +/* ----------------------------------------------------- */ +/* ¿ï³æ¦ì¸m */ +/* ----------------------------------------------------- */ + +/* itoc.µù¸Ñ: ª`·N MENU_XPOS n >= MENU_XNOTE + MOVIE_LINES */ + +#define MENU_XNOTE 2 /* °ÊºA¬ÝªO¥Ñ (2, 0) ¶}©l */ +#define MOVIE_LINES 10 /* °Êµe³Ì¦h¦³ 10 ¦C */ + +#define MENU_XPOS 13 /* ¿ï³æ¶}©lªº (x, y) ®y¼Ð */ +#define MENU_YPOS ((d_cols >> 1) + 18) + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡G*_neck() ®Éªº necker ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* necker ªº¦æ¼Æ³£¬O¤G¦æ¡A±q (1, 0) ¨ì (2, 80) */ + +/* ©Ò¦³ªº XZ_* ³£¦³ necker¡A¥u¬O¦³¨Ç¦b *_neck()¡A¦³¨ÇÂæb *_head() */ + +/* ulist_neck() ¤Î xpost_head() ªº²Ä¤@¦æ¤ñ¸û¯S§O¡A¤£¦b¦¹©w¸q */ + +#define NECKER_CLASS "[¡ö]¥D¿ï³æ [¡÷]¾\\Ū [¡ô¡õ]¿ï¾Ü [c]½g¼Æ [y]¸ü¤J [/?]·j´M [s]¬ÝªO [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_ULIST "\n" \ + COLOR3 " ½s¸¹ ¥N¸¹ ¼ÊºÙ%*s %-*s °ÊºA ¶¢¸m \033[m" + +#define NECKER_PAL "[¡ö]Â÷¶} [a]·s¼W [c]×§ï [d]§R°£ [m]±H«H [w]¤ô²y [s]¾ã²z [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤Í ½Ë%*s \033[m" + +#define NECKER_ALOHA "[¡ö]Â÷¶} [a]·s¼W [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [w]¤ô²y [s]«¾ã [f]¤Þ¤J [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤W ¯¸ ³q ª¾ ¦W ³æ%*s \033[m" + +#define NECKER_VOTE "[¡ö]Â÷¶} [R]µ²ªG [^P]Á|¦æ [E]×§ï [V]¹wÄý [^Q]§ï´Á [o]¦W³æ [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¶}²¼¤é ¥D¿ì¤H §ë ²¼ ©v ¦®%*s \033[m" + +#define NECKER_BMW "[¡ö]Â÷¶} [d]§R°£ [D]°Ï¬q§R°£ [m]±H«H [M]Àx¦s [w]¤ô²y [s]§ó·s [¡÷]¬d¸ß [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥N ¸¹ ¤º ®e%*s ®É¶¡ \033[m" + +#define NECKER_MF "[¡ö]Â÷¶} [¡÷]¶i¤J [^P]·s¼W [d]§R°£ [c]¤Á´« [C]½Æ»s [^V]¶K¤W [m]²¾°Ê [h]»¡©ú\n" \ + COLOR3 " %s ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ¤H®ð ªO ¥D%*s \033[m" + +#define NECKER_COSIGN "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]¥Ó½Ð [d]§R°£ [o]¶}ªO [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á Á|¿ì¤H ¬Ý ªO ¼Ð ÃD%*s \033[m" + +#define NECKER_SONG "[¡ö]Â÷¶} [¡÷]ÂsÄý [o]ÂIºq¨ì¬ÝªO [m]ÂIºq¨ì«H½c [Enter]ÂsÄý [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +#define NECKER_NEWS "[¡ö]Â÷¶} [¡÷]¾\\Ū [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ·s »D ¼Ð ÃD%*s \033[m" + +#define NECKER_XPOST "\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s \033[m" + +#define NECKER_MBOX "[¡ö]Â÷¶} [¡÷,r]Ū«H [d]§R°£ [R,y](¸s²Õ)¦^«H [s]±H«H [x]Âà¿ý [X]Âà¹F [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ «H ¥ó ¼Ð ÃD%*s \033[m" + +#define NECKER_POST "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]µoªí [b]¶iªOµe± [d]§R°£ [V]§ë²¼ [TAB]ºëµØ°Ï [h]»¡©ú\n" \ + COLOR3 " ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD%*s µû:%s ¤H®ð:%-4d \033[m" + +#define NECKER_GEM "[¡ö]Â÷¶} [¡÷]ÂsÄý [B]¼Ò¦¡ [C]¼È¦s [F]Âà±H [d]§R°£ [h]»¡©ú %s\n" \ + COLOR3 " ½s¸¹ ¥D ÃD%*s [½s ¿ï] [¤é ´Á]\033[m" + +/* ¥H¤U³o¨Ç«h¬O¤@¨ÇÃþ XZ_* µ²ºcªº necker */ + +#define NECKER_VOTEALL "[¡ô/¡õ]¤W¤U [PgUp/PgDn]¤W¤U¶ [Home/End]º§À [¡÷]§ë²¼ [¡ö][q]Â÷¶}\n" \ + COLOR3 " ½s¸¹ ¬Ý ªO Ãþ§OÂà«H ¤¤ ¤å ±Ô z%*s ªO ¥D%*s \033[m" + +#define NECKER_CREDIT "[¡ö]Â÷¶} [C]´«¶ [1]·s¼W [2]§R°£ [3]¥þ§R [4]Á`p\n" \ + COLOR3 " ½s¸¹ ¤é ´Á ¦¬¤ä ª÷ ÃB ¤ÀÃþ »¡ ©ú%*s \033[m" + +#define NECKER_HELP "[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]·s¼W [d]§R°£ [T]¼ÐÃD [E]½s¿è [m]²¾°Ê\n" \ + COLOR3 " ½s¸¹ ÀÉ ®× ¼Ð ÃD%*s \033[m" + +#define NECKER_INNBBS "[¡ö]Â÷¶} [^P]·s¼W [d]§R°£ [E]½s¿è [/]·j´M [Enter]¸Ô²Ó\n" \ + COLOR3 " ½s¸¹ ¤º ®e%*s \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gmore() ®Éªº footer ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + +/* itoc.010914.µù¸Ñ: ³æ¤@½g¡A©Ò¥H¥s FOOTER¡A³£¬O 78 char */ + +/* itoc.010821: ª`·N \\ ¬O \¡A³Ì«á§Oº|¤F¤@ӪťÕÁä :p */ + +#define FOOTER_POST \ +COLOR1 " ¤å³¹¿ïŪ " COLOR2 " (ry)¦^À³ (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (C)¼È¦s " + +#define FOOTER_MAILER \ +COLOR1 " ³½¶©¹ªð " COLOR2 " (ry)¦^«H/¸s²Õ (X)Âà¹F (d)§R°£ (m)¼Ð°O (C)¼È¦s (=\\[]<>-+;'`|?QAkj) " + +#define FOOTER_GEM \ +COLOR1 " ºëµØ¿ïŪ " COLOR2 " (=\\[]<>-+;'`)¥DÃD (|?QA)·j´M¼ÐÃD§@ªÌ (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} " + +#ifdef HAVE_GAME +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^O)¹ï«³¼Ò¦¡ (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í " +#else +#define FOOTER_TALK \ +COLOR1 " ¥æ½Í¼Ò¦¡ " COLOR2 " (^C,^D)µ²§ô¥æ½Í (^T)¤Á´«©I¥s¾¹ (^Z)§Ö±¶¦Cªí (^G)¹Í¹Í (^Y)²M°£ " +#endif + +#define FOOTER_COSIGN \ +COLOR1 " ³s¸p¾÷¨î " COLOR2 " (ry)¥[¤J³s¸p (kj)¤W¤U½g (¡ô¡õ¡ö)¤W¤UÂ÷¶} (h)»¡©ú " + +#define FOOTER_MORE \ +COLOR1 " ÂsÄý P.%d (%d%%) " COLOR2 " (h)»¡©ú [PgUp][PgDn][0][$]²¾°Ê (/n)·j´M (C)¼È¦s (¡öq)µ²§ô " + +#define FOOTER_VEDIT \ +COLOR1 " %s " COLOR2 " (^Z)»¡©ú (^W)²Å¸¹ (^L)«Ã¸ (^X)Àɮ׳B²z ùø%s¢x%sùø%5d:%3d \033[m" + + +/* ----------------------------------------------------- */ +/* °T®§¦r¦ê¡Gxo_foot() ®Éªº feeter ³£§ì¥X¨Ó©w¸q¦b³o */ +/* ----------------------------------------------------- */ + + +/* itoc.010914.µù¸Ñ: ¦Cªí¦h½g¡A©Ò¥H¥s FEETER¡A³£¬O 78 char */ + +#define FEETER_CLASS \ +COLOR1 " ¬ÝªO¿ï¾Ü " COLOR2 " (c)·s¤å³¹ (vV)¼Ð°O¤wŪ¥¼Åª (y)¥þ³¡¦C¥X (z)¿ïq (A)¥þ°ì·j´M (S)±Æ§Ç " + +#define FEETER_ULIST \ +COLOR1 " ºô¤Í¦Cªí " COLOR2 " (f)¦n¤Í (t)²á¤Ñ (q)¬d¸ß (ad)¥æ¤Í (m)±H«H (w)¤ô²y (s)§ó·s (TAB)¤Á´« " + +#define FEETER_PAL \ +COLOR1 " ©IªB¤Þ¦ñ " COLOR2 " (a)·s¼W (d)§R°£ (c)¤Í½Ë (m)±H«H (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_ALOHA \ +COLOR1 " ¤W¯¸³qª¾ " COLOR2 " (a)·s¼W (d)§R°£ (D)°Ï¬q§R°£ (f)¤Þ¤J¦n¤Í (r^Q)¬d¸ß (s)§ó·s " + +#define FEETER_VOTE \ +COLOR1 " ¬ÝªO§ë²¼ " COLOR2 " (¡÷/r/v)§ë²¼ (R)µ²ªG (^P)·s¼W§ë²¼ (E)×§ï (V)¹wÄý (b)¶}²¼ (o)¦W³æ " + +#define FEETER_BMW \ +COLOR1 " ¤ô²y¦^ÅU " COLOR2 " (d)§R°£ (D)°Ï¬q§R°£ (m)±H«H (w)¤ô²y (^R)¦^°T (^Q)¬d¸ß (s)§ó·s " + +#define FEETER_MF \ +COLOR1 " ³Ì·R¬ÝªO " COLOR2 " (^P)·s¼W (Cg)½Æ»s (p^V)¶K¤W (d)§R°£ (c)·s¤å³¹ (vV)¼Ð°O¤wŪ/¥¼Åª " + +#define FEETER_COSIGN \ +COLOR1 " ³s¸p¤p¯¸ " COLOR2 " (r)Ū¨ú (y)¦^À³ (^P)µoªí (d)§R°£ (o)¶}ªO (c)Ãö³¬ (E)½s¿è (B)³]©w " + +#define FEETER_SONG \ +COLOR1 " ÂIºq¨t²Î " COLOR2 " (r)Ū¨ú (o)ÂIºq¨ì¬ÝªO (m)ÂIºq¨ì«H½c (E)½s¿èÀÉ®× (T)½s¿è¼ÐÃD " + +#define FEETER_NEWS \ +COLOR1 " ·s»DÂI¿ï " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)¿ï¨ú (¡ö)(q)Â÷¶} " + +#define FEETER_XPOST \ +COLOR1 " ¦ê¦C·j´M " COLOR2 " (y)¦^À³ (x)Âà¿ý (m)¼Ð°O (d)§R°£ (^P)µoªí (^Q)¬d¸ß§@ªÌ (t)¼ÐÅÒ " + +#define FEETER_MBOX \ +COLOR1 " «H«H¬Û±¤ " COLOR2 " (y)¦^«H (F/X/x)Âà±H/Âà¹F/Âà¿ý (d)§R°£ (D)°Ï¬q§R°£ (m)¼Ð°O (E)½s¿è " + +#define FEETER_POST \ +COLOR1 " ¤å³¹¦Cªí " COLOR2 " (ry)¦^«H (S/a)·j´M/¼ÐÃD/§@ªÌ (~G)¦ê¦C·j´M (x)Âà¿ý (V)§ë²¼ (u)·s»D " + +#define FEETER_GEM \ +COLOR1 " ¬ÝªOºëµØ " COLOR2 " (^P/a/f)·s¼W/¤å³¹/¥Ø¿ý (E)½s¿è (T)¼ÐÃD (m)²¾°Ê (c)½Æ»s (p^V)¶K¤W " + +#define FEETER_VOTEALL \ +COLOR1 " §ë²¼¤¤¤ß " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷)§ë²¼ (¡ö)(q)Â÷¶} " + +#define FEETER_HELP \ +COLOR1 " »¡©ú¤å¥ó " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡÷r)ÂsÄý (¡ö)(q)Â÷¶} " + +#define FEETER_INNBBS \ +COLOR1 " Âà«H³]©w " COLOR2 " (¡ô/¡õ)¤W¤U (PgUp/PgDn)¤W¤U¶ (Home/End)º§À (¡ö)(q)Â÷¶} " + + +/* ----------------------------------------------------- */ +/* ¯¸¥x¨Ó·½Ã±¦W */ +/* ----------------------------------------------------- */ + +/* itoc: «ØÄ³ banner ¤£n¶W¹L¤T¦æ¡A¹Lªøªº¯¸Ã±¥i¯à·|³y¦¨¬Y¨Ç¨Ï¥ÎªÌªº¤Ï·P */ + +#define EDIT_BANNER "\n--\n" \ + " \033[1;41m¡÷\033[44m¡õ\033[m O\033[1mri\033[30mgi\033[mn: \033[1;43m "SCHOOLNAME"£»"BBSNAME" \033[47m "MYHOSTNAME" \033[m\n" \ + " \033[1;45m¡ô\033[42m¡ö\033[m Au\033[1mt\033[30mho\033[mr: \033[1;33m%s\033[m ±q \033[1;34m%s\033[m µoªí\n" + +#define MODIFY_BANNER " \033[1;43m¡ù\033[46m¡ø\033[m \033[1mMo\033[30mdi\033[mfy: %s ©ó \033[1;33m%s\033[m ×§ï\n" + + +/* ----------------------------------------------------- */ +/* ¨ä¥L°T®§¦r¦ê */ +/* ----------------------------------------------------- */ + +#define VMSG_NULL " \033[1;43m ¡ò ½Ð«ö¥ô·NÁäÄ~Äò ¡ò \033[m" + +#define ICON_UNREAD_BRD "\033[1;33m£k" /* ¥¼Åª¬ÝªO */ +#define ICON_READ_BRD " " /* ¤wŪ¬ÝªO */ + +#define ICON_GAMBLED_BRD "\033[1;31m½ä\033[m" /* Á|¦æ½ä½L¤¤ªº¬ÝªO */ +#define ICON_VOTED_BRD "\033[1;33m§ë\033[m" /* Á|¦æ§ë²¼¤¤ªº¬ÝªO */ +#define ICON_NOTRAN_BRD "¡º" /* ¤£Âà«HªO */ +#define ICON_TRAN_BRD "¡»" /* Âà«HªO */ + +#define TOKEN_ZAP_BRD '-' /* zap ªO */ +#define TOKEN_FRIEND_BRD '#' /* ¦n¤ÍªO */ +#define TOKEN_SECRET_BRD ']' /* ¯µ±KªO */ + +#endif /* _THEME_H_ */ diff --git a/include/ufo.h b/include/ufo.h new file mode 100644 index 0000000..4ed7d4b --- /dev/null +++ b/include/ufo.h @@ -0,0 +1,173 @@ +/*-------------------------------------------------------*/ +/* ufo.h ( NTHU CS MapleBBS Ver 2.36 ) */ +/*-------------------------------------------------------*/ +/* target : User Flag Option */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ + + +#ifndef _UFO_H_ +#define _UFO_H_ + + +/* ----------------------------------------------------- */ +/* User Flag Option : flags in ACCT.ufo */ +/* ----------------------------------------------------- */ + + +#define BFLAG(n) (1 << n) /* 32 bit-wise flag */ + + +#define UFO_NOUSE00 BFLAG(0) /* ¨S¥Î¨ì */ +#define UFO_MOVIE BFLAG(1) /* °ÊºA¬ÝªOÅã¥Ü */ +#define UFO_BRDPOST BFLAG(2) /* 1: ¬ÝªO¦CªíÅã¥Ü½g¼Æ 0: ¬ÝªO¦CªíÅã¥Ü¸¹½X itoc.010912: «í¬°·s¤å³¹¼Ò¦¡ */ +#define UFO_BRDNAME BFLAG(3) /* itoc.010413: ¬ÝªO¦Cªí¨Ì 1:brdname 0:class+title ±Æ§Ç */ +#define UFO_BRDNOTE BFLAG(4) /* Åã¥Ü¶iªOµe± */ +#define UFO_VEDIT BFLAG(5) /* ²¤Æ½s¿è¾¹ */ +#define UFO_MOTD BFLAG(6) /* ²¤Æ¶i/Â÷¯¸µe± */ + +#define UFO_PAGER BFLAG(7) /* Ãö³¬©I¥s¾¹ */ +#define UFO_RCVER BFLAG(8) /* itoc.010716: ©Ú¦¬¼s¼½ */ +#define UFO_QUIET BFLAG(9) /* µ²Ãf¦b¤H¹Ò¡A¦ÓµL¨®°¨³Ù */ +#define UFO_PAL BFLAG(10) /* ¨Ï¥ÎªÌ¦W³æ¥uÅã¥Ü¦n¤Í */ +#define UFO_ALOHA BFLAG(11) /* ±µ¨ü¤W¯¸³qª¾ */ +#define UFO_NOALOHA BFLAG(12) /* itoc.010716: ¤W¯¸¤£³qª¾/¨ó´M */ + +#define UFO_BMWDISPLAY BFLAG(13) /* itoc.010315: ¤ô²y¦^ÅU¤¶± */ +#define UFO_NWLOG BFLAG(14) /* lkchu.990510: ¤£¦s¹ï¸Ü¬ö¿ý */ +#define UFO_NTLOG BFLAG(15) /* lkchu.990510: ¤£¦s²á¤Ñ¬ö¿ý */ + +#define UFO_NOSIGN BFLAG(16) /* itoc.000320: ¤£¨Ï¥Îñ¦WÀÉ */ +#define UFO_SHOWSIGN BFLAG(17) /* itoc.000319: ¦sÀÉ«eÅã¥Üñ¦WÀÉ */ + +#define UFO_ZHC BFLAG(18) /* hightman.060504: ¥þ«¬¦r°»´ú */ +#define UFO_JUMPBRD BFLAG(19) /* itoc.020122: ¦Û°Ê¸õ¥h¤U¤@Ó¥¼Åª¬ÝªO */ +#define UFO_NOUSE20 BFLAG(20) +#define UFO_NOUSE21 BFLAG(21) +#define UFO_NOUSE22 BFLAG(22) +#define UFO_NOUSE23 BFLAG(23) + +#define UFO_CLOAK BFLAG(24) /* 1: ¶i¤JÁô§Î */ +#define UFO_SUPERCLOAK BFLAG(25) /* 1: ¶W¯ÅÁô¨ */ +#define UFO_ACL BFLAG(26) /* 1: ¨Ï¥Î ACL */ +#define UFO_NOUSE27 BFLAG(27) +#define UFO_NOUSE28 BFLAG(28) +#define UFO_NOUSE29 BFLAG(29) +#define UFO_NOUSE30 BFLAG(30) +#define UFO_NOUSE31 BFLAG(31) + +/* ·sµù¥U±b¸¹¡Bguest ªº¹w³] ufo */ + +#define UFO_DEFAULT_NEW (UFO_MOVIE | UFO_BRDNOTE | UFO_MOTD | UFO_BMWDISPLAY | UFO_NOSIGN) +#define UFO_DEFAULT_GUEST (UFO_MOVIE | UFO_BRDNOTE | UFO_QUIET | UFO_NOALOHA | UFO_NWLOG | UFO_NTLOG | UFO_NOSIGN) + + +/* ----------------------------------------------------- */ +/* Status : flags in UTMP.status */ +/* ----------------------------------------------------- */ + + +#define STATUS_BIFF BFLAG(0) /* ¦³·s«H¥ó */ +#define STATUS_REJECT BFLAG(1) /* true if reject any body */ +#define STATUS_BIRTHDAY BFLAG(2) /* ¤µ¤Ñ¥Í¤é */ +#define STATUS_COINLOCK BFLAG(3) /* ¿ú¹ôÂê©w */ +#define STATUS_DATALOCK BFLAG(4) /* ¸ê®ÆÂê©w */ +#define STATUS_MQUOTA BFLAG(5) /* «H½c¤¤¦³¹L´Á¤§«H¥ó */ +#define STATUS_MAILOVER BFLAG(6) /* «H½c¹L¦h«H¥ó */ +#define STATUS_MGEMOVER BFLAG(7) /* Ó¤HºëµØ°Ï¹L¦h */ +#define STATUS_EDITHELP BFLAG(8) /* ¦b edit ®É¶i¤J help */ +#define STATUS_PALDIRTY BFLAG(9) /* ¦³¤H¦b¥LªºªB¤Í¦W³æ·s¼W©Î²¾°£¤F§Ú */ +#define STATUS_FOOLDAY BFLAG(10) + +#define HAS_STATUS(x) (cutmp->status&(x)) + + +/* ----------------------------------------------------- */ +/* ¦UºØ²ßºDªº¤¤¤å·N¸q */ +/* ----------------------------------------------------- */ + + +/* itoc.000320: ¼W´î¶µ¥Øn§ó§ï NUMUFOS_* ¤j¤p, ¤]§O§Ñ¤F§ï STR_UFO */ + +#define NUMUFOS 27 +#define NUMUFOS_GUEST 5 /* guest ¥i¥H¥Î«e 5 Ó ufo */ +#define NUMUFOS_USER 20 /* ¤@¯ë¨Ï¥ÎªÌ ¥i¥H¥Î«e 20 Ó ufo */ + +#define STR_UFO "-mpsnemPBQFANbwtSHZJ----CHA" /* itoc: ·s¼W²ßºDªº®ÉÔ§O§Ñ¤F§ï³o¸Ì°Ú */ + + +#ifdef _ADMIN_C_ + +char *ufo_tbl[NUMUFOS] = +{ + "«O¯d", /* UFO_NOUSE */ + "Åã¥Ü°ÊºA¬ÝªO (¶}±Ò/Ãö³¬)", /* UFO_MOVIE */ + + "¬ÝªO¦CªíÅã¥Ü (¤å³¹¼Æ/½s¸¹)", /* UFO_BRDPOST */ + "¬ÝªO¦Cªí±Æ§Ç¨Ì (¦r¥À/¤ÀÃþ)", /* UFO_BRDNAME */ /* itoc.010413: ¬ÝªO¨Ì·Ó¦r¥À/¤ÀÃþ±Æ§Ç */ + "¶iªOµe± (Åã¥Ü/¸õ¹L)", /* UFO_BRDNOTE */ + "¤å³¹½s¿è¾¹ (²¤Æ/§¹¾ã)", /* UFO_VEDIT */ + "¶i/Â÷¯¸µe± (²¤Æ/§¹¾ã)", /* UFO_MOTD */ + + "½Ö¯à¥á§A¤ô²y(¥u¦³¦n¤Í/¥þ³¡)", /* UFO_PAGER */ +#ifdef HAVE_NOBROAD + "¤£±µ¨ü§O¤H¼s¼½ (©Ú¦¬/±µ¦¬)", /* UFO_RCVER */ +#else + "«O¯d", +#endif + "¤£±µ¨ü¥ô¦ó¤ô²y (©Ú¦¬/±µ¦¬)", /* UFO_QUITE */ + + "¨Ï¥ÎªÌ¦W³æÅã¥Ü (¦n¤Í/¥þ³¡)", /* UFO_PAL */ + +#ifdef HAVE_ALOHA + "§O¤H¤W¯¸®É³qª¾§Ú(³qª¾/¨ú®ø)", /* UFO_ALOHA */ +#else + "«O¯d", +#endif +#ifdef HAVE_NOALOHA + "¤W¯¸¤£³qª¾§O¤H(¤£³qª¾/³qª¾)", /* UFO_NOALOHA */ +#else + "«O¯d", +#endif + +#ifdef BMW_DISPLAY + "¤ô²y¦^ÅU¤¶± (§¹¾ã/¤W¦¸)", /* UFO_BMWDISPLAY */ +#else + "«O¯d", +#endif + "Â÷¯¸®É§R°£¤ô²y¡H(§R±¼/°Ý§Ú)", /* UFO_NWLOG */ + "Â÷¯¸§R°£²á¤Ñ¬ö¿ý(§R±¼/°Ý§Ú)", /* UFO_NTLOG */ + + "¤£¨Ï¥Îñ¦WÀÉ (¤£¥Î/¿ï¾Ü)", /* UFO_NOSIGN */ + "Åã¥Üñ¦WÀÉ (Åã¥Ü/¤£¬Ý)", /* UFO_SHOWSIGN */ + +#ifdef HAVE_MULTI_BYTE + "¥þ«¬¦r°»´ú (°»´ú/¤£¥Î)", /* UFO_ZHC */ +#else + "«O¯d", +#endif + +#ifdef AUTO_JUMPBRD + "¦Û°Ê¸õ¨ì¥¼Åª¬ÝªO(¸õ¥h/¤£¸õ)", /* UFO_JUMPBRD */ +#else + "«O¯d", +#endif + + "«O¯d", + "«O¯d", + "«O¯d", + "«O¯d", + + "Áô¨³N (Áô¨/²{¨)", /* UFO_CLOAK */ +#ifdef HAVE_SUPERCLOAK + "¶W¯ÅÁô¨³N (µµÁô/²{¨)", /* UFO_SUPERCLOAK */ +#else + "«O¯d", +#endif + + "¯¸ªø¤W¯¸¨Ó·½ (¨î/¥ô·N)" /* UFO_ACL */ +}; +#endif + +#endif /* _UFO_H_ */ diff --git a/include/xchat.h b/include/xchat.h new file mode 100644 index 0000000..b4ec436 --- /dev/null +++ b/include/xchat.h @@ -0,0 +1,136 @@ +/*-------------------------------------------------------*/ +/* xchat.h ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : definitions that xchat client/server used */ +/* create : 97/09/19 */ +/* update : 97/09/19 */ +/*-------------------------------------------------------*/ + + +#ifndef _XCHAT_H_ +#define _XCHAT_H_ + + +#define XCHAT_VERSION_MAJOR 3 +#define XCHAT_VERSION_MINOR 0 + + +/* ----------------------------------------------------- */ +/* XCHAT response code : RFI 3-digit */ +/* ----------------------------------------------------- */ +/* Response : */ +/* 1xx Informative message */ +/* 2xx Command ok */ +/* 3xx Command ok so far, send the rest of it */ +/* 4xx Command correct, but NG for some reason */ +/* 5xx Command unimplemented, incorrect, or serious */ +/* program error occurred */ +/* Function : */ +/* x0x Connection, setup, and miscellaneous messages */ +/* x1x Newsgroup selection */ +/* x2x Article selection */ +/* x3x Distribution functions */ +/* x4x Posting */ +/* x8x Nonstandard extensions (AUTHINFO, XGTITLE) */ +/* x9x Debugging output */ +/* Information : */ +/* No defined semantics */ +/* ----------------------------------------------------- */ + + +/* ¨Ñ·sª© client ¨Ï¥Î */ + + +#define MSG_LOGINOK 100 +#define MSG_VERSION 103 +#define MSG_MESSAGE 106 + +#define MSG_CHATROOM 110 +#define MSG_TOPIC 113 +#define MSG_ROOM 116 +#define MSG_NICK 118 +#define MSG_CLRSCR 120 + +#define MSG_MOTDSTART 130 +#define MSG_MOTD 330 +#define MSG_MOTDEND 230 + +#define MSG_ROOMLISTSTART 133 +#define MSG_ROOMLIST 333 +#define MSG_ROOMLISTEND 233 +#define MSG_ROOMNOTIFY 134 + +#define MSG_USERLISTSTART 136 +#define MSG_USERLIST 336 +#define MSG_USERLISTEND 236 +#define MSG_USERNOTIFY 137 + +#define MSG_PARTYINFO 140 +#define MSG_PARTYLISTSTART 340 +#define MSG_PARTYLIST 240 +#define MSG_PARTYLISTEND 141 + +#define MSG_PRIVMSG 145 +#define MSG_MYPRIVMSG 146 + +#define ERR_LOGIN_NICKINUSE 501 +#define ERR_LOGIN_NICKERROR 502 +#define ERR_LOGIN_USERONLINE 503 +#define ERR_LOGIN_NOSUCHUSER 504 +#define ERR_LOGIN_PASSERROR 505 + + +static int +Isspace(ch) + int ch; +{ + return (ch == ' ' || ch == '\t' || ch == 10 || ch == 13); +} + + +static char * +nextword(str) + char **str; +{ + char *head, *tail; + int ch; + + head = *str; + for (;;) + { + + ch = *head; + if (!ch) + { + *str = head; + return head; + } + if (!Isspace(ch)) + break; + head++; + } + + tail = head + 1; + while (ch = *tail) + { + + if (Isspace(ch)) + { + *tail++ = '\0'; + break; + } + tail++; + } + *str = tail; + + return head; +} + + +/* ¨Ñ·sª© server ¨Ï¥Î */ + + +#define MSG_CLOAKED "«¢«¢¡I§ÚÁô§Î°_¨Ó¤F" +#define MSG_UNCLOAK "§Ún«²{¦¿´ò¤F...." + +#endif /* _XCHAT_H_ */ diff --git a/innbbsd/Makefile b/innbbsd/Makefile new file mode 100644 index 0000000..63ca63d --- /dev/null +++ b/innbbsd/Makefile @@ -0,0 +1,71 @@ +# ------------------------------------------------------ # +# innbbsd/Makefile ( NTHU CS MapleBBS Ver 3.10 ) # +# ------------------------------------------------------ # +# target : Makefile for Âà«Hµ{¦¡ innbbsd # +# create : 95/03/29 # +# update : 01/08/26 # +# author : skhuang # +# ------------------------------------------------------ # + + +# ------------------------------------------------------ # +# ¤U¦Cªº make rules ¤£»Ý×§ï # +# ------------------------------------------------------ # + +INNOBJS = channel.o bbslib.o convcode.o inntobbs.o rec_article.o nocem.o history.o + +LNKOBJS = bbslink.o bbslib.o convcode.o inntobbs.o rec_article.o nocem.o history.o + +INNBBSD = innbbsd bbslink + +EXE = $(INNBBSD) + + +all: + @echo "Please enter 'make sys-type', " + @echo " make sun : for Sun-OS 4.x and maybe some BSD systems, cc or gcc" + @echo " make linux : for Linux" + @echo " make solaris : for Sun-OS 5.x gcc" + @echo " make sol-x86 : for Solaris 7 x86" + @echo " make freebsd : for BSD 4.4 systems" + @echo " make bsd : for BSD systems, cc or gcc, if not in the above lists" + @echo " make cygwin : for Microsoft Windows and Cygwin gcc" + +sun: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -fomit-frame-pointer -Wunused -I../include" LDFLAGS="-s -L../lib -ldao" $(EXE) + +linux: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao" $(EXE) + +solaris: + @$(MAKE) CC=gcc CFLAGS="-DSOLARIS -O2 -pipe -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao -lsocket -lnsl -L/usr/ucblib -lucb" $(EXE) + +sol-x86: + @$(MAKE) CC=gcc CFLAGS="-DSOLARIS -O2 -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao -lsocket -lnsl" $(EXE) + +freebsd: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao" $(EXE) + +bsd: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao" $(EXE) + +cygwin: + @$(MAKE) CC=gcc CFLAGS="-DCYGWIN -O2 -pipe -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao -lcygipc" $(EXE) + + + +bbslink: $(LNKOBJS) + $(CC) -o bbslink $(LNKOBJS) $(OPT) $(LDFLAGS) + +innbbsd: $(INNOBJS) + $(CC) -o innbbsd $(INNOBJS) $(OPT) $(LDFLAGS) + + +install: $(INNBBSD) + install -m 0700 $? $(HOME)/innd + +update: + -csh -c "kill `tail -1 $(HOME)/run/innbbsd.pid | awk '{print $$1}'`";exit 0 + +clean: + rm -f $(EXE) *.exe *.o *~ diff --git a/innbbsd/bbslib.c b/innbbsd/bbslib.c new file mode 100644 index 0000000..16260f2 --- /dev/null +++ b/innbbsd/bbslib.c @@ -0,0 +1,283 @@ +/*-------------------------------------------------------*/ +/* bbslib.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : innbbsd library */ +/* create : 95/04/27 */ +/* update : / / */ +/* author : skhuang@csie.nctu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "innbbsconf.h" +#include "bbslib.h" + +#ifdef _NoCeM_ +#include "nocem.h" +#endif + +#include <stdarg.h> + + +/* ----------------------------------------------------- */ +/* read nodelist.bbs */ +/* ----------------------------------------------------- */ + + +int NLCOUNT; +nodelist_t *NODELIST = NULL; + + +int +nl_bynamecmp(a, b) + nodelist_t *a, *b; +{ + return str_cmp(a->name, b->name); +} + + +static int /* 0:success -1:fail */ +read_nodelist() +{ + int fd, size; + struct stat st; + + if ((fd = open("innd/nodelist.bbs", O_RDONLY)) < 0) + return -1; + + fstat(fd, &st); + if ((size = st.st_size) <= 0) + { + close(fd); + return -1; + } + NODELIST = !NODELIST ? (nodelist_t *) malloc(size) : (nodelist_t *) realloc(NODELIST, size); + read(fd, NODELIST, size); + close(fd); + + NLCOUNT = size / sizeof(nodelist_t); + if (NLCOUNT > 1) + { + /* ±N NODELIST[] ¨Ì name ±Æ§Ç¡A¨º»ò¦b search_nodelist_byname() ¥i¥H§ä§Ö¤@ÂI */ + qsort(NODELIST, NLCOUNT, sizeof(nodelist_t), nl_bynamecmp); + } + + return 0; +} + + +/* ----------------------------------------------------- */ +/* read newsfeeds.bbs */ +/* ----------------------------------------------------- */ + + +int NFCOUNT; +newsfeeds_t *NEWSFEEDS = NULL; +newsfeeds_t *NEWSFEEDS_B = NULL; +newsfeeds_t *NEWSFEEDS_G = NULL; + + +int +nf_byboardcmp(a, b) + newsfeeds_t *a, *b; +{ + return str_cmp(a->board, b->board); +} + + +int +nf_bygroupcmp(a, b) + newsfeeds_t *a, *b; +{ + return str_cmp(a->newsgroup, b->newsgroup); +} + + +static int /* 0:success -1:fail */ +read_newsfeeds() +{ + int fd, size; + struct stat st; + + if ((fd = open("innd/newsfeeds.bbs", O_RDONLY)) < 0) + return -1; + + fstat(fd, &st); + if ((size = st.st_size) <= 0) + { + close(fd); + return -1; + } + NEWSFEEDS = !NEWSFEEDS ? (newsfeeds_t *) malloc(size) : (newsfeeds_t *) realloc(NEWSFEEDS, size); + read(fd, NEWSFEEDS, size); + close(fd); + + /* ¥t¥~·Ç³Æ¤G¥÷¬Û¦Pªº¸ê°T¡A¦ý¬O±Æ§Ç¤èªk¤£¦P */ + NEWSFEEDS_B = !NEWSFEEDS_B ? (newsfeeds_t *) malloc(size) : (newsfeeds_t *) realloc(NEWSFEEDS_B, size); + memcpy(NEWSFEEDS_B, NEWSFEEDS, size); + NEWSFEEDS_G = !NEWSFEEDS_G ? (newsfeeds_t *) malloc(size) : (newsfeeds_t *) realloc(NEWSFEEDS_G, size); + memcpy(NEWSFEEDS_G, NEWSFEEDS, size); + + NFCOUNT = size / sizeof(newsfeeds_t); + if (NFCOUNT > 1) + { + /* NEWSFEEDS[] ¤£ÅܰʡA¹w³]¨Ì¯¸¥x¦WºÙ±Æ§Ç */ + + /* ±N NEWSFEEDS_B[] ¨Ì board ±Æ§Ç¡A¨º»ò¦b search_newsfeeds_byboard() ¥i¥H§ä§Ö¤@ÂI */ + qsort(NEWSFEEDS_B, NFCOUNT, sizeof(newsfeeds_t), nf_byboardcmp); + + /* ±N NEWSFEEDS_G[] ¨Ì group ±Æ§Ç¡A¨º»ò¦b search_newsfeeds_bygroup() ¥i¥H§ä§Ö¤@ÂI */ + qsort(NEWSFEEDS_G, NFCOUNT, sizeof(newsfeeds_t), nf_bygroupcmp); + } + + return 0; +} + + +#ifdef _NoCeM_ +/* ----------------------------------------------------- */ +/* read ncmperm.bbs */ +/* ----------------------------------------------------- */ + + +ncmperm_t *NCMPERM = NULL; +int NCMCOUNT = 0; + + +int /* 0:success -1:fail */ +read_ncmperm() +{ + int fd, size; + struct stat st; + + if ((fd = open("innd/ncmperm.bbs", O_RDONLY)) < 0) + return -1; + + fstat(fd, &st); + if ((size = st.st_size) <= 0) + { + close(fd); + return -1; + } + NCMPERM = !NCMPERM ? (ncmperm_t *) malloc(size) : (ncmperm_t *) realloc(NCMPERM, size); + read(fd, NCMPERM, size); + close(fd); + + NCMCOUNT = size / sizeof(ncmperm_t); + + return 0; +} +#endif /* _NoCeM_ */ + + +/* ----------------------------------------------------- */ +/* read spamrule.bbs */ +/* ----------------------------------------------------- */ + + +spamrule_t *SPAMRULE = NULL; +int SPAMCOUNT = 0; + + +static int /* 0:success -1:fail */ +read_spamrule() +{ + int fd, size; + struct stat st; + spamrule_t *spam; + char *detail; + + if ((fd = open("innd/spamrule.bbs", O_RDONLY)) < 0) + return -1; + + fstat(fd, &st); + if ((size = st.st_size) <= 0) + { + close(fd); + return -1; + } + SPAMRULE = !SPAMRULE ? (spamrule_t *) malloc(size) : (spamrule_t *) realloc(SPAMRULE, size); + read(fd, SPAMRULE, size); + close(fd); + + SPAMCOUNT = size / sizeof(spamrule_t); + for (fd = 0; fd < SPAMCOUNT; fd++) + { + /* ±N SPAMRULE[] ³£Åܦ¨¤p¼g¡A³o¼Ë¤ñ¹ï®É´N¥i¥H¤j¤p¼g³q¦Y */ + spam = SPAMRULE + fd; + detail = spam->detail; + str_lowest(detail, detail); + } + + return 0; +} + + +/* ----------------------------------------------------- */ +/* initail INNBBSD */ +/* ----------------------------------------------------- */ + + +int /* 1:success 0:failure */ +initial_bbs() +{ + chdir(BBSHOME); /* chdir to bbs_home first */ + + /* ¨Ì§Ç¸ü¤J nodelist.bbs¡Bnewsfeeds.bbs¡Bncmperm.bbs¡Bspamrule.bbs */ + + if (read_nodelist() < 0) + { + printf("½ÐÀˬd nodelist.bbs¡AµLªkŪÀÉ\n"); + return 0; + } + + if (read_newsfeeds() < 0) + { + printf("½ÐÀˬd newsfeeds.bbs¡AµLªkŪÀÉ\n"); + return 0; + } + +#ifdef _NoCeM_ + if (read_ncmperm() < 0) + { + printf("½ÐÀˬd ncmperm.bbs¡AµLªkŪÀÉ¡F¦pªG±z¤£·Q³]©w NoCeM¡A¨º»ò½Ð©¿²¤¦¹°T®§\n"); + /* return 0; */ /* ncmperm.bbs ¥i¥H¬OªÅªº */ + } +#endif + + if (read_spamrule() < 0) + { + printf("½ÐÀˬd spamrule.bbs¡AµLªkŪÀÉ¡F¦pªG±z¤£·Q³]©w¾×«H³W«h¡A¨º»ò½Ð©¿²¤¦¹°T®§\n"); + /* return 0; */ /* spamrule.bbs ¥i¥H¬OªÅªº */ + } + + return 1; +} + + +/* ----------------------------------------------------- */ +/* log function */ +/* ----------------------------------------------------- */ + + +void +bbslog(char *fmt, ...) +{ + va_list args; + char datebuf[40]; + time_t now; + FILE *fp; + + if (fp = fopen(LOGFILE, "a")) + { + time(&now); + strftime(datebuf, sizeof(datebuf), "%b %d %X ", localtime(&now)); + fprintf(fp, "%s ", datebuf); + + va_start(args, fmt); + vfprintf(fp, fmt, args); + va_end(args); + + fclose(fp); + } +} diff --git a/innbbsd/bbslib.h b/innbbsd/bbslib.h new file mode 100644 index 0000000..d92aef8 --- /dev/null +++ b/innbbsd/bbslib.h @@ -0,0 +1,33 @@ +#ifndef _BBSLIB_H_ +#define _BBSLIB_H_ + +/* bbslib.c */ +extern int NLCOUNT; +extern nodelist_t *NODELIST; +extern int nl_bynamecmp(); + +/* bbslib.c */ +extern int NFCOUNT; +extern newsfeeds_t *NEWSFEEDS; +extern newsfeeds_t *NEWSFEEDS_B; +extern newsfeeds_t *NEWSFEEDS_G; +extern int nf_byboardcmp(); +extern int nf_bygroupcmp(); + +/* bbslib.c */ +extern int SPAMCOUNT; +extern spamrule_t *SPAMRULE; + +/* bbslib.c */ +extern int initial_bbs(); +extern void bbslog(char *fmt, ...); + +/* rec_article.c */ +extern void init_bshm(); +extern int cancel_article(); +extern int receive_article(); +#ifdef _NoCeM_ +extern int receive_nocem(); +#endif + +#endif /* _BBSLIB_H_ */ diff --git a/innbbsd/bbslink.c b/innbbsd/bbslink.c new file mode 100644 index 0000000..b9b181b --- /dev/null +++ b/innbbsd/bbslink.c @@ -0,0 +1,1053 @@ +/*-------------------------------------------------------*/ +/* bbslink.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : innbbsd NNTP and NNRP */ +/* create : 95/04/27 */ +/* update : 04/10/23 */ +/* author : skhuang@csie.nctu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "innbbsconf.h" +#include "bbslib.h" +#include "inntobbs.h" +#include "nntp.h" +#include <stdarg.h> + + +#if 0 /* itoc.030122.µù¸Ñ: µ{¦¡¬yµ{ */ + + 0. bbsd ·|§â·s¤å³¹ªºÀÉÀY°O¿ý¦b out.bntp + + 1. °õ¦æ¥»µ{¦¡¥H«á¡A¦b main() ³B²z¤@¤U°Ñ¼Æ + + 2. ¦b main():initial_bbs() Ū¥X³]©wÀÉ¡AµM«á¶i¤J bbslink() + + 3. ¦b bbslink():deal_bntp() ¤¤º¥ý³B²z out.bntp + ¥Ñ©ó out.bntp ¬O§â©Ò¦³ªOªº·s¤å³¹³£©ñ¦b¤@°_¡A©Ò¥H¦b³o¸Ì§â³o out.bntp Àɨ̯¸¥x¤À¥h *.link + + 4. ¦b bbslink():visit_site() ¤¤¨Ì¥H¤U¨BÆJ¡A¤@¤@«ô³X¦U¯¸ + + 4.1. open_connect() ¶}±Ò³s½u + 4.2. send_outgoing() §â¥»¯¸¥x¹ïÀ³ªº link Àɤ@µ§¤@µ§Åª¥X¨Ó¡A§â«H°e¥h¹ï¤è¯¸ + 4.3. readnews() ¨Ì§ÇŪ¨ú¨CÓ·Qnªº newsgroup¡A¨Ã¨ú¹ï¤è¯¸ªº«H + 4.4. close_connect() Ãö³¬³s½u + + [µù] §Y¨Ï¨S¦³±Ò°Ê innbbsd¡A¤]¥i¥H¨Ï¥Î bbslink + +#endif + + +static int SERVERfd = -1; +static FILE *SERVERrfp = NULL; +static FILE *SERVERwfp = NULL; +static char SERVERbuffer[1024]; + + +/* itoc.030122.µù¸Ñ: ¥H¤U³o´XÓ¦b«ü©w°Ñ¼Æ®É¤~¦³¥Î */ +static int Verbose = 0; /* 1: Åã¥Ü¸Ô²Ó°T®§ */ +static int KillFormerProc = 0; /* 1: §R°£¤W¦¸°õ¦æ¥¢±Ñªº bbslink */ +static int ResetActive = 0; /* 1: ±N high-number §ó·s¨ì»P news server ¤W¬Û¦P */ +static int MaxArts = MAX_ARTS; /* ¹ï news server ¨CÓ¸s²Õ³Ì¦h¥u§ì´X«Ê¤å³¹ */ +static char *DefaultProcSite = NULL; /* !=NULL: ¥u³B²z¬Y¯S©w¯¸¥x */ + + +#define DEBUG(arg) if (Verbose) printf arg + + +/*-------------------------------------------------------*/ +/* ³B²z bntp ÀÉ */ +/*-------------------------------------------------------*/ + + +static nodelist_t * +search_nodelist_bynode(name) + char *name; +{ + nodelist_t nl; + + str_ncpy(nl.name, name, sizeof(nl.name)); + return bsearch(&nl, NODELIST, NLCOUNT, sizeof(nodelist_t), nl_bynamecmp); +} + + +static newsfeeds_t * +search_newsfeeds_byboard(board) + char *board; +{ + newsfeeds_t nf; + + str_ncpy(nf.board, board, sizeof(nf.board)); + return bsearch(&nf, NEWSFEEDS_B, NFCOUNT, sizeof(newsfeeds_t), nf_byboardcmp); +} + + +typedef struct +{ + char board[BNLEN + 1]; + char filename[9]; + char group[80]; + char from[80]; + char title[80]; + char date[40]; + char msgid[80]; + char control[80]; + char charset[20]; +} soverview_t; + + +static void +queuefeed(node, sover) + nodelist_t *node; + soverview_t *sover; +{ + int fd; + + /* itoc.030122.µù¸Ñ: *.link ÀɬO¨Ì¯¸¥x¤À¦n «Ý°e(©Î°e¤£¦¨)ªº batch */ + + if (node->feedfd < 0) + { + char linkfile[64]; + + sprintf(linkfile, "innd/%s.link", node->name); + if ((fd = open(linkfile, O_WRONLY | O_CREAT | O_APPEND, 0600)) < 0) + return; + node->feedfd = fd; + } + else + { + fd = node->feedfd; + } + + /* flock(fd, LOCK_EX); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_exlock(fd); + + write(fd, sover, sizeof(soverview_t)); + + /* flock(fd, LOCK_UN); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_unlock(fd); +} + + +static char * +Gtime(now) + time_t now; +{ + static char datemsg[40]; + + strftime(datemsg, sizeof(datemsg), "%d %b %Y %X GMT", gmtime(&now)); + return datemsg; +} + + +static void +deal_sover(bntp) + bntp_t *bntp; +{ + newsfeeds_t *nf; + nodelist_t *nl; + soverview_t sover; + time_t mtime; + char buf[80]; + char *board, *filename; + + board = bntp->board; + + if (!(nf = search_newsfeeds_byboard(board))) + { + bbslog("<bbslink> :Warn: %s ¦¹ªO¤£¦b newsfeeds.bbs ¤¤\n", board); + DEBUG(("¢w¡÷:Warn: %s ¦¹ªO¤£¦b newsfeeds.bbs ¤¤\n", board)); + return; + } + + if (!(nl = search_nodelist_bynode(nf->path))) + return; + + filename = bntp->xname; + + memset(&sover, 0, sizeof(soverview_t)); + + if (bntp->chrono > 0) /* ·s«H */ + { + int fd; + char folder[64]; + HDR hdr; + + mtime = bntp->chrono; + brd_fpath(folder, board, FN_DIR); + if ((fd = open(folder, O_RDONLY)) >=0) + { + while (read(fd, &hdr, sizeof(HDR)) == sizeof(HDR)) + { + if (mtime == hdr.chrono) + { + if (hdr.xmode & POST_RESTRICT) + { + close(fd); + return; + } + break; + } + } + close(fd); + } + + str_ncpy(sover.title, bntp->title, sizeof(sover.title)); + sprintf(sover.msgid, "%s$%s@" MYHOSTNAME, filename, board); + } + else /* cancel */ + { + time(&mtime); + sprintf(buf, "%s$%s@" MYHOSTNAME, filename, board); /* ±ý¬å¤å³¹ªº Message-ID */ + sprintf(sover.title, "cmsg cancel <%s>", buf); + sprintf(sover.msgid, "C%s$%s@" MYHOSTNAME, filename, board);/* LHD.030628: ¦bì msgid ¥[¥ô·N¦r¦ê·í§@ cmsg ªº Message-ID */ + sprintf(sover.control, "cancel <%s>", buf); + } + + str_ncpy(sover.board, board, sizeof(sover.board)); + str_ncpy(sover.filename, filename, sizeof(sover.filename)); + sprintf(sover.from, "%s.bbs@" MYHOSTNAME " (%s)", bntp->owner, bntp->nick); + str_ncpy(sover.date, Gtime(mtime), sizeof(sover.date)); + str_ncpy(sover.group, nf->newsgroup, sizeof(sover.group)); + str_ncpy(sover.charset, nf->charset, sizeof(sover.charset)); + + queuefeed(nl, &sover); +} + + +static void +deal_bntp() +{ + char *OUTING = "innd/.outing"; /* ³B²z®É¼È¦sªºÀÉ */ + int fd, i; + nodelist_t *node; + bntp_t bntp; + + if (rename("innd/out.bntp", OUTING)) /* ¨S¦³·s¤å³¹ */ + return; + + /* initail ¦U node ªº feedfd */ + for (i = 0; i < NLCOUNT; i++) + { + node = NODELIST + i; + node->feedfd = -1; + } + + /* ¶K¨ì¦UÓ¯¸¥x©ÒÄݪº *.link */ + if ((fd = open(OUTING, O_RDONLY)) >= 0) + { + while (read(fd, &bntp, sizeof(bntp_t)) == sizeof(bntp_t)) + deal_sover(&bntp); + close(fd); + } + + /* close ¦U node ªº feedfd */ + for (i = 0; i < NLCOUNT; i++) + { + node = NODELIST + i; + if (node->feedfd >= 0) + close(node->feedfd); + } + + unlink(OUTING); +} + + +/*-------------------------------------------------------*/ +/* ³s¥h¬YÓ¯¸ */ +/*-------------------------------------------------------*/ + + +static int +inetclient(server, port) + char *server; + int port; +{ + struct hostent *host; /* host information entry */ + struct sockaddr_in sin; /* Internet endpoint address */ + int fd; + + if (!*server || !port) + return -1; + + memset(&sin, 0, sizeof(sin)); + + if (!(host = gethostbyname(server))) + sin.sin_addr.s_addr = inet_addr(server); + else + memcpy(&sin.sin_addr.s_addr, host->h_addr, host->h_length); + + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + + /* Allocate a socket */ + fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fd < 0) + return -1; + + /* Connect the socket to the server */ + if (connect(fd, (struct sockaddr *) & sin, sizeof(sin)) < 0) + { + close(fd); + return -1; + } + + return fd; +} + + +static int +tcpcommand(char *fmt, ...) +{ + va_list args; + char *ptr; + + va_start(args, fmt); + vfprintf(SERVERwfp, fmt, args); + va_end(args); + fprintf(SERVERwfp, "\r\n"); + fflush(SERVERwfp); + + if (!fgets(SERVERbuffer, sizeof(SERVERbuffer), SERVERrfp)) + return 0; + + if (ptr = strchr(SERVERbuffer, '\r')) + *ptr = '\0'; + if (ptr = strchr(SERVERbuffer, '\n')) + *ptr = '\0'; + + return atoi(SERVERbuffer); +} + + +static int /* 200~202:¦¨¥\ 0:¥¢±Ñ */ +open_connect(node) /* ³s¥h³oÓ¯¸ */ + nodelist_t *node; +{ + char *host = node->host; + int port = node->port; + + DEBUG(("¢~<open_connect> ¥¿¦b¶}±Ò³s½u\n")); + + if ((SERVERfd = inetclient(host, port)) < 0) + { + bbslog("<bbslink> :Err: ¦øªA¾¹³s½u¥¢±Ñ¡G%s %d\n", host, port); + DEBUG(("¢¢<open_connect> ¦øªA¾¹³s½u¥¢±Ñ\n")); + return 0; + } + + if (!(SERVERrfp = fdopen(SERVERfd, "r")) || !(SERVERwfp = fdopen(SERVERfd, "w"))) + { + bbslog("<bbslink> :Err: fdopen µo¥Í¿ù»~\n"); + DEBUG(("¢¢<open_connect> fdopen µo¥Í¿ù»~\n")); + return 0; + } + + if (!fgets(SERVERbuffer, sizeof(SERVERbuffer), SERVERrfp) || SERVERbuffer[0] != '2') /* 200 201 202 ³£¯à¨ú«H */ + { + bbslog("<bbslink> :Err: ¦øªA¾¹©Úµ´³s½u¡G%s %d\n", host, port); + DEBUG(("¢¢<open_connect> ¦øªA¾¹©Úµ´³s½u\n")); + return 0; + } + + /* itoc.040512: MODE READER ¥unÁ¿¤@¦¸´N°÷¤F */ + if (node->xmode & INN_USEPOST) + { + tcpcommand("MODE READER"); + if (SERVERbuffer[0] != '2') /* 200 201 202 ³£¯à¨ú«H */ + { + bbslog("<bbslink> :Err: ¦øªA¾¹©Úµ´³s½u¡G%s %d\n", host, port); + DEBUG(("¢¢<open_connect> ¦øªA¾¹©Úµ´³s½u\n")); + return 0; + } + } + + DEBUG(("¢x<open_connect> ¦øªA¾¹³s½u¦¨¥\\\n")); + return atoi(SERVERbuffer); +} + + +static void +close_connect() /* µ²§ô³s¥h³oÓ¯¸ */ +{ + int status; + + status = tcpcommand("QUIT"); + if (status != NNTP_GOODBYE_ACK_VAL && status != 221) + { + bbslog("<bbslink> :Warn: µLªk¥¿±`Â_½u\n"); + DEBUG(("¢x<close_connect> µLªk¥¿±`Â_½u\n")); + } + + DEBUG(("¢¢<close_connect> ¤wÃö³¬³s½u\n")); + + if (SERVERrfp) + fclose(SERVERrfp); + if (SERVERwfp) + fclose(SERVERwfp); + if (SERVERfd >= 0) + close(SERVERfd); +} + + +/*-------------------------------------------------------*/ +/* °e¥X¤å³¹ */ +/*-------------------------------------------------------*/ + + +static int /* -1:¥¢±Ñ */ +sover_post(sover) + soverview_t *sover; +{ + if (sover->control[0]) /* °e¥X cancel message */ + { + static char BODY_BUF[128]; + + sprintf(BODY_BUF, "%s\r\n", sover->title); + BODY = BODY_BUF; /* cancel message ®É¡ABODY «ü¦V BODY_BUF */ + } + else /* °e¥X·s¤å³¹ */ + { + static char *BODY_BUF; + char *ptr, *str, fpath[64]; + int fd, size; + struct stat st; + + /* Àˬd¤å³¹ÁÙ¦b¤£¦b */ + sprintf(fpath, "brd/%s/%c/%s", sover->board, sover->filename[7], sover->filename); + if ((fd = open(fpath, O_RDONLY)) < 0) + return -1; + fstat(fd, &st); + size = st.st_size; + if (size <= 0) + { + close(fd); + return -1; + } + + /* ¤@¯ë¤å³¹®É¡ABODY «ü¦V malloc ¥Í¥X¨Óªº°Ï¶ô */ + + BODY_BUF = !BODY_BUF ? (char *) malloc(size + 1) : (char *) realloc(BODY_BUF, size + 1); + read(fd, BODY_BUF, size); + close(fd); + ptr = BODY_BUF + size; + *ptr = '\0'; + + /* ¸õ¹L¤å³¹ªº«e´X¦æÀÉÀY¤£n */ + for (str = BODY_BUF;;str = ptr + 1) + { + ptr = strchr(str, '\n'); + if (!ptr) /* §ä¨ì¤å³¹³Ì«á¤FÁ٧䤣¨ìªÅ¦æ¡A¨º»ò¾ãÓÀɮ׳£·í°µ¤º¤å */ + { + BODY = BODY_BUF; + break; + } + + if (ptr == str) /* §ä¨ì¤@¦æªÅ¦æ¡A¨º»ò¥H¤U´N³£¬O¤º¤å¤F */ + { + BODY = str + 1; + break; + } + } + } + + if (sover->charset[0] == 'g') + { + b52gb(BODY); + b52gb(sover->from); + b52gb(sover->title); + } + + return 0; +} + + +static void +fail_post(msgid) + char *msgid; +{ + bbslog("<bbslink> :Warn: %s <%s>\n", SERVERbuffer, msgid); + DEBUG(("¢x¡÷:Warn: %s <%s>\n", SERVERbuffer, msgid)); +} + + +static void +send_outgoing(node, sover) + nodelist_t *node; + soverview_t *sover; +{ + int cc, status; + char *msgid, *str; + + msgid = sover->msgid; + + DEBUG(("¢x¢z MSGID: %s\n", msgid)); + DEBUG(("¢x¢x GROUP: %s\n", sover->group)); + DEBUG(("¢x¢x FROM : %s\n", sover->from)); + DEBUG(("¢x¢| SUBJ : %s\n", sover->title)); + + /* ¥ý§â¤å³¹·Ç³Æ¦n */ + if (sover_post(sover) < 0) + { + DEBUG(("¢x¡÷ ¥»½g¤å³¹¤w¾D§R°£©ÎÀɮ׿ò¥¢¡A¨ú®ø°e¥X\n")); + return; + } + + /* ¦V server °e¥X IHAVE/POST n¨D */ + if (node->xmode & INN_USEIHAVE) + { + status = tcpcommand("IHAVE <%s>", msgid); + if (status != NNTP_SENDIT_VAL) + { + fail_post(msgid); + return; + } + } + else /* if (node->xmode & INN_USEPOST) */ + { + status = tcpcommand("POST"); + if (status != NNTP_START_POST_VAL) + { + fail_post(msgid); + return; + } + } + + /* ¼g¤J¤å³¹ªºÀÉÀY */ + fprintf(SERVERwfp, "Path: %s\r\n", MYBBSID); + fprintf(SERVERwfp, "From: %s\r\n", sover->from); + fprintf(SERVERwfp, "Newsgroups: %s\r\n", sover->group); + /* fprintf(SERVERwfp, "Subject: %s\r\n", sover->title); */ + output_rfc2047_qp(SERVERwfp, "Subject: ", sover->title, sover->charset, "\r\n"); + fprintf(SERVERwfp, "Date: %s\r\n", sover->date); + fprintf(SERVERwfp, "Organization: %s\r\n", *sover->charset == 'b' ? BBSNAME : BBSNAME2); /* itoc.040425: Y¤£¬O big5 ´N¥Î^¤å¯¸¦W */ + fprintf(SERVERwfp, "Message-ID: <%s>\r\n", msgid); + fprintf(SERVERwfp, "Mime-Version: 1.0\r\n"); + fprintf(SERVERwfp, "Content-Type: text/plain; charset=\"%s\"\r\n", sover->charset); + fprintf(SERVERwfp, "Content-Transfer-Encoding: 8bit\r\n"); + if (sover->control[0]) + fprintf(SERVERwfp, "Control: %s\r\n", sover->control); + fputs("\r\n", SERVERwfp); /* ÀÉÀY©M¤º¤åªÅ¤@¦æ */ + + /* ¼g¤J¤å³¹ªº¤º®e */ + for (str = BODY; cc = *str; str++) + { + if (cc == '\n') + { + /* itoc.030127.µù¸Ñ: §â "\n" ´«¦¨ "\r\n" */ + fputc('\r', SERVERwfp); + } + else if (cc == '.') + { + /* If the text contained a period as the first character of the text + line in the original, that first period is doubled. */ + if (str == BODY || str[-1] == '\n') + fputc('.', SERVERwfp); + } + + fputc(cc, SERVERwfp); + } + + /* IHAVE/POST µ²§ô */ + status = tcpcommand("."); + if (node->xmode & INN_USEIHAVE) + { + if (status != NNTP_TOOKIT_VAL) + fail_post(msgid); + } + else /* if (node->xmode & INN_USEPOST) */ + { + if (status != NNTP_POSTEDOK_VAL) + fail_post(msgid); + } +} + + +/*-------------------------------------------------------*/ +/* ¹ï news server ¤U«ü¥O */ +/*-------------------------------------------------------*/ + + +static int +NNRPgroup(newsgroup) /* ¤Á´« group¡A¨Ã¶Ç¦^ high number */ + char *newsgroup; +{ + int high; + char *ptr; + + if (tcpcommand("GROUP %s", newsgroup) != NNTP_GROUPOK_VAL) + return -1; + + ptr = SERVERbuffer; + for (high = 0; high < 3; high++) /* §ä²Ä¤TÓ ' ' */ + { + ptr++; + if (!*ptr || !(ptr = strchr(ptr, ' '))) + return -1; + } + + if ((high = atoi(ptr + 1)) >= 0) + return high; + return -1; +} + + +static char *tempfile = "innd/bbslinktmp"; + +static int /* 1:¦¨¥\ 0:¥¢±Ñ */ +NNRParticle(artno) /* ¨ú¦^²Ä artno ½gªº¥þ¤å */ + int artno; +{ + FILE *fp; + char *ptr; + + if (tcpcommand("ARTICLE %d", artno) != NNTP_ARTICLE_FOLLOWS_VAL) + return 0; + + if (!(fp = fopen(tempfile, "w"))) + return 0; + + while (fgets(SERVERbuffer, sizeof(SERVERbuffer), SERVERrfp)) + { + if (ptr = strchr(SERVERbuffer, '\r')) + *ptr = '\0'; + if (ptr = strchr(SERVERbuffer, '\n')) + *ptr = '\0'; + + if (!strcmp(SERVERbuffer, ".")) /* ¤å³¹µ²§ô */ + break; + + fprintf(fp, "%s\n", SERVERbuffer); + } + + fclose(fp); + return 1; +} + + + +#if 0 /* itoc.030109.µù¸Ñ: my_post ªº¬yµ{ */ + ¢z¡÷ receive_article() ¡÷ bbspost_add() + my_post() ¢u¡÷ receive_nocem() ¡÷ °e¥h nocem.c ³B²z + ¢|¡÷ cancel_article() ¡÷ bbspost_cancel() +#endif + + +static void +my_post() +{ + int rel, size; + char *ptr, *data; + struct stat st; + + if ((rel = open(tempfile, O_RDONLY)) >= 0) + { + fstat(rel, &st); + size = st.st_size; + data = (char *) malloc(size + 1); /* «O¯d 1 byte µ¹ '\0' */ + size = read(rel, data, size); + close(rel); + + if (size >= 2) + { + if (data[size - 2] == '\n') /* §â³Ì«á«ÂЪº '\n' ´«¦¨ '\0' */ + size--; + } + data[size] = '\0'; /* ¸É¤W '\0' */ + + rel = readlines(data - 1); + + if (rel > 0) + { + if (ptr = CONTROL) + { + if (!str_ncmp(ptr, "cancel ", 7)) + rel = cancel_article(ptr + 7); + } + else + { +#ifdef _NoCeM_ + if (strstr(SUBJECT, "@@") && strstr(BODY, "NCM") && strstr(BODY, "PGP")) + rel = receive_nocem(); + else +#endif + rel = receive_article(); + } + + if (rel < 0) + { + DEBUG(("¢x¡÷<my_post> ±µ¦¬¤å³¹¥¢±Ñ\n")); + } + } + else if (rel == 0) /* PATH¥]¬A¦Û¤v */ + { + DEBUG(("¢x¡÷<my_post> PATH ¥]¬A¦Û¤v\n")); + } + else /* if (rel < 0) */ /* ÀÉÀYÄæ¦ì¤£§¹¾ã */ + { + DEBUG(("¢x¡÷<my_post> ÀÉÀYÄæ¦ì¤£§¹¾ã\n")); + } + + free(data); + } + + unlink(tempfile); +} + + +/*-------------------------------------------------------*/ +/* §ó·s high number */ +/*-------------------------------------------------------*/ + + +static int +nf_samegroup(nf) + newsfeeds_t *nf; +{ + return !strcmp(nf->newsgroup, GROUP) && !strcmp(nf->path, NODENAME); +} + + +static void +changehigh(hdd, ram) + newsfeeds_t *hdd, *ram; +{ + if (ram->high >= 0) + { + hdd->high = ram->high; + hdd->xmode &= ~INN_ERROR; + } + else + { + hdd->xmode |= INN_ERROR; + } +} + + +static void +updaterc(nf, pos, high) + newsfeeds_t *nf; + int pos; /* ©ó newsfeeds.bbs ¸Ì±ªº¦ì¸m */ + int high; /* >=0:¥Ø«e§ì¨ìþ¤@½g <0:error */ +{ + nf->high = high; + GROUP = nf->newsgroup; + rec_ref("innd/newsfeeds.bbs", nf, sizeof(newsfeeds_t), pos, nf_samegroup, changehigh); +} + + +/*-------------------------------------------------------*/ +/* §ì¨ú¤å³¹ */ +/*-------------------------------------------------------*/ + + +static void +readnews(node) + nodelist_t *node; +{ + int i, high, artcount, artno; + char *name, *newsgroup; + newsfeeds_t *nf; + + name = node->name; + + for (i = 0; i < NFCOUNT; i++) /* ¨Ì§ÇŪ¨ú¨CÓ newsgroup */ + { + nf = NEWSFEEDS + i; + + if (strcmp(name, nf->path)) /* ¦pªG¤£¬O³oÓ¯¸¥x´N¸õ¹L */ + continue; + + newsgroup = nf->newsgroup; + + DEBUG(("¢x¢z<readnews> ¶i¤J %s\n", newsgroup)); + + /* ¨ú±o news server ¤Wªº high */ + if ((high = NNRPgroup(newsgroup)) < 0) + { + updaterc(nf, i, -1); + DEBUG(("¢x¢|<readnews> µLªk¨ú±o¦¹¸s²Õªº high-number ©Î¦¹¸s²Õ¤£¦s¦b\n")); + continue; + } + + if (ResetActive) + { + if (nf->high != high) + updaterc(nf, i, high); + DEBUG(("¢x¢|<readnews> µ²§ô %s¡A¦¹¸s²Õ¤§ high-number ¤w§ó·s\n", newsgroup)); + continue; /* Y ResetActive «h¤£¨ú«H¡A½ü¤U¤@Ó¸s²Õ */ + } + + if (nf->high >= high) + { + if (nf->high > high) /* server re-number */ + updaterc(nf, i, high); + + DEBUG(("¢x¢|<readnews> µ²§ô %s¡A¦¹¸s²Õ¤w¨S¦³·s¤å³¹\n", newsgroup)); + continue; /* ³o¸s²Õ¤w¨S¦³·s¤å³¹¡A½ü¤U¤@Ó¸s²Õ */ + } + + /* ¨ú¦^¸s²Õ¤W²Ä nf->high + 1 ¶}©lªº MaxArts ½gªº¤å³¹ */ + + artcount = 0; + for (artno = nf->high + 1;; artno++) + { + if (NNRParticle(artno)) + { + DEBUG(("¢x¢x<readnews> [%d] ¥¿¨ú¦^¸s²Õ¤W²Ä %d ½g¤å³¹\n", artcount, artno)); + my_post(); + if (++artcount >= MaxArts) + break; + } + if (artno >= high) + break; + } + + updaterc(nf, i, artno); + + DEBUG(("¢x¢|<readnews> µ²§ô %s¡A¤@¦@¨ú¦^ %d ½g·s¤å³¹\n", newsgroup, artcount)); + } /* end for() */ +} + + +/*-------------------------------------------------------*/ +/* lock/unlock µ{¦¡¡A¦P®É¥u¯à¦³¤@Ó bbslink ¦b¶] */ +/*-------------------------------------------------------*/ + + +static char *lockfile = "innd/bbslinking"; + +static void +bbslink_un_lock() +{ + unlink(lockfile); +} + + +static int +bbslink_get_lock() +{ + int fd; + char buf[10]; + + if ((fd = open(lockfile, O_RDONLY)) >= 0) + { + int pid; + struct stat st; + + /* lockfile ¤w¦s¦b¡A¥Nªí¦³ bbslink ¥¿¦b¶] */ + + if (read(fd, buf, sizeof(buf)) > 0 && (pid = atoi(buf)) > 0 && kill(pid, 0) == 0) + { + /* ¦pªG¥d¤Ó¤[¡A´N¦Û°Ê kill ±¼ */ + if (KillFormerProc || (!fstat(fd, &st) && st.st_mtime > time(NULL) + BBSLINK_EXPIRE)) + { + kill(pid, SIGTERM); + } + else + { + DEBUG(("¦³¥t¥~¤@Ó bbslink ªº process [%d] ¥¿¦b¹B§@¤¤\n", pid)); + return 0; + } + } + + close(fd); + + bbslink_un_lock(); + } + + sprintf(buf, "%d\n", getpid()); + f_cat(lockfile, buf); + + return 1; +} + + +/*-------------------------------------------------------*/ +/* ¥Dµ{¦¡ */ +/*-------------------------------------------------------*/ + + +static void +visit_site(node) + nodelist_t *node; +{ + int status, response, fd, num; + char linkfile[64]; + soverview_t sover; + + NODENAME = node->name; + + /* Y¦³«ü©w¥u³B²z¬Y¯S©w¯¸¡A¨º»ò´N¥u³B²z¸Ó¯¸¥x */ + if (DefaultProcSite && strcmp(NODENAME, DefaultProcSite)) + { + DEBUG(("¡÷ ³o¨Ã«D©Ò«ü©wn³B²zªº¯¸¥x¡Aª½±µ¸õ¹L\n")); + return; + } + + status = 0; + sprintf(linkfile, "innd/%s.link", NODENAME); + if (dashf(linkfile)) + status ^= 0x01; + if (!(node->xmode & INN_FEEDED)) + status ^= 0x02; + + if (!status) /* ¤£»Ýn¥h«ô³X¹ï¤è */ + { + DEBUG(("¡÷ ¦¹¯¸¥x¨S¦³·s«H«Ý°e¥B³QÁý«H¡A¤£»Ýn¥h«ô³X\n")); + return; + } + + if (!(response = open_connect(node))) /* ³s½u¥¢±Ñ */ + return; + + if (status & 0x01) /* ¦³·s«H«Ý°e */ + { + if (response == NNTP_POSTOK_VAL) + { + /* §â linkfile ¸Ì±©Ò°O¿ýn°eªº«H¤@¤@°e¥X */ + num = 0; + if ((fd = open(linkfile, O_RDONLY)) >= 0) + { + while (read(fd, &sover, sizeof(soverview_t)) == sizeof(soverview_t)) + { + send_outgoing(node, &sover); + num++; + } + close(fd); + unlink(linkfile); + } + DEBUG(("¢x¡÷ Á`¦@°e¥X %d ½g¤å³¹\n", num)); + } + else + { + DEBUG(("¢x¡÷ ¨S¦³¦b¦¹¯¸¥xµoªí¤å³¹ªºÅv\n")); + } + } + else + { + DEBUG(("¢x¡÷ ¨S¦³·s«H«Ý°e\n")); + } + + if (status & 0x02) /* »Ýn³s¥h¨ú«H */ + { + readnews(node); + } + else + { + DEBUG(("¢x¡÷ ¦¹¯¸¥x³]©w³QÁý«H¡A¤£»Ýn¥h¨ú«H\n")); + } + + close_connect(); +} + + +static void +bbslink() +{ + int i; + nodelist_t *node; + + /* °T®§Åã¥Ü */ + DEBUG(("¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\n")); + DEBUG(("¡° nodelist.bbs ¸Ì±¤@¦@¦³ %d Ó¯¸¥x¡A±µ¤U¨Ó±N¤@¤@¥h«ô³X\n", NLCOUNT)); + DEBUG(("¡° °Ñ¼Æ³]©w¡G\n")); + DEBUG((" (1) §R°£¤W¦¸°õ¦æ¥¢±Ñªº bbslink¡G%s\n", KillFormerProc ? "¬O" : "§_")); + DEBUG((" (2) ±N high-number §ó·s¨ì»P news server ¤W¬Û¦P¡G%s\n", ResetActive ? "¬O" : "§_")); + DEBUG((" (3) ¹ï news server ¨CÓ¸s²Õ³Ì¦h¥u§ì %d «Ê¤å³¹\n", MaxArts)); + DEBUG((" (4) ¥u³B²z¬Y¯S©w¯¸¥x©Î¬O³B²z©Ò¦³¯¸¥x¡G%s\n", DefaultProcSite ? DefaultProcSite : "³B²z©Ò¦³¯¸¥x")); + + DEBUG(("¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\n")); + DEBUG(("¡· ¶}©l³B²z out.bntp¡A¾ã²zn°e¥X¥hªº¤å³¹\n")); + deal_bntp(); + DEBUG(("¡· out.bntp ¾ã²z§¹¦¨\n")); + DEBUG(("¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\n")); + + /* §â nodelist.bbs ¤¤ªº©Ò¦³¯¸¥x³£¥h«ô³X¤@¹M */ + for (i = 0; i < NLCOUNT; i++) + { + node = NODELIST + i; + DEBUG(("¡· [%d] ¶}©l«ô³X <%s> %s (%d)\n", i + 1, node->name, node->host, node->port)); + visit_site(node); + DEBUG(("¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\n")); + } +} + + +static void +usage(argv) + char *argv; +{ + printf("Usage: %s [options]\n", argv); + printf(" -c ±N high-number »P¦øªA¾¹¤W¦P¨B(¤£¨ú«H)\n"); + printf(" -k ¬å±¼¥Ø«e¥¿¦b¶]ªº bbslink¡A¨Ã«·s±Ò°Ê bbslink\n"); + printf(" -v Åã¥Ü¸Ô²Óªº³s½u¹Lµ{\n"); + printf(" -a ###### «ü©w¨CÓ¸s²Õ³Ì¦h¨ú´X«Ê«H(¹w³] %d «Ê)\n", MAX_ARTS); + printf(" -s site ¥u¨ú³oÓ¯¸¥xªº¤å³¹\n"); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int c, errflag = 0; + + chdir(BBSHOME); + umask(077); + + while ((c = getopt(argc, argv, "a:s:ckv")) != -1) + { + switch (c) + { + case 'a': + if ((c = atoi(optarg)) > 0) + MaxArts = c; + break; + + case 's': + DefaultProcSite = optarg; + break; + + case 'c': + ResetActive = 1; + break; + + case 'k': + KillFormerProc = 1; + break; + + case 'v': + Verbose = 1; + break; + + default: + errflag++; + break; + } + } + + if (errflag > 0) + { + usage(argv[0]); + return -1; + } + + /* ¶}©l bbslink¡A±N bbslink Âê¦í */ + if (!bbslink_get_lock()) + return -1; + + init_bshm(); + + if (initial_bbs()) + bbslink(); + + /* µ²§ô bbslink¡A±N bbslink ¸Ñ¶} */ + bbslink_un_lock(); + + return 0; +} diff --git a/innbbsd/channel.c b/innbbsd/channel.c new file mode 100644 index 0000000..191a5ea --- /dev/null +++ b/innbbsd/channel.c @@ -0,0 +1,884 @@ +/*-------------------------------------------------------*/ +/* channel.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : innbbsd main program */ +/* create : 95/04/27 */ +/* update : / / */ +/* author : skhuang@csie.nctu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "innbbsconf.h" +#include "bbslib.h" +#include "inntobbs.h" +#include "nntp.h" + +#ifdef _NoCeM_ +#include "nocem.h" +#endif + + +#define INNBBSD_PIDFILE "run/innbbsd.pid" + + +/* ----------------------------------------------------- */ +/* my recv */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + char *name; + char *usage; + int minargc; /* argc ³Ì¤Ö´XÓ */ + int maxargc; /* argc ³Ì¦h´XÓ */ + int mode; /* 0:ncommand-mode¤~¯à¶] 1:ndata-mode¤~¯à¶] 2:¨S¦³¨î */ + int errorcode; + int normalcode; + void (*main) (); +} daemoncmd_t; + + +typedef struct +{ + FILE *in, *out; + int argc; + char **argv; + daemoncmd_t *dc; +} argv_t; + + +typedef struct +{ + char *data; + int used; + int left; +} buffer_t; + + +typedef struct +{ + char nodename[13]; + char hostname[128]; /* client hostname */ + char buffer[4096]; + + int mode; /* 1:data mode 0:command mode */ + argv_t Argv; + + int fd; + buffer_t in; + buffer_t out; +} ClientType; + + +#if 0 /* itoc.030109.µù¸Ñ: my_recv ªº¬yµ{ */ + ¢z¡÷ receive_article() ¡÷ bbspost_add() + my_recv() ¢u¡÷ receive_nocem() ¡÷ °e¥h nocem.c ³B²z + ¢|¡÷ cancel_article() ¡÷ bbspost_cancel() +#endif + + +static void +my_recv(client) + ClientType *client; +{ + FILE *fout; + int rel; + char *ptr; + + fout = client->Argv.out; + + rel = readlines(client->in.data + 2); + + if (rel > 0) + { + rel = 0; + if (ptr = CONTROL) + { + if (!str_ncmp(ptr, "cancel ", 7)) + { + /* itoc.030127: cancel ¥¢±ÑÁÙ¬OnÄ~Äò¦¬¨ä¥L«Ê«H */ + /* rel = cancel_article(ptr + 7); */ + cancel_article(ptr + 7); + } + } + else + { +#ifdef _NoCeM_ + if (strstr(SUBJECT, "@@") && strstr(BODY, "NCM") && strstr(BODY, "PGP")) + rel = receive_nocem(); + else +#endif + rel = receive_article(); + } + + if (rel == -1) + fprintf(fout, "400 server side failed\r\n"); + else + fprintf(fout, "235\r\n"); + } + else if (rel == 0) /* PATH¥]¬A¦Û¤v */ + { + fprintf(fout, "235\r\n"); + } + else /* if (rel < 0) */ /* ÀÉÀYÄæ¦ì¤£§¹¾ã */ + { + fputs("437\r\n", fout); + } + + fflush(fout); +} + + +/* ----------------------------------------------------- */ +/* command sets */ +/* ----------------------------------------------------- */ + + +static daemoncmd_t cmds[]; + + +static daemoncmd_t * +searchcmd(cmd) + char *cmd; +{ + daemoncmd_t *p; + char *name; + + for (p = cmds; name = p->name; p++) + { + if (!str_cmp(name, cmd)) + return p; + } + return NULL; +} + + +#define MAX_ARG 16 +#define MAX_ARG_SIZE 1024 + + +static int +argify(line, argvp) + char *line, ***argvp; +{ + static char *argvbuffer[MAX_ARG + 2]; + char **argv = argvbuffer; + int i; + static char argifybuffer[MAX_ARG_SIZE]; + char *p; + + while (strchr("\t\n\r ", *line)) + line++; + p = argifybuffer; + strncpy(p, line, sizeof(argifybuffer)); + for (*argvp = argv, i = 0; *p && i < MAX_ARG;) + { + for (*argv++ = p; *p && !strchr("\t\r\n ", *p); p++); + if (*p == '\0') + break; + for (*p++ = '\0'; strchr("\t\r\n ", *p) && *p; p++); + } + *argv = NULL; + return argv - *argvp; +} + + +/* ----------------------------------------------------- */ +/* innd channel */ +/* ----------------------------------------------------- */ + + +static fd_set rfd; /* read fd_set */ + + +static void +reapchild(s) + int s; +{ + int state; + while (waitpid(-1, &state, WNOHANG | WUNTRACED) > 0) + { + /* printf("reaping child\n"); */ + } +} + + +static void +dokill(s) + int s; +{ + kill(0, SIGKILL); +} + + +static int /* -1:¥¢±Ñ */ +initinetserver() +{ + struct sockaddr_in sin; /* Internet endpoint address */ + int fd, value; + struct linger foobar; + + /* Allocate a socket */ + fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fd < 0) + { + printf("inet socket ¶}±Ò¥¢±Ñ\n"); + return -1; + } + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(INNBBS_PORT); + + if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) + { + printf("innbbsd ¤w¥Ñ inetd ±Ò°Ê¤F¡AµL»Ý¦A¤â°Ê°õ¦æ\n"); + return -1; + } + listen(fd, 10); + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value, sizeof(value)) < 0) + bbslog("setsockopt (SO_REUSEADDR)"); + foobar.l_onoff = 0; + if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &foobar, sizeof(foobar)) < 0) + bbslog("setsockopt (SO_LINGER)"); + + signal(SIGHUP, SIG_IGN); + signal(SIGUSR1, SIG_IGN); + signal(SIGCHLD, reapchild); + signal(SIGINT, dokill); + signal(SIGPIPE, dokill); + signal(SIGTERM, dokill); + + return fd; +} + + +static int +tryaccept(s) + int s; +{ + int ns; + int fromlen = sizeof(struct sockaddr_in); + struct sockaddr sockaddr; /* Internet endpoint address */ + extern int errno; + + do + { + ns = accept(s, &sockaddr, &fromlen); + errno = 0; + } while (ns < 0 && errno == EINTR); + return ns; +} + + +static void +channelcreate(client, sock, nodename, hostname) + ClientType *client; + int sock; + char *nodename, *hostname; +{ + buffer_t *in, *out; + + str_ncpy(client->nodename, nodename, 13); + str_ncpy(client->hostname, hostname, 128); + + client->fd = sock; + FD_SET(sock, &rfd); + client->Argv.in = fdopen(sock, "r"); + client->Argv.out = fdopen(sock, "w"); + + client->buffer[0] = '\0'; + client->mode = 0; + + in = &client->in; + if (in->data != NULL) + free(in->data); + in->data = (char *) malloc(ChannelSize * 4); + in->left = ChannelSize * 4; + in->used = 0; + + out = &client->out; + if (out->data != NULL) + free(out->data); + out->data = (char *) malloc(ChannelSize); + out->left = ChannelSize; + out->used = 0; +} + + +static void +channeldestroy(client) + ClientType *client; +{ + FD_CLR(client->fd, &rfd); + fclose(client->Argv.in); + fclose(client->Argv.out); + close(client->fd); + client->fd = -1; + + if (client->in.data != NULL) + { + free(client->in.data); + client->in.data = NULL; + } + if (client->out.data != NULL) + { + free(client->out.data); + client->out.data = NULL; + } +} + + +static int +channelreader(client) + ClientType *client; +{ + int len, used; + char *data, *head; + buffer_t *in; + + NODENAME = client->nodename; + + in = &client->in; + len = in->left; + used = in->used; + data = in->data; + if (len < ReadSize + 3) + { + len += (used + ReadSize); + len += (len >> 3); + + in->data = data = (char *) realloc(data, len); + len -= used; + in->left = len; + } + + head = data + used; + len = recv(client->fd, head, ReadSize, 0); + if (len <= 0) + return len; + + head[len] = '\0'; + head[len + 1] = '\0'; + + if (client->mode) /* data mode */ + { + char *dest; + int cc; + + dest = head - 1; + + for (;;) + { + cc = *head; + + if (!cc) + { + used = dest - data + 1; + in->left -= (used - in->used); + in->used = used; + return len; + } + + head++; + + if (cc == '\r') + continue; + + if (cc == '\n') + { + used = *dest; + + if (used == '.') + { + if (dest[-1] == '\n') + break; /* end of article body */ + } + else + { + /* strip the trailing space */ + /* Thor.990110: ¤£¬å ªÅ¦æ\n ªº space, for multi-line merge */ + /* while (used == ' ' || used == '\t') */ + while (dest[-1] != '\n' && (used == ' ' || used == '\t')) + used = *--dest; + } + } + + *++dest = cc; + } + + /* strip the trailing empty lines */ + *data = '\0'; + while (*--dest == '\n') + ; + dest += 2; + *dest = '\0'; + + my_recv(client); + client->mode = 0; + } + else /* command mode */ + { + argv_t *argv; + daemoncmd_t *dp; + FILE *out; + + head = (char *) strchr(head, '\n'); + + if (head == NULL) + { + in->used += len; + in->left -= len; + return len; + } + + *head++ = '\0'; + + argv = &client->Argv; + argv->argc = argify(data, &argv->argv); + argv->dc = dp = searchcmd(argv->argv[0]); + out = argv->out; + + if (dp) + { + if ((argv->argc < dp->minargc) || (argv->argc > dp->maxargc)) /* Àˬd argc ¬O§_º¡¨¬n¨D */ + { + fprintf(out, "%d Usage: %s\r\n", dp->errorcode, dp->usage); + fflush(out); + } + else if ((dp->mode == 0 || dp->mode == 1) && (client->mode != dp->mode)) /* Àˬd data/command mode ¬O§_º¡¨¬n¨D */ + { + fprintf(out, "%d %s error\r\n", dp->name, dp->errorcode); + fflush(out); + } + else /* ³q¹L¥H¤W¤T¹DÀˬd */ + { + void (*Main) (); + + if (Main = dp->main) + (*Main) (client); + } + } + else + { + fprintf(out, "500 Syntax error or bad command\r\n"); + fflush(out); + } + } + + /* Thor.980825: gc patch: ¦pªG¤w¸g°õ¦æ¹L CMDquit, ¤U±ªº°Ê§@³£¤£¥Î°µ¤F(client destroied) :) */ + /* if (client->mode == 0) */ + if (client->mode == 0 && client->in.data != NULL) + { + int left; + + left = in->left + in->used; + + if (used = *head) + { + char *str; + + str = data; + while (*str++ = *head++) + ; + + used = str - data; + } + + in->left = left - used; + in->used = used; + } + + return len; +} + + +/* ----------------------------------------------------- */ +/* command set */ +/* ----------------------------------------------------- */ + + +static int inetdstart = 0; + + +static void +CMDhelp(client) + ClientType *client; +{ + argv_t *argv = &client->Argv; + daemoncmd_t *p = argv->dc; + FILE *out = argv->out; + + client->mode = 0; + fprintf(out, "%d Available Commands\r\n", p->normalcode); + for (p = cmds; p->name; p++) + fprintf(out, " %s\r\n", p->usage); + fprintf(out, "Report problems to "STR_SYSOP".bbs@"MYHOSTNAME"\r\n"); + fputs(".\r\n", out); + fflush(out); +} + + +static void +CMDihave(client) + ClientType *client; +{ + argv_t *argv = &client->Argv; + daemoncmd_t *p = argv->dc; + FILE *out = argv->out; + char *data = argv->argv[1]; + + if (data[0] != '<') + { + fprintf(out, "%d Bad Message-ID\r\n", p->errorcode); + } + else + { + fprintf(out, "%d\r\n", p->normalcode); + client->mode = 1; + + strcpy(client->in.data, "\n\n\n"); + client->in.left += client->in.used - 3; + client->in.used = 3; + } + fflush(out); +} + + +static void +CMDstat(client) + ClientType *client; +{ + argv_t *argv = &client->Argv; + daemoncmd_t *p = argv->dc; + FILE *out = argv->out; + char *data = argv->argv[1]; + + if (data[0] != '<') /* ¥u¤ä´© <msgid> ¬d¸ß */ + { + fprintf(out, "%d We does NOT support article number stating\r\n", p->errorcode); + } + else /* ¬d¸ß¬O§_¤w¸g¦¬¨ì <msgid> */ + { + if (HISfetch(data, NULL, NULL)) + fprintf(out, "%d 0 %s article received\r\n", p->normalcode, data); + else + fprintf(out, "%d No such article\r\n", p->errorcode); + } + fflush(out); +} + + +static void +CMDquit(client) + ClientType *client; +{ + argv_t *argv = &client->Argv; + daemoncmd_t *p = argv->dc; + FILE *out = argv->out; + + client->mode = 0; + fprintf(out, "%d quit\r\n", p->normalcode); + fflush(out); + + channeldestroy(client); +} + + +static daemoncmd_t cmds[] = +{ + /* cmd-name, cmd-usage, min-argc, max-argc, mode, errorcode, normalcode, cmd-func */ + {"help", "help [cmd]", 1, 2, 2, 0, NNTP_HELPOK_VAL, CMDhelp}, + {"quit", "quit", 1, 1, 2, 0, NNTP_GOODBYE_ACK_VAL, CMDquit}, + {"ihave", "ihave mid", 2, 2, 0, NNTP_HAVEIT_VAL, NNTP_SENDIT_VAL, CMDihave}, + {"stat", "stat <mid>", 2, 2, 0, NNTP_NOTHING_FOLLOWS_VAL, NNTP_DONTHAVEIT_VAL, CMDstat}, + {NULL, NULL, 0, 0, 2, 0, 0, NULL} +}; + + +/* ----------------------------------------------------- */ +/* ¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static char * /* ¶Ç¦^¬O¥Ñþ¤@Ó¯¸¥xÁý«H¶i¨Óªº */ +search_nodelist_byhost(hostname) + char *hostname; +{ + nodelist_t *find; + struct hostent *he; + char client[128]; + int i; + + /* itoc.021216: §â NODELIST ³£´«¦¨ host¡A³o¼Ëªº¸Ü¡A + ¦pªG nodelist.bbs ¸Ì±¶ñªº¤£¬O¥¿¸Ñ¡A¹ï¤èÁÙ¬O¥i¥H access */ + + for (i = 0; i < NLCOUNT; i++) + { + find = NODELIST + i; + if (he = gethostbyname(find->host)) + { + str_ncpy(client, inet_ntoa(*(struct in_addr *) he->h_addr_list[0]), sizeof(client)); + if (!strcmp(hostname, client)) + return find->name; + } + } + + return NULL; +} + + +static time_t +filetime(fpath) /* ¶Ç¦^ fpath ªºÀɮ׮ɶ¡ */ + char *fpath; +{ + struct stat st; + + if (!stat(fpath, &st)) + return st.st_mtime; + return 0; +} + + +static void +inndchannel() +{ + int i, fd, sock; + char *nodename, hostname[128]; + time_t uptime1; /* time to maintain history */ + time_t uptime2; /* time in initail_bbs */ + time_t now; + struct tm *ptime; + struct timeval to; + fd_set orfd; /* temp read fd_set */ + struct sockaddr_in sin; + ClientType *clientp; + ClientType Channel[MAXCLIENT]; + + /* --------------------------------------------------- */ + /* initial server */ + /* --------------------------------------------------- */ + + if (inetdstart) /* inetd ±Ò°Ê */ + { + sock = 0; + } + else /* standalone */ + { + if ((sock = initinetserver()) < 0) + return; + } + + FD_ZERO(&rfd); + FD_SET(sock, &rfd); + + /* --------------------------------------------------- */ + /* initail history maintain time */ + /* --------------------------------------------------- */ + + time(&uptime1); + ptime = localtime(&uptime1); + i = (HIS_MAINT_HOUR - ptime->tm_hour) * 3600 + (HIS_MAINT_MIN - ptime->tm_min) * 60; + uptime1 += i; + + uptime2 = 0; /* force to initail_bbs in the first time */ + + /* --------------------------------------------------- */ + /* initial channel */ + /* --------------------------------------------------- */ + + memset(Channel, 0, sizeof(Channel)); + + for (i = 0; i < MAXCLIENT; i++) + { + clientp = Channel + i; + clientp->fd = -1; + } + + /* --------------------------------------------------- */ + /* main loop */ + /* --------------------------------------------------- */ + + for (;;) + { + time(&now); + + /* When to maintain history files. */ + if (now > uptime1) + { + HISmaint(); + uptime1 += 86400; + } + + /* YÀɮפñ uptime2 ÁÙ·sªº¸Ü¡A¨º»ò«·s¸ü¤J */ + if (filetime("innd/nodelist.bbs") > uptime2 || + filetime("innd/newsfeeds.bbs") > uptime2 || +#ifdef _NoCeM_ + filetime("innd/ncmperm.bbs") > uptime2 || +#endif + filetime("innd/spamrule.bbs") > uptime2) + { + if (!initial_bbs()) + return; + uptime2 = now; + } + + /* in order to maintain history, timeout every 20 minutes in case no connections */ + to.tv_sec = 60 * 20; + to.tv_usec = 0; + orfd = rfd; + if (select(FD_SETSIZE, &orfd, NULL, NULL, &to) <= 0) + continue; + + /* ¦³¤H¨Ó³X°Ý¤F */ + + if (FD_ISSET(sock, &orfd)) /* è¤W¯¸ */ + { + if ((fd = tryaccept(sock)) < 0) + continue; + + /* Àˬd¦³¨S¦³¦b nodelist.bbs ¸Ì± */ + i = sizeof(sin); /* ɥΠi */ + if (getpeername(fd, (struct sockaddr *) &sin, &i) < 0) + { + close(fd); + continue; + } + str_ncpy(hostname, inet_ntoa(sin.sin_addr), sizeof(hostname)); + if (!(nodename = search_nodelist_byhost(hostname))) + { + char buf[256]; + + bbslog("<channel> :Warn: %s ¸Õ¹Ï³s±µ¥»¯¸¡A¦ý¨ä¤£¦b nodelist.bbs ¦W³æ¤¤\n", hostname); + sprintf(buf, "502 ±z¤£¦b¥»¯¸ªº nodelist.bbs ¦W³æ¤¤ (%s).\r\n", hostname); + write(fd, buf, strlen(buf)); + close(fd); + continue; + } + + /* §ä¤@ӪŪº ClientType */ + for (i = 0; i < MAXCLIENT; i++) + { + clientp = Channel + i; + if (clientp->fd == -1) + break; + } + if (i == MAXCLIENT) + { + static char *msg_no_desc = "502 ¥Ø«e³s½u¤H¼Æ¹L¦h¡A½Ðµy«á¦A¸Õ\r\n"; + + write(fd, msg_no_desc, sizeof(msg_no_desc)); + close(fd); + continue; + } + + channelcreate(clientp, fd, nodename, hostname); + + fprintf(clientp->Argv.out, "200 INNBBSD %s (%s)\r\n", VERSION, hostname); + fflush(clientp->Argv.out); + } + + /* °õ¦æ©Ò¦³ ClientType ªº½Ð¨D¡A¨Ã²M±¼¨S¦b¥Îªº ClientType */ + for (i = 0; i < MAXCLIENT; i++) + { + clientp = Channel + i; + fd = clientp->fd; + + if ((fd >= 0) && FD_ISSET(fd, &orfd) && (channelreader(clientp) <= 0)) + channeldestroy(clientp); + } + } +} + + +#ifdef SOLARIS + +#include <sys/resource.h> + +static int +getdtablesize() +{ + struct rlimit limit; + + if (getrlimit(RLIMIT_NOFILE, &limit) >= 0) + return limit.rlim_cur; + return -1; +} +#endif + + +static void +standaloneinit() +{ + int ndescriptors, s; + FILE *fp; + + ndescriptors = getdtablesize(); + if (!inetdstart) + { + if (fork()) + exit(0); + } + + for (s = 3; s < ndescriptors; s++) + close(s); + + if (fp = fopen(INNBBSD_PIDFILE, "w")) + { + fprintf(fp, "%d\n", getpid()); + fclose(fp); + } +} + + +static void +usage(argv) + char *argv; +{ + printf("Usage: %s [options]\n", argv); + printf(" -i ¥H inetd wait option ±Ò°Ê\n"); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int c; + struct sockaddr_in sin; + + setgid(BBSGID); + setuid(BBSUID); + chdir(BBSHOME); + umask(077); + + while ((c = getopt(argc, argv, "i")) != -1) + { + switch (c) + { + case 'i': + c = sizeof(sin); + if (getsockname(0, (struct sockaddr *) &sin, &c) < 0) + { + printf("±z¤£¬O±q inetd ±Ò°Ê¡AµL»Ý¨Ï¥Î -i\n"); + exit(0); + } + inetdstart = 1; + break; + + default: + usage(argv[0]); + exit(-1); + } + } + + init_bshm(); + standaloneinit(); + inndchannel(); + + exit(0); +} diff --git a/innbbsd/convcode.c b/innbbsd/convcode.c new file mode 100644 index 0000000..55ac2c4 --- /dev/null +++ b/innbbsd/convcode.c @@ -0,0 +1,169 @@ +/* ----------------------------------------------------- */ +/* ²ÁcÅéº~¦rÂà´« */ +/* ----------------------------------------------------- */ +/* create : / / */ +/* update : 03/05/16 */ +/* author : kcn@cic.tsinghua.edu.cn */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/* ----------------------------------------------------- */ + + +#include <stdio.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> + + +#define BtoG_count 13973 +#define GtoB_count 7614 + +#define BtoG_bad1 0xa1 +#define BtoG_bad2 0xf5 +#define GtoB_bad1 0xa1 +#define GtoB_bad2 0xbc + + +static unsigned char *BtoG = NULL; +static unsigned char *GtoB = NULL; + + +static void +conv_init() +{ + int fd, size, BGsize, GBsize; + struct stat st; + + if (BtoG != NULL) + return; + + BGsize = BtoG_count << 1; /* ¨CÓº~¦r 2-byte */ + GBsize = GtoB_count << 1; + BtoG = (unsigned char *) malloc(BGsize + GBsize); + GtoB = BtoG + BGsize; + + if ((fd = open("etc/b2g_table", O_RDONLY)) >= 0) + { + fstat(fd, &st); + size = BGsize <= st.st_size ? BGsize : st.st_size; + read(fd, BtoG, size); + close(fd); + } + if ((fd = open("etc/g2b_table", O_RDONLY)) >= 0) + { + fstat(fd, &st); + size = GBsize <= st.st_size ? GBsize : st.st_size; + read(fd, GtoB, size); + close(fd); + } +} + + +#define c1 (unsigned char)(src[0]) +#define c2 (unsigned char)(src[1]) + + +static void +b2g(src, dst) + unsigned char *src, *dst; +{ + int i; + + if ((c1 >= 0xa1) && (c1 <= 0xf9)) + { + if ((c2 >= 0x40) && (c2 <= 0x7e)) + { + i = ((c1 - 0xa1) * 157 + (c2 - 0x40)) * 2; + dst[0] = BtoG[i++]; + dst[1] = BtoG[i]; + return; + } + else if ((c2 >= 0xa1) && (c2 <= 0xfe)) + { + i = ((c1 - 0xa1) * 157 + (c2 - 0xa1) + 63) * 2; + dst[0] = BtoG[i++]; + dst[1] = BtoG[i]; + return; + } + } + dst[0] = BtoG_bad1; + dst[1] = BtoG_bad2; +} + + +static void +g2b(src, dst) + unsigned char *src, *dst; +{ + int i; + + if ((c2 >= 0xa1) && (c2 <= 0xfe)) + { + if ((c1 >= 0xa1) && (c1 <= 0xa9)) + { + i = ((c1 - 0xa1) * 94 + (c2 - 0xa1)) * 2; + dst[0] = GtoB[i++]; + dst[1] = GtoB[i]; + return; + } + else if ((c1 >= 0xb0) && (c1 <= 0xf7)) + { + i = ((c1 - 0xb0 + 9) * 94 + (c2 - 0xa1)) * 2; + dst[0] = GtoB[i++]; + dst[1] = GtoB[i]; + return; + } + } + dst[0] = GtoB_bad1; + dst[1] = GtoB_bad2; +} + + +static char * +hzconvert(src, dst, dbcvrt) + char *src; /* source char buffer pointer */ + char *dst; /* destination char buffer pointer */ + void (*dbcvrt) (); /* º~¦r 2-byte conversion funcntion */ +{ + int len; + char *end, *p; + + conv_init(); + + p = dst; + len = strlen(src); + end = src + len; + while (src < end) + { + if (*src & 0x80) /* hi-bit on ªí¥Ü¬Oº~¦r */ + { + dbcvrt(src, p); + src += 2; /* ¤@¦¸Âà¤G½X */ + p += 2; + } + else + { + /* *p = *src; */ /* ¤£»Ýn¡A¦]¬°¦b b52gb()¡Bgb2b5() ªºÀ³¥Î¸Ì src == dst */ + src++; + p++; + } + } + /* dst[len] = '\0'; */ /* ¤£»Ýn¡A¦]¬°¦b b52gb()¡Bgb2b5() ªºÀ³¥Î¸Ì src == dst */ + + return dst; +} + + +void +b52gb(str) + char *str; +{ + hzconvert(str, str, b2g); +} + + +void +gb2b5(str) + char *str; +{ + hzconvert(str, str, g2b); +} diff --git a/innbbsd/history.c b/innbbsd/history.c new file mode 100644 index 0000000..b4893da --- /dev/null +++ b/innbbsd/history.c @@ -0,0 +1,135 @@ +/*-------------------------------------------------------*/ +/* history.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : innbbsd history */ +/* create : 04/04/01 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "innbbsconf.h" + + +typedef struct +{ + time_t htime; /* ¥[¤J history Àɪº®É¶¡ */ + int hash; /* ¬°¤F§Ö³t·j´M */ + char msgid[256]; /* message id (°²³] 256 ¤w°÷ªø) */ + char board[BNLEN + 1]; + char xname[9]; +} HIS; + + +void +HISmaint() /* ºûÅ@ history ÀÉ¡A±N¹L¦ªº history §R°£ */ +{ + int i, fd, total; + char fpath[64]; + time_t now; + struct stat st; + HIS *data, *hhead, *htail, *his; + + /* ¥u«O¯d³Ìªñ EXPIREDAYS ¤Ñªº history */ + time(&now); + now = time(NULL) - EXPIREDAYS * 86400; + + for (i = 0; i < 32; i++) + { + sprintf(fpath, "innd/history/%02d", i); + + if ((fd = open(fpath, O_RDONLY)) < 0) + continue; + + fstat(fd, &st); + data = (HIS *) malloc(total = st.st_size); + total = read(fd, data, total); + close(fd); + + hhead = data; + htail = data + total / sizeof(HIS); + total = 0; + + for (his = hhead; his < htail; his++) + { + if (his->htime > now) /* ³oµ§ history ¤£³Q¬å */ + { + memcpy(hhead, his, sizeof(HIS)); + hhead++; + total += sizeof(HIS); + } + } + + if ((fd = open(fpath, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0) + { + write(fd, data, total); + close(fd); + } + + free(data); + } +} + + +void +HISadd(msgid, board, xname) /* ±N (msgid, path, xname) ¦¹°t¹ï°O¿ý¦b history ¤¤ */ + char *msgid; + char *board; + char *xname; +{ + HIS his; + char fpath[64]; + + memset(&his, 0, sizeof(HIS)); + + time(&(his.htime)); + his.hash = str_hash(msgid, 1); + str_ncpy(his.msgid, msgid, sizeof(his.msgid)); + str_ncpy(his.board, board, sizeof(his.board)); + str_ncpy(his.xname, xname, sizeof(his.xname)); + + /* ¨Ì msgid ±N history ¥´´²¦Ü 32 ÓÀÉ®× */ + sprintf(fpath, "innd/history/%02d", his.hash & 31); + rec_add(fpath, &his, sizeof(HIS)); +} + + +int /* 1:¦bhistory¤¤ 0:¤£¦bhistory¤¤ */ +HISfetch(msgid, board, xname) /* ¬d¸ß history ¤¤¡Amsgid µoªí¥h¤Fþ¸Ì */ + char *msgid; + char *board; /* ¶Ç¥X¦b history ¤¤ªº°O¿ýªº¬ÝªO¤ÎÀɦW */ + char *xname; +{ + HIS his; + char fpath[64]; + int fd, hash; + int rc = 0; + + /* ¦pªG¦P¤@ msgid µoªí¥h«Ü¦hӬݪO¡A¨º»ò¥Ø«e¥u·|¦^¶Ç²Ä¤@ӬݪO¤ÎÀɦW */ + + /* ¨Ì msgid §ä¥X¦bþ¤@¥÷ history Àɮפ¤ */ + hash = str_hash(msgid, 1); + sprintf(fpath, "innd/history/%02d", hash & 31); + + /* ¥h¸Ó¥÷ history Àɮפ¤§ä¬Ý¬Ý¦³¨S¦³ */ + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + lseek(fd, 0, SEEK_SET); + while (read(fd, &his, sizeof(HIS)) == sizeof(HIS)) + { + /* ¥Î hash ¥ý²Ê²¤¤ñ¹ï¡AY¬Û¦P¦A¥Î msgid §¹¾ã¤ñ¹ï */ + if ((hash == his.hash) && !strcmp(msgid, his.msgid)) + { + if (board) + strcpy(board, his.board); + if (xname) + strcpy(xname, his.xname); + rc = 1; + break; + } + } + close(fd); + } + + return rc; +} diff --git a/innbbsd/innbbsconf.h b/innbbsd/innbbsconf.h new file mode 100644 index 0000000..02c860d --- /dev/null +++ b/innbbsd/innbbsconf.h @@ -0,0 +1,70 @@ +/*-------------------------------------------------------*/ +/* innbbsconf.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : innbbsd configurable settings */ +/* create : 95/04/27 */ +/* modify : / / */ +/* author : skhuang@csie.nctu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#ifndef _INNBBSCONF_H_ +#define _INNBBSCONF_H_ + +#include "bbs.h" + +#include <sys/wait.h> + + +/* ----------------------------------------------------- */ +/* ¤@¯ë²ÕºA */ +/* ----------------------------------------------------- */ + +#define VERSION "0.8-MapleBBS" /* ª©¥»«Å§i */ + +#define MYBBSID BBSNAME2 /* Path: ¥Î^¤å¯¸¦W */ + +#define LOGFILE "innd/innbbs.log" /* °O¿ýÀɸô®| */ + + +/* ----------------------------------------------------- */ +/* innbbsd ªº³]©w */ +/* ----------------------------------------------------- */ + + /* --------------------------------------------------- */ + /* channel ªº³]©w */ + /* --------------------------------------------------- */ + +#define MAXCLIENT 20 /* Maximum number of connections accepted by innbbsd */ + +#define ChannelSize 4096 +#define ReadSize 4096 + + /* --------------------------------------------------- */ + /* rec_article ªº³]©w */ + /* --------------------------------------------------- */ + +#define _NoCeM_ /* No See Them ¾×«H¾÷¨î */ + +#undef _KEEP_CANCEL_ /* «O¯d cancel ªº¤å³¹©ó deleted ªO */ + + +/* ----------------------------------------------------- */ +/* bbslink ªº³]©w */ +/* ----------------------------------------------------- */ + +#define MAX_ARTS 100 /* ¨CÓ newsgroup ¤@¦¸³Ì¦h¦¬´X«Ê«H */ + +#define BBSLINK_EXPIRE 3600 /* bbslink Y°õ¦æ¹L¤[¡A´Nª½±µ kill ±¼(¬í) */ + + +/* ----------------------------------------------------- */ +/* History Âà«H°O¿ýºûÅ@ */ +/* ----------------------------------------------------- */ + +#define EXPIREDAYS 5 /* Âà«H°O¿ý«O¯d¤Ñ¼Æ */ +#define HIS_MAINT_HOUR 4 /* time to maintain history database */ +#define HIS_MAINT_MIN 30 /* time to maintain history database */ + +#endif /* _INNBBSCONF_H_ */ diff --git a/innbbsd/inntobbs.c b/innbbsd/inntobbs.c new file mode 100644 index 0000000..0e868cf --- /dev/null +++ b/innbbsd/inntobbs.c @@ -0,0 +1,242 @@ +/*-------------------------------------------------------*/ +/* inntobbs.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : innbbsd INN to BBS */ +/* create : 95/04/27 */ +/* update : / / */ +/* author : skhuang@csie.nctu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "innbbsconf.h" +#include "bbslib.h" +#include "inntobbs.h" + + +typedef struct Header +{ + char *name; + int id; +} header_t; + + +enum HeaderValue /* ©Ò¦³¦³¥Î¨ìªº header */ +{ + SUBJECT_H, + FROM_H, + DATE_H, + PATH_H, + GROUP_H, + MSGID_H, + + SITE_H, + POSTHOST_H, + CONTROL_H, + + LASTHEADER +}; + + +/* ¥u¹ï³o¨ÇÀÉÀY¦³¿³½ì */ +static header_t headertable[LASTHEADER] = +{ + "Subject", SUBJECT_H, + "From", FROM_H, + "Date", DATE_H, + "Path", PATH_H, + "Newsgroups", GROUP_H, + "Message-ID", MSGID_H, + + /* SITE_H (§t) ¥H¤U¬°«D¥²³ÆÀÉÀY */ + "Organization", SITE_H, + "NNTP-Posting-Host", POSTHOST_H, + "Control", CONTROL_H, +}; + + +char *NODENAME; +char *BODY; +char *SUBJECT, *FROM, *DATE, *PATH, *GROUP, *MSGID, *POSTHOST, *SITE, *CONTROL; + + +static int +header_cmp(a, b) + header_t *a, *b; +{ + return str_cmp(a->name, b->name); +} + + +static int +header_value(inputheader) + char *inputheader; +{ + header_t key, *findkey; + static int already_init = 0; + + if (!already_init) + { + qsort(headertable, sizeof(headertable) / sizeof(header_t), sizeof(header_t), header_cmp); + already_init = 1; + } + + key.name = inputheader; + findkey = bsearch(&key, (char *) headertable, sizeof(headertable) / sizeof(header_t), sizeof(key), header_cmp); + if (findkey != NULL) + return findkey->id; + + return -1; +} + + +static int +is_loopback(path, token, len) + char *path, *token; + int len; +{ + int cc; + + if (!path) /* Y¨S¦³ PATH «h¤£Àˬd */ + return 0; + + for (;;) + { + cc = path[len]; + if ((!cc || cc == '!') && !str_ncmp(path, token, len)) + return 1; + + for (;;) + { + cc = *path; + if (!cc) + return 0; + path++; + if (cc == '!') + break; + } + } + + return 0; +} + + +int /* 1:¦¨¥\ 0:PATH¥]¬A¦Û¤v -1:ÀÉÀY¤£§¹¾ã */ +readlines(data) /* Ū¤JÀÉÀY©M¤º¤å */ + char *data; +{ + int i; + char *front, *ptr, *hptr; + static char *HEADER[LASTHEADER]; + + for (i = 0; i < LASTHEADER; i++) + HEADER[i] = NULL; + BODY = NULL; + + ptr = data; + + for (;;) + { + front = ptr + 1; + if (*front == '\n') + { + /* skip leading empty lines */ + do + { + front++; + } while (*front == '\n'); + + BODY = front; + break; + } + + ptr = (char *) strchr(front, '\n'); + if (!ptr) + break; + *ptr = '\0'; + + hptr = (char *) strchr(front, ':'); + if (hptr && hptr[1] == ' ') + { + *hptr = '\0'; + + i = header_value(front); + if (i >= 0) /* ¬O¦³¿³½ìªºÀÉÀY */ + { + HEADER[i] = hptr + 2; + + /* merge multi-line header */ + + hptr = ptr; + + /* while (ptr[1] == ' ') */ + /* Thor.990110: ¦³ªº¬O¥Î \t ¥NªíÁÙ¦³ */ + while (ptr[1] == ' ' || ptr[1] == '\t') + { + /* while (*++ptr == ' ') ; */ + do + { + ++ptr; + } while (*ptr == ' ' || *ptr == '\t'); + + for (;;) + { + i = *ptr; + if (i == '\n') + break; + if (i == '\0') + { + ptr--; + break; + } + ptr++; + *hptr++ = i; + } + + *hptr = '\0'; + } + + /* well, ptr point to end of line */ + } + } + + front = ptr; + } + + /* ÀˬdÀÉÀYÄæ¦ì¬O§_§¹¾ã */ + for (i = 0; i < POSTHOST_H; i++) /* POSTHOST_H (§t) ¥H¤U¬°«D¥²³ÆÀÉÀY */ + { + if (!HEADER[i] || !*HEADER[i]) + return -1; + } + if (!BODY || !*BODY) + return -1; + + SUBJECT = HEADER[SUBJECT_H]; + FROM = HEADER[FROM_H]; + DATE = HEADER[DATE_H]; + PATH = HEADER[PATH_H]; + GROUP = HEADER[GROUP_H]; + MSGID = HEADER[MSGID_H]; + SITE = HEADER[SITE_H]; + POSTHOST = HEADER[POSTHOST_H]; + CONTROL = HEADER[CONTROL_H]; + + /* SITE_H (§t) ¥H¤U¬°«D¥²³ÆÀÉÀY¡A¦ý¤´nÀˬd¬O§_¬°ªÅ¦r¦ê */ + if (SITE && !*SITE) + SITE = NULL; + if (POSTHOST && !*POSTHOST) + POSTHOST = NULL; + if (CONTROL && !*CONTROL) + return -1; + + if (!CONTROL) /* ¤@¯ë«H¥ó */ + { + /* itoc.030223.µù¸Ñ: ¬Ý¨ì path ¸Ì±¦³¦Û¤v¯¸ªº¦WºÙ¥H«á¡A«H´N¤£·|¶i¨Ó¡A + Á×§K¯¸¤Wªº«H³Q bbslink °e¥h news server ¥H«á¡A¤S³Q¦Û¤v¥Î bbsnnrp ¨ú¦^ */ + if (is_loopback(PATH, MYBBSID, strlen(MYBBSID))) + return 0; + } + + return 1; +} diff --git a/innbbsd/inntobbs.h b/innbbsd/inntobbs.h new file mode 100644 index 0000000..c593abf --- /dev/null +++ b/innbbsd/inntobbs.h @@ -0,0 +1,17 @@ +#ifndef _INNTOBBS_H_ +#define _INNTOBBS_H_ + +/* inntobbs.c */ +extern char *NODENAME; +extern char *BODY; +extern char *SUBJECT, *FROM, *DATE, *PATH, *GROUP, *MSGID, *SITE, *POSTHOST, *CONTROL; + +/* inntobbs.c */ +extern int readlines(char *data); + +/* history.c */ +extern void HISmaint(); +extern void HISadd(char *msgid, char *board, char *xname); +extern int *HISfetch(char *msgid, char *board, char *xname); + +#endif /* _INNTOBBS_H_ */ diff --git a/innbbsd/nntp.h b/innbbsd/nntp.h new file mode 100644 index 0000000..72dc5fa --- /dev/null +++ b/innbbsd/nntp.h @@ -0,0 +1,145 @@ +/* $Revision: 1.1.1.1 $ +** +** Here be a set of NNTP response codes as defined in RFC977 and elsewhere. +** The reponse codes are three digits, RFI, defined like this: +** R, Response: +** 1xx Informative message +** 2xx Command ok +** 3xx Command ok so far, send the rest of it. +** 4xx Command was correct, but couldn't be performed for +** some reason. +** 5xx Command unimplemented, or incorrect, or a serious +** program error occurred. +** F, Function: +** x0x Connection, setup, and miscellaneous messages +** x1x Newsgroup selection +** x2x Article selection +** x3x Distribution functions +** x4x Posting +** x8x Nonstandard extensions (AUTHINFO, XGTITLE) +** x9x Debugging output +** I, Information: +** No defined semantics +*/ +#define NNTP_HELPOK_VAL 100 +#define NNTP_BAD_COMMAND_VAL 500 +#define NNTP_BAD_COMMAND "500 Syntax error or bad command" +#define NNTP_TEMPERR_VAL 503 +#define NNTP_ACCESS "502 Permission denied" +#define NNTP_ACCESS_VAL 502 +#define NNTP_GOODBYE_ACK "205" +#define NNTP_GOODBYE_ACK_VAL 205 +#define NNTP_GOODBYE "400" +#define NNTP_GOODBYE_VAL 400 +#define NNTP_HAVEIT "435 Duplicate" +#define NNTP_HAVEIT_BADID "435 Bad Message-ID" +#define NNTP_HAVEIT_VAL 435 +#define NNTP_LIST_FOLLOWS "215" +#define NNTP_LIST_FOLLOWS_VAL 215 +#define NNTP_HELP_FOLLOWS "100 Legal commands" +#define NNTP_HELP_FOLLOWS_VAL 100 +#define NNTP_NOTHING_FOLLOWS_VAL 223 +#define NNTP_ARTICLE_FOLLOWS "220" +#define NNTP_ARTICLE_FOLLOWS_VAL 220 +#define NNTP_NEWGROUPS_FOLLOWS_VAL 231 +#define NNTP_HEAD_FOLLOWS "221" +#define NNTP_HEAD_FOLLOWS_VAL 221 +#define NNTP_BODY_FOLLOWS_VAL 222 +#define NNTP_OVERVIEW_FOLLOWS_VAL 224 +#define NNTP_DATE_FOLLOWS_VAL 111 +#define NNTP_POSTOK "200" +#define NNTP_POSTOK_VAL 200 +#define NNTP_START_POST_VAL 340 +#define NNTP_NOPOSTOK_VAL 201 +#define NNTP_SLAVEOK_VAL 202 +#define NNTP_REJECTIT_VAL 437 +#define NNTP_REJECTIT_EMPTY "437 Empty article" +#define NNTP_DONTHAVEIT "430" +#define NNTP_DONTHAVEIT_VAL 430 +#define NNTP_RESENDIT_NOHIST "436 Can't write history" +#define NNTP_RESENDIT_NOSPACE "436 No space" +#define NNTP_RESENDIT_VAL 436 +#define NNTP_POSTEDOK "240 Article posted" +#define NNTP_POSTEDOK_VAL 240 +#define NNTP_POSTFAIL_VAL 441 +#define NNTP_GROUPOK_VAL 211 +#define NNTP_SENDIT "335" +#define NNTP_SENDIT_VAL 335 +#define NNTP_SYNTAX_USE "501 Bad command use" +#define NNTP_SYNTAX_VAL 501 +#define NNTP_TOOKIT "235" +#define NNTP_TOOKIT_VAL 235 +#define NNTP_NOTINGROUP "412 Not in a newsgroup" +#define NNTP_NOTINGROUP_VAL 412 +#define NNTP_NOSUCHGROUP "411 No such group" +#define NNTP_NOSUCHGROUP_VAL 411 +#define NNTP_NEWNEWSOK "230 New news follows" +#define NNTP_NOARTINGRP "423 Bad article number" +#define NNTP_NOARTINGRP_VAL 423 +#define NNTP_NOCURRART "420 No current article" +#define NNTP_NOCURRART_VAL 420 +#define NNTP_NONEXT_VAL 421 +#define NNTP_NOPREV_VAL 422 +#define NNTP_CANTPOST "440 Posting not allowed" +#define NNTP_CANTPOST_VAL 440 + + +/* +** The first character of an NNTP reply can be used as a category class. +*/ +#define NNTP_CLASS_OK '2' +#define NNTP_CLASS_ERROR '4' +#define NNTP_CLASS_FATAL '5' + + +/* +** The NNTP protocol currently has no way to say "offer me this article +** later, but don't close the connection." That will be fixed in NNTP2. +#define NNTP_RESENDIT_LATER "?" +#define NNTP_RESENDIT_LATER_VAL ? +*/ + + +/* +** Authentication commands from the RFC update (not official). +*/ +#define NNTP_AUTH_NEEDED "480" +#define NNTP_AUTH_NEEDED_VAL 480 +#define NNTP_AUTH_BAD "481" +#define NNTP_AUTH_NEXT "381" +#define NNTP_AUTH_NEXT_VAL 381 +#define NNTP_AUTH_OK "281" +#define NNTP_AUTH_OK_VAL 281 +#define NNTP_AUTH_REJECT_VAL 482 + +/* +** XGTITLE, from ANU news. +*/ +#define NNTP_XGTITLE_BAD 481 /* Yes, 481. */ +#define NNTP_XGTITLE_OK 282 + +#define NNTP_STRLEN 512 + +/* +** For tin newsreader +*/ +#define OK_XINDEX 218 /* Tin style group index file follows */ +#define OK_XMOTD 217 /* Motd (message of the day) file follows */ +#define ERR_XINDEX 418 /* No tin style index file for newsgroup */ +#define ERR_XMOTD 417 /* No motd (message of the day) file */ + +/* For DBZ server */ +#define NNTP_ADDHIST_OK 283 /* addhist OK */ +#define NNTP_GREPHIST_OK 284 /* grephist OK */ +#define NNTP_MIDCHECK_OK 285 /* grephist OK */ +#define NNTP_SHUTDOWN_OK 286 /* grephist OK */ +#define NNTP_RELOAD_OK 287 /* grephist OK */ +#define NNTP_MODE_OK 101 /* grephist OK */ +#define NNTP_VERBOSELOG_OK 289 /* grephist OK */ +#define NNTP_ADDHIST_BAD 483 /* addhist fail */ +#define NNTP_GREPHIST_BAD 484 /* grephist fail */ +#define NNTP_MIDCHECK_BAD 485 /* grephist fail */ +#define NNTP_SHUTDOWN_BAD 486 /* grephist fail */ +#define NNTP_RELOAD_BAD 487 /* grephist fail */ +#define NNTP_MODE_BAD 488 /* grephist fail */ +#define NNTP_VERBOSELOG_BAD 489 /* grephist fail */ diff --git a/innbbsd/nocem.c b/innbbsd/nocem.c new file mode 100644 index 0000000..a67ef00 --- /dev/null +++ b/innbbsd/nocem.c @@ -0,0 +1,508 @@ +/*-------------------------------------------------------*/ +/* nocem.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : NoCeM-INNBBSD */ +/* create : 99/02/25 */ +/* update : / / */ +/* author : leeym@cae.ce.ntu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 /* itoc.030109.µù¸Ñ: nocem.c ªº¬yµ{ */ + ±q rec_article.c ¦¬¨ì receive_nocem() ¥H«á + receive_nocem() ¡÷ NCMparse() §â notice parse ¥X¨Ó ¡÷ NCMverify() ÅçÃÒ¬O¤£¬O¯uªº + ¡÷ NCMcancel() ¦A°e¦^ rec_article.c ªº cancel_article() ³B²z +#endif + + +#include "innbbsconf.h" + +#ifdef _NoCeM_ + +#include "bbslib.h" +#include "inntobbs.h" +#include "nocem.h" + + +/* ÅçÃÒñ¦W¡G¥H¤U¤GªÌ¦Ü¦h¥u¯à¿ï¤@ªÌ #define (¥i¥H¤GªÌ³£ #undef) */ +#undef PGP /* ¥²¶·¸Ë¦³ pgp5 ¤~¥i define¡A¨Ã½ÐÀˬd pgpv ªº¸ô®| */ +#undef GPG /* ¥²¶·¸Ë¦³ gpg ¤~¥i define¡A¨Ã½ÐÀˬd gpg ªº¸ô®| */ + +static int num_spammid = 0; +static char NCMVER[20]; +static char ISSUER[80]; +static char TYPE[40]; +static char ACTION[20]; +static char SPAMMID_NOW[80]; +static char SPAMMID[MAXSPAMMID][80]; +static char errmsg[512] = "nothing"; + + +/* ----------------------------------------------------- */ +/* NCM maintain */ +/* ----------------------------------------------------- */ + + +ncmperm_t * +search_issuer(issuer, type) + char *issuer; + char *type; /* Y type == NULL ªí¥Ü¥u¤ñ¹ï issuer */ +{ + ncmperm_t *find; + int i; + + for (i = 0; i < NCMCOUNT; i++) + { + find = NCMPERM + i; + if (strstr(issuer, find->issuer) && + (!type || !strcmp(find->type, "*") || !str_cmp(find->type, type))) + return find; + } + return NULL; +} + + +static void +NCMupdate(issuer, type) + char *issuer, *type; +{ + ncmperm_t ncm; + + memset(&ncm, 0, sizeof(ncmperm_t)); + str_ncpy(ncm.issuer, issuer, sizeof(ncm.issuer)); + str_ncpy(ncm.type, type, sizeof(ncm.type)); + ncm.perm = 0; + rec_add("innd/ncmperm.bbs", &ncm, sizeof(ncmperm_t)); + read_ncmperm(); +} + + +/* ----------------------------------------------------- */ +/* PGP verify */ +/* ----------------------------------------------------- */ + + +#ifdef PGP +static int +run_pgp(cmd, in, out) + char *cmd; + FILE **in, **out; +{ + int pin[2], pout[2], child_pid; + char fpath[64]; + + strcpy(fpath, BBSHOME "/.pgp"); + setenv("PGPPATH", fpath, 1); + + *in = *out = NULL; + + pipe(pin); + pipe(pout); + + if (!(child_pid = fork())) + { + /* We're the child. */ + close(pin[1]); + dup2(pin[0], 0); + close(pin[0]); + + close(pout[0]); + dup2(pout[1], 1); + close(pout[1]); + + execl("/bin/sh", "sh", "-c", cmd, NULL); + _exit(127); + } + /* Only get here if we're the parent. */ + close(pout[1]); + *out = fdopen(pout[0], "r"); + + close(pin[0]); + *in = fdopen(pin[1], "w"); + + return child_pid; +} + + +static int +verify_buffer(buf, passphrase) + char *buf, *passphrase; +{ + FILE *pgpin, *pgpout; + char tmpbuf[1024] = " "; + int ans = NOPGP; + + setenv("PGPPASSFD", "0", 1); + run_pgp("/usr/local/bin/pgpv -f +batchmode=1 +OutputInformationFD=1", &pgpin, &pgpout); + if (pgpin && pgpout) + { + fprintf(pgpin, "%s\n", passphrase); /* Send the passphrase in, first */ + memset(passphrase, 0, strlen(passphrase)); /* Burn the passphrase */ + fprintf(pgpin, "%s", buf); + fclose(pgpin); + + *buf = '\0'; + fgets(tmpbuf, sizeof(tmpbuf), pgpout); + while (!feof(pgpout)) + { + strcat(buf, tmpbuf); + fgets(tmpbuf, sizeof(tmpbuf), pgpout); + } + + wait(NULL); + + fclose(pgpout); + } + + if (strstr(buf, "BAD signature made")) + { + strcpy(errmsg, "BAD signature"); + ans = PGPBAD; + } + else if (strstr(buf, "Good signature made")) + { + strcpy(errmsg, "Good signature"); + ans = PGPGOOD; + } + else if (strcpy(tmpbuf, strstr(buf, "Signature by unknown keyid:"))) + { + sprintf(errmsg, "%s ", strtok(tmpbuf, "\r\n")); + ans = PGPUN; + } + + unsetenv("PGPPASSFD"); + return ans; +} + + +static int /* return 0 success, otherwise fail */ +NCMverify() +{ + char passphrase[80] = "Haha, I am Leeym.."; + return verify_buffer(BODY, passphrase); +} +#endif /* PGP */ + + +/* ----------------------------------------------------- */ +/* GPG verify */ +/* ----------------------------------------------------- */ + + +#ifdef GPG +static int +run_gpg(cmd, in, out) + char *cmd; + FILE **in, **out; +{ + int pin[2], pout[2], child_pid; + char fpath[64]; + + strcpy(fpath, BBSHOME "/.gnupg"); + setenv("GPGPATH", fpath, 1); + + *in = *out = NULL; + + pipe(pin); + pipe(pout); + + if (!(child_pid = fork())) + { + /* We're the child. */ + close(pin[1]); + dup2(pin[0], 0); + close(pin[0]); + + close(pout[0]); + dup2(pout[1], 1); + close(pout[1]); + + execl("/bin/sh", "sh", "-c", cmd, NULL); + _exit(127); + } + /* Only get here if we're the parent. */ + close(pout[1]); + *out = fdopen(pout[0], "r"); + + close(pin[0]); + *in = fdopen(pin[1], "w"); + + return child_pid; +} + + +static int +verify_buffer(buf) + char *buf; +{ + FILE *pgpin, *pgpout; + char tmpbuf[1024] = " "; + int ans = NOPGP; + + setenv("PGPPASSFD", "0", 1); + run_gpg("/usr/local/bin/gpg --no-secmem-warning --verify", &pgpin, &pgpout); + if (pgpin && pgpout) + { + fprintf(pgpin, "%s", buf); + fclose(pgpin); + + *buf = '\0'; + fgets(tmpbuf, sizeof(tmpbuf), pgpout); + while (!feof(pgpout)) + { + strcat(buf, tmpbuf); + fgets(tmpbuf, sizeof(tmpbuf), pgpout); + } + + wait(NULL); + + fclose(pgpout); + } + + if (strstr(buf, "BAD signature made")) + { + strcpy(errmsg, "BAD signature"); + ans = PGPBAD; + } + else if (strstr(buf, "Good signature made")) + { + strcpy(errmsg, "Good signature"); + ans = PGPGOOD; + } + else if (strcpy(tmpbuf, strstr(buf, "Signature by unknown keyid:"))) + { + sprintf(errmsg, "%s ", strtok(tmpbuf, "\r\n")); + strcpy(KEYID, strrchr(tmpbuf, ' ') + 1); + ans = PGPUN; + } + + unsetenv("PGPPASSFD"); + return ans; +} + + +static int +NCMverify() +{ + return verify_buffer(BODY); +} +#endif /* GPG */ + + +/* ----------------------------------------------------- */ +/* parse NoCeM Notice Headers/Body */ +/* ----------------------------------------------------- */ + + +static int +readNCMheader(line) + char *line; +{ + if (!str_ncmp(line, "Version", strlen("Version"))) + { + str_ncpy(NCMVER, line + strlen("Version") + 2, sizeof(NCMVER)); + if (strcmp(NCMVER, "0.9")) + { + sprintf(errmsg, "unknown version: %s", NCMVER); + return P_FAIL; + } + } + else if (!str_ncmp(line, "Issuer", strlen("Issuer"))) + { + str_ncpy(ISSUER, line + strlen("Issuer") + 2, sizeof(ISSUER)); + FROM = ISSUER; + } + else if (!str_ncmp(line, "Type", strlen("Type"))) + { + str_ncpy(TYPE, line + strlen("Type") + 2, sizeof(TYPE)); + } + else if (!str_ncmp(line, "Action", strlen("Action"))) + { + str_ncpy(ACTION, line + strlen("Action") + 2, sizeof(ACTION)); + if (strcmp(ACTION, "hide")) + { + sprintf(errmsg, "unsupported action: %s", ACTION); + return P_FAIL; + } + } + + return P_OKAY; +} + + +static int +readNCMbody(line) + char *line; +{ + char buf[LINELEN], *group; + + strcpy(buf, line); + + if (!strstr(buf, "\t")) + return P_FAIL; + + group = strrchr(line, '\t') + 1; + + if (buf[0] == '<' && strstr(buf, ">")) + { + strtok(buf, "\t"); + strcpy(SPAMMID_NOW, buf); + } + + if (num_spammid && !strcmp(SPAMMID[num_spammid - 1], SPAMMID_NOW)) + return 0; + + if (search_newsfeeds_bygroup(group)) + strcpy(SPAMMID[num_spammid++], SPAMMID_NOW); +} + + +static int /* return 0 success, otherwise fail */ +NCMparse() +{ + char *fptr, *ptr; + int type = TEXT; + + if (!(fptr = strstr(BODY, "-----BEGIN PGP SIGNED MESSAGE-----"))) + { + strcpy(errmsg, "notice isn't signed"); + return P_FAIL; + } + + for (ptr = strchr(fptr, '\n'); ptr != NULL && *ptr != '\0'; fptr = ptr + 1, ptr = strchr(fptr, '\n')) + { + int ch = *ptr; + int ch2 = *(ptr - 1); + + *ptr = '\0'; + if (*(ptr - 1) == '\r') + *(ptr - 1) = '\0'; + + if (num_spammid > MAXSPAMMID) + return P_OKAY; + + if (!strncmp(fptr, "@@", 2)) + { + if (strstr(fptr, "BEGIN NCM HEADERS")) + { + type = NCMHDR; + } + else if (strstr(fptr, "BEGIN NCM BODY")) + { + if (NCMVER && ISSUER && TYPE && ACTION) + { + ncmperm_t *ncmt; + ncmt = (ncmperm_t *) search_issuer(ISSUER, TYPE); + if (ncmt == NULL) + { + NCMupdate(ISSUER, TYPE); + sprintf(errmsg, "unknown issuer: %s, %s", ISSUER, MSGID); + return P_UNKNOWN; + } + if (!ncmt->perm) + { + sprintf(errmsg, "disallow issuer: %s, %s", ISSUER, MSGID); + return P_DISALLOW; + } + } + else + { + strcpy(errmsg, "HEADERS syntax not correct"); + return P_FAIL; + } + type = NCMBDY; + } + else if (strstr(fptr, "END NCM BODY")) + { + *ptr = ch; + *(ptr - 1) = ch2; + break; + } + else + { + strcpy(errmsg, "NCM Notice syntax not correct"); + return P_FAIL; + } + *ptr = ch; + *(ptr - 1) = ch2; + continue; + } + + if (type == NCMHDR && readNCMheader(fptr) == P_FAIL) + return P_FAIL; + if (type == NCMBDY) + readNCMbody(fptr); + *ptr = ch; + *(ptr - 1) = ch2; + } + + if (NCMVER && ISSUER && TYPE && ACTION) + return P_OKAY; + + strcpy(errmsg, "HEADERS syntax not correct"); + return P_FAIL; +} + + +extern int cancel_article(); + + +static void +NCMcancel() +{ + int i; + + for (i = 0; i < num_spammid; i++) + cancel_article(SPAMMID[i]); +} + + +/* ----------------------------------------------------- */ +/* NoCeM-innbbsd */ +/* ----------------------------------------------------- */ + + +static void +initial_nocem() +{ + memset(SPAMMID[0], 0, strlen(SPAMMID[0]) * num_spammid); + num_spammid = 0; + memset(SPAMMID_NOW, 0, strlen(SPAMMID_NOW)); +} + + +int /* 0:success -1:fail */ +receive_nocem() +{ + int cc; + + initial_nocem(); + + cc = NCMparse(); + + if (cc != P_OKAY) + { + if (cc != P_DISALLOW) + bbslog("<nocem> :Warn: %s\n", errmsg); + return 0; + } + + if (!num_spammid) /* nothing to cancel */ + return 0; + +#if (defined(PGP) || defined(GPG)) + cc = NCMverify(); + + if (cc != PGPGOOD) + { + bbslog("<nocem> :Warn: %s, %s, %s\n", errmsg, MSGID, ISSUER); + return -1; + } +#endif + + NCMcancel(); + + return 0; +} +#endif /* _NoCeM_ */ diff --git a/innbbsd/nocem.h b/innbbsd/nocem.h new file mode 100644 index 0000000..92033b5 --- /dev/null +++ b/innbbsd/nocem.h @@ -0,0 +1,41 @@ +/* + NoCeM-INNBBSD + Yen-Ming Lee <leeym@cae.ce.ntu.edu.tw> +*/ + +#ifndef _NOCEM_H_ +#define _NOCEM_H_ + +#define NCMINNBBSVER "NoCeM-INNBBSD-0.8" /* ª©¥»«Å§i */ + + +#define TEXT 0 +#define NCMHDR 1 +#define NCMBDY 2 + +#define NOPGP -1 +#define PGPGOOD 0 +#define PGPBAD 1 +#define PGPUN 2 + +#define P_OKAY 0 +#define P_FAIL -1 +#define P_UNKNOWN -2 +#define P_DISALLOW -3 + +#define MAXSPAMMID 10000 +#define LINELEN 512 + + +/* bbslib.c */ +extern ncmperm_t *NCMPERM; +extern int NCMCOUNT; + +/* receive_article.c */ +extern newsfeeds_t *search_newsfeeds_bygroup(); + +/* nocem.c */ +extern ncmperm_t *search_issuer(); +extern int receive_nocem(); + +#endif /* _NOCEM_H_ */ diff --git a/innbbsd/nocem/CHANGES.nocem b/innbbsd/nocem/CHANGES.nocem new file mode 100644 index 0000000..3832c25 --- /dev/null +++ b/innbbsd/nocem/CHANGES.nocem @@ -0,0 +1,94 @@ +NoCeM-innbbsd-patch (¥H¤U²ºÙ ncm-innbbsd) +CHANGES + +ver 0.80 +1-9-04 ¤ä´© GPG + (·PÁ AlanSung) + +ver 0.71 +5-23-01 ¸É¤W¤@¨Ç¿ù»~°T®§, ×¥¿ NCMparse() + +ver 0.70 +5-11-01 ×¥¿ NCMparse ªº "END NCM BODY" ³¡¤À + (·PÁ lcr.bbs@server.old-castle.org) + +ver 0.69 +11-5-00 ×¥¿ NCMparse() ¦w¥þ©Ê°ÝÃD + (·PÁ DarkKiller.bbs@abpe.org) + +ver 0.68 +11-4-00 ×¥¿ NCMparse() ¦w¥þ©Ê°ÝÃD + (·PÁ DarkKiller.bbs@abpe.org) + +ver 0.67 +11-3-00 ×¥¿ NCMparse() ¦w¥þ©Ê°ÝÃD + (·PÁ DarkKiller.bbs@abpe.org) + ¹w³]§ï¦^¨Ï¥Î PGP ÅçÃÒ, ¤£¥Î PGP ªÌ½Ð¦Û¦æ #undef PGP5 + (·PÁ Amis.bbs@bbs.ee.nthu.edu.tw) + +ver 0.66 +5-19-00 ¥Î stdarg.h ¨ú¥N varargs.h, ×¥¿ SOLARIS ªº va_start() °ÝÃD + (·PÁ edwardc@concorde.upma.net) + +ver 0.65 +4-26-00 ¥[¤J search_issuer_type() , ¤À§O±µ¦¬¦P¤@ issuer ¤£¦P type ªº notice + ¼W¥[ MAXSPAMMID ¨ì 10000 + ·s¼W LINELEN, ³]©w¬° 512 + ¹w³]§ï¬°¤£¨Ï¥Î PGP ÅçÃÒ. + NCMregister() §¹¦¨¶¥¬q©Ê²Îp¥ô°È, ¤£·Q¥[¤J²Îp, ©ÎªÌ³s¦Ü TANet ³t«× + ¤£§Öªº¯¸¥x, ¥i¦b nocem.h ³]©w #define DONT_REGISTER ¤£¦C¤J²Îp + +ver 0.63 +2-13-00 ¥[¤J¹ï M3-innbbsd ªº patch + (·PÁ mat.bbs@fall.twbbs.org) + M3 ªº BODY ¤w±N \r ³B²z±¼, ©Ò¥Hì¥ý§ì¦æ§Àªº \r ±N·|§ì¤£¨ì + §ó¥¿ v0.6 ¤å¥ó INSTALL.nocem 4.b ¿ù»~ªº¦a¤è + * ¹ï¨Ï¥Î v0.6 ¦ÓµLªk¹B§@ªº M3 ¯¸ªøÌPºp * + +ver 0.62 +1-24-00 ¥[¤J tcpcommand() ªº Solaris patch + (·PÁ edwardc.bbs@drogon.seed.net.tw) + ¥[¤J PGP5 ªº #define ¥H¤Î #if .. #endif, ¥i¿ï¾ÜÃö³¬ PGP5 ÅçÃÒ + +ver 0.6 +1-17-00 «·s¾ã²z¤@¤U NCMregister(), §ï¥Î gethostname() + §K±o¦³ bbsadm ³s Makefile ªº ADMINUSER ³£Ãi±o§ï + ¥[¤J¹ï Maple3 ªº¦w¸Ë»¡©ú + +ver 0.51 +5-21-99 ·s¼W NCMregister(), ¬ö¿ý NoCeM-innbbsd ¨Ï¥Î±¡§Î. + +ver 0.5 +3-6-99 §ó·s¤å¥ó +3-5-99 ±N strcasestr() ´«¦¨ strstr(). +3-4-99 de ±¼¤@Ó«ÜÄY«ªº bug: SPAMMID ¤£¨î°}¦C¤j¤pªº¸Ü±N·|¶W¥Î, + »\±¼¨ä¥LÅܼÆ.. ³y¦¨ innbbsd ±¾±¼. + (¯S§O¹³¬O¦Y¨ì nocem@newsgate.nctu.edu.tw ¤@½g notice ªº Count ¤C¦Ê¦h) + ¾ã²zµ{¦¡½X, Beta release.. + +ver 0.43 +3-3-99 ×§ï receive_nocem(), µo²{¤£¬O notice §Y§ï receive_article() + +ver 0.42 +3-2-99 ×§ï cancel_article_front(), ¤¹³\ Issuer ¬å«H, ¨Ã°t¦X×¥¿»¡©ú¤å¥ó + +ver 0.41 +3-2-99 ×§ï NCMverify(); + +ver 0.4 +3-1-99 ²Ó³¡¾ã¦X, ÅܼƳB²z, §ï¥Î NCMfunction() ²Î¤@®æ¦¡´£°ªµ{¦¡¥iŪ©Ê + +ver 0.3 +2-28-99 ·s¼W PGP verify ¤§Ã±¦WÀˬd + ·s¼W NCMupdate ¦Û°Ê§ó·s³]©wÀÉ + §ï¥Ñ search_group ¨Ó¤ñ¹ï¤å³¹, ´î¤Ö DBfetch ªº¦¸¼Æ, ¤j´T´£°ª®Ä¯à. + +ver 0.2 +2-27-99 ·s¼W ncmperm.bbs ¤§ Issuer Åv±±¨î + +ver 0.1 +2-26-99 ½s¼g ncm-innbbsd ¥Dµ{¦¡ + ¤ÀªR NCM 0.9 ¤§ NCM HEADERS + ¤ÀªR NCM ¤§ NCM BODY + ¤ÀªR NCM 0.93 ¤§ NCM HEADERS +2-25-99 °Ñ¦Ò ncmspool-0.92.3b ¤Î c-nocem-3.2 ¨M©w ncm-innbbsd ¤§¹B§@¤è¦¡ diff --git a/innbbsd/nocem/NOCEM b/innbbsd/nocem/NOCEM new file mode 100644 index 0000000..20d42dc --- /dev/null +++ b/innbbsd/nocem/NOCEM @@ -0,0 +1,140 @@ +§@ªÌ: benjamin («¢~) ¬ÝªO: benjamin +¼ÐÃD: NoCeM ²¤¶ +®É¶¡: Fri Mar 5 05:03:38 1999 + + + NoCeM ²¤¶ + +1.NoCeM²¤¶ + + NoCeMªºµoµ¬°(No See 'Em, ¤]´N¬ONo See Them), ¨ä¥Dnªº¥Øªº¬O³B²z²{¦b + ±`¨£ªº SPAM, ¾A¥Îªº¹ï¹³¬Û·í¼sªx, ±q news server ªººÞ²zû¨ì¤@¯ë¾\Ū + NEWS ªº¨Ï¥ÎªÌ³£¥i¥[¤J. + + ¨C¦ì¨Ï¥ÎªÌ¥i±N¥L¦bºô¸ô¤W»{¬°¤£È±o¾\Ū(©Îȱo¾\Ūªº¤å³¹), ¾ã²z¥X¨Ó, + «ö·Ó¤@©wªº®æ¦¡ (NoCeM¦³¯S§O³W©w®æ¦¡), ±N¬ÛÃöªº¸ê®Æ(message-id)»s¦¨¤@ + ½g¤å³¹ (¦bNoCeM¤¤ºÙ¬°notice), §Q¥Î¦UºØºÞ¹D±N³o¨Ç¸ê®Æ´²¼½µ¹¨ä¥Lªº¨Ï¥Î + ªÌ, ´²¼½ªººÞ¹D¨Ã¨S¦³¨î, mailing list, web, news³£¬O±`¨£ªº¤è¦¡. + + ¨ä¥Lªº¨Ï¥ÎªÌ«h¥i±µ¨ü³o¨Çnotice, ±µ¨üµo¤åªÌªº«ØÄ³, ¾\Ū©ÎªÌ©Ú¬Ý¤å³¹, + ¨Ï¥ÎªÌ¦³µ´¹ïªºÅv§Q¥i¥H¿ï¾Ü¬O§_±µ¨ü³o¨Çnotice, ¦pªG¨Ï¥ÎªÌ«H¥ôµo¥X + noticeªº¨Ï¥ÎªÌ, ¨º»ò¥i¥H¿ï¾Ü±µ¨ü¥Lªº«ØÄ³, ©Ú¬Ý¬Y¨Ç¤å³¹, ¤Ï¤§, ¨Ï¥ÎªÌ + ¤]¦³¥R¥÷ªº¦Û¥Ñ¥i¥H¿ï¾Ü¤£¥[²z·|. + + ¯S§O«nªº¤@ÂI, ©Ò¦³ªºnotice¥²¶·¸g¹Lµo¤åªÌªº PGP ñ¦W, ¦p¦¹¥i¥H½T©w + notice¤£·|³Q¥ô¦ó¤H°°³y©Î«§ï. + +2.¹ê»Úªº°µªk¤ÎÀ³¥Î + + ¤W±´£¨ì¨Ï¥ÎªÌ±µ¨ì notice «á¥i¥H±µ¨ü«ØÄ³©Ú¬Ý¤å³¹, ¹ê»ÚªºÀ³¥Î¥i¤À: + ¤@¯ë¨Ï¥ÎªÌ»P news server ºÞ²zªÌ¨Ó»¡©ú + + ¤@¯ë¨Ï¥ÎªÌ: + + ¨C¦ì¨Ï¥ÎªÌ¥i¥H¦Û¦æ³]©w±µ¨ü¨º¨Ç¤H°e¥Xªº notice, ·í¨Ï¥ÎªÌ¦b¾\ۤ峹¤§«e + ¥ý¨ú±o nocem notice, µM«á°w¹ï¨Ï¥ÎªÌªº³]©w°µ PGP ñ¦WªºÀˬd, Àˬd³q¹L + «á¤~Ä~Äò¶i¦æ¤U¤@Ó¨BÆJ. + + è¤~´£¨ì notice ¥i¤À¬°«ØÄ³¾\Ū(show), ©Î©Ú¬Ý(hide), ¨Ó§ó°Ê¨Ï¥ÎªÌªº + .newsrcÀÉ, ¤Z¬O³QÂk¬°hideªº¤å³¹, ·|¦b .newsrc¤W°µ¤W¼Ð°O, ¨Ï±o¨Ï¥ÎªÌ±µ¤U + ¨Ó¾\ۤ峹®É, ¸Ó¤å³¹·|¦Û°Ê³Q¹LÂo±¼©Î³Q³]¬°¤wŪ, ¦Ü©óÂkÃþ¬°showªº¤å³¹ + ¤]°µ¯S§O¼Ð°O±N¨äÅã¥Ü¥X¨Ó + + ¥H¥Ø«e¨ÓÁ¿, hide¬O¸û±`³Q¨Ï¥Îªº, ©Ò¦³ªºspam³£·|³QÂkÃþ¬°hide. + + ¦]¦¹, ¦b¨Ï¥ÎªÌ¾\Ū®É, ´N¤w¸g¬Ý¤£¨ì³o½g¤å³¹, ¤£¹L, ³o½g¤å³¹¨ÌµM¦s¦b news + server¤§¤¤, ¨Ã¤£·|³Q§R°£ + + ²{¦b¤w¦³µo®i¬ÛÃöªºµ{¦¡, ¨Ñ¨Ï¥ÎªÌ¿ï¥Î, ¤£¹L¥u©w¤ä´©¦³.newsrcÀɪº news + reader µ{¦¡, ¦p:tin...... + ¤@¯ë¨Ï¥ÎªÌ°£¤F¥i¥H«ü©w±µ¦¬¨º¨Ç¤H°e¥Xªºnotice¥~, ¤]¥i³]©w³o¨Çnotice©Ò + ¯à¼vÅT¤Î±±¨îªºnewsgroup. + + news serverºÞ²zªÌ: + + ¥Dnªºì²z©M¤W±©Ò¼gªº¤jP¬Û¦P, ¤£¹Lì¨Ó×§ï.newsrcÀɪº°Ê§@, ²{¦bÅܦ¨ + ª½±µ±N¤å³¹±q news server ¤¤§R°£, ¦P¼Ë¦a, ºÞ²zªÌ¦³µ´¹ïªºÅv§Q¿ï¾Ü¬O§_¥[¤J + NoCeM ©Î¬O¥[¤J«á¥u±µ¨ü¬Y¨Ç¤Hªºnotice. + +3.NoCeMªºÀu¯ÊÂI + + A.¸`¬Ùºô¸ôÀW¼e + + »Pcancel message¤ñ¸û, NoCeM¦û¤F¸û¤ÖªºÀW¼e¤ÎªÅ¶¡; cancel message + ªº¯S©Ê¬O¤@¹ï¤@, ¤@½gspam´Nn¹ïÀ³¤@½gcancel message, ¹ïµwºÐ¨Ó»¡ + spam³Q§R°£¤F, ¦ý«o¦h¤F¤@½gcancel message; ¹ïºô¸ôÀW¼e¨Ó»¡, spam + »Pcancel message³£³Q¶Ç»¼, ¨âªÌ³£®ö¶O¤FÀW¼e, ¦pªG±q news ¬y¶q¨Ó¤ÀªR, + spam»Pcancel messageªº¶q¬O±µªñ 1:1 ªº + + ¤£¹LNoCeM«h¤£¬Û¦P, ¤@½gnotice¤¤¥i¥H¥]§t¬Û·í¦hªºmessage-id, »P + cancel¬Û¤ñ, ¬Ù¥h¤F¤j¶q¶Ç»¼©Ò¦ûªºÀW¼e + + B.¸û¤Öª§Ä³, §ó¦h¼u©Ê + + cancel message³Ì±`¤Þ¤Hª§Ä³ªº¬O¨ä¬y¶Ç½d³ò¼s(·íµM, ¸g¹L¾A·íªº³]©w + «á, ¥i¥H§ïµ½), ¬Æ¦Ü¦³¤Ö¼Æ¨Ï¥ÎªÌ±N¤§µø¬°ºô¸ô¤Wªº¥Õ¦â®£©Æ, «a¤W¤@³» + ¨î¨¥½×¦Û¥Ñªº¤j´U¤l, ¬°¤F§K°£³o¨ÇÅU¼{, NoCeM¥iºâ¬O¤@ºØ¤£¿ùªº¸Ñªk + ºÞ²zªÌ¥i¦Û¥Ñ¿ï¾Ü¬O§_¥[¤JNoCeM, ©Î¬O¿ï¾Ü±µ¦¬¦ó¤Hªº¤å³¹, ¨S¦³¤H±j¢¥þ + ¥@¬ÉªººÞ²zªÌ³£n°Ñ¥[, ¦]¬°³o¬O¨CÓ¤Hªº¿ï¾Ü + + ·íµM, ©Î³\¦³¨Ï¥ÎªÌn°Ý, ¦pªG§Úªºnews serverºÞ²zªÌ¥[¤JNoCeM, ¨º»ò + ¥L¤£´N¶¡±µªº¼vÅT¨ì§Ú©ÒŪªº¤å³¹?? ªº½T, ·íºÞ²zªÌ±µ¨ünotice§R°£ news + server ¤¤ªº¤å³¹«á, ¨Ï¥ÎªÌªº½TµLªk¦b³oÓserver¤W¬Ý¨ì³o½g¤å³¹, ¤£¹L + ¨Ï¥ÎªÌÁÙ¬O¦³¥R¥÷ªº¿ï¾ÜÅv, ¥i¥H¿ï¾Ü§Oªºnews server¾\Ū, ¬Æ¦Ü, + ´«¤@ÓISP!! + +4.NoCeMªº©µ¦ù + + NoCeM notice¥i¥H¥Ñ¥ô¦ó¤Hµo¥X, ¤]¥i¥H³Q¥ô¦ó¤H±µ¦¬, ®Ú¾Ú³o¼Ëªº·§©À, ´Nµo + ®i¥Xpseudo moderator; ·í¬YӨϥΪ̹ï¬Y¨Ç¯S©wªº°Q½×°Ï¦³µÛ¸û¦hªº¸gÅç®É, + ¥i¥H¦Û§i¾Ä«iªº°e¥Xnotice, °w¹ï¯S©wªº°Q½×°Ï¤ºªº¤å³¹§@¤@¿z¿ï, «ØÄ³¨ä¥Lªº + ¨º´X½g¥i¥H¸Ô¥[¾\Ū, ¨º´X½g¤£È±o¤@¬Ý, ¦Ó¨ä¥LªºÅªªÌ, ¦pªG¬Û«H¥Lªº¸gÅç©M + §PÂ_, ´N¥i¥H³]©w±µ¦¬¥Lªºnotice, ³o´N¬Opseudo moderator. + + ¤@¯ëªºnewsgroup moderator²£¥Íªº¤èªk¸û¬°ÄYÂÔ, ©Ò¦³ªº¤å³¹¥²»Ý¸g¹Lmoderator + »{¦P«á, ¤~¯à°e¤Wnewsgroup, ¦]¦¹¨Ã¤£¬O©Ò¦³ªºnewsgroup³£¦³moderator¨Ó¬°¤å + ³¹«~½è§âÃö. + + ¨Æ¹ê¤Wpseudo moderatorªºÆ[©À, ´N¹³¤@¯ëBBS¤¤¨CÓªOªºªO¥D¤@¼Ë, ¥u¤£¹L + pseudo moderator¨Ã¨S¦³Åv§Q§R°£¥ô¦ó¤å³¹, °£«DŪªÌ±µ¨ü¥L°e¥Xªºnotice, ¦] + ¦¹, ¸û¤£©öµo¥Í "ªO¥DºÞ²z¤£¤½" "ªO¥DÀݬå¤å³¹", ½Ñ¦p¦¹Ãþªº±¡§Î, ¥unŪ + ªÌÃhºÃ©Î¤£¯à±µ¨üpseudo moderatorªº§PÂ_, ÀH®É¥i¥H°±¤î±µ¨üpseudo moderator + °e¥Xªºnotice, ŪªÌ¥i¥H¦Û¥Ñªº°µ¥X¨M©w. + +5.NoCeMªº±À¼s»PÀ³¥Î + + ¥Ø«eNoCeMªº¾÷¨î¤w¦³¤@©wªº³W¼Ò, ¦Ó¥B¦bUSENET¤W¥H±À¦æ¦³¤@¬q®É¶¡, + ¦ý¬OÀ³¥Îµ{¦¡ªº´¶¤Î¤~¯à¨Ï§ó¦h¨Ï¥ÎªÌ¨ü´f, À³¥Îµ{¦¡ªº³¡¥÷¥i¥H¤Àµ{¨â³¡¥÷ + +¤@¯ë¨Ï¥ÎªÌ: + + ¥Ø«e¥DnÁÙ¬O´£¨Ñµ¹¨Ï¥Î.newsrcÀɪºnews readerµ{¦¡¨Ï¥Î, ¦ptin.... + ¨ä¥L¹³¬Onetscape outlookµ¥, ¥Ø«e¦ü¥G¨S¦³¬Ý¨ì¬ÛÃöªº¤ä´© + + °£¦¹¤§¥~, tw.* ¦³¤£¤Öªº¤å³¹¬O¥Ñ BBS °e¥X, ¤£¥i§_»{ªº BBS ¤]À³³Qµø¬° + ¨Ï¥ÎªÌµoªí¤å³¹ªººÞ¹D»P¤u¨ã, ¥¦©Ò±a¨Óªº§ïÅܤ]¼vÅT¤F¤£¤Ö¨Ï¥ÎªÌ°Ñ»P NEWS + °Q½×ªº²ßºD, ¥Ø«e NoCeM »P BBS(innbbsd) ªº¾ã¦X¤w¸g¦³¤Fªì¨Bªºµ²ªG, + Leeym ¤w¸g¨Ï±o innbbsd ¥i¥H¤ä´© NoCeM, ¨Ã¥B¥¿¦b´ú¸Õ, ¬° NoCeM »P BBS + ªºµ²¦X»P¶Ê¥Í½ñ¥X¤@¤j¨B + +news serverºÞ²zªÌ: + + ³o¤è±¬ÛÃöªºµ{¦¡¤w¸g»á¦h, ¤]¤ä´©¼ÆºØ¤£¦Pªºnews serverµ{¦¡, ¥Hinn¬°¨Ò + http://sites.inka.de/~bigred/sw/c-nocem.html + c-nocem¥i¤ä´©inn2.x¥H¤UªºªO¥» + +6.¨ä¥L + + A.¥Ø«e NoCeM notice¤j³¡¥÷³£¬O³z¹L news ¶Ç°e, alt.nocem.misc¬O¥Dn¶Ç°e + ³o¨Çnoticeªºnewsgroup + +7.°Ñ¦Ò + + http://www.cm.org + http://sites.inka.de/~bigred/sw/c-nocem.html + http://cae.ce.ntu.edu.tw/~leeym/nocem/ncm-innbbsd-latest.tgz + news:news.admin.nocem + news:alt.nocem.misc + +-- +¡° Origin: ºô»Ú·s¥@¬É ¡» From: 163.28.64.246 diff --git a/innbbsd/nocem/README.nocem b/innbbsd/nocem/README.nocem new file mode 100644 index 0000000..a693acd --- /dev/null +++ b/innbbsd/nocem/README.nocem @@ -0,0 +1,39 @@ +# Author: Yen-Ming Lee <leeym@cae.ce.ntu.edu.tw> +# Start Date: Thu Feb 25 1999 +0800 +# Project: INNBBSD - NoCeM +# File: nocem.c nocem.h +# +# Copyright: Copyright (c) 2000 by Yen-Ming Lee +# +# Permission to use, copy, modify, and distribute this +# software for any purpose with or without fee is hereby +# granted, provided that the above copyright notice and this +# permission notice appear in all copies. + + + innbbsd ¥Ñ skhuang@csie.nctu.edu.tw ½s¼g + ¥»µ{¦¡ NoCeM-innbbsd ¥u¬O patch + + ¥»µ{¦¡·PÁ clcheng@CCCA.NCTU.edu.tw ¤Î stevel@bbs.ee.ntu.edu.tw + ´£¨ÑÄ_¶Q·N¨£. + + NoCeM ¤§³]©wÀɦb ~bbs/innd/ncmperm.bbs, ®æ¦¡¬° "Issuer Type Perm" + ¦UÄæ¦ì *¥²¶·* ¨Ï¥Î tab ¹j¶}. ²Ä¤@¦¸¸ü¤J®Éµ{¦¡·|¦Û°Ê²£¥Í³]©wÀÉ. + + ¦pÄ@±µ¦¬¬Y¤@¦W Issuer ªº ncm-notice, ½Ð±N³Ì«á¤@Äæ no ±q§ï¬° yes + µM«á ctlinnbbsd reload «·s¸ü¤J¸ê®Æ§Y¥i. + *½Ð¤Å* ¨Ï¥Î ve ½s¿è ncmperm.bbs , ¦]¬° ve ·|±N tab ¥þ³¡Âର space + + ¥»µ{¦¡»Ý°t¦X pgp5 ¨Ï¥Î, ¦w¸Ë NoCeM-innbbsd-patch «e, ½Ð¥ý¦w¸Ë pgp5 + §_«h½Ð×§ï nocem.c , #undef PGP5 + + pgp5 ªº¤¤¤å¤å¥ó¥i¦b©³¤U´X³B§ä¨ì. + http://bbs.ee.ntu.edu.tw/boards/BSD/4/62.html + http://www.sinica.edu.tw/cc/netsrv/dawei/pgp5.0/ + + NoCeM ¸ê®Æ½Ð°Ñ¦Ò http://www.cm.org + ¤Î benjamin.bbs@com.neto.net (clcheng) ©Ò¼gªº»¡©ú¤å¥ó. + +-- + Yen-Ming Lee [§õ«Û©ú] | http://cae.ce.ntu.edu.tw/~leeym/ + CAE Group, Civil Engineering, NTU, Taipei, Taiwan diff --git a/innbbsd/rec_article.c b/innbbsd/rec_article.c new file mode 100644 index 0000000..9853929 --- /dev/null +++ b/innbbsd/rec_article.c @@ -0,0 +1,522 @@ +/*-------------------------------------------------------*/ +/* rec_article.c( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : innbbsd receive article */ +/* create : 95/04/27 */ +/* update : / / */ +/* author : skhuang@csie.nctu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + ¦¬¨ì¤§¤å³¹¤º®e©MÀÉÀY¤À§O¦b + ¤º¤å (body) ¦b char *BODY + ÀÉÀY (header) ¦b char *SUBJECT, *FROM, *SITE, *DATE, *PATH, *GROUP, *MSGID, *POSTHOST, *CONTROL; +#endif + + +#include "innbbsconf.h" +#include "bbslib.h" +#include "inntobbs.h" + + +/* ----------------------------------------------------- */ +/* board¡Gshm ³¡¥÷¶·»P cache.c ¬Û®e */ +/* ----------------------------------------------------- */ + + +static BCACHE *bshm; + + +void +init_bshm() +{ + /* itoc.030727: ¦b¶}±Ò bbsd ¤§«e¡AÀ³¸Ó´Nn°õ¦æ¹L account¡A + ©Ò¥H bshm À³¸Ó¤w³]©w¦n */ + + bshm = shm_new(BRDSHM_KEY, sizeof(BCACHE)); + + if (bshm->uptime <= 0) /* bshm ¥¼³]©w§¹¦¨ */ + exit(0); +} + + +/* ----------------------------------------------------- */ +/* ³B²z DATE */ +/* ----------------------------------------------------- */ + + +#if 0 /* itoc.030303.µù¸Ñ: RFC 822 ªº DATE Äæ¦ì¡FRFC 1123 ±N year §ï¦¨ 4-DIGIT */ + +date-time := [ wday "," ] date time ; dd mm yy, hh:mm:ss zzz +wday := "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun" +date := 1*2DIGIT month 4DIGIT ; mday month year +month := "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" +time := hour zone ; ANSI and Military +hour := 2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59 +zone := "UT" / "GMT" / "EST" / "EDT" / "CST" / "CDT" / "MST" / "MDT" / "PST" / "PDT" / 1ALPHA / ( ("+" / "-") 4DIGIT ) + +#endif + +static time_t datevalue; + +static void +parse_date() /* §â²Å¦X "dd mmm yyyy hh:mm:ss" ªº®æ¦¡¡AÂন time_t */ +{ + static char months[12][4] = {"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"}; + int i; + char *ptr, *str, buf[80]; + struct tm ptime; + + str_ncpy(buf, DATE, sizeof(buf)); + str_lower(buf, buf); /* ³q³q´«¤p¼g¡A¦]¬° Dec DEC dec ¦UºØ³£¦³¤H¥Î */ + + str = buf + 2; + for (i = 0; i < 12; i++) + { + if (ptr = strstr(str, months[i])) + break; + } + + if (ptr) + { + ptr[-1] = ptr[3] = ptr[8] = ptr[11] = ptr[14] = ptr[17] = '\0'; + + ptime.tm_sec = atoi(ptr + 15); + ptime.tm_min = atoi(ptr + 12); + ptime.tm_hour = atoi(ptr + 9); + ptime.tm_mday = (ptr == buf + 2 || ptr == buf + 7) ? atoi(ptr - 2) : atoi(ptr - 3); /* RFC 822 ¤¹³\ mday ¬O 1- ©Î 2- DIGIT */ + ptime.tm_mon = i; + ptime.tm_year = atoi(ptr + 4) - 1900; + ptime.tm_isdst = 0; +#ifndef CYGWIN + ptime.tm_zone = "GMT"; + ptime.tm_gmtoff = 0; +#endif + + datevalue = mktime(&ptime); + str = ptr + 18; + if (ptr = strchr(str, '+')) + { + /* ¦pªG¦³ +0100 (MET) µ¥µù©ú®É°Ï¡A¥ý½Õ¦^ GMT ®É°Ï */ + datevalue -= ((ptr[1] - '0') * 10 + (ptr[2] - '0')) * 3600 + ((ptr[3] - '0') * 10 + (ptr[4] - '0')) * 60; + } + else if (ptr = strchr(str, '-')) + { + /* ¦pªG¦³ -1000 (HST) µ¥µù©ú®É°Ï¡A¥ý½Õ¦^ GMT ®É°Ï */ + datevalue += ((ptr[1] - '0') * 10 + (ptr[2] - '0')) * 3600 + ((ptr[3] - '0') * 10 + (ptr[4] - '0')) * 60; + } + datevalue += 28800; /* ¥xÆW©Ò¦bªº CST ®É°Ï¤ñ GMT §Ö¤K¤p®É */ + } + else + { + /* ¦pªG¤ÀªR¥¢±Ñ¡A¨º»ò®³²{¦b®É¶¡¨Ó·íµo¤å®É¶¡ */ + time(&datevalue); + /* bbslog("<rec_article> :Warn: parse_date ¿ù»~¡G%s\n", DATE); */ + } +} + + +/* ----------------------------------------------------- */ +/* process post write */ +/* ----------------------------------------------------- */ + + +static void +update_btime(brdname) + char *brdname; +{ + BRD *brdp, *bend; + + brdp = bshm->bcache; + bend = brdp + bshm->number; + do + { + if (!strcmp(brdname, brdp->brdname)) + { + brdp->btime = -1; + break; + } + } while (++brdp < bend); +} + + +static void +bbspost_add(board, addr, nick) + char *board, *addr, *nick; +{ + int cc; + char *str; + char folder[64], fpath[64]; + HDR hdr; + FILE *fp; + + /* ¼g¤J¤å³¹¤º®e */ + + brd_fpath(folder, board, FN_DIR); + + if (fp = fdopen(hdr_stamp(folder, 'A', &hdr, fpath), "w")) + { + fprintf(fp, "µo«H¤H: %.50s ¬ÝªO: %s\n", FROM, board); + fprintf(fp, "¼Ð ÃD: %.70s\n", SUBJECT); + if (SITE) + fprintf(fp, "µo«H¯¸: %.27s (%.40s)\n\n", SITE, DATE); + else + fprintf(fp, "µo«H¯¸: %.40s\n\n", DATE); + + /* chuan: header ¸ò body nªÅ¦æ¹j¶} */ + + /* fprintf(fp, "%s", BODY); */ + + for (str = BODY; cc = *str; str++) + { + if (cc == '.') + { + /* for line beginning with a period, collapse the doubled period to a single one. */ + if (str >= BODY + 2 && str[-1] == '.' && str[-2] == '\n') + continue; + } + + fputc(cc, fp); + } + + fclose(fp); + } + + /* ³y HDR */ + + hdr.xmode = POST_INCOME; + + /* Thor.980825: ¨¾¤î¦r¦ê¤Óªø»\¹LÀY */ + str_ncpy(hdr.owner, addr, sizeof(hdr.owner)); + str_ncpy(hdr.nick, nick, sizeof(hdr.nick)); + str_stamp(hdr.date, &datevalue); /* ¨Ì DATE: Äæ¦ìªº¤é´Á¡A»P hdr.chrono ¤£¦P¨B */ + str_ncpy(hdr.title, SUBJECT, sizeof(hdr.title)); + + rec_bot(folder, &hdr, sizeof(HDR)); + + update_btime(board); + + HISadd(MSGID, board, hdr.xname); +} + + +/* ----------------------------------------------------- */ +/* process cancel write */ +/* ----------------------------------------------------- */ + + +#ifdef _KEEP_CANCEL_ +static inline void +move_post(hdr, board, filename) + HDR *hdr; + char *board, *filename; +{ + HDR post; + char folder[64]; + + brd_fpath(folder, board, FN_DIR); + hdr_stamp(folder, HDR_LINK | 'A', &post, filename); + unlink(filename); + + /* ª½±µ½Æ»s trailing data */ + + memcpy(post.owner, hdr->owner, TTLEN + 140); + + sprintf(post.title, "[cancel] %-60.60s", FROM); + + rec_bot(folder, &post, sizeof(HDR)); +} +#endif + + +static void +bbspost_cancel(board, chrono, fpath) + char *board; + time_t chrono; + char *fpath; +{ + HDR hdr; + struct stat st; + long size; + int fd, ent; + char folder[64]; + off_t off, len; + + /* XLOG("cancel [%s] %d\n", board, time); */ + + brd_fpath(folder, board, FN_DIR); + if ((fd = open(folder, O_RDWR)) == -1) + return; + + /* flock(fd, LOCK_EX); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_exlock(fd); + + fstat(fd, &st); + size = sizeof(HDR); + ent = ((long) st.st_size) / size; + + /* itoc.030307.µù¸Ñ: ¥h .DIR ¤¤ÂǥѤñ¹ï chrono §ä¥X¬Oþ¤@½g */ + + while (1) + { + /* itoc.030307.µù¸Ñ: ¨C 16 ½g¬°¤@Ó block */ + ent -= 16; + if (ent <= 0) + break; + + lseek(fd, size * ent, SEEK_SET); + if (read(fd, &hdr, size) != size) + break; + + if (hdr.chrono <= chrono) /* ¸¨¦b³oÓ block ¸Ì */ + { + do + { + if (hdr.chrono == chrono) + { + /* Thor.981014: mark ªº¤å³¹¤£³Q cancel */ + if (hdr.xmode & POST_MARKED) + break; + +#ifdef _KEEP_CANCEL_ + /* itoc.030613: «O¯d³Q cancel ªº¤å³¹©ó [deleted] */ + move_post(&hdr, BN_DELETED, fpath); +#else + unlink(fpath); +#endif + + update_btime(board); + + /* itoc.030307: ³Q cancel ªº¤å³¹¤£«O¯d header */ + + off = lseek(fd, 0, SEEK_CUR); + len = st.st_size - off; + + board = (char *) malloc(len); + read(fd, board, len); + + lseek(fd, off - size, SEEK_SET); + write(fd, board, len); + ftruncate(fd, st.st_size - size); + + free(board); + break; + } + + if (hdr.chrono > chrono) + break; + } while (read(fd, &hdr, size) == size); + + break; + } + } + + /* flock(fd, LOCK_UN); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_unlock(fd); + + close(fd); + return; +} + + +int /* 0:cancel success -1:cancel fail */ +cancel_article(msgid) + char *msgid; +{ + int fd; + char fpath[64], cancelfrom[128], buffer[128]; + char board[BNLEN + 1], xname[9]; + + /* XLOG("cancel %s <%s>\n", FROM, msgid); */ + + if (!HISfetch(msgid, board, xname)) + return -1; + + str_from(FROM, cancelfrom, buffer); + + /* XLOG("cancel %s (%s)\n", cancelfrom, buffer); */ + + sprintf(fpath, "brd/%s/%c/%s", board, xname[7], xname); /* ¥h§ä¥X¨º½g¤å³¹ */ + + /* XLOG("cancel fpath (%s)\n", fpath); */ + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + int len; + + len = read(fd, buffer, sizeof(buffer)); + close(fd); + + /* Thor.981221.µù¸Ñ: ¥~¨Ó¤å³¹¤~¯à³Q cancel */ + if ((len > 10) && !memcmp(buffer, "µo«H¤H: ", 8)) + { + char *xfrom, *str; + + xfrom = buffer + 8; + if (str = strchr(xfrom, ' ')) + { + *str = '\0'; + +#ifdef _NoCeM_ + /* gslin.000607: ncm_issuer ¥i¥H¬å§O¯¸µoªº«H */ + if (strcmp(xfrom, cancelfrom) && !search_issuer(FROM, NULL)) +#else + if (strcmp(xfrom, cancelfrom)) +#endif + { + /* itoc.030107.µù¸Ñ: Y cancelfrom ©M¥»¦a¤å³¹ header °O¿ýªº xfrom ¤£¦P¡A´N¬O fake cancel */ + bbslog("<rec_article> :Warn: µL®Äªº cancel¡G%s, sender: %s, path: %s\n", xfrom, FROM, PATH); + return -1; + } + + bbspost_cancel(board, chrono32(xname), fpath); + } + } + } + + return 0; +} + + +/* ----------------------------------------------------- */ +/* check spam rule */ +/* ----------------------------------------------------- */ + + +static int /* 1: ²Å¦X¾×«H³W«h */ +is_spam(board, addr, nick) + char *board, *addr, *nick; +{ + spamrule_t *spam; + int i, xmode; + char *compare, *detail; + + for (i = 0; i < SPAMCOUNT; i++) + { + spam = SPAMRULE + i; + + compare = spam->path; + if (*compare && strcmp(compare, NODENAME)) + continue; + + compare = spam->board; + if (*compare && strcmp(compare, board)) + continue; + + xmode = spam->xmode; + detail = spam->detail; + + if (xmode & INN_SPAMADDR) + compare = addr; + else if (xmode & INN_SPAMNICK) + compare = nick; + else if (xmode & INN_SPAMSUBJECT) + compare = SUBJECT; + else if (xmode & INN_SPAMPATH) + compare = PATH; + else if (xmode & INN_SPAMMSGID) + compare = MSGID; + else if (xmode & INN_SPAMBODY) + compare = BODY; + else if (xmode & INN_SPAMSITE && SITE) /* SITE ¥i¥H¬O NULL */ + compare = SITE; + else if (xmode & INN_SPAMPOSTHOST && POSTHOST) /* POSTHOST ¥i¥H¬O NULL */ + compare = POSTHOST; + else + continue; + + if (str_sub(compare, detail)) + return 1; + } + return 0; +} + + +/* ----------------------------------------------------- */ +/* process receive article */ +/* ----------------------------------------------------- */ + + +#ifndef _NoCeM_ +static +#endif +newsfeeds_t * +search_newsfeeds_bygroup(newsgroup) + char *newsgroup; +{ + newsfeeds_t nf, *find; + + str_ncpy(nf.newsgroup, newsgroup, sizeof(nf.newsgroup)); + find = bsearch(&nf, NEWSFEEDS_G, NFCOUNT, sizeof(newsfeeds_t), nf_bygroupcmp); + if (find && !(find->xmode & INN_NOINCOME)) + return find; + return NULL; +} + + +int /* 0:success -1:fail */ +receive_article() +{ + newsfeeds_t *nf; + char myaddr[128], mynick[128], mysubject[128], myfrom[128], mydate[80]; + char poolx[256]; + char *group; + int firstboard = 1; + + /* try to split newsgroups into separate group */ + for (group = strtok(GROUP, ","); group; group = strtok(NULL, ",")) + { + if (!(nf = search_newsfeeds_bygroup(group))) + continue; + + if (firstboard) /* opus: ²Ä¤@ÓªO¤~»Ýn³B²z */ + { + /* Thor.980825: gc patch: lib/str_decode ¥u¯à±µ¨ü decode §¹ strlen < 256 */ + + str_ncpy(poolx, SUBJECT, 255); + str_decode(poolx); + str_ansi(mysubject, poolx, 70); /* 70 ¬O bbspost_add() ¼ÐÃD©Ò»Ýªºªø«× */ + SUBJECT = mysubject; + + str_ncpy(poolx, FROM, 255); + str_decode(poolx); + str_ansi(myfrom, poolx, 128); /* ÁöµM bbspost_add() µo«H¤H©Ò»Ýªºªø«×¥u»Ýn 50¡A¦ý¬O str_from() »Ýnªø¤@¨Ç */ + FROM = myfrom; + + /* itoc.030218.µù¸Ñ: ³B²z¡uµo«H¯¸¡v¤¤ªº®É¶¡ */ + parse_date(); + strcpy(mydate, (char *) Btime(&datevalue)); + DATE = mydate; + + if (*nf->charset == 'g') + { + gb2b5(BODY); + gb2b5(FROM); + gb2b5(SUBJECT); + if (SITE) + gb2b5(SITE); + } + + strcpy(poolx, FROM); + str_from(poolx, myaddr, mynick); + + if (is_spam(nf->board, myaddr, mynick)) + { +#ifdef _KEEP_CANCEL_ + bbspost_add(BN_DELETED, myaddr, mynick); +#endif + break; + } + + firstboard = 0; + } + + bbspost_add(nf->board, myaddr, mynick); + } /* for board1,board2,... */ + + return 0; +} diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000..e5a0340 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,92 @@ +# ------------------------------------------------------ # +# lib/Makefile ( NTHU CS MapleBBS Ver 3.10 ) # +# ------------------------------------------------------ # +# author : opus.bbs@bbs.cs.nthu.edu.tw # +# target : Makefile for MapleBBS library routines # +# create : 95/03/29 # +# update : 95/12/15 # +# ------------------------------------------------------ # + + +CC = gcc +RANLIB = ranlib +CPROTO = cproto -E"gcc -pipe -E" -I../include # -s -v +CFLAGS = -O2 -s -pipe -fomit-frame-pointer -Wunused -I../include + + +# ------------------------------------------------------ # +# ¤U¦Cªº make rules ¤£»Ý×§ï # +# ------------------------------------------------------ # + + +SRC = \ + is_alnum.c is_alpha.c not_addr.c \ + \ + dns.c dns_aton.c dns_name.c dns_open.c dns_smtp.c \ + \ + str_ansi.c str_cat.c str_cmp.c str_decode.c str_folder.c str_fpath.c \ + str_from.c str_has.c str_hash.c str_lower.c str_lowest.c str_ncmp.c \ + str_ncpy.c str_passwd.c str_stamp.c str_str.c str_sub.c str_tail.c \ + str_time.c str_trim.c str_ttl.c \ + \ + archiv32.c chrono32.c hash32.c radix32.c \ + \ + f_cat.c f_cp.c f_img.c f_ln.c f_lock.c f_map.c f_mode.c f_mv.c f_new.c \ + f_path.c f_rm.c f_suck.c mak_dirs.c \ + \ + rec_add.c rec_bot.c rec_num.c rec_del.c rec_get.c rec_ins.c rec_put.c \ + rec_ref.c rec_sync.c \ + \ + hdr_fpath.c hdr_stamp.c \ + \ + shm.c \ + \ + splay.c \ + \ + acl_has.c rfc2047.c xwrite.c \ + \ + dl_lib.c + +OBJ = \ + is_alnum.o is_alpha.o not_addr.o \ + \ + dns.o dns_aton.o dns_name.o dns_open.o dns_smtp.o \ + \ + str_ansi.o str_cat.o str_cmp.o str_decode.o str_folder.o str_fpath.o \ + str_from.o str_has.o str_hash.o str_lower.o str_lowest.o str_ncmp.o \ + str_ncpy.o str_passwd.o str_stamp.o str_str.o str_sub.o str_tail.o \ + str_time.o str_trim.o str_ttl.o \ + \ + archiv32.o chrono32.o hash32.o radix32.o \ + \ + f_cat.o f_cp.o f_img.o f_ln.o f_lock.o f_map.o f_mode.o f_mv.o f_new.o \ + f_path.o f_rm.o f_suck.o mak_dirs.o \ + \ + rec_add.o rec_bot.o rec_num.o rec_del.o rec_get.o rec_ins.o rec_put.o \ + rec_ref.o rec_sync.o \ + \ + hdr_fpath.o hdr_stamp.o \ + \ + shm.o \ + \ + splay.o \ + \ + acl_has.o rfc2047.o xwrite.o \ + \ + dl_lib.o + + +.c.o: ; $(CC) $(CFLAGS) -c $*.c + + +all: libdao.a + +dao.p: $(SRC) + $(CPROTO) -o $@ $? + +libdao.a: $(OBJ) + ar rv $@ $? + $(RANLIB) $@ + +clean: + rm -f libdao.a *.o *~ diff --git a/lib/acl_has.c b/lib/acl_has.c new file mode 100644 index 0000000..c9e2c3e --- /dev/null +++ b/lib/acl_has.c @@ -0,0 +1,102 @@ +/*-------------------------------------------------------*/ +/* lib/acl_has.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : Access Control List */ +/* create : 98/03/20 */ +/* update : 98/03/29 */ +/*-------------------------------------------------------*/ + + +#include <stdio.h> + + +/* ----------------------------------------------------- */ +/* ACL config file format */ +/* ----------------------------------------------------- */ +/* user: majordomo@* bad@cs.nthu.edu.tw */ +/* ^ Thor.980825: À³¬°ªÅ¥Õ */ +/* host: cs.nthu.edu.tw 140.114.77.1 */ +/* subnet: .nthu.edu.tw 140.114.77. */ +/* ----------------------------------------------------- */ + + +/* return -1 : ACL file ¤£¦s¦b */ +/* return 0 : ACL ¤£¥]§t¸Ó pattern */ +/* return 1 : ACL ²Å¦X¸Ó pattern */ + + +int +acl_has(acl, user, host) + char *acl; /* file name of access control list */ + char *user; /* lower-case string */ + char *host; /* lower-case string */ +{ + int i, cc, luser, lhost; + FILE *fp; + char filter[256], *addr, *str; + + if (!(fp = fopen(acl, "r"))) + return -1; + + i = 0; + luser = strlen(user); /* length of user name */ + lhost = strlen(host); /* length of host name */ + + while (fgets(filter, sizeof(filter), fp)) + { + addr = NULL; + + for (str = filter; (cc = *str) > ' '; str++) + { /* Thor.980825: µù¸Ñ: ¹J¨ì ªÅ¥Õ ´Nºâ¦¹¦æµ²§ô */ + if (cc == '@') + addr = str; + } + + if (str == filter) /* empty line */ + continue; + + *str = '\0'; /* Thor.980825: µù¸Ñ: ±Nµ²§ô³B¶ñ0, §K¥ÍªK¸` */ + str_lower(filter, filter); /* lkchu.981201: lower-case string */ + + if (addr) /* match user name */ + { + if ((luser != addr - filter) || memcmp(user, filter, luser)) + continue; + + if (!*++addr) + { + i = 1; + break; + } + } + else + { + addr = filter; + } + + /* match host name */ + + cc = str - addr; + + if (cc > lhost) + continue; + + if (cc == lhost) + { + if (memcmp(addr, host, lhost)) + continue; + } + else + { + if (((*addr != '.') || memcmp(addr, host + lhost - cc, cc)) && + ((addr[cc - 1] != '.') || memcmp(addr, host, cc))) + continue; + } + + i = 1; + break; + } + + fclose(fp); + return i; +} diff --git a/lib/archiv32.c b/lib/archiv32.c new file mode 100644 index 0000000..7f56ff4 --- /dev/null +++ b/lib/archiv32.c @@ -0,0 +1,41 @@ +#include "dao.h" + + +void +archiv32(chrono, fname) + time_t chrono; /* 32 bits */ + char *fname; /* 7 chars */ +{ + char *str; + + str = fname + 7; + *str = '\0'; + for (;;) + { + *(--str) = radix32[chrono & 31]; + if (str == fname) + return; + chrono >>= 5; + } +} + + +#if 0 +void +archiv32m(chrono, fname) + time_t chrono; /* 32 bits */ + char *fname; /* 7 chars */ +{ + char *str; + + str = fname + 8; + *str = '\0'; + for (;;) + { + *(--str) = radix32[chrono & 31]; + if (str == fname) + return; + chrono >>= 5; + } +} +#endif diff --git a/lib/chrono32.c b/lib/chrono32.c new file mode 100644 index 0000000..fe7fd34 --- /dev/null +++ b/lib/chrono32.c @@ -0,0 +1,18 @@ +#include "dao.h" + + +time_t +chrono32(str) + char *str; /* M0123456 */ +{ + time_t chrono; + int ch; + + chrono = 0; + while (ch = *++str) + { + ch -= (ch > '9') ? 'A' - 10 : '0'; + chrono = (chrono << 5) + ch; + } + return chrono; +} diff --git a/lib/dao.p b/lib/dao.p new file mode 100644 index 0000000..f9237de --- /dev/null +++ b/lib/dao.p @@ -0,0 +1,151 @@ +/* is_alnum.c */ +int is_alnum(int ch); +/* is_alpha.c */ +int is_alpha(int ch); +/* not_addr.c */ +int not_addr(char *addr); + +#ifdef _RESOLV_H +/* dns.c */ +void dns_init(void); +/* dns_aton.c */ +unsigned long dns_aton(char *name); +int dns_query(char *name, int qtype, querybuf *ans); +/* dns_name.c */ +int dns_name(unsigned char *addr, char *name); +/* dns_open.c */ +int dns_open(char *host, int port); +/* dns_smtp.c */ +int dns_mx(char *domain, char *mxlist); +int dns_smtp(char *host); +#endif + +/* str_ansi.c */ +void str_ansi(char *dst, char *str, int max); +/* str_cat.c */ +void str_cat(char *dst, char *s1, char *s2); +/* str_cmp.c */ +int str_cmp(char *s1, char *s2); +/* str_decode.c */ +char *mm_getencode(unsigned char *str, char *code); +void mm_getcharset(const char *str, char *charset, int size); +int mmdecode(unsigned char *src, int encode, unsigned char *dst); +void str_decode(unsigned char *str); +/* str_folder.c */ +void str_folder(char *fpath, char *folder, char *fname); +/* str_fpath.c */ +void setdirpath(char *fpath, char *direct, char *fname); +/* str_from.c */ +int str_from(char *from, char *addr, char *nick); +/* str_has.c */ +int str_has(char *list, char *tag, int len); +/* str_hash.c */ +int str_hash(char *str, int seed); +/* str_len.c */ +int str_len(char *str); +/* str_lower.c */ +void str_lower(char *dst, char *src); +/* str_lowest.c */ +void str_lowest(char *dst, char *src); +/* str_ncmp.c */ +int str_ncmp(char *s1, char *s2, int n); +/* str_ncpy.c */ +void str_ncpy(char *dst, char *src, int n); +/* str_passwd.c */ +char *genpasswd(char *pw); +int chkpasswd(char *passwd, char *test); +/* str_stamp.c */ +void str_stamp(char *str, time_t *chrono); +/* str_str.c */ +char *str_str(char *str, char *tag); +/* str_sub.c */ +char *str_sub(char *str, char *tag); +/* str_tail.c */ +char *str_tail(char *str); +/* str_time.c */ +char *Atime(time_t *clock); +char *Btime(time_t *clock); +char *Now(void); +/* str_trim.c */ +void str_trim(char *buf); +/* str_ttl.c */ +char *str_ttl(char *title); + +/* archiv32.c */ +void archiv32(time_t chrono, char *fname); +/* chrono32.c */ +time_t chrono32(char *str); +/* hash32.c */ +int hash32(unsigned char *str); +/* radix32.c */ + +/* f_cat.c */ +void f_cat(char *fpath, char *msg); +/* f_cp.c */ +int f_cp(char *src, char *dst, int mode); +/* f_img.c */ +char *f_img(char *fpath, int *fsize); +/* f_ln.c */ +int f_ln(char *src, char *dst); +/* f_lock.c */ +int f_exlock(int fd); +int f_unlock(int fd); +/* f_map.c */ +char *f_map(char *fpath, int *fsize); +/* f_mode.c */ +int f_mode(char *fpath); +/* f_mv.c */ +int f_mv(char *src, char *dst); +/* f_new.c */ +FILE *f_new(char *fold, char *fnew); +/* f_path.c */ +void brd_fpath(char *fpath, char *board, char *fname); +void gem_fpath(char *fpath, char *board, char *fname); +void usr_fpath(char *fpath, char *user, char *fname); +/* f_rm.c */ +int f_rm(char *fpath); +/* f_suck.c */ +void f_suck(FILE *fp, char *fpath); +/* mak_dirs.c */ +void mak_dirs(char *fpath); +void mak_links(char *fpath); + +/* rec_add.c */ +int rec_add(char *fpath, void *data, int size); +/* rec_bot.c */ +int rec_bot(char *fpath, void *data, int size); +/* rec_num.c */ +int rec_num(char *fpath, int size); +/* rec_del.c */ +int rec_del(char *fpath, int size, int pos, int (*fchk)()); +/* rec_get.c */ +int rec_get(char *fpath, void *data, int size, int pos); +/* rec_ins.c */ +int rec_ins(char *fpath, void *data, int size, int pos, int num); +/* rec_put.c */ +int rec_put(char *fpath, void *data, int size, int pos, int (*fchk)()); +/* rec_ref.c */ +int rec_ref(char *fpath, void *data, int size, int pos, int (*fchk)(), void (*fref)()); +/* rec_sync.c */ +int rec_sync(char *fpath, int size, int (*fsync)(), int (*fchk)()); + +/* hdr_fpath.c */ +void hdr_fpath(char *fpath, char *folder, HDR *hdr); +/* hdr_stamp.c */ +int hdr_stamp(char *folder, int token, HDR *hdr, char *fpath); + +/* shm.c */ +void *shm_new(int shmkey, int shmsize); + +/* splay.c */ +SplayNode *splay_in(SplayNode *top, void *data, int (*compare)()); + +/* acl_has.c */ +int acl_has(char *acl, char *user, char *host); +/* rfc2047.c */ +void output_rfc2047_qp(FILE *fp, char *prefix, char *str, char *charset, char *suffix); +/* xwrite.c */ +int xwrite(int fd, char *data, int size); + +/* dl_lib.c */ +void *DL_get(char *name); diff --git a/lib/dl_lib.c b/lib/dl_lib.c new file mode 100644 index 0000000..2a203b9 --- /dev/null +++ b/lib/dl_lib.c @@ -0,0 +1,114 @@ +/* ----------------------------------------------------- */ +/* author : thor.bbs@bbs.cs.nthu.edu.tw */ +/* target : dynamic link modules library for maple bbs */ +/* create : 99/02/14 */ +/* update : / / */ +/* ----------------------------------------------------- */ + + +#include <dlfcn.h> +#include <strings.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> + + +typedef struct +{ + char *path; + void *handle; +} DL_list; + + +static DL_list *dl_pool; +static int dl_size, dl_head; + +#define DL_ALLOC_MIN 5 + + +void * +DL_get(name) + char *name; /* format: "Xmodule_path:Xname" */ +{ + char buf[512], *t; + DL_list *p, *tail; + + strcpy(buf, name); + if (!(t = (char *)strchr(buf, ':'))) + return NULL; + + *t++ = 0; + + if (!dl_pool) + { + /* Initialize DL entries */ + dl_size = DL_ALLOC_MIN; + dl_head = 0; + dl_pool = (DL_list *) malloc(dl_size * sizeof(DL_list)); + if (!dl_pool) + exit(1); /* Thor.991121: out of space */ + } + + p = dl_pool; + tail = p + dl_head; + while (p < tail) + { + if (!strcmp(buf, p->path)) + break; + p++; + } + + if (p >= tail) + { /* not found */ + if (dl_head >= dl_size) + { /* not enough space */ + dl_size += DL_ALLOC_MIN; + dl_pool = (DL_list *) realloc(dl_pool, dl_size * sizeof(DL_list)); + if (!dl_pool) + exit(1); /* Thor.991121: out of space */ + p = dl_pool + dl_head; /* Thor.991121: to a new place */ + } + +#if defined(__OpenBSD__) + p->handle = dlopen(p->path = (char *)strdup(buf), RTLD_LAZY); +#else + p->handle = dlopen(p->path = (char *)strdup(buf), RTLD_NOW); +#endif + + dl_head++; + } + + if (!p->handle) + return NULL; + +#if defined(DLSYM_NEEDS_UNDERSCORE) + char *symbol = (char *) malloc(sizeof(char) * (strlen(t) + 2)); + void *retval; + sprintf(symbol, "_%s", t); + retval = dlsym(p->handle, symbol); + free(symbol); + return retval; +#else + return dlsym(p->handle, t); +#endif +} + + +int +DL_func(char *name, ...) +{ + va_list args; + int (*f) (), ret; + + va_start(args, name); + + if (!(f = DL_get(name))) + { /* not get func */ + return -1; + } + + ret = (*f) (args); + va_end(args); + + return ret; +} diff --git a/lib/dns.c b/lib/dns.c new file mode 100644 index 0000000..eed724f --- /dev/null +++ b/lib/dns.c @@ -0,0 +1,45 @@ +/*-------------------------------------------------------*/ +/* lib/dns.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : included C file for DNS routines */ +/* create : 96/11/20 */ +/* update : 96/12/15 */ +/*-------------------------------------------------------*/ + + +#include "dns.h" + + +void +dns_init() +{ + res_init(); + /* _res.retrans = 5; */ /* DNS query timeout */ + _res.retry = 2; + /* _res.options |= RES_USEVC; */ /* Thor.001228: ¥ý¤£¥Î TCP, ©È¥d¦í */ +} + + +int +dns_query(name, qtype, ans) + char *name; /* domain name */ + int qtype; /* type of query */ + querybuf *ans; /* buffer to put answer */ +{ + querybuf buf; + + qtype = res_mkquery(QUERY, name, C_IN, qtype, (char *) NULL, 0, NULL, + (char *) &buf, sizeof(buf)); + + if (qtype >= 0) + { + qtype = res_send((char *) &buf, qtype, (char *) ans, sizeof(querybuf)); + + /* avoid problems after truncation in tcp packets */ + + if (qtype > sizeof(querybuf)) + qtype = sizeof(querybuf); + } + + return qtype; +} diff --git a/lib/dns.p b/lib/dns.p new file mode 100644 index 0000000..824ee6b --- /dev/null +++ b/lib/dns.p @@ -0,0 +1,14 @@ +/* dns.c */ +void dns_init(void); +/* dns_aton.c */ +unsigned long dns_aton(char *name); +int dns_query(char *name, int qtype, querybuf *ans); +/* dns_ident.c */ +void dns_ident(int sock, struct sockaddr_in *from, char *rhost, char *ruser); +/* dns_name.c */ +int dns_name(unsigned char *addr, char *name); +/* dns_open.c */ +int dns_open(char *host, int port); +/* dns_smtp.c */ +int dns_mx(char *domain, char *mxlist); +int dns_smtp(char *host); diff --git a/lib/dns_aton.c b/lib/dns_aton.c new file mode 100644 index 0000000..b4355bf --- /dev/null +++ b/lib/dns_aton.c @@ -0,0 +1,149 @@ +/*-------------------------------------------------------*/ +/* lib/dns_aton.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : included C file for DNS routines */ +/* create : 96/11/20 */ +/* update : 99/08/11 */ +/*-------------------------------------------------------*/ + + +#include "dns.h" + + +/* ----------------------------------------------------- */ +/* get IP address by address string */ +/* ----------------------------------------------------- */ + +/* Thor.990811: §ì¥Xip addr */ + +unsigned long +dns_aton(name) + char *name; +{ + ip_addr addr; + u_char *cp; + int cc, cd; + + /* disallow names consisting only of digits/dots, unless they end in a dot. */ + + cc = name[0]; + if (cc >= '0' && cc <= '9') + { + addr.addr = 0; cd = 0; + + for (cp = name;; ++cp) + { + cc = *cp; + if (!cc) + { + /* + * All-numeric, no dot at the end. Fake up a hostent as if we'd + * actually done a lookup. What if someone types 255.255.255.255? + * The test below will succeed spuriously... ??? + */ + + if (*--cp == '.' || cd != 3) + return INADDR_NONE; + + return addr.addr; + } + else if(cc >= '0' && cc <= '9') + { + addr.d[cd] *= 10; + addr.d[cd] += cc - '0'; + } + else if(cc == '.') + { + if( ++cd >= 4) + break; + } + else + break; + } + } + return INADDR_NONE; +} + +#if 0 +/* ----------------------------------------------------- */ +/* get IP address by host name */ +/* ----------------------------------------------------- */ + + +unsigned long +dns_addr(name) + char *name; +{ + ip_addr addr; + u_char *cp, *eom; + int cc, n, type, ancount, qdcount; + querybuf ans; + char hostbuf[MAXDNAME]; + + /* disallow names consisting only of digits/dots, unless they end in a dot. */ + + cc = name[0]; + if (cc >= '0' && cc <= '9') + { + for (cp = name;; ++cp) + { + cc = *cp; + if (!cc) + { + /* + * All-numeric, no dot at the end. Fake up a hostent as if we'd + * actually done a lookup. What if someone types 255.255.255.255? + * The test below will succeed spuriously... ??? + */ + + if (*--cp == '.') + break; + + return inet_addr(name); + } + if ((cc < '0' || cc > '9') && cc != '.') + break; + } + } + + n = dns_query(name, T_A, &ans); + if (n < 0) + return INADDR_NONE; + + /* find first satisfactory answer */ + + cp = (u_char *) & ans + sizeof(HEADER); + eom = (u_char *) & ans + n; + + for (qdcount = ntohs(ans.hdr.qdcount); qdcount--; cp += n + QFIXEDSZ) + { + if ((n = dn_skipname(cp, eom)) < 0) + return INADDR_NONE; + } + + ancount = ntohs(ans.hdr.ancount); + while (--ancount >= 0 && cp < eom) + { + if ((n = dn_expand((u_char *) &ans, eom, cp, hostbuf, MAXDNAME)) < 0) + return INADDR_NONE; + + cp += n; + type = getshort(cp); + n = getshort(cp + 8); + cp += 10; + + if (type == T_A) + { + + addr.d[0] = cp[0]; + addr.d[1] = cp[1]; + addr.d[2] = cp[2]; + addr.d[3] = cp[3]; + return addr.addr; + } + + cp += n; + } + return INADDR_NONE; +} +#endif diff --git a/lib/dns_ident.c b/lib/dns_ident.c new file mode 100644 index 0000000..f42b294 --- /dev/null +++ b/lib/dns_ident.c @@ -0,0 +1,178 @@ +/*-------------------------------------------------------*/ +/* lib/dns_ident.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : included C file for DNS routines */ +/* create : 96/11/20 */ +/* update : 96/12/15 */ +/*-------------------------------------------------------*/ + + +#include "dns.h" + +#include <unistd.h> /* Thor.991215: for timeout */ +#include <signal.h> + +/* ----------------------------------------------------- */ +/* get remote host / user name */ +/* ----------------------------------------------------- */ + + +/* + * dns_ident() speaks a common subset of the RFC 931, AUTH, TAP, IDENT and + * RFC 1413 protocols. It queries an RFC 931 etc. compatible daemon on a + * remote host to look up the owner of a connection. The information should + * not be used for authentication purposes. + */ + + +#define RFC931_PORT 113 /* Semi-well-known port */ +#define ANY_PORT 0 /* Any old port will do */ + + +#define RFC931_TIMEOUT /* Thor.991215: ¬O§_´£¨Ñ timeout */ + +#ifdef RFC931_TIMEOUT +static const int timeout = 6; /* Y 6 ¬í«á³s½u¥¼§¹¦¨¡A«h©ñ±ó */ + +static void +pseudo_handler() /* Thor.991215: for timeout */ +{ + /* connect time out */ +} +#endif + + +/* Thor.990325: ¬°¤FÅý¤Ï¬d®É¯à½T©w¬d¥X¡A¨Ó¦ÛþÓinterface´N±q¨º³s¦^¡A¥H¨¾¤Ï¬d¤£¨ì */ + +void +dns_ident(sock, from, rhost, ruser) + int sock; /* Thor.990330: t¼Æ«O¯dµ¹, ¥ÎgetsockµLªk§ì¥X¥¿½Tportªº®ÉÔ. + ¥Nªí Port, ¤£¹L¤£¤Ó¥i¯à¥Î¨ì */ + struct sockaddr_in *from; + char *rhost; + char *ruser; +{ + struct sockaddr_in rmt_sin; + struct sockaddr_in our_sin; + unsigned rmt_port, rmt_pt; + unsigned our_port, our_pt; + int s, cc; + char buf[512]; + +#ifdef RFC931_TIMEOUT + unsigned old_alarm; /* Thor.991215: for timeout */ + struct sigaction act, oact; +#endif + + *ruser = '\0'; + + /* get remote host name */ + + if (dns_name((char *) &from->sin_addr, rhost)) + return; /* °²³]¨S¦³ FQDN ´N¨S¦³¶] identd */ + + /* + * Use one unbuffered stdio stream for writing to and for reading from the + * RFC931 etc. server. This is done because of a bug in the SunOS 4.1.x + * stdio library. The bug may live in other stdio implementations, too. + * When we use a single, buffered, bidirectional stdio stream ("r+" or "w+" + * mode) we read our own output. Such behaviour would make sense with + * resources that support random-access operations, but not with sockets. + */ + + /* Thor.990325: ¬°¤FÅý¤Ï¬d®É¯à½T©w¬d¥X¡A¨Ó¦ÛþÓinterface´N±q¨º³s¦^¡A¥H¨¾¤Ï¬d¤£¨ì */ + /* Thor.990330: t¼Æ«O¯dµ¹¡A¥ÎgetsockµLªk§ì¥X¥¿½Tportªº®ÉÔ¡A¤£¤Ó¥i¯à */ + if (sock >= 0) + { + s = sizeof(our_sin); + + if (getsockname(sock, (struct sockaddr *) &our_sin, &s) < 0) + return; + + /* Thor.990325: ¬°¤FÅý¤Ï¬d®É¯à½T©w¬d¥X¡A¨Ó¦ÛþÓinterface´N±q¨º³s¦^ */ + our_pt = ntohs(our_sin.sin_port); + our_sin.sin_port = htons(ANY_PORT); + } + else + { + our_pt = -sock; + } + + if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) + return; + + /* + * Bind the local and remote ends of the query socket to the same IP + * addresses as the connection under investigation. We go through all this + * trouble because the local or remote system might have more than one + * network address. The RFC931 etc. client sends only port numbers; the + * server takes the IP addresses from the query socket. + */ + +#ifdef RFC931_TIMEOUT + /* Thor.991215: set for timeout */ + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = pseudo_handler; /* SIG_IGN; */ + sigaction(SIGALRM, &act, &oact); + + old_alarm = alarm(timeout); +#endif + + rmt_sin = *from; + rmt_pt = ntohs(rmt_sin.sin_port); + rmt_sin.sin_port = htons(RFC931_PORT); + + /* Thor.990325: ¬°¤FÅý¤Ï¬d®É¯à½T©w¬d¥X¡A¨Ó¦ÛþÓinterface´N±q¨º³s¦^ */ + if ((sock < 0 || !bind(s, (struct sockaddr *) & our_sin, sizeof(our_sin))) + && !connect(s, (struct sockaddr *) & rmt_sin, sizeof(rmt_sin))) + { + /* + * Send query to server. Neglect the risk that a 13-byte write would have + * to be fragmented by the local system and cause trouble with buggy + * System V stdio libraries. + */ + + sprintf(buf, "%u,%u\r\n", rmt_pt, our_pt); + write(s, buf, strlen(buf)); + + cc = read(s, buf, sizeof(buf)); + if (cc > 0) + { + buf[cc] = '\0'; + + if (sscanf(buf, "%u , %u : USERID :%*[^:]:%79s", &rmt_port, &our_port, ruser) == 3 && + rmt_pt == rmt_port && our_pt == our_port) + { + /* + * Strip trailing carriage return. It is part of the protocol, not + * part of the data. + */ + + for (;;) + { + cc = *ruser; + + if (cc == '\r') + { + *ruser = '\0'; + break; + } + + if (cc == '\0') + break; + + ruser++; + } + } + } + } + +#ifdef RFC931_TIMEOUT + /* Thor.991215: recover for timeout */ + alarm(old_alarm); + sigaction(SIGALRM, &oact, NULL); +#endif + + close(s); +} diff --git a/lib/dns_name.c b/lib/dns_name.c new file mode 100644 index 0000000..ca70e80 --- /dev/null +++ b/lib/dns_name.c @@ -0,0 +1,78 @@ +/*-------------------------------------------------------*/ +/* lib/dns_name.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : included C file for DNS routines */ +/* create : 96/11/20 */ +/* update : 96/12/15 */ +/*-------------------------------------------------------*/ + + +#include "dns.h" + + +/* ----------------------------------------------------- */ +/* get host name by IP address */ +/* ----------------------------------------------------- */ + + +int +dns_name(addr, name) + unsigned char *addr; + char *name; +{ + querybuf ans; + char qbuf[MAXDNAME]; + char hostbuf[MAXDNAME]; + int n, type, ancount, qdcount; + u_char *cp, *eom; + + sprintf(name, INADDR_FMT, addr[0], addr[1], addr[2], addr[3]); + + sprintf(qbuf, INADDR_FMT ".in-addr.arpa", + addr[3], addr[2], addr[1], addr[0]); + + n = dns_query(qbuf, T_PTR, &ans); + if (n < 0) + return n; + + /* find first satisfactory answer */ + + cp = (u_char *) & ans + sizeof(HEADER); + eom = (u_char *) & ans + n; + + for (qdcount = ntohs(ans.hdr.qdcount); qdcount--; cp += n + QFIXEDSZ) + { + if ((n = dn_skipname(cp, eom)) < 0) + return n; + } + + for (ancount = ntohs(ans.hdr.ancount); --ancount >= 0 && cp < eom; cp += n) + { + if ((n = dn_expand((u_char *) &ans, eom, cp, hostbuf, MAXDNAME)) < 0) + return n; + + cp += n; + type = getshort(cp); + n = getshort(cp + 8); + cp += 10; + + if (type == T_PTR) + { + if ((n = dn_expand((u_char *) &ans, eom, cp, hostbuf, MAXDNAME)) >= 0) + { + strcpy(name, hostbuf); + return 0; + } + } + +#if 0 + if (type == T_CNAME) + { + strcpy(name, hostbuf); + return 0; + } +#endif + } + + return -1; +} diff --git a/lib/dns_open.c b/lib/dns_open.c new file mode 100644 index 0000000..6f588c5 --- /dev/null +++ b/lib/dns_open.c @@ -0,0 +1,98 @@ +/*-------------------------------------------------------*/ +/* lib/dns_open.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : included C file for DNS routines */ +/* create : 96/11/20 */ +/* update : 96/12/15 */ +/*-------------------------------------------------------*/ + + +#include "dns.h" + +/* Thor.990811: find out A record */ + +unsigned long +dns_a(host) + char *host; +{ + querybuf ans; + int n, ancount, qdcount; + unsigned char *cp, *eom; + char buf[MAXDNAME]; + int type; + ip_addr addr; + + n = dns_query(host, T_A, &ans); + if (n < 0) + return INADDR_NONE; + + /* find first satisfactory answer */ + + cp = (u_char *) & ans + sizeof(HEADER); + eom = (u_char *) & ans + n; + + for (qdcount = ntohs(ans.hdr.qdcount); qdcount--; cp += n + QFIXEDSZ) + { + if ((n = dn_skipname(cp, eom)) < 0) + return INADDR_NONE; + } + + ancount = ntohs(ans.hdr.ancount); + + while (--ancount >= 0 && cp < eom) + { + if ((n = dn_expand((void *) &ans, eom, cp, buf, MAXDNAME)) < 0) + return INADDR_NONE; + + cp += n; + + type = getshort(cp); + n = getshort(cp + 8); + cp += 10; + + if (type == T_A) + { + addr.d[0] = cp[0]; + addr.d[1] = cp[1]; + addr.d[2] = cp[2]; + addr.d[3] = cp[3]; + return addr.addr; + } + + cp += n; + } + + return INADDR_NONE; +} + +int +dns_open(host, port) + char *host; + int port; +{ + struct sockaddr_in sin; + ip_addr addr; + + /* Thor.990811: check ¬O§_¤w¬°ip */ + if ((addr.addr = dns_aton(host)) != INADDR_NONE + || (addr.addr = dns_a(host)) != INADDR_NONE) + { + int sock; + + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); + + sin.sin_addr.s_addr = addr.addr; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) + return sock; + + if (!connect(sock, (struct sockaddr *) & sin, sizeof(sin))) + return sock; + + close(sock); + } + return -1; +} diff --git a/lib/dns_smtp.c b/lib/dns_smtp.c new file mode 100644 index 0000000..9124c55 --- /dev/null +++ b/lib/dns_smtp.c @@ -0,0 +1,129 @@ +/*-------------------------------------------------------*/ +/* lib/dns_smtp.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : included C file for DNS routines */ +/* create : 96/11/20 */ +/* update : 96/12/15 */ +/*-------------------------------------------------------*/ + + +#include "dns.h" + + +/* static inline */ void /* Thor. 990811: for bmtad use to check from */ +dns_mx(domain, mxlist) + char *domain; + char *mxlist; +{ + querybuf ans; + int n, ancount, qdcount; + unsigned char *cp, *eom; + int type; + + *mxlist = 0; + + n = dns_query(domain, T_MX, &ans); + + if (n < 0) + return; + + /* find first satisfactory answer */ + + cp = (u_char *) & ans + sizeof(HEADER); + eom = (u_char *) & ans + n; + + for (qdcount = ntohs(ans.hdr.qdcount); qdcount--; cp += n + QFIXEDSZ) + { + if ((n = dn_skipname(cp, eom)) < 0) + return; + } + + ancount = ntohs(ans.hdr.ancount); + domain = mxlist + MAX_MXLIST - MAX_DNAME - 2; + + while (--ancount >= 0 && cp < eom) + { + if ((n = dn_expand((void *) &ans, eom, cp, mxlist, MAX_DNAME)) < 0) + break; + + cp += n; + + type = getshort(cp); + n = getshort(cp + 8); + cp += 10; + + if (type == T_MX) + { + /* pref = getshort(cp); */ + *mxlist = '\0'; + if ((dn_expand((void *) &ans, eom, cp + 2, mxlist, MAX_DNAME)) < 0) + break; + + if (!*mxlist) + return; + + /* Thor.980820:µù¸Ñ: ±N¼ÆÓ MX entry ¥Î : ¦ê°_¨Ó¥H«K¤@Ó¤@Ó¸Õ */ + while (*mxlist) + mxlist++; + *mxlist++ = ':'; + + if (mxlist >= domain) + break; + } + + cp += n; + } + + *mxlist = '\0'; +} + + +int +dns_smtp(host) + char *host; +{ + int sock; + char *str, *ptr, mxlist[MAX_MXLIST]; + +#ifdef HAVE_RELAY_SERVER + /* ¦pªG¦³¦Û©wªº relay server¡A¥ý try ¥¦¸Õ¸Õ */ + if ((sock = dns_open(RELAY_SERVER, 25)) >= 0) + return sock; +#endif + + dns_mx(host, str = mxlist); + if (!*str) + { + /* Thor.990716: ¦]©I¥s®É¥i¯à±Nhost¥Îip©ñ¤J¡A¬G§@¯S§O³B²z¡A + ¨Ï¤£³z¹Ldns_open()±H«H */ + /* if(*host>='0' && *host<='9') return -1; */ + /* Thor.990811: ¥Îdns_aton()¸û§¹¾ã */ + if (dns_aton(host) != INADDR_NONE) + return -1; + + str = host; + } + + for (;;) + { /* Thor.980820: µù¸Ñ: ¸U¤@host®æ¦¡¬° xxx:yyy:zzz, «h¥ý¸Õ xxx,¤£¦æ¦A¸Õ yyy */ + ptr = str; + while (sock = *ptr) + { + if (sock == ':') + { + *ptr++ = '\0'; + break; + } + ptr++; + } + + if (!*str) + return -1; + + sock = dns_open(str, 25); + if (sock >= 0) + return sock; + + str = ptr; + } +} diff --git a/lib/f_cat.c b/lib/f_cat.c new file mode 100644 index 0000000..4aaf60b --- /dev/null +++ b/lib/f_cat.c @@ -0,0 +1,16 @@ +#include <fcntl.h> + + +void +f_cat(fpath, msg) + char *fpath; + char *msg; +{ + int fd; + + if ((fd = open(fpath, O_WRONLY | O_CREAT | O_APPEND, 0600)) >= 0) + { + write(fd, msg, strlen(msg)); + close(fd); + } +} diff --git a/lib/f_cp.c b/lib/f_cp.c new file mode 100644 index 0000000..bf741c0 --- /dev/null +++ b/lib/f_cp.c @@ -0,0 +1,35 @@ +#include "dao.h" +#include <sys/types.h> +#include <fcntl.h> + + +int +f_cp(src, dst, mode) + char *src, *dst; + int mode; /* O_EXCL / O_APPEND / O_TRUNC */ +{ + int fsrc, fdst, ret; + + ret = 0; + + if ((fsrc = open(src, O_RDONLY)) >= 0) + { + ret = -1; + + if ((fdst = open(dst, O_WRONLY | O_CREAT | mode, 0600)) >= 0) + { + char pool[BLK_SIZ]; + + src = pool; + do + { + ret = read(fsrc, src, BLK_SIZ); + if (ret <= 0) + break; + } while (write(fdst, src, ret) > 0); + close(fdst); + } + close(fsrc); + } + return ret; +} diff --git a/lib/f_img.c b/lib/f_img.c new file mode 100644 index 0000000..e34c4d6 --- /dev/null +++ b/lib/f_img.c @@ -0,0 +1,32 @@ +#include <stdlib.h> +#include <fcntl.h> +#include <sys/stat.h> + + +char * +f_img(fpath, fsize) + char *fpath; + int *fsize; +{ + int fd, size; + struct stat st; + + if ((fd = open(fpath, O_RDONLY)) < 0) + return NULL; + + fpath = NULL; + + if (!fstat(fd, &st) && S_ISREG(st.st_mode) && (size = st.st_size) > 0 && + (fpath = (char *) malloc(size))) + { + *fsize = size; + if (read(fd, fpath, size) != size) + { + free(fpath); + fpath = NULL; + } + } + + close(fd); + return fpath; +} diff --git a/lib/f_ln.c b/lib/f_ln.c new file mode 100644 index 0000000..8726e2f --- /dev/null +++ b/lib/f_ln.c @@ -0,0 +1,22 @@ +/* ----------------------------------------------------- */ +/* f_ln() : link() cross partition / disk */ +/* ----------------------------------------------------- */ + + +#include <fcntl.h> +#include <errno.h> + + +int +f_ln(src, dst) + char *src, *dst; +{ + int ret; + + if (ret = link(src, dst)) + { + if (errno != EEXIST) + ret = f_cp(src, dst, O_EXCL); + } + return ret; +} diff --git a/lib/f_lock.c b/lib/f_lock.c new file mode 100644 index 0000000..e47bfe9 --- /dev/null +++ b/lib/f_lock.c @@ -0,0 +1,36 @@ +#include <unistd.h> +#include <fcntl.h> + +static struct flock fl = +{ + l_whence: SEEK_SET, + l_start: 0, + l_len: 0, +}; + + +int +f_exlock(fd) + int fd; +{ +#if 0 + return flock(fd, LOCK_EX); +#endif + /* Thor.981205: ¥Î fcntl ¨ú¥N flock¡APOSIX ¼Ð·Ç¥Îªk */ + fl.l_type = F_WRLCK; + /* Thor.990309: with blocking */ + return fcntl(fd, F_SETLKW /* F_SETLK */, &fl); +} + + +int +f_unlock(fd) + int fd; +{ +#if 0 + return flock(fd, LOCK_UN); +#endif + /* Thor.981205: ¥Î fcntl ¨ú¥N flock¡APOSIX ¼Ð·Ç¥Îªk */ + fl.l_type = F_UNLCK; + return fcntl(fd, F_SETLKW /* F_SETLK */, &fl); +} diff --git a/lib/f_map.c b/lib/f_map.c new file mode 100644 index 0000000..e60c2f4 --- /dev/null +++ b/lib/f_map.c @@ -0,0 +1,35 @@ +#include <stdio.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/mman.h> + + +#ifdef MAP_FILE /* 44BSD defines this & requires it to mmap files */ +# define DAO_MAP (MAP_SHARED | MAP_FILE) +#else +# define DAO_MAP (MAP_SHARED) +#endif + + +char * +f_map(fpath, fsize) + char *fpath; + int *fsize; +{ + int fd, size; + struct stat st; + + if ((fd = open(fpath, O_RDONLY)) < 0) + return (char *) -1; + + if (fstat(fd, &st) || !S_ISREG(st.st_mode) || (size = st.st_size) <= 0) + { + close(fd); + return (char *) -1; + } + + fpath = (char *) mmap(NULL, size, PROT_READ, DAO_MAP, fd, 0); + close(fd); + *fsize = size; + return fpath; +} diff --git a/lib/f_mode.c b/lib/f_mode.c new file mode 100644 index 0000000..c077077 --- /dev/null +++ b/lib/f_mode.c @@ -0,0 +1,14 @@ +#include <sys/stat.h> + + +int +f_mode(fpath) + char *fpath; +{ + struct stat st; + + if (stat(fpath, &st)) + return 0; + + return st.st_mode; +} diff --git a/lib/f_mv.c b/lib/f_mv.c new file mode 100644 index 0000000..8ec96f9 --- /dev/null +++ b/lib/f_mv.c @@ -0,0 +1,17 @@ +#include <fcntl.h> + + +int +f_mv(src, dst) + char *src, *dst; +{ + int ret; + + if (ret = rename(src, dst)) + { + ret = f_cp(src, dst, O_TRUNC); + if (!ret) + unlink(src); + } + return ret; +} diff --git a/lib/f_new.c b/lib/f_new.c new file mode 100644 index 0000000..2c21e75 --- /dev/null +++ b/lib/f_new.c @@ -0,0 +1,50 @@ +/* ----------------------------------------------------- */ +/* exclusively create file [*.n] */ +/* ----------------------------------------------------- */ + + +#include <stdio.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> + + +FILE * +f_new(fold, fnew) + char *fold; + char *fnew; +{ + int fd, try; + extern int errno; + + try = 0; + str_cat(fnew, fold, ".n"); + + for (;;) + { + fd = open(fnew, O_WRONLY | O_CREAT | O_EXCL, 0600); + + if (fd >= 0) + return fdopen(fd, "w"); + + if (errno != EEXIST) + break; + + if (!try++) + { + struct stat st; + + if (stat(fnew, &st)) + break; + if (st.st_mtime < time(NULL) - 20 * 60) /* °²³] 20 ¤ÀÄÁ¤ºÀ³¸Ó³B²z§¹ */ + unlink(fnew); + } + else + { + if (try > 24) /* µ¥«Ý 120 ¬íÄÁ */ + break; + sleep(5); + } + } + return NULL; +} diff --git a/lib/f_path.c b/lib/f_path.c new file mode 100644 index 0000000..340e726 --- /dev/null +++ b/lib/f_path.c @@ -0,0 +1,86 @@ +/* ----------------------------------------------------- */ +/* file structure : set file path for boards/user home */ +/* ----------------------------------------------------- */ + + +static void +mak_fpath(str, key, name) + char *str; + char *key; + char *name; +{ + int cc; + + cc = '/'; + for (;;) + { + *str = cc; + if (!cc) + break; + str++; + cc = *key++; + } + + if (name) + { + *str++ = '/'; + strcpy(str, name); + } +} + + +void +brd_fpath(fpath, board, fname) + char *fpath; + char *board; + char *fname; +{ + *fpath++ = 'b'; + *fpath++ = 'r'; + *fpath++ = 'd'; + mak_fpath(fpath, board, fname); +} + + +void +gem_fpath(fpath, board, fname) + char *fpath; + char *board; + char *fname; +{ + *fpath++ = 'g'; + *fpath++ = 'e'; + *fpath++ = 'm'; + *fpath++ = '/'; + *fpath++ = 'b'; + *fpath++ = 'r'; + *fpath++ = 'd'; + mak_fpath(fpath, board, fname); +} + + +void +usr_fpath(fpath, user, fname) + char *fpath; + char *user; + char *fname; +{ +#define IDLEN 12 /* Length of user id, copy from struct.h */ + + char buf[IDLEN + 1]; + + *fpath++ = 'u'; + *fpath++ = 's'; + *fpath++ = 'r'; + *fpath++ = '/'; + +#if 0 + str_lower(buf, user); /* lower case */ +#endif + /* Thor.981027: ¨¾¤î buffer overflow, ÁöµM SunOS 4.1.x¤WµL¦¹±¡ªp, ¥H«á¦A·Q¦nªº§ïªk */ + str_ncpy(buf, user, sizeof(buf)); + str_lower(buf, buf); + + *fpath++ = *buf; + mak_fpath(fpath, buf, fname); +} diff --git a/lib/f_rm.c b/lib/f_rm.c new file mode 100644 index 0000000..5158306 --- /dev/null +++ b/lib/f_rm.c @@ -0,0 +1,59 @@ +#include <sys/stat.h> +#include <dirent.h> + + +static int +rm_dir(fpath) + char *fpath; +{ + struct stat st; + DIR *dirp; + struct dirent *de; + char buf[256], *fname; + + if (!(dirp = opendir(fpath))) + return -1; + + for (fname = buf; *fname = *fpath; fname++, fpath++) + ; + + *fname++ = '/'; + + while (de = readdir(dirp)) + { + fpath = de->d_name; + + /* skip ./ ¤Î ../ */ + if (!*fpath || (*fpath == '.' && (fpath[1] == '\0' || (fpath[1] == '.' && fpath[2] == '\0')))) + continue; + + strcpy(fname, fpath); + if (!stat(buf, &st)) + { + if (S_ISDIR(st.st_mode)) + rm_dir(buf); + else + unlink(buf); + } + } + closedir(dirp); + + *--fname = '\0'; + return rmdir(buf); +} + + +int +f_rm(fpath) + char *fpath; +{ + struct stat st; + + if (stat(fpath, &st)) + return -1; + + if (!S_ISDIR(st.st_mode)) + return unlink(fpath); + + return rm_dir(fpath); +} diff --git a/lib/f_suck.c b/lib/f_suck.c new file mode 100644 index 0000000..098f96d --- /dev/null +++ b/lib/f_suck.c @@ -0,0 +1,26 @@ +#include "dao.h" +#include <stdio.h> +#include <fcntl.h> +#include <sys/types.h> + + +void +f_suck(fp, fpath) + FILE *fp; + char *fpath; +{ + int fd; + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + char pool[BLK_SIZ]; + int size; + + fpath = pool; + while ((size = read(fd, fpath, BLK_SIZ)) > 0) + { + fwrite(fpath, size, 1, fp); + } + close(fd); + } +} diff --git a/lib/hash32.c b/lib/hash32.c new file mode 100644 index 0000000..431cde4 --- /dev/null +++ b/lib/hash32.c @@ -0,0 +1,13 @@ +int +hash32(str) + unsigned char *str; +{ + int xo, cc; + + xo = 1048583; /* a big prime number */ + while (cc = *str++) + { + xo = (xo << 5) - xo + cc; /* 31 * xo + cc */ + } + return (xo & 0x7fffffff); +} diff --git a/lib/hdr_fpath.c b/lib/hdr_fpath.c new file mode 100644 index 0000000..064a828 --- /dev/null +++ b/lib/hdr_fpath.c @@ -0,0 +1,37 @@ +#include "dao.h" + + +void +hdr_fpath(fpath, folder, hdr) + char *fpath; + char *folder; + HDR *hdr; +{ + char *str; + int cc, chrono; + + while (cc = *folder++) + { + *fpath++ = cc; + if (cc == '/') + str = fpath; + } + + chrono = hdr->chrono; + folder = hdr->xname; + cc = *folder; + if (cc != '@') + cc = radix32[chrono & 31]; + + if (*str == '.') + { + *str++ = cc; + *str++ = '/'; + } + else + { + str[-2] = cc; + } + + strcpy(str, hdr->xname); +} diff --git a/lib/hdr_stamp.c b/lib/hdr_stamp.c new file mode 100644 index 0000000..bcdcae9 --- /dev/null +++ b/lib/hdr_stamp.c @@ -0,0 +1,131 @@ +/* ----------------------------------------------------- */ +/* hdr_stamp - create unique HDR based on timestamp */ +/* ----------------------------------------------------- */ +/* fpath - directory */ +/* token - (A / F / 0) | [HDR_LINK / HDR_COPY] */ +/* ----------------------------------------------------- */ +/* return : open() fd (not close yet) or link() result */ +/* ----------------------------------------------------- */ + + +#include "dao.h" +#include <fcntl.h> +#include <errno.h> + +#if 0 /* itoc.030303.µù¸Ñ: ²©ö»¡©ú */ + + hdr_stamp() ·|°µ¥X¤@Ó·sªº HDR¡A¨Ì¶Ç¤Jªº token ¤£¦P¦Ó¦³®t²§¡G + + 0 : ·s¼W¤@½g«H¥ó(family ¬O @)¡A¦^¶Çªº fpath ¬O hdr ©Ò«ü¦V + ©M hdr_fpath(fpath, folder, hdr); ©Ò²£¥Íªº fpath ¬Û¦P + + 'A': ·s¼W¤@½g¤å³¹(family ¬O A)¡A¦^¶Çªº fpath ¬O hdr ©Ò«ü¦V + ©M hdr_fpath(fpath, folder, hdr); ©Ò²£¥Íªº fpath ¬Û¦P + + 'F': ·s¼W¤@Ó¨÷©v(family ¬O F)¡A¦^¶Çªº fpath ¬O hdr ©Ò«ü¦V + ©M hdr_fpath(fpath, folder, hdr); ©Ò²£¥Íªº fpath ¬Û¦P + + HDR_LINK : fpath ¤w¦³ÂÂÀɮ׮ɡAn½Æ»sÂÂÀɮרì·s«H¥ó(family ¬O @) ¥h + ¨Ã±N hdr «ü¦V³o½g·s«H¥ó¡A¦^¶Çªº fpath ¬Oì¨ÓÂÂÀÉ®× + ÂÂÀɮשM·s«H¥ó¬O hard link¡A§ï¤F¨ä¤¤¤@½g¡A¥t¤@½g¤]·|¤@°_³Q§ï + §R°£ÂÂÀɮסA·s«H¥ó¨Ã¤£·|³Q§R°£ + + HDR_LINK | 'A': fpath ¤w¦³ÂÂÀɮ׮ɡAn½Æ»sÂÂÀɮרì·s¤å³¹(family ¬O A) ¥h + ¨Ã±N hdr «ü¦V³o½g·s¤å³¹¡A¦^¶Çªº fpath ¬Oì¨ÓÂÂÀÉ®× + ÂÂÀɮשM·s¤å³¹¬O hard link¡A§ï¤F¨ä¤¤¤@½g¡A¥t¤@½g¤]·|¤@°_³Q§ï + §R°£ÂÂÀɮסA·s¤å³¹¨Ã¤£·|³Q§R°£ + + HDR_COPY : fpath ¤w¦³ÂÂÀɮ׮ɡAn½Æ»sÂÂÀɮרì·s«H¥ó(family ¬O @) ¥h + ¨Ã±N hdr «ü¦V³o½g·s«H¥ó¡A¦^¶Çªº fpath ¬Oì¨ÓÂÂÀÉ®× + ÂÂÀɮשM·s«H¥ó¬O copy¡A§ï¤F¨ä¤¤¤@½g¡A¥t¤@½g¨Ã¤£·|³Q§ï + ÂÂÀÉ®×»P·s«H¥ó¬O§¹¥þ¿W¥ß¤£¬ÛÃöªº¤GÓÀÉ®× + + HDR_COPY | 'A': fpath ¤w¦³ÂÂÀɮ׮ɡAn½Æ»sÂÂÀɮרì·s¤å³¹(family ¬O A) ¥h + ¨Ã±N hdr «ü¦V³o½g·s¤å³¹¡A¦^¶Çªº fpath ¬Oì¨ÓÂÂÀÉ®× + ÂÂÀɮשM·s¤å³¹¬O copy¡A§ï¤F¨ä¤¤¤@½g¡A¥t¤@½g¨Ã¤£·|³Q§ï + ÂÂÀÉ®×»P·s¤å³¹¬O§¹¥þ¿W¥ß¤£¬ÛÃöªº¤GÓÀÉ®× + +#endif + +int +hdr_stamp(folder, token, hdr, fpath) + char *folder; + int token; + HDR *hdr; + char *fpath; +{ + char *fname, *family; + int rc, chrono; + char *flink, buf[128]; + + flink = NULL; + if (token & (HDR_LINK | HDR_COPY)) + { + flink = fpath; + fpath = buf; + } + + fname = fpath; + while (rc = *folder++) + { + *fname++ = rc; + if (rc == '/') + family = fname; + } + if (*family != '.') + { + fname = family; + family -= 2; + } + else + { + fname = family + 1; + *fname++ = '/'; + } + + if (rc = token & 0xdf) /* Åܤj¼g */ + { + *fname++ = rc; + } + else + { + *fname = *family = '@'; + family = ++fname; + } + + chrono = time(0); + + for (;;) + { + *family = radix32[chrono & 31]; + archiv32(chrono, fname); + + if (flink) + { + if (token & HDR_LINK) + rc = f_ln(flink, fpath); + else + rc = f_cp(flink, fpath, O_EXCL); + } + else + { + rc = open(fpath, O_WRONLY | O_CREAT | O_EXCL, 0600); + } + + if (rc >= 0) + { + memset(hdr, 0, sizeof(HDR)); + hdr->chrono = chrono; + str_stamp(hdr->date, &hdr->chrono); + strcpy(hdr->xname, --fname); + break; + } + + if (errno != EEXIST) + break; + + chrono++; + } + + return rc; +} diff --git a/lib/is_alnum.c b/lib/is_alnum.c new file mode 100644 index 0000000..cc65945 --- /dev/null +++ b/lib/is_alnum.c @@ -0,0 +1,7 @@ +int +is_alnum(ch) + int ch; +{ + return ((ch >= '0' && ch <= '9') || + (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')); +} diff --git a/lib/is_alpha.c b/lib/is_alpha.c new file mode 100644 index 0000000..dad6cef --- /dev/null +++ b/lib/is_alpha.c @@ -0,0 +1,6 @@ +int +is_alpha(ch) + int ch; +{ + return ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')); +} diff --git a/lib/mak_dirs.c b/lib/mak_dirs.c new file mode 100644 index 0000000..1857d14 --- /dev/null +++ b/lib/mak_dirs.c @@ -0,0 +1,66 @@ +/* ----------------------------------------------------- */ +/* make directory hierarchy [0-9A-V] : 32-way interleave */ +/* ----------------------------------------------------- */ + + +#include <sys/stat.h> + + +void +mak_dirs(fpath) + char *fpath; +{ + char *fname; + int ch; + + if (mkdir(fpath, 0700)) + return; + + fname = fpath; + while (*++fname); + *fname++ = '/'; + fname[1] = '\0'; + + ch = '0'; + for (;;) + { + *fname = ch++; + mkdir(fpath, 0700); + if (ch == 'W') + break; + if (ch == '9' + 1) + ch = '@'; /* @ : for special purpose */ + } + + fname[-1] = '\0'; +} + + +void +mak_links(fpath) /* itoc.010924: ´î¤ÖÓ¤HºëµØ°Ï¥Ø¿ý¡A¥Î link ¨Ó¥N´À¥Ø¿ý */ + char *fpath; +{ + char *fname; + int ch; + + if (mkdir(fpath, 0700)) + return; + + fname = fpath; + while (*++fname); + *fname++ = '/'; + fname[1] = '\0'; + + ch = '0'; + for (;;) + { + *fname = ch++; + symlink(".", fpath); + if (ch == 'W') + break; + if (ch == '9' + 1) + ch = '@'; /* @ : for special purpose */ + } + + fname[-1] = '\0'; +} diff --git a/lib/not_addr.c b/lib/not_addr.c new file mode 100644 index 0000000..5566213 --- /dev/null +++ b/lib/not_addr.c @@ -0,0 +1,32 @@ +#define STRICT_FQDN_EMAIL + + +int +not_addr(addr) + char *addr; +{ + int ch, mode; + + mode = -1; + + while (ch = *addr) + { + if (ch == '@') + { + if (++mode) + break; + } + +#ifdef STRICT_FQDN_EMAIL + else if ((ch != '.') && (ch != '-') && (ch != '_') && !is_alnum(ch)) +#else + else if (!is_alnum(ch) && !strchr(".-_[]%!:", ch)) +#endif + + return 1; + + addr++; + } + + return mode; +} diff --git a/lib/radix32.c b/lib/radix32.c new file mode 100644 index 0000000..2a6cbb0 --- /dev/null +++ b/lib/radix32.c @@ -0,0 +1,13 @@ +/* ----------------------------------------------------- */ +/* chrono ==> file name (32-based) */ +/* 0123456789ABCDEFGHIJKLMNOPQRSTUV */ +/* ----------------------------------------------------- */ + + +char radix32[32] = +{ + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', +}; diff --git a/lib/rec_add.c b/lib/rec_add.c new file mode 100644 index 0000000..c7d0b1b --- /dev/null +++ b/lib/rec_add.c @@ -0,0 +1,21 @@ +#include <fcntl.h> + + +int +rec_add(fpath, data, size) + char *fpath; + void *data; + int size; +{ + int fd; + + if ((fd = open(fpath, O_WRONLY | O_CREAT | O_APPEND, 0600)) < 0) + return -1; + + /* flock(fd, LOCK_EX); */ + write(fd, data, size); + /* flock(fd, LOCK_UN); */ + close(fd); + + return 0; +} diff --git a/lib/rec_bot.c b/lib/rec_bot.c new file mode 100644 index 0000000..3b15f1e --- /dev/null +++ b/lib/rec_bot.c @@ -0,0 +1,87 @@ +#include "dao.h" +#include <fcntl.h> +#include <unistd.h> +#include <sys/file.h> +#include <sys/stat.h> + + +static int +is_bottompost(hdr) + HDR *hdr; +{ + return (hdr->xmode & POST_BOTTOM); +} + + +int +rec_bot(fpath, data, size) /* amaki.040715: ´O¤J¦¡¼gÀÉ */ + char *fpath; + void *data; + int size; +{ + int fd, fsize, count; + void *pool, *set; + char set_pool[REC_SIZ]; + struct stat st; + + if ((fd = open(fpath, O_RDWR | O_CREAT, 0600)) < 0) + return -1; + + /* flock(fd, LOCK_EX); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_exlock(fd); + + fstat(fd, &st); + + count = 0; + set = (void *) set_pool; + + if (fsize = st.st_size) + { + while ((fsize -= size) >= 0) + { + lseek(fd, fsize, SEEK_SET); + read(fd, set, size); + + if (!is_bottompost(set)) + { + if (count) + { + pool = (void *) malloc(count * size); + + read(fd, pool, count * size); + lseek(fd, -size * count, SEEK_CUR); + } + break; + } + else if (fsize <= 0) /* amaki.040715: ¥þ³¡³£¬O¸m©³ªºªF¦è */ + { + count++; + pool = (void *) malloc(count * size); + + lseek(fd, -size, SEEK_CUR); + read(fd, pool, count * size); + lseek(fd, -size * count, SEEK_CUR); + break; + } + else + count++; + } + } + + write(fd, data, size); + + if (count) + { + write(fd, pool, count * size); + free(pool); + } + + /* flock(fd, LOCK_EX); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_unlock(fd); + + close(fd); + + return 0; +} diff --git a/lib/rec_del.c b/lib/rec_del.c new file mode 100644 index 0000000..dd1a167 --- /dev/null +++ b/lib/rec_del.c @@ -0,0 +1,84 @@ +#include "dao.h" +#include <fcntl.h> +#include <unistd.h> +#include <sys/file.h> +#include <sys/stat.h> + + +int +rec_del(fpath, size, pos, fchk) + char *fpath; + int size; + int pos; + int (*fchk) (); +{ + int fd; + off_t off, len; + char pool[REC_SIZ]; + struct stat st; + + if ((fd = open(fpath, O_RDWR)) < 0) + return -1; + + /* flock(fd, LOCK_EX); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_exlock(fd); + + fstat(fd, &st); + len = st.st_size; + + fpath = pool; + off = size * pos; + + /* ÅçÃÒ pos ¦ì¸m¸ê®Æªº¥¿½T©Ê */ + + if (len > off) + { + lseek(fd, off, SEEK_SET); + read(fd, fpath, size); + + pos = fchk ? (*fchk) (fpath) : 1; + } + else + { + pos = 0; + } + + /* ¤£¹ïªº¸Ü¡A«ÀY§ä°_ */ + + if (!pos) + { + off = 0; + lseek(fd, off, SEEK_SET); + while (read(fd, fpath, size) == size) + { + if (pos = (*fchk) (fpath)) + break; + + off += size; + } + } + + /* §ä¨ì¤§«á¡A§R°£¸ê®Æ */ + + if (pos) + { + len -= (off + size); + fpath = (char *) malloc(len); + read(fd, fpath, len); + + lseek(fd, off, SEEK_SET); + write(fd, fpath, len); + + ftruncate(fd, off + len); + free(fpath); + } + + /* flock(fd, LOCK_UN); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_unlock(fd); + + close(fd); + + return !pos; +} diff --git a/lib/rec_get.c b/lib/rec_get.c new file mode 100644 index 0000000..05c3f3a --- /dev/null +++ b/lib/rec_get.c @@ -0,0 +1,26 @@ +#include <fcntl.h> +#include <unistd.h> + + +int +rec_get(fpath, data, size, pos) + char *fpath; + void *data; + int size, pos; +{ + int fd; + int ret; + + ret = -1; + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + if (lseek(fd, (off_t) (size * pos), SEEK_SET) >= 0) + { + if (read(fd, data, size) == size) + ret = 0; + } + close(fd); + } + return ret; +} diff --git a/lib/rec_ins.c b/lib/rec_ins.c new file mode 100644 index 0000000..fbac05f --- /dev/null +++ b/lib/rec_ins.c @@ -0,0 +1,58 @@ +#include <fcntl.h> +#include <unistd.h> +#include <sys/file.h> +#include <sys/stat.h> + + +int +rec_ins(fpath, data, size, pos, num) + char *fpath; + void *data; + int size; + int pos; + int num; +{ + int fd; + off_t off, len; + struct stat st; + + if ((fd = open(fpath, O_RDWR | O_CREAT, 0600)) < 0) + return -1; + + /* flock(fd, LOCK_EX); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_exlock(fd); + + fstat(fd, &st); + len = st.st_size; + + /* lkchu.990428: ernie patch ¦pªG len=0 & pos>0 + (¦bè¶}ºëµØ°Ï¥Ø¿ý¶i¥h¶K¤W¡A¿ï¤U¤@Ó) ®É·|¼g¤J©U§£ */ + off = len ? size * pos : 0; + lseek(fd, off, SEEK_SET); + + size *= num; + len -= off; + if (len > 0) + { + fpath = (char *) malloc(pos = len + size); + memcpy(fpath, data, size); + read(fd, fpath + size, len); + lseek(fd, off, SEEK_SET); + data = fpath; + size = pos; + } + + write(fd, data, size); + + /* flock(fd, LOCK_UN); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_unlock(fd); + + close(fd); + + if (len > 0) + free(data); + + return 0; +} diff --git a/lib/rec_mov.c b/lib/rec_mov.c new file mode 100644 index 0000000..d9eef86 --- /dev/null +++ b/lib/rec_mov.c @@ -0,0 +1,75 @@ +#include <fcntl.h> +#include <unistd.h> +#include <sys/file.h> +#include <sys/stat.h> + + +int +rec_mov(fpath, size, from, to) + char *fpath; + int size; + int from; + int to; +{ + int fd, backward; + off_t off, len; + char *pool; + struct stat st; + + if ((fd = open(fpath, O_RDWR)) < 0) + return -1; + + /* flock(fd, LOCK_EX); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_exlock(fd); + + fstat(fd, &st); + len = st.st_size / size - 1; + + if (from > to) + { + backward = from; + from = to; + to = backward; + backward = 1; + } + else + { + backward = 0; + } + + if (to >= len) + to = len; + + off = size * from; + lseek(fd, off, SEEK_SET); + + len = (to - from + 1) * size; + pool = fpath = (char *) malloc(len + size); + + if (backward) + fpath += size; + read(fd, fpath, len); + + fpath = pool + len; + if (backward) + memcpy(pool, fpath, size); + else + memcpy(fpath, pool, size); + + fpath = pool; + if (!backward) + fpath += size; + + lseek(fd, off, SEEK_SET); + write(fd, fpath, len); + + /* flock(fd, LOCK_UN); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_unlock(fd); + + close(fd); + free(pool); + + return 0; +} diff --git a/lib/rec_num.c b/lib/rec_num.c new file mode 100644 index 0000000..b0cc375 --- /dev/null +++ b/lib/rec_num.c @@ -0,0 +1,14 @@ +#include <sys/stat.h> + + +int +rec_num(fpath, size) + char *fpath; + int size; +{ + struct stat st; + + if (stat(fpath, &st)) + return 0; + return (st.st_size / size); +} diff --git a/lib/rec_put.c b/lib/rec_put.c new file mode 100644 index 0000000..c61f081 --- /dev/null +++ b/lib/rec_put.c @@ -0,0 +1,92 @@ +#include "dao.h" +#include <fcntl.h> +#include <unistd.h> +#include <sys/file.h> +#include <sys/stat.h> + + +int +rec_put(fpath, data, size, pos, fchk) + char *fpath; + void *data; + int size, pos; + int (*fchk)(); +{ + int fd; + off_t off, len; + char pool[REC_SIZ]; + struct stat st; + + if ((fd = open(fpath, O_RDWR | O_CREAT, 0600)) < 0) + return -1; + + /* flock(fd, LOCK_EX); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_exlock(fd); + + fstat(fd, &st); + len = st.st_size; + + fpath = pool; + off = size * pos; + + /* ÅçÃÒ pos ¦ì¸m¸ê®Æªº¥¿½T©Ê */ + + if (len > off) + { + if (fchk) + { + lseek(fd, off, SEEK_SET); + read(fd, fpath, size); + pos = (*fchk) (fpath); + } + else + { + pos = 1; + } + } + else + { + if (len) + { + pos = 0; /* ±qÀY§ä°_ */ + } + else + { + /* Y쥻¬OªÅÀɮסA¨º»ò rec_put ·í¦¨ rec_add */ + pos = 1; + off = 0; + } + } + + /* ¤£¹ïªº¸Ü¡A«ÀY§ä°_ */ + + if (!pos) + { + off = 0; + lseek(fd, off, SEEK_SET); + while (read(fd, fpath, size) == size) + { + if (pos = (*fchk) (fpath)) + break; + + off += size; + } + } + + /* §ä¨ì¤§«á¡A§ó·s¸ê®Æ */ + + if (pos) + { + lseek(fd, off, SEEK_SET); + write(fd, data, size); + } + + /* flock(fd, LOCK_UN); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_unlock(fd); + + close(fd); + + return 0; +} diff --git a/lib/rec_ref.c b/lib/rec_ref.c new file mode 100644 index 0000000..ca5afdb --- /dev/null +++ b/lib/rec_ref.c @@ -0,0 +1,88 @@ +#include "dao.h" +#include <fcntl.h> +#include <unistd.h> +#include <sys/file.h> +#include <sys/stat.h> + + +int +rec_ref(fpath, data, size, pos, fchk, fref) + char *fpath; + void *data; + int size, pos; + int (*fchk)(); + void (*fref)(); +{ + int fd; + off_t off, len; + char pool[REC_SIZ]; + struct stat st; + + if ((fd = open(fpath, O_RDWR, 0600)) < 0) + return -1; + + /* flock(fd, LOCK_EX); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_exlock(fd); + + fstat(fd, &st); + len = st.st_size; + + fpath = pool; + off = size * pos; + + /* ÅçÃÒ pos ¦ì¸m¸ê®Æªº¥¿½T©Ê */ + + if (len > off) + { + lseek(fd, off, SEEK_SET); + read(fd, fpath, size); + pos = fchk ? (*fchk) (fpath) : 1; + } + else + { + if (len) + { + pos = 0; /* ±qÀY§ä°_ */ + } + else + { + /* Y쥻¬OªÅÀɮסA¨º»ò©ñ±ó */ + f_unlock(fd); + close(fd); + return -1; + } + } + + /* ¤£¹ïªº¸Ü¡A«ÀY§ä°_ */ + + if (!pos) + { + off = 0; + lseek(fd, off, SEEK_SET); + while (read(fd, fpath, size) == size) + { + if (pos = (*fchk) (fpath)) + break; + + off += size; + } + } + + /* §ä¨ì¤§«á¡A§ó·s¸ê®Æ */ + + if (pos) + { + (*fref) (fpath, data); + lseek(fd, off, SEEK_SET); + write(fd, fpath, size); + } + + /* flock(fd, LOCK_UN); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_unlock(fd); + + close(fd); + + return 0; +} diff --git a/lib/rec_sync.c b/lib/rec_sync.c new file mode 100644 index 0000000..f3c372f --- /dev/null +++ b/lib/rec_sync.c @@ -0,0 +1,72 @@ +#include "dao.h" +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> + + +int +rec_sync(fpath, size, fsync, fchk) + char *fpath; + int size; + int (*fsync) (); + int (*fchk) (); +{ + int fd, fsize; + struct stat st; + + fsize = 0; + + if ((fd = open(fpath, O_RDWR, 0600)) < 0) + return fsize; + + if (!fstat(fd, &st) && (fsize = st.st_size) > 0) + { + char *base; + + base = (char *) malloc(fsize); + fsize = read(fd, base, fsize); + + if (fsize >= size) + { + if (fchk) /* Àˬd¬O§_¦³¤£¥¿½Tªº¸ê®Æ */ + { + char *head, *tail; + + head = base; + tail = base + fsize; + while (head < tail) + { + if (fchk(head)) /* ¦¹µ§¸ê®Æ¥¿½T */ + { + head += size; + continue; + } + + /* ¦³°ÝÃDªº¸ê®Æn§R°£ */ + tail -= size; + if (head >= tail) + break; + memcpy(head, tail, size); + } + fsize = tail - base; + } + + if (fsize > 0) + { + if (fsize > size) + qsort(base, fsize / size, size, fsync); + + lseek(fd, 0, SEEK_SET); + write(fd, base, fsize); + ftruncate(fd, fsize); + } + } + free(base); + } + close(fd); + + if (fsize <= 0) + unlink(fpath); + + return fsize; +} diff --git a/lib/rfc2047.c b/lib/rfc2047.c new file mode 100644 index 0000000..b521660 --- /dev/null +++ b/lib/rfc2047.c @@ -0,0 +1,193 @@ +/*-------------------------------------------------------*/ +/* rfc2047.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : RFC 2047 QP/base64 encode */ +/* create : 03/04/11 */ +/* update : 03/05/19 */ +/* author : PaulLiu.bbs@bbs.cis.nctu.edu.tw */ +/*-------------------------------------------------------*/ + + +#include <stdio.h> + + +#if 0 /* itoc.030411: ¨S¦³¸g RFC 2047 encode */ +void +output_str(fp, prefix, str, charset, suffix) + FILE *fp; + char *prefix; + char *str; + char *charset; + char *suffix; +{ + fprintf(fp, "%s%s%s", prefix, str, suffix); +} +#endif + + +/*-------------------------------------------------------*/ +/* RFC2047 QP encode */ +/*-------------------------------------------------------*/ + + +void +output_rfc2047_qp(fp, prefix, str, charset, suffix) + FILE *fp; + char *prefix; + char *str; + char *charset; + char *suffix; +{ + int i, ch; + int blank = 1; /* 1:¥þ¥ÑªÅ¥Õ²Õ¦¨ */ + static char tbl[16] = {'0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F'}; + + fputs(prefix, fp); + + /* ¦pªG¦r¦ê¶}ÀY¦³ US_ASCII printable characters¡A¥i¥ý¦æ¿é¥X¡A³o¼Ë¤ñ¸û¦n¬Ý¡A¤]¤ñ¸û¬Û®e */ + for (i = 0; ch = str[i]; i++) + { + if (ch != '=' && ch != '?' && ch != '_' && ch > '\x1f' && ch < '\x7f') + { + if (blank) + { + if (ch != ' ') + blank = 0; + else if (str[i + 1] == '\0') /* Y¥þ¬OªÅ¥Õ¡A³Ì«á¤@ÓnÂà½X */ + break; + } + fprintf(fp, "%c", ch); + } + else + break; + } + + if (ch != '\0') /* ¦pªG³£¨S¦³¯S®í¦r¤¸´Nµ²§ô */ + { + /* ¶}©l encode */ + fprintf(fp, "=?%s?Q?", charset); /* «ü©w¦r¶° */ + for (; ch = str[i]; i++) + { + /* ¦pªG¬O non-printable ¦r¤¸´NnÂà½X */ + /* ½d³ò: '\x20' ~ '\x7e' ¬° printable, ¨ä¤¤ =, ?, _, ªÅ¥Õ, ¬°¯S®í²Å¸¹¤]nÂà½X */ + + if (ch == '=' || ch == '?' || ch == '_' || ch <= '\x1f' || ch >= '\x7f') + fprintf(fp, "=%c%c", tbl[(ch >> 4) & '\x0f'], tbl[ch & '\x0f']); + else if (ch == ' ') /* ªÅ¥Õ¤ñ¸û¯S®í, Âন '_' ©Î "=20" */ + fprintf(fp, "=20"); + else + fprintf(fp, "%c", ch); + } + fputs("?=", fp); + } + + fputs(suffix, fp); +} + + +#if 0 + +/* output_rfc2047_qp() ¥i¥H¥þ³¡´«¦¨ output_rfc2047_base64()¡A¦pªG·Q´« encode ªº¸Ü */ + +/*-------------------------------------------------------*/ +/* RFC2047 base64 encode */ +/*-------------------------------------------------------*/ + + +static int +output_rfc2047_prefix(fp, str) + FILE *fp; + const unsigned char *str; +{ + int i, lastspace; + + /* output prefix US_ASCII printable characters */ + lastspace = -1; + + /* step 1: find the last space */ + for (i = 0; str[i] != '\0' && str[i] != '=' && str[i] != '?' + && str[i] != '_' && str[i] > '\x1f' && str[i] < '\x7f'; i++) + { + if (str[i] == ' ') + lastspace = i; + } + if (str[i] == '\0') /* if non special char then outout directly */ + { + fprintf(fp, "%s", str); + return i; + } + + /* step 2: output the prefix with last space */ + for (i = 0; i <= lastspace; i++) + fprintf(fp, "%c", str[i]); + return i; +} + + +static void +output_rfc2047_base64_3to4(a, b, c, oa, ob, oc, od) + unsigned char a, b, c; + char *oa, *ob, *oc, *od; +{ + static char tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + int i; + + *oa = '='; + *ob = '='; + *oc = '='; + *od = '='; + + i = (int)((a >> 2) & '\x3f'); + *oa = tbl[i]; + i = (int)((a << 4) & '\x30') | (int)((b >> 4) & '\x0f'); + *ob = tbl[i]; + if (b == '\0') + return; + i = (int)((b << 2) & '\x3c') | (int)((c >> 6) & '\x03'); + *oc = tbl[i]; + if (c == '\0') + return; + i = (int)(c & '\x3f'); + *od = tbl[i]; +} + + +void +output_rfc2047_base64(fp, prefix, str, charset, suffix) + FILE *fp; + char *prefix; + const unsigned char *str; + const unsigned char *charset; + char *suffix; +{ + int i, j; + char a[3], oa[5]; + + fputs(prefix, fp); + + /* output prefix US_ASCII printable characters */ + i = output_rfc2047_prefix(fp, str); + if (str[i] == '\0') + return; + + /* start encoding */ + fprintf(fp, "=?%s?B?", charset); + for (; str[i] != '\0';) + { + memset(a, 0, sizeof(a)); + for (j = 0; j < 3; j++) + { + a[j] = str[i]; + if (str[i] != '\0') + i++; + } + output_rfc2047_base64_3to4(a[0], a[1], a[2], + &(oa[0]), &(oa[1]), &(oa[2]), &(oa[3])); + oa[4] = '\0'; + fprintf(fp, "%s", oa); + } + fprintf(fp, "?="); + + fputs(suffix, fp); +} +#endif diff --git a/lib/shm.c b/lib/shm.c new file mode 100644 index 0000000..8fecea6 --- /dev/null +++ b/lib/shm.c @@ -0,0 +1,34 @@ +#include <stdio.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/shm.h> + + +void * +shm_new(shmkey, shmsize) + int shmkey, shmsize; +{ + void *shmptr; + int shmid; + + shmid = shmget(shmkey, shmsize, 0); + if (shmid < 0) + { + shmid = shmget(shmkey, shmsize, IPC_CREAT | 0600); + if (shmid < 0) + exit(-1); + } + else + { + shmsize = 0; + } + + shmptr = (void *) shmat(shmid, NULL, 0); + if (shmptr == (void *) -1) + exit(-2); + + if (shmsize) + memset(shmptr, 0, shmsize); + + return shmptr; +} diff --git a/lib/splay.c b/lib/splay.c new file mode 100644 index 0000000..990abf8 --- /dev/null +++ b/lib/splay.c @@ -0,0 +1,174 @@ +/*-------------------------------------------------------*/ +/* lib/splay.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* author : opus.bbs@bbs.cs.nthu.edu.tw */ +/* target : splay-tree sort routines */ +/* create : 97/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ + + +#include <stdio.h> +#include "splay.h" + + +SplayNode * +splay_in(top, data, compare) + SplayNode *top; + void *data; + int (*compare)(); +{ + int splay_cmp; + SplayNode *node, *l, *r, *x, N; + + node = (SplayNode *) malloc(sizeof(SplayNode)); + node->data = data; + + if (top == NULL) + { + node->left = node->right = NULL; + return node; + } + + /* --------------------------------------------------- */ + /* splay this splay tree */ + /* --------------------------------------------------- */ + + N.left = N.right = NULL; + l = r = &N; + + for (;;) + { + splay_cmp = compare(data, top->data); + if (splay_cmp < 0) + { + if (!(x = top->left)) + break; + if ((splay_cmp = compare(data, x->data)) < 0) + { + /* rotate right */ + + top->left = x->right; + x->right = top; + top = x; + if (top->left == NULL) + break; + } + r->left = top; /* link right */ + r = top; + top = top->left; + } + else if (splay_cmp > 0) + { + if (!(x = top->right)) + break; + if ((splay_cmp = compare(data, x->data)) > 0) + { + /* rotate left */ + + top->right = x->left; + x->left = top; + top = x; + if (top->right == NULL) + break; + } + l->right = top; /* link left */ + l = top; + top = top->right; + } + else + { + break; + } + } + + l->right = top->left; /* assemble */ + r->left = top->right; + top->left = N.right; + top->right = N.left; + + /* --------------------------------------------------- */ + /* construct this splay tree */ + /* --------------------------------------------------- */ + + if (splay_cmp < 0) + { + node->left = top->left; + node->right = top; + top->left = NULL; + return node; + } + + if (splay_cmp > 0) + { + node->right = top->right; + node->left = top; + top->right = NULL; + return node; + } + + /* duplicate entry */ + + free(node); + return top; +} + + +#ifdef TEST + +typedef struct +{ + int i; +} intnode; + + +static void +printint(a) + intnode *a; +{ + printf("%d\n", a->i); +} + + +static int +compareint(a, b) + intnode *a, *b; +{ + return a->i - b->i; +} + + +static void +splay_out(top) + SplayNode *top; +{ + if (top == NULL) + return; + + splay_out(top->left); + printint(top->data); + splay_out(top->right); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int i; + intnode *I; + SplayNode *top = NULL; + + srand(time(NULL)); + for (i = 0; i < 100; i++) + { + I = (intnode *) malloc(sizeof(intnode)); + I->i = rand() % 1000; + top = splay_in(top, I, compareint); + } + splay_out(top); + return 0; +} + +#endif /* TEST */ diff --git a/lib/str_ansi.c b/lib/str_ansi.c new file mode 100644 index 0000000..81d411e --- /dev/null +++ b/lib/str_ansi.c @@ -0,0 +1,37 @@ +/* ----------------------------------------------------- */ +/* ¥h°£ ANSI ±±¨î½X */ +/* ----------------------------------------------------- */ + + +void +str_ansi(dst, str, max) /* strip ANSI code */ + char *dst, *str; + int max; +{ + int ch, ansi; + char *tail; + + for (ansi = 0, tail = dst + max - 1; ch = *str; str++) + { + if (ch == '\n') + { + break; + } + else if (ch == '\033') + { + ansi = 1; + } + else if (ansi) + { + if ((ch < '0' || ch > '9') && ch != ';' && ch != '[') + ansi = 0; + } + else + { + *dst++ = ch; + if (dst >= tail) + break; + } + } + *dst = '\0'; +} diff --git a/lib/str_cat.c b/lib/str_cat.c new file mode 100644 index 0000000..42723cd --- /dev/null +++ b/lib/str_cat.c @@ -0,0 +1,15 @@ +void +str_cat(dst, s1, s2) + char *dst; + char *s1; + char *s2; +{ + while (*dst = *s1) + { + s1++; + dst++; + } + + while (*dst++ = *s2++) + ; +} diff --git a/lib/str_cmp.c b/lib/str_cmp.c new file mode 100644 index 0000000..1fa82de --- /dev/null +++ b/lib/str_cmp.c @@ -0,0 +1,19 @@ +int +str_cmp(s1, s2) + char *s1, *s2; +{ + int c1, c2, diff; + + do + { + c1 = *s1++; + c2 = *s2++; + if (c1 >= 'A' && c1 <= 'Z') + c1 |= 0x20; + if (c2 >= 'A' && c2 <= 'Z') + c2 |= 0x20; + if (diff = c1 - c2) + return (diff); + } while (c1); + return 0; +} diff --git a/lib/str_decode.c b/lib/str_decode.c new file mode 100644 index 0000000..d2c2ab4 --- /dev/null +++ b/lib/str_decode.c @@ -0,0 +1,374 @@ +/*-------------------------------------------------------*/ +/* lib/str_decode.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : included C for QP/BASE64 decoding */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ + + +/* ----------------------------------------------------- */ +/* QP code : "0123456789ABCDEF" */ +/* ----------------------------------------------------- */ + + +static int +qp_code(x) + register int x; +{ + if (x >= '0' && x <= '9') + return x - '0'; + if (x >= 'a' && x <= 'f') + return x - 'a' + 10; + if (x >= 'A' && x <= 'F') + return x - 'A' + 10; + return -1; +} + + +/* ------------------------------------------------------------------ */ +/* BASE64 : */ +/* "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" */ +/* ------------------------------------------------------------------ */ + + +static int +base64_code(x) + register int x; +{ + if (x >= 'A' && x <= 'Z') + return x - 'A'; + if (x >= 'a' && x <= 'z') + return x - 'a' + 26; + if (x >= '0' && x <= '9') + return x - '0' + 52; + if (x == '+') + return 62; + if (x == '/') + return 63; + return -1; +} + + +/* ----------------------------------------------------- */ +/* ¨ú encode / charset */ +/* ----------------------------------------------------- */ + + +static inline int +isreturn(c) + unsigned char c; +{ + return c == '\r' || c == '\n'; +} + + +static inline int +isspace(c) + unsigned char c; +{ + return c == ' ' || c == '\t' || isreturn(c); +} + + +/* ¨úContent-Transfer-Encode ªº²Ä¤@Ó¦r¤¸, ¨Ì·Ó¼Ð·Ç¥u¥i¯à¬O q,b,7,8 ³o¥|Ó */ +char * +mm_getencode(str, code) + unsigned char *str; + char *code; +{ + if (str) + { + /* skip leading space */ + while (isspace(*str)) + str++; + + if (!str_ncmp(str, "quoted-printable", 16)) + { + *code = 'q'; + return str + 16; + } + if (!str_ncmp(str, "base64", 6)) + { + *code = 'b'; + return str + 6; + } + } + + *code = 0; + return str; +} + + +/* ¨ú charset */ +void +mm_getcharset(str, charset, size) + const char *str; + char *charset; + int size; /* charset size */ +{ + char *ptr, delim; + int i; + + *charset = '\0'; + + if (!str) + return; + + if (!(ptr = (char *) strstr(str, "charset="))) + return; + + ptr += 8; + delim = '\0'; + i = 0; + size--; /* «O¯dªÅ¶¡µ¹ '\0' */ + + for (; *ptr && *ptr != delim && !isspace(*ptr); ptr++) + { + if (*ptr == '\"') + { + delim = *ptr; + continue; + } + + charset[i] = *ptr; + if (++i >= size) + break; + } + charset[i] = '\0'; + + if (!str_cmp(charset, "iso-8859-1")) /* ¾ú¥v¥]¥ñ¤£¥i¥á */ + *charset = '\0'; +} + + +/* ----------------------------------------------------- */ +/* judge & decode QP / BASE64 */ +/* ----------------------------------------------------- */ + + +/* PaulLiu.030410: + RFC 2047 (Header) QP ³¡¤À¡A¸Ì±³W©w '_' ªí¥Ü ' ' (US_ASCIIªºªÅ¥Õ) + ¦Ó RFC 2045 (Body) QP ³¡¤À¡A'_' ÁÙ¬O '_'¡A¨S¦³¯S®í¥Î³~ + ©Ò¥H¦b¦¹ mmdecode ¤À¤G°¦¼g +*/ + +static int +mmdecode_header(src, encode, dst) /* ¸Ñ Header ªº mmdecode */ + unsigned char *src; /* Thor.980901: src©Mdst¥i¬Û¦P, ¦ýsrc¤@©w¦³?©Î\0µ²§ô */ + unsigned char encode; /* Thor.980901: ª`·N, decode¥Xªºµ²ªG¤£·|¦Û¤v¥[¤W \0 */ + unsigned char *dst; +{ + unsigned char *t; + int pattern, bits; + int ch; + + t = dst; + encode |= 0x20; /* Thor: to lower */ + + switch (encode) + { + case 'q': /* Thor: quoted-printable */ + + while ((ch = *src) && ch != '?') /* Thor: Header ¸Ì± 0 ©M '?' ³£¬O delimiter */ + { + if (ch == '=') + { + int x, y; + + x = *++src; + y = x ? *++src : 0; + if (isreturn(x)) + continue; + + if ((x = qp_code(x)) < 0 || (y = qp_code(y)) < 0) + return -1; + + *t++ = (x << 4) + y; + } + else if (ch == '_') /* Header n§â '_' ´«¦¨ ' ' */ + { + *t++ = ' '; + } + else + { + *t++ = ch; + } + src++; + } + return t - dst; + + case 'b': /* Thor: base 64 */ + + /* Thor: pattern & bits are cleared outside while() */ + pattern = 0; + bits = 0; + + while ((ch = *src) && ch != '?') /* Thor: Header ¸Ì± 0 ©M '?' ³£¬O delimiter */ + { + int x; + + x = base64_code(*src++); + if (x < 0) /* Thor: ignore everything not in the base64,=,.. */ + continue; + + pattern = (pattern << 6) | x; + bits += 6; /* Thor: 1 code gains 6 bits */ + if (bits >= 8) /* Thor: enough to form a byte */ + { + bits -= 8; + *t++ = (pattern >> bits) & 0xff; + } + } + return t - dst; + } + + return -1; +} + + +int +mmdecode(src, encode, dst) /* ¸Ñ Header ªº mmdecode */ + unsigned char *src; /* Thor.980901: src©Mdst¥i¬Û¦P, ¦ýsrc¤@©w¦³?©Î\0µ²§ô */ + unsigned char encode; /* Thor.980901: ª`·N, decode¥Xªºµ²ªG¤£·|¦Û¤v¥[¤W \0 */ + unsigned char *dst; +{ + unsigned char *t; + int pattern, bits; + int ch; + + t = dst; + encode |= 0x20; /* Thor: to lower */ + + switch (encode) + { + case 'q': /* Thor: quoted-printable */ + + while (ch = *src) /* Thor: 0 ¬O delimiter */ + { + if (ch == '=') + { + int x, y; + + x = *++src; + y = x ? *++src : 0; + if (isreturn(x)) + continue; + + if ((x = qp_code(x)) < 0 || (y = qp_code(y)) < 0) + return -1; + + *t++ = (x << 4) + y; + } + else + { + *t++ = ch; + } + src++; + } + return t - dst; + + case 'b': /* Thor: base 64 */ + + /* Thor: pattern & bits are cleared outside while() */ + pattern = 0; + bits = 0; + + while (ch = *src) /* Thor: 0 ¬O delimiter */ + { + int x; + + x = base64_code(*src++); + if (x < 0) /* Thor: ignore everything not in the base64,=,.. */ + continue; + + pattern = (pattern << 6) | x; + bits += 6; /* Thor: 1 code gains 6 bits */ + if (bits >= 8) /* Thor: enough to form a byte */ + { + bits -= 8; + *t++ = (pattern >> bits) & 0xff; + } + } + return t - dst; + } + + return -1; +} + + +void +str_decode(str) + unsigned char *str; +{ + int adj; + unsigned char *src, *dst; + unsigned char buf[512]; + + src = str; + dst = buf; + adj = 0; + + while (*src && (dst - buf) < sizeof(buf) - 1) + { + if (*src != '=') + { /* Thor: not coded */ + unsigned char *tmp = src; + while (adj && *tmp && isspace(*tmp)) + tmp++; + if (adj && *tmp == '=') + { /* Thor: jump over space */ + adj = 0; + src = tmp; + } + else + *dst++ = *src++; + } + else /* Thor: *src == '=' */ + { + unsigned char *tmp = src + 1; + if (*tmp == '?') /* Thor: =? coded */ + { + /* "=?%s?Q?" for QP, "=?%s?B?" for BASE64 */ + tmp++; + while (*tmp && *tmp != '?') + tmp++; + if (*tmp && tmp[1] && tmp[2] == '?') /* Thor: *tmp == '?' */ + { + int i = mmdecode_header(tmp + 3, tmp[1], dst); + if (i >= 0) + { + tmp += 3; /* Thor: decode's src */ + while (*tmp && *tmp++ != '?'); /* Thor: no ? end, mmdecode_header -1 */ + /* Thor.980901: 0 ¤]ºâ decode µ²§ô */ + if (*tmp == '=') + tmp++; + src = tmp; /* Thor: decode over */ + dst += i; + adj = 1; /* Thor: adjcent */ + } + } + } + + while (src != tmp) /* Thor: not coded */ + *dst++ = *src++; + } + } + *dst = 0; + strcpy(str, buf); +} + + +#if 0 +int +main() +{ + char buf[1024] = "=?Big5?B?pl7C0CA6IFtNYXBsZUJCU11UbyB5dW5sdW5nKDE4SzRGTE0pIFtWQUxJ?=\n\t=?Big5?B?RF0=?="; + + str_decode(buf); + puts(buf); + + buf[mmdecode("=A7=DA=A4@=AA=BD=B8I=A4=A3=A8=EC=A7=DA=BE=C7=AA=F8", 'q', buf)] = '\0'; + puts(buf); +} +#endif diff --git a/lib/str_folder.c b/lib/str_folder.c new file mode 100644 index 0000000..aaa2a55 --- /dev/null +++ b/lib/str_folder.c @@ -0,0 +1,19 @@ +void +str_folder(fpath, folder, fname) + char *fpath; + char *folder; + char *fname; +{ + int ch; + char *token; + + while (ch = *folder++) + { + *fpath++ = ch; + if (ch == '/') + token = fpath; + } + if (*token != '.') + token -= 2; + strcpy(token, fname); +} diff --git a/lib/str_fpath.c b/lib/str_fpath.c new file mode 100644 index 0000000..415ee6f --- /dev/null +++ b/lib/str_fpath.c @@ -0,0 +1,109 @@ +void +setdirpath(fpath, direct, fname) + char *fpath, *direct, *fname; +{ + int ch; + char *target; + + while (ch = *direct) + { + *fpath++ = ch; + if (ch == '/') + target = fpath; + direct++; + } + + strcpy(target, fname); +} + +#if 0 +int +is_fname(str) + char *str; +{ + int ch; + + ch = *str; + if (ch == '/') + return 0; + + do + { + if (!is_alnum(ch) && !strchr("-._/+@", ch)) + return 0; + } while (ch = *++str); + return 1; +} + + +/* ----------------------------------------------------- */ +/* transform to real path & security check */ +/* ----------------------------------------------------- */ + + +int +is_fpath(path) + char *path; +{ + int ch, level; + char *source, *target; + + level = 0; + source = target = path; + + + for (;;) + { + ch = *source; + + if (ch == '/') + { + int next; + + next = source[1]; + + if (next == '/') + { + return 0; /* [//] */ + } + else if (next == '.') + { + next = source[2]; + + if (next == '/') + return 0; /* [/./] */ + + if (next == '.' && source[3] == '/') + { + /* -------------------------- */ + /* abc/xyz/../def ==> abc/def */ + /* -------------------------- */ + + for (;;) + { + if (target <= path) + return 0; + + target--; + if (*target == '/') + break; + } + + source += 3; + continue; + } + } + + level++; + } + + *target = ch; + + if (ch == 0) + return level; + + target++; + source++; + } +} +#endif diff --git a/lib/str_from.c b/lib/str_from.c new file mode 100644 index 0000000..069a156 --- /dev/null +++ b/lib/str_from.c @@ -0,0 +1,92 @@ +/* ---------------------------------------------------- */ +/* E-mail address format */ +/* ---------------------------------------------------- */ +/* 1. user@domain */ +/* 2. <user@domain> */ +/* 3. user@domain (nick) */ +/* 4. user@domain ("nick") */ +/* 5. nick <user@domain> */ +/* 6. "nick" <user@domain> */ +/* ---------------------------------------------------- */ + + +#include "dao.h" + + +int +str_from(from, addr, nick) + char *from, *addr, *nick; +{ + char *str, *ptr, *langle; + int cc; + + *nick = 0; + + langle = ptr = NULL; + + for (str = from; cc = *str; str++) + { + if (cc == '<') + langle = str; + else if (cc == '@') + ptr = str; + } + + if (ptr == NULL) + { + strcpy(addr, from); + return -1; + } + + if (langle && langle < ptr && str[-1] == '>') + { + /* case 2/5/6 : name <mail_addr> */ + + str[-1] = 0; + if (langle > from) + { + ptr = langle - 2; + if (*from == '"') + { + from++; + if (*ptr == '"') + ptr--; + } + if (*from == '(') + { + from++; + if (*ptr == ')') + ptr--; + } + ptr[1] = '\0'; + strcpy(nick, from); + str_decode(nick); + } + + from = langle + 1; + } + else + { + /* case 1/3/4 */ + + if (*--str == ')') + { + if (str[-1] == '"') + str--; + *str = 0; + + if (ptr = (char *) strchr(from, '(')) + { + ptr[-1] = 0; + if (*++ptr == '"') + ptr++; + + strcpy(nick, ptr); + str_decode(nick); + } + } + } + + strcpy(addr, from); + return 0; +} diff --git a/lib/str_has.c b/lib/str_has.c new file mode 100644 index 0000000..e07b917 --- /dev/null +++ b/lib/str_has.c @@ -0,0 +1,30 @@ +int /* >=1:¦b¦W³æªºþ¤@Ó 0:¤£¦b¦W³æ¤º */ +str_has(list, tag, len) + char *list; + char *tag; + int len; /* strlen(tag) */ +{ + int cc, priority; + char *str; + + priority = 1; + str = tag; + do + { + cc = list[len]; /* itoc.030730.µù¸Ñ: ¥i¯à·|«ü¨ì¶W¹L list ªºªø«×¥H¥~¥h¤F¡A¤£¹L¨S®t */ + if ((!cc || cc == '/') && !str_ncmp(list, str, len)) + { + return priority; + } + while (cc = *list++) + { + if (cc == '/') + { + priority++; + break; + } + } + } while (cc); + + return 0; +} diff --git a/lib/str_hash.c b/lib/str_hash.c new file mode 100644 index 0000000..f513233 --- /dev/null +++ b/lib/str_hash.c @@ -0,0 +1,13 @@ +int +str_hash(str, seed) + char *str; + int seed; +{ + int cc; + + while (cc = *str++) + { + seed = (seed << 5) - seed + cc; /* 31 * seed + cc */ + } + return (seed & 0x7fffffff); +} diff --git a/lib/str_lower.c b/lib/str_lower.c new file mode 100644 index 0000000..e179c3e --- /dev/null +++ b/lib/str_lower.c @@ -0,0 +1,14 @@ +void +str_lower(dst, src) + char *dst, *src; +{ + int ch; + + do + { + ch = *src++; + if (ch >= 'A' && ch <= 'Z') + ch |= 0x20; + *dst++ = ch; + } while (ch); +} diff --git a/lib/str_lowest.c b/lib/str_lowest.c new file mode 100644 index 0000000..e36d310 --- /dev/null +++ b/lib/str_lowest.c @@ -0,0 +1,17 @@ +void +str_lowest(dst, src) + char *dst, *src; +{ + int ch; + int in_chi = 0; /* 1: «e¤@½X¬O¤¤¤å¦r */ + + do + { + ch = *src++; + if (in_chi || ch & 0x80) + in_chi ^= 1; + else if (ch >= 'A' && ch <= 'Z') + ch |= 0x20; + *dst++ = ch; + } while (ch); +} diff --git a/lib/str_ncmp.c b/lib/str_ncmp.c new file mode 100644 index 0000000..56995fc --- /dev/null +++ b/lib/str_ncmp.c @@ -0,0 +1,26 @@ +int +str_ncmp(s1, s2, n) + char *s1, *s2; + int n; +{ + int c1, c2; + + while (n--) + { + c1 = *s1++; + if (c1 >= 'A' && c1 <= 'Z') + c1 |= 0x20; + + c2 = *s2++; + if (c2 >= 'A' && c2 <= 'Z') + c2 |= 0x20; + + if (c1 -= c2) + return (c1); + + if (!c2) + break; + } + + return 0; +} diff --git a/lib/str_ncpy.c b/lib/str_ncpy.c new file mode 100644 index 0000000..b7a4d08 --- /dev/null +++ b/lib/str_ncpy.c @@ -0,0 +1,22 @@ +/* + * str_ncpy() - similar to strncpy(3) but terminates string always with '\0' + * if n != 0, and doesn't do padding + */ + + +void +str_ncpy(dst, src, n) + char *dst; + char *src; + int n; +{ + char *end; + + end = dst + n - 1; + + do + { + n = (dst >= end) ? 0 : *src++; + *dst++ = n; + } while (n); +} diff --git a/lib/str_passwd.c b/lib/str_passwd.c new file mode 100644 index 0000000..19603b2 --- /dev/null +++ b/lib/str_passwd.c @@ -0,0 +1,52 @@ +#define PASSLEN 13 + + +/* ----------------------------------------------------- */ +/* password encryption */ +/* ----------------------------------------------------- */ + + +char *crypt(); +static char pwbuf[PASSLEN + 1]; + + +char * +genpasswd(pw) + char *pw; +{ + char saltc[2]; + int i, c; + + if (!*pw) + return pw; + + i = 9 * getpid(); + saltc[0] = i & 077; + saltc[1] = (i >> 6) & 077; + + for (i = 0; i < 2; i++) + { + c = saltc[i] + '.'; + if (c > '9') + c += 7; + if (c > 'Z') + c += 6; + saltc[i] = c; + } + strcpy(pwbuf, pw); + return crypt(pwbuf, saltc); +} + + +/* Thor.990214: µù¸Ñ: ¦X±K½X®É, ¶Ç¦^0 */ +int +chkpasswd(passwd, test) + char *passwd, *test; +{ + char *pw; + + /* if(!*passwd) return -1 */ /* Thor.990416: ©È¦³®Épasswd¬OªÅªº */ + str_ncpy(pwbuf, test, sizeof(pwbuf)); + pw = crypt(pwbuf, passwd); + return (strncmp(pw, passwd, PASSLEN)); +} diff --git a/lib/str_stamp.c b/lib/str_stamp.c new file mode 100644 index 0000000..82236fd --- /dev/null +++ b/lib/str_stamp.c @@ -0,0 +1,23 @@ +/* ------------------------------------------ */ +/* mail / post ®É¡A¨Ì¾Ú®É¶¡«Ø¥ßÀɮסA¥[¤W¶lÂW */ +/* ------------------------------------------ */ +/* Input: fpath = directory; */ +/* Output: fpath = full path; */ +/* ------------------------------------------ */ + + +#include <time.h> + + +void +str_stamp(str, chrono) + char *str; + time_t *chrono; +{ + struct tm *ptime; + + ptime = localtime(chrono); + /* Thor.990329: y2k */ + sprintf(str, "%02d/%02d/%02d", + ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday); +} diff --git a/lib/str_str.c b/lib/str_str.c new file mode 100644 index 0000000..71f9a8d --- /dev/null +++ b/lib/str_str.c @@ -0,0 +1,41 @@ +#include "dao.h" + + +char * +str_str(str, tag) + char *str; + char *tag; /* non-empty lower case pattern */ +{ + int cc, c1, c2; + char *p1, *p2; + + cc = *tag++; + + while (c1 = *str) + { + if (c1 >= 'A' && c1 <= 'Z') + c1 |= 0x20; + + if (c1 == cc) + { + p1 = str; + p2 = tag; + + do + { + c2 = *p2; + if (!c2) + return str; + + p2++; + c1 = *++p1; + if (c1 >= 'A' && c1 <= 'Z') + c1 |= 0x20; + } while (c1 == c2); + } + + str++; + } + + return NULL; +} diff --git a/lib/str_str_kmp.c b/lib/str_str_kmp.c new file mode 100644 index 0000000..7695865 --- /dev/null +++ b/lib/str_str_kmp.c @@ -0,0 +1,119 @@ +/* a alternative str_str() using KMP algorithm. */ +/* English case independent and BIG5 Chinese supported */ + +#include <stdlib.h> + + +void +str_expand(dst, src) /* ±N char Âର short¡A¨Ã±N^¤åÅܤp¼g */ + char *dst, *src; +{ + int ch; + int in_chi = 0; /* 1: «e¤@½X¬O¤¤¤å¦r */ + + do + { + ch = *src++; + + if (in_chi || ch & 0x80) + { + in_chi ^= 1; + } + else + { + if (ch >= 'A' && ch <= 'Z') + ch |= 0x20; + *dst++ = 0; + } + *dst++ = ch; + } while (ch); +} + + +void +str_str_kmp_tbl(pat, tbl) + const short *pat; + int *tbl; +{ + register short c; + register int i, j; + + tbl[0] = -1; + for (j = 1; c = pat[j]; j++) + { + i = tbl[j - 1]; + while (i >= 0 && c != pat[i + 1]) + i = tbl[i]; + tbl[j] = (c == pat[i + 1]) ? i + 1 : -1; + } +} + + +const int +str_str_kmp(str, pat, tbl) + const short *str; + const short *pat; + const int *tbl; +{ + register const short *i; + register int j; + + for (i = str, j = 0; *i && pat[j];) + { + if (*i == pat[j]) + { + j++; + } + else if (j) + { + j = tbl[j - 1] + 1; + continue; /* ¤£»Ýn i++ */ + } + i++; + } + + /* match */ + if (!pat[j]) + return 1; + + return 0; +} + + +#undef TEST + +#ifdef TEST +static void +try_match(str, key) + char *str, *key; +{ + short a[256], b[256]; /* °²³] 256 ¤w¨¬°÷ */ + int tbl[256]; + + str_expand(a, str); + str_expand(b, key); + + str_str_kmp_tbl(key, tbl); + printf("¡u%s¡v %s¥]¬A ¡u%s¡v\n", + str, str_str_kmp(a, b, tbl) ? "" : "¤£", key); +} + + +int +main() +{ + try_match("¦nªº¹q¼v", "º¹"); + try_match("¦nªº¹q¼v", "N"); + try_match("¦nªº¹q¼v", "n"); + try_match("¦nªº¹q¼v", "¦nªº"); + + try_match("x¦nªºx¹q¼v", "ºx¹q"); + try_match("x¦nªºx¹q¼v", "ªºx"); + try_match("x¦nªºx¹q¼v", "ªºX"); + try_match("x¦nªºX¹q¼v", "ªºx"); + + try_match("abx¦nªºx¹q¼v", "x¹q"); + + return 0; +} +#endif diff --git a/lib/str_sub.c b/lib/str_sub.c new file mode 100644 index 0000000..225ef2b --- /dev/null +++ b/lib/str_sub.c @@ -0,0 +1,55 @@ +#include "dao.h" + + +char * +str_sub(str, tag) + char *str; + char *tag; /* non-empty lowest case pattern */ +{ + int cc, c1, c2; + char *p1, *p2; + int in_chi = 0; /* 1: «e¤@½X¬O¤¤¤å¦r */ + int in_chii; /* 1: «e¤@½X¬O¤¤¤å¦r */ + + cc = *tag++; + + while (c1 = *str) + { + if (in_chi) + { + in_chi ^= 1; + } + else + { + if (c1 & 0x80) + in_chi ^= 1; + else if (c1 >= 'A' && c1 <= 'Z') + c1 |= 0x20; + + if (c1 == cc) + { + p1 = str; + p2 = tag; + in_chii = in_chi; + + do + { + c2 = *p2; + if (!c2) + return str; + + p2++; + c1 = *++p1; + if (in_chii || c1 & 0x80) + in_chii ^= 1; + else if (c1 >= 'A' && c1 <= 'Z') + c1 |= 0x20; + } while (c1 == c2); + } + } + + str++; + } + + return NULL; +} diff --git a/lib/str_tail.c b/lib/str_tail.c new file mode 100644 index 0000000..77e4bc9 --- /dev/null +++ b/lib/str_tail.c @@ -0,0 +1,10 @@ +char * +str_tail(str) + char *str; +{ + while (*str) + { + str++; + } + return str; +} diff --git a/lib/str_time.c b/lib/str_time.c new file mode 100644 index 0000000..59bf986 --- /dev/null +++ b/lib/str_time.c @@ -0,0 +1,60 @@ +#include <time.h> + + +static char datemsg[40]; + + +char * +Atime(clock) /* Thor.990125: °²¸Ë ARPANET ®É¶¡®æ¦¡ */ + time_t *clock; +{ + /* ARPANET format: Thu, 11 Feb 1999 06:00:37 +0800 (CST) */ + /* strftime(datemsg, 40, "%a, %d %b %Y %T %Z", localtime(clock)); */ + /* Thor.990125: time zoneªº¶Ç¦^Ȥ£ª¾©MARPANET®æ¦¡¬O§_¤@¼Ë,¥ýµwµ¹,¦Psendmail*/ + strftime(datemsg, 40, "%a, %d %b %Y %T +0800 (CST)", localtime(clock)); + return (datemsg); +} + + +char * +Btime(clock) /* BBS ®É¶¡®æ¦¡ */ + time_t *clock; +{ + struct tm *t = localtime(clock); + + sprintf(datemsg, "%d/%02d/%02d %.3s %02d:%02d:%02d", + t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, + "SunMonTueWedThuFriSat" + (t->tm_wday * 3), + t->tm_hour, t->tm_min, t->tm_sec); + return (datemsg); +} + +char * +Bdifftime(sec) + int sec; +{ + char *buf; + + int days, hours, minutes; + + days = sec / (60 * 60 * 24); + sec %= (60 * 60 * 24); + + hours = sec / (60 * 60); + sec %= (60 * 60); + + minutes = sec / 60; + sec %= 60; + + sprintf (buf, "%d ¤é %d ®É %d ¤À %d ¬í", days, hours, minutes, sec); + return buf; +} + +char * +Now() +{ + time_t now; + + time(&now); + return Btime(&now); +} diff --git a/lib/str_trim.c b/lib/str_trim.c new file mode 100644 index 0000000..63f4170 --- /dev/null +++ b/lib/str_trim.c @@ -0,0 +1,16 @@ +void +str_trim(buf) /* remove trailing space */ + char *buf; +{ + char *p = buf; + + while (*p) + p++; + while (--p >= buf) + { + if (*p == ' ') + *p = '\0'; + else + break; + } +} diff --git a/lib/str_ttl.c b/lib/str_ttl.c new file mode 100644 index 0000000..14b7f7f --- /dev/null +++ b/lib/str_ttl.c @@ -0,0 +1,14 @@ +char * +str_ttl(title) + char *title; +{ + if ((title[2] == ':') && + ((title[0] == 'R' && title[1] == 'e') || (title[0] == 'F' && title[1] == 'w'))) + { + title += 3; + if (*title == ' ') + title++; + } + + return title; +} diff --git a/lib/xsort.c b/lib/xsort.c new file mode 100644 index 0000000..fa84b3e --- /dev/null +++ b/lib/xsort.c @@ -0,0 +1,198 @@ +#include <sys/types.h> +#include <stdlib.h> + + +#define min(a, b) (a) < (b) ? a : b +#undef TEST + + +/* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". */ + + +#define swapcode(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + register TYPE *pi = (TYPE *) (parmi); \ + register TYPE *pj = (TYPE *) (parmj); \ + do { \ + register TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} + + +#define SWAPINIT(a, es) \ + swaptype = (((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long)) ? 2 : (es == sizeof(long)? 0 : 1); + + +static inline void +swapfunc(a, b, n, swaptype) + char *a, *b; + int n, swaptype; +{ + if (swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} + + +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype) + + +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) + + +static inline char * +med3(a, b, c, cmp) + char *a, *b, *c; + int (*cmp) (); +{ + return cmp(a, b) < 0 ? + (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a)) + : (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c)); +} + + +void +xsort(a, n, es, cmp) + void *a; + size_t n, es; + int (*cmp) (); +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + + SWAPINIT(a, es); + +loop: + + swap_cnt = 0; + if (n < 7) + { + for (pm = a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + + pm = a + (n / 2) * es; + + if (n > 7) + { + pl = a; + pn = a + (n - 1) * es; + if (n > 40) + { + d = (n >> 3) * es; + pl = med3(pl, pl + d, pl + d + d, cmp); + pm = med3(pm - d, pm, pm + d, cmp); + pn = med3(pn - 2 * d, pn - d, pn, cmp); + } + pm = med3(pl, pm, pn, cmp); + } + swap(a, pm); + pa = pb = a + es; + + pc = pd = a + (n - 1) * es; + for (;;) + { + while (pb <= pc && (r = cmp(pb, a)) <= 0) + { + if (r == 0) + { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = cmp(pc, a)) >= 0) + { + if (r == 0) + { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + + if (swap_cnt == 0) + { /* Switch to insertion sort */ + for (pm = a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; pl -= es) + swap(pl, pl - es); + return; + } + + pn = a + n * es; + r = min(pa - (char *) a, pb - pa); + vecswap(a, pb - r, r); + + r = min(pd - pc, pn - pd - es); + vecswap(pb, pn - r, r); + + if ((r = pb - pa) > es) + xsort(a, r / es, es, cmp); + + if ((r = pd - pc) > es) + { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } + /* xsort(pn - r, r / es, es, cmp); */ +} + + +#ifdef TEST + +#define MMM (0x40000) + +static int +int_cmp(a, b) + int *a; + int *b; +{ + return *a - *b; +} + + +main() +{ + int *x, *y, *z, n; + + x = malloc(MMM * sizeof(int)); + if (!x) + return; + + y = x; + z = x + MMM; + + n = time(0) & (0x40000 -1) /* 16387 */; + + do + { + *x = n = (n * 10001) & (0x100000 - 1); + } while (++x < z); + + xsort(y, MMM, sizeof(int), int_cmp); +} +#endif diff --git a/lib/xwrite.c b/lib/xwrite.c new file mode 100644 index 0000000..23d2df1 --- /dev/null +++ b/lib/xwrite.c @@ -0,0 +1,18 @@ +int +xwrite(fd, data, size) + int fd; + char *data; + int size; +{ + int cc; + + while (size > 0) + { + cc = write(fd, data, size); + if (cc < 0) + return cc; + data += cc; + size -= cc; + } + return 0; +} diff --git a/maple/CHANGE b/maple/CHANGE new file mode 100644 index 0000000..fed4f25 --- /dev/null +++ b/maple/CHANGE @@ -0,0 +1,1766 @@ +/*-------------------------------------------------------*/ +/* CHANGE ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : difference from MapleBBS Ver 3.10 */ +/* create : 00/02/01 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + + ¥» BBS ª©¥»¬O¥Ñ NTHU CS MapleBBS Ver 3.10 §ïª©¦Ó¨Ó¡C + + ¨ä¤¤°Ñ¦Ò bbs.cs.nthu.edu.tw [plan] ªO ½Ñ¦ì¤j¤jªº´¼¼zµ²´¹¡A + + ¥H¤Î WindTop WD Ptt Firebird µ¥ BBS µ{¦¡¡C + + ©Ò¦³´¼¼z°]²£§¡ÄÝ©óì§@ªÌ¡C + + + +[2000/02/ ] bbsd.c §ï¦¨¤W¯¸¤@¤ÀÄÁ¥H«á¤~¼W¥[¤W¯¸¦¸¼Æ¡C + acct.c perm.h ·s¼W¡yµù¥U²Õªø¡zÅv PERM_REGISTRAR¡Aµ¹¼f®Öµù¥U³æ¥Î¡C + post.c ¤å³¹§@ªÌ¥i¥H edit ¦Û¤vªº¤å³¹¡C + +[2000/02/13] post.c ì§@ªÌ¥i¥H«ö T ×§ï¦Û¤vªº¤å³¹¼ÐÃD¡C + talk.c ¦n¤Í¼s¼½¥X²{¼s¼½ªÌªº id¡C¬°¥H¥Ü°Ï§O¡A¤ô²y¥X²{ id¡A¼s¼½¥X²{ id >¡C + +[2000/02/19] acct.c menu.c maple.p ¥[/´î PERM_BM µ{¦¡¡C + +[2000/02/20] gem.c ·s¼W¤pªO¥D¥\¯à¡C + +[2000/02/25] talk.c ·s¼W¨Ï¥ÎªÌ¦W³æ¦n¤Í¸m«e¨ÌID±Æ§Ç¡A¥B³]¬°¹w³]È¡C + +[2000/02/26] gem.c ºëµØ°Ï¨î¯Å¤å³¹¦WºÙ«O±K¡C + +[2000/02/27] post.c ¦ê±µ·j´M¦pªG¨S¦³¿é¤J¼ÐÃD¡B§@ªÌ¡A«h·j´M´å¼Ð©Ò¦b¤å³¹¼ÐÃD¡C(¤w¨ú®ø) + post.c ·s¼W¦ê¦C·j´M¤U [ ªº¥\¯à¡C + +[2000/02/28] gem.c ºëµØ°Ï¦¬¿ý¤è¦¡±q link ÅÜ copy¡AÁ×§K×§ï¨ìªO¤Wªº¤å³¹¡C + +[2000/03/03] post.c ×¥¿¦ê±µ·j´M¼Ò¦¡«á h Â÷¶}·|¦³°ÝÃD¡C + +[2000/03/04] xover.c ¾\ۤ峹®É¤£´`Àô¾\Ū¡C + +[2000/03/05] account.c ¤W¯¸¤H¦¸°O¿ý ¦~¥÷ % 100¡C + +[2000/03/12] acct.c board.c ªO¥D¥i¥Hק襤¤åªO¦W±Ôz¡C + talk.c ²á¤Ñ«Ç·s¼W«ü¥O HOME/END/Ctrl+A/Ctrl+E ²¾¨ì¦æÀY/¦æ§À¡C + +[2000/03/15] config.h acct.c pop3_check.c ·s¼W POP3 ¦Û°Ê»{ÃÒ¡C + +[2000/03/17] post.c ×¥¿ more §¹²¦®É¤£·|¥X²{ help¡C + +[2000/03/19] xover.c every_Z ³Ì¦h¤G¼h¡C + edit.c ·s¼W ¤å³¹½s¿è®É Ctrl+W ²Å¸¹¿é¤J¤u¨ã¡C + xover.c ×¥¿¨î¯Å¤å³¹¤£±oÂà±H¡B¶×¤J¼È¦sÀÉ¡B Z-modem ¤U¸ü¡C + post.c ¦Û¤vèµoªí«áªº¤å³¹¤£n¥X²{¥¼¾\Ūªº¡Ï¸¹¡C + bbsd.c guest ¶Ã¼Æ¨ú¼ÊºÙ¡C + +[2000/03/20] acct.c struch.h User -> Setup ·s¼W¤£¨Ï¥Îñ¦WÀÉ UFO_NOSIGN¡C + acct.c struct.h edit.c User -> Setup ·s¼WÅã¥Üñ¦WÀÉ UFO_SHOWSIGN¡C + bbsd.c Åܰʷs¨Ï¥ÎªÌªº¹w³]ºX¼Ð¡C + +[2000/03/25] global.h mail.c ×§ï¸s²Õ±H«H»P¦^¤ô²yµ{¦¡½Ä¬ðªº°ÝÃD¡C + +[2000/03/28] modes.h ½s¨t²ÎÀÉ®× & ½sÓ¤HÀÉ®× ®ÉÔ¨ú®ø¥i¥H³Q talk request¡C + +[2000/04/07] bbsd.c board.c 0Announce ¦³·s¤å³¹®É±j¢¾\Ū¡C + acct.c ³]©w ²¤Æ¶i/Â÷¯¸µe± ªÌ¡AÂ÷¯¸¤£Åã¥ÜÓ¤H¸ê®Æ¡C + post.c µoªí¤å³¹¶W¹L 100 ½g¥H«á¤£´£¥Ü¤å³¹µoªíºõ»â¡C + xover.c ×¥¿ M_VOTE M_BMW °ÊºA¿ù»~¡C + +[2000/04/26] acct.c ¶}ªO³Ì«á·|³]©w expire.conf¡C(¤w¨ú®ø) + +[2000/05/07] sh/bakbbs/bak* ·s¼W³Æ¥÷ script¡C + +[2000/05/12] acct.c ¸Ñ¨M¦P®É¬å°£¦P¤@ӬݪO·|³y¦¨ºëµØ°Ï¡B¬ÝªO¥þ·´ªº°ÝÃD¡C + visio.c ¶¢¸m¹L¤[µ¹¤©Äµ§i¡C + mail.c menu.c admutil.c ±H«Hµ¹¥þ³¡ªO¥D/¨Ï¥ÎªÌ¡C + +[2000/05/13] mail.c «HŪ¨ì¤@¥b¥i¥H reply mark delete forward¡C + more.c ¤å³¹/«H¾\Ū¨ì¤@¥bªº®ÉÔ«ö q ¥i¥Hª½±µÂ÷¶}¡C + more.c §ïÅܤ@¨Ç«öÁä©w¸q¡C + +[2000/05/15] post.c mail.c post_browse mbox_browse ®É¥i¦s¤J¼È¦sÀÉ¡B¬Ý help¡C + +[2000/05/16] acct.c Â_½u®Éµù¥U³æ×´_¡C + +[2000/05/27] bbsd.c Á×§K¦³¯¸ªø¥á¤ô²yµ¹ guest¡C + +[2000/09/30] xover.c ×¥¿ every_Z «áªO¥DÅv¿ù»~¡C + +[2000/10/29] mail.c ¯¸ªø¥i¥HŪ¨ú¨Ï¥ÎªÌ«H½c¡C + +[2000/11/01] perm.h *.c §â¯¸°ÈªºÅvµe²M¡C + +[2000/11/02] bbsd.c ¥H sysop µn¤J¥i¥HÅܧó¨Ï¥ÎªÌ¨¤À¡C + +[2000/11/09] menu.c post.c §ïÅÜ PERM_ALLBOARD ¦bºëµØ°ÏªºÅv¡C + gem.c §âºëµØ°Ï¦¬¿ý´£¥Ü¦r¼Ë§ï¦¨¤¤¤å¡C + +[2000/11/18] post.c ·s¼W XoXsearch() ·j´M¬Û¦P¼ÐÃD¤å³¹¡C + bbsd.c config.h HAVE_WHERE ×¥¿¬G¶m§P©w¡C + acct.c menu.c ¦pªG¨S¦³ define HAVE_ALOHA¡A´N¤£¥Î UFO_ALOHA¡C + +[2000/11/19] acct.c ²¾°£ etc/register¡C + +[2000/11/25] mail.c §ï¼g¸s²Õ¦^«HªºÀˬd¡C + +[2000/11/26] maple.p Makefile acct.c talk.c bbsd.c xover.c aloha.c camera.c rec_loc.c + global.h modes.h struct.h @aloha.hlp ·sªº HAVE_ALOHA¡C + talk.c ·s¼W¤ô²y°O¿ý°Ï¬q§R°£¡C + +[2000/12/02] maple.p Makefile favorite.c bbsd.c board.c menu.c xover.c camera.c + config.h global.h modes.h struct.h @mf.hlp ·s¼W MY_FAVORITE¡C + aloha.c ·s¼W¦n¤Í¦W³æ±Æ§Ç¡B¬d¸ß¥\¯à¡C + +[2000/12/03] outgo.c ¦Û°Ê°e«Hµ{¦¡¡C + camera.c ²¾°£ FILM_GOODBYE¡C + +[2000/12/17] perm.h ×§ï HAS_PERM(x) HAVE_PERM(x)¡C + *.c HAVE_PERM(x) ¤Î cuser.level & x ´«¦¨ HAS_PERM()¡C + +[2000/12/20] config.h §â SYSOPNICK ¿W¥ß¥X¨Ó¡C + post.c ·s¼W post_cross_terminator() §R°£¬Û¦P§@ªÌ¡C + xover.c §ïÅܤ@¨Ç«öÁä keymap¡C + post.c ·s¼W XoX ¨t¦Cªº·j´M¡A¨Ï»P ¨ä¥Lª©¥» BBS ¬Û¦P¡C + +[2000/12/21] talk.c Talk ®É¥i¥H¤è¦VÁä²¾°Ê¡BCtrl+Y ²M°£¤§Ãþªº¥\¯àÁä¡C + config.h talk.c ²¾°£ TALK_USER_LIST¡C + +[2000/12/22] talk.c ¨Ï¥ÎªÌ¦W³æ¥[¦n¤Í®ÉÀˬd¦n¤ÍӼƬO§_¶W¹L¤W¡C + global.h §â³\¦h message define ¦b³o¡A¨Ã±N COLOR ¿W¥ß¥X¨Ó¡C + +[2000/12/23] talk.c cache.c bbsd.c §âÃa¤H¤]¸ü¤J CACHE¡C + +[2000/12/24] config.h global.h talk.c ADV_ULIST ¨Ï¥ÎªÌ¦W³æ¤¤¡A¤£¦Pªº¦n¤Í·|°Ï¤ÀÃC¦â¡C + aloha.c ¤Þ¤J¦n¤Í¦Ü¦h¥u¤Þ¨ì ALOHA_MAX ªºÓ¼Æ + +[2001/01/01] acct.c ×¥¿ POP3 »{ÃҮɤ£·|Àx¦s¨Ï¥ÎªÌ«H½c¡C + talk.c ¨Ï¥ÎªÌ¦W³æ¤¤ UFO_PAL ¤£¥X²{»P§Ú¬°¤Í¡A¥H§K¦n¤Í¼s¼½¿ù»~¡C + +[2001/01/02] acct.c ¨t²Î«¸m¡C + +[2001/01/06] dns_aton.c dns_open.c dns_smtp.c bmtad.c ¤ä´© mail-abuse¡C + config.h global.h acct.c untrust.acl trust.acl HAVE_TRUST »{ÃÒ¶Â¥Õ¦W³æ¡C + acct.c camera.c struct.h §â ¤@¨Ç±`¥Îªº¤å¥ó§ì¥h FILM_XX¡C + talk.c ¥[ªø¤ô²yªø«×¡C + talk.c @ulist.hlp ¨Ï¥ÎªÌ¦W³æ¤¤«ö d §R°£¦n¤Í/Ãa¤H¡C + +[2001/01/08] config.h global.h struct.h modes.h camera.c menu.c newbrd.c + ´£¨Ñ¬ÝªO³s¸p¥\¯à¡C + talk.c °O¿ý²á¤Ñ¶}©l®É¶¡¡C + +[2001/01/10] §â src/maple ¤¤ªº so ·h¥h src/so¡C + admutil.c menu.c acct.c maple.p + §â¯¸ªø«ü¥O m_xfile m_resetsys m_reg_merge ¥~±¾¡C + favorite.c @mf.hlp §Úªº³Ì·R¤¤¥i¥H×§ï¬ÝªO¡C + +[2001/01/11] *.c §â xxx_head ¤ºªº´£¥Ü¦r¼Ë®æ¦¡§ï¦¨¬Û¦P¡C + config.h mail.c acct.c ¨Ï undef EMAIL_JUSTIFY ¦³®Ä¡C + +[2001/01/12] config.h global.h acct.c mail.c menu.c maple.p bmtad.c + @justify @e-mail valid HAVE_REGKEY_CHECK »{ÃÒ½XÅçÃÒ¡C + bbsd.c ¨Ï¬G¶m±Æ§Ç¥¿±`¡C + +[2001/01/13] config.h menu.c ´£¨Ñ¿ï³æ¥ú´Î¡C + +[2001/01/15] xover.c menu.c Ctrl('U') ¸õ¨ì¨Ï¥ÎªÌ¦W³æ¡C + +[2001/01/16] §â COLOR3 ¿W¥ß¥X¨Ó¡C + +[2001/01/17] mail.c ¤å³¹¡B¶l¥ó¤é´Á¤W¦â¡C + +[2001/01/27] newbrd.c struct.h °Î¦W³s¸p¾÷¨î¡C + visio.c menu.c ×¥¿ vmsg(NULL) pad_view() + ¦b°»´ú¥ª¥kÁä¥þ§Î¤U¡A«ö¥ªÁä·|¸õÂ÷¤G¼h¿ï³æªº°ÝÃD¡C + talk.c ¹ï¤è§Y¨Ï¨S¶}¡u¦n¤Í¤W¯¸³qª¾¡v¤]³qª¾¡C + talk.c ¦Û¤v¬O¹ï¤èªº¦n¤Í¥B¹ï¤è¨S¦³¡u»·Â÷¹ÐÄÛ¡v¤~¥i¥H¦^¦©¤W¯¸³qª¾¡C + §ó·s bpop3d.c¡C + +[2001/01/28] bbsd.c admutil.c ¬G¶m¤ñ¹ï¥i¥H¤ñ¹ï FQDN¡C + board.c @class.hlp ¬ÝªO¦Cªí«ö v ³]©w¬ÝªO¤wŪ¡C + +[2001/01/29] bmtad.c ¥H indent ±Æª©¡C + board.c @class.hlp ¬ÝªO¦Cªí«ö V ³]©w¬ÝªO¥¼Åª¡C + +[2001/02/05] edit.c post.c bmtad.c config.h ÅÜ´« Origin ¼Ë¦¡¡C + post.c ¨î¤å³¹Âà¿ý½g¼Æ¡C + post.c µoªí«áªº¤å³¹´N°O¿ý¡A¨Ï¤£¥X²{¥¼¾\Ūªº¡Ï¸¹¡C + config.h struct.h global.h menu.c xover.c song.c camera.c + @song.hlp ´£¨ÑÂIºq¥\¯à¡C + +[2001/02/07] camera.c ´£¨ÑÂIºq¨ì°ÊºA¬ÝªO¥\¯à¡C + global.h *.c §â¨t²ÎªO¦W¿W¥ß¥X¨Ó define BN_XXXX¡C + bwboard.c guessnum.c ¥H indent ±Æª©¡C + post.c board.c ¤å³¹¦Cªí³¡¤À visit¡C + bmtad.c mailpost ®ÉÀˬd¨Ï¥ÎªÌÅv¬O§_º¡¨¬¬ÝªO¾\Ū/µoªíÅv¡C + +[2001/02/08] bbsd.c talk.c guest ¶Ã¼Æ¨ú¬G¶m¡C + modes.h menu.c °ÊºA«±Æ¡C + km.c menu.c ´£¨Ñ¤Õ©ú´Ñ¹CÀ¸¡C + +[2001/02/09] menu.c «·s¾ã²z¿ï³æ¡C + menu.c ¥D¿ï³æ«ö s ª½±µ¶i¤J Select()¡A´î¤Ö¿ï³æªø«×¡C + +[2001/02/10] dns_smtp.c ¥Î relay server¡C + +[2001/02/11] acct.c bbsd.c ¦Û°Ê¨ú¤UÂ÷¾ªO¥DÅv¡C + acct.c ·s¬ÝªO¹w³]µoªíÅv¬°µoªí¤å³¹¡A¹w³]Äݩʬ°¤£Âà«H¡C + +[2001/02/12] src/Makefile §Ö³t¦w¸Ë¥Îªº Makefile¡C + acct.c ¶}·sªO/×§ï¬ÝªO¦Û°Ê¥[¤WªO¥DÅv¡C + +[2001/02/15] mine.c menu.c ´£¨Ñ½ò¦a¹p¹CÀ¸¡C + +[2001/02/17] mail.c ¤å³¹¡B«H¥ó¦Cªí¤é´Á§ï¥Î¬P´Á´X¤W¦â¡C + talk.c Talk ®É¦³ insert ¥\¯à¡C + +[2001/02/18] gem.c ºëµØ°Ï²§°Ê°O¿ý®æ¦¡ÅܰʡC + +[2001/02/20] fantan.c menu.c ´£¨Ñ±µÀs¹CÀ¸¡C + +[2001/02/21] favorite.c ¨î§Úªº³Ì·R¥u¯à§R°£ªÅ¥Ø¿ý¡A¥H§K¯d¤UÀÉ®×´ÝÀe¡C + global.h edit.c §â origin banner ªº logo ¿W¥ß¥X¨Ó¡C + +[2001/02/22] gem-check.c Á×§KºëµØ°Ï Class¤U©ñ Folder ³Q expire ±¼¡C + transacct.c .ACCT Âà´«µ{¦¡¡C + +[2001/02/23] maple/Makefile ¤£¥Î make clean ª½±µ¹ï©Ò¦³ªº .o °µ³sµ²¡C + bbsd.c ¯¸°È¤£°µ©w´Á»{ÃÒ¡C + perm.h *.c §â¯¸°ÈÅv°µ§ó²Ó¨Bªº«¾ã¡C + *.hlp ¥[¤J xover.c ¤¤ªº«ü¥O¡A¨Ã«·s¾ã²z±Æª©¦¨¬Û¦P®æ¦¡¡C + post.c gem.c ·s¼W¨Ï¥ÎªÌ²ßºDªº c/p ¦¬¿ýºëµØ°Ï¡C + +[2001/02/24] gem-check.c µL±ø¥ó§R°£¨S¥ÎªºÀɮסC + account.c §â¤@¨Ç¤å¥ó©ñ¦b [BN_SECURITY]¡C + usies-sort.c account.c ²Îp§C¨Ï¥Î²vªº¬ÝªO¨ì [BN_SECURITY]¡C + acct.c account.c °O¿ý¯¸ªø×§ïÅv¨ì [BN_SECURITY]¡C + +[2001/02/25] mine.c ×¥¿¤p¿ù»~¡C + talk.c ·s¼W²Ä¤Tª© talk_char()¡C + +[2001/02/26] board.c favorite.c ×¥¿¤¤¤åªO¦W¤Óªø®É¡A¬Y¨Ç term ¬Ý°_¨Ó·|¸õ¦æªº°ÝÃD¡C + +[2001/02/28] config.h menu.c mail.c maple.p HAVE_MAIL_ZIP + ´£¨Ñ§â«H¥ó/ºëµØ°ÏÀ£ÁYÂà±Hªº¥\¯à¡C + +[2001/03/01] xyz.c menu.c etc/tip ¨C¤é¤p¯µ³Z¡C + post.c edit.c ´£¨Ñ½s¿è(¦ý¤£¯àÀx¦s)¨ä¥L¤Hµoªí¤å³¹ªº¥\¯à¡C + mail.c ´£¨Ñ½s¿è(¦ý¤£¯àÀx¦s)«H½c¤¤«H¥óªº¥\¯à¡C + fantan.c ×¥¿¯}Ãö®É¤£·|µ²§ôªº°ÝÃD¡C + +[2001/03/02] inst.sh ¦Û°Ê¦w¸Ë script¡C + util/uno/Makefile util/tran/Makefile ¤è«K make¡C + config.h talk.c HAVE_BADPAL ¥i¥H®³±¼¾ãÓÃa¤H¥\¯à¡C + +[2001/03/03] bbsd.c currtitle ÁÙì¡C + more.c @more.hlp ·s¼W¤W±²¤@¦æ¡C + +[2001/03/04] newbrd.c @cosign.hlp §â³s¸p¬É±°µ±o§ó¹³¾\ۤ峹¤@¼Ë¡C + global.h *.c ¾ã²z©Ò¦³ªº footer¡C + talk.c ¼Wªø¤ô²y°O¿ý¡C + menu.c ¶i¥X¤l¿ï³æ³£«¼·°ÊºA¬ÝªO¡C + menu.c ·s¼W§Úªº³Ì·R§Ö³tÁä¡C + talk.c ¦b¤ô²y¦^ÅU¤¤¡AÅý¶Ç°T/¦¬°T/¼s¼½ªº¤ô²y³£¥i¥H¦^¡C + +[2001/03/06] config.h mail.c CHECK_ONLINE ¤å³¹¦Cªí¤¤¥i¥HÅã¥Ü¨Ï¥ÎªÌ¬O§_¦b¯¸¤W¡C + +[2001/03/07] xyz.c menu.c ´£¨Ñ BBSNET ªA°È¡C + +[2001/03/09] menu.c ¤£¥²Â÷¯¸¥i¥H¼g¯d¨¥ªO¡C + menu.c ¯d¨¥ªO´£¨Ñ¤£¦PªºÃC¦â¤Î¶¼Æ¡C + acct.c §â User/Setup ªº»¡©ú¼g©ú¥Õ¤@ÂI¡C + acct.c ¿é¤J id ®É´£¥Ü¥i«ö space ¦Û°Ê·j´M¡C + menu.c ¿ï³æ±Ôz½s±Æ¡C + struct.h bbsd.c §â userlevel ¤]©ñ¤J cache¡C + talk.c §Q¥Î cache ªº userlevel §ïµ½Àˬd³t«×¡C + +[2001/03/10] mail.c ×¥¿¸s²Õ±H«Hµ²§ô®É½Ð«ö¥ô·NÁäÄ~Äò·|©Ç©Çªº¡C + +[2001/03/11] global.h menu.c acct.c visio.c §ì¥X MENU_XYPOS ©w¸q¡A¥H«Kק虜±¡C + global.h acct.c menu.c §ì¥X MENU_YNOTE ©w¸q¡A¥H«Kק虜±¡C + cache.c camera.c §ì¥X MOVIE_LINES ©w¸q¡A¥H«Kק虜±¡C + post.c mbox.c @board.hlp @mbox.hlp ²Î¤@«öÁä¡C + 'x' Â൹ user 'X' Âà¨ì board ^X ©Ø·¬¸¨¸ + +[2001/03/12] config.h modes.h talk.c visio.c BMW_COUNT pºâ¤¤¤ô²yªºÓ¼Æ¡C + visio.c acct.c ×¥¿ vget() ´å¼Ð²¾°ÊÅã¥Üªº°ÝÃD¡C + fantan.c guessnum.c mine.c ¨ú®ø¤@¨Ç¨S¥Îªº°T®§¡C + config.h *.c §â¤@¨Ç°Ñ¼Æ¾ã²z¤@¤U¡A·h¥h¥LÌÂkÄݪºµ{¦¡¡C + +[2001/03/13] config.h talk.c BMW_DISPLAY Åã¥Ü«e´XÓ¤ô²y¡C + acct.c ¥[±jª©ªº¿Ã¹õÂê©w¥\¯à¡AÅýÂê©w®É¤£¯à±µ/¶Ç¤ô²y¡A¥B²M°£¿Ã¹õ¡C + +[2001/03/15] struct.h acct.c talk.c ¥[¤J¦Û©w Ctrl+R ¬O§_n¦^ÅU¤ô²yªº¿ï¶µ¡C + +[2001/03/16] *.c ²Î¤@°ÝÃD®æ¦¡¬° "§An¶Ü(Y/N)¡H[N] " ¥þ§Î°Ý¸¹ ¤j¼g Y/N ¹w³]¥Î [] ¡C + ^ µLªÅ¥Õ ^ªÅ¥Õ + +[2001/03/17] acct.c bbsd.c ¤£Åý user ×§ï©m¦WÄæ¦ì¡C + util/backup/*.c ¦Û°Ê³Æ¥÷µ{¦¡¡C + +[2001/03/19] *.c *.h §â©Ò¦³ªº define ¤ÀÃþ¾ã²z¨ì config.h¡C + config.h modes.h bbsd.c mail.c xover.c mboxgem.c reaper.c + HAVE_MBOX_GEM ´£¨ÑÓ¤H«H½cºëµØ°Ï¡C + +[2001/03/21] xchatd.c MUD-like ªº«ü¥O³¡¤À match ´Nºâ¡C + xchatd.c MUD-like «ü¥O«ö¦r¥À±Æ§Ç¡C + +[2001/03/22] chat.c ¶i¤J²á¤Ñ«Ç®É¹w³]§ï¬°¤£²á¤Ñ¡C + xover.c §â¤£±`¥ÎªºÁ䮳±¼¡AÄÀ¥Xµ¹¨ä¥Lµ{¦¡¨Ï¥Î¡C + *.c @*.hlp «öÁä«·s²Î¤@¡C + edit.c ANSI ½s¿è®É«ö«á°hÁä¦^¨ì«D ANSI ¼Ò¦¡¡C + +[2001/03/24] post.c ¦ê¦C·j´Mµ²ªG´£¥Ü§@ªÌ/¥DÃD¡A¨Ã¸Ñ¨M´£¥Ü¤¤¤å¦r·|©Ç©Çªº°ÝÃD¡C + mail.c ¸Ñ¨M«H¥óÂsÄý¥u§â³Ì«á¤@½g³]¤wŪªº°ÝÃD¡C + more.c KEY_UP KEY_PGUP ¹ï¤G¶¥H¤Wªº¤å³¹¥iÂ÷¶}¨Ã½¤W¤@½g¡C + post.c ¦ê¦C·j´M¼Ò¦¡¤¤®É«ö¤W¤UÁä¤]¥i¥H´`§Ç¾\Ū¡C + +[2001/03/25] bmtad.c mail post Àˬd¬O§_¦³µoªíªºÅv¡C + post.c @board.hlp ·j´M©Ò¦³ mark ªº¤å³¹¡C + talk.c ½Õ¾ã¨Ï¥ÎªÌ¦W³æªº°ÊºAªø«×¡C + +[2001/03/27] post.c ´£¨ÑªO¥D¦bªO¤º×§ï¤¤¤åªO¦W¡C + xover.c ×¥¿¦bºëµØ°Ï¤£¥iÂà±H¡C + +[2001/03/28] post.c cache.c @board.hlp ¦b¤å³¹¦Cªí¥i¥H¥á½u¤W§@ªÌ¤ô²y¡C + config.h acct.c more.c post.c xover.c §ì¥X HAVE_NOFORWARD¡C + *.c §â¬Ýª©¡B¼Æ¥D³£§ï¦¨¡uªO¡v¡A²Î¤@¥Î¦r¡C :p + *.c Åý xxx_cb ¤¤ªº dynamic load ¤£·|¦³ warning¡C + +[2001/03/29] mode.h «·s¾ã²z¡C + +[2001/03/30] bmw.c board.c pal.c post.c talk.c maple.p + §â talk.c ¸Ì±ªºµ{¦¡¤À´²¨ì¦U¾A·íªº¦a¤è¡C + util/tran/*.c ´£¨Ñ sob Ptt WD FireBird Âà maple 3 ªºµ{¦¡¡C + +[2001/04/02] favor.c §Úªº³Ì·R¤¤¥i¥H³]©w¬ÝªO¤wŪ/¥¼Åª¡C + board.c favor.c mf.hlp ¬ÝªO¦Cªí¤¤³]©w¬ÝªO¥¼Åª«á¡A¥¼Åªªº¿O·|«G°_¨Ó¡C + +[2001/04/03] bmw.c ×´_¤ô²y°Ï¶ô§R°£ªº¥\¯à¡C + xover.c *.c global.h ¦b³Ì«á¤@¦æ´£¥Ü«ü¥O¡C + song.c ºq¥»¤¤Åý¤@¯ë¨Ï¥ÎªÌ¤]¥i¥H edit ¬Ý±±¨î½X¡C + +[2001/04/07] config.h board.c favor.c ENHANCED_VISIT ¤wŪ/¥¼Åª§ï¬°§PÂ_³Ì«á¤@½g¤å³¹¡C + menu.c ×¥¿ guest ¥i¥H¶i¤J§Úªº³Ì·Rªº bug¡C + cache.c edit.c more.c visio.c ¼W¥[ SHOW_USER_IN_TEXT ªººØÃþ¡C + +[2001/04/08] acct.c talk.c ·s¼Wª÷¿ú¡B¥Í¤é¡B©Ê§OÄæ¦ì¡C + post.c edit.c µoªí¤å³¹¥[¿ú¡C + mail.c ¦b«H¥ó¦Cªí¥i¥H¥á½u¤W§@ªÌ¤ô²y¡C + +[2001/04/13] mboxgem.c ¤p patch¡C + @board.hlp @mbox.hlp ¥[±j¡C + struch.h @class.hlp board.c acct.c account.c ¬ÝªO¦Cªí¥i¿ï¾Ü¨Ì¦r¥À/¤ÀÃþ±Æ§Ç¡C + +[2001/04/14] vote.c menu.c global.h ·s¼W§ë²¼¤¤¤ßªº¥\¯à¡C + +[2001/04/15] account.c ·s¼W¦P¤@ email »{ÃÒ¹L¦hªº°O¿ý¡C + bbsd.c ¥Í¤é·í¤Ñ¤W¯¸¦³¯S§Oªº¶i¯¸µe±¡C + +[2001/04/19] @gem.hlp gem.c mboxgem.c ¥[¤JºëµØ°Ï·s¼W¤å³¹/¨÷©vªº§Ö³tÁä¡C + +[2001/04/20] *.c §â¤@¨Ç vget() ¤£»Ýn GCARRY ªº´«¦¨ DOECHO¡C + dice.c menu.c ·s¼WÂY»ë¤l¹CÀ¸¡C + +[2001/04/21] gp.c menu.c ·s¼Wª÷¼³§J±ô«¢¹CÀ¸¡C + race.c menu.c ·s¼WÁɰ¨³õ¹CÀ¸¡C + bingo.c menu.c ·s¼W»«ªG¹CÀ¸¡C + bmw.c cache.c ¸Ñ¨M¦pªG post ®É¤¤¤ô²y¡A¤£·|Åã¥Ü¨Ó·½ªº°ÝÃD¡C + +[2001/04/23] bj.c menu.c ·s¼W¶Â³Ç§J¤G¤Q¤@ÂI¹CÀ¸¡C + admutil.c acct.c menu.c maplep.p §âµù¥U³æ»{ÃÒªºµ{¦¡·h¥h dynamic load¡C + +[2001/04/24] nine.c menu.c etc/game/99 ·s¼W¤Ñ¦a¤E¤E¹CÀ¸¡C + +[2001/04/25] chessmj.c menu.c ·s¼W¶H´Ñ³Â±N¹CÀ¸¡C + +[2001/04/26] util/tran/wd2brd.c ´£¨ÑÂà´«¬ÝªOÄݩʡC + seven.c menu.c ·s¼W½ä«°¤C±i¹CÀ¸¡C + marie.c etc/game/marie menu.c ·s¼W¤pº¿ÄR¼Ö¶é¹CÀ¸¡C + +[2001/04/27] bar.c menu.c ·s¼W§a¥xº¿ÄR¹CÀ¸¡C + +[2001/05/02] km.c ¤Õ©ú´Ñ§ï¶i¡A¨Ï·|¥X²{´ÑÃЦWºÙ¡C + +[2001/05/08] stock.c menu.c etc/game/stock.name etc/game/stock.now etc/game/stock.sh + ·s¼WªÑ¥«¤j¦ë¹CÀ¸¡C + +[2001/05/09] km.c ¤Õ©ú´Ñ§ï¶i¡A¨Ï¯à°O¿ý§¹¦¨ªº´ÑÃФή¬´Ñ¡C + etc/game/km ¿é¤J¤j¶q¤Õ©ú´ÑÃСC + +[2001/05/25] visio.c ¡u½Ð«ö¥ô·NÁäÄ~Äò¡v¶]°¨¿O¡C + +[2001/05/28] chat.c ¤£¥i¥H¥Î§O¤Hªº id ·í°µ²á¤Ñ«Ç¥N¸¹¡C + +[2001/05/29] struct.h ¼W¥[ BMW.userid ªºªø«×¡Aµ¹¼s¼½²Å¸¹¥Î¡C + +[2001/06/02] menu.c §ï±¼¤@¨Ç«ÂÐÃöÁä¦rªº¿ï¶µ¡C + config.h post.c xover.c @board.hlp HAVE_REFUSEMARK ´£¨Ñ¬ÝªO¤å³¹¥[±K¥\¯à¡C + xover.c ×¥¿¤w§R°£¤å³¹¤£±oÂà±H¡B¶×¤J¼È¦sÀÉ¡B Z-modem ¤U¸ü¡C + bmtad.c mailpost.c ¸Ñ¨M¤£¯à Email Justufy »{ÃÒ¡C + +[2001/06/06] bpop3d.c ×¥¿¬Y¨Ç client ¨ú«H·|¥d¦ºªº°ÝÃD¡C + dl_lib.c ¸Ñ¨M¥~±¾¤Ó¦h.so Ãz±¼¤Fªº°ÝÃD¡C + +[2001/06/09] railway.c ¿é¤J¨®¯¸¦W®É§ï¥Î¿ï¸¹½Xªº¡C + +[2001/06/16] menu.c ¸Ñ¨M°ÊºA¬ÝªO 12 ¦æ¡A¤S¨Ï¥Î¿ï³æ¥ú´Î®É¡Aµe±·|¦³´ÝÀeªº°ÝÃD¡C + +[2001/06/19] wd2usr.c ¸Ñ¨M .PASSWD ±`¦³ªÅ¥ÕÄæ¦ìªº°ÝÃD¡C + +[2001/06/29] more.c ±N¤Þ¨¥¤ÀÃC¦â¡C + +[2001/07/09] acct.c POP3 REGKEY »{ÃÒ¥u¯à¦³ PERM_VALID¡A¦b¤U¦¸ login ®É¦Û°Ê¥[¤W¨ä¥LÅv¡A + ¥H§K³Q°±ÅvªÌÂǦ¹¤èªk´_Åv¡A¤]¤£·|»P NEWUSER_LIMIT ½Ä¬ð¡C + +[2001/07/09] post.c ×§ï¤å³¹¼ÐÃD®É¶¶«Kק鷺¤åªº¼ÐÃD¡C + +[2001/07/10] chip.c ª±¹CÀ¸¤£¯à multi_login¡C + backupacct.c ³Æ¥÷¥þ¯¸¨Ï¥ÎªÌ .ACCT¡C + menu.c ×¥¿ system load ¬d¸ß¡C + +[2001/07/11] board.c ¬ÝªO¨Ì¦WºÙ/¤¤¤åªO¦W¤Á´«®ÉÀ³Àx¦s¾\Ū°O¿ý¡C + topusr.c ¥i²Îp¤W¯¸¦¸¼Æ/Äé¤ô¦¸¼Æ/»È¹ô/ª÷¹ô/¦~ÄÖ/¬P®y¡C + mine.c ×¥¿ª±½ò¦a¹pÀH«K¶Ã¼Ð°O¡A·í¼Ð°O¼Æ=¦a¹p¼Æ´N»¡§A¹LÃö¤F¡C + post.c §R°£¤å³¹n¦©¿ú¡C + +[2001/07/12] chip.c marie.c etc/game/marie ×§ï¦X²zªº½ß²v¡C + post.c §ï¥Î¦r¼Æ¤Îªá¶O®É¶¡¨Ópºâ½Z¶O¡C + +[2001/07/14] dice.c ×§ï¦X²zªº½ß²v¡C + gp.c ×§ï¨Ï¯à§@¹ú¨Ó°§C³Ó²v¡C + .BRD brd/* gem/brd/* run/class*.img §â¹w³]¬ÝªO«Ø¥ß°_¨Ó¡C + gem/@ §â (A)nnounce ¿ï³æ«Ø¥ß°_¨Ó¡C + +[2001/07/16] showUSR.c showACCT.c Åã¥Ü .USR .ACCT ¥Îµ{¦¡¡C + setusr.c setperm.c ¥~³¡³]©w¨Ï¥ÎªÌ¸ê®Æ¡C + menu.c bank.c ¥[¤J»È¦æ¡A´£¨ÑÂà±b¡B¶×§I¥\¯à¡C + config.h struct.h acct.c bbsd.c HAVE_NOALOHA ´£¨Ñ¤W¯¸¤£³qª¾¦n¤Í¡C + config.h struct.h acct.c talk.c HAVE_NOBROAD ´£¨Ñ©Ú¦¬¼s¼½¡C + bbsd.c «OÃÒ¤H¨î«×°O¿ý«O¤H¡C + stock.c ¹w¨¾ªÑ»ù = 0 (¤½¥q˳¬)¡C + +[2001/07/17] post.c ´£¨Ñ XPOST ¤¤¥i¥H½s¿è¼ÐÃD¡B¤å³¹¡A¥[±K¡C + config.h menu.c bank.c ´£¨ÑÁʶRÅv¡C + menu.c ½Õ¾ã feeter ªºªø«×¡C + config.h talk.c @ulist.hlp HAVE_CHANGE_ID ¨Ï¥ÎªÌ¦W³æ¯¸ªø¼È®É×§ïID¡C + +[2001/07/19] menu.c recall.c ´£¨Ñ°O¾Ð¹CÀ¸¡C + +[2001/07/20] vote.c ×¥¿ vote_all «ö End ©Î $ À³Àˬd¬O§_¤w¨ì³Ì«á¤@¶µ¡C + +[2001/07/23] xover.c post.c gem.c §ï¼g gem_gather()¡C + menu.c gray.c ´£¨Ñ²L¦Ç¤j¾Ô¹CÀ¸¡C + gem.c mboxgem.c ×¥¿¬Y¨Ç±¡ªp¤U¤£¯à Ctrl+P gem_add ªº°ÝÃD¡C + +[2001/07/25] menu.c pip/* etc/game/pipgame etc/game/pipdata ´£¨Ñ¹q¤l¤pÂû¹CÀ¸¡C + post.c §Y¨Ï¬Oì¤åÂà¸ü¡A¤]¤£n¥Î HDR_LINK ªº¤èªk¡A´Nµø¬°¬O¤£¦Pªº¤å³¹¡C + gem.c ©Ò¦³¦¬¿ý¤å³¹ªº°Ê§@³£§ï¦¨¨S¦³ HDR_LINK¡A¤@½g¤å³¹´N¬O¤@ÓÀɮסC + +[2001/07/26] gem.c ¥Ñ©ó¤@½g¤å³¹´N¬O¤@ÓÀɮסA©Ò¥H§R°£®É§ï¦¨ª½±µ§R°£ÀɮסC + gem.c ´£¨Ñ°Ï¬q§R°£¥\¯à¡C + gem.c ¤ä´©¸ó°Ï«þ¨©¡C + gem-check.c ¤£¦A¨Ï¥Î¡C + favor.c ¨t²Î¦Û°Ê²¾°£¾D¬åªOªº¬ÝªO¡B¬ÝªO±¶®|¡C + +[2001/07/27] acct.c ×§ï¬ÝªO®É¡A´£¨Ñ²M°£©Ò¦³ªO¥D(ªO¥DÄæ¯d¥Õ)¡C + mboxgem.c config.h global.h modes.h ¨ú®ø¤£¨Ï¥Î¡C + gem.c ¥Ñ©ó¤ä´©¸ó°Ï«þ¨©¡A¤¹³\©Ò¦³¤H¦¬¿ý¬ÝªO¡B½Æ»sºëµØ°Ï¤å³¹¨ì¥L¾á¥ô(¤p)ªO¥D/Ó¤H«H½cªº¦a½L¡C + gem.c ºëµØ°Ï¶K¤W®ÉÀˬdÁ×§Kµo¥Í°j°é¡C + bbsd.c gem.c ±NÓ¤H«H½cºëµØ°Ï©M¬ÝªOºëµØ°Ï¾ã¦X¡C + fb2usr.c sob2usr.c wd2usr.c Âà´«µ{¦¡¼W¥[Ó¤HºëµØ°Ï¡C + +[2001/07/29] dreye.c ´£¨Ñ͍å³q½u¤W¦r¨å¥\¯à¡C + +[2001/08/02] etc/pipgame/* pip/* ¹q¤lÂû¹CÀ¸¤j§ïª©¡C + +[2001/08/03] @goodbye struct.h camera.c menu.c Â÷¯¸®É¨q¤@±i¹Ï¡C + +[2001/08/04] acct.c ´_Åv¥\¯à¡C + +[2001/08/05] acct.c ×¥¿«·s»{ÃÒ®ÉÅv¤£¹ïªº°ÝÃD¡C + visio.c «ö¥ô¤@Áä²M°£¤ô²y¼Æ¡C + newbrd.c acct.c ·sªO³s¸p§¹¡A¯¸ªø¥i¥Hª½±µ¶}ªO¡C + +[2001/08/11] acct.c so/*.c pip/pip_basic.c post.c §â¥[´î¿ú¦^¦sµwºÐªº¨ç¦¡¿W¥ß¦¨ acct_savemoney()¡C + cache.c acct.c perm.h bbsd.c admutil.c maple.p °ÊºA³]©w¨Ï¥ÎªÌ¸ê®Æ¡C + +[2001/08/12] menu.c so/*.c §â¹CÀ¸°ÝÄw½Xªº¨ç¦¡¨Ö¤J menu.c¡C + +[2001/08/14] pip_stuff.c §ïÅܦsÀɮ榡¡C + pipstruct.h pip_fight.c pip_prac.c ·s¼WÅ@¨¡B»´¥\¡B¤ßªk¡B¤Mªkµ¥¾Ô°«§Þ¯à¡C + pip_fight.c Â×´I©ÇÃ~²£¥Í¾¹¥[¤J©Çª«ÄݩʡC + +[2001/08/15] mail.c ´£¨Ñ§âÓ¤HºëµØ°ÏÀ£ÁY±H¦^¥hªº¥\¯à¡C + +[2001/08/16] xchatd.c ½Í¤Ñ«Ç¤¤ mud-like «ü¥O±Ôz§ï¼g¡C + pip/* etc/game/pip/* «·s¾ã²z¡C + +[2001/08/20] pip.c pip_fight.c pipstruct.h ·s¼W¯S®í§Þ¯à¡C + gem.c post.c ¦¬¿ýºëµØ°Ï¤£¥[¤W POST_GEM¡C + *.c etc/* ²Î¤@¡u¨¤À¡v¥Î¦r¡C + acct.c bmtad.c mailpost.c §ï¼g»{ÃÒ³¡¤Àµ{¦¡¡C + +[2001/08/21] chessmj.c ×¥¿¥[¿ú¿ù»~¡C + global.h *.c ¾ã²z¤ÀÃþ FN_XXXX¡C + so/*.c ¨ú®øª±¹CÀ¸¤£»Ýn«Ã¸¿ï³æ¡C + jcee.c etc/jcee/* ¤j¾ÇÁp¦Ò¬dº]¡C + favor.c ×¥¿¬ÝªO^¤å¦WºÙÅܰʫá¡A§Úªº³Ì·R·|¥X¿ù¡F×¥¿ÅvÅܰʫá¡A¬Ý¨ì·sÅv¤£¯à¬Ý¨ìªº¬ÝªO¡C + newbrd.c acct.c ×¥¿³s¸p¶}ªO®É¤£·|§â§@ªÌ¦Û°Ê¥[¤WªO¥DÅvªº°ÝÃD¡C + global.h edit.c more.c §ï¤@¨Ç FOOTER ¨Ïµ¥ªø¹ï»ô¡C + +[2001/08/22] config.h mode.h global.h xover.c post.c HAVE_XYNEWS ·s»D¾\Ū¼Ò¦¡¡C + post.c ·j´M¥»¦a¤å³¹¡C + +[2001/08/24] pipstruct.h pip_fight.c ·s¼W§Þ¯à·t¾¹¡C + xyz.c §ïµ½ BBSNET ªº¬É±¡C + +[2001/08/25] xyz.c etc/game/qkmj/* ·s¼W QKMJ¡C + global.h bmtad.c mailpost.c mail.c acct.c »{ÃÒ½X»{ÃÒ¤£»Ýn¶}ÀÉ¡C + +[2001/08/27] innbbsd/Makefile §ï¼g¡C + gem-expire.c §ï¼g¡C + visio.c ·s¼W½Ð«ö¯S®íÁäÄ~Äò¡C + +[2001/08/29] talk.c §ïµ½¨Ï¥ÎªÌ¦W³æ®Ä²v¡C + pal.c ×¥¿ÁÙ¨S¨ì¦n¤Í¤W´Nĵ§i¦n¤Í¹L¦hªº°ÝÃD¡C + +[2001/08/30] gp.c ×¥¿¯S®íµP«¬¿é¿úªº°ÝÃD¡C + +[2001/08/31] acct.c bbsd.c menu.c post.c so/*.c pip_basic.c perm.h + §Q¥Î disable ²Ä¤G°¦¥H«áªº multi-login ªº¿ú¹ô¨Ó¹w¨¾ multi ÁÈ¿ú¡A + ¦p¦¹«K¥i¥H¨ú®øÄw½X¨î«×¡A¨Ã´î¤Ö¤j¶qªº¦^¦s .ACCT¡C + +[2001/09/01] struct.h ×¥¿ MODE_STAT ·|¿ù¶Ãªº°ÝÃD¡C + vote.c global.h §ë²¼°Ï¥kÁä§Y¥i§ë²¼¡C + +[2001/09/02] admutil.c menu.c ·j´M¨Ï¥ÎªÌ¡C + +[2001/09/07] visio.c ×¥¿¥Î Ctrl-R ¦^¤ô²y¤£·|«p¤ô²y¼Æ¡C + classtable.c menu.c ´£¨Ñ¥\½Òªí¥\¯à¡C + gray.c Â÷¶}²L¦Ç¹CÀ¸n«Ã¸ menu¡C + +[2001/09/08] wd2pal.c sob2pal.c Âà´«¦n¤Í¦W³æµ{¦¡¡C + +[2001/09/09] talk.c §Ö³tÁô¨¡C + brd2gem.c Âà´«¬ÝªO¤ÀÃþ¨ìºëµØ°Ï¡C + board.c favor.c vote.c ¬ÝªO¦Cªí¬ÝªO¤ÀÃþ¥[ÃC¦â¡C + talk.c bmw.c pal.c struct.h ×¥¿Âê©w¦^¤ô²y§PÂ_¤£¥¿½Tªº°ÝÃD¡C + +[2001/09/10] config.h board.c xover.c maple.p ²Ä¤@¦¸¶i¤J¤å³¹¦Cªí¡A§â´å¼Ð©ñ¦b²Ä¤@½g¥¼Åª¡C + config.h board.c ¬ÝªO¦Cªí¦Û°Ê¸õ¥h¤U¤@Ó¥¼Åª¬ÝªO¡C + menu.c Select Favorite everywhere¡C + +[2001/09/11] edit.c @edit.hlp etc/model ½s¿è¤å³¹®É´¡¤J½d¥»ºëÆF¡C + +[2001/09/12] struct.h board.c favor.c acct.c «í¬°·s¤å³¹¼Ò¦¡¡C + talk.c menu.c maple.p Áô¨±Kªk¡C + +[2001/09/13] board.c talk.c xover.c ×¥¿·j´M®É¤£·|²M°£³Ì«á¤@¦æªº°ÝÃD¡C + +[2001/09/15] struct.h acct.c bbsd.c talk.c §â realname ©M username ªºªø«×§ì¥X¨Ó define¡C + wd2mf.c §Úªº³Ì·RÂà´«µ{¦¡¡C + +[2001/09/17] gem.c ×¥¿ºëµØ°Ï¬å¥Ø¿ý»~¬åªº°ÝÃD¡C + +[2001/09/22] talk.c maple.p menu.c cache.c ¥[¤J¿ï¾Ü Talk ¥\¯à¡C + acct.c User/Info ´«ª©±¡C + admutil.c ¯S®í·j´M«á¥i¥H×§ï¸Ó¨Ï¥ÎªÌ¡C + +[2001/09/23] talk.c ¿ï³æ¤Á´«¦©¾÷¡C + edit.c ×¥¿ SHOW_USER_IN_TEXT ¦b«·s½s¿è¤å³¹®Éªº bug¡C + wd2usr.c Âà´« habit¡C + pal.c ×¥¿¦b¬ÝªO¦n¤Í¦W³æ¤¤¥i¥H«ÂÐ¥[¤J¡C + config.h pal.c menu.c maple.p ·s¼W¯S§O¦W³æªº¥\¯à¡C + pal.c aloha.c @pal.hlp @aloha.hlp ¦b¦n¤Í/¤W¯¸¦W³æ¤¤¥i¥H±H«H/¤ô²y¡C + maple/*.c xyz.c modes.h ²Î¤@¦r¦ê¬°¡u¤ô²y¡v¡C + +[2001/09/24] bbsd.c fb2usr.c sob2usr.c wd2usr.c §ïÅÜÓ¤HºëµØ°Ï¬[ºc¨Ó´î¤Ö¥Ø¿ýӼơC + modeh.h ×¥¿ mode ©M type ¹ïÀ³¿ù»~¡C + bbsd.c etc/mboxgem.over ÀˬdÓ¤HºëµØ°Ï¬O§_¹L¤j¡C + +[2001/09/24] gem.c post.c @gem.hlp @board.hlp §ï¼gºëµØ°Ï¡G + ×¥¿¤@¯ë¨Ï¥ÎªÌ¦b«DªO¥D¬ÝªOºëµØ°Ï¤£¯à gem_copy()¡C + Åý©Ò¦³¨Ï¥ÎªÌ¦bºëµØ°Ï¥i¥H½s¿è¤å³¹(¤£¯àÀx¦s)¡C + ¤pªO¥D¥i¥H¬Ý¨£¦Û¤vºÞÁҰϤ¤ªº¨î¯Å¥Ø¿ý¦WºÙ¡C + ×¥¿¸ó°Ï«þ¨©¿ïªþ¥[ÀÉ®×·|¥¢±Ñ¡C + ¨î gem_gather() ¤@©wn¥ý©wÁã¡A¥H§K¼È¦sÓ¤HºëµØ°Ï¦^¦¬µ©¤Ó¦h¡C + ·s¼W post_copy() ¦¬¿ý¬ÝªO¤¤¤å³¹¨ìºëµØ°Ï¡C + +[2001/09/26] vote.c ´£¨Ñ¥ß§Y¶}²¼¿ï¶µ¡C + jcee.c ×¥¿¥u¿é¤J©m¦W¬d¸ß®É¿ù»~ªº°ÝÃD¡C + +[2001/09/27] util/tran/*.c ¸É¤Wº|±¼ªº closedir()¡C + src/Makefile bin/install.sh §ï¼g¡C + xchatd.c §ïµ½ Mud-like «ü¥O·j´M¡C + +[2001/09/28] config.h global.h struct.h song.c topsong.c @-topsong + LOG_SONG_USIES ºq¥»¨Ï¥Î²Îp¡C + global.h bbsd.c talk.c menu.c ×¥¿¯¸¤WÁ`¨Ï¥ÎªÌÅã¥Ü¤£¥¿½Tªº°ÝÃD¡C + +[2001/09/29] admutil.c ¸É¤Wº|±¼ªº closedir()¡C + board.c menu.c maple.p ¼W¥[×§ï¬ÝªO¿ï¶µ¡C + +[2001/10/01] topusr.c @-birthday ²Îp¥»¤é¹Ø¬P¡C + +[2001/10/02] reaper.c bquota.c crontab (reaper-vac.c bquota-vac.c) + §â¥®É/´»°²¥Îªº±b¸¹/«H¥ó²M°£µ{¦¡¾ã¦X¦¨¤@¤ä¡A¦Û°Ê§PÂ_¤é´Á¡C + talk.c ×¥¿ guest ¥i¥HÂǥѨϥΪ̦W³æ¶i¤J XZ_BMW¡C + talk.c ×¥¿¨Ï¥ÎªÌ¦W³æ±H«H«ÂÐÀˬdÅv¡C + +[2001/10/03] np2gem.c Napoleon Âà´«ºëµØ°Ïµ{¦¡¡C + +[2001/10/04] nine.c ×¥¿¤Ñ¦a¤E¤E·|¦Û¤vÀ°ª±®a¥XµPªº°ÝÃD¡C + account.c «·s¾ã²z½s±Æ¤@¤U¡C + +[2001/10/05] showACCT.c showBRD.c Åã¥Ü .ACCT .BRD¡C + acct.c ×§ï acct_show() ºX¼ÐÅã¥Ü¡C + gem.c ¨î©Ê¤å³¹¤£¯à³Q½Æ»s¶K¤W¡C + +[2001/10/11] dice.c ×¥¿Åã¥Ü¿²v©M¥[¿ú¤£¦X¡C + bbsd.c ¤j¤p¼g¨Ó·½³£¯à³Q¦¨¥\§P©w¬G¶m¡C + chessmj.c ×¥¿¥[¿ú¤£¹ïªº°ÝÃD¡C + bj.c ×¥¿¥i¥HµL¦¸ double¡B¹q¸£®³¨ì AA µP®Éªº§PÂ_¿ù»~¡C + +[2001/10/12] etc/tip §ï¤@¨Ç¤£¹ïªº¡C + edit.c ¥Î -- ¤À³Îñ¦WÀÉ¡A¤£¥²n¤»¦æ¡C + +[2001/10/13] song.c ÂIºq³Ì«á¤@¦æ¥[¤W <~Src~> ·Q¹ï <~Des~> »¡ <~Say~> (¬°WDªººq¥»³]p)¡C + +[2001/10/18] gem.c ºëµØ°Ï«þ¨©/§R°£³¡¤Àµ{¦¡§ïµ½¡A×¥¿«Ý§R°£¨÷©v¤U¦³¸ê®Æ¡B + ¬ÝªO¡B¨î¯Å¤å³¹®É·|µo¥ÍµL½a°j°éªº°ÝÃD¡C + +[2001/10/19] backup*.c ³Æ¥÷µ{¦¡¡C + +[2001/10/22] bar.c ×¥¿¿ù»~¡C + struct.h bbsd.c talk.c ¨Ï¥ÎªÌ¦W³æÅã¥Ü¹Ø¬P¡C + +[2001/10/23] pip_stuff.c ×¥¿¦¬Ã¬©u¤ñÁÉ¥[¿ú¤£¹ï¡C + gp.c YÄ~ÄòÀ£ª`¡Aµ¹¿ú·|¤£¹ï¡C + +[2001/10/24] bj.c ²ø®aÅã¥ÜÂI¼Æ¿ù»~¡C + etc/game/pip/badman/pic000 pip_fight.c ¾Ô°«×¦æ³õ´º¦a¹Ï¡C + +[2001/10/25] board.c @class.hlp ¨ÌªO¥D·j´M¬ÝªO¡C + mail.c «H½c¤å³¹«þ¨©¡C + +[2001/10/26] struct.h talk.c post.c transacct.c §â ACCT ¤¤ money/gold Äæ¦ì§ï¦¨ int¡C + post.c ×¥¿©Ø·¬¸¨¸±Ù¥\¯à¡C + src/util/backup/* ³Æ¥÷/³Æ¥÷«ì´_µ{¦¡¡C + +[2001/10/27] global.h bbsd.c menu.c talk.c ¯¸¤WÁ`¤H¼ÆÅã¥Ü×¥¿¡C + +[2001/10/30] pip_prac.c ½m²ß®É¿ï¨ú®ø¤@¼Ë·|¥[ÄݩʡC + +[2001/11/04] modes.h vote.c board.c maple.p ´£¨Ñ¦n¤Í¬ÝªOÄݩʡC + vote.c ×¥¿§ë²¼¤¤¤ß«ö PGDN PGUP ·|½¹LÀYªº°ÝÃD¡C + +[2001/11/05] camera.c ¤¹³\°ÊºA¬ÝªO¤ÀÃþ¤¤ÁÙ¦³¨÷©v¤ÀÃþ¡C + +[2001/11/10] aloha.c ×¥¿§R°£¤W¯¸³qª¾¦W³æ®É¡AY³Q§R°£ªº¨Ï¥ÎªÌ¤w¾D reaper ·|¶i¤JµL½a°j°éªº°ÝÃD¡C + +[2001/11/15] mail.c maple.p acct.c km.c §â±HÀɮתº¨ç¦¡µ¹¿W¥ß¥X¨Ó¡C + song.c Åý¨S¦³ <~Src~> ªººq¥»¤]¯à¥D°Ê¥[¤J <~Src~>¡C + +[2001/11/16] etc/re-reg global.h bbsd.c «·s»{ÃÒ³qª¾«H¡C + +[2001/11/20] config.h global.h mail.c bmw.c menu.c talk.c xover.c chat.c + topsong.c wd2mf.c ×¥¿¤@¨Ç #undef ®Éªº¤p¿ù»~¡C + acct.c ¯¸ªø¥i¥H©ñ¤ô¥[¨Ï¥ÎªÌ»{ÃÒÅv¡C + showACCT.c §ï¥¿¿ù»~ªºµ{¦¡¡C + +[2001/11/23] bmw.c ´«¤ô²y°O¿ý®æ¦¡¡C + @bmw.hlp bmw.c ¤ô²y¦Cªí¤¤¥i¿ï¾ÜÀx¦s¡A¤£¥²µ¥¦AÂ÷¯¸¡C + admutil.c ¯¸ªø¥þ¯¸¨Ï¥ÎªÌ/ªO¥D±H«H®É¡AY¿ï¾Ü¨ú®ø¡AÀɮפ£·|²M°£¡C + +[2001/11/24] talk.c ¨Ï¥ÎªÌ¦W³æ¤¤¤£¯à¥á¤ô²yµ¹Áô§Îªº¨Ï¥ÎªÌ¡C + talk.c ×¥¿¨Ï¥ÎªÌ¦W³æ¤¤¬Ý¨ìÁô§Îªº¨Ï¥ÎªÌ¤Î¤£¬O¦n¤Íªº¦n¤Í¡C + +[2001/11/25] post.c ¬ÝªO¤¤×§ï¤¤¤åªO¦W«á¡An§ó·sª©±¡C + vote.c ªO¥D¦b¨S¦³§ë²¼ªº¬ÝªOÁ|¦æ§ë²¼¡A¦ý¤£¿é¤J¼ÐÃD¡A·|µo¥Í¿ù»~¡C + +[2001/11/26] talk.c ×¥¿¼s¼½»~´Óªº°ÝÃD¡C + +[2001/12/08] acct.c newbrd.c §ï¥Î¸û«K§Qªº¬ÝªOÅv³]©w¡C + bank.c Àˬd¿ú¬O§_¬°tªº¡C + +[2001/12/09] pip_stuff.c ×¥¿¤pÂû³Æ¥÷Àx¦s/Ū¨ú·|¥¢±Ñ¡C + modes.h ×¥¿°ÊºA¬°¬d¸ß/½Í¤Ñ®É¤£·|¥X²{¹ï¶H id¡C + xover.c guest ¤£±oÂÇ every_Z ¶i¤J¤ô²y¦^ÅU¡C + xover.c menu.c talk.c bwboard.c chat.c ×¥¿ + ¶i§Úªº³Ì·R/¤ô²y¦^ÅU«á¥Î every_Z ¸õ¥h¨ä¥L¿ï³æ¦A¥X¨Ó·|µo¥Í¿ù»~¡C + +[2001/12/10] pip_basic.c ¬Ý playboy ®É¸oÄ^¬O¼W¥[¤£¬O´î¤Ö¡C + +[2001/12/17] acct.c board.c maple.p is_bm() ¨ç¦¡¾ã¦X¦b¤@°_¡C + gem.c ÅýºëµØ°Ï¤¤ [userA/userB ªº¦h¦ì¤pªO¥D¼Ò¦¡¤]¾A¥Î¡C + +[2001/12/21] bmtad.c ID ªø«×«ê¬° IDLEN ªº¨Ï¥ÎªÌµLªk¦¬¨Ó¦ÛInternetªº«H¥ó¡C + +[2001/12/22] pipstruct.h pip_menu.c pip_visio.c pip_quest.c etc/game/pip/quest/ ¹q¤lÂû¥ô°È¡C + +[2001/12/26] modes.h talk.c acct.c µo§b¥i¿é¤J²z¥Ñ¡C + +[2001/12/30] pip.h pip_fight.c pip_quest.c pip_item.c ×¥¿ bug ¤Î¼W¥[¥ô°È¡C + post.c @board.hlp mail.c maple.p ·s¼WÂà¿ý¬ÝªO¤å³¹µ¹¨Ï¥ÎªÌ¡A¨Ã»P mbox ¾ã¦X¦b¤@°_¡C + +[2002/01/04] bmw.c global.h ¦^¤ô²y®É¥i¥Î ^R ^T ±²°Ê¡C + +[2002/01/05] bmw.c Åý¦^¤ô²y®É¡A¦b¤W¤èªº¦^ÅU¦³½bÀYÀH¤ô²y²¾°Ê¦Ó°Ê¡C + wd2brd.c wd2gem.c wd2usr.c WD->M3 Âà´«µ{¦¡¥i¤@¦¸Âà´«³æ¤H©Î¥þ¯¸¡C + +[2002/01/07] util/uno/*.c ¥[¤W chdir(BBSHOME); ¥H§K¨S¦b BBSHOME ¤U°õ¦æ¡C + +[2002/01/08] global.h ¥[¤J«öÁä¹ïÀ³µù¸Ñ¡C + +[2002/01/13] xover.c ×¥¿Y¨ú®ø every_Z ¥H«á¤£¯à¦A¶i every_Z¡A + ¥H¤Î¥Î every_Z ±q XZ_ ¦^ menu ®É³Ì«á¤@¦æ¥¼¦^´_¡C + vote.c ×§ï§ë²¼¿ï¶µªº®ÉÔ·|¹w³]¥X²{ì¥ýªº¿ï¶µ¡C + maple.p mail.c post.c Åý¦Û¤v¥i¥H½s¿è¦Û¤v«H½cªº«Hªº¼ÐÃD¤Î¤º®e¡C + config.h post.c POST_PREFIX µoªí¤å³¹®É¿ï¾Ü¤å³¹¼ÐÃD¤ÀÃþ¡C + +[2002/01/14] post.c guest ¤£¯à¹ï¨ä¥L guest ªº¤å³¹¥[±K¡C + +[2002/01/17] struct.h vote.c pal.c maple.p ´£¨Ñ¨î¦W³æ§ë²¼¡C + acct.c §R°£¬ÝªO®É¶¶«K§R°£ gem/@/@Class ¤Uªº¬ÝªOºëµØ°Ï±¶®|¡C + +[2002/01/18] board.c Ben_Perm() ×§ï¡C + +[2002/01/20] acct.c POP3 »{ÃҮɡA¥[¤J¥D¾÷¦WºÙ pop3.xxx ªº³s½u¡C + +[2002/01/22] newbrd.c ¦b¨S¦³³s¸p®ÉÁ|¦æ³s¸p¡A¦ý¨ú®ø¡A·|µo¥Í¿ù»~¡C + wd2bmw.c WD->M3 Âà´«¤ô²y°O¿ý¡C + menu.c ×¥¿¾\Ū¯d¨¥ªO®É¡A¶½XÅã¥Ü¿ù»~¤ÎY«ê¦³ 5n ½g®É·|¦h¨q¤@¶ªÅ¥Õ¡C + +[2002/01/23] board.c favor.c ¤£ºÞ¦³µL UFO_BRDPOST¡A¤@·§§ó·s¬ÝªOª¬ºA¡A¥H§K¥¼Åª¿O¤£·|«G¡C + acct.c XFile ¤À¤GÄæ¡A¨Ï¥i¥H½s¿è¤ñ¸û¦hÀɮסC + acct.c edit.c ¤TÓñ¦WÀÉÀɮפÀ¶}¡C + +[2002/01/24] xover.c ¦b³Ì«á¤@¶«ö KEY_PGDN ¥i½¨ì³Ì«e±¡C + +[2002/01/25] config.h bmtad.c HOST_ALIAS §ì¥X¨Ó define¡C + mail.c ¯¸¤º internet mail ®É·|ÄdºI±H«H¨ì¥»¯¸ªº¡C + +[2002/01/26] config.h global.h credit.c menu.c HAVE_CREDIT ´£¨Ñ°O±b¥»¥\¯à¡C + mail.c ½Õ¾ã«H½cª©±¨Ï©M¨ä¥L XZ_ ª©±¬Û¦P¡C + admutil.c ¥þ¯¸/ªO¥D³q§iµ{¦¡×¥¿¡C + wd2pip.c Âà´«¹q¤lÂûµ{¦¡¡C + wd2list.c Âà´«¯S®í¦W³æµ{¦¡¡C + global.h bbsd.c maple.p menu.c bmw.c ¤ô²yÂsÄý¬É±¡C + +[2002/01/27] topgem.c ¤£Àˬd¯µ±K¬ÝªO¡C + topusr.c ª©±×¥¿¡C + +[2002/01/29] stock-open.c crontab ¨úªÑ¥«¸ê®Æ¡C + enews.c menu.c global.h struch.h enews-open.c run/kimo/* crontab ´£¨Ñ¹q¤l³ø¥\¯à¡C + +[2002/01/30] mail.c post.c global.h @mbox.hlp @board.hlp ²Î¤@¦b post/mbox ¤¤ + ³£¬O¤p¼g x Âà¬ÝªO¡A¤j¼g X Âà¨Ï¥ÎªÌ¡C + xover.c YµL¿ï Tag ®É¡AAskTag ¤£°Ý°ÝÃD¡C + +[2002/02/17] config.h bbsd.c mail.c OVERDUE_MAILDEL Àˬd¹L´Á«H¥ó¡C + railway.c ¸¹½X§ï¬°ÅK¸ô¯¸ªº¨®¯¸¥N½X¡C + enews.c ×¥¿¶W¹L¤@¦æªº¼ÐÃD·|¸õ¦æ¡C + config.h pipstruct.h pip_menu.c pip_pk.c cache.c maple.p ¹q¤lÂû PK ¹ï¾Ô¡C + +[2002/02/27] mail.c ¥´¥]¬ÝªO¤å³¹¡C + +[2002/03/01] visio.c Åý ESC + * + s µ¥±±¨î½X¦b¤å³¹½s¿è/¾\Ū¤]¾A¥Î¡C + config.h post.c board.c HAVE_BUCKET ´£¨Ñ¬ÝªO¤ô±í¥\¯à¡C + bank.c Âà±b¤]¥i¥HÂàª÷¹ô¡C + menu.c ¥D¿ï³æ¾\Ū¬ÝªO¡C + +[2002/03/02] board.c ×¥¿¬Y¨ÇÁôÂêO·|³Q¬Ý¨£ªº°ÝÃD¡C + +[2002/03/05] post.c ×¥¿Âà¹F¤å³¹¦^«H½c¡A¤å³¹¸Ì±¼ÊºÙ¿ù»~¡C + xover.c Á×§K every_U ¶i¤J¤Ó¦h¼h¥H¤Î×¥¿¬Y¨ÇÂ_½u°ÝÃD¡C + menu.c xover.c ¿ï³æ¯S®íÁäµ{¦¡§ó·s¡C + +[2002/03/07] config.h hdr.h @board.hlp post.c HAVE_LABELMARK ¬ÝªO¤å³¹¥[«Ý¬å¼Ð°O¥\¯à¡C + +[2002/03/08] post.c ×¥¿¥Ñ every_Z «Âжi¤J¦ê±µ¼Ò¦¡/·s»D¾\Ū¡AÂ÷¶}·|µo¥Í¿ù»~¡C + +[2002/03/10] talk.c Áô§Îªº¤H¦b talk ®É¤£³Qª¾¹D©M½Ö talk¡C + +[2002/03/14] talk.c bwboard.c chat.c ½Í¤Ñ/²á¤Ñ/¤U´Ñ®É«ö Ctrl+Z ¦^¨Ó«á¿Ã¹õ¤£·|«ì´_¡C + +[2002/03/16] config.h talk.c visio.c bbsd.c bguard.c DETAIL_IDLETIME ®É±`§ó·s¶¢¸m®É¶¡¡C + bbsd.c §ó§ï¬G¶m§P©wµ{¦¡ + +[2002/03/21] talk.c bmw.c maple.p post.c pal.c aloha.c §ó·s can_override()¡C + +[2002/03/25] shm.c cache.c maple.p account.c mailtoall.c bmtad.c bguard.c + pip_pk.c stock.c §â attach_shm() ¥Î lib/shm.c ¤¤ªº shm_new() ¨ú¥N¡C + +[2002/03/26] restoreacct.c ÁÙì³Æ¥÷ªº .ACCT¡C + +[2002/04/01] poststat.c ×¥¿¥»¶g/¥»¤ë/¥»¦~ªº¤Q¤j¸ÜÃDµLªkÅã¥Ü¡C + +[2002/04/02] mail.c ×¥¿¸s²Õ±H«H¦pªG¦¬«H¤H¤Ó¦hªº¸Ü·|±¾±¼¡C + +[2002/04/05] song.c ¦bÂIºq®É¡A¶i¤J¬Ý§¹ºq³æ¦A¥X¨Ó«á¡A©³³¡ªº´£¥Ü°T®§·|®ø¥¢¡C + board.c ¬ÝªO«e«ö v/V ©ó .BRD ²Ä¤@ÓªOµL®Ä¡C + +[2002/04/10] bmw.c maple.p post.c pal.c talk.c aloha.c ©Ò¦³ xo_write() ³£¾ã¦X°_¨Ó¡C + xyz.c BBSNET µ{¦¡×¥¿¡C + +[2002/04/15] menu.c mail.c §ï vs_head()¡C + +[2002/04/27] bbsmail.c Á×§K SIGSEGV¡C + +[2002/04/31] newbrd.c §â³s¸p°O¿ý²¾¨ì run/newbrd/ ¤U¡C + vote.c §â§ë²¼°O¿ý²¾¨ì brd/_/@/G*¡C + +[2002/05/02] newbrd.c @cosign.hlp ×§ï³s¸p¤º®e¡C + +[2002/05/04] board.c guest ¤£¯à±q¬ÝªO¦Cªí¥[¤J§Úªº³Ì·R¡C + +[2002/05/10] acct.c ¥i³]©w¨Ï¥ÎªÌ±b¸¹¡C + +[2002/05/14] setusr.c ¥i³]©w¨Ï¥ÎªÌ²ßºD¡C + ufo.h struct.h acct.c §â UFO ¿W¥ß¥X¨Ó¦¨¬° ufo.h¡C + acct.c ¥i³]©w¨Ï¥ÎªÌ²ßºD¡C + +[2002/05/23] liteon.c menu.c ·s¼W¶}¿O¹CÀ¸¡C + +[2002/05/29] mail.c @mbox.hlp «H¥ó³]©w¾\Ū°O¿ý¡C + +[2002/05/30] railway.c ·sª©µ{¦¡¡C + +[2002/05/31] talk.c ·sªº Talk µ{¦¡¡C + bbsnet.c ¿W¥ß©ó xyz.c¡C + visio.c save_foot() restore_foot() ×¥¿¡C + +[2002/06/01] innbbsd/Makefile bbslib.c bbslink.c receive_article.c ncmbbs.h ncmbbs.c innd/ncmperm.bbs + ´£¨Ñ NoCeM ¥\¯à¡C + +[2002/06/02] menu.c xyz.c etc/loveletter ´£¨Ñ±¡®Ñ²£¥Í¾¹¡C + config.h global.h board.c talk.c HAVE_BRDPAL ´£¨Ñ¬ÝªO¦n¤Í¥\¯à¡C + config.h ufo.h talk.c bmw.c @ulist.hlp HAVE_SUPERCLOAK ´£¨Ñ¶W¯ÅÁô§Î(µµÁô)¥\¯à¡C + config.h global.h post.c HAVE_UNANONYMOUS_BOARD ¤Ï°Î¦WªO¡C + +[2002/06/08] account.c ªÅÀɮפ£¦bªO¤W keeplog¡C + usies-sort.c ×¥¿¦pªG¨S¦³¤H¤W¯¸·|µo²{¿ù»~¡C + +[2002/06/11] post.c «Ý¬åªº¤å³¹¤£¯à mark¡C + config.h maple.p menu.c visio.c acct.c talk.c pal.c mine.c ²Î¤@®y¼Ð¬° (x, y)¡C + +[2002/06/12] post.c ×¥¿¦b¦ê±µ¼Ò¦¡¤¤ªO¥D copy ¤å³¹¨ìºëµØ°Ï¡A¦^¦ê±µ·|¿ù»~¡C + post.c ×¥¿¦b¦ê±µ¼Ò¦¡¤¤¾\ۤ峹 more() ®É¡AªO¥D«ö m ·|¥XÂñ¡C + etc/feast global.h menu.c bbsd.c ¿ï³æ feeter Åã¥Ü¸`¤é¡C + config.h mail.c post.c HAVE_DECORATE ªº³¡¤Àµ{¦¡§R°£¡C + mail.c ¥uÅýªO¥D§â¬ÝªO/ºëµØ°Ï¥´¥]¦^®a¡C + +[2002/06/13] check_newsfeeds.c Àˬd newsfeeds.bbs ¬O§_¦³¤£¦s¦bªº¬ÝªOÁÙÂà«Hªº¡C + +[2002/06/15] board.c favor.c ¤ÀÃþ¬ÝªO¤Î§Úªº³Ì·R³£¥i¥H¨Ï¥Î¦Û°Ê¸õ¥h¤U¤@Ó¥¼Åª¬ÝªO¥\¯à¡C + +[2002/06/15] talk.c t_pager() ©Ú¦¬¼s¼½ªºµ{¦¡×¥¿¡C + newbrd.c nbrd_browse() ÅýÂsÄý§ó¬yºZ¡C + +[2002/06/17] topusr.c ²Îp¥»¤ë¹Ø¬P¡C + +[2002/06/18] xover.c xo_forward() µ{¦¡×¥¿¡C + +[2002/06/19] bbsd.c ×¥¿ multi-login ½ð¨ì¦Û¤v¥i¥H«½Æ¬~¿ú¡C + +[2002/06/21] fb2usr.c sob2usr.c wd2usr.c Âà´«µ{¦¡n«Ø usr/_/_/MF ³o¥Ø¿ý¡C + mail.c ¾\Ū«H¥ó¨ì¤@¥b«ö d §R°£¶l¥ó¥H«án«·s¸ü¤J .DIR¡C + +[2002/06/23] stock.c µ{¦¡´«·s¡C + +[2002/07/02] camera.c µ{¦¡×¥¿¡C + +[2002/07/03] mail.c m_internet() ª©±§ó°Ê¡C + visio.c bmw.c §â¦^¤ô²y·h¥h³Ì¤W±¤@¦æ¡C + +[2002/07/04] gem.c ºëµØ°Ï§R°£®Én½T»{¡C + gem-index.c µ{¦¡×¥¿¡C + src/Makefile ×¥¿¦³¨Ç OS ·|¥X²{»yªk¿ù»~ªº°ÝÃD¡C + *.h *.c LINUX ¤U sys/time.h ´«¦¨ time.h¡C + wd2gem.c wd2usr.c ×¥¿Âà´«¹LªººëµØ°Ï©MºëµØ°Ï¯Á¤Þ/²§°Ê½Ä¬ðªº°ÝÃD¡C + +[2002/07/08] menu.c pad_draw() ×¥¿·|Â_½uªº°ÝÃD¡C + +[2002/07/12] bbsnet.c BBSNET ¤ä´© port ¤£¬O 23 ªº telnet¡C + classtable.c ¥\½Òªí¥\¯à¥[±j¡C + +[2002/07/13] menu.c vs_head() µ{¦¡×¥¿¡C + railway.c ×¥¿§ì¤£¨ìºô¶·|¶i¤JµL½a°j°éªº°ÝÃD¡C + +[2002/07/16] bank.c ¶R§¹Åv·|´£¥Ü«·s¤W¯¸¦r²´¡AÁ×§K¨Ï¥ÎªÌ¤@ª½«ÂжRÅv¡C + cache.c talk.c µµÁô©ó§@ªÌ½u¤W¤Î¬d¸ß®É¤]¬Ý¤£¨£¡C + +[2002/07/18] bbsnet.c BBSNET ¥[¤J°O¿ý¡C + board.c gem/@/@class.hlp ·s¼W Zap ±¼¥þ³¡¬ÝªOªº¥\¯à¡C + talk.c ¨Ï¥ÎªÌ¦W³æ¬Ý¤£¨ìªO¤Íªº¬G¶m¡C + talk.c ©MÁô§Î¤H Talk ¤£¦b°ÊºA¤¤Åã¥Ü¡C + +[2002/07/20] bank.c ×¥¿¶×¿ú¦³ bug ªº°ÝÃD¡C + enews.c enews-open.c run/kimo/L ©_¼¯·s»D·s¼W¥ð¶¢Ãþ¡C + +[2002/07/21] post.c Åý¤@¯ë¨Ï¥ÎªÌ¤]¯à¬Ý¨ì¶iªOµe±ªº ANSI ½X + +[2002/07/25] etc/webx.conf.cwb ®ð¶H³ø¾É¡C + newbrd.c struct.h @cosign.hlp ·s¼W§@ªÌ¬d¸ß/³]©w¤Î³s¸p³]©wªº¥\¯à¡C + +[2002/07/26] railway.c ×¥¿·|¯d¤U´Ý¾lÀɮתº°ÝÃD¡C + railway.c ×¥¿¿ï³Ì«á¤@¦æªº¯¸®É·|Â_½u¡C + bbcall.c dreye.c enew.c fortune.c ¿ù¦rq¥¿¡C + mail.c ¯¸ªø¥i¬Ý guest ªº«H½c¡C + acct.c newbrd.c ¶}·sªO³s¸p®ÉnÀˬd¬ÝªOªO¦W¬O§_¦Xªk¡C + +[2002/07/28] km.c ¹CÀ¸¦¨¥\©Î¥¢±Ñ³£¥i±µÃö¡C + +[2002/07/30] check_newsfeeds.c Àˬd newsfeeds.bbs ¤¤¬O§_¦³¥¼Âà«Hªº¬ÝªO¡C + +[2002/08/05] bwboard.c ·s¼Wx´Ñ/·t´Ñ¹CÀ¸¡C + +[2002/08/06] show_id_in_USR.c ¥i¥H·j´M¬Y id ¦b .USR ¤¤ªº userno¡C + +[2002/08/07] acct.c ×¥¿ 0Admin/QSetBoard ®ÉY¬O edit currboard ·|¥¢±Ñ¡C + board.c ×¥¿¦b Boards ¬Ý§¹¬YªO¤å³¹«á¡A¦A±q¿ï³æ«ö s ¶i¥h¸ÓªO¡Aè¬Ý§¹ªº¤å³¹ÁÙ¬O¨S¬Ý§¹¡C + acct.c pop3.c POP3 »{ÃÒµ{¦¡×¥¿¡C + bbsd.c Åý ps ®É¯à¥X²{ bbsd ¬OþӨϥΪ̤Ψӷ½¡C + +[2002/08/08] post.c ¯¸ªø§ï¤å³¹¼ÐÃD®É¡A¤]¥i¶¶«K§ï¼ÊºÙ¡C + +[2002/08/09] etc/jcee/90.txt etc/jcee/91.txt jcee.c ´£¨Ñ 91 ¦~¤j¾ÇÁp©Û¬dº]¡C + +[2002/08/11] talk.c @ulist.hlp ¨Ï¥ÎªÌ¦W³æ¤Á´«¬G¶m/¤Í½Ë¡C + +[2002/08/12] src/innbbsd/Makefile innbbsd.h innbbsd.c ®³±¼ ADMINUSER¡C + menu.c ¯d¨¥ªO§ïÅܪ©±¡C + stock-open.c ×¥¿¬P´Á¤@¤£·|§ìªÑ¥«¦¬½L»ùªº°ÝÃD¡C + +[2002/08/13] config.h global.h maple.p edit.c post.c km.c bmtad.c mailpost.c ²¾°£ RANDOM_BANNER¡C + edit.c post.c km.c ¼W¥[¨ç¦¡ ve_banner()¡C + +[2002/08/14] modes.h struct.h bguard.c bmw.c cache.c talk.c visio.c BMW_COUNT µ{¦¡§ï¼g¡C + +[2002/08/16] talk.c @ulist.hlp ¨Ï¥ÎªÌ¦W³æ«ö L ÂsÄý¤ô²y¡C + bbsd.c ×¥¿ multi-login ®É¿ù»~ªº acct_save()¡C + +[2002/08/17] newbrd.c credit.c aloha.c ²Î¤@ vs_head() ªº¥Îªk¡C + bbs.h config.h global.h theme.h *.c §G´º¥DÃD¡C + +[2002/08/21] visio.c ×¥¿¦b¤W¯¸³~¤¤/ºëµØ°Ï idle ¹L¤[¡A·|¥X²{ status_foot¡C + +[2002/08/22] mailpost.c §â¤@¨Ç¨ç¦¡¥Î lib/ ¤¤ªº¥N±¼¡C + cache.c menu.c §â¶Ã¼Æ¿ï°ÊºA¬ÝªOªºµ{¦¡±q film_out() ²¾¨ì movie()¡C + +[2002/08/23] bmw.c theme.h ¦^¤ô²y®É«ö¤W¤UÁä§ï¦¨lastcmd¦Ó¤£¬O¦^«e«á¤@ӨϥΪ̡C + +[2002/08/28] bbsd.c ×¥¿¦b¶}ÀYµe±¹L¤[¥¼¿é¤J®É igetch ·|¥X²{ movie¡C + so/*.c pip.c ×¥¿¦P¤@®É¶¡¤£¦P±b¸¹¶Ã¼Æ¤]¬Û¦Pªº°ÝÃD¡C + chessmj.c ¹CÀ¸¤@¶}©l®É´N¥ý¦©¤@¥÷¥»ª÷¡A¥H§Kª±®aª½±µ¸õ¥X®É¨S¦©¨ì¿ú¡C + bbs.h proto.h so/*.c ×¥¿¶Ã¼Æµ{¦¡¡C + mail.c multi-send ®É¨ú®ø¦Ó·|³Q·í¦¨ MAIL_REPLIED¡C + +[2002/08/29] talk.c ¤W¯¸³qª¾/¨ó´M¡A§Y¨Ï§ÚÁô§Î¡A¹ï¤è¦pªG¦³¬Ý¨£Áô§Î¤]³qª¾¡C + bmw.c µµÁôªº¤H¥i¥H¥áµµÁôªº¤H¤ô²y¡C + menu.c ¿ï³æ¤p´T½Õ¾ã¡C + expire.c µ{¦¡×§ï¡C + talk.c bwboard.c cache.c ²á¤Ñ¹ï¶HÁô§Î®É¦b¨Ï¥ÎªÌ¦W³æ°ÊºA¤£³Q¬Ý¨ì¡C + bbsd.c ufo.h maple.p §â¤W¯¸¤£°e¨ó´M¨Ö¤J UFO_NOALOHA¡C + +[2002/08/30] cola2brd.c cola2gem.c Cola Âà´«µ{¦¡¡C + +[2002/08/31] src/maple/Makefile src/util/Makefile solaris ªº Makefile¡C + menu.c SunOS ¤U¨S¦³ getloadavg()¡C + global.h bank.c account.c Âà±b°O¿ý¡C + calendar.c menu.c ¸U¦~¾ä¡C + +[2002/09/01] src/maple/Makefile src/so/Makefile src/pip/Makefile §ï¼g¡C + doc/b_postfix FreeBSD ¤U postfix + bbsmail + mailpost ªº¨Ï¥Î»¡©ú¡C + talk.c pal_ship() µ{¦¡×¥¿¡C + +[2002/09/02] receive_article.c ×¥¿¨Ï NoCeM notice ¦³®Ä¡C + gem/?/* ·s¼W¤@¨Ç»¡©ú¤å¥ó¡C + +[2002/09/04] edit.c ¤º½X¿é¤J¤u¨ãµ{¦¡×¥¿¡C + rec_sync.c ·s¼W record «¾ã library¡C + +[2002/09/05] menu.c pushbox.c etc/game/pushbox.map ´£¨ÑÜ®wµf¹CÀ¸¡C + wd2*.c sob2*.c src/util/tran/Makefile ¤p§ï¼g¡C + talk.c ¤W¯¸³qª¾/¨ó´M¡AµµÁô¤£³qª¾¡C + +[2002/09/10] mag2*.c Magic Âà´«µ{¦¡¡C + make_new_USR.c µ{¦¡×¥¿¡C + etc/game/qkmj/* QKMJ µ{¦¡ª©¥»§ó·s¡C + +[2002/09/11] receive_article.c µ{¦¡×¥¿¡C + +[2002/09/14] pip.h pip_play.c pip_weapon.c gem.c railway.c µ{¦¡×¥¿¡C + +[2002/09/15] bar.c ×§ï§a¥xº¿²úªº¤¤¼ú¾÷²v¡C + +[2002/09/16] gem.c favor.c song.c vote.c µ{¦¡×¥¿¡C + +[2002/09/17] acct.c ×¥¿¥Î multi-login + User/Info ªº¤èªk¨Ó¨Ï¿ú¿¼W¡C + +[2002/09/29] nine.c ¤Ñ¦a¤[¤[µ{¦¡§ï¼g¡C + +[2002/10/09] marie.c etc/game/marie ¤pº¿²úµ{¦¡§ï¼g¡C + more.c ×¥¿¦b¤G¶¥H¤Wªº¤å³¹¤¤«ö KEY_DEL µo²{¿ù»~¡C + song.c µ{¦¡×¥¿¡C + +[2002/10/11] post.c ©Ø·¬¸¨¸±Ù¥i¦Û©w§R°£ªº§@ªÌ¼ÐÃD¡C + +[2002/10/14] marie.c ¤pº¿²ú¨îÁ`©ãª÷¡C + bmtad.c bbsmail.c ¾× html ®æ¦¡ªº«H¥ó¡C + +[2002/10/15] marie.c ×¥¿»ÊÁ´fÅU®É¤¤¼ú¶µ¥Ø·|¥X²{¿ù»~¡C + menu.c tetris.c ·s¼W«Xù´µ¤è¶ô¹CÀ¸¡C + +[2002/10/18] fortune.c ¹B¶Õ¹w´úºô¶¸ô®|×¥¿¡C + gem.c ¶i¤JªÅºëµØ°Ï¥i¥H°¨¤W¶K½Æ¡C + +[2002/10/21] acct.c ¼W¥[§R°£±b¸¹ªº¿ï¶µ¡C + +[2002/10/26] wd2usr.c wd2gem.c µ{¦¡×¥¿¡C + sob.h sob2brd.c sob2gem.c sob2usr.c SOB Âà´«µ{¦¡§ï¼g¡C + +[2002/10/27] post.c ×¥¿¥[±K¤å³¹¥i¥ô·NÂà¹F¨Ï¥ÎªÌ¡C + +[2002/10/28] post.c ×¥¿ guest ¥iÂǦ^§@ªÌ«H½c¨Ó±H«H¡C + mail.c ¸s²Õ¦^«Hµ{¦¡§ï¼g¡C + +[2002/10/29] gem.c ×¥¿ºëµØ°Ï§R°£¤å³¹§¹¥H«á¡A¥Ø¿ý¤º³Ñ 0 ½g¡A¿Ã¹õ·|¤£°®²b¡C + +[2002/10/31] post.c ×¥¿ guest ¥iÂà¹F¤å³¹¡C + src/pip/* ¹q¤lÂû¹CÀ¸·s¼W¤É¯Å¥ô°È¡BªZ¾¹¨t²Î¡C + enews.c ×¥¿©_¼¯·s»DÂà¿ý¨ú®ø¿Ã¹õ¿ù¶Ãªº°ÝÃD¡C + +[2002/11/01] board.c favor.c config.h ENHANCED_BSHM_UPDATE + ¬ÝªO¦Cªí§R°£/¼Ð°O¤å³¹¤£¦C¤J¥¼Åªªº¿O¡C + +[2002/11/02] bmw.c config.h ¤ô²y¦sÃÒ¡C + song.c ¨î¨C¤ÑÂIºq¦¸¼Æ¡C + +[2002/11/05] bguard.c bmw.c talk.c §âÀˬd¬O§_¯à¬Ý¨£¹ï¤èªºµ{¦¡¾ã²z¦b¤@°_¡C + +[2002/11/07] src/web/ html/ WEB-BBS ¥\¯à¡C + +[2002/11/11] bj.c chessmj.c fantan.c gp.c seven.c §ïÅܨúµPªº¶Ã¼Æµ{¦¡¡C + +[2002/11/13] showUSR.c µ{¦¡§ï¼g¡C + +[2002/11/14] Makefile ´£¨Ñ make update ªº«ü¥O¡C + +[2002/11/17] make_new_USR.c ×¥¿¿ù»~¡C + +[2002/11/22] xover.c vote.c §âÃþ XZ_ µ²ºcªº´å¼Ð²¾°Êµ{¦¡¾ã²z¦b¤@°_¡C + xover.c maple.p camera.c struct.h *.c §â help ¿W¥ß¥X film_out Åܦ¨¿ï³æ¡C + +[2002/11/26] favor.c ×¥¿ºëµØ°Ï±¶®|ªO¥DÅv¿ù»~ªº°ÝÃD¡C + +[2002/12/04] favor.c ·s¼W§Úªº³Ì·R¿ï¨ú¬ÝªO¥\¯à¡C + +[2002/12/05] menu.c ×¥¿ #define COLOR_HEADER ®É¡A¶l®t¨Ó«ö¹aªºÃC¦â·|¤£¹ï¡C + talk.c Y¦b Talk ®É«ö¤F¤@°ï¦L¤£¥X¨Óªº¦r¡A´N¤£¼g¶i talk-log¡C + *.c mail_self() ¦h¤@ӰѼơA§ó¤è«K¨Ï¥Î¡C + talk.c §â mail_self() ¾ã¦X¶i talk_save()¡C + talk.c ×¥¿ Talk ®É³Ì«á¤@¥y¸Ü¤£·|³Q°O¦b½Í¤Ñ°O¿ý¤¤¡C + talk.c ×¥¿ Talk ®É·í´å¼Ð¦A¹ï¤è°Ï°ì®É«ö¤UCtrl+k·|µo¥Í¿ù»~¡C + +[2002/12/06] board.c favor.c theme.h maple.p Åý¬ÝªO¦Cªí¤¤ªº¯µ±KªO¡B¦n¤ÍªO¡BZAP ªO¼Ð¥Ü²M·¡¡C + +[2002/12/09] enews-open.c §ì©_¼¯·s»Dªºµ{¦¡§ó·s¡C + +[2002/12/10] pal.c ½s¿èªO¤Í¦W³æ®É¡A¤Þ¤J¦n¤Í¦W³æ¡C + +[2002/12/13] global.h struct.h account.c board.c ¥i¥H zap ±¼¤ÀÃþ¡C + +[2002/12/15] account.c µ{¦¡§ï¼g¡C + +[2002/12/16] bbslib.c ¦pªG nodelist.bbs ¸Ì±¶ñªº¤£¬O¥¿¸Ñ¡A¹ï¤èÁÙ¬O¥i¥H access¡C + mail.c ×§ï¸s²Õ±H«H®É¡AY¦W³æ¹L¦h·|Â_½u¡C + +[2002/12/18] song.c µ{¦¡×¥¿¡C + bbslink.c news ¿é¥X RFC 2045¡C + +[2002/12/21] dns_ident.c dl_lib.c µ{¦¡§ó·s¡C + +[2002/12/22] *.c Query µ{¦¡§ó·s¡C + +[2002/12/24] struct.h acct.c bbsd.c §â±K½Xªø«×²Î¤@©w¬° 8¡C + edit.c ¦]Â_½u¥¼§¹¦¨ªº¤å³¹¥i¿ï¾Ü¥á¥h¼È¦sÀɩΫH½c¡C + +[2002/12/26] post.c ¦b¦ê±µ¼Ò¦¡¤U edit ¤å³¹§¹¡AÀ³¸Ó¥X²{ xpost_head() ¦Ó¤£¬O post_head()¡C + +[2002/12/27] xover.c post.hlp gem.hlp ²¾°£ Z-modem ¤U¸ü¥\¯à¡C + fortune.c menu.c ²¾°£¹B¶Õ¹w´ú¥\¯à¡C + bbcall.c menu.c ²¾°£ BBCall ¥\¯à¡C + emailpage.c mail.c bmtad.c ²¾°£ emailpage ¥\¯à¡C + config.h edit.c §R°£ HAVE_ORIGIN¡C + config.h km.c edit.c talk.c §R°£ REALINFO¡C + cache.c µ{¦¡§ó·s¡C + bingo.c µ{¦¡§ó·s¡C + +[2002/12/28] camera.c menu.c config.h µ{¦¡§ó·s¡C + +[2002/12/30] camera.c cache.c str_rle.c fshm ¤£À£ÁY¡C + +[2003/01/01] talk.c ×¥¿¯¸ªø°µ¦n¤Í¼s¼½®É¥i¯à·|»~´Óªº°ÝÃD¡C + ufo.h acct.c §â²ßºDªºªø«×§ì¥X¨Ó define ¦¨ NUMUFOS¡C + bmta.sh ¤ÀªR bmta.log ªº³s½u¦¸¼Æ¡C + +[2003/01/02] pip_fight.c ×¥¿¦³¨Ç§Þ¯à¾Ç¨ì¥H«áµLªk¨Ï¥Îªº°ÝÃD¡C + +[2003/01/03] src/innbbsd/*.c µ{¦¡ºë²¡C + *.c ²¾°£ HAVE_NOFORWARD¡A¨Ã§â NUMATTRS ©M STR_BATTR §ì¥X¨Ó©w¸q¡C + *.c ½Õ¾ã¬Y¨Ç¯¸ªøÅv¡C + +[2003/01/10] topgem.c µ{¦¡§ó·s¡C + +[2003/01/11] more.c µ{¦¡´«·s¡A×¥¿¤W±²¤@¦æ¿ù»~¡B·j´M¦r¦ê·|§ä¤£¨ìªº°ÝÃD¡C + innbbsd/* Âà«Hµ{¦¡§ïª©¡C + aloha.c newbrd.c µ{¦¡§ó·s¡C + xover.c ×¥¿¦b help ®É«ö KEY_HOME ·|Â_½uªº°ÝÃD¡C + +[2003/01/12] bmw.c ×¥¿¤ô²yÀx¦sÅܦ¨¬Û¤Ï¹ï¸Üªº°ÝÃD¡C + +[2003/01/13] song.c °Î¦WÂIºq¤]ºâ¤J¨C¤é¥u¯àÂI¤Tº¡C + +[2003/01/15] innbbsd/* µ{¦¡§ó·s¡C + xover.c ×¥¿ every_Z ¶i¤J¬ÝªO®É¥i¯à³y¦¨¤å³¹¤wŪ/¥¼Åª¿ù»~¡C + +[2003/01/19] admutil.c ¯¸ªø«¸m¨t²Î®ÉÀx¦s¬ÝªO¾\Ū°O¿ý¡C + modes.h menu.c ®³±¼ M_CLASS¡C + +[2003/01/23] railway.c ÀH¥xÅKªº®æ¦¡§ó·s¡C + +[2003/02/07] enews.c ©_¼¯·s»DÂà±H¨ì¯¸¥~¡C + +[2003/02/08] edit.c ¨î¼È¦sÀɤj¤p¡C + marie.c °§C¤j¤pº¿²ú¹CÀ¸ªº´Á±æÈ¡C + dice.c °§C¨gÂY»ë¤l¹CÀ¸ªº´Á±æÈ¡C + xover.c enews.c mail.c ¾ã²z DENYMAIL ªºµ{¦¡¡C + +[2003/02/11] cola.h cola2brd.c cola2gem.c cola2usr.c ColaBBS Âà´«µ{¦¡¡C + +[2003/02/19] innbbsd/* innd/newsfeeds.bbs etc/b2g_table etc/g2b_table ²ÁcÅéÂà«H¡C + +[2003/02/21] cola2post.c Cola ¬ÝªO¤å³¹®æ¦¡Âà´«¡C + +[2003/02/23] post.c ×¥¿Âà¿ý¤å³¹¨ì¤£°µ¼öªù¸ÜÃD²Îpªº¬ÝªO¡A³o½g³QÂà¿ýªº¤å³¹¤´µM·|³Q¦C¤J²Îp¡C + acct.c ¥u¦³ PERM_SYSOP ¯àÅܧó¨ä¥L¯¸°Èªº±K½X¡C + +[2003/02/25] cola2gem.c sob2gem.c wd2gem.c ×¥¿¤l¥Ø¿ýÂà´«¥¢±Ñªº°ÝÃD¡C + +[2003/03/02] brdmail.c ¥Ñ Internet ±H«Hµ¹ BBS ¯¸¤º¬ÝªO¡C + +[2003/03/03] counter.c ¾ú¥vy¸ñ¡C + +[2003/03/04] enews-open.c ©_¼¯·s»D¼ÐÃD¤Óªø®É·|¦³¿ù»~¡C + song.c ºq¥»¥[±K®É¤£¯àÂI¨ºººq¡C + +[2003/03/05] edit.c ñ¦WÀɤ]ºâ¤Þ¨¥ªø«×¡C + +[2003/03/06] song.c global.h ºq¥»§ï©ñ¦b ktv ªOºëµØ°Ï¡C + gem-index.c ºëµØ°Ï¯Á¤Þ/²§°Ê ¥iÁôÂáC + +[2003/03/07] gem.c ×¥¿ºëµØ°Ï½Æ»sªº³¡¤Àµ{¦¡¡C + hdr.h *.c ¤£¥Î lazy_delete¡Arec_del() ®³±¼¤@ÓÄæ¦ì¡APOST_DELETE ²¾°£¡C + hdr.h post.c POST_LABEL ´«½s¸¹¡C + *.c §ó·s record ®ÉnÀˬd¡C + rec_article.c ¦¬¨ì cancel ¤å³¹ª½±µ§R°£¡A¤£ lazy_delete¡C + hdr.h *.c POST_CANCEL ²¾°£¡C + +[2003/03/10] vote.c ¤À¨¤£¯à§ë²¼¡C + rec_loc.c bmw.c aloha.c °Ï¬q§R°£µ{¦¡×¥¿¡C + +[2003/03/15] edit.c Show ñ¦WÀɮɡA«e¨âÓ¥u¯à¨q¥X MAXSIGLINES-1 ¦æ¡C + +[2003/03/23] bmtad.c ±H«Hµ¹¬ÝªO¡C + mail.c mail ¿é¥X RFC 2045¡C + +[2003/03/25] hdr_stamp.c post.c enews.c gem.c hdr_stamp() ·s¼W HDR_COPY ³oÓ token¡C + bank.c Âà±bµ{¦¡×¥¿¡C + post.c outgo.c Á×§K¨S¦³ nick ®É·|³y¦¨Âà«H¥¢±Ñ¡C + expire.c µ{¦¡¤p§ïª©¡C + +[2003/03/26] admutil.c ×¥¿¥þ¯¸/ªO¥D³q§i³¡¤Àµ{¦¡¡A¨Ã¥[¤W¶l®t¨Ó«ö¹a¡C + +[4~[2003/03/27] post.c mail.c §ï¼ÐÃD®ÉY¨S¦³ÅܰʡA«h¤£°Ý Y/N¡C + more.c µ{¦¡×¥¿¡C + +[2003/03/30] rec_article.c ×¥¿¿é¤J RFC 2047 »P ANSI ±±¨î½Xªº°ÝÃD¡C + +[2003/03/31] pip_race.c ¦¬Ã¬©u²i¶¹¤ñÁÉ·s¼Wµæ¦â¿ï¾Ü¡C + +[2003/04/01] gem.c ºëµØ°Ïªº²Å¸¹¤À²M·¡¤@ÂI¡C + +[2003/04/07] post.c mail.c hdr_out() ±q mail.c ·h¥h post.c¡C + post.c §R°£ getsubject()¡C + rec_put.c µ{¦¡×§ï¡C + +[2003/04/08] xover.c Ãþ XZ_* µ²ºcªº´å¼Ð²¾°Êµ{¦¡×§ï¡C + +[2003/04/11] rfc2047.c dao.p bbslink.c mail.c news/mail ¿é¥X RFC 2047¡C + +[2003/04/15] inntobbs.c inntobbs.h rec_article.c ¨S¥Î¨ìªº HEADER ´N¤£¨ú¤F¡C + +[2003/04/16] board.c ²Ä¤G¦¸¶i¤J board_main ®É¡An free ±¼ class_img¡C + +[2003/04/22] talk.c config.h theme.h ±N #ndef ADV_ULIST ªºµ{¦¡§R°£¡C + aloha.c bmw.c pal.c xxxx_body() ²Î¤@©M¨ä¥L®æ¦¡¤@¼Ë¡C + talk.c ulist_body() ²Î¤@©M¨ä¥L®æ¦¡¤@¼Ë¡A¨Ã¿W¥ß¥X ulist_item¡C + railway.c ¥xÅKºô¶®æ¦¡ÅܰʡC + +[2003/04/23] post.c bmtad.c topgem.c bwboard.c ×§ï¤@¤U¨Ï²Å¦X gcc 3.2.2¡C + +[2003/04/26] talk.c ulist_cb[] µ{¦¡×¥¿¡C + xover.c ×¥¿©ó help ·s¼W»¡©ú®É¡AY¶W¹L¤@¶·|µo¥Í¿ù»~¡C + +[2003/05/03] edit.c ª`µ¤å¹LÂo¡C + +[2003/05/04] Makefile ¥þ³¡²Î¤@¼gªk¡C + +[2003/05/10] str_ansi.c bmtad.c rec_article.c bbsmail.c brdmail.c mailpost.c cola2post.c + §â strip_ansi ªºµ{¦¡²Î¤@¦b lib/¡C + cola2brd.c fb2brd.c mag2brd.c sob2brd.c wd2brd.c + Âà´«µ{¦¡³B²z¤å³¹¼ÐÃD®É¥[¤J strip_ansi¡C + mak_dirs.c bbsd.c cola2brd.c fb2brd.c mag2brd.c sob2brd.c wd2brd.c transacct.c + §â mak_links ªºµ{¦¡²Î¤@¦b lib/¡C + help.c xover.c xo_help() ·h¥h so/¡C + +[2003/05/11] innbbsd ³¡¤Àµ{¦¡§ï¼g¡C + +[2003/05/13] bmtad.c bbsmail.c ¾×±¼«D big5 ªº«H¥ó¡C + +[2003/05/14] config.h visio.c bguard.c TIME_KICKER ¬O§_¦Û°Êñ°h idle ¹L¤[ªº¨Ï¥ÎªÌ¡C + bbs.h Makefile ®³±¼ REDHAT ªº³¡¤À¡C + +[2003/05/15] modes.h board.c post.c xover.c ±N STAT_BOARD »P STAT_BM ¤ÀÂ÷¥X¨Ó¡C + post.c xover.c ¯¸ªøµLªk¬Ý¨ì¥[±K¤å³¹¡C + +[2003/05/24] showDIR.c ¨q¥X .DIR ªº¸ê°T¡C + +[2003/05/25] board.c ×¥¿¿ù»~ªº¬ÝªO¾\Ū°O¿ý·|·í¦b¤W¯¸µe±¡C + mail.c ±H¥Xªº«HªºÀÉÀY From Äæ¦ì¥[¤W real name Äæ¦ì¡C + +[2003/05/26] lottery.c lottery-open.c etc/game/lottery.main etc/game/lottery.rule ¼Ö³z¹CÀ¸¡C + +[2003/05/27] *.c *.h ¤ä´©¶W¹L 24 ¦Cªø¿Ã¹õªºµe±¡C + util/Makefile §ï¼g¡C + +[2003/05/28] post.c ¦ê¦C/·s»Dµ{¦¡§ï¼g¡C + +[2003/06/04] config.h bmtad.c bbsmail.c mail.c §â MYCHARSET §ì¥X¨Ó©w¸q¡C + +[2003/06/05] cache.c post.c utmp_get() µ{¦¡×¥¿¡C + hdr.h gem.c xover.c song.c camera.c gem-index.c gem-check.c §R°£ GEM_HTTP ¤Î GEM_URL¡C + +[2003/06/06] innbbsd/* Âà«Hµ{¦¡×§ï¡C + +[2003/06/07] post.c mail.c maple.p §â tag ¼Ð * ªº§¤¼Ð±q (x, 8) ²¾¨ì (x, 6)¡C + config.h hdr.h post.c ¤å³¹µû¤À¥\¯à¡C + +[2003/06/11] global.h *.c ¨Ï¥Î¥þ°ìÅÜ¼Æ currbno ¨Ó¥N´À brd_bno(currboard)¡C + +[2003/06/13] rec_article.c «O¯d³Q cancel ªº¤å³¹©ó deleted ªO¡C + +[2003/06/18] global.h post.c edit.c ¨Ï¥Î¥þ°ìÅÜ¼Æ currbattr ±N battr ¿W¥ß¥X bbstate¡C + +[2003/06/19] bmw.c mail.c §R°£ bmw_choose() ªº¥\¯à¡C + bmw.c theme.h visio.c talk.c §ïÅܤô²y®æ¦¡¡C + +[2003/06/20] bmw.c visio.c ¦b reply ¤ô²y®É·|¨q¥X¤W¦¸¶Çµ¹³o¤Hªº¸Ü¡C + +[2003/06/27] global.h ufo.h visio.c more.c acct.c ²¾°£ UFO_COLOR¡C + +[2003/06/28] battr.h struct.h bbs.h acct.c ±N battr ¾ã²z¨ì battr.h¡C + bbslink.c ×¥¿ cmsg »Pn¬åªº¤å³¹ Message-ID ¬Û¦P·|³Q news server ©Úµ´ªº°ÝÃD¡C + rec_article.c brdmail.c bmtad.c ®³±¼ Âà«H¯¸: ¤Î Origin: ªº¤å³¹ÀÉÀY¡C + more.c ¤£°»´ú Âà«H¯¸: ¤Î Origin: ªº¤å³¹ÀÉÀY¡C + +[2003/06/30] struct.h acct.c board.c post.c gem.c vote.c newbrd.c tran/*brd.c account.c + ¼W¥[ BRD.class ¬ÝªO¤ÀÃþÄæ¦ì¡C + theme.h board.c §ì¥X ICON_(NO)TRAN_BRD ¨Ó©w¸q¡C + windtop.h windtop2usr.c windtop2brd.c WindTop Âà´«µ{¦¡¡C + +[2003/07/02] bbsd.c ¤¹³\ belong_list() ¤¤ªº desc ¥i¥H¦³ªÅ¥Õ¡C + +[2003/07/03] weather.sh ¤Ñ®ð¹w³ø¥[¤W more ÀÉÀY¡C + topusr.c ²Îp©Ê§O¡C + +[2003/07/04] bbslink.c ±q¤W¦¸¤¤Â_³BÄ~Äò°e«H¡C + admutil.c ¼f§¹µù¥U³æ³q¹L¡A·|¨Ï·í®É¦b½u¤Wªº¨Ï¥ÎªÌ«G°_¶l®t¨Ó«ö¹a¡C + acct.c showACCT.c topusr.c §ïÅÜ sex Äæ¦ì¹ï©Ê§Oªº©w¸q¡A¼W¥[¤¤©Ê¡C + +[2003/07/05] struct.h ufo.h perm.h ±N PERM_DATALOCK PERM_COINLOCK UFO_BIFF + UFO_REJECT UFO_BIRTHDAY UFO_MQUOTA ¿W¥ß¥X¨Ó¦¨¬° UTMP.status¡C + ±N cuser.ufo ¤Î cutmp->ufo ¦P¨B¡C + +[2003/07/06] bbslink.c bbsnnrp.c ¤ä´©»Ýn±b¸¹/±K½Xªº news server¡C + talk.c bmw.c ¼s¼½µ{¦¡×¥¿¡C + +[2003/07/07] bhttpd.c ²©öªº Web-BBS¡C + +[2003/07/09] transbrd.c .BRD Âà´«µ{¦¡¡C + +[2003/07/13] ±N doc ´«¦¨ html ÀÉ¡C + +[2003/07/14] decode.ic §R°£¡C + mailpost.c µ{¦¡§ï¼g¡C + +[2003/07/15] tetris.c µ{¦¡§ï¼g¡C + +[2003/07/18] bmw.c ×¥¿Y¹ï¤è¤U¯¸¤F¡A¤ô²y¥i¯à·|¥á¿ù¤H¡C + board.c ¥þ°ì·j´M¥i¦P®É·j´M¼ÐÃD¡C + pal.c ¦n¤Í/¸s²Õ¦W³æ¼s¼½¡C + bbsnnrp.c ¤j´T§ï¼g¡C + +[2003/07/19] gem.c post.c mail.c edit.c vote.c ¼ÐÃD vget() ªø«×ªº×§ï¡C + admutil.c ¥þ¯¸¨Ï¥ÎªÌ/ªO¥D±H«Hµ{¦¡×§ï¡C + +[2003/07/20] hdr.h hdr_fpath.c gem.c §â GEM_EXTEND ªº¥\¯à²¾°£¡C + gem.c ×¥¿ªO¥D¥i¥H¦b¨ä¥LªO¨Ï¥Î gem_state¡C + +[2003/07/22] bmw.c »P¯S©w¹ï¶Hªº¤ô²y¦s¦Ü«H½c¡C + +[2003/07/23] dragon.c ±µÀs¹CÀ¸¡C + config.h window.c edit.c visio.c ÂÛ¥X¦¡µøµ¡¡C + etc/game/pip ¸É»ô¹q¤lÂûªº´¡¹Ï¡C + account.c Àˬd CH_MAX ¬O§_¤p©ó Class ¼Æ¶q¡C + +[2003/07/24] camera.c ¨t²Î¤å¥ó¦³¯Ê®É¡A·|¦Û°Ê¸É¤W³qª¾¡C + +[2003/07/25] account.c ¾ã²z .BRD ¤¤ªÅ¥ÕªºÄæ¦ì¡C + bmw.c visio.c Ctrl+T ¥i¥H¦^§OÁû¤ô²y¡C + +[2003/07/27] post.c manage.c ±NªO¥D¿ï³æ¾ã¦X¦b¤@°_¡C + bhttpd.c bshm µ{¦¡§ï¼g¡C + gemd.c ×¥¿¥i¥H¥Ñ gopher ¬Ý¯µ±KªOºëµØ°Ïªº°ÝÃD¡C + +[2003/07/28] bbsd.c mail.c global.h ±N etc/* ªºÀɮ׸ô®|¾ã²z¥X¨Ó FN_ETC_*¡C + +[2003/07/31] xover.c every_Z ×¥¿ÂÇµÛ ^Z ¸õ¥h§OªO¦A¦^³oªO®Éªº¿ù»~¡C + +[2003/08/01] bbsd.c ªø¿Ã¹õµ{¦¡×¥¿¡C + +[2003/08/03] Makefile make update Y¥X²{ error «h©¿²¤¡C + +[2003/08/07] pal.c ×¥¿ªO¤Í¦W³æ¤Þ¤J¦n¤Í¿ù»~¡C + +[2003/08/09] jcee.c etc/jcee/92.txt 92 ¦~¬dº]ªA°È¡C + +[2003/08/13] struct.h enews.c xover.c ²¾°£ MQ_UUENCODE¡C + struct.h mail.c ×¥¿«H¥ó¥´¥]®É Content-Type ¿ù»~¡C + +[2003/08/15] board.c ·j´M¤U¤@Ó¥¼Åª¬ÝªO¡C + rec_del.c µ{¦¡×¥¿¡C + +[2003/08/16] aloha.c ¥Î rec_del ¨Ó¨ú¥N rec_loc¡C + src/lib «·s¾ã²z¡A±N¨S¥Î¨ìªº§R°£¡C + bbsmail.c brdmail.c ¸Ñ½X quoted-printable/base64 ªº«H¥ó¡C + str_decode.c ×¥¿·í«H¥ó¤º¤å¬° QP ½s½X®É·|µo¥Í¿ù»~¡C + str_decode.c bbsmail.c brdmail.c bmtad.c ±N¨ú¥X charset ¤Î encode ªºµ{¦¡¶°¤¤¨ì lib¡C + +[2003/08/17] bmw.c µ{¦¡×¥¿¡C + +[2003/08/23] src/Makefile src/game/ ±N so/ ¤Uªº¹CÀ¸¤Îºô¸ôªA°È·h¨ì game/¡C + str_has.c acct.c board.c bmtad.c ªO¥D¦W³æµ{¦¡³¡¤À¾ã¨Ö¡C + edit.c ×¥¿Â²¤Æ½s¿è¾¹¡C + +[2003/08/24] todo.c etc/todo.welcome global.h menu.c ¦æ¨Æ¾ä¡C + +[2003/08/27] bbsnnrp.c ×¥¿·í host/active ¤£¦s¦b®É¡AµLªk unlock ªº°ÝÃD¡C + favor.c §Úªº³Ì·R·j´M¤U¤@Ó¥¼Åª¬ÝªO¡C + +[2003/08/29] stock.c µ{¦¡×¥¿¡C + +[2003/09/06] pal.c ¦n¤Í/ªO¤Í/¯S§O¦W³æ¥æ¤e¤Þ¥Î¡C + vote.c §ë²¼¨ì¤@¥b¡AªO¥D¥i¥H°½¬Ý¥Ø«e§ë²¼ª¬ªp¡C + +[2003/09/07] pal.c ¦n¤Í¦W³æ°Ï¬q§R°£¡C + config.h menu.c acct.c §R°£ HAVE_REPORT °O¿ý°£¿ùªºµ{¦¡¡C + visio.c ANSILINELEN µ{¦¡×¥¿¡C + +[2003/09/11] account.c admutil.c «¸m¨t²Î®É¤£°µ¼öªù¸ÜÃD²Îp¡C + +[2003/09/12] favor.c §Úªº³Ì·R°Ï¬q§R°£¡C + +[2003/09/13] bhttpd.c ´£¨Ñ email µoªí¤å³¹¡C + bguard.c talk.c ¯¸ªø kick ¨Ï¥ÎªÌ®ÉÀ³±N ushm->count ´î¤@¡C + +[2003/09/14] mail.c ¯¸°È«H½c¿ï ID ®É¥i¥H«öªÅ¥ÕÁä¦Û°Ê·j´M¡C + post.c ¥þ¤å·j´M¡C + +[2003/09/23] xpost.c post.c mbox.c ±N¦ê±µ·j´M¼Ò¦¡¾ã¦X¤J«H½c¡C + +[2003/09/26] bbsd.c mail.c ±N m_count() Àˬd«H½c¤w¸g¶W¹L¤Wªº³¡¤À²¾¨ì bbsd.c¡C + mail.c ±N¦^«Hªºµ{¦¡¾ã¨Ö¨ì do_mreply() ¸Ì±¡C + mail.c post.c §ï¼g mbox_browse() ¤Î post_browse()¡C + mail.c xpost.c ¦ê±µ¶l¥ó¤¤¥i¦^«H¡C + menu.c mail.c admutil.c ±N¿ï³æ¤¤·|¥Î¨ìªº¶l¥ó¿ï¶µ³£§ï¦W¬° m_xxxx()¡C + menu.c acct.c admutil.c ±N¿ï³æ¤¤·|¥Î¨ìªº¯¸°È¿ï¶µ³£§ï¦W¬° a_xxxx()¡C + +[2003/09/27] post.c gem.c ºëµØ°ÏÂà¿ý¨ì¬ÝªO¡BÂà¹F¨Ï¥ÎªÌ¡C + +[2003/09/28] bbsd.c §ï¼g tn_login()¡C + +[2003/09/29] ufo.h *.c ±N HAS_STATUS ¥¨¶°¾ã²z¥X¨Ó¡C + +[2003/10/01] xover.c bmw.c pal.c favor.c aloha.c post.c mail.c gem.c ±N°Ï¬q§R°£ªºµ{¦¡¾ã¦X¦b¤@°_¡C + +[2003/10/03] gem.c global.h backupgem.c restoregem.c ¼o°£ºëµØ°Ï¸ê·½¦^¦¬µ©ªº¥\¯à¡C + gem.c §ï¼gºëµØ°Ï§R°£ªºµ{¦¡¡C + xover.c post.c mail.c gem.c ±N¼ÐÅÒ§R°£ªºµ{¦¡¾ã¦X¦b¤@°_¡C + +[2003/10/04] edit.c post.c modes.h µo¤å¥[±K¦sÀÉ¡C + enews.c µ{¦¡×¥¿¡C + +[2003/10/08] gem.c ×¥¿¥[±K¤å³¹¥iÂÇ¥ÑºëµØ°Ïªþ¥[ÀɮרӰ½¬Ý¡C + +[2003/10/20] bhttpd.c ¤¹³\¨Ï¥ÎªÌµn¤J¡C + +[2003/11/09] edit.c ¶Ã¼Æ¿ï¾Üñ¦WÀÉ¡C + +[2003/11/10] stock.c stock-open.c ²¾°£ªÑ¥«¹CÀ¸¡C + +[2003/11/18] visio.c more.c edit.c etc/* °±¥Î ### %%% Åã¥Ü¨Ï¥Î¦WºÙ±±¨î½X¡A§ï¥Î **s ³oÃþ«¬ªº¡C + +[2003/11/22] dl_lib.c visio.c bbslink.c fileglue.c verbose.c ±N <varargs.h> §ï¥Î <stdarg.h>¡C + +[2003/11/23] more.c ×¥¿ more_line() ¦bè¦n 80 ¦r·|¦h¤@ªÅ¦æ¡C + struct.h edit.c more.c talk.c visio.c ±N¿Ã¹õ¼e«×³£²Î¤@¬° SCR_WIDTH¡C + +[2003/11/26] account.c ¶}²¼¥H«án²M°£¥i§ë²¼¦W³æ¡B¤w»â²¼°O¿ý¡C + +[2003/11/28] board.c class_namemode() ¥[¤J®É¶¡¨î¡C + +[2003/11/30] visio.c vget() ¤ä´© KEY_DEL¡C + +[2003/12/01] str_time.c *.c ±N©Ò¦³®É¶¡ªº®æ¦¡³£²Î¤@¡C + +[2003/12/02] acct.c admutil.c manage.c newbrd.c ×¥¿³B²zÅvÅܰʪºµ{¦¡¡C + post.c ¦Û°Ê°»´ú cross-post¡C + +[2003/12/03] game/*.c ×¥¿ª±¹CÀ¸®ÉY¶}±Ò¤è¦VÁä¥þ«¬°»´ú·|³y¦¨¿ù»~¡C + +[2003/12/04] more.c xover.c SLIDE_SHOW ¤å³¹/°Êµe¦Û°Ê¼½©ñ¡C + +[2003/12/11] rec_sync.c pal.c aloha.c ±N¯Á¤Þ±Æ§Çªºµ{¦¡¿W¥ß¥X¨Ó¡C + +[2003/12/14] bbslink.c ²¤Æ Message-ID ªº²£¥Í¤½¦¡¡Aª½±µ®³ÀɦW¡BªO¦W¨Óªí¥Ü¡C + bnntpd.c BBS-NNTP server¡C + +[2004/01/02] struct.h account.c board.c manage.c bhttpd.c bmtad.c ±NªO¤Í¦W³æ©ñ¶i shm¡C + +[2004/01/03] attr_lib.c attr.h §R°£ attr library¡C + bwboard.c §ï¼g¾ÔÁZ°O¿ýµ{¦¡¡C + +[2004/01/04] pal.c manage.c board.c ªO¤Í/¦n¤Í§Ö¨úµ{¦¡¾ã²z¦b¤@°_¡C + +[2004/01/06] acct.c bbsd.c bank.c game/*.c ª÷»È¹ô·¸¦ìÀˬd¡C + +[2004/01/10] bbsd.c µn¤J®É¦b¿é¤J§¹ ID/±K½X ¥H«á¤~¸ü¤J .ACCT¡AÁ×§K¦³¤HÂÇ vget ²£¥Íªº®É®t¨Ó¬~¿ú¡C + global.h bbsd.c ®³±¼ dns_ident ªº¨BÆJ¡C + +[2004/01/12] global.h cache.c bbsd.c §â¤@¨Ç etc/ ¤å¥ó·h¶i cache¡C + admutil.c §â etc/ ¤å¥ó³£¥[¤J¨t²ÎÀɮײM³æ¤¤¡C + expire.c rec_article.c ×¥¿ chrono32 ¿ù»~¡C + +[2004/01/13] str_hash2.c str_xor.c mail.c ifsigned.c §ïÅܹq¤lñ³¹ªº²£¥Í¤½¦¡¡C + +[2004/01/30] ufo.h edit.c help.c ×¥¿¦b vedit ®É¶i¤J help ¦A¶i¤J vedit ³y¦¨¤å³¹¬y¥¢¡C + +[2004/02/11] enews-open.c ¶®ªê¡I©_¼¯·s»Dºô¶§ïª©¡C + +[2004/02/16] dreye.c menu.c ĶÂI³q½u¤W¦r¨åªA°È°±¤î¡C + +[2004/02/17] more.c post.c mail.c gem.c ·j´M¦r¦ê¤Ï¥Õ¡C + +[2004/02/21] bhttpd.c µn¤J¡Bµoªí¤å³¹¡B§Úªº³Ì·Rµ{¦¡×¥¿¡C + +[2004/02/28] post.c Âà¿ý®É¥i¿ï¾Ü¥[±K¦sÀÉ¡C + +[2004/03/03] xpost.c ¦ê¦C¼Ò¦¡¾\Ū¤@¶¤å³¹§¹¥i·j´M¦r¦ê¡B¼È¦s¡Bµû¤À¡C + +[2004/03/05] pal.c aloha.c bmw.c ¦n¤Í/¤W¯¸³qª¾/¤ô²y¨t²Î¤ä´© tag ¼ÐÅÒ¡C + xover.c post.c mbox.c gem.c pal.c aloha.c bmw.c ¼ÐÅÒ§R°£¾ã¦X¦b¤@°_¡C + +[2004/03/06] vote.c ¥[¤J°Ï¬q§R°£¤Î¼ÐÅÒ§R°£¡C + more.c xpost.c ¦ê¦C/¦r¦ê·j´M®É¡A³B²z¤¤¤å¦rÅܤp¼gªº°ÝÃD¡C + +[2003/03/11] board.c post.c account.c rec_article.c bmtad.c brdmail.c ×¥¿¬ÝªO btime §ó·sªºµ{¦¡¡C + +[2003/03/13] bbsmail.c brdmail.c §ï¼g¡AºÉ¶q§ï¥Î libdao ªº¨ç¦¡¡C + +[2003/03/14] mailpost.c bmtad.c ®³±¼ mailpost ªº³¡¤À¡C + +[2004/03/15] struct.h *.c ±N PASSLEN ´À´«¦¨ PASSLEN + 1¡A¨Ã±N PASSLEN ±q 14 §ï¬° 13¡C + +[2004/03/18] bquota.c ¤£§R°£¾×«H¦W³æ¤W¨Ó·½ªº«H¡C + config.h acct.c admutil.c HAVE_TRUST Åܦ¨©l²× #define¡C + global.h admutil.c bmtad.c acl.ic etc/mail.acl etc/unmail.acl ¦¬«H¶Â¥Õ¦W³æ¡C + +[2004/03/22] topgem.c µ{¦¡§ï¼g¡C + +[2004/03/30] favor.c §Úªº³Ì·R¥i¥H¨ì¤U¤@¶·j´M¥¼Åª¬ÝªO¡C + +[2004/04/01] innbbsd/* InnNNSD §ïª©¡C + +[2004/04/05] str_len.c talk.c acct.c ®³±¼ str_len¡C + board.c acct.c ¦b Class ¤Uª½±µ·s¼W¬ÝªO¨ì¸Ó¤ÀÃþ¡C + +[2004/04/13] ±N bguard.c bmtad.c bpop3d.c gemd.c xchatd.c bhttpd.c bnntpd.c ·h¨ì daemon/ ¥Ø¿ý¡C + +[2004/04/24] song.c ÂIºq¨ì¯¸¥~«H½c¡C + +[2004/04/25] innbbsd/*.c admutil.c ±NÂà«H³]©w©M BBS µ²¦X¡C + +[2004/04/30] struct.h bbslink.c post.c outgo.c ±N out.bntp/*.link ªº§ï¬° binary ®æ¦¡¡C + +[2004/05/11] mail.c post.c ²Î¤@±H«H§¹ªº°T®§¡C + +[2004/05/19] game/*.c so/*.c ¹CÀ¸°T®§¤¤ªº¡u§A¡v§ï¦¨¡u±z¡v¡C + mailpost.c »{ÃÒ«H³¡¤Àµ{¦¡×¥¿¡C + +[2004/05/21] qkmj.c etc/game/qkmj ²¾°£ QKMJ ³s½u³Â±N¡C + jcee.c etc/jcee ²¾°£Áp¦Òº]³æ¬d¸ß¡C + webx.c ²¾°£®ð¶H³ø¾É§ì¨ú¡C + edit.c ²¾°Ê´¡¤J½d¥»¡C + +[2004/06/13] newbrd.c ²¤Æ³s¸p¨t²Î¡C + +[2004/06/16] board.c ×¥¿¥i¶i¤J¤w§R°£ªº¬ÝªO¡C + +[2004/06/21] *.c *.h ¤ä´©¶W¹L 80 ¦æ¼e¿Ã¹õªºµe±¡C + +[2004/07/21] bhttpd.c µoªí¤å³¹¨ú®ø¦r¼Æ¨î¡A¼W¥[µo¤å¨Ó·½¡A¨Ã¯àÂà«H¡C + +[2004/07/22] favor.c §Úªº³Ì·R´£¨Ñ¤À¹j½u¡C + +[2004/08/02] more.c ¤¤¤å¦rÂ_¦æ¡C + +[2004/08/04] bbsmail.c brdmail.c ¥[¤J¾×«H¶Â¥Õ¦W³æ¾÷¨î¡C + +[2004/08/06] str_lowest.c str_sub.c §ì¨ì library¡C + struct.h admutil.c bbslib.c rec_article.c ¥[¤J¾×«H³W«h¡C + +[2004/08/24] xpost.c ¥þ¤å·j´M¥[¤J½d³ò¨î¡C + +[2004/09/01] menu.c cache.c ¥D¿ï³æ/°ÊºA¬ÝªO¨Ì¼e¿Ã¹õ¸m¤¤¡C + +[2004/09/07] config.h xover.c post.c mail.c xpost.c HAVE_XYPOST Åܦ¨©l²× #define¡C + +[2004/09/11] bbsd.c struct.c camera.c §R°£ FILM_WELCOME ²¤Æ¶i¯¸µe±¡C + +[2004/09/16] xover.c xo_thread() §ï¼g¡C + +[2004/09/17] more.c ¶W¹L 256 ¶ªºÀɮפ]¯à°÷¥¿½Tªº³Qpºâ¡C + +[2004/09/22] bbslink.c bbsnnrp.c ×¥¿¿ù»~¨Ã¼W¥[ -v ªº°T®§¡C + +[2004/09/30] windtop2pip.c WindTop Âà´«¹q¤lÂû¡C + +[2004/10/01] talk.c ¨Ï¥ÎªÌ¦W³æµ{¦¡Â½·s¡C + +[2004/10/02] *.c *.h etc/help/pal ¡u¦n¤Í¦W³æ¡v§ï¬°¤¤©Êªº¡uªB¤Í¦W³æ¡v¡A¥H°Ï¤À¡u¦n¤Í¡v¡B¡uÃa¤H¡v¡B¡uªO¤Í¡v¡C + theme.h talk.c board.c ¡uªO¤Í¡v§ï¬°¡uªO¦ñ¡v¡C + +[2004/10/06] more.c ¾\Ū¨ì¤@¥b®ÉY¨Ï¥ÎªÌ¤¤Â_¡A«h¤£¨q footer¡C + bmtad.c ¶Â/¥Õ¦W³æÀˬdµ{¦¡×¥¿¡C + talk.c ¨Ï¥ÎªÌ¦W³æ¨ÌªO¦ñ±Æ§Ç¡C + +[2004/10/07] ulist.c ±N¨Ï¥ÎªÌ¦W³æ³¡¤Àªºµ{¦¡±q talk.c ¿W¥ß¥X¨Ó¡C + ulist.c ²¾°£¥ô·N±Æ¦C¡C + +[2004/10/10] mail.c song.c ¯¸¥~±H«H¥¢±Ñ´N¦s©³½Z¡C + talk.c bbsd.c FN_FRIEND_BENZ ¦P¨Bµ{¦¡¡C + +[2004/10/11] struct.h talk.c ±N¨t²Î¨ó´Mªº struct BENZ ¿W¥ß¥X¨Ó¡C + struct.h talk.c aloha.c ±N¤W¯¸³qª¾ªº struct FRIENZ ¿W¥ß¥X¨Ó¡C + +[2004/10/16] util/uno/* «¼g¾ã²z userno ªºµ{¦¡¡C + +[2004/10/19] ulist.c ¾\Ū°Î¦WªO¤£¬Ý¨ìªO¦ñ¡C + +[2004/10/23] gem.c mail.c post.c xpost.c ¾\Ū¨ì¨ì¤@¥b®É¥i¥H«ö E ½s¿è¤å³¹¡C + more.c ¦Û°Ê¼½©ñ§ï¬°¥u©w¦b³æ¤@½g¤å³¹¡C + bbslink.c bbsnnrp.c ±N°e«H¡B§ì«H¦X¨Ö¬°³æ¤@µ{¦¡¡C + +[2004/10/25] struct.h admutil.c µù¥U³æ§R°£¯u¹ê©m¦WÄæ¦ì¡C + +[2004/10/27] lottery.c lottery-open.c etc/game/lottery.main etc/game/lottery.rule ®³±¼¼Ö³z¹CÀ¸¡C + +[2004/10/28] struct.h admutil.c rec_article.c ¾×«H³W«h¼W¥[ SITE¡C + struct.h global.h bank.c ¤ä²¼¶×´Ú¡C + +[2004/11/01] vote.c ¥ß§Y¶}²¼¡C + vote.c account.c struct.h ´£¨Ñ½ä½L¥\¯à¡C + +[2004/11/10] struct.h cache.c account.c bno ¨ÌªO¦W±Æ§Ç¡A¥[³t¬ÝªO·j´M¡C + +[2004/11/13] cache.c menu.c °ÊºA¬ÝªO§ï¬°§¹¥þÀH¾÷¼½©ñ¡A¦Ó¤£¬O´`§ÇÀH¾÷¼½©ñ¡C + +[2004/11/14] more.c §ó·s¾\ۤ峹®É¡A«ö Up/PgUp ¤W±²ªºµ{¦¡¡C + +[2004/11/16] mail.c account.c °O¿ý¯¸¤º±H«H¡A¨Ã±N¯¸¤º/¯¸¥~±H«Hªº°O¿ý©ñ¦b log ªO¡C + +[2004/11/19] struct.h admutil.c rec_article.c ¾×«H³W«h¼W¥[ POSTHOST¡C + +[2004/11/25] admutil.c rec_article.c ¾×«H³W«h¥i¦UªO¯S§Oq©w¡C + +[2004/11/29] redir.c ºëµØ°Ï .DIR ««Øµ{¦¡¡C + +[2004/12/10] rec_bot.c *.c «n¤å³¹¸m©³¡C + +[2004/12/11] cache.c ×¥¿±qªB¤Í¦W³æ¥[¤J/²¾°£½u¤W¨Ï¥ÎªÌ®É¡A¦Û¤vªº¨Ï¥ÎªÌ¦W³æ¤£·|Åܦâ¡C + +[2004/12/23] config.h board.c HAVE_MMAP Åܦ¨©l²× #define¡C + +[2004/12/26] more.c ×¥¿ Home ·|µo¥Í¿ù»~¡C + +[2004/12/30] admutil.c Âà«H³]©w¼W¥[·j´Mªº¥\¯à¡C + +[2004/12/31] more.c §ïµ½¦b¾\Ūªø½g¤å³¹®É¤W±²³t«×«ÜºCªº°ÝÃD¡C + +[2005/01/01] bbsd.c §R°£³Ì«á¤@Ó«½Æ login «áÅܦ¨¥»´L¡C + +[2005/01/08] global.h acct.c mail.c xover.c enews.c ±N¿ù»~ E-mail address ªº°T®§²Î¤@¦¨ ERR_EMAIL¡C + mail.c ±q¯¸¤W±H«Hµ¹ xyz.brd@mydoamil ¤Ï¦Ó·|±Hµ¹ xyz ³o ID¡C + +[2005/01/11] manage.c post.c ·s¼W¬ÝªOÄݩʡG¤£¯àµû¤À¡C + admutil.c »{ÃÒ¹L´Á«e¤Q¤Ñ¥i¶ñµù¥U³æ¡C + acct.c Ó¤H¤W¯¸¬ö¿ýÀ˯Á¡C + xyz.c §Ñ°O±K½XªA°È¡C + etc/cross-post global.h post.c Cross-Post °±Åv±H«H³qª¾¡C + +[2005/02/28] enews.c enews-open.c ²¾°£©_¼¯·s»D¡C + +[2005/03/08] global.h edit.c post.c more.c §â QUOTE_CHAR ²Î¤@¦b¤@°_¡C + +[2005/03/09] bhttpd.c ±N«H½c¦Cªí§ï¬°¤@¦¸¥u¦L¥X¤¤Q«Ê«H¡C + +[2005/03/13] vote.c §R°£½ä½L®É·|°h´«½äª÷¡C + +[2005/03/16] config.h global.h board.c account.c usies-sort.c ²¾°£ LOG_BRD_USIES¡C + +[2005/03/23] board.c bhttpd.c pal.c ¬ÝªOÃa¤H¡C + +[2005/03/28] board.c pal.c ulist.c xover.c ¨Ï·j´M¤¤¤åÃöÁä¦r®É¤£·|¥X¿ù¡C + +[2005/03/29] acct.c ×§ï¬ÝªOªO¦W®É¡A@Class ·|¤@¨ÖÅܰʡC + +[2005/04/05] innbbs.c admutil.c ±NÂà«H³]©w¿W¥ß¦¨ innbbs.c¡C + acct.c admutil.c ±N¯¸°È«ü¥O¶°¤¤¨ì admutil.c¡C + acct.c user.c ±N¨Ï¥ÎªÌ«ü¥O¶°¤¤¨ì user.c¡C + struct.h user.c admutil.c ¨Ï¥ÎªÌ¦Û¦æ´_Åv¡C + +[2005/04/13] innbbs.c channel.c bbslink.c inntobbs.c rec_article.c ¾×«H³W«h¥i«]¾×¬Y¯S©w·s»D¦øªA¾¹ªº«H¡C + +[2005/04/14] gem.c ×¥¿ºëµØ°Ï½Æ»s·|Â_½uªº°ÝÃD¡C + +[2005/04/20] bwboard.c ×¥¿x´Ñ¬¶/¥]¦æ¨«¤è¦¡¡C + bwboard.c ·t´Ñ«ö·Ó²Ä¤@Ó½¤l¨M©wÃC¦â¡C + +[2005/04/23] manage.c ©Ø·¬¸¨¸±Ù¥i«ü©w¥i¬å(¤£)Âà«HªO¡C + post.c ªO¥D¦bºÞ²zªº¬ÝªO¤¤Âà¿ý¤£ºâ¸ó¶K¡C + vote.c ½ä½Lªº²¼»ù¥ÑªO¥D¨Ó¨M©w¡C + +[2005/04/24] innbbs.c innbbsd/* active Àɪº³]©w·h¤J newsfeeds.bbs ¤º¡C + +[2005/05/17] struct.h cache.c menu.c camera.c ±N¸`¤é·h¨ì fshm¡C + camera.c etc/feast ¤ä´©¬Y¤ë²Ä´XÓ¬P´Á´X¬°¸`¤éªº®æ¦¡¡C + +[2005/05/18] xpost.c ×¥¿¦P¼ÐÃD·j´Mn¼ÐÃD§¹¥þ¬Û¦P¤~ match¡C + +[2005/05/19] *.h *.c ±N¬ÝªOªø«×±q IDLEN ¿W¥ß¦¨ BNLEN¡C + +[2005/05/28] camera.c etc/feast ¤ä´©¹A¾ä¸`¼y¡C + +[2005/06/04] perm.h *.c §â¯¸¤º±H«HªºÅv¿W¥ß¦¨ PERM_LOCAL¡C + +[2005/06/06] config.h bbsd.c user.c admutil.c ±N INVALID_NOTICE_PERIOD ¾ã²z¥X¨Ó¡C + +[2005/06/09] theme.h edit.c bhttpd.c §â BANNER ¾ã²z¥X¨Ó¡C + struct.h board.c vote.c account.c ¬ÝªO¦CªíÅã¥Ü¸Ó¬ÝªO¦³½ä½L¶i¦æ¤¤¡C + +[2005/06/11] topusr.c ±Æ¦æº]¤¹³\¦P¦W¦¸¡C + +[2005/06/13] struct.h board.c post.c bbsd.c ¬ÝªO¤H®ð¡C + +[2005/06/17] bbsd.c game/*.c ¹CÀ¸¶Ã¼Æ¿ï¨ú¡C + +[2005/06/25] modes.h perm.h gem.c ºëµØ°ÏÅv»P¬ÝªOÅv¦P¨B¡C + +[2005/06/26] *.c ºëµØ°Ï¤£´£¨Ñ Gopher¡C + +[2005/06/30] *.c ±N xsort §ï¥Î qsort¡C + +[2005/07/01] bnntpd.c BNNTPD §ï¬° daemon¡C + +[2005/07/09] bhttpd.c BHTTPD §ï¬° daemon¡C + +[2005/07/12] xover.c bmw.c ±N bmw_cb ª½±µ¼g¨ì xz[]¡C + xover.c pal.c manage.c vote.c ±N pal_cb ª½±µ¼g¨ì xz[]¡C + modes.h pal.c manage.c vote.c °Ï¤ÀªB¤Í/¸s²Õ/ªO¤Í¦W³æªº´£¥Ü¦r¼Ë¡C + +[2005/07/16] post.c cache.c ´Nºâ¨S¦³ #define CHECK_ONLINE¡A¤]¥i¥H¥á¤å³¹/«H¥ó§@ªÌ¤ô²y¡C + pal.c aloha.c ªB¤Í¦W³æ/¤W¯¸³qª¾¦W³æ¤¤¡AY¸Ó¨Ï¥ÎªÌ¦b¯¸¤W·|«G¦â¡C + pal.c ×¥¿§ï¸s²Õ¦W³æ/ªO¤Í¦W³æ/¨î§ë²¼¦W³æ®É·|¿ù»~¥[¤W STATUS_PALDIRTY¡C + +[2005/08/10] bhttpd.c ¤j´T§ïª©¡C + +[2005/08/14] cache.c ×¥¿¨Ï¥ÎªÌ¤£¦b½u¤W¡A¦ý¦b¦Cªí¤¤«o«G¦â¡C + +[2005/08/26] visio.c §ï¼g¿Ã¹õ±±¨î³¡¤À¡C + +[2005/08/31] *.c ±N©Ò¦³´«¤j¤p¼gªºµ{¦¡²Î¤@¡C + +[2005/09/01] inntobbs.h inntobbs.c rec_article.c Organization ¤£¦C¬°¥²nÀÉÀY¡C + +[2005/10/07] *.c ¯¸ªø¦æ¬°°O¿ý¡C + +[2005/10/08] admutil.c ÁÙì³Æ¥÷¡C + +[2005/10/15] config.h innbbsd/* §â BBSNAME2¡BTAG_VALID¡Bbbsname.bbs ¾ã¦X¦b¤@°_¡C + +[2005/10/19] visio.c talk.c chat.c bwboard.c ×¥¿ vio_fd »P mysql ©R¦W½Ä¬ð¡C + +[2005/10/20] post.c ±q¯µ±K¬ÝªOÂà¿ý¥X¥hªº¤å³¹¤£Åã¥Ü¨Ó·½¬ÝªO¡C + +[2005/11/17] xover.c ×¥¿¦b¤å³¹¦Cªí«ö ^Z ¿ï¬ÝªO®É¡A·|¦h°µ¤@¦¸ XoPost()¡C + +[2005/11/18] more.c ±Ë±ó buffered file read ªº¤è¦¡¡A¦Ó±Ä full file read¡C + +[2005/11/23] bmw.c ´£¨Ñ§R°£©Ò¦³¤ô²yªº¥\¯à¡C + +[2005/12/09] bbsnet.c connlist ²¾°£ BBSNET¡C + +[2005/12/25] acct.c manage.c ªO¥D¦W³æ¿é¤J¦P¼Ë ID ®É¥i²¾°£¸Ó ID¡C + +[2006/01/23] camera.c etc/feasts ¯S®í¸`¤éªº¶}ÀYµe±¡C + +[2006/02/06] xpost.c post.c mail.c xover.c ¦ê¦C·j´M¤¹³\¼W¥[±ø¥ó¦A«×·j´M¡C + +[2006/02/08] struct.h innbbs.c bbslink.c ¦b newsfeeds ¸Ì±Åã¥Ü§ä¤£¨ì¸s²Õ¡C + +[2006/03/24] board.c vote.c ×¥¿¬ÝªO¤H®ðpºâ¿ù»~¡C + +[2006/03/30] bhttpd.c ´£¨Ñ robot exclusion¡C + ats2*.c ´£¨Ñ ATS Âà´«µ{¦¡¡C + +[2006/04/10] board.c ¦b¬ÝªO¦Cªí±N¬ÝªO¥[¤J§Úªº³Ì·R¤£·|«ÂÐ¥[¤J¡C + visio.c vget() ®É«öªÅ¥ÕÁ侨¶q¸É§¹ªO¦W¡C + +[2006/04/17] camera.c ¨î°ÊºA¬ÝªO¨C¦Cªø«×¡C + +[2006/04/20] more.c ×¥¿¤å³¹¾\Ū¨ì¤@¥b®É¡A¶i¥X help ·|¿ù»~¡C + str_ttl.c post.c ±NÂà¿ý¦r¼Ë§ï¦¨ Fw:¡C + +[2006/05/10] visio.c edit.c ¤ä´©º~¦r¾ã¦r§R°£¡B²¾°Ê¡BÅã¥Ü¡C + +[2006/05/12] chat.c ´£¨Ñ KEY_DEL §R¦r¥\¯à¡C + talk.c chat.c ¤ä´©º~¦r¾ã¦r§R°£¡B²¾°Ê¡BÅã¥Ü¡C + +[2006/05/21] railway.c ²¾°£ÅK¸ô®É¨è¬d¸ß¡C + diff --git a/maple/Makefile b/maple/Makefile new file mode 100644 index 0000000..0276fcd --- /dev/null +++ b/maple/Makefile @@ -0,0 +1,69 @@ +# ------------------------------------------------------ # +# maple/Makefile ( NTHU CS MapleBBS Ver 3.10 ) # +# ------------------------------------------------------ # +# author : opus.bbs@bbs.cs.nthu.edu.tw # +# target : Makefile for MapleBBS main programs # +# create : 95/03/29 # +# update : 95/12/15 # +# ------------------------------------------------------ # + +# ------------------------------------------------------ # +# ¤U¦Cªº make rules ¤£»Ý×§ï # +# ------------------------------------------------------ # + + +SRC = acct.c bbsd.c bmw.c board.c cache.c edit.c favor.c \ + gem.c mail.c menu.c more.c pal.c post.c talk.c ulist.c \ + user.c visio.c window.c xover.c xpost.c + +OBJ = acct.o bbsd.o bmw.o board.o cache.o edit.o favor.o \ + gem.o mail.o menu.o more.o pal.o post.o talk.o ulist.o \ + user.o visio.o window.o xover.o xpost.o + +EXE = bbsd + + +all: + @echo "Please enter 'make sys-type', " + @echo " make sun : for Sun-OS 4.x and maybe some BSD systems, cc or gcc" + @echo " make linux : for Linux" + @echo " make solaris : for Sun-OS 5.x gcc" + @echo " make sol-x86 : for Solaris 7 x86" + @echo " make freebsd : for BSD 4.4 systems" + @echo " make bsd : for BSD systems, cc or gcc, if not in the above lists" + @echo " make cygwin : for Microsoft Windows and Cygwin gcc" + +sun: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -fomit-frame-pointer -Wunused -I../include" LDFLAGS="-s -L../lib -ldao" $(EXE) + +linux: + @$(MAKE) CC=gcc CFLAGS="-DLINUX -O2 -pipe -fomit-frame-pointer -Wunused -I../include" LDFLAGS="-s -L../lib -ldao -lcrypt -lresolv -ldl -rdynamic" $(EXE) + +solaris: + @$(MAKE) CC=gcc CFLAGS="-DSOLARIS -DSYSV -O2 -pipe -fomit-frame-pointer -Wunused -I../include" LDFLAGS="-s -L../lib -ldao -ltermcap -lsocket -lnsl -lresolv -lelf -ldl" $(EXE) + +sol-x86: + @$(MAKE) CC=gcc CFLAGS="-DSOLARIS -DSYSV -O2 -fomit-frame-pointer -Wunused -I../include" LDFLAGS="-s -L../lib -ldao -ltermcap -lsocket -lnsl -lresolv -lelf -ldl" $(EXE) + +freebsd: + @$(MAKE) CC=gcc CFLAGS="-DBSD44 -O2 -pipe -fomit-frame-pointer -Wunused -I../include" LDFLAGS="-s -L../lib -ldao -lcrypt -export-dynamic" $(EXE) + +bsd: + @$(MAKE) CC=gcc CFLAGS="-DBSD44 -O2 -pipe -fomit-frame-pointer -Wunused -I../include" LDFLAGS="-s -L../lib -ldao" $(EXE) + +cygwin: + @$(MAKE) CC=gcc CFLAGS="-DLINUX -DCYGWIN -O2 -pipe -fomit-frame-pointer -Wunused -I../include" LDFLAGS="-s -L../lib -ldao -lcrypt -lresolv -lcygipc" $(EXE) + + +bbsd: $(OBJ) + $(CC) -o $@ $(OBJ) $(LDFLAGS) + + +install: $(EXE) + install -m 0700 $? $(HOME)/bin + +update: + -csh -c "kill `tail -1 $(HOME)/run/bbs.pid | awk '{print $$1}'`";exit 0 + +clean: + rm -f $(EXE) *.exe *.o *~ diff --git a/maple/acct.c b/maple/acct.c new file mode 100644 index 0000000..44b319e --- /dev/null +++ b/maple/acct.c @@ -0,0 +1,1203 @@ +/*-------------------------------------------------------*/ +/* acct.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : account / administration routines */ +/* create : 95/03/29 */ +/* update : 96/04/05 */ +/*-------------------------------------------------------*/ + + +#define _ADMIN_C_ + + +#include "bbs.h" + + +extern BCACHE *bshm; + + +/* ----------------------------------------------------- */ +/* (.ACCT) ¨Ï¥ÎªÌ±b¸¹ (account) subroutines */ +/* ----------------------------------------------------- */ + + +int +acct_load(acct, userid) + ACCT *acct; + char *userid; +{ + int fd; + + usr_fpath((char *) acct, userid, fn_acct); + fd = open((char *) acct, O_RDONLY); + if (fd >= 0) + { + /* Thor.990416: ¯S§Oª`·N, ¦³®É .ACCTªºªø«×·|¬O0 */ + read(fd, acct, sizeof(ACCT)); + close(fd); + } + return fd; +} + + +/* static */ /* itoc.010408: µ¹¨ä¥Lµ{¦¡¥Î */ +void +acct_save(acct) + ACCT *acct; +{ + int fd; + char fpath[64]; + + /* itoc.010811: Y³Q¯¸ªøÂê©w¡A´N¤£¯à¼g¦^¦Û¤vªºÀÉ®× */ + if ((acct->userno == cuser.userno) && HAS_STATUS(STATUS_DATALOCK) && !HAS_PERM(PERM_ALLACCT)) + return; + + usr_fpath(fpath, acct->userid, fn_acct); + fd = open(fpath, O_WRONLY, 0600); /* fpath ¥²¶·¤w¸g¦s¦b */ + if (fd >= 0) + { + write(fd, acct, sizeof(ACCT)); + close(fd); + } +} + + +int +acct_userno(userid) + char *userid; +{ + int fd; + int userno; + char fpath[64]; + + usr_fpath(fpath, userid, fn_acct); + fd = open(fpath, O_RDONLY); + if (fd >= 0) + { + read(fd, &userno, sizeof(userno)); + close(fd); + return userno; + } + return 0; +} + + +/* ----------------------------------------------------- */ +/* name complete for user ID */ +/* ----------------------------------------------------- */ +/* return value : */ +/* 0 : ¨Ï¥Îª½±µ«ö enter ==> cancel */ +/* -1 : bad user id */ +/* ow.: ¶Ç¦^¸Ó userid ¤§ userno */ +/* ----------------------------------------------------- */ + + +int +acct_get(msg, acct) + char *msg; + ACCT *acct; +{ + outz("¡¹ ¿é¤Jº¦r¥À«á¡A¥i¥H«öªÅ¥ÕÁä¦Û°Ê·j´M"); + + if (!vget(1, 0, msg, acct->userid, IDLEN + 1, GET_USER)) + return 0; + + if (acct_load(acct, acct->userid) >= 0) + return acct->userno; + + vmsg(err_uid); + return -1; +} + + +/* ----------------------------------------------------- */ +/* bit-wise display and setup */ +/* ----------------------------------------------------- */ + + +#define BIT_ON "£¾" +#define BIT_OFF "¡@" + + +void +bitmsg(msg, str, level) + char *msg, *str; + int level; +{ + int cc; + + outs(msg); + while (cc = *str) + { + outc((level & 1) ? cc : '-'); + level >>= 1; + str++; + } + + outc('\n'); +} + + +usint +bitset(pbits, count, maxon, msg, perms) + usint pbits; + int count; /* ¦@¦³´XÓ¿ï¶µ */ + int maxon; /* ³Ì¦h¥i¥H enable ´X¶µ */ + char *msg; + char *perms[]; +{ + int i, j, on; + + move(1, 0); + clrtobot(); + move(3, 0); + outs(msg); + + for (i = on = 0, j = 1; i < count; i++) + { + msg = BIT_OFF; + if (pbits & j) + { + on++; + msg = BIT_ON; + } + move(5 + (i & 15), (i < 16 ? 0 : 40)); + prints("%c %s %s", radix32[i], msg, perms[i]); + j <<= 1; + } + + while (i = vans("½Ð«öÁä¤Á´«³]©w¡A©Î«ö [Return] µ²§ô¡G")) + { + i -= '0'; + if (i >= 10) + i -= 'a' - '0' - 10; + + if (i >= 0 && i < count) + { + j = 1 << i; + if (pbits & j) + { + on--; + msg = BIT_OFF; + } + else + { + if (on >= maxon) + continue; + on++; + msg = BIT_ON; + } + + pbits ^= j; + move(5 + (i & 15), (i < 16 ? 2 : 42)); + outs(msg); + } + } + return (pbits); +} + + +static usint +setperm(level) + usint level; +{ + if (HAS_PERM(PERM_SYSOP)) + return bitset(level, NUMPERMS, NUMPERMS, MSG_USERPERM, perm_tbl); + + /* [±b¸¹ºÞ²zû] ¤£¯àºÞ PERM_SYSOP */ + if (level & PERM_SYSOP) + return level; + + /* [±b¸¹ºÞ²zû] ¤£¯à§ó§ïÅv PERM_ACCOUNTS CHATROOM BOARD SYSOP */ + return bitset(level, NUMPERMS - 4, NUMPERMS - 4, MSG_USERPERM, perm_tbl); +} + + +/* ----------------------------------------------------- */ +/* ±b¸¹ºÞ²z */ +/* ----------------------------------------------------- */ + + +static void +bm_list(userid) /* Åã¥Ü userid ¬Oþ¨ÇªOªºªO¥D */ + char *userid; +{ + int len; + char *list; + BRD *bhead, *btail; + + len = strlen(userid); + outs(" \033[32m¾á¥ôªO¥D¡G\033[37m"); /* itoc.010922: ´« user info ª©± */ + + bhead = bshm->bcache; + btail = bhead + bshm->number; + + do + { + list = bhead->BM; + if (str_has(list, userid, len)) + { + outs(bhead->brdname); + outc(' '); + } + } while (++bhead < btail); + + outc('\n'); +} + + +static void +adm_log(old, new) + ACCT *old, *new; +{ + int i; + usint bit, oldl, newl; + char *userid, buf[80]; + + userid = new->userid; + alog("²§°Ê¸ê®Æ", userid); + + if (strcmp(old->passwd, new->passwd)) + alog("²§°Ê±K½X", userid); + + if ((old->money != new->money) || (old->gold != new->gold)) + { + sprintf(buf, "%-13s»È%d¡÷%d ª÷%d¡÷%d", userid, old->money, new->money, old->gold, new->gold); + alog("²§°Ê¿ú¹ô", buf); + } + + /* Thor.990405: log permission modify */ + oldl = old->userlevel; + newl = new->userlevel; + for (i = 0, bit = 1; i < NUMPERMS; i++, bit <<= 1) + { + if ((newl & bit) != (oldl & bit)) + { + sprintf(buf, "%-13s%s %s", userid, (newl & bit) ? BIT_ON : BIT_OFF, perm_tbl[i]); + alog("²§°ÊÅv", buf); + } + } +} + +static void +brd_log(old, new) + BRD *old, *new; +{ + char buf[256]; + alog("³]©w¬ÝªO",old->brdname); + if(strcmp(old->brdname,new->brdname)){ + sprintf(buf,"%-13s%s",old->brdname,new->brdname); + alog("¬ÝªO§ó¦W",buf); + } + if(strcmp(old->class,new->class)){ + sprintf(buf,"%-13s%s ¡÷ %s",new->brdname,old->class,new->class); + alog("¬ÝªO¤ÀÃþ",buf); + } + if(strcmp(old->title,new->title)){ + sprintf(buf,"%-13s%s ¡÷ %s",new->brdname,old->title,new->title); + alog("¬ÝªO¥DÃD",buf); + } + if(strcmp(old->BM,new->BM)){ + sprintf(buf,"%-13s%s ¡÷ %s",new->brdname,(strlen(old->BM)) ? old->BM : "(µL)", + (strlen(new->BM)) ? new->BM : "(µL)"); + alog("×§ïªO¥D",buf); + } + int oldl = old->readlevel; + int newl = new->readlevel; + int i,bit; + for (i = 0, bit = 1; i < NUMPERMS; i++, bit <<= 1) + { + if ((newl & bit) != (oldl & bit)) + { + sprintf(buf, "%-13s%s %s", new->brdname, (newl & bit) ? BIT_ON : BIT_OFF, perm_tbl[i]); + alog("¾\\ŪÅv", buf); + } + } + oldl = old->postlevel; + newl = new->postlevel; + for (i = 0, bit = 1; i < NUMPERMS; i++, bit <<= 1) + { + if ((newl & bit) != (oldl & bit)) + { + sprintf(buf, "%-13s%s %s", new->brdname, (newl & bit) ? BIT_ON : BIT_OFF, perm_tbl[i]); + alog("µoªíÅv", buf); + } + } + oldl = old->battr; + newl = new->battr; + for (i = 0, bit = 1; i < NUMBATTRS; i++, bit <<= 1) + { + if ((newl & bit) != (oldl & bit)) + { + sprintf(buf, "%-13s%s %s", new->brdname, (newl & bit) ? BIT_ON : BIT_OFF, battr_tbl[i]); + alog("¬ÝªOÄÝ©Ê", buf); + } + } + +} + +static int /* 1:§ä¨ì 0:¨S§ä¨ì */ +find_rform(userno, userid, address, phone, career) + int userno; /* ¶Ç¤J userno/userid */ + char *userid; + char *address, *phone, *career; /* ¦^¶Ç address/phone/career */ +{ + RFORM *rform; + int fd, rc; + + rc = 0; + if ((fd = open(FN_RUN_RFORM_LOG, O_RDONLY)) >= 0) + { + mgets(-1); + + while (rform = mread(fd, sizeof(RFORM))) + { +// if (userno == rform->userno && !strcmp(userid, rform->userid)) + if (!strcmp(userid, rform->userid)) + { + strcpy(address, rform->address); + strcpy(phone, rform->phone); + strcpy(career, rform->career); + rc = 1; + //break; /* Y§â³o¦æ break ®³±¼¡A¨º»ò´N¬O§ä³Ì«á¤@µ§µù¥U³æ */ + } /* Y§â³o¦æ break ¯dµÛ¡A¨º»ò´N¬O§ä²Ä¤@µ§µù¥U³æ */ + } + + close(fd); + } + + return rc; +} + + +void +acct_show(u, adm) + ACCT *u; + int adm; /* 0: user info 1: admin 2: reg-form */ +{ + int diff; + usint ulevel; + char *uid, buf[80]; + + clrtobot(); + + /* itoc.010922: ´« user info ª©± */ + if (adm == 0) + { + outs("\n \033[30;41m¢s¢r¢s¢r¢s¢r\033[m \033[45mùüùÞùÞùûùúùÞùùùû" + "ùÝùÞùùùûùúùÞùùùû\033[m \033[30;41m¢s¢r¢s¢r¢s¢r\033[m\n" + " \033[30;41m¢r¢s¢r¢s¢r¢s\033[m \033[1;37;45m ùàùâ ùàùâ" + " ùøùàùáùâ ùàùâ ùø\033[m \033[30;41m¢r¢s¢r¢s¢r¢s\033[m\n" + " \033[30;41m¢s¢r¢s¢r¢s¢r\033[m \033[45m ùàùâ ùàùâ ùø" + "ùàùâùý ùàùâ ùø\033[m \033[30;41m¢s¢r¢s¢r¢s¢r\033[m\n" + " \033[30;41m¢r¢s¢r¢s¢r¢s\033[m \033[1;30;45mùüùäùäùûùãùå" + " ùüùãùå ùüùäùùùý\033[m \033[30;41m¢r¢s¢r¢s¢r¢s\033[m\n"); + } + + uid = u->userid; + + outs("\n\033[1m"); + + /* itoc.010408: ·s¼Wª÷¿ú/¥Í¤é/©Ê§OÄæ¦ì */ + + if (adm != 2) + prints(" \033[32m^¤å¥N¸¹¡G\033[37m%-35s\033[32m¥Î¤á½s¸¹¡G\033[37m%d\n", uid, u->userno); + + prints(" \033[32m§Úªº¼ÊºÙ¡G\033[37m%-35s\033[32m¾Ö¦³»È¹ô¡G\033[37m%d\n", u->username, u->money); + + prints(" \033[32m¯u¹ê©m¦W¡G\033[37m%-35s\033[32m¾Ö¦³ª÷¹ô¡G\033[37m%d\n", u->realname, u->gold); + + prints(" \033[32m¥X¥Í¤é´Á¡G\033[37m¥Á°ê %03d ¦~ %02d ¤ë %02d ¤é \033[32m§Úªº©Ê§O¡G\033[37m%.2s\n", u->year, u->month, u->day, "¡H¡ñ¡ð" + (u->sex << 1)); + + prints(" \033[32m¤W¯¸¦¸¼Æ¡G\033[37m%-35d\033[32m¤å³¹½g¼Æ¡G\033[37m%d\n", u->numlogins, u->numposts); + + prints(" \033[32m¶l¥ó«H½c¡G\033[37m%s\n", u->email); + + prints(" \033[32mµù¥U¤é´Á¡G\033[37m%s\n", Btime(&u->firstlogin)); + + prints(" \033[32m¥úÁ{¤é´Á¡G\033[37m%s\n", Btime(&u->lastlogin)); + + ulevel = u->userlevel; + + if (ulevel & PERM_ALLDENY) + { + /* yiting: Åã¥Ü°±Åv¤Ñ¼Æ */ + outs(" \033[32m°±Åv¤Ñ¼Æ¡G\033[37m"); + if ((diff = u->tvalid - time(0)) < 0) + { + outs("°±Åv´Á¤w¨ì¡A¥i¦Û¦æ¥Ó½Ð´_Åv\n"); + } + else + { + /* ¤£º¡¤@¤p®Éªº³¡¥÷¥[¤@¤p®Épºâ¡A³o¼ËÅã¥Ü0¤p®É´Nªí¥Ü¥i¥H¥h´_Åv¤F */ + diff += 3600; + prints("ÁÙ¦³ %d ¤Ñ %d ¤p®É\n", diff / 86400, (diff % 86400) / 3600); + } + } + else + { + prints(" \033[32m¨¤À»{ÃÒ¡G\033[37m%s\n", (ulevel & PERM_VALID) ? Btime(&u->tvalid) : "½Ð°Ñ¦Ò¥»¯¸¤½§GÄæ¶i¦æ½T»{¡A¥H´£ª@Åv"); + } + + usr_fpath(buf, uid, fn_dir); + prints(" \033[32mÓ¤H«H¥ó¡G\033[37m%d «Ê\n", rec_num(buf, sizeof(HDR))); + + if (adm) + { + char address[60], phone[20], career[50]; + prints(" \033[32m¤W¯¸¦aÂI¡G\033[37m%-35s\033[32mµo«H¦¸¼Æ¡G\033[37m%d\n", u->lasthost, u->numemails); + bitmsg(" \033[32mÅvµ¥¯Å¡G\033[37m", STR_PERM, ulevel); + bitmsg(" \033[32m²ßºDºX¼Ð¡G\033[37m", STR_UFO, u->ufo); + if (find_rform(u->userno, u->userid, address, phone, career)) + { + prints (" \033[32mµù¥U¦í§}¡G\033[37m%s\n", address); + prints (" \033[32mªA°È³æ¦ì¡G\033[37m%-35s" \ + "\033[32mµù¥U¹q¸Ü¡G\033[37m%s\n", + career, phone); + } + } + else + { + diff = (time(0) - ap_start) / 60; + prints(" \033[32m°±¯d´Á¶¡¡G\033[37m%d ¤p®É %d ¤À\n", diff / 60, diff % 60); + } + + if (adm == 2) + goto end_show; + + /* Thor: ·Q¬Ý¬Ý³oÓ user ¬O¨º¨ÇªOªºªO¥D */ + + if (ulevel & PERM_BM) + bm_list(uid); + +#ifdef NEWUSER_LIMIT + if (u->lastlogin - u->firstlogin < 3 * 86400) + outs("\n \033[36m·s¤â¤W¸ô¡G¤T¤Ñ«á¶}©ñÅv\n"); +#endif + +end_show: + outs("\033[m"); +} + + +void +acct_setup(u, adm) + ACCT *u; + int adm; +{ + ACCT x; + int i, num; + char *str, buf[80], pass[PSWDLEN + 1]; + int mmday[12] = {31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31}; + + acct_show(u, adm); + memcpy(&x, u, sizeof(ACCT)); + + char fpath_reg[256]; + + if (adm) + { + adm = vans("³]©w 1)¸ê®Æ 2)Åv 3)À˵øµù¥U³æ Q)¨ú®ø [Q] "); + if (adm == '2') + goto set_perm; + + if (adm == '3'){ + usr_fpath(fpath_reg,u->userid,"justify"); + if(more(fpath_reg,(char*) 0 ) == -1){ + vmsg("³oӨϥΪ̨S¦³¶ñ¹Lµù¥U³æ"); + }else{ + move(0,0),clrtoeol(),refresh(); + } + return; + } + + if (adm != '1') + return; + } + else + { + if (vans("×§ï¸ê®Æ(Y/N)¡H[N] ") != 'y') + return; + } + + move(i = 3, 0); + clrtobot(); + + if (adm) + { + str = x.userid; + for (;;) + { + /* itoc.010804.µù¸Ñ: §ï¨Ï¥ÎªÌ¥N¸¹®É½Ð½T©w¸Ó user ¤£¦b¯¸¤W */ + vget(i, 0, "¨Ï¥ÎªÌ¥N¸¹(¤£§ï½Ð«ö Enter)¡G", str, IDLEN + 1, GCARRY); + if (!str_cmp(str, u->userid) || !acct_userno(str)) + break; + vmsg("¿ù»~¡I¤w¦³¬Û¦P ID ªº¨Ï¥ÎªÌ"); + } + } + else + { + vget(i, 0, "½Ð½T»{±K½X¡G", buf, PSWDLEN + 1, NOECHO); + if (chkpasswd(u->passwd, buf)) + { + vmsg("±K½X¿ù»~"); + return; + } + } + + /* itoc.030223: ¥u¦³ PERM_SYSOP ¯àÅܧó¨ä¥L¯¸°Èªº±K½X */ + if (!adm || !(u->userlevel & PERM_ALLADMIN) || HAS_PERM(PERM_SYSOP)) + { + i++; + for (;;) + { + if (!vget(i, 0, "³]©w·s±K½X(¤£§ï½Ð«ö Enter)¡G", buf, PSWDLEN + 1, NOECHO)) + break; + + strcpy(pass, buf); + vget(i + 1, 0, "Àˬd·s±K½X¡G", buf, PSWDLEN + 1, NOECHO); + if (!strcmp(buf, pass)) + { + str_ncpy(x.passwd, genpasswd(buf), sizeof(x.passwd)); + break; + } + } + } + + i++; + str = x.username; + while (1) + { + if (vget(i, 0, "¼Ê ºÙ¡G", str, UNLEN + 1, GCARRY)) + break; + }; + + /* itoc.010408: ·s¼W¥Í¤é/©Ê§OÄæ¦ì¡A¤£±j¢¨Ï¥ÎªÌ¶ñ (¤¹³\¶ñ 0) */ + i++; + int year; + do + { + sprintf(buf, "¥Í¤é¡Ð¥Á°ê %02d ¦~¡G", u->year); + if (!vget(i, 0, buf, buf, 4, DOECHO)) + break; + year = atoi(buf); + } while (year <= 0 || year >= 256 /*|| x.year > 99*/); + x.year=year; + + if (((x.year + 1991) % 400 == 0) || + ((x.year + 1991) % 100 != 0 && (x.year + 1991) % 4 == 0)) + mmday[1]=29; + + do + { + sprintf(buf, "¥Í¤é¡Ð %02d ¤ë¡G", u->month); + if (!vget(i, 0, buf, buf, 3, DOECHO)) + break; + x.month = atoi(buf); + } while (x.month <= 0 || x.month > 12); + do + { + sprintf(buf, "¥Í¤é¡Ð %02d ¤é¡G", u->day); + if (!vget(i, 0, buf, buf, 3, DOECHO)) + break; + x.day = atoi(buf); + } while (x.day <= 0 || x.day > mmday[x.month-1] ); + + i++; + sprintf(buf, "©Ê§O (0)¤¤©Ê (1)¨k©Ê (2)¤k©Ê¡G[%d] ", u->sex); + if (vget(i, 0, buf, buf, 3, DOECHO)) + x.sex = (*buf - '0') & 3; + + i++; + str = x.realname; + do + { + vget(i, 0, "¯u¹ê©m¦W¡G", str, RNLEN + 1, GCARRY); + } while (strlen(str) < 4); + + if (adm) + { +// /* itoc.010317: ¤£Åý user §ï©m¦W */ +// i++; +// str = x.realname; +// do +// { +// vget(i, 0, "¯u¹ê©m¦W¡G", str, RNLEN + 1, GCARRY); +// } while (strlen(str) < 4); + + sprintf(buf, "%d", u->userno); + vget(++i, 0, "¥Î¤á½s¸¹¡G", buf, 10, GCARRY); + if ((num = atoi(buf)) > 0) + x.userno = num; + + sprintf(buf, "%d", u->numlogins); + vget(++i, 0, "¤W½u¦¸¼Æ¡G", buf, 10, GCARRY); + if ((num = atoi(buf)) >= 0) + x.numlogins = num; + + sprintf(buf, "%d", u->numposts); + vget(++i, 0, "¤å³¹½g¼Æ¡G", buf, 10, GCARRY); + if ((num = atoi(buf)) >= 0) + x.numposts = num; + + /* itoc.010408: ·s¼Wª÷¿úÄæ¦ì */ + sprintf(buf, "%d", u->money); + vget(++i, 0, "»È ¹ô¡G", buf, 10, GCARRY); + if ((num = atoi(buf)) >= 0) + x.money = num; + + sprintf(buf, "%d", u->gold); + vget(++i, 0, "ª÷ ¹ô¡G", buf, 10, GCARRY); + if ((num = atoi(buf)) >= 0) + x.gold = num; + + sprintf(buf, "%d", u->numemails); + vget(++i, 0, "µo«H¦¸¼Æ¡G", buf, 10, GCARRY); + if ((num = atoi(buf)) >= 0) + x.numemails = num; + + vget(++i, 0, "¤W¯¸¦aÂI¡G", x.lasthost, sizeof(x.lasthost), GCARRY); + vget(++i, 0, "¶l¥ó«H½c¡G", x.email, sizeof(x.email), GCARRY); + + if (vans("³]©w²ßºD(Y/N)¡H[N] ") == 'y') + x.ufo = bitset(x.ufo, NUMUFOS, NUMUFOS, MSG_USERUFO, ufo_tbl); + + if (vans("³]©wÅv(Y/N)¡H[N] ") == 'y') + { +set_perm: + + i = setperm(num = x.userlevel); + + if (i == num) + { + vmsg("¨ú®ø×§ï"); + if (adm == '2') + return; + } + else + { + x.userlevel = i; + + /* itoc.011120: ¯¸ªø©ñ¤ô¥[¤W»{ÃÒ³q¹LÅv¡Anªþ¥[§ï»{ÃҮɶ¡ */ + if ((i & PERM_VALID) && !(num & PERM_VALID)) + time(&x.tvalid); + + /* itoc.050413: ¦pªG¯¸ªø¤â°Ê°±Åv¡A´Nn¥Ñ¯¸ªø¤~¯à¨Ó´_Åv */ + if ((i & PERM_ALLDENY) && (i & PERM_ALLDENY) != (num & PERM_ALLDENY)) + x.tvalid = INT_MAX; + } + } + } + + if (!memcmp(&x, u, sizeof(ACCT)) || vans(msg_sure_ny) != 'y') + return; + + if (adm) + { + if (str_cmp(u->userid, x.userid)) + { /* Thor: 980806: ¯S§Oª`·N¦pªG usr¨CÓ¦r¥À¤£¦b¦P¤@partitionªº¸Ü·|¦³°ÝÃD */ + char dst[80]; + + usr_fpath(buf, u->userid, NULL); + usr_fpath(dst, x.userid, NULL); + rename(buf, dst); + /* Thor.990416: ¯S§Oª`·N! .USR¨Ã¥¼¤@¨Ö§ó·s, ¥i¯à¦³³¡¤À°ÝÃD */ + } + + /* itoc.010811: °ÊºA³]©w½u¤W¨Ï¥ÎªÌ */ + /* ³Q¯¸ªø§ï¹L¸ê®Æªº½u¤W¨Ï¥ÎªÌ(¥]¬A¯¸ªø¦Û¤v)¡A¨ä cutmp->status ·|³Q¥[¤W STATUS_DATALOCK + ³oÓºX¼Ð¡A´NµLªk acct_save()¡A©ó¬O¯¸ªø«K¥i¥H×§ï½u¤W¨Ï¥ÎªÌ¸ê®Æ */ + /* ¦b¯¸ªø×§ï¹L¤~¤W½uªº ID ¦]¬°¨ä cutmp->status ¨S¦³ STATUS_DATALOCK ªººX¼Ð¡A + ©Ò¥H±N¥i¥HÄ~Äò¦s¨ú¡A©Ò¥H½u¤W¦pªG¦P®É¦³×§ï«e¡B×§ï«áªº¦P¤@°¦ ID multi-login¡A¤]¬OµL§«¡C */ + utmp_admset(x.userno, STATUS_DATALOCK | STATUS_COINLOCK); + + /* lkchu.981201: security log */ + adm_log(u, &x); + } + else + { + /* itoc.010804.µù¸Ñ: ½u¤Wªº userlevel/tvalid ¬Oªº¡A.ACCT ¸Ì¤~¬O·sªº */ + if (acct_load(u, x.userid) >= 0) + { + x.userlevel = u->userlevel; + x.tvalid = u->tvalid; + } + } + + memcpy(u, &x, sizeof(ACCT)); + acct_save(u); +} + + +#if 0 /* itoc.010805.µù¸Ñ */ + + »{ÃÒ¦¨¥\¥u¥[¤W PERM_VALID¡AÅý user ¦b¤U¦¸¶i¯¸¤~¦Û°Ê±o¨ì PERM_POST | PERM_PAGE | PERM_CHAT + ¥H§K·s¤â¤W¸ô¡B°±Åvªº¥\¯à¥¢®Ä + + ¦ý«¶ñ email ®³±¼»{ÃҪ̻ݮ³±¼ PERM_VALID | PERM_POST | PERM_PAGE | PERM_CHAT + §_«h user ¥i¥H¦b¤U¦¸¶i¯¸«e¥ô·N¨Ï¥Î bbs_post + +#endif + +#if 0 /* itoc.010831.µù¸Ñ */ + + ¦]¬°½u¤W cuser.userlevel ¨Ã¤£¬O³Ì·sªº¡A¨Ï¥ÎªÌ¦pªG¦b½u¤W»{ÃҩάO³Q°±Åv¡A + µwºÐ¤¤ªº .ACCT ¼gªº¤~¬O¥¿½Tªº userlevel¡A + ©Ò¥Hn¥ýŪ¥X .ACCT¡A¥[¤J level «á¦A»\¦^¥h¡C + + ¨Ï¥Î acct_seperm(&acct, adm) ¤§«en¥ý acct_load(&acct, userid)¡A + ¨ä¤¤ &acct ¤£¯à¬O &cuser¡C + ¨Ï¥ÎªÌn«·s¤W¯¸¤~·|´«¦¨·sªºÅv¡C + +#endif + +void +acct_setperm(u, levelup, leveldown) /* itoc.000219: ¥[/´îÅvµ{¦¡ */ + ACCT *u; + usint levelup; /* ¥[Åv */ + usint leveldown; /* ´îÅv */ +{ + u->userlevel |= levelup; + u->userlevel &= ~leveldown; + + acct_save(u); +} + + +/* ----------------------------------------------------- */ +/* ¼W¥[ª÷»È¹ô */ +/* ----------------------------------------------------- */ + + +void +addmoney(addend) + int addend; +{ + if (addend < (INT_MAX - cuser.money)) /* Á×§K·¸¦ì */ + cuser.money += addend; + else + cuser.money = INT_MAX; +} + + +void +addgold(addend) + int addend; +{ + if (addend < (INT_MAX - cuser.gold)) /* Á×§K·¸¦ì */ + cuser.gold += addend; + else + cuser.gold = INT_MAX; +} + + +/* ----------------------------------------------------- */ +/* ¬ÝªOºÞ²z */ +/* ----------------------------------------------------- */ + + +#ifndef HAVE_COSIGN +static +#endif +int /* 1:¦XªkªºªO¦W */ +valid_brdname(brd) + char *brd; +{ + int ch; + + if (!is_alnum(*brd)) + return 0; + + while (ch = *++brd) + { + if (!is_alnum(ch) && ch != '.' && ch != '-' && ch != '_') + return 0; + } + return 1; +} + + +static int +brd_set(brd, row) + BRD *brd; + int row; +{ + int i, BMlen, len; + char *brdname, buf[80], userid[IDLEN + 2]; + ACCT acct; + + i = row; + brdname = brd->brdname; + strcpy(buf, brdname); + + for (;;) + { + if (!vget(i, 0, MSG_BID, brdname, BNLEN + 1, GCARRY)) + { + if (i == 1) /* ¶}·sªOYµL¿é¤JªO¦Wªí¥ÜÂ÷¶} */ + return -1; + + strcpy(brdname, buf); /* Thor:Y¬O²MªÅ«h³]¬°ì¦WºÙ */ + continue; + } + + if (!strcmp(buf, brdname) && valid_brdname(brdname)) /* Thor: »Pì¦W¦P«h¸õ¹L */ + break; + + if (brd_bno(brdname) >= 0) + outs("\n¿ù»~¡IªO¦W¹p¦P"); + else if (valid_brdname(brdname)) + break; + } + + vget(++i, 0, "¬ÝªO¤ÀÃþ¡G", brd->class, BCLEN + 1, GCARRY); + vget(++i, 0, "¬ÝªO¥DÃD¡G", brd->title, BTLEN + 1, GCARRY); + + /* vget(++i, 0, "ªO¥D¦W³æ¡G", brd->BM, BMLEN + 1, GCARRY); */ + + /* itoc.010212: ¶}·sªO/×§ï¬ÝªO¦Û°Ê¥[¤WªO¥DÅv. */ + /* ¥Ø«eªº§@ªk¬O¤@¿é¤J§¹ id ´N¥[¤JªO¥DÅv¡A§Y¨Ï³Ì«á¿ï¾Ü¤£ÅܰʡA + ¦pªG¦]¦¹¦h¥[¤FªO¥DÅv¡A¦b reaper.c ¤¤®³¤U */ + vget(++i, 0, "ªO¥D³]©w R)¤@¯ë³]©w¤è¦¡ F)¦Û¥Ñ×§ï¼Ò¦¡¡H[R] ", buf, 3, LCECHO); + + if(buf[0]=='f'){ + ++i; + outs("\033[1;33mĵ§i¡G¨Ï¥Î¦¹¼Ò¦¡×§ïª©¥D¦W³æ·|¾ÉP¨ü¼vÅTªº¨Ï¥ÎªÌªO¥DÅv¤£¥¿½T\033[m\n" + "\033[1;33m«ØÄ³¥u¦bªO¥D¦W³æªÅ¥Õ®É¨Ï¥Î¡A§_«h×§ï«á½Ð¦Û¦æ³B²zÅv°ÝÃD\033[m"); + i += 2; + vget(i, 0, "ªO¥D¦W³æ¡G", brd->BM , BMLEN + 1, GCARRY); + + }else{ + i += 4; + move(i - 2, 0); + prints("¥Ø«eªO¥D¬° %s\n½Ð¿é¤J·sªºªO¥D¦W³æ¡A©Î«ö [Return] ¤£§ï", brd->BM); + + strcpy(buf, brd->BM); + BMlen = strlen(buf); + + while (vget(i, 0, "½Ð¿é¤JªO¥D¡Aµ²§ô½Ð«ö Enter¡A²M±¼©Ò¦³ªO¥D½Ð¥´¡uµL¡v¡G", userid, IDLEN + 1, DOECHO)) + { + if (!strcmp(userid, "µL")) + { + buf[0] = '\0'; + BMlen = 0; + } + else if (is_bm(buf, userid)) /* §R°£Â¦³ªºªO¥D */ + { + len = strlen(userid); + if (BMlen == len) + { + buf[0] = '\0'; + } + else if (!str_cmp(buf + BMlen - len, userid)) /* ¦W³æ¤W³Ì«á¤@¦ì¡AID «á±¤£±µ '/' */ + { + buf[BMlen - len - 1] = '\0'; /* §R°£ ID ¤Î«e±ªº '/' */ + len++; + } + else /* ID «á±·|±µ '/' */ + { + str_lower(userid, userid); + strcat(userid, "/"); + len++; + brdname = str_str(buf, userid); + strcpy(brdname, brdname + len); + } + BMlen -= len; + } + else if (acct_load(&acct, userid) >= 0 && !is_bm(buf, userid)) /* ¿é¤J·sªO¥D */ + { + len = strlen(userid); + if (BMlen) + { + len++; /* '/' + userid */ + if (BMlen + len > BMLEN) + { + vmsg("ªO¥D¦W³æ¹Lªø¡AµLªk±N³o ID ³]¬°ªO¥D"); + continue; + } + sprintf(buf + BMlen, "/%s", acct.userid); + BMlen += len; + } + else + { + strcpy(buf, acct.userid); + BMlen = len; + } + + acct_setperm(&acct, PERM_BM, 0); + } + move(i - 2, 0); + prints("¥Ø«eªO¥D¬° %s", buf); + clrtoeol(); + } + strcpy(brd->BM, buf); + } + +#ifdef HAVE_MODERATED_BOARD + /* itoc.011208: §ï¥Î¸û«K§Qªº¬ÝªOÅv³]©w */ + switch (vget(++i, 0, "¬ÝªOÅv A)¤@¯ë B)¦Û©w C)¯µ±K D)¦n¤Í E)¯¸°ÈÁôª©¡H[Q] ", buf, 3, LCECHO)) + { + case 'c': + brd->readlevel = PERM_SYSOP; /* ¯µ±K¬ÝªO */ + brd->postlevel = 0; + brd->battr |= (BRD_NOSTAT | BRD_NOVOTE); + break; + + case 'd': + brd->readlevel = PERM_BOARD; /* ¦n¤Í¬ÝªO */ + brd->postlevel = 0; + brd->battr |= (BRD_NOSTAT | BRD_NOVOTE); + break; + +#else + + + switch (vget(++i, 0, "¬ÝªOÅv A)¤@¯ë B)¦Û©w E)¯¸°ÈÁôªO¡H[Q] ", buf, 3, LCECHO)) + { +#endif + + case 'a': + brd->readlevel = 0; + brd->postlevel = PERM_POST; /* ¤@¯ë¬ÝªOµoªíÅv¬° PERM_POST */ + brd->battr &= ~(BRD_NOSTAT | BRD_NOVOTE); /* ®³±¼¦n¤Í¡®¯µ±KªOÄÝ©Ê */ + break; + + case 'e': /* ¯¸°ÈÁôªO */ + brd->readlevel = (PERM_REGISTRAR | PERM_ACCOUNTS | PERM_CHATROOM | PERM_BOARD | PERM_SYSOP); + brd->postlevel = PERM_SYSOP; + brd->battr |= (BRD_NOSTAT | BRD_NOVOTE); + break; + + case 'b': + if (vget(++i, 0, "¾\\ŪÅv(Y/N)¡H[N] ", buf, 3, LCECHO) == 'y') + { + brd->readlevel = bitset(brd->readlevel, NUMPERMS, NUMPERMS, MSG_READPERM, perm_tbl); + move(2, 0); + clrtobot(); + i = 1; + } + + if (vget(++i, 0, "µoªíÅv(Y/N)¡H[N] ", buf, 3, LCECHO) == 'y') + { + brd->postlevel = bitset(brd->postlevel, NUMPERMS, NUMPERMS, MSG_POSTPERM, perm_tbl); + move(2, 0); + clrtobot(); + i = 1; + } + break; + + default: /* ¹w³]¤£ÅÜ°Ê */ + break; + } + + if (vget(++i, 0, "³]©wÄÝ©Ê(Y/N)¡H[N] ", buf, 3, LCECHO) == 'y') + brd->battr = bitset(brd->battr, NUMBATTRS, NUMBATTRS, MSG_BRDATTR, battr_tbl); + + return 0; +} + + +int /* 0:¶}ªO¦¨¥\ -1:¶}ªO¥¢±Ñ */ +brd_new(brd) + BRD *brd; +{ + int bno; + char fpath[64]; + + vs_bar("«Ø¥ß·sªO"); + + if (brd_set(brd, 1)) + return -1; + + if (vans(msg_sure_ny) != 'y') + return -1; + + time(&brd->bstamp); + if ((bno = brd_bno("")) >= 0) + { + rec_put(FN_BRD, brd, sizeof(BRD), bno, NULL); + } + /* Thor.981102: ¨¾¤î¶W¹Lshm¬ÝªOÓ¼Æ */ + else if (bshm->number >= MAXBOARD) + { + vmsg("¶W¹L¨t²Î©Ò¯à®e¯Ç¬ÝªOӼơA½Ð½Õ¾ã¨t²Î°Ñ¼Æ"); + return -1; + } + else if (rec_add(FN_BRD, brd, sizeof(BRD)) < 0) + { + vmsg("µLªk«Ø¥ß·sªO"); + return -1; + } + + gem_fpath(fpath, brd->brdname, NULL); + mak_dirs(fpath); + mak_dirs(fpath + 4); + + bshm_reload(); /* force reload of bcache */ + + brh_save(); + board_main(); /* reload brd_bits[] */ + + alog("·s¼W¬ÝªO",brd->brdname); + + return 0; +} + + +static void +brd_classchange(folder, oldname, newbrd) /* itoc.020117: ²§°Ê @Class ¤¤ªº¬ÝªO */ + char *folder; + char *oldname; + BRD *newbrd; /* Y¬° NULL¡Aªí¥Ün§R°£¬ÝªO */ +{ + int pos, xmode; + char fpath[64]; + HDR hdr; + + pos = 0; + while (!rec_get(folder, &hdr, sizeof(HDR), pos)) + { + xmode = hdr.xmode & (GEM_BOARD | GEM_FOLDER); + + if (xmode == (GEM_BOARD | GEM_FOLDER)) /* ¬ÝªOºëµØ°Ï±¶®| */ + { + if (!strcmp(hdr.xname, oldname)) + { + if (newbrd) /* ¬ÝªO§ó¦W */ + { + brd2gem(newbrd, &hdr); + rec_put(folder, &hdr, sizeof(HDR), pos, NULL); + } + else /* ¬ÝªO§R°£ */ + { + rec_del(folder, sizeof(HDR), pos, NULL); + continue; /* rec_del ¥H«á¤£»Ýn pos++ */ + } + } + } + else if (xmode == GEM_FOLDER) /* ¤ÀÃþ recursive ¶i¥h¬å */ + { + hdr_fpath(fpath, folder, &hdr); + brd_classchange(fpath, oldname, newbrd); + } + pos++; + } +} + + +void +brd_edit(bno) + int bno; +{ + BRD *bhdr, newbh; + char *bname, src[64], dst[64];; + char fpath[64]; + + vs_bar("¬ÝªO³]©w"); + bhdr = bshm->bcache + bno; + memcpy(&newbh, bhdr, sizeof(BRD)); + prints("¬ÝªO¦WºÙ¡G%s\n¬ÝªO»¡©ú¡G[%s] %s\nªO¥D¦W³æ¡G%s\n", + newbh.brdname, newbh.class, newbh.title, newbh.BM); + + bitmsg(MSG_READPERM, STR_PERM, newbh.readlevel); + bitmsg(MSG_POSTPERM, STR_PERM, newbh.postlevel); + bitmsg(MSG_BRDATTR, STR_BATTR, newbh.battr); + + switch (vget(8, 0, "(D)§R°£ (E)³]©w (L)Âê©w (Q)¨ú®ø¡H[Q] ", src, 3, LCECHO)) + { + case 'd': + + if (vget(9, 0, msg_sure_ny, src, 3, LCECHO) != 'y') + { + vmsg(MSG_DEL_CANCEL); + } + else + { + bname = bhdr->brdname; + if (*bname) /* itoc.000512: ¦P®É¬å°£¦P¤@ӬݪO·|³y¦¨ºëµØ°Ï¡B¬ÝªO¥þ·´ */ + { + alog("§R°£¬ÝªO", bname); + + gem_fpath(src, bname, NULL); + f_rm(src); + f_rm(src + 4); + brd_classchange("gem/@/@"CLASS_INIFILE, bname, NULL); /* itoc.020117: §R°£ @Class ¤¤ªº¬ÝªOºëµØ°Ï±¶®| */ + memset(&newbh, 0, sizeof(BRD)); + sprintf(newbh.title, "[%s] deleted by %s", bname, cuser.userid); + memcpy(bhdr, &newbh, sizeof(BRD)); + rec_put(FN_BRD, &newbh, sizeof(BRD), bno, NULL); + + /* itoc.050531: ¬åªO·|³y¦¨¬ÝªO¤£¬O«ö¦r¥À±Æ§Ç¡A©Ò¥Hn×¥¿ numberOld */ + if (bshm->numberOld > bno) + bshm->numberOld = bno; + + vmsg("§RªO§¹²¦"); + } + } + break; + + case 'l': + brd_fpath(fpath, bhdr->brdname, fn_lock); + brd_editlock(fpath); + break; + + case 'e': + + move(9, 0); + outs("ª½±µ«ö [Return] ¤£×§ï¸Ó¶µ³]©w"); + + BRD saveold; + + if (!brd_set(&newbh, 11)) + { + if (memcmp(&newbh, bhdr, sizeof(BRD)) && vans(msg_sure_ny) == 'y') + { + saveold = *bhdr; + bname = bhdr->brdname; + if (strcmp(bname, newbh.brdname)) /* ¬ÝªO§ó¦Wn²¾¥Ø¿ý */ + { + /* Thor.980806: ¯S§Oª`·N¦pªG¬ÝªO¤£¦b¦P¤@partition¸Ìªº¸Ü·|¦³°ÝÃD */ + gem_fpath(src, bname, NULL); + gem_fpath(dst, newbh.brdname, NULL); + rename(src, dst); + rename(src + 4, dst + 4); + brd_classchange("gem/@/@"CLASS_INIFILE, bname, &newbh);/* itoc.050329: ²§°Ê @Class ¤¤ªº¬ÝªOºëµØ°Ï±¶®| */ + + /* itoc.050520: §ï¤FªO¦W·|³y¦¨¬ÝªO¤£¬O«ö¦r¥À±Æ§Ç¡A©Ò¥Hn×¥¿ numberOld */ + if (bshm->numberOld > bno) + bshm->numberOld = bno; + } + memcpy(bhdr, &newbh, sizeof(BRD)); + rec_put(FN_BRD, &newbh, sizeof(BRD), bno, NULL); + brd_log(&saveold,&newbh); + } + } + vmsg("³]©w§¹²¦"); + break; + } +} + + +void +brd_title(bno) /* itoc.000312: ªO¥Dק襤¤å±Ôz */ + int bno; +{ + BRD *bhdr, newbh; + char *blist; + + bhdr = bshm->bcache + bno; + memcpy(&newbh, bhdr, sizeof(BRD)); + + blist = bhdr->BM; + + if (blist[0] > ' ' && is_bm(blist, cuser.userid)) + { + if (vans("¬O§_ק襤¤åªO¦W±Ôz(Y/N)¡H[N] ") == 'y') + { + vget(b_lines, 0, "¬ÝªO¥DÃD¡G", newbh.title, BTLEN + 1, GCARRY); + memcpy(bhdr, &newbh, sizeof(BRD)); + rec_put(FN_BRD, &newbh, sizeof(BRD), bno, NULL); + } + } +} diff --git a/maple/bbsd.c b/maple/bbsd.c new file mode 100644 index 0000000..986ea4b --- /dev/null +++ b/maple/bbsd.c @@ -0,0 +1,1663 @@ +/*-------------------------------------------------------*/ +/* bbsd.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* author : opus.bbs@bbs.cs.nthu.edu.tw */ +/* target : BBS daemon/main/login/top-menu routines */ +/* create : 95/03/29 */ +/* update : 96/10/10 */ +/*-------------------------------------------------------*/ + + +#define _MAIN_C_ + + +#include "bbs.h" +#include "dns.h" + + +#include <sys/wait.h> +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/telnet.h> +#include <sys/resource.h> + + +#define QLEN 3 +#define PID_FILE "run/bbs.pid" +#define LOG_FILE "run/bbs.log" +#undef SERVER_USAGE + +static int myports[MAX_BBSDPORT] = BBSD_PORT; + +static pid_t currpid; + +extern BCACHE *bshm; +extern UCACHE *ushm; + +/* static int mport; */ /* Thor.990325: ¤£»Ýn¤F:P */ +static u_long tn_addr; + + +#ifdef CHAT_SECURE +char passbuf[PSWDLEN + 1]; +#endif + + +#ifdef MODE_STAT +extern UMODELOG modelog; +extern time_t mode_lastchange; +#endif + + +/* ----------------------------------------------------- */ +/* Â÷¶} BBS µ{¦¡ */ +/* ----------------------------------------------------- */ + + + void +alog(mode, msg) /* Admin ¦æ¬°°O¿ý */ + char *mode, *msg; +{ + char buf[512]; + + sprintf(buf, "%s %s %-13s%s\n", Now(), mode, cuser.userid, msg); + f_cat(FN_RUN_ADMIN, buf); +} + + + void +blog(mode, msg) /* BBS ¤@¯ë°O¿ý */ + char *mode, *msg; +{ + char buf[512]; + + sprintf(buf, "%s %s %-13s%s\n", Now(), mode, cuser.userid, msg); + f_cat(FN_RUN_USIES, buf); +} + + void +cclog(mode, msg) /* ÅvÁʶR°O¿ý */ + char *mode, *msg; +{ + char buf[512]; + + sprintf(buf, "%s %s %-13s%s\n", Now(), mode, cuser.userid, msg); + f_cat("run/buyperm.log", buf); +} + + +#ifdef MODE_STAT + void +log_modes() +{ + time(&modelog.logtime); + rec_add(FN_RUN_MODE_CUR, &modelog, sizeof(UMODELOG)); +} +#endif + + + void +u_exit(mode) + char *mode; +{ + int fd, diff; + char fpath[80]; + ACCT tuser; + + if (currbno >= 0 && bshm->mantime[currbno] > 0) + bshm->mantime[currbno]--; /* °h¥X³Ì«á¬Ýªº¨ºÓªO */ + + utmp_free(cutmp); /* ÄÀ©ñ UTMP shm */ + + diff = (time(&cuser.lastlogin) - ap_start) / 60; + sprintf(fpath, "Stay: %d (%d)", diff, currpid); + blog(mode, fpath); + + if (cuser.userlevel) + { + ve_backup(); /* ½s¿è¾¹¦Û°Ê³Æ¥÷ */ + brh_save(); /* Àx¦s¾\Ū°O¿ýÀÉ */ + } + +#ifndef LOG_BMW /* Â÷¯¸§R°£¤ô²y */ + usr_fpath(fpath, cuser.userid, fn_amw); + unlink(fpath); + usr_fpath(fpath, cuser.userid, fn_bmw); + unlink(fpath); +#endif + +#ifdef MODE_STAT + log_modes(); +#endif + + + /* ¼g¦^ .ACCT */ + + if (!HAS_STATUS(STATUS_DATALOCK)) /* itoc.010811: ¨S¦³³Q¯¸ªøÂê©w¡A¤~¥i¥H¦^¦s .ACCT */ + { + usr_fpath(fpath, cuser.userid, fn_acct); + fd = open(fpath, O_RDWR); + if (fd >= 0) + { + if (read(fd, &tuser, sizeof(ACCT)) == sizeof(ACCT)) + { + if (diff >= 1) + { + cuser.numlogins++; /* Thor.980727.µù¸Ñ: ¦b¯¸¤W¥¼¶W¹L¤@¤ÀÄÁ¤£¤©pºâ¦¸¼Æ */ + addmoney(diff); /* itoc.010805: ¤W¯¸¤@¤ÀÄÁ¥[¤@¤¸ */ + } + + if (HAS_STATUS(STATUS_COINLOCK)) /* itoc.010831: Y¬O multi-login ªº²Ä¤G°¦¥H«á¡A¤£Àx¦s¿ú¹ô */ + { + cuser.money = tuser.money; + cuser.gold = tuser.gold; + } + + /* itoc.010811.µù¸Ñ: ¦pªG¨Ï¥ÎªÌ¦b½u¤W¨S¦³»{ÃÒªº¸Ü¡A + ¨º»ò cuser ¤Î tuser ªº userlevel/tvalid ¬O¦P¨Bªº¡F + ¦ýY¨Ï¥ÎªÌ¦b½u¤W¦^»{ÃÒ«H/¶ñ»{ÃÒ½X/³Q¯¸ªø¼f®Öµù¥U³æ..µ¥»{ÃÒ³q¹Lªº¸Ü¡A + ¨º»ò tuser ªº userlevel/tvalid ¤~¬O¤ñ¸û·sªº */ + cuser.userlevel = tuser.userlevel; + cuser.tvalid = tuser.tvalid; + + lseek(fd, (off_t) 0, SEEK_SET); + write(fd, &cuser, sizeof(ACCT)); + } + close(fd); + } + } +} + + + void +abort_bbs() +{ + if (bbstate) + u_exit("AXXED"); + exit(0); +} + + + static void +login_abort(msg) + char *msg; +{ + outs(msg); + refresh(); + exit(0); +} + + +/* Thor.980903: lkchu patch: ¤£¨Ï¥Î¤W¯¸¥Ó½Ð±b¸¹®É, «h¤U¦C function§¡¤£¥Î */ + +#ifdef LOGINASNEW + +/* ----------------------------------------------------- */ +/* Àˬd user µù¥U±¡ªp */ +/* ----------------------------------------------------- */ + + + static int +belong(flist, key) + char *flist; + char *key; +{ + int fd, rc; + + rc = 0; + if ((fd = open(flist, O_RDONLY)) >= 0) + { + mgets(-1); + + while (flist = mgets(fd)) + { + str_lower(flist, flist); + if (str_str(key, flist)) + { + rc = 1; + break; + } + } + + close(fd); + } + return rc; +} + + + static int +is_badid(userid) + char *userid; +{ + int ch; + char *str; + + if (strlen(userid) < 2) + return 1; + + if (!is_alpha(*userid)) + return 1; + + if (!str_cmp(userid, STR_NEW)) + return 1; + + str = userid; + while (ch = *(++str)) + { + if (!is_alnum(ch)) + return 1; + } + return (belong(FN_ETC_BADID, userid)); +} + + + static int +uniq_userno(fd) + int fd; +{ + char buf[4096]; + int userno, size; + SCHEMA *sp; /* record length 16 ¥i¾ã°£ 4096 */ + + userno = 1; + + while ((size = read(fd, buf, sizeof(buf))) > 0) + { + sp = (SCHEMA *) buf; + do + { + if (sp->userid[0] == '\0') + { + lseek(fd, -size, SEEK_CUR); + return userno; + } + userno++; + size -= sizeof(SCHEMA); + sp++; + } while (size); + } + + return userno; +} + + + static void +acct_apply() +{ + SCHEMA slot; + char buf[80]; + char *userid; + int try, fd; + + film_out(FILM_APPLY, 0); + + memset(&cuser, 0, sizeof(ACCT)); + userid = cuser.userid; + try = 0; + for (;;) + { + if (!vget(18, 0, msg_uid, userid, IDLEN + 1, DOECHO)) + login_abort("\n¦A¨£ ..."); + + if (is_badid(userid)) + { + vmsg("µLªk±µ¨ü³oÓ¥N¸¹¡A½Ð¨Ï¥Î^¤å¦r¥À¡A¨Ã¥B¤£n¥]§tªÅ®æ"); + } + else + { + usr_fpath(buf, userid, NULL); + if (dashd(buf)) + vmsg("¦¹¥N¸¹¤w¸g¦³¤H¨Ï¥Î"); + else + break; + } + + if (++try >= 10) + login_abort("\n±z¹Á¸Õ¿ù»~ªº¿é¤J¤Ó¦h¡A½Ð¤U¦¸¦A¨Ó§a"); + } + + for (;;) + { + vget(19, 0, "½Ð³]©w±K½X¡G", buf, PSWDLEN + 1, NOECHO); + if ((strlen(buf) < 4) || !strcmp(buf, userid)) + { + vmsg("±K½X¤Ó²³æ¡A©ö¾D¤J«I¡A¦Ü¤Ön 4 Ó¦r¡A½Ð«·s¿é¤J"); + continue; + } + + vget(20, 0, "½ÐÀˬd±K½X¡G", buf + PSWDLEN + 2, PSWDLEN + 1, NOECHO); + if (!strcmp(buf, buf + PSWDLEN + 2)) + break; + + vmsg("±K½X¿é¤J¿ù»~, ½Ð«·s¿é¤J±K½X"); + } + + str_ncpy(cuser.passwd, genpasswd(buf), sizeof(cuser.passwd)); + + do + { + vget(20, 0, "¼Ê ºÙ¡G", cuser.username, UNLEN + 1, DOECHO); + } while (strlen(cuser.username) < 2); + + // /* itoc.010317: ´£¥Ü user ¥H«á±N¤£¯à§ï©m¦W */ + // vmsg("ª`·N¡G½Ð¿é¤J¯u¹ê©m¦W¡A¥»¯¸¤£´£¨Ñ×§ï©m¦Wªº¥\\¯à"); + + do + { + vget(21, 0, "¯u¹ê©m¦W¡G", cuser.realname, RNLEN + 1, DOECHO); + } while (strlen(cuser.realname) < 4); + +#if 0 + char year; /* ¥Í¤é(¥Á°ê¦~) */ + char month; /* ¥Í¤é(¤ë) */ + char day; /* ¥Í¤é(¤é) */ + +#endif + + int year; + do + { + vget(22, 0, "¥X¥Í¦~(¥Á°ê)¡G", buf, 4, DOECHO); + year = atoi(buf); + } while (year < 1 || year > 255); + + cuser.year = year; + + do + { + vget (22, 18, "¥X¥Í¤ë¡G", buf, 3, DOECHO); + cuser.month = atoi(buf); + } while (cuser.month < 1 || cuser.month > 12); + + do + { + vget (22, 30, "¥X¥Í¤é¡G", buf, 3, DOECHO); + cuser.day = atoi(buf); + } while (cuser.day < 1 || cuser.day > 31); + + do + { + vget (23, 0, "©Ê§O (0)¤¤©Ê (1)¨k©Ê (2)¤k©Ê¡G", buf, 2, DOECHO); + cuser.sex = atoi(buf); + } while (cuser.sex < 0 || cuser.sex > 2); + + cuser.userlevel = PERM_DEFAULT; + cuser.ufo = UFO_DEFAULT_NEW; + cuser.numlogins = 1; + cuser.tvalid = ap_start; /* itoc.030724: ®³¤W¯¸®É¶¡·í²Ä¤@¦¸»{ÃÒ½Xªº seed */ + sprintf(cuser.email, "%s.bbs@%s", cuser.userid, str_host); /* itoc.010902: ¹w³] email */ + + /* Ragnarok.050528: ¥i¯à¤G¤H¦P®É¥Ó½Ð¦P¤@Ó ID¡A¦b¦¹¥²¶·¦AÀˬd¤@¦¸ */ + usr_fpath(buf, userid, NULL); + if (dashd(buf)) + { + vmsg("¦¹¥N¸¹è³Qµù¥U¨«¡A½Ð«·s¥Ó½Ð"); + abort_bbs(); + } + + /* dispatch unique userno */ + + cuser.firstlogin = cuser.lastlogin = cuser.tcheck = slot.uptime = ap_start; + memcpy(slot.userid, userid, IDLEN); + + fd = open(FN_SCHEMA, O_RDWR | O_CREAT, 0600); + { + /* flock(fd, LOCK_EX); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_exlock(fd); + + cuser.userno = try = uniq_userno(fd); + write(fd, &slot, sizeof(slot)); + /* flock(fd, LOCK_UN); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_unlock(fd); + } + close(fd); + + /* create directory */ + + /* usr_fpath(buf, userid, NULL); */ /* è°µ¹L */ + mkdir(buf, 0700); + strcat(buf, "/@"); + mkdir(buf, 0700); + usr_fpath(buf, userid, "gem"); /* itoc.010727: Ó¤HºëµØ°Ï */ + /* mak_dirs(buf); */ + mak_links(buf); /* itoc.010924: ´î¤ÖÓ¤HºëµØ°Ï¥Ø¿ý */ +#ifdef MY_FAVORITE + usr_fpath(buf, userid, "MF"); + mkdir(buf, 0700); +#endif + + usr_fpath(buf, userid, fn_acct); + fd = open(buf, O_WRONLY | O_CREAT, 0600); + write(fd, &cuser, sizeof(ACCT)); + close(fd); + /* Thor.990416: ª`·N: «ç»ò·|¦³ .ACCTªø«×¬O0ªº, ¦Ó¥B¥u¦³ @¥Ø¿ý, «ùÄòÆ[¹î¤¤ */ + + sprintf(buf, "%d", try); + blog("APPLY", buf); +} + +#endif /* LOGINASNEW */ + + +/* ----------------------------------------------------- */ +/* bad login */ +/* ----------------------------------------------------- */ + + +#define FN_BADLOGIN "logins.bad" + + static void +logattempt(type, content) + int type; /* '-' login failure ' ' success */ + char *content; +{ + char buf[128], fpath[64]; + + sprintf(buf, "%s %c %s\n", Btime(&ap_start), type, content); + + usr_fpath(fpath, cuser.userid, FN_LOG); + f_cat(fpath, buf); + + if (type != ' ') + { + usr_fpath(fpath, cuser.userid, FN_BADLOGIN); + sprintf(buf, "[%s] %s\n", Btime(&ap_start), fromhost); + f_cat(fpath, buf); + } +} + + +/* ----------------------------------------------------- */ +/* µn¿ý BBS µ{¦¡ */ +/* ----------------------------------------------------- */ + + +extern void talk_rqst(); +extern void bmw_rqst(); + + +#ifdef HAVE_WHERE +//static + int /* 1:¦blist¤¤ 0:¤£¦blist¤¤ */ +belong_list(filelist, key, desc) + char *filelist, *key, *desc; +{ + FILE *fp; + char buf[80], *str; + int rc; + + rc = 0; + if (fp = fopen(filelist, "r")) + { + while (fgets(buf, sizeof(buf), fp)) + { + if (buf[0] == '#') + continue; + + if (str = (char *) strchr(buf, ' ')) + { + *str = '\0'; + if (strstr(key, buf)) + { + /* ¸õ¹LªÅ¥Õ¤À¹j */ + for (str++; *str && isspace(*str); str++) + ; + + strcpy(desc, str); + if (str = (char *) strchr(desc, '\n')) /* ³Ì«áªº '\n' ¤£n */ + *str = '\0'; + rc = 1; + break; + } + } + } + fclose(fp); + } + return rc; +} +#endif + + + static void +utmp_setup(mode) + int mode; +{ + UTMP utmp; + uschar *addr; + + memset(&utmp, 0, sizeof(utmp)); + + utmp.pid = currpid; + utmp.userno = cuser.userno; + utmp.mode = bbsmode = mode; + /* utmp.in_addr = tn_addr; */ /* itoc.010112: §ïÅÜumtp.in_addr¥H¨Ïulist_cmp_host¥¿±` */ + addr = (uschar *) &tn_addr; + utmp.in_addr = (addr[0] << 24) + (addr[1] << 16) + (addr[2] << 8) + addr[3]; + utmp.userlevel = cuser.userlevel; /* itoc.010309: §â userlevel ¤]©ñ¤J cache */ + utmp.ufo = cuser.ufo; + utmp.status = 0; + + strcpy(utmp.userid, cuser.userid); + strcpy(utmp.realid, cuser.userid); +#ifdef DETAIL_IDLETIME + utmp.idle_time = ap_start; +#endif + +#ifdef GUEST_NICK + if (!cuser.userlevel) /* guest */ + { + char nick[9][5] = {"¹C¤l", "¤ôºw", "³X«È", "¸É©«", "½ÞÀY", "¼v¤l", "¯f¬r", "µ£¦~", "¥Û¹³"}; + sprintf(cuser.username, "¤Ó¶§¤Uªº%s", nick[ap_start % 9]); + } +#endif /* GUEST_NICK */ + + strcpy(utmp.username, cuser.username); + +#ifdef HAVE_WHERE + +# ifdef GUEST_WHERE + if (!cuser.userlevel) /* guest */ + { + /* itoc.010910: GUEST_NICK ©M GUEST_WHERE ªº¶Ã¼Æ¼Ò¼ÆÁ×§K¤@¼Ë */ + char from[16][9] = {"·«F¤E«ä", "«C®H´Â¶§", "²v·N³qÅü", "«n¥x»·²·", "±d²øªïÄf", "ºÑ¯ó¦p¯ô", "½t¼z¼í¥Í", "¦è®x¯º»y", + "¥É¾ð¦Vºa", "ºñ±»«¼Ó", "ªQªL¥ß»A", "¦Ë´ò±á·", "¦Ë¶é¬M«F", "¦±¹D§¨½®", "²ü¶í¤ë¦â", "«ä¶é¬K¾å"}; + strcpy(utmp.from, from[ap_start % 16]); + } + else +# endif /* GUEST_WHERE */ + { + + /* ¹³ hinet ³oºØ ip «Ü¦h¡A DN «Ü¤Öªº¡A´N¼g¤J etc/fqdn * + * ¹³ 140.112. ³oºØ´N¼g¦b etc/host * + * §Y¨Ï DNS Äê±¼¡A¦b etc/host ¸Ì±ªºÁÙ¬O¥i¥H·Ó¼Ë§PÂ_¦¨¥\ * + * ¦pªG§â 140.112. ¼g¤J etc/host ¤¤¡A´N¤£¥Î§â ntu.edu.tw * + * «Âмg¤J etc/fqdn ¸Ì¤F */ + + char name[48]; + + /* ¥ý¤ñ¹ï ID */ + str_lower(name, cuser.userid); + if (!belong_list(FN_ETC_IDHOME, name, utmp.from)) + { + /* ¦A¤ñ¹ï FQDN */ + str_lower(name, fromhost); /* itoc.011011: ¤j¤p¼g§¡¥i¡Aetc/fqdn ¸Ì±³£n¼g¤p¼g */ + if (!belong_list(FN_ETC_FQDN, name, utmp.from)) + { + /* ¦A¤ñ¹ï ip */ + sprintf(name, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); + if (!belong_list(FN_ETC_HOST, name, utmp.from)) + str_ncpy(utmp.from, fromhost, sizeof(utmp.from)); /* ¦pªG³£¨S§ä¨ì¹ïÀ³¬G¶m¡A´N¬O¥Î fromhost */ + } + } + } + +#else + str_ncpy(utmp.from, fromhost, sizeof(utmp.from)); +#endif /* HAVE_WHERE */ + + /* Thor: §i¶DUser¤w¸gº¡¤F©ñ¤£¤U... */ + if (!utmp_new(&utmp)) + login_abort("\n±zèè¿ïªº¦ì¤l¤w¸g³Q¤H±¶¨¬¥ýµn¤F¡A½Ð¤U¦¸¦A¨Ó§a"); + + /* itoc.001223: utmp_new §¹¦A pal_cache¡A¦pªG login_abort ´N¤£°µ¤F */ + pal_cache(); +} + + +/* ----------------------------------------------------- */ +/* user login */ +/* ----------------------------------------------------- */ + + + static int /* ¦^¶Ç multi */ +login_user(content) + char *content; +{ + int attempts; /* ¹Á¸Õ´X¦¸¿ù»~ */ + int multi; + char fpath[64], uid[IDLEN + 1]; +#ifndef CHAT_SECURE + char passbuf[PSWDLEN + 1]; +#endif + + move(b_lines, 0); + time_t now = time(NULL); + if (now >= 1301587200 && now <= 1301673600) /* ·M¤H¸`pµe */ + { + outs("\033[1;44m ¡° ¥»¯¸¤£¶}©ñ \033[1;32m" STR_GUEST "\033[1;37m °ÑÆ[" + " ¥Ó½Ð·s±b¸¹¡G\033[1;31m" STR_NEW "\033[1;44m \033[m"); + } + else + { + outs(" ¡° ¥»¯¸¤£¶}©ñ \033[1;32m" STR_GUEST "\033[m °ÑÆ[" + " ¥Ó½Ð·s±b¸¹¡G\033[1;31m" STR_NEW "\033[m"); + } + attempts = 0; + multi = 0; + for (;;) + { + if (++attempts > LOGINATTEMPTS) + { + film_out(FILM_TRYOUT, 0); + login_abort("\n¦A¨£ ..."); + } + + time_t now = time(NULL); + if (now >= 1301587200 && now <= 1301673600) /* ·M¤H¸` */ + { + vget(b_lines - 2, 0, " [Login ID] ", uid, IDLEN + 1, DOECHO); + } + else + { + vget(b_lines - 2, 0, " [±zªº±b¸¹] ", uid, IDLEN + 1, DOECHO); + } + + if (!str_cmp(uid, STR_NEW)) + { +#ifdef LOGINASNEW +# ifdef HAVE_GUARANTOR /* itoc.000319: «OÃÒ¤H¨î«× */ + vget(b_lines - 2, 0, " [±zªº«O¤H] ", uid, IDLEN + 1, DOECHO); + if (!*uid || (acct_load(&cuser, uid) < 0)) + { + vmsg("©êºp¡A¨S¦³¤¶²Ð¤H¤£±o¥[¤J¥»¯¸"); + } + else if (!HAS_PERM(PERM_GUARANTOR)) + { + vmsg("©êºp¡A±z¤£°÷¸ê®æ¾á¥ô§O¤Hªº¤¶²Ð¤H"); + } + else if (!vget(b_lines - 2, 40, "[«O¤H±K½X] ", passbuf, PSWDLEN + 1, NOECHO)) + { + continue; + } + else + { + if (chkpasswd(cuser.passwd, passbuf)) + { + logattempt('-', content); + vmsg(ERR_PASSWD); + } + else + { + FILE *fp; + char parentid[IDLEN + 1], buf[80]; + time_t now; + + /* itoc.010820: °O¿ý«O¤H©ó«OÃÒ¤H¤Î³Q«O¤H */ + strcpy(parentid, cuser.userid); + acct_apply(); + time(&now); + + /* itoc.010820.µù¸Ñ: §â¹ï¤è log ¦b¦æº¡A¦b reaper ®É¥i¥H¤è«K¬å tree */ + sprintf(buf, "%s ©ó %s ¤¶²Ð¦¹¤H(%s)¥[¤J¥»¯¸\n", parentid, Btime(&now), cuser.userid); + usr_fpath(fpath, cuser.userid, "guarantor"); + if (fp = fopen(fpath, "a")) + { + fputs(buf, fp); + fclose(fp); + } + sprintf(buf, "%s ©ó %s ³Q¦¹¤H(%s)¤¶²Ð¥[¤J¥»¯¸\n", cuser.userid, Btime(&now), parentid); + usr_fpath(fpath, parentid, "guarantor"); + if (fp = fopen(fpath, "a")) + { + fputs(buf, fp); + fclose(fp); + } + + break; + } + } +# else + acct_apply(); /* Thor.980917: µù¸Ñ: setup cuser ok */ + break; +# endif +#else + outs("\n¥»¨t²Î¥Ø«e¼È°±½u¤Wµù¥U, ½Ð¥Î " STR_GUEST " ¶i¤J"); + continue; +#endif + } + else if (!*uid) + { + /* Y¨S¿é¤J ID¡A¨º»ò continue */ + } + else if (str_cmp(uid, STR_GUEST)) /* ¤@¯ë¨Ï¥ÎªÌ */ + { + if (now >= 1301587200 && now <= 1301673600) /* ·M¤H¸` */ + { + if (!vget(b_lines - 2, 40, "[ÅçÃÒª÷Æ_] ", passbuf, PSWDLEN + 1, NOECHO)) + continue; /* ¤£¥´±K½X«h¨ú®øµn¤J */ + } + else + { + if (!vget(b_lines - 2, 40, "[±zªº±K½X] ", passbuf, PSWDLEN + 1, NOECHO)) + continue; /* ¤£¥´±K½X«h¨ú®øµn¤J */ + } + /* itoc.040110: ¦b¿é¤J§¹ ID ¤Î±K½X¡A¤~¸ü¤J .ACCT */ + if (acct_load(&cuser, uid) < 0) + { + vmsg(err_uid); + continue; + } + + if (chkpasswd(cuser.passwd, passbuf)) + { + logattempt('-', content); + vmsg(ERR_PASSWD); + } + else + { + + if (!str_cmp(cuser.userid, str_sysop)) + { +#ifdef SYSOP_SU + /* ²³æªº SU ¥\¯à */ + if (vans("Åܧó¨Ï¥ÎªÌ¨¤À(Y/N)¡H[N] ") == 'y') + { + for (;;) + { + if (vget(b_lines - 2, 0, " [Åܧó±b¸¹] ", uid, IDLEN + 1, DOECHO) && + acct_load(&cuser, uid) >= 0) + break; + vmsg(err_uid); + } + } + else +#endif + { + /* SYSOP gets all permission bits */ + /* itoc.010902: DENY perm ±Æ¥~ */ + // cuser.userlevel = ~0 ^ (PERM_DENYMAIL | PERM_DENYTALK | PERM_DENYCHAT | PERM_DENYPOST | PERM_DENYLOGIN | PERM_PURGE); + } + } + + if (cuser.ufo & UFO_ACL) + { + usr_fpath(fpath, cuser.userid, FN_ACL); + str_lower(fromhost, fromhost); /* lkchu.981201: ´«¤p¼g */ + if (!acl_has(fpath, "", fromhost)) + { /* Thor.980728: ª`·N acl Àɤ¤n¥þ³¡¤p¼g */ + logattempt('-', content); + login_abort("\n±zªº¤W¯¸¦aÂI¤£¤Ó¹ï«l¡A½Ð®Ö¹ï [¤W¯¸¦aÂI³]©wÀÉ]"); + } + } + + logattempt(' ', content); + + /* check for multi-session */ + + if (!HAS_PERM(PERM_ALLADMIN)) + { + UTMP *ui; + pid_t pid; + + if (HAS_PERM(PERM_DENYLOGIN | PERM_PURGE)) + login_abort("\n³oÓ±b¸¹¼È°±ªA°È¡A¸Ô±¡½Ð¦V¯¸ªø¬¢¸ß¡C"); + + + if (!(ui = (UTMP *) utmp_find(cuser.userno))) + break; /* user isn't logged in */ + + pid = ui->pid; + if (pid && vans("±z·Q½ð±¼¨ä¥L«½Æªº login (Y/N)¶Ü¡H[Y] ") != 'n' && pid == ui->pid) + { + if ((kill(pid, SIGTERM) == -1) && (errno == ESRCH)) + utmp_free(ui); + else + sleep(3); /* ³Q½ðªº¤H³o®ÉÔ¥¿¦b¦Û§Ú¤FÂ_ */ + blog("MULTI", cuser.userid); + } + + if ((multi = utmp_count(cuser.userno, 0)) >= MULTI_MAX || /* ½u¤W¤w¦³ MULTI_MAX °¦¦Û¤v¡A¸T¤îµn¤J */ + (!multi && acct_load(&cuser, uid) < 0)) /* yiting.050101: Yè¤w½ð±¼©Ò¦³ multi-login¡A¨º»ò«·sŪ¨ú¥H®M¥ÎÅܧó */ + login_abort("\n¦A¨£ ..."); + } + break; + } + } + else + { /* guest */ + vmsg("©êºp¡A¥»¯¸¤£¶}©ñ " STR_GUEST " °ÑÆ["); + continue; + } + } + + return multi; +} + + + static void +login_level() +{ + int fd; + usint level; + ACCT tuser; + char fpath[64]; + + /* itoc.010804.µù¸Ñ: ¦³ PERM_VALID ªÌ¦Û°Êµoµ¹ PERM_POST PERM_PAGE PERM_CHAT */ + level = cuser.userlevel | (PERM_ALLVALID ^ PERM_VALID); + + if (!(level & PERM_ALLADMIN)) + { +#ifdef JUSTIFY_PERIODICAL + if ((level & PERM_VALID) && (cuser.tvalid + VALID_PERIOD < ap_start)) + { + level ^= PERM_VALID; + /* itoc.011116: ¥D°Êµo«H³qª¾¨Ï¥ÎªÌ¡A¤@ª½°e«H¤£ª¾¹D·|¤£·|¤Ó¯ÓªÅ¶¡ !? */ + mail_self(FN_ETC_REREG, str_sysop, "±zªº»{ÃÒ¤w¸g¹L´Á¡A½Ð«·s»{ÃÒ", 0); + } +#endif + +#ifdef NEWUSER_LIMIT + /* §Y¨Ï¤w¸g³q¹L»{ÃÒ¡AÁÙ¬On¨£²ß¤T¤Ñ */ + if (ap_start - cuser.firstlogin < 3 * 86400) + level &= ~PERM_POST; +#endif + + /* itoc.000520: ¥¼¸g¨¤À»{ÃÒ, ¸T¤î post/chat/talk/write */ + if (!(level & PERM_VALID)) + level &= ~(PERM_POST | PERM_CHAT | PERM_PAGE); + + if (level & PERM_DENYPOST) + level &= ~PERM_POST; + + if (level & PERM_DENYTALK) + level &= ~PERM_PAGE; + + if (level & PERM_DENYCHAT) + level &= ~PERM_CHAT; + + if ((cuser.numemails >> 4) > (cuser.numlogins + cuser.numposts)) + level |= PERM_DENYMAIL; + } + + cuser.userlevel = level; + + usr_fpath(fpath, cuser.userid, fn_acct); + if ((fd = open(fpath, O_RDWR)) >= 0) + { + if (read(fd, &tuser, sizeof(ACCT)) == sizeof(ACCT)) + { + /* itoc.010805.µù¸Ñ: ³o¦¸ªº¼g¦^ .ACCT ¬O¬°¤FÅý§O¤H Query ½u¤W¨Ï¥ÎªÌ®É + ¥X²{ªº¤W¯¸®É¶¡/¨Ó·½¥¿½T¡A¥H¤Î¦^¦s¥¿½Tªº userlvel */ +tuser.userlevel = level; + tuser.lastlogin = ap_start; + strcpy(tuser.lasthost, cuser.lasthost); + + lseek(fd, (off_t) 0, SEEK_SET); + write(fd, &tuser, sizeof(ACCT)); + } + close(fd); + } +} + + + static void +login_status(multi) + int multi; +{ + usint status; + char fpath[64]; + struct tm *ptime; + + status = 0; + + /* itoc.010831: multi-login ªº²Ä¤G°¦¥[¤W¤£¥iÅܰʿú¹ôªººX¼Ð */ + if (multi) + status |= STATUS_COINLOCK; + + /* itoc.011022: ¥[¤J¥Í¤éºX¼Ð */ + ptime = localtime(&ap_start); + if (cuser.day == ptime->tm_mday && cuser.month == ptime->tm_mon + 1) + status |= STATUS_BIRTHDAY; + + /* ªB¤Í¦W³æ¦P¨B¡B²M²z¹L´Á«H¥ó */ + if (ap_start > cuser.tcheck + CHECK_PERIOD) + { + outz(MSG_CHKDATA); + refresh(); + + cuser.tcheck = ap_start; + usr_fpath(fpath, cuser.userid, fn_pal); + pal_sync(fpath); +#ifdef HAVE_ALOHA + usr_fpath(fpath, cuser.userid, FN_FRIENZ); + frienz_sync(fpath); +#endif +#ifdef OVERDUE_MAILDEL + status |= m_quota(); /* Thor.µù¸Ñ: ¸ê®Æ¾ã²z½]®Ö¦³¥]§t BIFF check */ +#endif + } +#ifdef OVERDUE_MAILDEL + else +#endif + status |= m_query(cuser.userid); + + /* itoc.010924: ÀˬdÓ¤HºëµØ°Ï¬O§_¹L¦h */ +#ifndef LINUX /* ¦b Linux ¤U³oÀˬd©Ç©Çªº */ + { + struct stat st; + usr_fpath(fpath, cuser.userid, "gem"); + if (!stat(fpath, &st) && (st.st_size >= 512 * 7)) + status |= STATUS_MGEMOVER; + } +#endif + + cutmp->status |= status; +} + + + static void +login_other() +{ + usint status; + char fpath[64]; + + /* §R°£¿ù»~µn¤J°O¿ý */ + usr_fpath(fpath, cuser.userid, FN_BADLOGIN); + if (more(fpath, (char *) -1) >= 0 && vans("¥H¤W¬°¿é¤J±K½X¿ù»~®Éªº¤W¯¸¦aÂI°O¿ý¡An§R°£¶Ü(Y/N)¡H[Y] ") != 'n') + unlink(fpath); + + if (!HAS_PERM(PERM_VALID)) + film_out(FILM_NOTIFY, -1); /* ©|¥¼»{ÃÒ³qª¾ */ +#ifdef JUSTIFY_PERIODICAL + else if (!HAS_PERM(PERM_ALLADMIN) && (cuser.tvalid + VALID_PERIOD - INVALID_NOTICE_PERIOD < ap_start)) + film_out(FILM_REREG, -1); /* ¦³®Ä®É¶¡¹O´Á 10 ¤Ñ«e´£¥Xĵ§i */ +#endif + +#ifdef NEWUSER_LIMIT + if (ap_start - cuser.firstlogin < 3 * 86400) + film_out(FILM_NEWUSER, -1); /* §Y¨Ï¤w¸g³q¹L»{ÃÒ¡AÁÙ¬On¨£²ß¤T¤Ñ */ +#endif + + status = cutmp->status; + +#ifdef OVERDUE_MAILDEL + if (status & STATUS_MQUOTA) + film_out(FILM_MQUOTA, -1); /* ¹L´Á«H¥ó§Y±N²M°£Äµ§i */ +#endif + + if (status & STATUS_MAILOVER) + film_out(FILM_MAILOVER, -1); /* «H¥ó¹L¦h©Î±H«H¹L¦h */ + + //if (status & STATUS_MGEMOVER) + //film_out(FILM_MGEMOVER, -1); /* itoc.010924: Ó¤HºëµØ°Ï¹L¦hĵ§i */ + + if (status & STATUS_BIRTHDAY) + film_out(FILM_BIRTHDAY, -1); /* itoc.010415: ¥Í¤é·í¤Ñ¤W¯¸¦³ special Åwªïµe± */ + + ve_recover(); /* ¤W¦¸Â_½u¡A½s¿è¾¹¦^¦s */ +} + + + static void +tn_login() +{ + int multi; + char buf[128]; + + bbsmode = M_LOGIN; /* itoc.020828: ¥H§K¹L¤[¥¼¿é¤J®É igetch ·|¥X²{ movie */ + + /* --------------------------------------------------- */ + /* µn¿ý¨t²Î */ + /* --------------------------------------------------- */ + + /* Thor.990415: °O¿ýip, ©È¥¿¬d¤£¨ì */ + sprintf(buf, "%s ip:%08x (%d)", fromhost, tn_addr, currpid); + + multi = login_user(buf); + + blog("ENTER", buf); + + /* --------------------------------------------------- */ + /* ªì©l¤Æ utmp¡Bflag¡Bmode¡B«H½c */ + /* --------------------------------------------------- */ + + bbstate = STAT_STARTED; /* ¶i¤J¨t²Î¥H«á¤~¥i¥H¦^¤ô²y */ + utmp_setup(M_LOGIN); /* Thor.980917: µù¸Ñ: cutmp, cutmp-> setup ok */ + total_user = ushm->count; /* itoc.011027: ¥¼¶i¨Ï¥ÎªÌ¦W³æ«e¡A±Ò©l¤Æ total_user */ + + mbox_main(); + +#ifdef MODE_STAT + memset(&modelog, 0, sizeof(UMODELOG)); + mode_lastchange = ap_start; +#endif + + if (cuser.userlevel) /* not guest */ + { + /* ------------------------------------------------- */ + /* ®Ö¹ï user level ¨Ã±N .ACCT ¼g¦^ */ + /* ------------------------------------------------- */ + + /* itoc.030929: ¦b .ACCT ¼g¦^¥H«e¡A¤£¥i¥H¦³¥ô¦ó vmsg(NULL) ©Î more(xxxx, NULL) + µ¥ªºªF¦è¡A³o¼Ë¦pªG user ¦b vmsg(NULL) ®É¦^»{ÃÒ«H¡A¤~¤£·|³Q¼g¦^ªº cuser »\¹L */ + + cuser.lastlogin = ap_start; + str_ncpy(cuser.lasthost, fromhost, sizeof(cuser.lasthost)); + + login_level(); + + /* ------------------------------------------------- */ + /* ³]©w status */ + /* ------------------------------------------------- */ + + login_status(multi); + + /* ------------------------------------------------- */ + /* ¨q¨Ç¸ê°T */ + /* ------------------------------------------------- */ + + login_other(); + } + + srand(ap_start * cuser.userno * currpid); +} + + + static void +tn_motd() +{ + usint ufo; + + ufo = cuser.ufo; + + if (!(ufo & UFO_MOTD)) + { + more("gem/@/@-day", NULL); /* ¤µ¤é¼öªù¸ÜÃD */ + pad_view(); + } + time_t now = time(NULL); + if (now >= 1301587200 && now <= 1301673600) + more("gem/@/@FOOLDAYPOST", NULL); /* ·M¤H¸` */ + +#ifdef HAVE_NOALOHA + if (!(ufo & UFO_NOALOHA)) +#endif + { +#ifdef LOGIN_NOTIFY + loginNotify(); +#endif +#ifdef HAVE_ALOHA + aloha(); +#endif + } + +#ifdef HAVE_FORCE_BOARD + brd_force(); /* itoc.000319: ±j¨î¾\Ū¤½§iªO */ +#endif +} + + +/* ----------------------------------------------------- */ +/* trap signals */ +/* ----------------------------------------------------- */ + + + static void +tn_signals() +{ + struct sigaction act; + + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + act.sa_handler = (void *) abort_bbs; + sigaction(SIGBUS, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGTERM, &act, NULL); + sigaction(SIGXCPU, &act, NULL); +#ifdef SIGSYS + /* Thor.981221: easy for porting */ + sigaction(SIGSYS, &act, NULL);/* bad argument to system call */ +#endif + + act.sa_handler = (void *) talk_rqst; + sigaction(SIGUSR1, &act, NULL); + + act.sa_handler = (void *) bmw_rqst; + sigaction(SIGUSR2, &act, NULL); + + /* ¦b¦¹É¥Î sigset_t act.sa_mask */ + sigaddset(&act.sa_mask, SIGPIPE); + sigprocmask(SIG_BLOCK, &act.sa_mask, NULL); + +} + + static int +show_file(fpath, ln, lines) + char *fpath; + int ln, lines; +{ + FILE *fp; + char buf[ANSILINELEN]; + int i; + + if ((fp = fopen(fpath, "r"))) + { + i = lines; + while (fgets(buf, ANSILINELEN, fp) && i--) + outs(buf); + fclose(fp); + return 1; + } + + sprintf(buf, "%s ¿ò¥¢¡A½Ð§iª¾¯¸ªø", fpath); + zmsg(buf); + return 0; +} + + static inline void +tn_main() +{ + clear(); + +#ifdef HAVE_LOGIN_DENIED + if (acl_has(BBS_ACLFILE, "", fromhost)) + login_abort("\n¶Q¾÷¾¹©ó¤£³Q±Í¯¸±µ¨ü"); +#endif + + + /* + outs("Ãö¯¸¡A¹wp¤Q¤ÀÄÁ«á«ì´_\n³y¦¨±zªº§xÂZ²`·P©êºp"); + if (vkey() != 'm' || vkey() != 'p' || vkey() != '6' || vkey() != '0' || vkey() != '7') + login_abort("\nÃö¯¸ºûסA¦A¨£"); + move(0, 0); + */ + + time(&ap_start); + + time_t now = time(NULL); + if (now >= 1301587200 && now <= 1301673600) + { + prints("\033[1;36;44msony.tfcis.org\033[0;44m \033[1;32m¡÷¡÷¡÷\033[0;44m \033[1;33m«n¤@¸ê°T\033[0;44m \033[1;32m¡ö¡ö¡ö\033[0;44 \033[1;36m210.70.137.212\033[m\n"); + prints("\033[1;44m Åwªï¥úÁ{¡i\033[33;46m ¯Á¥§¤p¯¸ \033[37;44m¡j¥Ø«e½u¤W¤H¼Æ [\033[33m%d\033[37m] ¤H\033[0;44m \033[m", ushm->count); + } + else + { + prints("%s ¡ó " SCHOOLNAME " ¡ó " MYIPADDR "\n" + "Åwªï¥úÁ{¡i\033[1;33;46m %s \033[m¡j¥Ø«e½u¤W¤H¼Æ [%d] ¤H", + str_host, str_site, ushm->count); + } + //film_out((ap_start % 3) + FILM_OPENING0, 3); /* ¶Ã¼ÆÅã¥Ü¶}ÀYµe± */ + char fpath[64]; + time(&ap_start); + sprintf(fpath, "gem/@/@opening.%d", time(0) % 3); + prints("\n\n"); /* Chensc.070322: ×¥¿¶i¯¸µe±««ª½¦ì¸m */ + show_file(fpath, 3, 20); + + currpid = getpid(); + + tn_signals(); /* Thor.980806: ©ñ©ó tn_login«e, ¥H«K call in¤£·|³Q½ð */ + tn_login(); + + board_main(); + gem_main(); +#ifdef MY_FAVORITE + mf_main(); +#endif + talk_main(); + + tn_motd(); + + menu(); + abort_bbs(); /* to make sure it will terminate */ +} + + +/* ----------------------------------------------------- */ +/* FSA (finite state automata) for telnet protocol */ +/* ----------------------------------------------------- */ + + + static void +telnet_init() +{ + static char svr[] = + { + IAC, DO, TELOPT_TTYPE, + IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE, + IAC, WILL, TELOPT_ECHO, + IAC, WILL, TELOPT_SGA + }; + + int n, len; + char *cmd; + int rset; + struct timeval to; + char buf[64]; + + /* --------------------------------------------------- */ + /* init telnet protocol */ + /* --------------------------------------------------- */ + + cmd = svr; + + for (n = 0; n < 4; n++) + { + len = (n == 1 ? 6 : 3); + send(0, cmd, len, 0); + cmd += len; + + rset = 1; + /* Thor.981221: for future reservation bug */ + to.tv_sec = 1; + to.tv_usec = 1; + if (select(1, (fd_set *) & rset, NULL, NULL, &to) > 0) + recv(0, buf, sizeof(buf), 0); + } +} + + +/* ----------------------------------------------------- */ +/* ¤ä´©¶W¹L 24 ¦Cªºµe± */ +/* ----------------------------------------------------- */ + + + static void +term_init() +{ +#if 0 /* fuse.030518: µù¸Ñ */ + server°Ý¡G§A·|§ïÅܦæ¦C¼Æ¶Ü¡H(TN_NAWS, Negotiate About Window Size) + clientµª¡GYes, I do. (TNCH_DO) + + ¨º»ò¦b³s½u®É¡A·íTERMÅܤƦæ¦C¼Æ®É´N·|µo¥X¡G + TNCH_IAC + TNCH_SB + TN_NAWS + ¦æ¼Æ¦C¼Æ + TNCH_IAC + TNCH_SE; +#endif + + /* ask client to report it's term size */ + static char svr[] = /* server */ + { + IAC, DO, TELOPT_NAWS + }; + + int rset; + char buf[64], *rcv; +struct timeval to; + + /* °Ý¹ï¤è (telnet client) ¦³¨S¦³¤ä´©¤£¦Pªº¿Ã¹õ¼e°ª */ + send(0, svr, 3, 0); + + rset = 1; + to.tv_sec = 1; + to.tv_usec = 1; + if (select(1, (fd_set *) & rset, NULL, NULL, &to) > 0) + recv(0, buf, sizeof(buf), 0); + + rcv = NULL; + if ((uschar) buf[0] == IAC && buf[2] == TELOPT_NAWS) + { + /* gslin: Unix ªº telnet ¹ï¦³µL¥[ port °Ñ¼Æªº¦æ¬°¤£¤Ó¤@¼Ë */ + if ((uschar) buf[1] == SB) + { + rcv = buf + 3; + } + else if ((uschar) buf[1] == WILL) + { + if ((uschar) buf[3] != IAC) + { + rset = 1; + to.tv_sec = 1; + to.tv_usec = 1; + if (select(1, (fd_set *) & rset, NULL, NULL, &to) > 0) + recv(0, buf + 3, sizeof(buf) - 3, 0); + } + if ((uschar) buf[3] == IAC && (uschar) buf[4] == SB && buf[5] == TELOPT_NAWS) + rcv = buf + 6; + } + } + + if (rcv) + { + b_lines = ntohs(* (short *) (rcv + 2)) - 1; + b_cols = ntohs(* (short *) rcv) - 1; + + /* b_lines ¦Ü¤Ön 23¡A³Ì¦h¤£¯à¶W¹L T_LINES - 1 */ + if (b_lines >= T_LINES) + b_lines = T_LINES - 1; + else if (b_lines < 23) + b_lines = 23; + /* b_cols ¦Ü¤Ön 79¡A³Ì¦h¤£¯à¶W¹L T_COLS - 1 */ + if (b_cols >= T_COLS) + b_cols = T_COLS - 1; + else if (b_cols < 79) + b_cols = 79; + } + else + { + b_lines = 23; + b_cols = 79; + } + + d_cols = b_cols - 79; +} + + +/* ----------------------------------------------------- */ +/* stand-alone daemon */ +/* ----------------------------------------------------- */ + + + static void +start_daemon(port) + int port; /* Thor.981206: ¨ú 0 ¥Nªí *¨S¦³°Ñ¼Æ* , -1 ¥Nªí -i (inetd) */ +{ + int n; + struct linger ld; + struct sockaddr_in sin; +#ifdef HAVE_RLIMIT + struct rlimit limit; +#endif + char buf[80], data[80]; + time_t val; + + /* + * More idiot speed-hacking --- the first time conversion makes the C + * library open the files containing the locale definition and time zone. + * If this hasn't happened in the parent process, it happens in the + * children, once per connection --- and it does add up. + */ + + time(&val); + strftime(buf, 80, "%d/%b/%Y %H:%M:%S", localtime(&val)); + +#ifdef HAVE_RLIMIT + /* --------------------------------------------------- */ + /* adjust resource : 16 mega is enough */ + /* --------------------------------------------------- */ + + limit.rlim_cur = limit.rlim_max = 16 * 1024 * 1024; + /* setrlimit(RLIMIT_FSIZE, &limit); */ + setrlimit(RLIMIT_DATA, &limit); + +#ifdef SOLARIS +#define RLIMIT_RSS RLIMIT_AS /* Thor.981206: port for solaris 2.6 */ +#endif + + setrlimit(RLIMIT_RSS, &limit); + + limit.rlim_cur = limit.rlim_max = 0; + setrlimit(RLIMIT_CORE, &limit); + + limit.rlim_cur = limit.rlim_max = 60 * 20; + setrlimit(RLIMIT_CPU, &limit); +#endif + + /* --------------------------------------------------- */ + /* speed-hacking DNS resolve */ + /* --------------------------------------------------- */ + + dns_init(); + + /* --------------------------------------------------- */ + /* change directory to bbshome */ + /* --------------------------------------------------- */ + + chdir(BBSHOME); + umask(077); + + /* --------------------------------------------------- */ + /* detach daemon process */ + /* --------------------------------------------------- */ + + /* The integer file descriptors associated with the streams + stdin, stdout, and stderr are 0,1, and 2, respectively. */ + + close(1); + close(2); + + if (port == -1) /* Thor.981206: inetd -i */ + { + /* Give up root privileges: no way back from here */ + setgid(BBSGID); + setuid(BBSUID); +#if 1 + n = sizeof(sin); + if (getsockname(0, (struct sockaddr *) &sin, &n) >= 0) + port = ntohs(sin.sin_port); +#endif + /* mport = port; */ /* Thor.990325: ¤£»Ýn¤F:P */ + + sprintf(data, "%d\t%s\t%d\tinetd -i\n", getpid(), buf, port); + f_cat(PID_FILE, data); + return; + } + + close(0); + + if (fork()) + exit(0); + + setsid(); + + if (fork()) + exit(0); + + /* --------------------------------------------------- */ + /* fork daemon process */ + /* --------------------------------------------------- */ + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + + if (port == 0) /* Thor.981206: port 0 ¥Nªí¨S¦³°Ñ¼Æ */ + { + n = MAX_BBSDPORT - 1; + while (n) + { + if (fork() == 0) + break; + + sleep(1); + n--; + } + port = myports[n]; + } + + n = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + val = 1; + setsockopt(n, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val)); + + ld.l_onoff = ld.l_linger = 0; + setsockopt(n, SOL_SOCKET, SO_LINGER, (char *) &ld, sizeof(ld)); + + /* mport = port; */ /* Thor.990325: ¤£»Ýn¤F:P */ + sin.sin_port = htons(port); + if ((bind(n, (struct sockaddr *) &sin, sizeof(sin)) < 0) || (listen(n, QLEN) < 0)) + exit(1); + + /* --------------------------------------------------- */ + /* Give up root privileges: no way back from here */ + /* --------------------------------------------------- */ + + setgid(BBSGID); + setuid(BBSUID); + + /* standalone */ + sprintf(data, "%d\t%s\t%d\n", getpid(), buf, port); + f_cat(PID_FILE, data); +} + + +/* ----------------------------------------------------- */ +/* reaper - clean up zombie children */ +/* ----------------------------------------------------- */ + + + static inline void +reaper() +{ + while (waitpid(-1, NULL, WNOHANG | WUNTRACED) > 0); +} + + +#ifdef SERVER_USAGE + static void +servo_usage() +{ + struct rusage ru; + FILE *fp; + + fp = fopen("run/bbs.usage", "a"); + + if (!getrusage(RUSAGE_CHILDREN, &ru)) + { + fprintf(fp, "\n[Server Usage] %d: %d\n\n" + "user time: %.6f\n" + "system time: %.6f\n" + "maximum resident set size: %lu P\n" + "integral resident set size: %lu\n" + "page faults not requiring physical I/O: %d\n" + "page faults requiring physical I/O: %d\n" + "swaps: %d\n" + "block input operations: %d\n" + "block output operations: %d\n" + "messages sent: %d\n" + "messages received: %d\n" + "signals received: %d\n" + "voluntary context switches: %d\n" + "involuntary context switches: %d\n\n", + + getpid(), ap_start, + (double) ru.ru_utime.tv_sec + (double) ru.ru_utime.tv_usec / 1000000.0, + (double) ru.ru_stime.tv_sec + (double) ru.ru_stime.tv_usec / 1000000.0, + ru.ru_maxrss, + ru.ru_idrss, + ru.ru_minflt, + ru.ru_majflt, + ru.ru_nswap, + ru.ru_inblock, + ru.ru_oublock, + ru.ru_msgsnd, + ru.ru_msgrcv, + ru.ru_nsignals, + ru.ru_nvcsw, + ru.ru_nivcsw); + } + + fclose(fp); +} +#endif + + + static void +main_term() +{ +#ifdef SERVER_USAGE + servo_usage(); +#endif + exit(0); +} + + + static inline void +main_signals() +{ + struct sigaction act; + + /* act.sa_mask = 0; */ /* Thor.981105: ¼Ð·Ç¥Îªk */ + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + act.sa_handler = reaper; + sigaction(SIGCHLD, &act, NULL); + + act.sa_handler = main_term; + sigaction(SIGTERM, &act, NULL); + +#ifdef SERVER_USAGE + act.sa_handler = servo_usage; + sigaction(SIGPROF, &act, NULL); +#endif + + /* sigblock(sigmask(SIGPIPE)); */ +} + + + int +main(argc, argv) + int argc; + char *argv[]; +{ + int csock; /* socket for Master and Child */ + int value; + int *totaluser; + struct sockaddr_in sin; + + /* --------------------------------------------------- */ + /* setup standalone daemon */ + /* --------------------------------------------------- */ + + /* Thor.990325: usage, bbsd, or bbsd -i, or bbsd 1234 */ + /* Thor.981206: ¨ú 0 ¥Nªí *¨S¦³°Ñ¼Æ*, -1 ¥Nªí -i */ + start_daemon(argc > 1 ? strcmp("-i", argv[1]) ? atoi(argv[1]) : -1 : 0); + + main_signals(); + + /* --------------------------------------------------- */ + /* attach shared memory & semaphore */ + /* --------------------------------------------------- */ + +#ifdef HAVE_SEM + sem_init(); +#endif + ushm_init(); + bshm_init(); + fshm_init(); + + /* --------------------------------------------------- */ + /* main loop */ + /* --------------------------------------------------- */ + + totaluser = &ushm->count; + /* avgload = &ushm->avgload; */ + + for (;;) + { + value = 1; + if (select(1, (fd_set *) & value, NULL, NULL, NULL) < 0) + continue; + + value = sizeof(sin); + csock = accept(0, (struct sockaddr *) &sin, &value); + if (csock < 0) + { + reaper(); + continue; + } + + ap_start++; + argc = *totaluser; + if (argc >= MAXACTIVE - 5 /* || *avgload > THRESHOLD */ ) + { + /* ɥΠcurrtitle */ + sprintf(currtitle, "¥Ø«e½u¤W¤H¼Æ [%d] ¤H¡A¨t²Î¹¡©M¡A½Ðµy«á¦A¨Ó\n", argc); + send(csock, currtitle, strlen(currtitle), 0); + close(csock); + continue; + } + + if (fork()) + { + close(csock); + continue; + } + + dup2(csock, 0); + close(csock); + + /* ------------------------------------------------- */ + /* ident remote host / user name via RFC931 */ + /* ------------------------------------------------- */ + + tn_addr = sin.sin_addr.s_addr; + dns_name((char *) &sin.sin_addr, fromhost); + + telnet_init(); + term_init(); + tn_main(); + } +} diff --git a/maple/bmw.c b/maple/bmw.c new file mode 100644 index 0000000..04a2e9b --- /dev/null +++ b/maple/bmw.c @@ -0,0 +1,1195 @@ +/*-------------------------------------------------------*/ +/* bmw.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : bmw routines */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +extern UCACHE *ushm; +extern XZ xz[]; +extern char xo_pool[]; + + +/* ----------------------------------------------------- */ +/* BMW : bbs message write routines */ +/* ----------------------------------------------------- */ + + +#define BMW_FORMAT "\033[1;33;46m¡¹%s \033[37;45m %s \033[m" /* ¦¬¨ìªº¤ô²y */ +#define BMW_FORMAT2 "\033[1;33;41m¡¸%s \033[34;47m %s \033[m" /* °e¥Xªº¤ô²y */ +#define BMW_FORMAT3 "\033[1;33;45m¡¹%s \033[34;47m %s \033[m" /* ¦¬¨ìªº¼s¼½ */ +#define BMW_FORMAT4 "\033[1;33;44m¡¹%s \033[34;47m %s \033[m" /* Robot ¤ô²y */ + +static int bmw_locus = 0; /* Á`¦@«O¦s´XÓ¤ô²y («O¯d³Ìªñ¦¬¨ì BMW_LOCAL_MAX Ó) */ +static BMW bmw_lslot[BMW_LOCAL_MAX]; /* «O¯d¦¬¨ìªº¤ô²y */ + +static int bmw_locat = 0; /* Á`¦@«O¦s´XÓ¤ô²y («O¯d³Ìªñ°e¥X BMW_LOCAL_MAX Ó) */ +static BMW bmw_lword[BMW_LOCAL_MAX]; /* «O¯d°e¥Xªº¤ô²y */ + + +int /* 1:¥i¥H¶Ç¤ô²yµ¹¹ï¤è/»P¹ï¤èTalk 0:¤£¯à¶Ç¤ô²yµ¹¹ï¤è/»P¹ï¤èTalk */ +can_override(up) + UTMP *up; +{ + int ufo; + + if (up->userno == cuser.userno) /* ¤£¯à¶Ç¤ô²yµ¹¦Û¤v(§Y¨Ï¬O¤À¨) */ + return 0; + + ufo = up->ufo; + +#ifdef HAVE_SUPERCLOAK + if ((ufo & UFO_SUPERCLOAK) && !(cuser.ufo & UFO_SUPERCLOAK)) /* µµÁô¥u¦³µµÁôªº¤~¬Ýªº¨£ */ + return 0; +#endif + + /* itoc.010909.µù¸Ñ: ¯¸ªø¥i¥H¶Ç¤ô²yµ¹ Âê©w/BBSNET... ªº¤H¡A³o¼Ë¦n¶Ü¡HÆ[¹î¤¤ */ + + if (HAS_PERM(PERM_ALLACCT)) /* ¯¸ªø¡B±b¸¹ºÞ²zû¥i¥H¶Çµ¹¥ô¦ó¤H */ + return 1; + + /* itoc.010909: Âê©w®É¤£¯à³Q¶Ç¤ô²y */ + if ((ufo & UFO_QUIET) || (up->status & STATUS_REJECT)) /* »·Â÷¹ÐÄÛ/Âê©w®É ¤£¯à³Q¶Ç */ + return 0; + + if (!(up->ufo & UFO_CLOAK) || HAS_PERM(PERM_SEECLOAK)) + { + /* itoc.001223: ¥Î is_ogood/is_obad ¨Ó°µ§PÂ_ */ + if (ufo & UFO_PAGER) + return is_ogood(up); /* pager Ãö³¬®É¥u¦³³Q³]¦n¤Í¯à¶Ç¤ô²y */ + else + return !is_obad(up); /* pager ¥´¶}®É¥un¨S¦³³Q³]Ãa¤H§Y¥i¶Ç¤ô²y */ + } + else + { + /* itoc.020321: ¹ï¤èYÁô§Î¶Ç§Ú¤ô²y¡A§Ú¤]¥i¥H³Q°Ê¦^ */ + BMW *bmw; + + for (ufo = bmw_locus - 1; ufo >= 0; ufo--) + { + bmw = &bmw_lslot[ufo]; + + /* itoc.030718: ¦pªG§Ú«·s¤W¯¸¤F¡A¨º»ò§Y¨Ï§Ú¤W¤@¦¸¤W¯¸¦³¥á¹ï¤è¤ô²y¡A¹ï¤è¤]¤£¥i¥H¦^§Ú + ¤£¹L³oÀˬdÁÙ¬O¦³Óº|¬}¡A´N¬O¦pªG«·s¤W¯¸¥H«á¤Sè¦n§¤¦P¤@Ó ushm ªº¦ì¸m¡A¨º»ò¹ï¤èÁÙ¬O¥i¥H¦^§Ú */ + if (bmw->caller == up && bmw->sender == up->userno) + return 1; + } + } + + return 0; +} + + +int /* 1:¥i¬Ý¨£ 0:¤£¥i¬Ý¨£ */ +can_see(my, up) + UTMP *my; + UTMP *up; +{ + usint mylevel, myufo, urufo; + + if (my->userno == up->userno) + return 1; + if (my == cutmp) /* ¥Î cuser. ¨Ó¥N´À cutmp-> */ + { + mylevel = cuser.userlevel; + myufo = cuser.ufo; + } + else + { + mylevel = my->userlevel; + myufo = my->ufo; + } + urufo = up->ufo; + + if ((urufo & UFO_CLOAK) && !(mylevel & PERM_SEECLOAK)) + return 0; + +#ifdef HAVE_SUPERCLOAK + if ((urufo & UFO_SUPERCLOAK) && !(myufo & UFO_SUPERCLOAK)) + return 0; +#endif + +#ifdef HAVE_BADPAL + if (my == cutmp) /* Àˬd§Ú¥i¤£¥i¥H¬Ý¨ì¹ï¤è */ + { + if (!(mylevel & PERM_SEECLOAK) && is_obad(up)) + return 0; + } + else /* Àˬd¹ï¤è¥i¤£¥i¥H¬Ý¨ì§Ú */ + { + if (!(mylevel & PERM_SEECLOAK) && is_mybad(my->userno)) + return 0; + } +#endif + + return 1; +} + + +int +bmw_send(callee, bmw) + UTMP *callee; + BMW *bmw; +{ + BMW *mpool, *mhead, *mtail, **mslot; + int i; + pid_t pid; + time_t texpire; + + if ((callee->userno != bmw->recver) || (pid = callee->pid) <= 0) + return 1; + + /* sem_lock(BSEM_ENTER); */ + + /* find callee's available slot */ + + mslot = callee->mslot; + i = 0; + + for (;;) + { + if (mslot[i] == NULL) + break; + + if (++i >= BMW_PER_USER) + { + /* sem_lock(BSEM_LEAVE); */ + return 1; + } + } + + /* find available BMW slot in pool */ + + texpire = time(&bmw->btime) - BMW_EXPIRE; + + mpool = ushm->mpool; + mhead = ushm->mbase; + if (mhead < mpool) + mhead = mpool; + mtail = mpool + BMW_MAX; + + do + { + if (++mhead >= mtail) + mhead = mpool; + } while (mhead->btime > texpire); + + *mhead = *bmw; + ushm->mbase = mslot[i] = mhead; + /* Thor.981206: »Ýª`·N, Yushm mapping¤£¦P, + «h¤£¦P°¦ bbsd ¤¬call·|core dump, + °£«D³o¤]¥Îoffset, ¤£¹L°£¤F -i, À³¸Ó¬O«D¥²n */ + + + /* sem_lock(BSEM_LEAVE); */ + return kill(pid, SIGUSR2); +} + + +#ifdef BMW_DISPLAY +static void +bmw_display(max) /* itoc.010313: display ¥H«eªº¤ô²y */ + int max; +{ + int i; + BMW *bmw; + + move(1, 0); + clrtoeol(); + outs("\033[1;36m¢~¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\033[37;44m [Ctrl-T]©¹¤W¤Á´« \033[36;40m¢w¢w¢w¢w¢w¢w¢¡\033[m"); + + i = 2; + for (; max >= 0; max--) + { /* ±q¸û·sªº¤ô²y©¹¤U¦L */ + bmw = &bmw_lslot[max]; + move(i, 0); + clrtoeol(); + prints(" " BMW_FORMAT, bmw->userid, bmw->msg); + i++; + } + + move(i, 0); + clrtoeol(); + outs("\033[1;36m¢¢¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\033[37;44m [Ctrl-R]©¹¤U¤Á´« \033[36;40m¢w¢w¢w¢w¢w¢w¢£\033[m"); +} +#endif + + +static int bmw_pos; /* ¥Ø«e«ü¦V bmw_lslot ªºþ¤@Äæ */ +static UTMP *bmw_up; /* ¥Ø«e¦^þÓ utmp */ +static int bmw_request; /* 1: ¦³·sªº¤ô²y¶i¨Ó */ + + +void +bmw_edit(up, hint, bmw) + UTMP *up; /* °eªº¹ï¶H¡AY¬O NULL ªí¥Ü¼s¼½ */ + char *hint; + BMW *bmw; +{ + int recver; + screenline slp[3]; + char *userid, fpath[64]; + FILE *fp; + + if (bbsmode != M_BMW_REPLY) /* Y¬O reply ªº¸Ü¡A¦b bmw_reply() ·|¦Û¦æ³B²zµe±«Ã¸ */ + save_foot(slp); + + recver = up ? up->userno : 0; + bmw->msg[0] = '\0'; + + for (;;) + { + int ch; + BMW *benz; + + ch = vget(0, 0, hint, bmw->msg, 62, GCARRY); + + if (!ch) /* ¨S¿é¤JªF¦è */ + { + if (bbsmode != M_BMW_REPLY) + restore_foot(slp, 1); + return; + } + + if (ch != Ctrl('R') && ch != Ctrl('T')) /* §¹¦¨¤ô²y¿é¤J */ + break; + + /* ¦³·sªº¤ô²y¶i¨Ó¡A«Ã¸¤ô²y¦^ÅU¡A¨Ã±N bmw_pos «ü¦Vì¨Ó¨ºÓ¤ô²y */ + if (bmw_request) + { + bmw_request = 0; + bmw_pos = bmw_locus - 1; + if (cuser.ufo & UFO_BMWDISPLAY) + bmw_display(bmw_pos); + bmw_reply_CtrlRT(ch); + continue; + } + + /* ¦b vget ¤¤«ö ^R ´« reply §Oªº¤ô²y */ + benz = &bmw_lslot[bmw_pos]; + if (benz->sender != up->userno) /* reply ¤£¦P¤H */ + { + up = bmw_up; + recver = up->userno; + sprintf(hint, "¡¹[%s]", up->userid); + } + } + + sprintf(fpath, "½T©wn°e¥X¡m¤ô²y¡nµ¹ %s ¶Ü(Y/N)¡H[Y] ", up ? up->userid : " ¼s¼½ "); + if (vans(fpath) != 'n') + { + int i; + + bmw->caller = cutmp; + bmw->sender = cuser.userno; + userid = cuser.userid; + + if (up) /* ¤£¬O¼s¼½ */ + { + /* °e¥X¤ô²y */ + bmw->recver = recver; + strcpy(bmw->userid, userid); + if (bmw_send(up, bmw)) /* ¤ô²y°e¤£¥X¥h¡A¤£¼g¤J¤ô²y¬ö¿ýÀÉ */ + { + vmsg(MSG_USR_LEFT); + if (bbsmode != M_BMW_REPLY) + restore_foot(slp, 2); + return; + } + + /* lkchu.990103: Y¬O¦Û¤v°e¥Xªº¤ô²y¡A¦s¹ï¤èªº userid */ + strcpy(bmw->userid, up->userid); + } + else /* ¼s¼½ */ + { + /* °e¥X¼s¼½ªºµ{¦¡¡A¦b ulist_broadcast() ³B²z */ + + bmw->recver = 0; /* ¦s 0 ¨Ï¤£¯à write ¦^¼s¼½ */ + + /* itoc.000213: ¥[ "> " ¬°¤F»P¤@¯ë¤ô²y°Ï¤À */ + sprintf(bmw->userid, "%s> ", cuser.userid); + } + + time(&bmw->btime); + usr_fpath(fpath, userid, fn_bmw); + rec_add(fpath, bmw, sizeof(BMW)); + + /* itoc.020126: ¥[¤J FN_AMW */ + usr_fpath(fpath, userid, fn_amw); + if (fp = fopen(fpath, "a")) + { + fprintf(fp, BMW_FORMAT2 " %s\n", bmw->userid, bmw->msg, Btime(&bmw->btime)); + fclose(fp); + } + + /* itoc.030621: «O¯d°e¥Xªº¤ô²y */ + if (bmw_locat >= BMW_LOCAL_MAX) + { + /* ªº©¹«e®¿ */ + i = BMW_LOCAL_MAX - 1; + memcpy(bmw_lword, bmw_lword + 1, i * sizeof(BMW)); + } + else + { + i = bmw_locat; + bmw_locat++; + } + bmw_lword[i].recver = recver; + strcpy(bmw_lword[i].msg, bmw->msg); + } + + if (bbsmode != M_BMW_REPLY) + restore_foot(slp, 2); +} + +static void +bmw_npcAI(msg) + char *msg; +{ + /* input msg ¬O¨Ï¥ÎªÌ©Ò¿é¤Jnµ¹ guest ªº¤ô²y */ + /* output ¤]¥Î msg¡A¬O NPC ¦^µ¹ cuser.userid ªº¤ô²y */ + int find; + FILE *fp; + char rule[80], ans[80], *str; + + find = 0; + if (fp = fopen("etc/npc", "r")) + { + while (fgets(rule, 80, fp) && fgets(ans, 80, fp)) /* ¤@¦¸ fget ¤G¦æ */ + { + if (str = strchr(rule, '\n')) + *str = '\0'; + if (strstr(msg, rule)) + { + if (str = strchr(ans, '\n')) + *str = '\0'; + str_ncpy(msg, ans, 60); + find = 1; + break; + } + } + + fclose(fp); + } + + if (!find) /* ¦pªG rule ¸Ì±¨S¦³¡A´NÀH«K¦^µª */ + strcpy(msg, "¤°»ò¤°»ò¡H¦Aµ¹§Ú»¡¤@¦¸¨Óťť = =+"); +} + + + + +static void +bmw_outz() +{ + int i; + BMW *bmw, *benz; + + /* ¦C¦Lªº¦ì¸mn©M save/restore_foot ©Ò«Ã¸ªº³¡¤À¬O¬Û¦Pªº */ + + bmw = &bmw_lslot[bmw_pos]; + move(b_lines, 0); + clrtoeol(); + prints(BMW_FORMAT, bmw->userid, bmw->msg); + + /* itoc.030621: ¥Ñ«O¯dªº°e¥X¤ô²y¤¤¡A§ä¥X¤W¦¸¦^³o¤Hªº¤ô²y¬O¤°»ò */ + for (i = bmw_locat; i >= 0; i--) + { + benz = &bmw_lword[i]; + if (benz->recver == bmw->sender) + break; + } + move(b_lines - 1, 0); + clrtoeol(); + prints(BMW_FORMAT2, bmw->userid, i >= 0 ? benz->msg : "¡i±z³Ìªñ¨S¦³¶Ç¤ô²yµ¹³o¦ì¨Ï¥ÎªÌ¡j"); +} + + +static UTMP * +can_reply(uhead, pos) + UTMP *uhead; + int pos; +{ + int userno; + BMW *bmw; + UTMP *up; + + bmw = &bmw_lslot[pos]; + + userno = bmw->sender; + if (!userno) /* Thor.980805: ¨¾¤î¨t²Î¨ó´M¦^¦© */ + return NULL; + + up = bmw->caller; + if ((up < uhead) || (up > uhead + ushm->offset) || (up->userno != userno)) + { + /* ¦pªG up-> ¤£¦b ushm ¤º¡A©Î¬O up-> ¤£¬O call-in §Úªº¤H¡Aªí¥Ü³o¤H¤U¯¸¤F¡A + ¦ý¬O¥L¥i¯à¤S¤W¯¸©Î¦³ multi¡A©Ò¥H«§ä¤@¦¸ */ + if (!(up = utmp_find(userno))) /* ¦pªG¦A§ä¤@¦¸ÁÙ¬O¨S¦³ */ + return NULL; + } + + /* itoc.010909: ¥i¥H³Q°Ê¦^µ¹ Áô§Î/»·Â÷¹ÐÄÛ/Ãö³¬pager ªº¤H¡A¦ý¬O¤£¯à¦^µ¹Âê©wªº¤H */ + if (bmw->caller != up || up->status & STATUS_REJECT) + return NULL; + + return up; +} + + +static UTMP * +bmw_lastslot(pos) /* §ä¥X³Ìªñ¤@Ó¥i¥H¦^¤ô²yªº¹ï¶H */ + int pos; +{ + int max, times; + UTMP *up, *uhead; + + uhead = ushm->uslot; + max = bmw_locus - 1; + + for (times = max; times >= 0; times--) + { + if (up = can_reply(uhead, pos)) + { + bmw_pos = pos; + return up; + } + + /* ©¹¤U´`Àô§ä¤@°é */ + pos = (pos == 0) ? max : pos - 1; + } + + return NULL; +} + + +static UTMP * +bmw_firstslot(pos) /* §ä¥X³Ì»·¤@Ó¥i¥H¦^¤ô²yªº¹ï¶H */ + int pos; +{ + int max, times; + UTMP *up, *uhead; + + uhead = ushm->uslot; + max = bmw_locus - 1; + + for (times = max; times >= 0; times--) + { + if (up = can_reply(uhead, pos)) + { + bmw_pos = pos; + return up; + } + + /* ©¹¤W´`Àô§ä¤@°é */ + pos = (pos == max) ? 0 : pos + 1; + } + + return NULL; +} + + +int +bmw_reply_CtrlRT(key) + int key; +{ + int max, pos; + + max = bmw_locus - 1; + if (max == 0) /* ¨S¨ä¥Lªº¤ô²y¥i¥H¿ï */ + return 0; + + pos = bmw_pos; /* ªº bmw_pos */ + + if (key == Ctrl('R')) + bmw_up = bmw_lastslot(pos == 0 ? max : pos - 1); /* ¥Ñ¥Ø«e©Ò¦b pos ©¹¤U§ä¤@Ó¥i¥H¦^¤ô²yªº¹ï¶H */ + else /* if (key == Ctrl('T')) */ + bmw_up = bmw_firstslot(pos == max ? 0 : pos + 1); /* ¥Ñ¥Ø«e©Ò¦b pos ©¹¤W§ä¤@Ó¥i¥H¦^¤ô²yªº¹ï¶H */ + + if (!bmw_up) /* §ä¤£¨ì§Oªº¤ô²y */ + { + bmw_pos = pos; + return 0; + } + +#ifdef BMW_DISPLAY + if (cuser.ufo & UFO_BMWDISPLAY) + { + move(2 + max - pos, 0); + outc(' '); + move(2 + max - bmw_pos, 0); + outc('>'); + } +#endif + + bmw_outz(); + return 1; +} + + +void +bmw_reply() +{ + int max, display, tmpmode; + char buf[128]; + UTMP *up; + BMW bmw; +#ifdef BMW_DISPLAY + screenline slt[T_LINES]; +#else + screenline slt[3]; +#endif + + cursor_save(); + + max = bmw_locus - 1; + if (!(up = bmw_lastslot(max))) + { + save_foot(slt); + vmsg("¥ý«e¨ÃµL¤ô²y©I¥s¡A©Î¹ï¤è¬Ò¤w¤U¯¸"); + restore_foot(slt, 2); + cursor_restore(); + refresh(); + return; + } + + tmpmode = bbsmode; /* lkchu.981201: Àx¦s bbsmode */ + utmp_mode(M_BMW_REPLY); + +#ifdef BMW_DISPLAY + display = cuser.ufo & UFO_BMWDISPLAY; + if (display) + { + vs_save(slt); /* itoc.010313: °O¿ý bmd_display ¤§«eªº screen */ + bmw_display(max); /* itoc.010313: display ¥H«eªº¤ô²y */ + move(2 + max - bmw_pos, 0); + outc('>'); + bmw_request = 0; + } + else +#endif + save_foot(slt); + + bmw_outz(); + + sprintf(buf, "¡¹[%s]", up->userid); + bmw_edit(up, buf, &bmw); + +#ifdef BMW_DISPLAY + if (display) + { + cursor_restore(); + vs_restore(slt); /* itoc.010313: ÁÙì bmw_display ¤§«eªº screen */ + } + else +#endif + { + restore_foot(slt, 3); /* ¤w bmw_outz¡AnÁÙì¤T¦C */ + cursor_restore(); + refresh(); + } + + utmp_mode(tmpmode); /* lkchu.981201: ¦^´_ bbsmode */ +} + + +void +bmw_rqst() +{ + int i, j, userno, locus; + BMW bmw[BMW_PER_USER], *mptr, **mslot; + char fpath[64]; + + /* download BMW slot first */ + + i = j = 0; + userno = cuser.userno; + mslot = cutmp->mslot; + + while (mptr = mslot[i]) + { + mslot[i] = NULL; + if (mptr->recver == userno) + { + bmw[j++] = *mptr; + } + mptr->btime = 0; + + if (++i >= BMW_PER_USER) + break; + } + + /* process the request */ + + if (j) + { + char buf[128]; + FILE *fp; + + locus = bmw_locus; + i = locus + j - BMW_LOCAL_MAX; + if (i >= 0) + { + locus -= i; + memcpy(bmw_lslot, bmw_lslot + i, locus * sizeof(BMW)); + } + + /* itoc.020126: ¥[¤J FN_AMW */ + usr_fpath(buf, cuser.userid, fn_amw); + fp = fopen(buf, "a"); + + i = 0; + do + { + mptr = &bmw[i]; + + /* lkchu.981230: §Q¥Î xover ¾ã¦X bmw */ + usr_fpath(buf, cuser.userid, fn_bmw); + rec_add(buf, mptr, sizeof(BMW)); + + /* itoc.020126: ¥[¤J FN_AMW */ + // fprintf(fp, BMW_FORMAT " %s\n", mptr->userid, mptr->msg, Btime(&mptr->btime)); + fprintf(fp, mptr->userid[strlen(mptr->userid) - 2] != '>' ? + BMW_FORMAT " %s\n" : BMW_FORMAT3 " %s\n", + mptr->userid, mptr->msg, Btime(&(mptr->btime))); + + bmw_lslot[locus++] = *mptr; /* structure copy */ + + /* ·í NPC ¦¬¨ì§O¤H¥á¤ô²y«á·|¦Û°Ê¦^¸Ü */ + if (!strcmp(cuser.userid, "Robot")) /* Robot ªº ID ¬O Robot */ + { + if (mptr->caller) + { + BMW new; + + time(&new.btime); + new.caller = cutmp; + new.sender = cuser.userno; + new.recver = mptr->sender; + strcpy(new.userid, cuser.userid); + strcpy(new.msg, mptr->msg); + bmw_npcAI(new.msg); + bmw_send(mptr->caller, &new); + + usr_fpath(fpath, cuser.userid, fn_bmw); + rec_add(fpath, &new, sizeof(BMW)); + + usr_fpath(fpath, cuser.userid, fn_amw); + if (fp = fopen(fpath, "a")) + { + fprintf(fp, BMW_FORMAT4 " %s\n", + new.userid, new.msg, Btime(&new.btime)); + fclose(fp); + } + } + } + + } while (++i < j); + + fclose(fp); + + bmw_locus = locus; + if (bbsmode == M_BMW_REPLY) + bmw_request = 1; /* n¨D§ó·s */ + + /* Thor.980827: ¬°¤F¨¾¤î¦C¦L¤@¥b(more)®É¤ô²y¦Ó«á¦C¦L¶W¹L½d³ò½ð¤H, ¬G¦s¤U´å¼Ð¦ì¸m */ + cursor_save(); + + // sprintf(buf, BMW_FORMAT, mptr->userid, mptr->msg); + sprintf(buf, mptr->userid[strlen(mptr->userid) - 2] != '>' ? + BMW_FORMAT : BMW_FORMAT3, mptr->userid, mptr->msg); + + outz(buf); + + /* Thor.980827: ¬°¤F¨¾¤î¦C¦L¤@¥b(more)®É¤ô²y¦Ó«á¦C¦L¶W¹L½d³ò½ð¤H, ¬GÁÙì´å¼Ð¦ì¸m */ + cursor_restore(); + + refresh(); + bell(); + +#ifdef BMW_COUNT + /* itoc.010312: ¦h¤¤¤@Ó¤ô²y */ + cutmp->bmw_count++; +#endif + } +} + + +void +do_write(up) + UTMP *up; +{ + if (can_override(up)) + { + BMW bmw; + char buf[20]; + + sprintf(buf, "¡¹[%s]", up->userid); + bmw_edit(up, buf, &bmw); + } +} + + +/* ----------------------------------------------------- */ +/* ¤ô²y¦Cªí: ¿ï³æ¦¡¾Þ§@¬É±´yz by lkchu */ +/* ----------------------------------------------------- */ + + +static void +bmw_item(num, bmw) + int num; + BMW *bmw; +{ + struct tm *ptime = localtime(&bmw->btime); + + if (bmw->sender == cuser.userno) /* °e¥Xªº¤ô²y */ + { + prints("%6d%c\033[33m%-13s\033[36m%-*.*s\033[33m%02d:%02d\033[m\n", + num, tag_char(bmw->btime), bmw->userid, d_cols + 53, d_cols + 53, bmw->msg, ptime->tm_hour, ptime->tm_min); + } + else /* ¦¬¨ìªº¤ô²y */ + { + prints("%6d%c%-13s\033[32m%-*.*s\033[m%02d:%02d\n", + num, tag_char(bmw->btime), bmw->userid, d_cols + 53, d_cols + 53, bmw->msg, ptime->tm_hour, ptime->tm_min); + } +} + + +static int +bmw_body(xo) + XO *xo; +{ + BMW *bmw; + int num, max, tail; + + max = xo->max; + if (max <= 0) + { + vmsg("¥ý«e¨ÃµL¤ô²y©I¥s"); + return XO_QUIT; + } + + bmw = (BMW *) xo_pool; + num = xo->top; + tail = num + XO_TALL; + if (max > tail) + max = tail; + + move(3, 0); + do + { + bmw_item(++num, bmw++); + } while (num < max); + clrtobot(); + + /* return XO_NONE; */ + return XO_FOOT; /* itoc.010403: §â b_lines ¶ñ¤W feeter */ +} + + +static int +bmw_head(xo) + XO *xo; +{ + vs_head("¹î¬Ý¤ô²y", str_site); + prints(NECKER_BMW, d_cols, ""); + return bmw_body(xo); +} + + +static int +bmw_load(xo) + XO *xo; +{ + xo_load(xo, sizeof(BMW)); + return bmw_body(xo); +} + + +static int +bmw_init(xo) + XO *xo; +{ + xo_load(xo, sizeof(BMW)); + return bmw_head(xo); +} + + +static int +bmw_delete(xo) + XO *xo; +{ + if (vans(msg_del_ny) == 'y') + { + if (!rec_del(xo->dir, sizeof(BMW), xo->pos, NULL)) + return bmw_load(xo); + } + + return XO_FOOT; +} + + +static int +bmw_rangedel(xo) /* itoc.001126: ·s¼W¤ô²y°Ï¬q§R°£ */ + XO *xo; +{ + return xo_rangedel(xo, sizeof(BMW), NULL, NULL); +} + + +static int +vfybmw(bmw, pos) + BMW *bmw; + int pos; +{ + return Tagger(bmw->btime, pos, TAG_NIN); +} + + +static int +bmw_prune(xo) + XO *xo; +{ + return xo_prune(xo, sizeof(BMW), vfybmw, NULL); +} + + +static int +bmw_mail(xo) + XO *xo; +{ + BMW *bmw; + char *str, userid[IDLEN + 1]; + + bmw = (BMW *) xo_pool + (xo->pos - xo->top); + strcpy(userid, bmw->userid); + if (str = strchr(userid, '>')) /* ¼s¼½ */ + *str = '\0'; + return my_send(userid); +} + + +static int +bmw_query(xo) + XO *xo; +{ + BMW *bmw; + char *str, userid[IDLEN + 1]; + + bmw = (BMW *) xo_pool + (xo->pos - xo->top); + move(1, 0); + clrtobot(); + strcpy(userid, bmw->userid); + if (str = strchr(userid, '>')) /* ¼s¼½ */ + *str = '\0'; + my_query(userid); + return bmw_head(xo); +} + + +static int +bmw_write(xo) + XO *xo; +{ + if (HAS_PERM(PERM_PAGE)) + { + int userno; + UTMP *up; + BMW *bmw; + + bmw = (BMW *) xo_pool + (xo->pos - xo->top); + + /* itoc.010304: Åý¶Ç°Tªº bmw ¤]¥i¥H¦^ */ + /* §Ú°e¤ô²yµ¹§O¤H¡A¦^µ¹¦¬°TªÌ¡F§O¤H°e¤ô²yµ¹§Ú¡A¦^µ¹°e°TªÌ */ + userno = (bmw->sender == cuser.userno) ? bmw->recver : bmw->sender; + if (!userno) + return XO_NONE; + + if (up = utmp_find(userno)) + do_write(up); + } + return XO_NONE; +} + + +static void +bmw_store(fpath) + char *fpath; +{ + int fd; + FILE *fp; + char buf[64], folder[64]; + HDR fhdr; + + /* itoc.020126.µù¸Ñ: ¥i¥Hª½±µ®³ FN_AMW ¨ÓÀx¦s§Y¥i¡A + ¥i¬O¦pªG¥Î FN_BMW «°µ¤@¦¸ªº¸Ü¡A¥i¥HÅý¨Ï¥ÎªÌ¦b t_bmw() ¤¤¦Û¥Ñ d ±¼¤£nªº¤ô²y */ + + if ((fd = open(fpath, O_RDONLY)) < 0) + return; + + usr_fpath(folder, cuser.userid, fn_dir); + if (fp = fdopen(hdr_stamp(folder, 0, &fhdr, buf), "w")) + { + BMW bmw; + + fprintf(fp, " == ¤ô²y°O¿ý %s ==\n\n", Now()); + + while (read(fd, &bmw, sizeof(BMW)) == sizeof(BMW)) + { + fprintf(fp, bmw.sender == cuser.userno ? BMW_FORMAT2 " %s\n" : BMW_FORMAT " %s\n", + bmw.userid, bmw.msg, Btime(&bmw.btime)); + } + fclose(fp); + } + + close(fd); + + fhdr.xmode = MAIL_READ | MAIL_NOREPLY; + strcpy(fhdr.title, "[³Æ §Ñ ¿ý] ¤ô²y¬ö¿ý"); + strcpy(fhdr.owner, cuser.userid); + rec_add(folder, &fhdr, sizeof(HDR)); +} + + +static int +bmw_save(xo) + XO *xo; +{ + if (vans("±z½T©wn§â¤ô²y¦s¨ì«H½c¸Ì¶Ü(Y/N)¡H[N] ") == 'y') + { + char fpath[64]; + + usr_fpath(fpath, cuser.userid, fn_bmw); + bmw_store(fpath); + unlink(fpath); + usr_fpath(fpath, cuser.userid, fn_amw); + unlink(fpath); + return bmw_init(xo); + } + return XO_FOOT; +} + + +static int +bmw_save_user(xo) + XO *xo; +{ + int fd; + FILE *fp; + char buf[64], folder[64]; + HDR fhdr; + ACCT acct; + + if (acct_get(msg_uid, &acct) > 0 && acct.userno != cuser.userno) + { + usr_fpath(buf, cuser.userid, fn_bmw); + if ((fd = open(buf, O_RDONLY)) >= 0) + { + usr_fpath(folder, cuser.userid, fn_dir); + if (fp = fdopen(hdr_stamp(folder, 0, &fhdr, buf), "w")) + { + BMW bmw; + + fprintf(fp, " == »P %s ¥áªº¤ô²y¬ö¿ý %s ==\n\n", acct.userid, Now()); + + while (read(fd, &bmw, sizeof(BMW)) == sizeof(BMW)) + { + if (bmw.sender == acct.userno || bmw.recver == acct.userno) + { + fprintf(fp, bmw.sender == cuser.userno ? BMW_FORMAT2 " %s\n" : BMW_FORMAT " %s\n", + bmw.userid, bmw.msg, Btime(&bmw.btime)); + } + } + fclose(fp); + } + close(fd); + + fhdr.xmode = MAIL_READ | MAIL_NOREPLY; + strcpy(fhdr.title, "[³Æ §Ñ ¿ý] ¤ô²y¬ö¿ý"); + strcpy(fhdr.owner, cuser.userid); + rec_add(folder, &fhdr, sizeof(HDR)); + vmsg("¤ô²y¬ö¿ý¤w±H¨ì«H½c"); + } + } + + return bmw_head(xo); +} + + +static int +bmw_clear(xo) + XO *xo; +{ + if (vans("¬O§_§R°£©Ò¦³¤ô²y¬ö¿ý(Y/N)¡H[N] ") == 'y') + { + char fpath[64]; + + usr_fpath(fpath, cuser.userid, fn_bmw); + unlink(fpath); + usr_fpath(fpath, cuser.userid, fn_amw); + unlink(fpath); + return XO_QUIT; + } + + return XO_FOOT; +} + + +static int +bmw_tag(xo) + XO *xo; +{ + BMW *bmw; + int tag, pos, cur; + + pos = xo->pos; + cur = pos - xo->top; + bmw = (BMW *) xo_pool + cur; + + if (tag = Tagger(bmw->btime, pos, TAG_TOGGLE)) + { + move(3 + cur, 6); + outc(tag > 0 ? '*' : ' '); + } + + /* return XO_NONE; */ + return xo->pos + 1 + XO_MOVE; /* lkchu.981201: ¸õ¦Ü¤U¤@¶µ */ +} + + +static int +bmw_help(xo) + XO *xo; +{ + xo_help("bmw"); + return bmw_head(xo); +} + + +KeyFunc bmw_cb[] = +{ + XO_INIT, bmw_init, + XO_LOAD, bmw_load, + XO_HEAD, bmw_head, + XO_BODY, bmw_body, + + 'd', bmw_delete, + 'D', bmw_rangedel, + 'm', bmw_mail, + 'w', bmw_write, + 'r', bmw_query, + Ctrl('Q'), bmw_query, + 's', bmw_init, + 'M', bmw_save, + 'u', bmw_save_user, + 't', bmw_tag, + Ctrl('D'), bmw_prune, + 'C', bmw_clear, + + 'h', bmw_help +}; + + +int +t_bmw() +{ +#if 0 /* itoc.010715: ¥Ñ©ó every_Z n¥Î¡A·h¥h talk_main ±`¾n */ + XO *xo; + char fpath[64]; + + usr_fpath(fpath, cuser.userid, fn_bmw); + xz[XZ_BMW - XO_ZONE].xo = xo = xo_new(fpath); + xover(XZ_BMW); + free(xo); +#endif + + xover(XZ_BMW); + return 0; +} + + +int +t_display() /* itoc.020126: display FN_AMW */ +{ + char fpath[64]; + + usr_fpath(fpath, cuser.userid, fn_amw); + return more(fpath, NULL); /* Thor.990204: ¥un¤£¬O XEASY ´N¥i¥H reload menu ¤F */ +} + + +#ifdef RETAIN_BMW +static void +bmw_retain(fpath) + char *fpath; +{ + char folder[64]; + HDR fhdr; + + usr_fpath(folder, str_sysop, fn_dir); + hdr_stamp(folder, HDR_COPY, &fhdr, fpath); + strcpy(fhdr.owner, cuser.userid); + strcpy(fhdr.title, "¤ô²y¦sÃÒ"); + fhdr.xmode = 0; + rec_add(folder, &fhdr, sizeof(HDR)); +} +#endif + + +#ifdef LOG_BMW +void +bmw_log() +{ + int op; + char fpath[64], buf[64]; + struct stat st; + + /* lkchu.981201: ©ñ¶i¨p¤H«H½c¤º/²M°£/«O¯d */ + usr_fpath(fpath, cuser.userid, fn_bmw); + + if (!stat(fpath, &st) && S_ISREG(st.st_mode)) + { + usr_fpath(buf, cuser.userid, fn_amw); + + if ((cuser.ufo & UFO_NWLOG) || !st.st_size) /* itoc.000512: ¤£Àx¦s¤ô²y°O¿ý */ + { /* itoc.020711: ¦pªG bmw size ¬O 0 ´N²M°£ */ + op = 'c'; + } + else + { + more(buf, (char *) -1); +#ifdef RETAIN_BMW + op = vans("¥»¦¸¤W¯¸¤ô²y³B²z (M)²¾¦Ü³Æ§Ñ¿ý (R)«O¯d (C)²M°£ (S)¦sÃÒ¡H[R] "); +#else + op = vans("¥»¦¸¤W¯¸¤ô²y³B²z (M)²¾¦Ü³Æ§Ñ¿ý (R)«O¯d (C)²M°£¡H[R] "); +#endif + } + + switch (op) + { + case 'm': + bmw_store(fpath); + + case 'c': + unlink(fpath); + unlink(buf); + break; + +#ifdef RETAIN_BMW + case 's': + if (vans("¦sÃÒ¬O§â¤ô²yÂà±Hµ¹¯¸ªø¥HÀËÁ|¨ä¥L¨Ï¥ÎªÌ¡A±z½T©wn¦sÃÒ¶Ü(Y/N)¡H[N] ") == 'y') + bmw_retain(buf); /* ¥Î¤£¯à§ïªº amw ¨Ó¦sÃÒ */ + break; +#endif + + default: + break; + } + } +} +#endif diff --git a/maple/board.c b/maple/board.c new file mode 100644 index 0000000..817ae8f --- /dev/null +++ b/maple/board.c @@ -0,0 +1,2259 @@ +/*-------------------------------------------------------*/ +/* board.c ( NTHU CS MapleBBS Ver 2.36 ) */ +/*-------------------------------------------------------*/ +/* target : ¬ÝªO¡B¸s²Õ¥\¯à */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +extern BCACHE *bshm; +extern XZ xz[]; +extern char xo_pool[]; + + +char brd_bits[MAXBOARD]; + +#ifndef ENHANCED_VISIT +time_t brd_visit[MAXBOARD]; /* ³ÌªñÂsÄý®É¶¡ */ +#endif + + +static char *class_img = NULL; +static XO board_xo; + +/* ´M§ä¬ÝªO¨ç¦¡; °½¦Û daemon/bmtad.c -> brd_get () */ +/* ¥u¥Î©ó talk.c -> do_query () */ +BRD * +has_personalbrd(bname) + char *bname; +{ + BRD *bhdr, *tail; + + bhdr = bshm->bcache; + tail = bhdr + bshm->number; + do + { + if (!str_cmp(bname, bhdr->brdname)) + return bhdr; + } while (++bhdr < tail); + return NULL; +} + + +/* ----------------------------------------------------- */ +/* ¬ÝªO¾\Ū°O¿ý .BRH (Board Reading History) */ +/* ----------------------------------------------------- */ + + +typedef struct BoardReadingHistory +{ + time_t bstamp; /* «Ø¥ß¬ÝªOªº®É¶¡, unique */ /* Thor.brh_tail */ + time_t bvisit; /* ¤W¦¸¾\ۮɶ¡ */ /* Thor.980904: ¨S¦bۮɩñ¤W¦¸Åªªº®É¶¡, ¥¿¦bۮɩñ bhno */ + int bcount; /* Thor.980902: ¨S¥Î¨ì */ + + /* --------------------------------------------------- */ + /* time_t {final, begin} / {final | BRH_SIGN} */ + /* --------------------------------------------------- */ + /* Thor.980904.µù¸Ñ: BRH_SIGN¥Nªífinal begin ¬Û¦P */ + /* Thor.980904.µù¸Ñ: ¥Ñ¤j¨ì¤p±Æ¦C,¦s©ñ¤wŪinterval */ +} BRH; + + +#define BRH_EXPIRE 180 /* Thor.980902.µù¸Ñ: «O¯d¦h¤Ö¤Ñ */ +#define BRH_MAX 200 /* Thor.980902.µù¸Ñ: ¨CªO³Ì¦h¦³´XÓ¼ÐÅÒ */ +#define BRH_PAGE 2048 /* Thor.980902.µù¸Ñ: ¨C¦¸¦h°t¶q, ¥Î¤£¨ì¤F */ +#define BRH_MASK 0x7fffffff /* Thor.980902.µù¸Ñ: ³Ì¤j¶q¬°2038¦~1¤ë¤¤*/ +#define BRH_SIGN 0x80000000 /* Thor.980902.µù¸Ñ: zap¤ÎÀ£final±M¥Î */ +#define BRH_WINDOW (sizeof(BRH) + sizeof(time_t) * BRH_MAX * 2) + + +static int *brh_base; /* allocated memory */ +static int *brh_tail; /* allocated memory */ +static int brh_size; /* allocated memory size */ +static time_t brh_expire; + + +static int * +brh_alloc(tail, size) + int *tail; + int size; +{ + int *base, n; + + base = brh_base; + n = (char *) tail - (char *) base; + size += n; + if (size > brh_size) + { + /* size = (size & -BRH_PAGE) + BRH_PAGE; */ + size += n >> 4; /* ¦h¹w¬ù¤@¨Ç°O¾ÐÅé */ + base = (int *) realloc((char *) base, size); + + if (base == NULL) + abort_bbs(); + + brh_base = base; + brh_size = size; + tail = (int *) ((char *) base + n); + } + + return tail; +} + + +static void +brh_put() +{ + int *list; + + /* compact the history list */ + + list = brh_tail; + + if (*list) + { + int *head, *tail, n, item, chrono; + + n = *++list; /* Thor.980904: ¥¿Åª®É¬Obhno */ + brd_bits[n] |= BRD_H_BIT; + time((time_t *) list); /* Thor.980904.µù¸Ñ: bvisit time */ + + item = *++list; + head = ++list; + tail = head + item; + + while (head < tail) + { + chrono = *head++; + n = *head++; + if (n == chrono) /* Thor.980904.µù¸Ñ: ¬Û¦Pªº®ÉÔÀ£°_¨Ó */ + { + n |= BRH_SIGN; + item--; + } + else + { + *list++ = chrono; + } + *list++ = n; + } + + list[-item - 1] = item; + *list = 0; + brh_tail = list; /* Thor.980904:·sªºªÅbrh */ + } +} + + +void +brh_get(bstamp, bhno) + time_t bstamp; /* board stamp */ + int bhno; +{ + int *head, *tail; + int size, bcnt, item; + char buf[BRH_WINDOW]; + + if (bstamp == *brh_tail) /* Thor.980904.µù¸Ñ: ¸ÓªO¤w¦b brh_tail¤W */ + return; + + brh_put(); + + bcnt = 0; + tail = brh_tail; + + if (brd_bits[bhno] & BRD_H_BIT) + { + head = brh_base; + while (head < tail) + { + item = head[2]; + size = item * sizeof(time_t) + sizeof(BRH); + + if (bstamp == *head) + { + bcnt = item; + memcpy(buf, head + 3, size); + tail = (int *) ((char *) tail - size); + if (item = (char *) tail - (char *) head) + memcpy(head, (char *) head + size, item); + break; + } + head = (int *) ((char *) head + size); + } + } + + brh_tail = tail = brh_alloc(tail, BRH_WINDOW); + + *tail++ = bstamp; + *tail++ = bhno; + + if (bcnt) /* expand history list */ + { + int *list; + + size = bcnt; + list = tail; + head = (int *) buf; + + do + { + item = *head++; + if (item & BRH_SIGN) + { + item ^= BRH_SIGN; + *++list = item; + bcnt++; + } + *++list = item; + } while (--size); + } + + *tail = bcnt; +} + + +int +brh_unread(chrono) + time_t chrono; +{ + int *head, *tail, item; + + /* itoc.010407.µù¸Ñ: BRH_EXPIRE (180) ¤Ñ«eªº¤å³¹³£³]¬°¤wŪ */ + if (chrono <= brh_expire) + return 0; + + head = brh_tail + 2; + if ((item = *head) > 0) + { + /* check {final, begin} history list */ + + head++; + tail = head + item; + do + { + if (chrono > *head) + return 1; + + head++; + if (chrono >= *head) + return 0; + + } while (++head < tail); + } + return 1; +} + + +void +brh_visit(mode) + int mode; /* 0 : visit, 1: un-visit */ +{ /* itoc.010207: ©Î¬O¶Ç¤Jchrono, ¥NªíŪ¦Üþ */ + int *list; + + list = (int *) brh_tail + 2; + *list++ = 2; + if (mode) + { + *list = mode; + } + else + { + time((time_t *)list); + } + /* *++list = mode; */ + *++list = 0; /* itoc.010207: ±j©w¬° 0, for ³¡¤À visit */ +} + + +int +brh_add(prev, chrono, next) + time_t prev, chrono, next; +{ + int *base, *head, *tail, item, final, begin; + + head = base = brh_tail + 2; + item = *head++; + tail = head + item; + + begin = BRH_MASK; + + while (head < tail) + { + final = *head; + if (chrono > final) + { + if (prev <= final) + { + if (next < begin) /* increase */ + *head = chrono; + else + { /* merge */ + *base = item - 2; + base = head - 1; + do + { + *base++ = *++head; + } while (head < tail); + } + return; + } + + if (next >= begin) + { + head[-1] = chrono; + return; + } + + break; + } + + begin = *++head; + head++; + } + + /* insert or append */ + + /* [21, 22, 23] ==> [32, 30] [15, 10] */ + + if (item < BRH_MAX) + { + /* [32, 30] [22, 22] [15, 10] */ + + *base = item + 2; + tail += 2; + } + else + { + /* [32, 30] [22, 10] */ /* Thor.980923: how about [6, 7, 8] ? [15, 7] ? */ + + tail--; + } + + prev = chrono; + for (;;) + { + final = *head; + *head++ = chrono; + + if (head >= tail) + return; + + begin = *head; + *head++ = prev; + + if (head >= tail) + return; + + chrono = final; + prev = begin; + } +} + + +/* ----------------------------------------------------- */ +/* board permission check */ +/* ----------------------------------------------------- */ + + +int /* >=1:²Ä´XÓªO¥D 0:¤£¬OªO¥D */ +is_bm(list, userid) + char *list; /* ªO¥D¡GBM list */ + char *userid; +{ + return str_has(list, userid, strlen(userid)); +} + + +static inline int +Ben_Perm(bno, ulevel) + int bno; + usint ulevel; +{ + usint readlevel, postlevel, bits; + char *blist, *bname; + BRD *brd; +#ifdef HAVE_MODERATED_BOARD + BPAL *bpal; + int ftype; /* 0:¤@¯ëID 1:ªO¦n 2:ªOÃa */ + + /* itoc.040103: ¬ÝªO¾\Ūµ¥¯Å»¡©úªí + + ¢z¢w¢w¢w¢w¢s¢w¢w¢w¢w¢s¢w¢w¢w¢w¢s¢w¢w¢w¢w¢{ + ¢x ¢x¤@¯ë¥Î¤á¢x¬ÝªO¦n¤Í¢x¬ÝªOÃa¤H¢x + ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢q¢w¢w¢w¢w¢q¢w¢w¢w¢w¢t + ¢x¤@¯ë¬ÝªO¢xÅv¨M©w¢x §¹¾ã ¢x ¤ô±í ¢x ¬Ý¤£¨£¡G¦b¬ÝªO¦Cªí¤¤µLªk¬Ý¨ì³oÓªO¡A¤]¶i¤£¥h + ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢q¢w¢w¢w¢w¢q¢w¢w¢w¢w¢t ¶i¤£¥h¡G¦b¬ÝªO¦Cªí¤¤¥i¥H¬Ý¨ì³oÓªO¡A¦ý¬O¶i¤£¥h + ¢x¦n¤Í¬ÝªO¢x ¶i¤£¥h ¢x §¹¾ã ¢x ¤ô±í ¢x ¤ô ±í¡G¦b¬ÝªO¦Cªí¤¤¥i¥H¬Ý¨ì³oÓªO¡A¤]¶i±o¥h¡A¦ý¬O¤£¯àµo¤å + ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢q¢w¢w¢w¢w¢q¢w¢w¢w¢w¢t §¹ ¾ã¡G¦b¬ÝªO¦Cªí¤¤¥i¥H¬Ý¨ì³oÓªO¡A¤]¶i±o¥h¤Îµo¤å + ¢x¯µ±K¬ÝªO¢x ¬Ý¤£¨£ ¢x §¹¾ã ¢x ¤ô±í ¢x + ¢|¢w¢w¢w¢w¢r¢w¢w¢w¢w¢r¢w¢w¢w¢w¢r¢w¢w¢w¢w¢} + */ + + static int bit_data[9] = + { /* ¤@¯ë¥Î¤á ¬ÝªO¦n¤Í ¬ÝªOÃa¤H */ + /* ¤½¶}¬ÝªO */ 0, BRD_L_BIT | BRD_R_BIT | BRD_W_BIT, BRD_L_BIT | BRD_R_BIT, + /* ¦n¤Í¬ÝªO */ BRD_L_BIT, BRD_L_BIT | BRD_R_BIT | BRD_W_BIT, BRD_L_BIT | BRD_R_BIT, + /* ¯µ±K¬ÝªO */ 0, BRD_L_BIT | BRD_R_BIT | BRD_W_BIT, BRD_L_BIT | BRD_R_BIT, + }; +#endif + + brd = bshm->bcache + bno; + bname = brd->brdname; + if (!*bname) + return 0; + + readlevel = brd->readlevel; + +#ifdef HAVE_MODERATED_BOARD + bpal = bshm->pcache + bno; + ftype = is_bgood(bpal) ? 1 : is_bbad(bpal) ? 2 : 0; + + if (readlevel == PERM_SYSOP) /* ¯µ±K¬ÝªO */ + bits = bit_data[6 + ftype]; + else if (readlevel == PERM_BOARD) /* ¦n¤Í¬ÝªO */ + bits = bit_data[3 + ftype]; + else if (ftype) /* ¤½¶}¬ÝªO¡AY¦bªO¦n/ªOÃa¦W³æ¤¤ */ + bits = bit_data[ftype]; + else /* ¤½¶}¬ÝªO¡A¨ä¥L¨ÌÅv§P©w */ +#endif + + if (!readlevel || (readlevel & ulevel)) + { + bits = BRD_L_BIT | BRD_R_BIT; + + postlevel = brd->postlevel; + if (!postlevel || (postlevel & ulevel)) + /* ¬ÝªO¨S¦³³]©wthat½Ö¥i¥Hµo¤å || ¬ÝªO¦³³]©wthat½Ö¥i¥Hµo¤å¦Ó¥B·í«e¥ÎªÌ²Å¦X¦¹Åv */ + bits |= BRD_W_BIT; + } + else + { + bits = 0; + } + + /* Thor.980813.µù¸Ñ: ¯S§O¬° BM ¦Ò¶q¡AªO¥D¦³¸ÓªOªº©Ò¦³Åv */ + blist = brd->BM; + if ((ulevel & PERM_BM) && blist[0] > ' ' && is_bm(blist, cuser.userid)) + bits = BRD_L_BIT | BRD_R_BIT | BRD_W_BIT | BRD_X_BIT | BRD_M_BIT; + + /* itoc.030515: ¬ÝªOÁ`ºÞ«·s§PÂ_ */ + if (ulevel & PERM_ALLBOARD) + { + /* chitsaou:060612: ¯¸°È¤£¯à¶i¤J¥¼¸g±ÂÅvªºªO */ + bits |= BRD_L_BIT; + + if (!strcmp(brd->class, "¯¸°È")) + bits = BRD_L_BIT | BRD_R_BIT | BRD_W_BIT | BRD_X_BIT | BRD_M_BIT; + + } +// bits = BRD_L_BIT | BRD_R_BIT | BRD_W_BIT | BRD_X_BIT; + + return bits; +} + + +/* ----------------------------------------------------- */ +/* ¸ü¤J currboard ¶i¦æY¤z³]©w */ +/* ----------------------------------------------------- */ + + +int +bstamp2bno(stamp) + time_t stamp; +{ + BRD *brd; + int bno, max; + + bno = 0; + brd = bshm->bcache; + max = bshm->number; + for (;;) + { + if (stamp == brd->bstamp) + return bno; + if (++bno >= max) + return -1; + brd++; + } +} + + +static inline void +brh_load() +{ + BRD *brdp; + usint ulevel; + int n, cbno; + char *bits; + + int size, *base; + time_t expire; + char fpath[64]; + +#ifndef ENHANCED_VISIT + time_t *bstp; +#endif + + memset(bits = brd_bits, 0, sizeof(brd_bits)); +#ifndef ENHANCED_VISIT + memset(bstp = brd_visit, 0, sizeof(brd_visit)); +#endif + + ulevel = cuser.userlevel; + n = 0; + cbno = bshm->number; + + do + { + *bits++ = Ben_Perm(n, ulevel); + } while (++n < cbno); + + /* --------------------------------------------------- */ + /* ±N .BRH ¸ü¤J memory */ + /* --------------------------------------------------- */ + + size = 0; + cbno = -1; + brh_expire = expire = time(0) - BRH_EXPIRE * 86400; + + if (ulevel) + { + struct stat st; + + usr_fpath(fpath, cuser.userid, FN_BRH); + if (!stat(fpath, &st)) + size = st.st_size; + } + + /* --------------------------------------------------- */ + /* ¦h«O¯d BRH_WINDOW ªº¹B§@ªÅ¶¡ */ + /* --------------------------------------------------- */ + + /* brh_size = n = ((size + BRH_WINDOW) & -BRH_PAGE) + BRH_PAGE; */ + brh_size = n = size + BRH_WINDOW; + brh_base = base = (int *) malloc(n); + + if (size && ((n = open(fpath, O_RDONLY)) >= 0)) + { + int *head, *tail, *list, bstamp, bhno; + + size = read(n, base, size); + close(n); + + /* compact reading history : remove dummy/expired record */ + + head = base; + tail = (int *) ((char *) base + size); + bits = brd_bits; + + while (head < tail && head >= brh_base) + { + bstamp = *head; + + if (bstamp & BRH_SIGN) /* zap */ + { + bstamp ^= BRH_SIGN; + bhno = bstamp2bno(bstamp); + if (bhno >= 0) + { + /* itoc.001029: NOZAP®É, ¤´·|¥X²{ */ + brdp = bshm->bcache + bhno; + if (!(brdp->battr & BRD_NOZAP)) + bits[bhno] |= BRD_Z_BIT; + } + head++; + continue; + } + + bhno = bstamp2bno(bstamp); + list = head + 2; + + if (list > tail) + break; + + n = *list; + size = n + 3; + + /* ³oӬݪO¦s¦b¡B¨S¦³³Q zap ±¼¡B¥i¥H list */ + + if (bhno >= 0 && (bits[bhno] & BRD_L_BIT)) + { + bits[bhno] |= BRD_H_BIT;/* ¤w¦³¾\Ū°O¿ý */ + +#ifndef ENHANCED_VISIT + bstp[bhno] = head[1]; /* ¤W¦¸¾\ۮɶ¡ */ +#endif + + cbno = bhno; + + if (n > 0) + { + list += n; /* Thor.980904.µù¸Ñ: ³Ì«á¤@Ó tag */ + + if (list > tail) + break; + + do + { + bhno = *list; + if ((bhno & BRH_MASK) > expire) + break; + + if (!(bhno & BRH_SIGN)) + { + if (*--list > expire) + break; + n--; + } + + list--; + n--; + } while (n > 0); + + head[2] = n; + } + + n = n * sizeof(time_t) + sizeof(BRH); + if (base != head) + memcpy(base, head, n); + base = (int *) ((char *) base + n); + } + head += size; + } + } + + *base = 0; + brh_tail = base; +} + + +void +brh_save() +{ + int *base, *head, *tail, bhno, size; + BRD *bhdr, *bend; + char *bits; + + /* Thor.980830: lkchu patch: ÁÙ¨S load ´N¤£¥Î save */ + if (!(base = brh_base)) + return; + + brh_put(); + + /* save history of un-zapped boards */ + + bits = brd_bits; + head = base; + tail = brh_tail; + while (head < tail) + { + bhno = bstamp2bno(*head); + size = head[2] * sizeof(time_t) + sizeof(BRH); + if (bhno >= 0 && !(bits[bhno] & BRD_Z_BIT)) + { + if (base != head) + memcpy(base, head, size); + base = (int *) ((char *) base + size); + } + head = (int *) ((char *) head + size); + } + + /* save zap record */ + + tail = brh_alloc(base, sizeof(time_t) * MAXBOARD); + + bhdr = bshm->bcache; + bend = bhdr + bshm->number; + do + { + if (*bits++ & BRD_Z_BIT) + { + *tail++ = bhdr->bstamp | BRH_SIGN; + } + } while (++bhdr < bend); + + /* OK, save it */ + + base = brh_base; + if ((size = (char *) tail - (char *) base) > 0) + { + char fpath[64]; + int fd; + + usr_fpath(fpath, cuser.userid, FN_BRH); + if ((fd = open(fpath, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0) + { + write(fd, base, size); + close(fd); + } + } +} + + +/* ----------------------------------------------------- */ +/* ¤ÀÃþ zap °O¿ý .CZH (Class Zap History) */ +/* ----------------------------------------------------- */ + + +typedef struct ClassZapHistory +{ + char brdname[BNLEN + 1]; /* ¤ÀÃþªº brdname */ +} CZH; + + +static char class_bits[CH_MAX + 3]; + + +static int /* >=0:pos -1:¤£¦b .CZH */ +czh_find(fpath, brdname) /* Àˬd¬O§_¤w¸g¦b .CZH ¤º */ + char *fpath; + char *brdname; +{ + CZH czh; + int fd, pos; + int rc = -1; + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + pos = 0; + while (read(fd, &czh, sizeof(CZH)) == sizeof(CZH)) + { + if (!strcmp(czh.brdname, brdname)) + { + rc = pos; + break; + } + pos++; + } + close(fd); + } + return rc; +} + + +static int /* >=0:¦b .CZH -1:¤£¦b .CZH */ +czh_put(brdname) + char *brdname; +{ + char fpath[64]; + int pos; + + usr_fpath(fpath, cuser.userid, FN_CZH); + + /* Y¤w¸g¦b .CZH ¤ºªº¸Ü¡A«h§R°£¦¹µ§¸ê®Æ¡FY¤£¦b .CZH ¤ºªº¸Ü¡A«h¥[¤J¦¹µ§¸ê®Æ */ + if ((pos = czh_find(fpath, brdname)) >= 0) + rec_del(fpath, sizeof(CZH), pos, NULL); + else + rec_add(fpath, brdname, sizeof(CZH)); + + return pos; +} + + +static void +czh_load() +{ + int fsize, chn, min_chn; + short *chx; + char *img, fpath[64]; + CZH *chead, *ctail, *czh; + + memset(class_bits, 0, sizeof(class_bits)); + + usr_fpath(fpath, cuser.userid, FN_CZH); + if (chead = (CZH *) f_img(fpath, &fsize)) + { + min_chn = bshm->min_chn; + + czh = chead; + ctail = chead + fsize / sizeof(CZH); + img = class_img; + do + { + for (chn = CH_END - 2;; chn--) /* ¦b©Ò¦³ªº¤ÀÃþ¤¤§ä¤@ÓªO¦W¬Û¦Pªº */ + { + chx = (short *) img + (CH_END - chn); + if (!strncmp(czh->brdname, img + *chx, BNLEN)) + { + class_bits[-chn] |= BRD_Z_BIT; + break; + } + if (chn <= min_chn) /* ¦pªG§ä¤£¨ì¡Aªí¥Ü¸Ó¤ÀÃþ¤w®ø¥¢¡A±q .CZH §R°£ */ + { + czh_put(czh->brdname); + break; + } + } + } while (++czh < ctail); + free(chead); + } +} + +static void +brd_usies() +{ + char fpath[64], buf[256]; + + brd_fpath(fpath, currboard, "usies"); + sprintf(buf, "%s %s\n", Now(), cuser.userid); + f_cat(fpath, buf); +} + + + +/*-------------------------------------------------------*/ + + +int +XoPost(bno) + int bno; +{ + XO *xo; + BRD *brd; + int bits; + char *str, fpath[64]; + + brd = bshm->bcache + bno; + if (!brd->brdname[0]) /* ¤w§R°£ªº¬ÝªO */ + return -1; + + bits = brd_bits[bno]; + + if (currbno != bno) /* ¬ÝªO¨S´«³q±`¬O¦]¬° every_Z() ¦^ì¬ÝªO */ + { +#ifdef HAVE_MODERATED_BOARD + if (!(bits & BRD_R_BIT)) + { + vmsg("¹ï¤£°_¡A¦¹ªO¥uãªO¤Í¶i¤J¡A½Ð¦VªO¥D¥Ó½Ð¤J¹Ò³\\¥i"); + return -1; + } +#endif + + /* lantw44: ³B²z¬ÝªOÂê©w */ + brd_fpath(fpath, brd->brdname, fn_lock); + struct stat trash; + char lock_perm = 0; + char can_enter = 0; + char is_admin = 0; + char lock_type,lock_id[IDLEN + 1]; + if(stat(fpath, &trash) >= 0){ + /* lock_type = '0' ªí¥Ü¤j®a³£¶i¤£¥h + * lock_type = '1' ªí¥ÜÂê©wªÌ¥i¶i¤J */ + brd_getlockinfo(fpath, &lock_type, lock_id, NULL); + if(lock_type == '1' && !strcmp(lock_id, cuser.userid)){ + can_enter = 1; + } + if(bits & BRD_X_BIT){ + if(HAS_PERM(PERM_ALLBOARD)){ + lock_perm = 1; + is_admin = 1; + }else{ + switch(is_bm(brd->BM, cuser.userid)){ + case 0: + break; + case 1: + lock_perm = 1; + break; + default: + if(!strcmp(lock_id,cuser.userid)){ + lock_perm = 1; + } + } + } + } + brd_viewlock(fpath); + if(lock_perm && !is_admin){ + if(can_enter){ + if(vans("½Ð°Ý±zn [E]¶i¤J¬ÝªO (M)×§ïÂê©wª¬ºA ")=='m'){ + brd_editlock(fpath); + } + }else{ + if(vans("½Ð°Ý±zn×§ïÂê©wª¬ºA¶Ü¡H[N]")=='y'){ + brd_editlock(fpath); + } + return -1; + } + }else{ + if(!can_enter){ + vmsg("¥Ø«e¦¹¬ÝªO¤w¸gÂê©w¡A±zµLªk¶i¤J"); + return -1; + } + } + } + + /* ³B²zÅv */ + bbstate = STAT_STARTED; + if (bits & BRD_M_BIT) + bbstate |= (STAT_BM | STAT_BOARD | STAT_POST); + else if (bits & BRD_X_BIT) + bbstate |= (STAT_BOARD | STAT_POST); + else if (bits & BRD_W_BIT) + bbstate |= STAT_POST; + + /* itoc.050613.µù¸Ñ: ¤H®ðªº´î¤Ö¤£¬O¦bÂ÷¶}¬ÝªO®É¡A¦Ó¬O¦b¶i¤J·sªº¬ÝªO©Î¬OÂ÷¯¸®É¡A + ³o¬O¬°¤FÁ×§K switch ¸õ¬ÝªO·|ºâ¿ù¤H®ð */ + if (currbno >= 0) + bshm->mantime[currbno]--; /* °h¥X¤W¤@ÓªO */ + bshm->mantime[bno]++; /* ¶i¤J·sªºªO */ + + currbno = bno; + currbattr = brd->battr; + strcpy(currboard, brd->brdname); + str = brd->BM; + sprintf(currBM, "ªO¥D¡G%s", *str <= ' ' ? "¼x¨D¤¤" : str); +#ifdef HAVE_BRDMATE + strcpy(cutmp->reading, currboard); +#endif + + + brd_fpath(fpath, currboard, fn_dir); + +#ifdef AUTO_JUMPPOST + xz[XZ_POST - XO_ZONE].xo = xo = xo_get_post(fpath, brd); /* itoc.010910: ¬° XoPost ¶q¨¥´³y¤@¤ä xo_get() */ +#else + xz[XZ_POST - XO_ZONE].xo = xo = xo_get(fpath); +#endif + xo->key = XZ_POST; + xo->xyz = brd->title; + } + + /* itoc.011113: ²Ä¤@¦¸¶iªO¤@©wn¬Ý¶iªOµe±¡A²Ä¤G¦¸¥H«á«h¨ú¨M ufo ³]©w */ + if (!(bits & BRD_V_BIT) || (cuser.ufo & UFO_BRDNOTE)) + { + brd_bits[bno] = bits | BRD_V_BIT; + brd_fpath(fpath, currboard, fn_note); + more(fpath, NULL); + } + + brh_get(brd->bstamp, bno); + if (!(brd->battr & BRD_ANONYMOUS)) + brd_usies(); +// xo->pos = (brd->btime < 0 ? rec_num(fpath, sizeof(HDR)) : brd->bpost) - 1; + return 0; +} + +void brd_editlock(const char* fpath){ + struct stat trash; + char type,userid[IDLEN + 1],reason[49]; + switch(vans("L)Âê©w M)×§ï²z¥Ñ U)¸ÑÂê¡H[Q]")){ + case 'l': + if(stat(fpath,&trash)>=0){ + vmsg("³oӬݪO¥Ø«e¤w¸g³B©óÂê©wª¬ºA"); + break; + } + if(vans("Âê©wÃþ«¬ (1)¤¹³\\¦Û¤v¥i¥H¶i¤J¬ÝªO [2]©Ò¦³¤H¬ÒµLªk¶i¤J¬ÝªO¡H")=='1'){ + type = '1'; + }else{ + type = '0'; + } + vget(b_lines, 0, "²z¥Ñ¡G", reason, 48, DOECHO); + strcpy(userid, cuser.userid); + if(vans(msg_sure_ny)=='y'){ + brd_setlockinfo(fpath,type,userid,reason); + } + break; + break; + case 'm': + if(stat(fpath,&trash)<0){ + vmsg("³oӬݪO¨Ã¥¼Âê©w"); + break; + } + brd_getlockinfo(fpath,&type,userid,reason); + if(HAS_PERM(PERM_ALLBOARD)){ + vget(b_lines, 0, "¥Ñ½ÖÂê©w¡G", userid, IDLEN + 1, GCARRY); + } + vget(b_lines, 0, "²z¥Ñ¡G", reason, 48, GCARRY); + if(vans(msg_sure_ny)=='y'){ + brd_setlockinfo(fpath,type,userid,reason); + } + break; + case 'u': + if(stat(fpath,&trash)<0){ + vmsg("³oӬݪO¨Ã¥¼Âê©w"); + break; + } + unlink(fpath); + } +} + +void brd_viewlock(const char* fpath){ + /* move(19,0),clrtobot(),refresh(); */ + char userid[IDLEN + 1],reason[49]; + brd_getlockinfo(fpath, NULL, userid, reason); + char buf[80]; + sprintf(buf, "Âê©wªÌ¡G%s", userid); + vmsg(buf); + sprintf(buf, "²z¥Ñ¡G%s", reason); + vmsg(buf); +} +/* + prints("\033[1;33m[¥Ñ½ÖÂê©w]\033[m %s\n", userid); + prints("\033[1;33m[Âê©w²z¥Ñ]\033[m %s\n", reason); +*/ +void brd_getlockinfo(fpath, type, userid, reason) + const char* fpath; + char* type; + char* userid; + char* reason; +{ + FILE* fp = fopen(fpath, "r"); + if(fp == NULL){ + strcpy(userid, "Ū¨ú¥¢±Ñ"); + strcpy(reason, "Ū¨ú¥¢±Ñ"); + return; + } + if(type != NULL){ + *type = getc(fp); + }else{ + fseek(fp, 1, SEEK_CUR); + } + if(userid != NULL){ + fread(userid, IDLEN, 1, fp); + userid[IDLEN] = '\0'; + int i; + for(i=0;i<IDLEN;i++){ + if(userid[i]=='\033'){ + userid[i]='\0'; + break; + } + } + }else{ + fseek(fp, IDLEN, SEEK_CUR); + } + if(reason != NULL){ + fread(reason, 48, 1, fp); + reason[48]='\0'; + int i; + for(i=0;i<48;i++){ + if(reason[i]=='\033'){ + reason[i]='\0'; + break; + } + } + }else{ + fseek(fp, 48, SEEK_CUR); + } + fclose(fp); +} + +void brd_setlockinfo(fpath, type, userid, reason) + const char* fpath; + char type; + const char* userid; + const char* reason; +{ + FILE* fp = fopen(fpath, "w"); + if(fp == NULL){ + return; + } + putc(type, fp); + char tmpid[IDLEN], tmprs[48]; + int i; + char complete_flag; + for(i=0,complete_flag=0;i<IDLEN;i++){ + if(complete_flag){ + tmpid[i]='\033'; + }else{ + if(userid[i]=='\0'){ + tmpid[i]='\033'; + complete_flag = 1; + }else{ + tmpid[i]=userid[i]; + } + } + } + fwrite(tmpid, IDLEN, 1, fp); + for(i=0,complete_flag=0;i<48;i++){ + if(complete_flag){ + tmprs[i]='\033'; + }else{ + if(reason[i]=='\0'){ + tmprs[i]='\033'; + complete_flag = 1; + }else{ + tmprs[i]=reason[i]; + } + } + } + fwrite(tmprs, 48, 1, fp); + fclose(fp); +} + +#ifdef HAVE_FORCE_BOARD +void +brd_force() /* itoc.010407: ±j¨î¾\Ū¤½§iªO¡A¥B±j¢Åª³Ì«á¤@½g */ +{ + if (cuser.userlevel) /* guest ¸õ¹L */ + { + int bno; + BRD *brd; + + if ((bno = brd_bno(BN_ANNOUNCE)) < 0) + return; + brd = bshm->bcache + bno; + if (brd->btime < 0) /* ©|¥¼§ó·s brd->blast ´N¤£±j¨î¾\Ū¤½§iªO */ + return; + +#ifdef ENHANCED_VISIT + brh_get(brd->bstamp, bno); + while (brh_unread(brd->blast)) +#else + if (brd->blast > brd_visit[bno]) +#endif + { + vmsg("¦³·s¤½§i¡I½Ð¥ý¾\\Ū§¹·s¤½§i«á¦AÂ÷¶}"); + XoPost(bno); + xover(XZ_POST); + +#ifndef ENHANCED_VISIT + time(&brd_visit[bno]); +#endif + } + } +} +#endif /* HAVE_FORCE_BOARD */ + + +/* ----------------------------------------------------- */ +/* Class [¤ÀÃþ¸s²Õ] */ +/* ----------------------------------------------------- */ + + +#ifdef MY_FAVORITE +int class_flag = 0; /* favorite.c n¥Î */ +#else +static int class_flag = 0; +#endif + + +#ifdef AUTO_JUMPBRD +static int class_jumpnext = 0; /* itoc.010910: ¬O§_¸õ¥h¤U¤@Ó¥¼ÅªªO 1:n 0:¤£n */ +#endif + + +#define BFO_YANK 0x01 + + +static int +class_load(xo) + XO *xo; +{ + short *cbase, *chead, *ctail; + int chn; /* ClassHeader number */ + int pos, max, val, zap; + BRD *brd; + char *bits; + + /* lkchu.990106: ¨¾¤î ¥¼¥Î account ³y¥X class.img ©Î¨S¦³ class ªº±¡ªp */ + if (!class_img) + return 0; + + chn = CH_END - xo->key; + + cbase = (short *) class_img; + chead = cbase + chn; + + pos = chead[0] + CH_TTLEN; + max = chead[1]; + + chead = (short *) ((char *) cbase + pos); + ctail = (short *) ((char *) cbase + max); + + max -= pos; + + if (cbase = (short *) xo->xyz) + cbase = (short *) realloc(cbase, max); + else + cbase = (short *) malloc(max); + + xo->xyz = (char *) cbase; + + max = 0; + brd = bshm->bcache; + bits = brd_bits; + zap = (class_flag & BFO_YANK) ? 0 : BRD_Z_BIT; + + do + { + chn = *chead++; + if (chn >= 0) /* ¤@¯ë¬ÝªO */ + { + val = bits[chn]; + if (!(val & BRD_L_BIT) || (val & zap) || !(brd[chn].brdname[0])) + continue; + } + else /* ¤ÀÃþ¸s²Õ */ + { + if (class_bits[-chn] & zap) + continue; + } + + max++; + *cbase++ = chn; + } while (chead < ctail); + + xo->max = max; + if (xo->pos >= max) + xo->pos = xo->top = 0; + + return max; +} + + +static int +XoClass(chn) + int chn; +{ + XO xo, *xt; + + /* Thor.980727: ¸Ñ¨M XO xoªº¤£½T©w©Ê, + class_load¤º³¡·| initial xo.max, ¨ä¥L¤£½T©w */ + xo.pos = xo.top = 0; + + xo.key = chn; + xo.xyz = NULL; + if (!class_load(&xo)) + { + if (xo.xyz) + free(xo.xyz); + return 0; + } + + xt = xz[XZ_CLASS - XO_ZONE].xo; + xz[XZ_CLASS - XO_ZONE].xo = &xo; + +#ifdef AUTO_JUMPBRD + if (cuser.ufo & UFO_JUMPBRD) + class_jumpnext = 1; /* itoc.010910: ¥D°Ê¸õ¥h¤U¤@Ó¥¼Åª¬ÝªO */ +#endif + xover(XZ_CLASS); + + free(xo.xyz); + xz[XZ_CLASS - XO_ZONE].xo = xt; + + return 1; +} + + +static inline void +btime_refresh(brd) + BRD *brd; +{ + /* itoc.020123: ¤£ºÞ¦³µL UFO_BRDPOST¡A¤@·§§ó·s¡A¥H§K¥¼Åª¿O¤£·|«G */ + if (brd->btime < 0) + { + int fd, fsize; + char folder[64]; + struct stat st; + + brd->btime = 1; + brd_fpath(folder, brd->brdname, fn_dir); + if ((fd = open(folder, O_RDONLY)) >= 0) + { + if (!fstat(fd, &st) && (fsize = st.st_size) >= sizeof(HDR)) + { +#ifdef ENHANCED_BSHM_UPDATE + HDR hdr; + + brd->bpost = fsize / sizeof(HDR); + /* itoc.020829: §ä³Ì«á¤@½g¥¼³Q¥[±K¡B¤£¬O¸m©³ªº HDR */ + while ((fsize -= sizeof(HDR)) >= 0) + { + lseek(fd, fsize, SEEK_SET); + read(fd, &hdr, sizeof(HDR)); + if (!(hdr.xmode & (POST_RESTRICT | POST_BOTTOM))) + break; + } + brd->blast = hdr.chrono; +#else + brd->bpost = fsize / sizeof(HDR); + lseek(fd, fsize - sizeof(HDR), SEEK_SET); + read(fd, &brd->blast, sizeof(time_t)); +#endif + } + else + { + brd->blast = brd->bpost = 0; + } + close(fd); + } + } +} + + +void +class_item(num, bno, brdpost) + int num, bno, brdpost; +{ + BRD *brd; + char *str1, *str2, *str3, token, buf[16]; + + brd = bshm->bcache + bno; + + btime_refresh(brd); + + /* ³B²z ½s¸¹/½g¼Æ */ + if (brdpost) + num = brd->bpost; + + /* ³B²z zap/friend/secret ªOªº²Å¸¹ */ + if (brd_bits[bno] & BRD_Z_BIT) + token = TOKEN_ZAP_BRD; + else if (brd->readlevel == PERM_SYSOP) + token = TOKEN_SECRET_BRD; + else if (brd->readlevel == PERM_BOARD) + token = TOKEN_FRIEND_BRD; + else if ((brd->readlevel & 0xFF000000) && !((brd->readlevel) & (PERM_BASIC | PERM_CHAT | PERM_PAGE | PERM_POST | PERM_VALID))){ + token = '#'; + } + else + token = ' '; + + /* ³B²z ¤wŪ/¥¼Åª */ +#ifdef ENHANCED_VISIT + /* itoc.010407: §ï¥Î³Ì«á¤@½g¤wŪ/¥¼Åª¨Ó§PÂ_ */ + brh_get(brd->bstamp, bno); + str1 = brh_unread(brd->blast) ? ICON_UNREAD_BRD : ICON_READ_BRD; +#else + str1 = brd->blast > brd_visit[bno] ? ICON_UNREAD_BRD : ICON_READ_BRD; +#endif + + /* ³B²z §ë²¼/Âà«H */ + if (brd->bvote) + str2 = (brd->bvote > 0) ? ICON_VOTED_BRD : ICON_GAMBLED_BRD; + else + str2 = (brd->battr & BRD_NOTRAN) ? ICON_NOTRAN_BRD : ICON_TRAN_BRD; + + /* ³B²z ¤H®ð */ + bno = bshm->mantime[bno]; +// if (bno > 99) +// str3 = "\033[1;31mÃz\033[m"; + if (bno > 30) + str3 = "\033[1;33;41mÃz\033[m"; + else if (bno >= 20) + str3 = "\033[1;33mµo\033[m"; + else if (bno >= 10) + str3 = "\033[1;31mµo\033[m"; + else if (bno >= 5) + sprintf(str3 = buf, "\033[1m%2d\033[m", bno); + else if (bno >= 1) + sprintf(str3 = buf, "\033[m%2d\033[m", bno); +// else if (bno > 0) +// sprintf(str3 = buf, "%2d", bno); + else + str3 = " "; + + /* itoc.010909: ªO¦W¤Óªøªº§R±¼¡B¥[¤ÀÃþÃC¦â¡C°²³] BCLEN = 4 */ + prints("%6d%c%s%-13s\033[1;3%dm%-5s\033[m%s %-*.*s %s %.*s\n", + num, token, str1, brd->brdname, + brd->class[3] & 7, brd->class, str2, + (d_cols >> 1) + 32, (d_cols >> 1) + 33, brd->title, str3, + d_cols - (d_cols >> 1) + 12, brd->BM); +} + + +static int +class_body(xo) + XO *xo; +{ + short *chp; + BRD *bcache; + int n, cnt, max, chn, brdpost; +#ifdef AUTO_JUMPBRD + int nextpos; +#endif + + bcache = bshm->bcache; + max = xo->max; + cnt = xo->top; + +#ifdef AUTO_JUMPBRD + nextpos = 0; + + /* itoc.010910: ·j´M¤U¤@Ó¥¼Åª¬ÝªO */ + if (class_jumpnext) + { + class_jumpnext = 0; + n = xo->pos; + chp = (short *) xo->xyz + n; + + while (n < max) + { + chn = *chp++; + if (chn >= 0) + { + BRD *brd; + + brd = bcache + chn; + +#ifdef ENHANCED_VISIT + /* itoc.010407: §ï¥Î³Ì«á¤@½g¤wŪ/¥¼Åª¨Ó§PÂ_ */ + brh_get(brd->bstamp, chn); + if (brh_unread(brd->blast)) +#else + if (brd->blast > brd_visit[chn]) +#endif + { + nextpos = n; + break; + } + } + n++; + } + + /* ¤U¤@Ó¥¼ÅªªO¦b§O¶¡An½¹L¥h */ + if (nextpos >= cnt + XO_TALL) + return nextpos + XO_MOVE; + } +#endif + + brdpost = class_flag & UFO_BRDPOST; + chp = (short *) xo->xyz + cnt; + + n = 3; + move(3, 0); + do + { + chn = *chp; + if (cnt < max) + { + clrtoeol(); + cnt++; + if (chn >= 0) /* ¤@¯ë¬ÝªO */ + { + class_item(cnt, chn, brdpost); + } + else /* ¤ÀÃþ¸s²Õ */ + { + short *chx; + char *img, *str; + + img = class_img; + chx = (short *) img + (CH_END - chn); + str = img + *chx; + prints("%6d%c %-13.13s\033[1;3%dm%-5.5s\033[m%s\n", + cnt, class_bits[-chn] & BRD_Z_BIT ? TOKEN_ZAP_BRD : ' ', + str, str[BNLEN + 4] & 7, str + BNLEN + 1, str + BNLEN + 1 + BCLEN + 1); + } + chp++; + } + else + { + clrtobot(); + break; + } + } while (++n < b_lines); + +#ifdef AUTO_JUMPBRD + /* itoc.010910: ¤U¤@Ó¥¼ÅªªO¦b¥»¶¡An§â´å¼Ð²¾¹L¥h */ + outf(FEETER_CLASS); + return nextpos ? nextpos + XO_MOVE : XO_NONE; +#else + /* return XO_NONE; */ + return XO_FOOT; /* itoc.010403: §â b_lines ¶ñ¤W feeter */ +#endif +} + + +static int +class_neck(xo) + XO *xo; +{ + move(1, 0); + prints(NECKER_CLASS, + class_flag & UFO_BRDPOST ? "Á`¼Æ" : "½s¸¹", + d_cols >> 1, "", d_cols - (d_cols >> 1), ""); + return class_body(xo); +} + + +static int +class_head(xo) + XO *xo; +{ + vs_head("¬ÝªO¦Cªí", str_site); + return class_neck(xo); +} + + +static int +class_init(xo) /* re-init */ + XO *xo; +{ + class_load(xo); + return class_head(xo); +} + + +static int +class_postmode(xo) + XO *xo; +{ + cuser.ufo ^= UFO_BRDPOST; + cutmp->ufo = cuser.ufo; + class_flag ^= UFO_BRDPOST; + return class_neck(xo); +} + + +static int +class_namemode(xo) /* itoc.010413: ¬ÝªO¨Ì·Ó¦r¥À/¤ÀÃþ±Æ¦C */ + XO *xo; +{ + static time_t last = 0; + time_t now; + + if (time(&now) - last < 10) + { + vmsg("¨C¤Q¬íÄÁ¥u¯à¤Á´«¤@¦¸"); + return XO_FOOT; + } + last = now; + + if (cuser.userlevel) + brh_save(); /* itoc.010711: Àx¦s¾\Ū°O¿ýÀÉ */ + cuser.ufo ^= UFO_BRDNAME; + cutmp->ufo = cuser.ufo; + board_main(); /* «·s¸ü¤J class_img */ + return class_neck(xo); +} + + +static int +class_help(xo) + XO *xo; +{ + xo_help("class"); + return class_head(xo); +} + + +static int +class_search(xo) + XO *xo; +{ + int num, pos, max; + char buf[BNLEN + 1]; + + if (vget(b_lines, 0, MSG_BID, buf, BNLEN + 1, DOECHO)) + { + short *chp, chn; + BRD *bcache, *brd; + + str_lowest(buf, buf); + + bcache = bshm->bcache; + pos = num = xo->pos; + max = xo->max; + chp = (short *) xo->xyz; + + do + { + if (++pos >= max) + pos = 0; + chn = chp[pos]; + if (chn >= 0) + { + brd = bcache + chn; + if (str_str(brd->brdname, buf) || str_sub(brd->title, buf)) + { + outf(FEETER_CLASS); /* itoc.010913: §â b_lines ¶ñ¤W feeter */ + return pos + XO_MOVE; + } + } + } while (pos != num); + } + + return XO_FOOT; +} + + +static int +class_searchBM(xo) + XO *xo; +{ + int num, pos, max; + char buf[IDLEN + 1]; + + if (vget(b_lines, 0, "½Ð¿é¤JªO¥D¡G", buf, IDLEN + 1, DOECHO)) + { + short *chp, chn; + BRD *bcache, *brd; + + str_lower(buf, buf); + + bcache = bshm->bcache; + pos = num = xo->pos; + max = xo->max; + chp = (short *) xo->xyz; + + do + { + if (++pos >= max) + pos = 0; + chn = chp[pos]; + if (chn >= 0) + { + brd = bcache + chn; + if (str_str(brd->BM, buf)) + { + outf(FEETER_CLASS); /* itoc.010913: §â b_lines ¶ñ¤W feeter */ + return pos + XO_MOVE; + } + } + } while (pos != num); + } + + return XO_FOOT; +} + + +static int +class_yank(xo) + XO *xo; +{ + /* itoc.001029: ©Ò¦³ªºclass,board¦Cªí¤U, key < 0, 1 «h¬°§ä´M§@ªÌ¼Ò¦¡ + ¨Ï¨ä¤£¯à¶] XO_INIT(ùرªºclass_load), ¦p class_yank, + °£¤F¨¾¤î§ä¥Xªº§@ªÌ¬ÝªO¦Cªí®ø¥¢, ¤]¨¾½ð¤H */ + if (xo->key >= 0) + return XO_NONE; + + class_flag ^= BFO_YANK; + return class_init(xo); +} + + +static int +class_zap(xo) + XO *xo; +{ + BRD *brd; + short *chp; + int pos, num, chn; + char token; + + pos = xo->pos; + chp = (short *) xo->xyz + pos; + chn = *chp; + if (chn >= 0) /* ¤@¯ë¬ÝªO */ + { + brd = bshm->bcache + chn; + if (!(brd->battr & BRD_NOZAP)) + { + /* itoc.010909: nÀH class_item() ª©±ÅÜ */ + move(3 + pos - xo->top, 6); + num = brd_bits[chn] ^= BRD_Z_BIT; + + /* ³B²z zap/friend/secret ªOªº²Å¸¹ */ + if (num & BRD_Z_BIT) + token = TOKEN_ZAP_BRD; + else if (brd->readlevel == PERM_SYSOP) + token = TOKEN_SECRET_BRD; + else if (brd->readlevel == PERM_BOARD) + token = TOKEN_FRIEND_BRD; + else + token = ' '; + + outc(token); + } + } + else /* ¤ÀÃþ¸s²Õ */ + { + short *chx; + char *img, brdname[BNLEN + 1]; + + /* itoc.010909: nÀH class_body() ª©±ÅÜ */ + move(3 + pos - xo->top, 6); + num = class_bits[-chn] ^= BRD_Z_BIT; + outc(num & BRD_Z_BIT ? TOKEN_ZAP_BRD : ' '); + + img = class_img; + chx = (short *) img + (CH_END - chn); + str_ncpy(brdname, img + *chx, BNLEN + 1); + czh_put(brdname); + } + + /* return XO_NONE; */ + return XO_MOVE + pos + 1; /* itoc.020219: ¸õ¦Ü¤U¤@¶µ */ +} + + +static int +class_zapall(xo) + XO *xo; +{ + BRD *brdp, *bend; + int ans, bno; + + ans = vans("³]©w©Ò¦³¬ÝªO (U)q¾\\ (Z)¤£q¾\\ (Q)¨ú®ø¡H [Q] "); + if (ans != 'z' && ans != 'u') + return XO_FOOT; + + brdp = bshm->bcache; + bend = brdp + bshm->number; + bno = 0; + do + { + if (ans == 'z') + { + if (!(brdp->battr & BRD_NOZAP)) + brd_bits[bno] |= BRD_Z_BIT; + } + else + { + brd_bits[bno] &= ~BRD_Z_BIT; + } + + bno++; + } while (++brdp < bend); + + class_flag |= BFO_YANK; /* ±j¢ yank °_¨Ó¬Ýµ²ªG */ + return class_init(xo); +} + + +static int +class_visit(xo) /* itoc.010128: ¬ÝªO¦Cªí³]©w¬ÝªO¤wŪ */ + XO *xo; +{ + short *chp; + int chn; + + chp = (short *) xo->xyz + xo->pos; + chn = *chp; + if (chn >= 0) + { + BRD *brd; + brd = bshm->bcache + chn; + brh_get(brd->bstamp, chn); + brh_visit(0); +#ifndef ENHANCED_VISIT + time(&brd_visit[chn]); +#endif + } + return class_body(xo); +} + + +static int +class_unvisit(xo) /* itoc.010129: ¬ÝªO¦Cªí³]©w¬ÝªO¥¼Åª */ + XO *xo; +{ + short *chp; + int chn; + + chp = (short *) xo->xyz + xo->pos; + chn = *chp; + if (chn >= 0) + { + BRD *brd; + brd = bshm->bcache + chn; + brh_get(brd->bstamp, chn); + brh_visit(1); +#ifndef ENHANCED_VISIT + brd_visit[chn] = 0; /* itoc.010402: ³ÌªñÂsÄý®É¶¡Âk¹s¡A¨Ï¬ÝªO¦Cªí¤¤Åã¥Ü¥¼Åª */ +#endif + } + return class_body(xo); +} + + +static int +class_nextunread(xo) + XO *xo; +{ + int max, pos, chn; + short *chp; + BRD *bcache, *brd; + + bcache = bshm->bcache; + max = xo->max; + pos = xo->pos; + chp = (short *) xo->xyz + pos; + + while (++pos < max) + { + chn = *(++chp); + if (chn >= 0 && !(brd_bits[chn] & BRD_Z_BIT)) /* ¸õ¹L¤ÀÃþ¤Î zap ±¼ªº¬ÝªO */ + { + brd = bcache + chn; + +#ifdef ENHANCED_VISIT + /* itoc.010407: §ï¥Î³Ì«á¤@½g¤wŪ/¥¼Åª¨Ó§PÂ_ */ + brh_get(brd->bstamp, chn); + if (brh_unread(brd->blast)) +#else + if (brd->blast > brd_visit[chn]) +#endif + return pos + XO_MOVE; + } + } + + return XO_NONE; +} + + +static int +class_edit(xo) + XO *xo; +{ + if (HAS_PERM(PERM_ALLBOARD | PERM_BM)) + { + short *chp; + int chn; + + chp = (short *) xo->xyz + xo->pos; + chn = *chp; + if (chn >= 0) + { + if (!HAS_PERM(PERM_ALLBOARD)) + brd_title(chn); /* itoc.000312: ªO¥Dק襤¤å±Ôz */ + else + brd_edit(chn); + return class_init(xo); + } + } + return XO_NONE; +} + + +static int +hdr_cmp(a, b) + HDR *a; + HDR *b; +{ + /* ¥ý¤ñ¹ï¤ÀÃþ¡A¦A¤ñ¹ïªO¦W */ + int k = strncmp(a->title + BNLEN + 1, b->title + BNLEN + 1, BCLEN); + return k ? k : str_cmp(a->xname, b->xname); +} + + +static int +class_newbrd(xo) + XO *xo; +{ + BRD newboard; + + if (!HAS_PERM(PERM_ALLBOARD)) + return XO_NONE; + + memset(&newboard, 0, sizeof(BRD)); + + /* itoc.010211: ·s¬ÝªO¹w³] postlevel = PERM_POST; battr = ¤£Âà«H */ + newboard.postlevel = PERM_POST; + newboard.battr = BRD_NOTRAN; + + if (brd_new(&newboard) < 0) + return class_head(xo); + + if (xo->key < CH_END) /* ¦b¤ÀÃþ¸s²Õ¸Ì± */ + { + short *chx; + char *img, *str; + char xname[BNLEN + 1], fpath[64]; + HDR hdr; + + img = class_img; + chx = (short *) img + (CH_END - xo->key); + str = img + *chx; + + str_ncpy(xname, str, sizeof(xname)); + if (str = strchr(xname, '/')) + *str = '\0'; + + /* ¥[¤J¤ÀÃþ¸s²Õ */ + sprintf(fpath, "gem/@/@%s", xname); + brd2gem(&newboard, &hdr); + rec_add(fpath, &hdr, sizeof(HDR)); + rec_sync(fpath, sizeof(HDR), hdr_cmp, NULL); + + vmsg("·sªO¦¨¥ß"); + } + else /* ¦b¬ÝªO¦Cªí¸Ì± */ + { + vmsg("·sªO¦¨¥ß¡A°OµÛ¥[¤J¤ÀÃþ¸s²Õ"); + } + + return class_init(xo); +} + + +static int +class_browse(xo) + XO *xo; +{ + short *chp; + int chn; + + chp = (short *) xo->xyz + xo->pos; + chn = *chp; + if (chn < 0) /* ¶i¤J¤ÀÃþ */ + { + if (!XoClass(chn)) + return XO_NONE; + } + else /* ¶i¤J¬ÝªO */ + { + if (XoPost(chn)) /* µLªk¾\Ū¸ÓªO */ + return XO_FOOT; + xover(XZ_POST); +#ifndef ENHANCED_VISIT + time(&brd_visit[chn]); +#endif + } + +#ifdef AUTO_JUMPBRD + if (cuser.ufo & UFO_JUMPBRD) + class_jumpnext = 1; /* itoc.010910: ¥u¦³¦bÂ÷¶}¬ÝªO¦^¨ì¬ÝªO¦Cªí®É¤~»Ýn¸õ¥h¤U¤@Ó¥¼Åª¬ÝªO */ +#endif + + return class_head(xo); /* Thor.980701: µLªk²M¤Ö¤@ÂI, ¦]¬° XoPost */ +} + + +int +Select() +{ + int bno; + BRD *brd; + char bname[BNLEN + 1]; + + if (brd = ask_board(bname, BRD_R_BIT, NULL)) + { + bno = brd - bshm->bcache; + if(XoPost(bno)){ + return 0; + } + xover(XZ_POST); +#ifndef ENHANCED_VISIT + time(&brd_visit[bno]); +#endif + } + else + { + vmsg(err_bid); + } + + return 0; +} + + +static int +class_switch(xo) + XO *xo; +{ + Select(); + return class_head(xo); +} + + +#ifdef MY_FAVORITE + +/* ----------------------------------------------------- */ +/* MyFavorite [§Úªº³Ì·R] */ +/* ----------------------------------------------------- */ + + +static inline int +in_favor(brdname) + char *brdname; +{ + MF mf; + int fd; + int rc = 0; + char fpath[64]; + + if (brdname[0]) + { + mf_fpath(fpath, cuser.userid, FN_MF); + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + while (read(fd, &mf, sizeof(MF)) == sizeof(MF)) + { + if (!strcmp(brdname, mf.xname)) + { + rc = 1; + break; + } + } + } + close(fd); + } + return rc; +} + + +static int +class_addMF(xo) + XO *xo; +{ + short *chp; + int chn; + + if (!cuser.userlevel) + return XO_NONE; + + chp = (short *) xo->xyz + xo->pos; + chn = *chp; + + if (chn >= 0) + { + BRD *bhdr; + + bhdr = bshm->bcache + chn; + + if (!in_favor(bhdr->brdname)) + { + MF mf; + char fpath[64]; + + memset(&mf, 0, sizeof(MF)); + time(&mf.chrono); + mf.mftype = MF_BOARD; + strcpy(mf.xname, bhdr->brdname); + + mf_fpath(fpath, cuser.userid, FN_MF); + rec_add(fpath, &mf, sizeof(MF)); + vmsg("¤w¥[¤J§Úªº³Ì·R"); + } + else + { + vmsg("¦¹¬ÝªO¤w¦b³Ì·R¤¤¡CYn«ÂÐ¥[¤J¡A½Ð¶i§Úªº³Ì·R¸Ì·s¼W"); + } + } + + return XO_FOOT; +} + +#endif /* MY_FAVORITE */ + + +#ifdef AUTHOR_EXTRACTION +/* Thor.980818: ·Q§ï¦¨¥H¥Ø«eªº¬ÝªO¦Cªí©Î¤ÀÃþ¨Ó§ä, ¤£n§ä¥þ³¡ */ + + +/* opus.1127 : pµe«¼g, ¥i extract author/title */ + + +static int +XoAuthor(xo) + XO *xo; +{ + int chn, len, max, tag; + short *chp, *chead, *ctail; + BRD *brd; + char key[30], author[IDLEN + 1]; + XO xo_a, *xoTmp; + + vget(b_lines, 0, MSG_XYPOST1, key, 30, DOECHO); + vget(b_lines, 0, MSG_XYPOST2, author, IDLEN + 1, DOECHO); + + if (!*key && !*author) + return XO_FOOT; + + str_lowest(key, key); + str_lower(author, author); + len = strlen(author); + + chead = (short *) xo->xyz; + max = xo->max; + ctail = chead + max; + + tag = 0; + chp = (short *) malloc(max * sizeof(short)); + brd = bshm->bcache; + + do + { + if ((chn = *chead++) >= 0) /* Thor.980818: ¤£¬° group */ + { + /* Thor.980701: ´M§ä«ü©w§@ªÌ¤å³¹, ¦³«h²¾¦ì¸m, ¨Ã©ñ¤J */ + + int fsize; + char *fimage; + + char folder[80]; + HDR *head, *tail; + + sprintf(folder, "¡m´M§ä«ü©w¼ÐÃD§@ªÌ¡n¬ÝªO¡G%s \033[5m...\033[m", brd[chn].brdname); + outz(folder); + refresh(); + brd_fpath(folder, brd[chn].brdname, fn_dir); + + fimage = f_map(folder, &fsize); + + if (fimage == (char *) -1) + continue; + + head = (HDR *) fimage; + tail = (HDR *) (fimage + fsize); + + while (head <= --tail) + { + if ((!*key || str_sub(tail->title, key)) && + (!len || !str_ncmp(tail->owner, author, len))) + { + xo_get(folder)->pos = tail - head; + chp[tag++] = chn; + break; + } + } + + munmap(fimage, fsize); + } + } while (chead < ctail); + + if (!tag) + { + free(chp); + vmsg("ªÅµL¤@ª«"); + return XO_FOOT; + } + + xo_a.pos = xo_a.top = 0; + xo_a.max = tag; + xo_a.key = 1; /* all boards */ + /* Thor.990621: ©Ò¦³ªºclass,board¦Cªí¤U, key < 0, ¥H 1 »P¥¿±`¼Ò¦¡°Ï¤À + ¨Ï¨ä¤£¯à¶] XO_INIT(ùرªºclass_load), ¦p class_yank, + °£¤F¨¾¤î§ä¥Xªº§@ªÌ¬ÝªO¦Cªí®ø¥¢, ¤]¨¾½ð¤H */ + xo_a.xyz = (char *) chp; + + xoTmp = xz[XZ_CLASS - XO_ZONE].xo; /* Thor.980701: °O¤Uì¨Óªºclass_xo */ + xz[XZ_CLASS - XO_ZONE].xo = &xo_a; + +#ifdef AUTO_JUMPBRD + if (cuser.ufo & UFO_JUMPBRD) + class_jumpnext = 1; /* itoc.010910: ¥D°Ê¸õ¥h¤U¤@Ó¥¼Åª¬ÝªO */ +#endif + xover(XZ_CLASS); + + free(chp); + xz[XZ_CLASS - XO_ZONE].xo = xoTmp; /* Thor.980701: ÁÙì class_xo */ + + return class_body(xo); +} +#endif + + +static int class_binfo(xo) + XO *xo; +{ + BRD *brd; + short *chp; + int chn; + chp = (short *) xo->xyz + xo->pos; + chn = *chp; + brd = bshm->bcache + chn; + do_binfo(brd); + return class_init(xo); +} +static KeyFunc class_cb[] = +{ + XO_INIT, class_head, + XO_LOAD, class_body, + XO_HEAD, class_head, + XO_BODY, class_body, + + 'r', class_browse, + '/', class_search, + '?', class_searchBM, + 's', class_switch, + 'c', class_postmode, + 'S', class_namemode, + + 'y', class_yank, + 'z', class_zap, + 'Z', class_zapall, + 'v', class_visit, + 'V', class_unvisit, + '`', class_nextunread, + 'E', class_edit, + 'W', class_binfo, + +#ifdef AUTHOR_EXTRACTION + 'A', XoAuthor, +#endif + +#ifdef MY_FAVORITE + 'a', class_addMF, + 'f', class_addMF, +#endif + + Ctrl('P'), class_newbrd, + + 'h', class_help +}; + + +int +Class() +{ + /* XoClass(CH_END - 1); */ + /* Thor.980804: ¨¾¤î ¥¼¥Î account ³y¥X class.img ©Î¨S¦³ class ªº±¡ªp */ + if (!class_img || !XoClass(CH_END - 1)) + { + vmsg("¥¼©w¸q¤À²Õ°Q½×°Ï"); + return XEASY; + } + return 0; +} + + +void +board_main() +{ + int fsize; + + brh_load(); + + if (class_img) /* itoc.030416: ²Ä¤G¦¸¶i¤J board_main ®É¡An free ±¼ class_img */ + { + free(class_img); + } + else /* itoc.040102: ²Ä¤@¦¸¶i¤J board_main ®É¡A¤~»Ýnªì©l¤Æ class_flag */ + { + class_flag = cuser.ufo & UFO_BRDPOST; /* ¬ÝªO¦Cªí 1:¤å³¹¼Æ 0:½s¸¹ */ + if (!cuser.userlevel) /* guest yank all boards */ + class_flag |= BFO_YANK; + + /* ³]©w default board */ + strcpy(currboard, BN_NULL); + currbno = -1; + } + + /* class_img = f_img(CLASS_IMGFILE, &fsize); */ + /* itoc.010413: ¨Ì·Ó ufo ¨Ó¸ü¤J¤£¦Pªº class image */ + class_img = f_img(cuser.ufo & UFO_BRDNAME ? CLASS_IMGFILE_NAME : CLASS_IMGFILE_TITLE, &fsize); + + if (class_img == NULL) + blog("CACHE", "class.img"); + else + czh_load(); + + board_xo.key = CH_END; + class_load(&board_xo); + + xz[XZ_CLASS - XO_ZONE].xo = &board_xo; /* Thor: default class_xo */ + xz[XZ_CLASS - XO_ZONE].cb = class_cb; /* Thor: default class_xo */ +} + + +int +Boards() +{ + /* class_xo = &board_xo; *//* Thor: ¤w¦³ default, ¤£»Ý§@¦¹ */ + +#ifdef AUTO_JUMPBRD + if (cuser.ufo & UFO_JUMPBRD) + class_jumpnext = 1; /* itoc.010910: ¥D°Ê¸õ¥h¤U¤@Ó¥¼Åª¬ÝªO */ +#endif + xover(XZ_CLASS); + + return 0; +} diff --git a/maple/cache.c b/maple/cache.c new file mode 100644 index 0000000..91164ef --- /dev/null +++ b/maple/cache.c @@ -0,0 +1,589 @@ +/*-------------------------------------------------------*/ +/* cache.c ( NTHU CS MapleBBS Ver 2.36 ) */ +/*-------------------------------------------------------*/ +/* target : cache up data by shared memory */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" +#include <sys/ipc.h> +#include <sys/shm.h> + + +#ifdef HAVE_SEM +#include <sys/sem.h> +#endif + + +#ifdef MODE_STAT +UMODELOG modelog; +time_t mode_lastchange; +#endif + + +#ifdef HAVE_SEM + +/* ----------------------------------------------------- */ +/* semaphore : for critical section */ +/* ----------------------------------------------------- */ + + +static int ap_semid; + + +static void +attach_err(shmkey) + int shmkey; +{ + char buf[20]; + + sprintf(buf, "key = %x", shmkey); + blog("shmget", buf); + exit(1); +} + + +void +sem_init() +{ + int semid; + + union semun + { + int val; + struct semid_ds *buf; + ushort *array; + } arg = + { + 1 + }; + + semid = semget(BSEM_KEY, 1, 0); + if (semid == -1) + { + semid = semget(BSEM_KEY, 1, IPC_CREAT | BSEM_FLG); + if (semid == -1) + attach_err(BSEM_KEY); + semctl(semid, 0, SETVAL, arg); + } + ap_semid = semid; +} + + +void +sem_lock(op) + int op; /* op is BSEM_ENTER or BSEM_LEAVE */ +{ + struct sembuf sops; + + sops.sem_num = 0; + sops.sem_flg = SEM_UNDO; + sops.sem_op = op; + semop(ap_semid, &sops, 1); +} + + +#endif /* HAVE_SEM */ + + +/*-------------------------------------------------------*/ +/* .UTMP cache */ +/*-------------------------------------------------------*/ + + +UCACHE *ushm; + + +void +ushm_init() +{ + ushm = shm_new(UTMPSHM_KEY, sizeof(UCACHE)); +} + + +void +utmp_mode(mode) + int mode; +{ + if (bbsmode != mode) + { +#ifdef MODE_STAT + time_t now; + + time(&now); + modelog.used_time[bbsmode] += (now - mode_lastchange); + mode_lastchange = now; +#endif + + cutmp->mode = bbsmode = mode; + } +} + + +int +utmp_new(up) + UTMP *up; +{ + UCACHE *xshm; + UTMP *uentp, *utail; + + /* --------------------------------------------------- */ + /* semaphore : critical section */ + /* --------------------------------------------------- */ + +#ifdef HAVE_SEM + sem_lock(BSEM_ENTER); +#endif + + xshm = ushm; + uentp = xshm->uslot; + utail = uentp + MAXACTIVE; + + /* uentp += (up->pid % xshm->count); */ /* hashing */ + + do + { + if (!uentp->pid) + { + usint offset; + + offset = (void *) uentp - (void *) xshm->uslot; + memcpy(uentp, up, sizeof(UTMP)); + xshm->count++; + if (xshm->offset < offset) + xshm->offset = offset; + cutmp = uentp; + +#ifdef HAVE_SEM + sem_lock(BSEM_LEAVE); +#endif + + return 1; + } + } while (++uentp < utail); + + /* Thor:§i¶Duser¦³¤Hµn¥ý¤@¨B¤F */ + +#ifdef HAVE_SEM + sem_lock(BSEM_LEAVE); +#endif + + return 0; +} + + +void +utmp_free(up) + UTMP *up; +{ + if (!up || !up->pid) + return; + +#ifdef HAVE_SEM + sem_lock(BSEM_ENTER); +#endif + + up->pid = up->userno = 0; + ushm->count--; + +#ifdef HAVE_SEM + sem_lock(BSEM_LEAVE); +#endif +} + + +UTMP * +utmp_find(userno) + int userno; +{ + UTMP *uentp, *uceil; + + uentp = ushm->uslot; + uceil = (void *) uentp + ushm->offset; + do + { + if (uentp->userno == userno) + return uentp; + } while (++uentp <= uceil); + + return NULL; +} + + +UTMP * +utmp_get(userno, userid) /* itoc.010306: Àˬd¨Ï¥ÎªÌ¬O§_¦b¯¸¤W */ + int userno; + char *userid; +{ + UTMP *uentp, *uceil; + int seecloak; +#ifdef HAVE_SUPERCLOAK + int seesupercloak; +#endif + + /* itoc.020718.µù¸Ñ: ¥Ñ©ó¦P¤@¶ªº¦P¼Ë§@ªÌªº¾÷²v¹ê¦b¤Ó°ª¡A¦Ò¼{¬O§_°O¤U¬d¸ßµ²ªG¡A + µM«á¥ý¬d¥ý«eªº°O¿ý¡AY§ä¤£¨ì¦A¥h¨Ï¥ÎªÌ¦W³æ§ä */ + + seecloak = HAS_PERM(PERM_SEECLOAK); +#ifdef HAVE_SUPERCLOAK + seesupercloak = cuser.ufo & UFO_SUPERCLOAK; +#endif + uentp = ushm->uslot; + uceil = (void *) uentp + ushm->offset; + do + { + if (uentp->pid && /* ¤w¸gÂ÷¯¸ªº¤£Àˬd */ + ((userno && uentp->userno == userno) || (userid && !strcmp(userid, uentp->userid)))) + { + if (!seecloak && (uentp->ufo & UFO_CLOAK)) /* Áô§Î¬Ý¤£¨£ */ + continue; + +#ifdef HAVE_SUPERCLOAK + if (!seesupercloak && (uentp->ufo & UFO_SUPERCLOAK)) /* µµÁô¬Ý¤£¨£ */ + continue; +#endif + +#ifdef HAVE_BADPAL + if (!seecloak && is_obad(uentp)) /* ³Q³]Ãa¤H¡A³s§OÓ multi-login ¤]¬Ý¤£¨£ */ + break; +#endif + + return uentp; + } + } while (++uentp <= uceil); + + return NULL; +} + + +UTMP * +utmp_seek(hdr) /* itoc.010306: Àˬd¨Ï¥ÎªÌ¬O§_¦b¯¸¤W */ + HDR *hdr; +{ + if (hdr->xmode & POST_INCOME) /* POST_INCOME ©M MAIL_INCOME ¬O¬Û¦Pªº */ + return NULL; + return utmp_get(0, hdr->owner); +} + + +void +utmp_admset(userno, status) /* itoc.010811: °ÊºA³]©w½u¤W¨Ï¥ÎªÌ */ + int userno; + usint status; +{ + UTMP *uentp, *uceil; + extern int ulist_userno[]; + + uentp = ushm->uslot; + uceil = (void *) uentp + ushm->offset; + do + { + if (uentp->userno == userno) + uentp->status |= status; /* ¥[¤W¸ê®Æ³QÅܰʹLªººX¼Ð */ + + /* itoc.041211: ·í§Ú§â¹ï¤è·s¼W/²¾°£/ÅܰʪB¤Í®É¡A + °£¤FnÀ°¥L¥[¤W STATUS_PALDIRTY (¥ç§Y¥s¥L«·s§PÂ_¥L¦Û¤vªº ulist_ftype[¥þ³¡])¡A + ÁÙn§â§Ú ulist_userno[¹ï¤è] Åܦ¨ 0 (¥ç§Y¥s§Ú¦Û¤v§ó·s ulist_ftype[¹ï¤è]) */ + if (status == STATUS_PALDIRTY) + ulist_userno[uentp - ushm->uslot] = 0; + } while (++uentp <= uceil); +} + + +int +utmp_count(userno, show) + int userno; + int show; +{ + UTMP *uentp, *uceil; + int count; + + count = 0; + uentp = ushm->uslot; + uceil = (void *) uentp + ushm->offset; + do + { + if (uentp->userno == userno) + { + count++; + if (show) + { + prints("(%d) ¥Ø«eª¬ºA¬°: %-17.16s(¨Ó¦Û %s)\n", + count, bmode(uentp, 0), uentp->from); + } + } + } while (++uentp <= uceil); + return count; +} + + +UTMP * +utmp_search(userno, order) + int userno; + int order; /* ²Ä´XÓ */ +{ + UTMP *uentp, *uceil; + + uentp = ushm->uslot; + uceil = (void *) uentp + ushm->offset; + do + { + if (uentp->userno == userno) + { + if (--order <= 0) + return uentp; + } + } while (++uentp <= uceil); + return NULL; +} + + +#if 0 +int +apply_ulist(fptr) + int (*fptr) (); +{ + UTMP *uentp; + int i, state; + + uentp = ushm->uslot; + for (i = 0; i < USHM_SIZE; i++, uentp++) + { + if (uentp->pid) + if (state = (*fptr) (uentp)) + return state; + } + return 0; +} +#endif + + +/*-------------------------------------------------------*/ +/* .BRD cache */ +/*-------------------------------------------------------*/ + + +BCACHE *bshm; + + +void +bshm_init() +{ + int i; + + /* itoc.030727: ¦b¶}±Ò bbsd ¤§«e¡AÀ³¸Ó´Nn°õ¦æ¹L account¡A + ©Ò¥H bshm À³¸Ó¤w³]©w¦n */ + + bshm = shm_new(BRDSHM_KEY, sizeof(BCACHE)); + + i = 0; + while (bshm->uptime <= 0) /* bshm ¥¼³]©w§¹¦¨¡A¤]³\¬O¥¼¶] account¡A¤]³\¬O¯¸ªø¥¿¦n¦b¶}ªO */ + { + sleep(5); + if (++i >= 6) /* Y 30 ¬í¥H«áÁÙ¨S¦n¡AÂ_½uÂ÷¶} */ + abort_bbs(); + } +} + + +void +bshm_reload() /* ¶}ªO¥H«á¡A«·s¸ü¤J bshm */ +{ + time_t *uptime; + int fd; + BRD *head, *tail; + + uptime = &(bshm->uptime); + + while (*uptime <= 0) + { + /* ¨ä¥L¯¸ªø¤]è¦n¦b¶}ªO¡Aµ¥«Ý 30 ¬í */ + sleep(30); + } + + *uptime = -1; /* ¶}©l³]©w */ + + if ((fd = open(FN_BRD, O_RDONLY)) >= 0) + { + bshm->number = read(fd, bshm->bcache, MAXBOARD * sizeof(BRD)) / sizeof(BRD); + close(fd); + } + + /* µ¥©Ò¦³ boards ¸ê®Æ§ó·s«á¦A³]©w uptime */ + time(uptime); + + /* itoc.040314: ªO¥D§ó§ï¬ÝªO±Ôz©Î¬O¯¸ªø§ó§ï¬ÝªO®É¤~·|§â bpost/blast ¼g¶i .BRD ¤¤ + ©Ò¥H .BRD ¸Ìªº bpost/blast ¥¼¥²¬O¹ïªº¡An«·s initial¡C + initial ªº¤èªk¬O±N btime ³]¦¨ -1¡AÅý class_item() ¥h§ó·s */ + head = bshm->bcache; + tail = head + bshm->number; + do + { + head->btime = -1; + } while (++head < tail); + + blog("CACHE", "reload bcache"); +} + + +#if 0 +int +apply_boards(func) + int (*func) (); +{ + extern char brd_bits[]; + BRD *bhdr; + int i; + + for (i = 0, bhdr = bshm->bcache; i < bshm->number; i++, bhdr++) + { + if (brd_bits[i]) + { + if ((*func) (bhdr) == -1) + return -1; + } + } + return 0; +} +#endif + + +static int +brdname_cmp(a, b) + BRD *a, *b; +{ + return str_cmp(a->brdname, b->brdname); +} + + +int +brd_bno(bname) + char *bname; +{ + BRD xbrd, *bcache, *brdp, *bend; + + bcache = bshm->bcache; + + /* ¥ý¦b¬ݪO binary serach */ + + /* str_ncpy(xbrd.brdname, bname, sizeof(xbrd.brdname)); */ + str_lower(xbrd.brdname, bname); /* ª½±µ´«¤p¼g¡A³o¼Ë¦b brdname_cmp() ®É·|§Ö¤@¨Ç */ + if (bend = bsearch(&xbrd, bcache, bshm->numberOld, sizeof(BRD), brdname_cmp)) + return bend - bcache; + + /* Y§ä¤£¨ì¡A¦A¥h·s¬ÝªO sequential search */ + + brdp = bcache + bshm->numberOld; + bend = bcache + bshm->number; + + while (brdp < bend) + { + if (!str_cmp(bname, brdp->brdname)) + return brdp - bcache; + + brdp++; + } + + return -1; +} + + +/*-------------------------------------------------------*/ +/* movie cache */ +/*-------------------------------------------------------*/ + + +FCACHE *fshm; + + +void +fshm_init() +{ + fshm = shm_new(FILMSHM_KEY, sizeof(FCACHE)); +} + + +/* ----------------------------------------------------- */ +/* itoc.020822.µù¸Ñ: */ +/* ----------------------------------------------------- */ +/* ²Ä 0 ¡ã FILM_MOVIE-1 ±i¬O¨t²Îµe±¤Î»¡©úµe± */ +/* ²Ä FILM_MOVIE ¡ã fmax-1 ±i¬O°ÊºA¬ÝªO */ +/* ----------------------------------------------------- */ +/* tag: */ +/* < FILM_MOVIE ¡÷ ¼½©ñ¸Ó±iµe± */ +/* >= FILM_MOVIE ¡÷ ¶Ã¼Æ¼½©ñ FILM_MOVIE~fmax-1 ¨ä¤¤¤@±i */ +/* ----------------------------------------------------- */ +/* row: */ +/* >=0 ¡÷ ¨t²Îµe±¡A±q (row, 0) ¶}©l¦L */ +/* <0 ¡÷ »¡©úµe±¡A±q (0, 0) ¶}©l¦L¡A³Ì«á·| vmsg(NULL) */ +/* ----------------------------------------------------- */ + + +void +film_out(tag, row) + int tag; + int row; /* -1 : help */ +{ + int fmax, len, *shot; + char *film, buf[FILM_SIZ]; + + len = 0; + shot = fshm->shot; + + while (!(fmax = *shot)) /* util/camera.c ¥¿¦b´«¤ù */ + { + sleep(5); + if (++len >= 6) /* Y 30 ¬í¥H«áÁÙ¨S´«¦n¤ù¡A¥i¯à¬O¨S¶] camera¡Aª½±µÂ÷¶} */ + return; + } + + if (row <= 0) + clear(); + else + move(row, 0); + + if (tag >= FILM_MOVIE) /* °ÊºA¬ÝªO */ + tag += time(0) % (fmax - FILM_MOVIE); + + film = fshm->film; + + if (tag) + { + len = shot[tag]; + film += len; + len = shot[tag + 1] - len; + } + else + { + len = shot[1]; + } + + if (len >= FILM_SIZ - MOVIE_LINES) + return; + + memcpy(buf, film, len); + buf[len] = '\0'; + + if (d_cols) /* waynesan.040831: ¨Ì¼e¿Ã¹õ¸m¤¤ */ + { + char *ptr; + for (film = buf; *film;) + { + if (ptr = strchr(film, '\n')) + *ptr = '\0'; + move(row++, (d_cols >> 1)); + outx(film); + if (ptr) + film = ptr + 1; + } + } + else + outx(buf); + + if (row < 0) /* help screen */ + vmsg(NULL); + + return; +} diff --git a/maple/edit.c b/maple/edit.c new file mode 100644 index 0000000..0268123 --- /dev/null +++ b/maple/edit.c @@ -0,0 +1,2380 @@ +/*-------------------------------------------------------*/ +/* edit.c ( NTHU CS MapleBBS Ver 2.36 ) */ +/*-------------------------------------------------------*/ +/* target : simple ANSI/Chinese editor */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +/* #define VE_WIDTH (ANSILINELEN - 1) */ +/* Thor.990330: ¬°¨¾¤î¤Þ¨¥«á, ">"nÅܦâ, ¤@¦æ·|¶W¹LANSILINELEN, ¬G¦h¯dªÅ¶¡ */ +/* itoc.010317.µù¸Ñ: ¨º»ò¹ê»Ú¤@¦C¥i¥H©ñ¤Uªº¦³®Ä¦r¼Æ¬° VE_WIDTH - 3 */ +#define VE_WIDTH (ANSILINELEN - 11) + + +typedef struct textline +{ + struct textline *prev; + struct textline *next; + int len; + uschar data[ANSILINELEN]; +} textline; + + +static textline *vx_ini; /* first line */ +static textline *vx_cur; /* current line */ +static textline *vx_top; /* top line in current window */ + + +static int ve_lno; /* current line number */ +static int ve_row; /* cursor position */ +static int ve_col; + + +static int ve_mode; /* operation mode */ + + +#ifdef HAVE_MULTI_BYTE +static int zhc; /* ¬O§_¦³ UFO_ZHC */ +#endif + + +#ifdef HAVE_ANONYMOUS +char anonymousid[IDLEN + 1]; /* itoc.010717: ¦Û©w°Î¦W ID */ +#endif + + +#define VE_INSERT 0x01 +#define VE_ANSI 0x02 +#define VE_FOOTER 0x04 +#define VE_REDRAW 0x08 + +#ifdef EVERY_BIFF +#define VE_BIFF 0x10 +#endif /* Thor.980805: ¶l®t¨ì³B¨Ó«ö¹a */ + + +#define FN_BAK "bak" + + +/* ----------------------------------------------------- */ +/* °O¾ÐÅéºÞ²z»P½s¿è³B²z */ +/* ----------------------------------------------------- */ + + +#ifdef DEBUG_VEDIT +static void +ve_abort(i) + int i; +{ + char msg[40]; + + sprintf(msg, "ÄY«¤º¶Ë %d", i); + blog("VEDIT", msg); +} + +#else + +#define ve_abort(n) ; +#endif + + +static void +ve_position(cur, top) + textline *cur; + textline *top; +{ + int row; + + row = cur->len; + if (ve_col > row) + ve_col = row; +#ifdef HAVE_MULTI_BYTE + else if (zhc && ve_col < row && IS_ZHC_LO(cur->data, ve_col)) /* hightman.060504: º~¦r¾ã¦r½Õ¸` */ + ve_col++; +#endif + + row = 0; + while (cur != top) + { + row++; + cur = cur->prev; + } + ve_row = row; + + ve_mode |= VE_REDRAW; +} + + +static inline void +ve_pageup() +{ + textline *cur, *top, *tmp; + int lno, n; + + cur = vx_cur; + top = vx_top; + lno = ve_lno; + for (n = PAGE_SCROLL; n > 0; n--) + { + if (!(tmp = cur->prev)) + break; + + cur = tmp; + lno--; + + if (tmp = top->prev) + top = tmp; + } + + vx_cur = cur; + vx_top = top; + ve_lno = lno; + + ve_position(cur, top); +} + + +static inline void +ve_forward(n) + int n; +{ + textline *cur, *top, *tmp; + int lno; + + cur = vx_cur; + top = vx_top; + lno = ve_lno; + while (n--) + { + if (!(tmp = cur->next)) + break; + + lno++; + cur = tmp; + + if (tmp = top->next) + top = tmp; + } + + vx_cur = cur; + vx_top = top; + ve_lno = lno; + + ve_position(cur, top); +} + + +static inline char * +ve_strim(s) + char *s; +{ + while (*s == ' ') + s++; + return s; +} + + +static textline * +ve_alloc() +{ + textline *p; + + if (p = (textline *) malloc(sizeof(textline))) + { + p->prev = NULL; + p->next = NULL; + p->len = 0; + p->data[0] = '\0'; + return p; + } + + ve_abort(13); /* °O¾ÐÅé¥Î¥ú¤F */ + abort_bbs(); +} + + +/* ----------------------------------------------------- */ +/* Thor: ansi ®y¼ÐÂà´« for color ½s¿è¼Ò¦¡ */ +/* ----------------------------------------------------- */ + + +static int +ansi2n(ansix, line) + int ansix; + textline *line; +{ + uschar *data, *tmp; + int ch; + + data = tmp = line->data; + + while (ch = *tmp) + { + if (ch == KEY_ESC) + { + for (;;) + { + ch = *++tmp; + if (ch >= 'a' && ch <= 'z' /* isalpha(ch) */ ) + { + tmp++; + break; + } + if (!ch) + break; + } + continue; + } + if (ansix <= 0) + break; + tmp++; + ansix--; + } + return tmp - data; +} + + +static int +n2ansi(nx, line) + int nx; + textline *line; +{ + uschar *tmp, *nxp; + int ansix; + int ch; + + tmp = nxp = line->data; + nxp += nx; + ansix = 0; + + while (ch = *tmp) + { + if (ch == KEY_ESC) + { + for (;;) + { + ch = *++tmp; + if (ch >= 'a' && ch <= 'z' /* isalpha(ch) */ ) + { + tmp++; + break; + } + if (!ch) + break; + } + continue; + } + if (tmp >= nxp) + break; + tmp++; + ansix++; + } + return ansix; +} + + +/* ----------------------------------------------------- */ +/* delete_line deletes 'line' from the list, */ +/* and maintains the vx_ini pointers. */ +/* ----------------------------------------------------- */ + + +static void +delete_line(line) + textline *line; +{ + textline *p = line->prev; + textline *n = line->next; + + if (p || n) + { + if (n) + n->prev = p; + + if (p) + p->next = n; + else + vx_ini = n; + + free(line); + } + else + { + line->data[0] = line->len = 0; + } +} + + +/* ----------------------------------------------------- */ +/* split 'line' right before the character pos */ +/* ----------------------------------------------------- */ + + +static void +ve_split(line, pos) + textline *line; + int pos; +{ + int len = line->len - pos; + + if (len >= 0) + { + textline *p, *n; + uschar *ptr; + + line->len = pos; + p = ve_alloc(); + p->len = len; + strcpy(p->data, (ptr = line->data + pos)); + *ptr = '\0'; + + /* --------------------------------------------------- */ + /* append p after line in list. keep up with last line */ + /* --------------------------------------------------- */ + + if (p->next = n = line->next) + n->prev = p; + line->next = p; + p->prev = line; + + if (line == vx_cur && pos <= ve_col) + { + vx_cur = p; + ve_col -= pos; + ve_row++; + ve_lno++; + } + ve_mode |= VE_REDRAW; + } +} + + +/* ----------------------------------------------------- */ +/* connects 'line' and the next line. returns true if: */ +/* 1) lines were joined and one was deleted */ +/* 2) lines could not be joined */ +/* 3) next line is empty */ +/* ----------------------------------------------------- */ +/* returns false if: */ +/* 1) Some of the joined line wrapped */ +/* ----------------------------------------------------- */ + + +static int +ve_join(line) + textline *line; +{ + textline *n; + uschar *data, *s; + int sum, len; + + if (!(n = line->next)) + return 1; + + if (!*ve_strim(data = n->data)) + return 1; + + len = line->len; + sum = len + n->len; + if (sum < VE_WIDTH) + { + strcpy(line->data + len, data); + line->len = sum; + delete_line(n); + return 1; + } + + s = data - len + VE_WIDTH - 1; + while (*s == ' ' && s != data) + s--; + while (*s != ' ' && s != data) + s--; + if (s == data) + return 1; + + ve_split(n, (s - data) + 1); + if (len + n->len >= VE_WIDTH) + { + ve_abort(0); + return 1; + } + + ve_join(line); + n = line->next; + len = n->len; + if (len >= 1 && len < VE_WIDTH - 1) + { + s = n->data + len - 1; + if (*s != ' ') + { + *s++ = ' '; + *s = '\0'; + n->len = len + 2; + } + } + return 0; +} + + +static void +join_up(line) + textline *line; +{ + while (!ve_join(line)) + { + line = line->next; + if (line == NULL) + { + ve_abort(2); + abort_bbs(); + } + } +} + + +/* ----------------------------------------------------- */ +/* character insert / detete */ +/* ----------------------------------------------------- */ + + +static void +ve_char(ch) + int ch; +{ + textline *p; + int col, len, mode; + uschar *data; + + p = vx_cur; + len = p->len; + col = ve_col; + + if (col > len) + { + ve_abort(1); + return; + } + + data = p->data; + mode = ve_mode; + + /* --------------------------------------------------- */ + /* overwrite */ + /* --------------------------------------------------- */ + + if ((col < len) && !(mode & VE_INSERT)) + { + data[col++] = ch; + + /* Thor: ansi ½s¿è, ¥i¥H overwrite, ¤£»\¨ì ansi code */ + + if (mode & VE_ANSI) + col = ansi2n(n2ansi(col, p), p); + + ve_col = col; + return; + } + + /* --------------------------------------------------- */ + /* insert / append */ + /* --------------------------------------------------- */ + + for (mode = len; mode >= col; mode--) + { + data[mode + 1] = data[mode]; + } + data[col++] = ch; + ve_col = col; + p->len = ++len; + + if (len >= VE_WIDTH - 2) + { + /* Thor.980727: ×¥¿ editor buffer overrun °ÝÃD, ¨£«á */ + + ve_split(p, VE_WIDTH - 3); + +#if 0 + uschar *str = data + len; + + while (*--str == ' ') + { + if (str == data) + break; + } + + ve_split(p, (str - data) + 1); +#endif + + + +#if 0 + §@ªÌ yvb (yvb) ¬ÝªO SYSOP + ¼ÐÃD Ãö©ó editor... + ®É¶¡ Sun Jun 28 11:28:02 1998 +¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w + + post ¤Î mail µ¥ªº³oÓ editor, ¦pªG§A¤@ª½©¹«á±¥´¦r, + ³Ì¦h¥i¥H¥´¨ì¤@¦C 157 ¦r§a... ¦A¥´´N·|³Q¢´«¦æ. + + ¤£¹L¦pªG§A°í«ù¤´n¦b«á±¥[¦r... ¤]´N¬O¦A²¾¦^è¤~¨º¦æ + Ä~Äò¥´¦r... ¨º¨t²Î¤´·|Åý§A¦b¸Ó¦CÄ~Äò¥[¤@Ó¦r¥À, ¨Ã¥B + ´«¥X·sªº¤@¦æ¨Ó... + + «ÂгoÓ¨BÆJ, ¨ì²Ä 170 ¦r®É, §A´N·|³QÂ_½u¤F... + ¨þ... °÷ÅܺA§a :P + + ¨ä¹ê, ±q¥t¤@ÓÆ[ÂI¨Ó»¡, Y³o¤£¬O¨t²Î¯S·N³o¼Ë¤l³]p, + ¨º´Nªí¥Ü³oùئü¥G¼çÂõۥiÂÇ¥Ñ buffer overrun ªº¤è¦¡, + ¥i¯à¹F¦¨¤J«I¨t²Îªº¦M¾÷... +-- +¡° ¨Ó·½: ¤ë¥ú´ËªL ¡» From: bamboo.Dorm6.NCTU.edu.tw + +#endif + + } +} + + +static void +delete_char(cur, col) + textline *cur; + int col; +{ + uschar *dst, *src; + + cur->len--; + dst = cur->data + col; + for (;;) + { + src = dst + 1; + if (!(*dst = *src)) + break; + dst = src; + } +} + + +static void +ve_string(str) + uschar *str; +{ + int ch; + + while (ch = *str) + { + if (isprint2(ch) || ch == KEY_ESC) + { + ve_char(ch); + } + else if (ch == '\t') + { + do + { + ve_char(' '); + } while (ve_col & TAB_WIDTH); + } + else if (ch == '\n') + { + ve_split(vx_cur, ve_col); + } + str++; + } +} + + +static void +ve_ansi() +{ + int fg, bg, mode; + char ans[4], buf[16], *apos, *color, *tmp; + static char t[] = "BRGYLPCW"; + + mode = ve_mode | VE_REDRAW; + color = str_ransi; + + if (mode & VE_ANSI) + { + move(b_lines - 1, 55); + outs("\033[1;33;40mB\033[41mR\033[42mG\033[43mY\033[44mL\033[45mP\033[46mC\033[47mW\033[m"); + if (fg = vget(b_lines, 0, "½Ð¿é¤J «G«×/«e´º/I´º[¥¿±`¥Õ¦r¶Â©³][0wb]¡G", + apos = ans, 4, LCECHO)) + { + color = buf; + strcpy(color, "\033["); + if (isdigit(fg)) + { + sprintf(color, "%s%c", color, *(apos++)); + if (*apos) + strcat(color, ";"); + } + if (*apos) + { + if (tmp = strchr(t, toupper(*(apos++)))) + fg = tmp - t + 30; + else + fg = 37; + sprintf(color, "%s%d", color, fg); + } + if (*apos) + { + if (tmp = strchr(t, toupper(*(apos++)))) + bg = tmp - t + 40; + else + bg = 40; + sprintf(color, "%s;%d", color, bg); + } + strcat(color, "m"); + } + } + + ve_mode = mode | VE_INSERT; + ve_string(color); + ve_mode = mode; +} + + +static textline * +ve_line(this, str) + textline *this; + uschar *str; +{ + int cc, len; + uschar *data; + textline *line; + + do + { + line = ve_alloc(); + data = line->data; + len = 0; + + for (;;) + { + cc = *str; + + if (cc == '\n') + cc = 0; + if (cc == 0) + break; + + str++; + + if (cc == '\t') + { + do + { + *data++ = ' '; + len++; + } while ((len & TAB_WIDTH) && (len < VE_WIDTH)); + } + else if (cc < ' ' && cc != KEY_ESC) + { + continue; + } + else + { + *data++ = cc; + len++; + } + if (len >= VE_WIDTH) + break; + } + + *data = '\0'; + line->len = len; + line->prev = this; + this = this->next = line; + + } while (cc); + + return this; +} + + +/* ----------------------------------------------------- */ +/* Åã¥Üñ¦WÀÉ */ +/* ----------------------------------------------------- */ + + +static void +show_sign(ch) /* itoc.000319: Åã¥Üñ¦WÀɪº¤º®e */ + char ch; +{ + int fd, len, i; + char fpath[64], buf[10], *str; + + clear(); + + sprintf(buf, "%s.0", FN_SIGN); + usr_fpath(fpath, cuser.userid, buf); /* itoc.020123: ¦UÓñ¦WÀÉÀɮפÀ¶} */ + len = strlen(fpath) - 1; + + + for (; ch <= '6'; ch++) /* ¤»Óñ¦WÀÉ */ + { + fpath[len] = ch; + + fd = open(fpath, O_RDONLY); + if (fd >= 0) + { + mgets(-1); + move(((ch - '1') %3 ) * (MAXSIGLINES + 1), 0); + prints("\033[1;36m¡i ñ¦WÀÉ %c ¡j\033[m\n", ch); + + for (i = 1; i <= MAXSIGLINES; i++) + { + if (!(str = mgets(fd))) + break; + prints("%s\n", str); + } + + if(((ch -'0') % 3 ) == 0) + break; + } + } +} + + +/* ----------------------------------------------------- */ +/* ²Å¸¹¿é¤J¤u¨ã Input Tools */ +/* ----------------------------------------------------- */ + + +#ifdef INPUT_TOOLS +static void +input_tools() /* itoc.000319: ²Å¸¹¿é¤J¤u¨ã */ +{ + char msg1[] = {"1.¬A²Å¤è¶ô 2.½u±øªí®Ø 3.¼Æ¾Ç²Å¸¹ (PgDn/N:¤U¤@¶)¡H[Q] "}; + char msg2[] = {"4.¹Ï®×¼Æ¦r 5.§ÆÃ¾¦r¥À 6.ª`µ¼ÐÂI (PgUp/P:¤W¤@¶)¡H[Q] "}; + + char ansi[6][100] = + { + { /* 1.¬A²Å¤è¶ô */ + "¢b¢c¢d¢e¢f¢g¢h¢i¢¨¢©" + "¢j¢k¢l¢m¢n¢o¢p¢ª¢«¡¼" + "¡]¡^¡a¡b¡e¡f¡i¡j¡m¡n" + "¡q¡r¡u¡v¡y¡z¡k¡l¡o¡p" + "¡_¡`¡c¡d¡g¡h¡w¡x¡{¡|" + }, + + { /* 2.½u±øªí®Ø */ + "ùïùðùñùõùöù÷¢w¢xùù¡ü" + "¢z¢s¢{¢u¢q¢t¢|¢r¢}¢®" + "ùÝùÞùßùàùáùâùãùäùå¡\\" + "ùæùèùéùëùìùî¢~¢¡¢¢¢£" + "¢b¢v¢j¢y¢¬¢¡ö¡÷¡ô¡õ" + }, + + { /* 3.¼Æ¾Ç²Å¸¹ */ + "¡Ï¡Ð¡Ñ¡Ò¡Ó¡×¡Õ¡Ö¡Ø¡Ù" + "¡Ú¡Ý¡ã¡î¡ï¡ä¡å¡Û£k¡Ô" + "£U£S¡ì¡í¡ç¡æ¡è¡é£G¢X" + "¡¡®¡¯¡°¢I¢C¢D¢F¢G¢H" + "¢J¢K¢P¢Q¢R¢T¢U¢V¢W¡±" + }, + + { /* 4.¹Ï®×¼Æ¦r */ + "¡³¡´¡µ¡¶¡·¡¸¡º¡»¡¼¡½" + "¡¾¡¿¡À¡ò¡ó¢Ì¢Í¢Î¡ñ¡ð" + "¢¯¢°¢±¢²¢³¢´¢µ¢¶¢·¢¸" + "¢¹¢º¢»¢¼¢½¢¾¢¿¢À¢Á¢Â" + "ƵƶƷƸƹƺƻƼƽƾ" + }, + + { /* 5.§ÆÃ¾¦r¥À */ + "£D£E£F£G£H£I£J£K£L£M" + "£N£O£P£Q£R£S£T£U£V£W" + "£X£Y£Z£[£\\£]£^£_£`£a" + "£b£c£d£e£f£g£h£i£j£k" + "£l£m£n£o£p£q£r£s¢A¢B" + }, + + { /* 6.ª`µ¼ÐÂI */ + "£t£u£v£w£x£y£z£{£|£}" + "£~£¡£¢£££¤£¥£¦£§£¨£©" + "£ª£«£¬££®£¯£°£±£²£³" + "£´£µ£¶£·£¸£¹£º£½£¾£¿" + "£»¡A¡C¡B¡I¡H¡G¡F¡u¡v" + } + }; + + char buf[80], tmp[6]; + char *ptr, *str; + int ch, page; + + /* ¿ï¤ÀÃþ */ + ch = KEY_PGUP; + do + { + outz("¤º½X¿é¤J¤u¨ã¡G"); + outs((ch == KEY_PGUP || ch == 'P') ? msg1 : msg2); + ch = vkey(); + } while (ch == KEY_PGUP || ch == 'P' || ch == KEY_PGDN || ch == 'N'); + + if (ch < '1' || ch > '6') + return; + + ptr = ansi[ch - '1']; + page = 0; + + for (;;) + { + buf[0] = '\0'; + str = ptr + page * 20; /* ¨C page ¦³¤QÓ¤¤¤å¦r¡A¨CÓ¤¤¤å¦r¬O 2 char */ + + for (ch = 0; ch < 10; ch++) + { + sprintf(tmp, "%d.%2.2s ", ch, str + ch * 2); /* ¨CÓ¤¤¤å¦r¬O 2 char */ + strcat(buf, tmp); + } + strcat(buf, "(PgUp/P:¤W PgDn/N:¤U)[Q] "); + outz(buf); + ch = vkey(); + + if (ch == KEY_PGUP || ch == 'P') + { + if (page) + page--; + } + else if (ch == KEY_PGDN || ch == 'N') + { + if (page != 4) + page++; + } + else if (ch < '0' || ch > '9') + { + break; + } + else + { + str += (ch - '0') * 2; + ve_char(*str); /* ¦L¥X¤GÓ char ¤¤¤å¦r */ + ve_char(*++str); + break; + } + } +} +#endif + + +/* ----------------------------------------------------- */ +/* ¼È¦sÀÉ TBF (Temporary Buffer File) routines */ +/* ----------------------------------------------------- */ + + +char * +tbf_ask() +{ + static char fn_tbf[] = "buf.1"; + int ch; + + do + { + ch = vget(b_lines, 0, "½Ð¿ï¾Ü¼È¦sÀÉ(1-5)¡G", fn_tbf + 4, 2, GCARRY); + } while (ch < '1' || ch > '5'); + return fn_tbf; +} + + +FILE * +tbf_open() +{ + int ans; + char fpath[64], op[4]; + struct stat st; + + usr_fpath(fpath, cuser.userid, tbf_ask()); + ans = 'a'; + + if (!stat(fpath, &st)) + { + ans = vans("¼È¦sÀɤw¦³¸ê®Æ (A)ªþ¥[ (W)Âмg (Q)¨ú®ø¡H[A] "); + if (ans == 'q') + return NULL; + + if (ans != 'w') + { + /* itoc.030208: Àˬd¼È¦sÀɤj¤p */ + if (st.st_size >= 100000) /* 100KB À³¸Ó°÷¤F */ + { + zmsg("¼È¦sÀɤӤj¡AµLªkªþ¥["); + return NULL; + } + + ans = 'a'; + } + } + + op[0] = ans; + op[1] = '\0'; + + return fopen(fpath, op); +} + + +static textline * +ve_load(this, fd) + textline *this; + int fd; +{ + uschar *str; + textline *next; + + next = this->next; + + mgets(-1); + while (str = mgets(fd)) + { + this = ve_line(this, str); + } + + this->next = next; + if (next) + next->prev = this; + + return this; +} + + +static inline void +tbf_read() +{ + int fd; + char fpath[80]; + + usr_fpath(fpath, cuser.userid, tbf_ask()); + + fd = open(fpath, O_RDONLY); + if (fd >= 0) + { + ve_load(vx_cur, fd); + close(fd); + } +} + + +static inline void +tbf_write() +{ + FILE *fp; + textline *p; + uschar *data; + + if (fp = tbf_open()) + { + for (p = vx_ini; p;) + { + data = p->data; + p = p->next; + if (p || *data) + fprintf(fp, "%s\n", data); + } + fclose(fp); + } +} + + +static inline void +tbf_erase() +{ + char fpath[64]; + + usr_fpath(fpath, cuser.userid, tbf_ask()); + unlink(fpath); +} + + +/* ----------------------------------------------------- */ +/* ½s¿è¾¹¦Û°Ê³Æ¥÷ */ +/* ----------------------------------------------------- */ + + +void +ve_backup() +{ + textline *p, *n; + + if (p = vx_ini) + { + FILE *fp; + char bakfile[64]; + + vx_ini = NULL; + usr_fpath(bakfile, cuser.userid, FN_BAK); + if (fp = fopen(bakfile, "w")) + { + do + { + n = p->next; + fprintf(fp, "%s\n", p->data); + free(p); + } while (p = n); + fclose(fp); + } + } +} + + +void +ve_recover() +{ + char fpbak[80], fpath[80]; + int ch; + + usr_fpath(fpbak, cuser.userid, FN_BAK); + if (dashf(fpbak)) + { + ch = vans("±z¦³¤@½g¤å³¹©|¥¼§¹¦¨¡A(M)±H¨ì«H½c (S)¼g¤J¼È¦sÀÉ (Q)ºâ¤F¡H[M] "); + if (ch == 's') + { + usr_fpath(fpath, cuser.userid, tbf_ask()); + rename(fpbak, fpath); + return; + } + else if (ch != 'q') + { + mail_self(fpbak, cuser.userid, "¥¼§¹¦¨ªº¤å³¹", 0); + } + unlink(fpbak); + } +} + + +/* ----------------------------------------------------- */ +/* ¤Þ¥Î¤å³¹ */ +/* ----------------------------------------------------- */ + + +static int +is_quoted(str) + char *str; /* "--\n", "-- \n", "--", "-- " */ +{ + if (*str == '-') + { + if (*++str == '-') + { + if (*++str == ' ') + str++; + if (*str == '\n') + str++; + if (!*str) + return 1; + } + } + return 0; +} + + +static inline int +quote_line(str, qlimit) + char *str; + int qlimit; /* ¤¹³\´X¼h¤Þ¨¥¡H */ +{ + int qlevel = 0; + int ch; + + while ((ch = *str) == QUOTE_CHAR1 || ch == QUOTE_CHAR2) + { + if (*(++str) == ' ') + str++; + if (qlevel++ >= qlimit) + return 0; + } + while ((ch = *str) == ' ' || ch == '\t') + str++; + if (qlevel >= qlimit) + { + if (!memcmp(str, "¡° ", 3) || !memcmp(str, "==>", 3) || + strstr(str, ") ´£¨ì:\n")) + return 0; + } + return (*str != '\n'); +} + + +static void +ve_quote(this) + textline *this; +{ + int fd, op; + FILE *fp; + textline *next; + char *str, buf[ANSILINELEN]; + static char msg[] = "¿ï¾Üñ¦WÀÉ (1~6 0=¤£¥[ r=¶Ã¼Æ n=´«¶)[0]¡G"; + + next = this->next; + + /* --------------------------------------------------- */ + /* ¤Þ¨¥ */ + /* --------------------------------------------------- */ + + if (*quote_file) + { + op = vans("¬O§_¤Þ¥Îì¤å Y)¤Þ¥Î N)¤£¤Þ¥Î A)¤Þ¥Î¥þ¤å R)«¶K¥þ¤å 1-9)¤Þ¥Î¼h¼Æ¡H[Y] "); + + if (op != 'n') + { + if (fp = fopen(quote_file, "r")) + { + str = buf; + + if ((op >= '1') && (op <= '9')) + op -= '1'; + else if ((op != 'a') && (op != 'r')) + op = 1; /* default : 2 level */ + + if (op != 'a') /* ¥h±¼ header */ + { + if (*quote_nick) + sprintf(buf + 128, " (%s)", quote_nick); + else + buf[128] = '\0'; + sprintf(str, "¡° ¤Þz¡m%s%s¡n¤§»Ê¨¥¡G", quote_user, buf + 128); + this = ve_line(this, str); + + while (fgets(str, ANSILINELEN, fp) && *str != '\n'); + + if (curredit & EDIT_LIST) /* ¥h±¼ mail list ¤§ header */ + { + while (fgets(str, ANSILINELEN, fp) && (!memcmp(str, "¡° ", 3))); + } + } + + if (op == 'r') + { + op = 'a'; + } + else + { + *str++ = QUOTE_CHAR1; + *str++ = ' '; + } + + if (op == 'a') + { + while (fgets(str, ANSILINELEN - 2, fp)) /* ¯dªÅ¶¡µ¹ "> " */ + this = ve_line(this, buf); + } + else + { + while (fgets(str, ANSILINELEN - 2, fp)) /* ¯dªÅ¶¡µ¹ "> " */ + { + if (is_quoted(str)) /* "--\n" */ + break; + if (quote_line(str, op)) + this = ve_line(this, buf); + } + } + fclose(fp); + } + } + *quote_file = '\0'; + } + + this = ve_line(this, ""); + + /* --------------------------------------------------- */ + /* ñ¦WÀÉ */ + /* --------------------------------------------------- */ + +#ifdef HAVE_ANONYMOUS + if (!(currbattr & BRD_ANONYMOUS) && !(cuser.ufo & UFO_NOSIGN)) /* ¦b°Î¦WªO¤¤µL½×¬O§_°Î¦W¡A§¡¤£¨Ï¥Îñ¦WÀÉ */ +#else + if (!(cuser.ufo & UFO_NOSIGN)) /* itoc.000320: ¤£¨Ï¥Îñ¦WÀÉ */ +#endif + { + int topsig = 1; /* LHD.031107: ¥»¶³Ì¤W±ªºÃ±¦WÀÉ */ + show_sign: + + if (cuser.ufo & UFO_SHOWSIGN) /* itoc.000319: Åã¥Üñ¦WÀɪº¤º®e */ + show_sign('0'+ topsig); + + msg[38] = op = cuser.signature + '0'; + if (fd = vget(b_lines, 0, msg, buf, 3, DOECHO)) + { + if (fd == 'n') /* LHD.031007: «ön´`Àô´«¶ */ + { + topsig = (topsig + 3 ) % 6; + goto show_sign; + } + + if (op != fd && ((fd >= '0' && fd <= '6') || fd == 'r')) + { + cuser.signature = fd - '0'; + op = fd; + } + } + + if (op == 'r') + op = (time(0) % 6) + '1'; + + if (op != '0') + { + char fpath[64]; + + sprintf(buf, "%s.%c", FN_SIGN, op); + usr_fpath(fpath, cuser.userid, buf); /* itoc.020123: ¦UÓñ¦WÀÉÀɮפÀ¶} */ + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + op = 0; + mgets(-1); + while ((str = mgets(fd)) && (op < MAXSIGLINES)) + { + if (!op) + this = ve_line(this, "--"); + + this = ve_line(this, str); + op++; + } + close(fd); + } + } + } + + this->next = next; + if (next) + next->prev = this; +} + + +/* ----------------------------------------------------- */ +/* ¼f¬d user ¤Þ¨¥ªº¨Ï¥Î */ +/* ----------------------------------------------------- */ + + +static int +quote_check() +{ + textline *p; + char *str; + int post_line; + int quot_line; + int in_quote; + + post_line = quot_line = in_quote = 0; + for (p = vx_ini; p; p = p->next) + { + str = p->data; + + /* itoc.030305: ¬°ºûÅ@ºô¸ô§»ö¡Añ¦WÀɤ]ºâ¤Þ¨¥ :p */ + + if (in_quote) /* ñ¦WÀÉ */ + { + quot_line++; + } + else if (is_quoted(str)) /* ñ¦WÀɶ}©l */ + { + in_quote = 1; + quot_line++; + } + else if (str[0] == QUOTE_CHAR1 && str[1] == ' ') /* ¤Þ¨¥ */ + { + quot_line++; + } + else /* ¤@¯ë¤º¤å */ + { + /* ªÅ¥Õ¦æ¤£ºâ post_line */ + while (*str == ' ') + str++; + if (*str) + post_line++; + } + } + + if ((quot_line >> 2) <= post_line) /* ¤å³¹¦æ¼Æn¦h©ó¤Þ¨¥¦æ¼Æ¥|¤À¤§¤@ */ + return 0; + + if (HAS_PERM(PERM_ALLADMIN)) + return (vans("¤Þ¨¥¹L¦h (E)Ä~Äò½s¿è (W)±j¨î¼g¤J¡H[E] ") != 'w'); + + vmsg("¤Þ¨¥¤Ó¦h¡A½Ð«ö Ctrl+Y ¨Ó§R°£¤£¥²n¤§¤Þ¨¥"); + return 1; +} + + +/* ----------------------------------------------------- */ +/* ¼f¬d user µoªí¤å³¹¦r¼Æ/ª`µ¤åªº¨Ï¥Î */ +/* ----------------------------------------------------- */ + + +int wordsnum; /* itoc.010408: ºâ¤å³¹¦r¼Æ */ + + +#ifdef ANTI_PHONETIC +static int +words_check() +{ + textline *p; + uschar *str, *pend; + int phonetic; /* ª`µ¤å¼Æ¥Ø */ + + wordsnum = phonetic = 0; + + for (p = vx_ini; p; p = p->next) + { + if (is_quoted(str = p->data)) /* ñ¦WÀɶ}©l */ + break; + + if (!(str[0] == QUOTE_CHAR1 && str[1] == ' ') && strncmp(str, "¡° ", 3)) /* «D¤Þ¥Î¥L¤H¤å³¹ */ + { + wordsnum += p->len; + + pend = str + p->len; + while (str < pend) + { + if (str[0] >= 0x81 && str[0] < 0xFE && str[1] >= 0x40 && str[1] <= 0xFE && str[1] != 0x7F) /* ¤¤¤å¦r BIG5+ */ + { + if (str[0] == 0xA3 && str[1] >= 0x74 && str[1] <= 0xBA) /* ª`µ¤å */ + phonetic++; + str++; /* ¤¤¤å¦rÂù¦ì¤¸¡An¦h¥[¤@¦¸ */ + } + str++; + } + + } + } + return phonetic; +} + +#else + +static void +words_check() +{ + textline *p; + char *str; + + wordsnum = 0; + + for (p = vx_ini; p; p = p->next) + { + if (is_quoted(str = p->data)) /* ñ¦WÀɶ}©l */ + break; + + if (!(str[0] == QUOTE_CHAR1 && str[1] == ' ') && strncmp(str, "¡° ", 3)) /* «D¤Þ¥Î¥L¤H¤å³¹ */ + wordsnum += p->len; + } +} +#endif + + +/* ----------------------------------------------------- */ +/* Àɮ׳B²z¡GŪÀÉ¡B¦sÀÉ¡B¼ÐÃD¡Bñ¦WÀÉ */ +/* ----------------------------------------------------- */ + + +void +ve_header(fp) + FILE *fp; +{ + time_t now; + char *title; + + title = ve_title; + title[72] = '\0'; + time(&now); + + if (curredit & EDIT_MAIL) + { + fprintf(fp, "%s %s (%s)\n", str_author1, cuser.userid, cuser.username); + } + else + { +#ifdef HAVE_ANONYMOUS + if (currbattr & BRD_ANONYMOUS && !(curredit & EDIT_RESTRICT)) + { + if (vans("n°Î¦Wµoªí¤å³¹¶Ü(Y/r)¡H[Y] ") != 'r') /* ¹w³]§ï¬°°Î¦Wµoªí */ + { + do + { + if (!vget(b_lines, 0, "½Ð¿é¤J§A·Q¥ÎªºID¡Aª½±µ«ö[Enter]¥Î¹w³]¡B¿é¤Jr¥Î¯u¦W¡G", + anonymousid, IDLEN, DOECHO)) + { + strcpy(anonymousid, STR_ANONYMOUS);/* «öEnter¡A°Î¦WID´N¥Î¹w³]ªº */ + curredit |= EDIT_ANONYMOUS; + break; + } + else if (!strcmp(anonymousid, cuser.userid)) /* ¦Û©w°Î¦WID */ + { /* ©M¦Û¤vªºID¤@¼Ë¡A¤£°Î¦Wµo¤å */ +// curredit |= EDIT_ANONYMOUS; + break; + } + else + { + char fpath[64]; + usr_fpath(fpath, anonymousid, NULL); + if (!strcmp(anonymousid, "r")) + { + strcpy(anonymousid, cuser.userid); + break; + } + if (dashd(fpath)) /* Àˬd³oÓID¦³¨S¦³µù¥U */ + { + vmsg("³oÓ¢×¢Ò¦³¤H¥Î¤F³á¡I´«¤@Ó§a¡C"); //°T®§¤º®e¥i¦Û¤v§ó§ï + } + else /* ²×©ó¥i¥H¥Î¦Û¤v·QnªºIDµo¤å¤F:P */ + { + strcat(anonymousid, ".");/* Y¬O¦Û©wID¡An¦b«á±¥[Ó . ªí¥Ü¤£¦P*/ + curredit |= EDIT_ANONYMOUS; + break; + } + } + + } while (1); + + } + } + +#if 0 + if (!vget(b_lines, 0, "½Ð¿é¤J±z·Q¥ÎªºID¡A¤]¥iª½±µ«ö[Enter]¡A©Î¬O«ö[r]¥Î¯u¦W¡G", anonymousid, IDLEN, DOECHO)) + { /* ¯d 1 byte ¥[ "." */ + strcpy(anonymousid, STR_ANONYMOUS); + curredit |= EDIT_ANONYMOUS; + } + else if (strcmp(anonymousid, "r")) + { + strcat(anonymousid, "."); /* Y¬O¦Û©wID¡An¦b«á±¥[Ó . ªí¥Ü¤£¦P */ + curredit |= EDIT_ANONYMOUS; + } + } +#endif +#endif + if (!(currbattr & BRD_NOSTAT) && !(curredit & EDIT_RESTRICT)) /* ¤£p¤å³¹½g¼Æ ¤Î ¥[±K¦sÀÉ ¤£¦C¤J²Îp½g¼Æ */ + { + /* ²£¥Í²Îp¸ê®Æ */ + + POSTLOG postlog; + +#ifdef HAVE_ANONYMOUS + /* Thor.980909: anonymous post mode */ + if (curredit & EDIT_ANONYMOUS) + strcpy(postlog.author, anonymousid); + else + +#endif + strcpy(postlog.author, cuser.userid); + + strcpy(postlog.board, currboard); + str_ncpy(postlog.title, str_ttl(title), sizeof(postlog.title)); + postlog.date = now; + postlog.number = 1; + + rec_add(FN_RUN_POST, &postlog, sizeof(POSTLOG)); + } + +#ifdef HAVE_ANONYMOUS + /* Thor.980909: anonymous post mode */ + if (curredit & EDIT_ANONYMOUS) + { + fprintf(fp, "%s %s (%s) %s %s\n", + str_author1, anonymousid, STR_ANONYMOUS, + curredit & EDIT_OUTGO ? str_post1 : str_post2, currboard); + } + else +#endif + + { + fprintf(fp, "%s %s (%s) %s %s\n", + str_author1, cuser.userid, cuser.username, + curredit & EDIT_OUTGO ? str_post1 : str_post2, currboard); + } + } + fprintf(fp, "¼ÐÃD: %s\n®É¶¡: %s\n\n", title, Btime(&now)); +} + +#define FOOL2011_EDIT_BANNER "\n--\n" \ +"\033[m \033[1m¢¨¢g¢© ¢p¢d¢« ¢¨¢g¢© ¢¨¢g¢© ¢¨¢g¢©\033[m\n" \ +"\033[44m \033[1;33m¥x«n¤@¤¤\033[;37;44m ¢i¢« ¢y¢i¢ª¢k ¢i¢« ¢ª¢g¢© ¢i¢« \033[1;33m¯Á¥§¤p¯¸\033[;37;44m \033[m\n"\ +" \033[1m¢ª¢g¢« ¢i ¢y¢© ¢ª¢g¢« ¢ª¢e¢« ¢ª¢g¢«\033[m\n" \ +"\033[0m Or\033[1mig\033[30min\033[37m ¡¸ \033[32msony.tfcis.org\033[m¡C\033[1;32mbbs.tfcis.org\033[m" \ +" A\033[1mut\033[30mho\033[mr\033[1m ¡¸ \033[33m%s\033[m\n" \ +" \033[mF\033[1mr\033[30mom\033[37m ¡¸ \033[m\033[1;35m%s(%s)\033[m\033[0m\n\n" + +void +ve_banner(fp, modify) /* ¥[¤W¨Ó·½µ¥°T®§ */ + FILE *fp; + int modify; /* 1:×§ï 0:ì¤å */ +{ + /* chitsaou: IP ¥\¯à */ + char name[40], fqdn[40], ipaddr[40]; + unsigned long sum; + unsigned long base[4]={16777216,65536,256,1}; + int i, ip[4]; + + /* ¨ú±oip */ + sum = dns_a(fromhost); + + for (i=0; i<=3; i++) + { + ip[i] = sum / base[i]; + sum -= base[i]*ip[i]; + } + + sprintf(ipaddr, "%d.%d.%d.%d", ip[3], ip[2], ip[1], ip[0]); + + /* ¥ý¤ñ¹ï FQDN */ + str_lower(name, fromhost); /* itoc.011011: ¤j¤p¼g§¡¥i¡Aetc/fqdn ¸Ì±³£n¼g¤p¼g */ + if (!belong_list(FN_ETC_FQDN, name, fqdn) && !belong_list(FN_ETC_HOST, name, fqdn)) + { + /* ¦A¤ñ¹ï ip */ + strcpy(name, ipaddr); + + if (!belong_list(FN_ETC_HOST, name, fqdn)) + { + strcpy(ipaddr, fromhost); //replace ipaddr with fromhost, to avoid ip=255.255.255.255 + strcpy(fqdn, "¨S¦³¬G¶m"); //also mark it + } + } + + if (!strcmp(ipaddr, "255.255.255.255")) + strcpy(ipaddr, fromhost); + + + /* itoc: «ØÄ³ banner ¤£n¶W¹L¤T¦æ¡A¹Lªøªº¯¸Ã±¥i¯à·|³y¦¨¬Y¨Ç¨Ï¥ÎªÌªº¤Ï·P */ + + time_t now = time(NULL); + if (!modify) + { + fprintf(fp, (now >= 1301587200 && now <= 1301673600) ? FOOL2011_EDIT_BANNER : EDIT_BANNER, +#ifdef HAVE_ANONYMOUS + (curredit & EDIT_ANONYMOUS) ? STR_ANONYMOUS : +#endif + cuser.userid, +#ifdef HAVE_ANONYMOUS + (curredit & EDIT_ANONYMOUS) ? "¶³»P¤sªº©¼ºÝ ^O^||" : +#endif + ipaddr, +#ifdef HAVE_ANONYMOUS + (curredit & EDIT_ANONYMOUS) ? "¤£§i¶D§A!" : +#endif + fqdn); + } + else + { + fprintf(fp, MODIFY_BANNER, cuser.userid, Now()); + } +} + + +static int +ve_filer(fpath, ve_op) + char *fpath; + int ve_op; /* 1: ¦³ header 0,2: µL header -1: ¤£¯àÀx¦s */ +{ + int ans; +#ifdef ANTI_PHONETIC + int phoneticsnum; /* ª`µ¤åªº¼Æ¶q */ +#endif + + FILE *fp; + textline *p, *v; + char buf[80], *msg; + +#ifdef POPUP_ANSWER + char **menu; +# ifdef HAVE_REFUSEMARK + char *menu1[] = {"EE", "Abort ©ñ±ó", "Title §ï¼ÐÃD", "Edit Ä~Äò½s¿è", "Read Ū¨ú¼È¦sÀÉ", "Write ¼g¤J¼È¦sÀÉ", "Delete §R°£¼È¦sÀÉ", NULL}; + char *menu2[] = {"SE", "Save ¦sÀÉ","Bottom ¸m©³¦sÀÉ", "Abort ©ñ±ó", "Title §ï¼ÐÃD", "Edit Ä~Äò½s¿è", "Read Ū¨ú¼È¦sÀÉ", "Write ¼g¤J¼È¦sÀÉ", "Delete §R°£¼È¦sÀÉ", NULL}; + char *menu3[] = {"SE", "Save ¦sÀÉ","Bottom ¸m©³¦sÀÉ", "Local ¦s¬°¯¸¤ºÀÉ", "XRefuse ¥[±K¦sÀÉ", "Abort ©ñ±ó", "Title §ï¼ÐÃD", "Edit Ä~Äò½s¿è", "Read Ū¨ú¼È¦sÀÉ", "Write ¼g¤J¼È¦sÀÉ", "Delete §R°£¼È¦sÀÉ", NULL}; + char *menu4[] = {"LE", "Local ¦s¬°¯¸¤ºÀÉ", "Save ¦sÀÉ","Bottom ¸m©³¦sÀÉ", "XRefuse ¥[±K¦sÀÉ", "Abort ©ñ±ó", "Title §ï¼ÐÃD", "Edit Ä~Äò½s¿è", "Read Ū¨ú¼È¦sÀÉ", "Write ¼g¤J¼È¦sÀÉ", "Delete §R°£¼È¦sÀÉ", NULL}; +# else + char *menu1[] = {"EE", "Abort ©ñ±ó", "Title §ï¼ÐÃD", "Edit Ä~Äò½s¿è", "Read Ū¨ú¼È¦sÀÉ", "Write ¼g¤J¼È¦sÀÉ", "Delete §R°£¼È¦sÀÉ", NULL}; + char *menu2[] = {"SE", "Save ¦sÀÉ", "Abort ©ñ±ó", "Title §ï¼ÐÃD", "Edit Ä~Äò½s¿è", "Read Ū¨ú¼È¦sÀÉ", "Write ¼g¤J¼È¦sÀÉ", "Delete §R°£¼È¦sÀÉ", NULL}; + char *menu3[] = {"SE", "Save ¦sÀÉ", "Local ¦s¬°¯¸¤ºÀÉ", "Abort ©ñ±ó", "Title §ï¼ÐÃD", "Edit Ä~Äò½s¿è", "Read Ū¨ú¼È¦sÀÉ", "Write ¼g¤J¼È¦sÀÉ", "Delete §R°£¼È¦sÀÉ", NULL}; + char *menu4[] = {"LE", "Local ¦s¬°¯¸¤ºÀÉ", "Save ¦sÀÉ", "Abort ©ñ±ó", "Title §ï¼ÐÃD", "Edit Ä~Äò½s¿è", "Read Ū¨ú¼È¦sÀÉ", "Write ¼g¤J¼È¦sÀÉ", "Delete §R°£¼È¦sÀÉ", NULL}; +# endif +#else +# ifdef HAVE_REFUSEMARK + char *msg1 = "[E]Ä~Äò (A)©ñ±ó (R/W/D)Ū¼g§R¼È¦sÀÉ¡H"; + char *msg2 = "[S]¦sÀÉ (B) ¸m©³ (A)©ñ±ó (T)§ï¼ÐÃD (E)Ä~Äò (R/W/D)Ū¼g§R¼È¦sÀÉ¡H"; + char *msg3 = "[S]¦sÀÉ (B) ¸m©³ (L)¯¸¤º (X)±K«Ê (A)©ñ±ó (T)§ï¼ÐÃD (E)Ä~Äò (R/W/D)Ū¼g§R¼È¦sÀÉ¡H"; + char *msg4 = "[L]¯¸¤º (S)¦sÀÉ (B) ¸m©³ (X)±K«Ê (A)©ñ±ó (T)§ï¼ÐÃD (E)Ä~Äò (R/W/D)Ū¼g§R¼È¦sÀÉ¡H"; +# else + char *msg1 = "[E]Ä~Äò (A)©ñ±ó (R/W/D)Ū¼g§R¼È¦sÀÉ¡H"; + char *msg2 = "[S]¦sÀÉ (A)©ñ±ó (T)§ï¼ÐÃD (E)Ä~Äò (R/W/D)Ū¼g§R¼È¦sÀÉ¡H"; + char *msg3 = "[S]¦sÀÉ (L)¯¸¤º (A)©ñ±ó (T)§ï¼ÐÃD (E)Ä~Äò (R/W/D)Ū¼g§R¼È¦sÀÉ¡H"; + char *msg4 = "[L]¯¸¤º (S)¦sÀÉ (A)©ñ±ó (T)§ï¼ÐÃD (E)Ä~Äò (R/W/D)Ū¼g§R¼È¦sÀÉ¡H"; +# endif +#endif + + ans = 0; + +#ifdef POPUP_ANSWER + if (ve_op < 0) /* itoc.010301: ·s¼W ve_op = -1 ¤£¯àÀx¦s */ + menu = menu1; + else if (bbsmode != M_POST) /* ¼g«H */ + menu = menu2; + else if (curredit & EDIT_OUTGO) /* Âà«HªOµo¤å */ + menu = menu3; + else + menu = menu4; + + switch (pans(3, 20, "¦sÀɿﶵ", menu)) +#else + if (ve_op < 0) /* itoc.010301: ·s¼W ve_op = -1 ¤£¯àÀx¦s */ + msg = msg1; + else if (bbsmode != M_POST) /* ¼g«H */ + msg = msg2; + else if (curredit & EDIT_OUTGO) /* Âà«HªOµo¤å */ + msg = msg3; + else + msg = msg4; + + switch (vans(msg)) +#endif + + { + case 's': + if (ve_op < 0) /* itoc.010301: ¤£¯àÀx¦s */ + return VE_FOOTER; + /* Thor.990111: ¤£Âà«H«h¤£¥~¬y */ + if (HAS_PERM(PERM_INTERNET) && !(currbattr & BRD_NOTRAN)) + curredit |= EDIT_OUTGO; + break; + + case 'a': + ans = -1; + break; + + case 'l': + if (ve_op < 0) /* itoc.010301: ¤£¯àÀx¦s */ + return VE_FOOTER; + curredit &= ~EDIT_OUTGO; + break; + +#ifdef HAVE_REFUSEMARK + case 'x': + if (ve_op < 0) /* itoc.010301: ¤£¯àÀx¦s */ + return VE_FOOTER; + curredit |= EDIT_RESTRICT; + curredit &= ~EDIT_OUTGO; /* ¥[±K¥²¬O local save */ + break; +#endif + + case 'b': + if (ve_op < 0) + return VE_FOOTER; + if ((bbsmode == M_POST) && (bbstate & STAT_BOARD)) /* ªO¥Dµo¤å */ + curredit |= EDIT_BOTTOM; + else if (HAS_PERM(PERM_INTERNET) && !(currbattr & BRD_NOTRAN)) + curredit |= EDIT_OUTGO; /* §_«hµø¬° save */ + break; + + case 'r': + tbf_read(); + return VE_REDRAW; + + case 'e': + return VE_FOOTER; + + case 'w': + tbf_write(); + return VE_FOOTER; + + case 'd': + tbf_erase(); + return VE_FOOTER; + + case 't': + if (ve_op > 0) /* itoc.010301: ¤£¯àÀx¦s */ + { + strcpy(buf, ve_title); + if (!vget(b_lines, 0, "¼ÐÃD¡G", ve_title, TTLEN + 1, GCARRY)) + strcpy(ve_title, buf); + } + return VE_FOOTER; + + default: + if (ve_op < 0) /* itoc.010301: ¤£¯àÀx¦s */ + return VE_FOOTER; + } + + if (!ans) + { + if (ve_op == 1 && !(curredit & EDIT_MAIL) && quote_check()) + return VE_FOOTER; + +#ifdef ANTI_PHONETIC + phoneticsnum = words_check(); + if (!(curredit & EDIT_MAIL) && bbsmode != M_UFILES && + (currbattr & BRD_NOPHONETIC) && phoneticsnum > 2) + { + char xdbuffer[20]; + sprintf (xdbuffer, "½Ð¤Å¨Ï¥Îª`µ¤å (%d)", phoneticsnum); + //vmsg("½Ð¤Å¨Ï¥Îª`µ¤å"); + vmsg (xdbuffer); + return VE_FOOTER; + } +#endif + + if (!*fpath) + { + usr_fpath(fpath, cuser.userid, fn_note); + } + + if ((fp = fopen(fpath, "w")) == NULL) + { + ve_abort(5); + abort_bbs(); + } + +#ifndef ANTI_PHONETIC + words_check(); /* itoc.010408: ºâ¤å³¹¦r¼Æ */ +#endif + + if (ve_op == 1) + ve_header(fp); + } + + if (p = vx_ini) + { + vx_ini = NULL; + + do + { + v = p->next; + if (!ans) + { + msg = p->data; + str_trim(msg); + fprintf(fp, "%s\n", msg); + } + free(p); + } while (p = v); + } + + if (!ans) + { + if (bbsmode == M_POST || bbsmode == M_SMAIL) + ve_banner(fp, 0); + fclose(fp); + } + + return ans; +} + + +/* ----------------------------------------------------- */ +/* ¿Ã¹õ³B²z¡G»²§U°T®§¡BÅã¥Ü½s¿è¤º®e */ +/* ----------------------------------------------------- */ + + +static void +ve_outs(text) + uschar *text; +{ + int ch; + uschar *tail; + + tail = text + SCR_WIDTH; + while (ch = *text) + { + switch (ch) + { + case KEY_ESC: + ch = '*'; + break; + } + outc(ch); + + if (++text >= tail) + break; + } +} + + +int +ve_subject(row, topic, dft) + int row; + char *topic; + char *dft; +{ + char *title; + + title = ve_title; + + if (topic) + { + sprintf(title, "Re: %s", str_ttl(topic)); + title[TTLEN] = '\0'; + } + else + { + if (dft) + strcpy(title, dft); + else + *title = '\0'; + } + + return vget(row, 0, "¼ÐÃD¡G", title, TTLEN + 1, GCARRY); +} + + +/* ----------------------------------------------------- */ +/* ½s¿è³B²z¡G¥Dµ{¦¡¡BÁä½L³B²z */ +/* ----------------------------------------------------- */ + +/* ----------------------------------------------------- */ +/* vedit ¦^¶Ç -1:¨ú®ø½s¿è 0:§¹¦¨½s¿è */ +/* ----------------------------------------------------- */ +/* ve_op: */ +/* 0 => ¯Âºé½s¿èÀÉ®× */ +/* -1 => ½s¿è¦ý¤£¯àÀx¦s¡A¥Î¦b½s¿è§@ªÌ¤£¬O¦Û¤vªº¤å³¹ */ +/* 1 => ¤Þ¤å¡B¥[ñ¦WÀÉ¡A¨Ã¥[¤WÀÉÀY¡A¥Î¦bµoªí¤å³¹/¯¸¤º«H */ +/* 2 => ¤Þ¤å¡B¥[ñ¦WÀÉ¡A¤£¥[¤WÀÉÀY¡A¥Î¦b±H¯¸¥~«H */ +/* ----------------------------------------------------- */ +/* Y ve_op ¬O 1 ©Î 2 ®É¡A¶i¤J vedit «eÁÙ±o«ü©w curredit */ +/* ©M quote_file */ +/* ----------------------------------------------------- */ + +int /* -1:¨ú®ø½s¿è 0:§¹¦¨½s¿è */ +vedit(fpath, ve_op) + char *fpath; + int ve_op; /* 0:¯Âºé½s¿èÀÉ®× -1:½s¿è¦ý¤£¯àÀx¦s 1:quote/header 2:quote */ +{ + textline *vln, *tmp; + int cc, col, mode, margin, pos; + + /* --------------------------------------------------- */ + /* ªì©l³]©w¡G¸ü¤JÀɮסB¤Þ¥Î¤å³¹¡B³]©w½s¿è¼Ò¦¡ */ + /* --------------------------------------------------- */ + + tmp = vln = ve_alloc(); + + if (*fpath) + { + cc = open(fpath, O_RDONLY); + if (cc >= 0) + { + vln = ve_load(vln, cc); + } + else + { + cc = open(fpath, O_WRONLY | O_CREAT, 0600); + if (cc < 0) + { + ve_abort(4); + abort_bbs(); + } + } + close(cc); + } + + /* if (ve_op) */ + if (ve_op > 0) /* itoc.010301: ·s¼W ve_op = -1 ®É¤£¯àÀx¦s */ + { + ve_quote(vln); + } + + if (vln = tmp->next) + { + free(tmp); + vln->prev = NULL; + } + else + { + vln = tmp; + } + + vx_cur = vx_top = vx_ini = vln; + + ve_col = ve_row = margin = 0; + ve_lno = 1; + ve_mode = VE_INSERT | VE_REDRAW | VE_FOOTER; + +#ifdef HAVE_MULTI_BYTE + zhc = (cuser.ufo & UFO_ZHC); +#endif + + /* --------------------------------------------------- */ + /* ¥D°j°é¡G¿Ã¹õÅã¥Ü¡BÁä½L³B²z¡BÀɮ׳B²z */ + /* --------------------------------------------------- */ + + clear(); + + for (;;) + { + vln = vx_cur; + mode = ve_mode; + col = ve_col; + /* itoc.031123.µù¸Ñ: ¦pªG¶W¹L SCR_WIDTH¡A¨º»ò¶±©¹¥k½¡A¨Ã«O¯d¥ª¶ªº³Ì«á 4 ¦r */ + cc = (col < SCR_WIDTH) ? 0 : (col / (SCR_WIDTH - 4)) * (SCR_WIDTH - 4); + if (cc != margin) + { + mode |= VE_REDRAW; + margin = cc; + } + + if (mode & VE_REDRAW) + { + ve_mode = (mode ^= VE_REDRAW); + + tmp = vx_top; + + for (pos = 0;; pos++) + { + move(pos, 0); + clrtoeol(); + if (pos == b_lines) + break; + if (tmp) + { + if (mode & VE_ANSI) + outx(tmp->data); + else if (tmp->len > margin) + ve_outs(tmp->data + margin); + tmp = tmp->next; + } + else + { + outc('~'); + } + } +#ifdef EVERY_BIFF + if (!(mode & VE_BIFF)) + { + if (HAS_STATUS(STATUS_BIFF)) + ve_mode = mode |= VE_BIFF; + } +#endif + } + else + { + move(ve_row, 0); + if (mode & VE_ANSI) + outx(vln->data); + else if (vln->len > margin) + ve_outs(vln->data + margin); + clrtoeol(); + } + + /* ------------------------------------------------- */ + /* Åã¥Üª¬ºA¡BŪ¨úÁä½L */ + /* ------------------------------------------------- */ + + if (mode & VE_ANSI) /* Thor: §@ ansi ½s¿è */ + pos = n2ansi(col, vln); /* Thor: ansi ¤£·|¥Î¨ìcc */ + else /* Thor: ¤£¬Oansin§@margin shift */ + pos = col - margin; + + if (mode & VE_FOOTER) + { + move(b_lines, 0); + clrtoeol(); + + if (cuser.ufo & UFO_VEDIT) + { + ve_mode = (mode ^= VE_FOOTER); + } + else + { + prints(FOOTER_VEDIT, +#ifdef EVERY_BIFF + mode & VE_BIFF ? "¶l®t¨Ó¤F" : "½s¿è¤å³¹", +#else + "½s¿è¤å³¹", +#endif + mode & VE_INSERT ? "´¡¤J" : "¨ú¥N", + mode & VE_ANSI ? "ANSI" : "¤@¯ë", + ve_lno, 1 + (mode & VE_ANSI ? pos : col)); + } + } + + move(ve_row, pos); + +ve_key: + + cc = vkey(); + + if (isprint2(cc)) + { + ve_char(cc); + } + else + { + switch (cc) + { + case '\n': + + ve_split(vln, col); + break; + + case KEY_TAB: + + do + { + ve_char(' '); + } while (ve_col & (TAB_STOP - 1)); + break; + + case KEY_INS: /* Toggle insert/overwrite */ + + ve_mode = mode ^ VE_INSERT; + continue; + + case KEY_BKSP: /* backspace */ + + /* Thor: ¦b ANSI ½s¿è¼Ò¦¡¤U, ¤£¥i¥H«ö˰h, ¤£µM·|«Ü¥i©È.... */ + + if (mode & VE_ANSI) + { +#if 0 + goto ve_key; /* «ö«á°hÁä´N·í¨S«ö */ +#endif + + /* itoc.010322: ANSI ½s¿è®É«ö«á°hÁä¦^¨ì«D ANSI ¼Ò¦¡ */ + mode ^= VE_ANSI; + clear(); + ve_mode = mode | VE_REDRAW; + continue; + } + + if (col) + { + delete_char(vln, --col); +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: §PÂ_²{¦b§R°£ªº¦ì¸m¬O§_¬°º~¦rªº«á¥b¬q¡AY¬O§R¤G¦r¤¸ */ + if (zhc && col && IS_ZHC_LO(vln->data, col)) + delete_char(vln, --col); +#endif + ve_col = col; + continue; + } + + if (!(tmp = vln->prev)) + goto ve_key; + + ve_row--; + ve_lno--; + vx_cur = tmp; + ve_col = tmp->len; + if (*ve_strim(vln->data)) + join_up(tmp); + else + delete_line(vln); + ve_mode = mode | VE_REDRAW; + break; + + case Ctrl('D'): + case KEY_DEL: /* delete current character */ + + cc = vln->len; + if (cc == col) + { + join_up(vln); + ve_mode = mode | VE_REDRAW; + } + else + { + if (cc == 0) + goto ve_key; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: §PÂ_²{¦b§R°£ªº¦ì¸m¬O§_¬°º~¦rªº«e¥b¬q¡AY¬O§R¤G¦r¤¸ */ + /* ª`·N즳ªºÂù¦â¦r§R°£«á¥i¯à¥X°ÝÃD¡A¼È®É¤£§@¥t¦æ³B²z */ + if (zhc && col < cc - 1 && IS_ZHC_HI(vln->data[col])) + delete_char(vln, col); +#endif + delete_char(vln, col); + if (mode & VE_ANSI) /* Thor: ÁöµM¼W¥[ load, ¤£¹Ledit ®É·|¤ñ¸û¦n¬Ý */ + ve_col = ansi2n(n2ansi(col, vln), vln); + } + continue; + + case KEY_LEFT: + + if (col) + { + ve_col = (mode & VE_ANSI) ? ansi2n(pos - 1, vln) : col - 1; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: ¥ª²¾®É¸I¨ìº~¦r²¾Âù®æ */ + if (zhc && ve_col && IS_ZHC_LO(vln->data, ve_col)) + ve_col--; +#endif + continue; + } + + if (!(tmp = vln->prev)) + goto ve_key; + + ve_row--; + ve_lno--; + ve_col = tmp->len; + vx_cur = tmp; + break; + + case KEY_RIGHT: + + if (col < vln->len) + { + ve_col = (mode & VE_ANSI) ? ansi2n(pos + 1, vln) : col + 1; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: ¥k²¾®É¸I¨ìº~¦r²¾Âù®æ */ + if (zhc && ve_col < vln->len && IS_ZHC_HI(vln->data[ve_col - 1])) + ve_col++; +#endif + continue; + } + + if (!(tmp = vln->next)) + goto ve_key; + + ve_row++; + ve_lno++; + ve_col = 0; + vx_cur = tmp; + break; + + case KEY_HOME: + case Ctrl('A'): + + ve_col = 0; + continue; + + case KEY_END: + case Ctrl('E'): + + ve_col = vln->len; + continue; + + case KEY_UP: + case Ctrl('P'): + + if (!(tmp = vln->prev)) + goto ve_key; + + ve_row--; + ve_lno--; + if (mode & VE_ANSI) + { + ve_col = ansi2n(pos, tmp); + } + else + { + cc = tmp->len; + if (col > cc) + ve_col = cc; + } + vx_cur = tmp; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: º~¦r¾ã¦r½Õ¸` */ + if (zhc && ve_col < tmp->len && IS_ZHC_LO(tmp->data, ve_col)) + ve_col++; +#endif + break; + + case KEY_DOWN: + case Ctrl('N'): + + if (!(tmp = vln->next)) + goto ve_key; + + ve_row++; + ve_lno++; + if (mode & VE_ANSI) + { + ve_col = ansi2n(pos, tmp); + } + else + { + cc = tmp->len; + if (col > cc) + ve_col = cc; + } + vx_cur = tmp; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: º~¦r¾ã¦r½Õ¸` */ + if (zhc && ve_col < tmp->len && IS_ZHC_LO(tmp->data, ve_col)) + ve_col++; +#endif + break; + + case KEY_PGUP: + case Ctrl('B'): + + ve_pageup(); + continue; + + case KEY_PGDN: + case Ctrl('F'): + case Ctrl('T'): /* tail of file */ + + ve_forward(cc == Ctrl('T') ? -1 : PAGE_SCROLL); + continue; + + case Ctrl('S'): /* start of file */ + + vx_cur = vx_top = vx_ini; + ve_col = ve_row = 0; + ve_lno = 1; + ve_mode = mode | VE_REDRAW; + continue; + + case Ctrl('V'): /* Toggle ANSI color */ + + mode ^= VE_ANSI; + clear(); + ve_mode = mode | VE_REDRAW; + continue; + + case Ctrl('X'): /* Save and exit */ + + /* cc = ve_filer(fpath, ve_op & 1); */ + cc = ve_filer(fpath, ve_op); /* itoc.010301: ·s¼W ve_op = -1 ®É¤£¯àÀx¦s */ + if (cc <= 0) + return cc; + ve_mode = mode | cc; + continue; + + case Ctrl('Z'): + + cutmp->status |= STATUS_EDITHELP; + xo_help("post"); + cutmp->status ^= STATUS_EDITHELP; + ve_mode = mode | VE_REDRAW; + continue; + + case Ctrl('C'): + + ve_ansi(); + break; + + case Ctrl('O'): /* delete to end of file */ + + /* vln->len = ve_col = cc = 0; */ + tmp = vln->next; + vln->next = NULL; + while (tmp) + { + vln = tmp->next; + free(tmp); + tmp = vln; + } + ve_mode = mode | VE_REDRAW; + continue; + + case Ctrl('Y'): /* delete current line */ + + vln->len = ve_col = 0; + vln->data[0] = '\0'; /* Thor.981001: ±N¤º®e¤@¨Ö²M°£ */ + + case Ctrl('K'): /* delete to end of line */ + + if (cc = vln->len) + { + if (cc != col) + { + vln->len = col; + vln->data[col] = '\0'; + continue; + } + + join_up(vln); + } + else + { + tmp = vln->next; + if (!tmp) + { + tmp = vln->prev; + if (!tmp) + break; + + if (ve_row > 0) + { + ve_row--; + ve_lno--; + } + } + if (vln == vx_top) + vx_top = tmp; + delete_line(vln); + vx_cur = tmp; + } + + ve_mode = mode | VE_REDRAW; + break; + + case Ctrl('U'): + + ve_char(KEY_ESC); + break; + +#ifdef SHOW_USER_IN_TEXT + case Ctrl('Q'): + cc = vans("Åã¥Ü¨Ï¥ÎªÌ¸ê®Æ(1)id (2)¼ÊºÙ (3)¯u¹ê©m¦W¡H"); + if (cc >= '1' && cc <= '3') + { + ve_char(KEY_ESC); + ve_char('*'); + ve_char("snr"[cc - '1']); + } + ve_mode = mode | VE_FOOTER; + break; +#endif + +#ifdef INPUT_TOOLS + case Ctrl('W'): + + input_tools(); + ve_mode = mode | VE_FOOTER; + break; +#endif + +#ifdef HAVE_MULTI_BYTE + case Ctrl('G'): + /* lantw44: ¥þ«¬¦r°»´ú¤Á´« (Ctrl Áä ³£³Q¥Î¥ú¤F©Ò¥H¥Î³oÓ) */ + cuser.ufo ^= UFO_ZHC; + zhc = (cuser.ufo & UFO_ZHC); + if(zhc){ + vmsg("¥þ«¬¦r°»´ú¶}±Ò"); + }else{ + vmsg("¥þ«¬¦r°»´úÃö³¬"); + } + break; +#endif + + default: + + goto ve_key; + } + } + + /* ------------------------------------------------- */ + /* ve_row / ve_lno ½Õ¾ã */ + /* ------------------------------------------------- */ + + cc = ve_row; + if (cc < 0) + { + ve_row = 0; + if (vln = vx_top->prev) + { + vx_top = vln; + rscroll(); + } + else + { + ve_abort(6); + } + } + else if (cc >= b_lines) + { + ve_row = b_lines - 1; + if (vln = vx_top->next) + { + vx_top = vln; + scroll(); + } + else + { + ve_abort(7); + } + } + } +} diff --git a/maple/favor.c b/maple/favor.c new file mode 100644 index 0000000..3e3717c --- /dev/null +++ b/maple/favor.c @@ -0,0 +1,848 @@ +/*-------------------------------------------------------*/ +/* favorite.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : §Úªº³Ì·R */ +/* create : 00/06/16 */ +/* update : / / */ +/* author : weichung.bbs@bbs.ntit.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#ifdef MY_FAVORITE + +static int mf_add(); +static int mf_paste(); +static int mf_load(); + + +extern XZ xz[]; +extern char xo_pool[]; +extern char brd_bits[]; /* itoc.010821: §PÂ_¬O§_¦³¾\Ū¬ÝªOªºÅv */ +extern BCACHE *bshm; +extern int class_flag; + +#ifndef ENHANCED_VISIT +extern time_t brd_visit[]; +#endif + +#ifdef AUTO_JUMPBRD +static int mf_jumpnext = 0; /* itoc.020615: ¬O§_¸õ¥h¤U¤@Ó¥¼ÅªªO 1:n 0:¤£n */ +#endif + + +static MF mftmp; /* for copy & paste */ + + +void +mf_fpath(fpath, userid, fname) + char *fpath; + char *userid; + char *fname; +{ + char buf[64]; + + sprintf(buf, "MF/%s", fname); + usr_fpath(fpath, userid, buf); +} + + +static void +mf_item(num, mf) + int num; + MF *mf; +{ + char folder[64]; + int mftype, brdpost, bno; + + mftype = mf->mftype; + brdpost = cuser.ufo & UFO_BRDPOST; + + if (mftype & MF_FOLDER) + { + if (brdpost) + { + mf_fpath(folder, cuser.userid, mf->xname); + num = rec_num(folder, sizeof(MF)); + } + prints("%6d%c %s %s\n", num, mftype & MF_MARK ? ')' : ' ', "¡»", mf->title); + } + else if (mftype & MF_BOARD) + { + if ((bno = brd_bno(mf->xname)) >= 0) + class_item(num, bno, brdpost); + else + /* itoc.010821: ¤£¨£ªº¬ÝªO¡AÅý user ¦Û¤v²M±¼¡A¦p¦¹ user ¤~ª¾¹Dþ¨Ç¬ÝªO³Q¬å¤F */ + prints(" \033[36m<%s ¤w§ï¦W©Î³Q§R°£¡A½Ð±N¥»±¶®|§R°£>\033[m\n", mf->xname); + } + else if (mftype & MF_GEM) + { + prints("%6d%c %s %s\n", + brdpost ? 0 : num, + mftype & MF_MARK ? ')' : ' ', "¡½", mf->title); + } + else /* if (mftype & MF_LINE) */ /* qazq.040721: ¤À¹j½u */ + { + prints("%6d %s\n", + brdpost ? 0 : num, mf->title); + } +} + + +static int +mf_body(xo) + XO *xo; +{ + MF *mf; + int max, num, tail; +#ifdef AUTO_JUMPBRD + int nextpos; + static int originpos = -1; +#endif + + max = xo->max; + if (max <= 0) + { + max = vans("§Úªº³Ì·R (A)·s¼W (P)¶K¤W (Q)Â÷¶} [Q] "); + switch (max) + { + case 'a': + + max = mf_add(xo); + if (xo->max > 0) + return max; + break; + + case 'p': + + mf_paste(xo); + return mf_load(xo); + } + + return XO_QUIT; + } + + num = xo->top; + tail = num + XO_TALL; + if (max > tail) + max = tail; + +#ifdef AUTO_JUMPBRD + nextpos = 0; + + /* itoc.020615: ·j´M¤U¤@Ó¥¼Åª¬ÝªO */ + if (mf_jumpnext) + { + BRD *bcache; + + tail = xo->pos; /* ɥΠtail */ + if (originpos < 0) /* ¦b¥h¤U¶·j´M¥¼Åª¬ÝªO«e¡A°O¿ý¤@¶}©l´å¼Ð©Ò¦b */ + originpos = tail; + mf = (MF *) xo_pool + tail - num; + bcache = bshm->bcache; + + while (tail < max) /* ¥u¯à§ä¥»¶¤¤ªº¥¼Åª¬ÝªO¡A¦]¬°¤U¶ÁÙ¨S¸ü¤J */ + { + if (mf->mftype & MF_BOARD) + { + int chn; + BRD *brd; + + chn = brd_bno(mf->xname); + brd = bcache + chn; + +#ifdef ENHANCED_VISIT + /* itoc.010407: §ï¥Î³Ì«á¤@½g¤wŪ/¥¼Åª¨Ó§PÂ_ */ + brh_get(brd->bstamp, chn); + if (brh_unread(brd->blast)) +#else + if (brd->blast > brd_visit[chn]) +#endif + { + nextpos = tail; + mf_jumpnext = 0; + originpos = -1; + break; + } + } + tail++; + mf++; + } + + if (mf_jumpnext) /* ¦pªG¦b¥»¶¨S¦³§ä¨ì¥¼Åª¬ÝªO */ + { + if (max < rec_num(xo->dir, sizeof(MF))) /* ¦A¥h¤U¶§ä */ + return num + XO_TALL + XO_MOVE; + + /* ¤w¸g¬O³Ì«á¤@¶¤FÁÙ¬O§ä¤£¨ì¥¼Åª¬ÝªO */ + mf_jumpnext = 0; + tail = originpos; + originpos = -1; + if (tail < num) /* ¦^¨ìì¨Ó¨º¶ */ + return tail + XO_MOVE; + } + } +#endif + + mf = (MF *) xo_pool; + + move(3, 0); + do + { + mf_item(++num, mf++); + } while (num < max); + clrtobot(); + +#ifdef AUTO_JUMPBRD + /* itoc.020615: ¤U¤@Ó¥¼ÅªªO¦b¥»¶¡An§â´å¼Ð²¾¹L¥h */ + outf(FEETER_MF); + return nextpos ? nextpos + XO_MOVE : XO_NONE; +#else + /* return XO_NONE; */ + return XO_FOOT; /* itoc.010403: §â b_lines ¶ñ¤W feeter */ +#endif +} + + +static int +mf_head(xo) + XO *xo; +{ + vs_head("§Úªº³Ì·R", str_site); + prints(NECKER_MF, + class_flag & UFO_BRDPOST ? "Á`¼Æ" : "½s¸¹", + d_cols >> 1, "", d_cols - (d_cols >> 1), ""); + return mf_body(xo); +} + + +static int +mf_init(xo) + XO *xo; +{ + xo_load(xo, sizeof(MF)); + return mf_head(xo); +} + + +static int +mf_load(xo) + XO *xo; +{ + xo_load(xo, sizeof(MF)); + return mf_body(xo); +} + + +static int +mf_stamp(mf) + MF *mf; +{ + char fpath[64]; + int fd; + + mf->xname[0] = 'F'; + archiv32(mf->chrono, mf->xname + 1); + + mf_fpath(fpath, cuser.userid, mf->xname); + + if ((fd = open(fpath, O_WRONLY | O_CREAT | O_EXCL, 0600)) >= 0) + close(fd); + + return fd; +} + + +static int +mf_add(xo) + XO *xo; +{ + MF mf; + int ans; + + ans = vans("·s¼W (B)¬ÝªO±¶®| (F)¨÷©v (G)ºëµØ°Ï±¶®| (L)¤À¹j½u [Q] "); + + if (ans != 'b' && ans != 'f' && ans != 'g' && ans != 'l') + return XO_FOOT; + + time(&mf.chrono); + + if (ans == 'b' || ans == 'g') + { + BRD *brd; + char bname[BNLEN + 1]; + + if (!(brd = ask_board(bname, BRD_R_BIT, NULL))) + return mf_head(xo); + + mf.mftype = (ans == 'b') ? MF_BOARD : MF_GEM; + strcpy(mf.xname, brd->brdname); + if (ans == 'g') + sprintf(mf.title, "%s ªO ºëµØ°Ï±¶®|", mf.xname); + } + else /* if (ans == 'f' || ans == 'l') */ + { + if (!vget(b_lines, 0, "¼ÐÃD¡G", mf.title, BTLEN + 1, DOECHO)) + return XO_FOOT; + + mf.mftype = (ans == 'f') ? MF_FOLDER : MF_LINE; + if (ans == 'f') + { + if (mf_stamp(&mf) < 0) + return XO_FOOT; + } + } + + ans = vans("¦s©ñ¦ì¸m A)·s¼W I)´¡¤J N)¤U¤@Ó Q)Â÷¶} [A] "); + switch (ans) + { + case 'q': + break; + + case 'i': + case 'n': + + rec_ins(xo->dir, &mf, sizeof(MF), xo->pos + (ans == 'n'), 1); + break; + + default: + + rec_add(xo->dir, &mf, sizeof(MF)); + break; + } + + return mf_init(xo); +} + + +static void +mf_do_delete(folder) + char *folder; +{ + MF mf; + char fpath[64]; + FILE *fp; + + if (!(fp = fopen(folder, "r"))) + return; + + while (fread(&mf, sizeof(MF), 1, fp) == 1) + { + if (mf.mftype & MF_FOLDER) + { + mf_fpath(fpath, cuser.userid, mf.xname); + mf_do_delete(fpath); + } + } + + fclose(fp); + unlink(folder); +} + + +static int +mf_delete(xo) + XO *xo; +{ + MF *mf; + int mftype; + char fpath[64]; + + mf = (MF *) xo_pool + (xo->pos - xo->top); + mftype = mf->mftype; + + if (mftype & MF_MARK) + return XO_NONE; + + if (vans(msg_del_ny) == 'y') + { + if (mftype & MF_FOLDER) + { + mf_fpath(fpath, cuser.userid, mf->xname); + mf_do_delete(fpath); + } + if (!rec_del(xo->dir, sizeof(MF), xo->pos, NULL)) + return mf_load(xo); + } + + return XO_FOOT; +} + + +static void +delmf(xo, mf) + XO *xo; + MF *mf; +{ + if (mf->mftype & MF_FOLDER) + { + char fpath[64]; + + mf_fpath(fpath, cuser.userid, mf->xname); + mf_do_delete(fpath); + } +} + + +static int +mf_rangedel(xo) /* amaki.030910: ´£¨Ñ§Úªº³Ì·R°Ï¬q§R°£ */ + XO *xo; +{ + return xo_rangedel(xo, sizeof(MF), NULL, delmf); +} + + +static int +mf_title(xo) + XO *xo; +{ + MF *mf, xmf; + + mf = (MF *) xo_pool + (xo->pos - xo->top); + xmf = *mf; + + if (!(mf->mftype & (MF_FOLDER | MF_LINE))) + return XO_NONE; + + vget(b_lines, 0, "¼ÐÃD¡G", xmf.title, BTLEN + 1, GCARRY); + + if (memcmp(mf, &xmf, sizeof(MF)) && vans(msg_sure_ny) == 'y') + { + int num; + + *mf = xmf; + num = xo->pos; + rec_put(xo->dir, mf, sizeof(MF), xo->pos, NULL); + num++; + move(num - xo->top + 2, 0); + mf_item(num, mf); + } + + return XO_FOOT; +} + + +static int +mf_move(xo) + XO *xo; +{ + MF *mf; + char *dir, buf[40]; + int pos, newOrder; + + pos = xo->pos; + mf = (MF *) xo_pool + (pos - xo->top); + + sprintf(buf, "½Ð¿é¤J²Ä %d ¿ï¶µªº·s¦ì¸m¡G", pos + 1); + if (!vget(b_lines, 0, buf, buf, 5, DOECHO)) + return XO_FOOT; + + newOrder = atoi(buf) - 1; + if (newOrder < 0) + newOrder = 0; + else if (newOrder >= xo->max) + newOrder = xo->max - 1; + + if (newOrder != pos) + { + dir = xo->dir; + if (!rec_del(dir, sizeof(MF), pos, NULL)) + { + rec_ins(dir, mf, sizeof(MF), newOrder, 1); + xo->pos = newOrder; + return mf_load(xo); + } + } + + return XO_FOOT; +} + + +static int +mf_mark(xo) + XO *xo; +{ + MF *mf; + + mf = (MF *) xo_pool + (xo->pos - xo->top); + + if (mf->mftype & MF_FOLDER) + { + int num; + + mf->mftype ^= MF_MARK; + num = xo->pos; + rec_put(xo->dir, mf, sizeof(MF), num, NULL); + num++; + move(num - xo->top + 2, 0); + mf_item(num, mf); + } + + return XO_NONE; +} + + +static int +mf_browse(xo) + XO *xo; +{ + int type, bno; + char *xname, fpath[64]; + BRD *brd; + MF *mf; + + mf = (MF *) xo_pool + (xo->pos - xo->top); + type = mf->mftype; + xname = mf->xname; + + if (type & MF_BOARD) /* ¬ÝªO±¶®| */ + { + /* itoc.010726: Y¬O¬ÝªO¤w¸g³Q¬å©ÎÅv¨S¦³¤F¡A«hn²¾°£±¶®| */ + if ((bno = brd_bno(xname)) < 0 || !(brd_bits[bno] & BRD_R_BIT)) + { + //rec_del(xo->dir, sizeof(MF), xo->pos, NULL); + //vmsg("¥»¬ÝªO¤w³Q§R°£©Î±z¨S¦³Åv¾\\Ū¥»¬ÝªO¡A¨t²Î±N¦Û°Ê²¾°£±¶®|"); + vmsg ("¥»¬ÝªO¤w³Q§R°£©Î±z¨S¦³Åv¾\\Ū¥»¬ÝªO¡C"); + return mf_load(xo); + } + + brd = bshm->bcache + bno; + if(XoPost(bno)){ + return mf_load(xo); + } + xover(XZ_POST); +#ifndef ENHANCED_VISIT + time(&brd_visit[bno]); +#endif + +#ifdef AUTO_JUMPBRD + if (cuser.ufo & UFO_JUMPBRD) + mf_jumpnext = 1; /* itoc.010910: ¥u¦³¦bÂ÷¶}¬ÝªO¦^¨ì¬ÝªO¦Cªí®É¤~»Ýn¸õ¥h¤U¤@Ó¥¼Åª¬ÝªO */ +#endif + + return mf_init(xo); + } + else if (type & MF_GEM) /* ºëµØ°Ï±¶®| */ + { + /* itoc.010726: Y¬O¬ÝªO¤w¸g³Q¬å©ÎÅv¨S¦³¤F¡A«hn²¾°£±¶®| */ + if ((type = gem_link(xname)) < 0) + { + //rec_del(xo->dir, sizeof(MF), xo->pos, NULL); + //vmsg("¥»¬ÝªO¤w³Q§R°£©Î±z¨S¦³Åv¾\\Ū¥»¬ÝªO¡A¨t²Î±N¦Û°Ê²¾°£±¶®|"); + vmsg ("¥»¬ÝªO¤w³Q§R°£©Î±z¨S¦³Åv¾\\Ū¥»¬ÝªO¡C"); + return mf_load(xo); + } + + gem_fpath(fpath, xname, fn_dir); + XoGem(fpath, "ºëµØ°Ï", type); + return mf_init(xo); + } + else if (type & MF_FOLDER) /* ¸ê®Æ§¨ */ + { + mf_fpath(fpath, cuser.userid, xname); + XoMF(fpath); + return mf_load(xo); + } + + return XO_NONE; +} + + +static int +mf_copy(xo) + XO *xo; +{ + MF *mf; + + mf = (MF *) xo_pool + (xo->pos - xo->top); + + memcpy(&mftmp, mf, sizeof(MF)); + zmsg("«þ¨©§¹¦¨¡A¦ý¬O¨÷©v¤ºªº¸ê®Æ¤£·|³Q«þ¨©"); + + return XO_FOOT; +} + + +static int +mf_paste(xo) + XO *xo; +{ + MF mf; + int ans; + + if (!mftmp.chrono) + { + zmsg("½Ð¥ý°õ¦æ copy ©R¥O«á¦A paste"); + return XO_FOOT; + } + + memcpy(&mf, &mftmp, sizeof(MF)); + time(&mf.chrono); /* ³y¤@Ó·sªº chrono */ + + /* itoc.010726.µù¸Ñ: Y¬O MF_FOLDER¡A«h´«ÓÀɦW¦A¶K¤W¡A¤@Ó¨÷©v¤@ÓÀÉ®× */ + /* itoc.010726.µù¸Ñ: ¨÷©v½Æ»s¶K¤W¡A¸Ì±ªºªF¦è¨Ã¨S¦³¶K¤W¡AÃi±o¼g recursive ªºµ{¦¡ :p */ + if (mf.mftype & MF_FOLDER) + { + if (mf_stamp(&mf) < 0) + { + vmsg("¸ê®Æ¦³»~¡A½Ð«·s½Æ»s«á¦A¶K¤W"); + return XO_FOOT; + } + } + + ans = vans("¦s©ñ¦ì¸m A)·s¼W I)´¡¤J N)¤U¤@Ó Q)Â÷¶} [A] "); + switch (ans) + { + case 'q': + return XO_FOOT; + + case 'i': + case 'n': + + rec_ins(xo->dir, &mf, sizeof(MF), xo->pos + (ans == 'n'), 1); + break; + + default: + + rec_add(xo->dir, &mf, sizeof(MF)); + break; + } + + return mf_load(xo); +} + + +static int +mf_namemode(xo) + XO *xo; +{ + cuser.ufo ^= UFO_BRDPOST; + cutmp->ufo = cuser.ufo; + class_flag ^= UFO_BRDPOST; /* ©M class ¦P¨B */ + return mf_head(xo); +} + + +static int +mf_edit(xo) /* itoc.010110: §Úªº³Ì·R¤¤¬ÝªO×§ï */ + XO *xo; +{ + MF *mf; + + mf = (MF *) xo_pool + (xo->pos - xo->top); + + if ((mf->mftype & MF_BOARD) && (HAS_PERM(PERM_ALLBOARD | PERM_BM))) + { + int bno; + + bno = brd_bno(mf->xname); + if (bno >= 0) + { + if (!HAS_PERM(PERM_ALLBOARD)) + brd_title(bno); + else + brd_edit(bno); + return mf_init(xo); + } + } + return XO_NONE; +} + + +static int +mf_switch(xo) + XO *xo; +{ + Select(); + return mf_init(xo); +} + + +static int +mf_visit(xo) /* itoc.010402: ¬ÝªO¦Cªí³]©w¬ÝªO¤wŪ */ + XO *xo; +{ + int bno; + MF *mf; + + mf = (MF *) xo_pool + (xo->pos - xo->top); + bno = brd_bno(mf->xname); + + if (bno >= 0) /* itoc.010110: À³¸Ó¤£·| < 0 ? */ + { + BRD *brd; + brd = bshm->bcache + bno; + brh_get(brd->bstamp, bno); + brh_visit(0); +#ifndef ENHANCED_VISIT + time(&brd_visit[bno]); +#endif + if(xo->pos+1 < xo->max) + { + xo->pos++; + return mf_load(xo); + } + } + return mf_body(xo); +} + + +static int +mf_unvisit(xo) /* itoc.010402: ¬ÝªO¦Cªí³]©w¬ÝªO¥¼Åª */ + XO *xo; +{ + int bno; + MF *mf; + + mf = (MF *) xo_pool + (xo->pos - xo->top); + bno = brd_bno(mf->xname); + + if (bno >= 0) /* itoc.010110: À³¸Ó¤£·| < 0 ? */ + { + BRD *brd; + brd = bshm->bcache + bno; + brh_get(brd->bstamp, bno); + brh_visit(1); +#ifndef ENHANCED_VISIT + brd_visit[bno] = 0; /* itoc.010402: ³ÌªñÂsÄý®É¶¡Âk¹s¡A¨Ï¬ÝªO¦Cªí¤¤Åã¥Ü¥¼Åª */ +#endif + } + return mf_body(xo); +} + + +static int +mf_nextunread(xo) + XO *xo; +{ + int max, pos, bno; + MF *mf; + + max = xo->max; + pos = xo->pos; + mf = (MF *) xo_pool + (xo->pos - xo->top); + + while (++pos < max) + { + bno = brd_bno((++mf)->xname); + if (bno >= 0 && !(brd_bits[bno] & BRD_Z_BIT)) /* ¸õ¹L¤ÀÃþ¤Î zap ±¼ªº¬ÝªO */ + { + BRD *brd; + brd = bshm->bcache + bno; + +#ifdef ENHANCED_VISIT + /* itoc.010407: §ï¥Î³Ì«á¤@½g¤wŪ/¥¼Åª¨Ó§PÂ_ */ + brh_get(brd->bstamp, bno); + + if (brh_unread(brd->blast)) +#else + if (brd->blast > brd_visit[bno]) +#endif + return pos + XO_MOVE; + } + } + + return XO_NONE; +} + + +static int +mf_help(xo) + XO *xo; +{ + xo_help("mf"); + return mf_head(xo); +} + +static int +mf_binfo(XO* xo){ + MF* mf = (MF *) xo_pool + (xo->pos - xo->top); + int bno; + bno = brd_bno(mf->xname); + BRD *brd; + brd = bshm->bcache + bno; + do_binfo(brd); + return mf_init(xo); +} + +static KeyFunc mf_cb[] = +{ + XO_INIT, mf_init, + XO_LOAD, mf_load, + XO_HEAD, mf_head, + XO_BODY, mf_body, + + 'r', mf_browse, + 'd', mf_delete, + 'D', mf_rangedel, + 'o', mf_mark, + 'm', mf_move, + 'T', mf_title, + 'E', mf_edit, + 's', mf_switch, + 'c', mf_namemode, + 'v', mf_visit, + 'V', mf_unvisit, + '`', mf_nextunread, + 'W', mf_binfo, + + Ctrl('P'), mf_add, + 'C', mf_copy, + 'g', mf_copy, + 'p', mf_paste, + Ctrl('V'), mf_paste, + + 'h', mf_help +}; + + +void +XoMF(folder) + char *folder; +{ + XO *xo, *last; + + last = xz[XZ_MF - XO_ZONE].xo; /* record */ + + xz[XZ_MF - XO_ZONE].xo = xo = xo_new(folder); + xo->pos = 0; + +#ifdef AUTO_JUMPBRD + if (cuser.ufo & UFO_JUMPBRD) + mf_jumpnext = 1; /* itoc.020615: ¥D°Ê¸õ¥h¤U¤@Ó¥¼Åª¬ÝªO */ +#endif + xover(XZ_MF); + + free(xo); + xz[XZ_MF - XO_ZONE].xo = last; /* restore */ +} + + +int +MyFavorite() +{ + char fpath[64]; + + mftmp.chrono = 0; /* ªì©l¤Æ */ + mf_fpath(fpath, cuser.userid, FN_MF); + XoMF(fpath); + + return 0; +} + + +void +mf_main() +{ + char fpath[64]; + XO *xo; + + mf_fpath(fpath, cuser.userid, FN_MF); + xz[XZ_MF - XO_ZONE].xo = xo = xo_new(fpath); + xz[XZ_MF - XO_ZONE].cb = mf_cb; + + xo->pos = 0; +} +#endif /* MY_FAVORITE */ diff --git a/maple/gem.c b/maple/gem.c new file mode 100644 index 0000000..b02bdd4 --- /dev/null +++ b/maple/gem.c @@ -0,0 +1,1472 @@ +/*-------------------------------------------------------*/ +/* gem.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : ºëµØ°Ï¾\Ū¡B½s¿ï */ +/* create : 95/03/29 */ +/* update : 97/02/02 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +extern XZ xz[]; +extern char xo_pool[]; +extern char brd_bits[]; + +extern int TagNum; +extern TagItem TagList[]; + + +#define GEM_WAY 3 +static int gem_way; /* 0:¥u¦L¼ÐÃD 1:¼ÐÃD¥[ÀɦW 2:¼ÐÃD¥[½sªÌ */ + +static int GemBufferNum; /* Thor.990414: ´£«e«Å§i¡A¥Î©ógem_head */ + +static char GemAnchor[64]; /* ©wÁã°Ïªº¸ô®| */ +static char GemSailor[20]; /* ©wÁã°Ïªº¼ÐÃD */ + +static int gem_add_all(); +static int gem_paste(); +static int gem_anchor(); + + +static void +gem_item(num, hdr, level) + int num; + HDR *hdr; + int level; +{ + int xmode, gtype; + + /* ¡·¡¸¡¹¡º¡»¡¼¡½¡¾¡¿ : A1B7 ... */ + + xmode = hdr->xmode; + gtype = (char) 0xba; + + /* ¥Ø¿ý¥Î¹ê¤ß¡A¤£¬O¥Ø¿ý¥ÎªÅ¤ß */ + if (xmode & GEM_FOLDER) /* ¤å³¹:¡º ¨÷©v:¡» */ + gtype += 1; + + if (hdr->xname[0] == '@') /* ¸ê®Æ:¡¸ ¤ÀÃþ:¡¹ */ + gtype -= 2; + else if (xmode & GEM_BOARD) /* ¬ÝªO:¡½ */ + gtype += 2; + + prints("%6d%c%c\241%c ", num, xmode & GEM_RESTRICT ? ')' : ' ', + TagNum && !Tagger(hdr->chrono, num - 1, TAG_NIN) ? '*' : ' ', gtype); + + if ((xmode & GEM_RESTRICT) && !(level & GEM_M_BIT)) + outs(MSG_DATA_CLOAK); /* itoc.000319: ¨î¯Å¤å³¹«O±K */ + else if (gem_way == 0) + prints("%.*s\n", d_cols + 64, hdr->title); + else + prints("%-*.*s%-13s%s\n", d_cols + 46, d_cols + 45, hdr->title, (gem_way == 1 ? hdr->xname : hdr->owner), hdr->date); +} + + +static int +gem_body(xo) + XO *xo; +{ + HDR *hdr; + int num, max, tail; + + max = xo->max; + if (max <= 0) + { + outs("\n\n¡mºëµØ°Ï¡n©|¦b§l¨ú¤Ñ¦a¶¡ªº¤éºë¤ëµØ :)"); + + if (xo->key & GEM_W_BIT) + { + switch (vans("(A)·s¼W¸ê®Æ (P)¶K½Æ (G)®üÁã¥\\¯à [N]µL©Ò¨Æ¨Æ ")) + { + case 'a': + max = gem_add_all(xo); + if (xo->max > 0) + return max; + break; + + case 'p': + max = gem_paste(xo); + if (xo->max > 0) + return max; + break; + + case 'g': + gem_anchor(xo); + break; + } + } + else + { + vmsg(NULL); + } + return XO_QUIT; + } + + hdr = (HDR *) xo_pool; + num = xo->top; + tail = num + XO_TALL; + if (max > tail) + max = tail; + + move(3, 0); + tail = xo->key; /* ɥΠtail */ + do + { + gem_item(++num, hdr++, tail); + } while (num < max); + clrtobot(); + + /* return XO_NONE; */ + return XO_FOOT; /* itoc.010403: §â b_lines ¶ñ¤W feeter */ +} + + +static int +gem_head(xo) + XO *xo; +{ + char buf[20]; + + vs_head("ºëµØ¤å³¹", xo->xyz); + + if ((xo->key & GEM_W_BIT) && GemBufferNum > 0) + sprintf(buf, "(°Å¶Kï %d ½g)", GemBufferNum); + else + buf[0] = '\0'; + + prints(NECKER_GEM, buf, d_cols, ""); + return gem_body(xo); +} + + +static int +gem_toggle(xo) + XO *xo; +{ + gem_way++; + gem_way %= GEM_WAY; + + /* ¥u¦³¯¸ªø¯à¬Ý¨ìÀɦW */ + /* lantw44: ªO¥D´N¥i¥H¬ÝÀɦW¤F */ + if (!(xo->key & GEM_M_BIT) && gem_way == 1) + gem_way++; + + return gem_body(xo); +} + + +static int +gem_init(xo) + XO *xo; +{ + xo_load(xo, sizeof(HDR)); + return gem_head(xo); +} + + +static int +gem_load(xo) + XO *xo; +{ + xo_load(xo, sizeof(HDR)); + return gem_body(xo); +} + + +/* ----------------------------------------------------- */ +/* gem_check : attribute check out */ +/* ----------------------------------------------------- */ + + +#define GEM_PLAIN 0x01 /* ¹w´Á¬O plain text */ + + +static HDR * /* NULL:µLÅvŪ¨ú */ +gem_check(xo, fpath, op) + XO *xo; + char *fpath; + int op; +{ + HDR *hdr; + int gtype; + + hdr = (HDR *) xo_pool + (xo->pos - xo->top); + gtype = hdr->xmode; + + if ((gtype & GEM_RESTRICT) && !(xo->key & GEM_M_BIT)) + return NULL; + + if (op && (gtype & GEM_LINE)) + return NULL; + + if ((op & GEM_PLAIN) && (gtype & GEM_FOLDER)) + return NULL; + + if (fpath) + { + if (gtype & GEM_BOARD) + gem_fpath(fpath, hdr->xname, fn_dir); + else + hdr_fpath(fpath, xo->dir, hdr); + } + return hdr; +} + + +#if 0 +static int /* -1:¤£¬O¬ÝªOºëµØ°Ï >=0:bno */ +gem_bno(xo) + XO *xo; +{ + char *dir, *str; + int bno; + + /* ¥Ñ xo->dir §ä¥X¥Ø«e¦bþ¤@ÓªOªººëµØ°Ï */ + dir = xo->dir; + + /* Àˬd¬O§_¬° gem/brd/brdname/.DIR ªº®æ¦¡¡A + Á×§KY¦b gem/.DIR ©Î usr/u/userid/gem/.DIR ·|³y¦¨¿ù»~ */ + if (dir[0] == 'g' && dir[4] == 'b') + { + dir += 8; /* ¸õ¹L "gem/brd/" */ + if (str = strchr(dir, '/')) + { + *str = '\0'; + bno = brd_bno(dir); + *str = '/'; + return bno; + } + } + + return -1; +} +#endif + + +/* ----------------------------------------------------- */ +/* ¸ê®Æ¤§·s¼W¡Gappend / insert */ +/* ----------------------------------------------------- */ + + +void +brd2gem(brd, gem) + BRD *brd; + HDR *gem; +{ + memset(gem, 0, sizeof(HDR)); + time(&gem->chrono); + str_stamp(gem->date, &gem->chrono); + strcpy(gem->xname, brd->brdname); + sprintf(gem->title, "%-13s%-5s%s", brd->brdname, brd->class, brd->title); + gem->xmode = GEM_BOARD | GEM_FOLDER; +} + + +#if 0 /* itoc.010218: ´«·sªº gem_log() */ +static void +gem_log(folder, action, hdr) + char *folder; + char *action; + HDR *hdr; +{ + char fpath[64], buf[256]; + + if (hdr->xmode & (GEM_RESTRICT | GEM_RESERVED)) + return; + + str_folder(fpath, folder, "@/@log"); + sprintf(buf, "[%s] %s (%s) %s\n%s\n\n", + action, hdr->xname, Now(), cuser.userid, hdr->title); + f_cat(fpath, buf); +} +#endif + + +static void +gem_log(folder, action, hdr) + char *folder; + char *action; + HDR *hdr; +{ + char fpath1[64], fpath2[64]; + FILE *fp1, *fp2; + + if (hdr->xmode & (GEM_RESTRICT | GEM_RESERVED)) + return; + + /* mv @log @log.old */ + str_folder(fpath1, folder, "@/@log"); + str_folder(fpath2, folder, "@/@log.old"); + f_mv(fpath1, fpath2); + + if (!(fp1 = fopen(fpath1, "a"))) + return; + + /* §â·sªº²§°Ê©ñ¦b³Ì¤W±¡A¨Ã¨Ì²§°Ê¶¶§Ç½s¸¹ */ + + fprintf(fp1, "<01> %s %-12s [%s] %s\n %s\n\n", Now(), + cuser.userid, action, hdr->xname, hdr->title); + + if (fp2 = fopen(fpath2, "r")) + { + char buf[STRLEN]; + int i = 6; /* ±q²Ä¤G½g¶}©l */ + int j; + + while (fgets(buf, STRLEN, fp2)) + { + if (++i > 63) /* ¥u«O¯d³Ì·s 20 µ§²§°Ê */ + break; + + j = i % 3; + if (j == 1) /* ²Ä¤@¦æ */ + fprintf(fp1, "<%02d> %s", i / 3, buf + 5); + else if (j == 2) /* ²Ä¤G¦æ */ + fprintf(fp1, "%s\n", buf); + /* ²Ä¤T¦æ¬OªÅ¦æ */ + } + fclose(fp2); + } + fclose(fp1); +} + + +static int +gem_add(xo, gtype) + XO *xo; + int gtype; +{ + int level, fd, ans; + char title[80], fpath[64], *dir; + HDR hdr; + + level = xo->key; + if (!(level & GEM_W_BIT)) + return XO_NONE; + + if (!gtype) + { + gtype = vans((level & GEM_X_BIT) ? + /* "·s¼W A)rticle B)oard C)lass D)ata F)older P)aste Q)uit [Q] " : */ + "·s¼W (A)¤å³¹ (B)¬ÝªO (C)¤ÀÃþ (D)¸ê®Æ (F)¨÷©v (L)¤À¹j (P)¶K½Æ (Q)¨ú®ø¡H[Q] " : + "·s¼W (A)¤å³¹ (F)¨÷©v (L)¤À¹j (P)¶K½Æ (Q)¨ú®ø¡H[Q] "); + } + + if (gtype == 'p') + return gem_paste(xo); + + if (gtype != 'a' && gtype != 'f' && gtype != 'l' && + (!(level & GEM_X_BIT) || (gtype != 'b' && gtype != 'c' && gtype != 'd'))) + return XO_FOOT; + + dir = xo->dir; + fd = -1; + + if (gtype == 'b') + { + BRD *brd; + + if (!(brd = ask_board(fpath, BRD_L_BIT, NULL))) + return gem_head(xo); + + brd2gem(brd, &hdr); + gtype = 0; + } + else + { + if (!vget(b_lines, 0, "¼ÐÃD¡G", title, TTLEN + 1, DOECHO)) + return XO_FOOT; + + if (gtype == 'c' || gtype == 'd') + { + if (!vget(b_lines, 0, "ÀɦW¡G", fpath, BNLEN + 1, DOECHO)) + return XO_FOOT; + + if (strchr(fpath, '/')) + { + zmsg("¤£¦XªkªºÀɮצWºÙ"); + /* return XO_NONE; */ + return XO_FOOT; /* itoc.010726: §â b_lines ¶ñ¤W feeter */ + } + + memset(&hdr, 0, sizeof(HDR)); + time(&hdr.chrono); + str_stamp(hdr.date, &hdr.chrono); + sprintf(hdr.xname, "@%s", fpath); + if (gtype == 'c') + { + strcat(fpath, "/"); + sprintf(hdr.title, "%-13s¤ÀÃþ ¡¼ %.50s", fpath, title); + hdr.xmode = GEM_FOLDER; + } + else + { + strcpy(hdr.title, title); + hdr.xmode = 0; + } + gtype = 1; + } + else + { + if ((fd = hdr_stamp(dir, gtype, &hdr, fpath)) < 0) + return XO_FOOT; + close(fd); + + if (gtype == 'a') + { + if (vedit(fpath, 0)) /* Thor.981020: ª`·N³Qtalkªº°ÝÃD */ + { + unlink(fpath); + zmsg(msg_cancel); + return gem_head(xo); + } + gtype = 0; + } + else if (gtype == 'f') + { + gtype = GEM_FOLDER; + } + else if (gtype == 'l') + { + gtype = GEM_LINE; + } + hdr.xmode = gtype; + strcpy(hdr.title, title); + } + } + + /* ans = vans("¦s©ñ¦ì¸m A)ppend I)nsert N)ext Q)uit [A] "); */ + ans = vans("¦s©ñ¦ì¸m A)¥[¨ì³Ì«á I/N)´¡¤J¥Ø«e¦ì¸m Q)Â÷¶} [A] "); + + if (ans == 'q') + { + if (fd >= 0) + unlink(fpath); + return (gtype ? XO_FOOT : gem_head(xo)); + } + + strcpy(hdr.owner, cuser.userid); + + if (vans("¬O§_¶i¦æ¥[±K(Y/N)¡H[N] ") == 'y') + hdr.xmode ^= GEM_RESTRICT; + + if (ans == 'i' || ans == 'n') + rec_ins(dir, &hdr, sizeof(HDR), xo->pos + (ans == 'n'), 1); + else + rec_add(dir, &hdr, sizeof(HDR)); + + if (!(hdr.xmode & GEM_RESTRICT)) + gem_log(dir, "·s¼W", &hdr); + + return (gtype ? gem_load(xo) : gem_init(xo)); +} + + +static int +gem_add_all(xo) + XO *xo; +{ + return gem_add(xo, 0); +} + + +static int +gem_add_article(xo) /* itoc.010419: §Ö³tÁä */ + XO *xo; +{ + return gem_add(xo, 'a'); +} + + +static int +gem_add_folder(xo) /* itoc.010419: §Ö³tÁä */ + XO *xo; +{ + return gem_add(xo, 'f'); +} + + +/* ----------------------------------------------------- */ +/* ¸ê®Æ¤§×§ï¡Gedit / title */ +/* ----------------------------------------------------- */ + + +static int +gem_edit(xo) + XO *xo; +{ + int level; + char fpath[64]; + HDR *hdr; + + if (!(hdr = gem_check(xo, fpath, GEM_PLAIN))) + return XO_NONE; + + level = xo->key; + + if (!(level & GEM_W_BIT) || ((hdr->xmode & GEM_RESERVED) && !(level & GEM_X_BIT))) + { + vedit(fpath, -1); + } + else + { + if (vedit(fpath, 0) >= 0) + gem_log(xo->dir, "×§ï", hdr); + } + + return gem_head(xo); +} + + +static int +gem_title(xo) + XO *xo; +{ + HDR *fhdr, mhdr; + int pos, cur; + + if (!(xo->key & GEM_W_BIT) || !(fhdr = gem_check(xo, NULL, 0))) + return XO_NONE; + + memcpy(&mhdr, fhdr, sizeof(HDR)); + + vget(b_lines, 0, "¼ÐÃD¡G", mhdr.title, TTLEN + 1, GCARRY); + + if (xo->key & GEM_X_BIT) + { + vget(b_lines, 0, "½sªÌ¡G", mhdr.owner, IDLEN + 1, GCARRY); + /* vget(b_lines, 0, "¼ÊºÙ¡G", mhdr.nick, sizeof(mhdr.nick), GCARRY); */ /* ºëµØ°Ï¦¹Äæ¦ì¬°ªÅ */ + vget(b_lines, 0, "¤é´Á¡G", mhdr.date, sizeof(mhdr.date), GCARRY); + } + + if (memcmp(fhdr, &mhdr, sizeof(HDR)) && vans(msg_sure_ny) == 'y') + { + pos = xo->pos; + cur = pos - xo->top; + + memcpy(fhdr, &mhdr, sizeof(HDR)); + rec_put(xo->dir, fhdr, sizeof(HDR), pos, NULL); + + move(3 + cur, 0); + gem_item(++pos, fhdr, xo->key); + + gem_log(xo->dir, "¼ÐÃD", fhdr); + } + return XO_FOOT; +} + + +static int +gem_refuse(xo) + XO *xo; +{ + HDR *hdr; + int num; + + if ((xo->key & GEM_M_BIT) && (hdr = gem_check(xo, NULL, 0))) + { + hdr->xmode ^= GEM_RESTRICT; + + num = xo->pos; + rec_put(xo->dir, hdr, sizeof(HDR), num, NULL); + num++; + move(num - xo->top + 2, 0); + gem_item(num, hdr, xo->key); + } + + return XO_NONE; +} + + +static int +gem_state(xo) + XO *xo; +{ + HDR *hdr; + char fpath[64]; + struct stat st; + + if ((xo->key & GEM_W_BIT) && (hdr = gem_check(xo, fpath, 0))) + { + move(12, 0); + clrtobot(); + prints("\nDir : %s", xo->dir); + prints("\nName: %s", hdr->xname); + prints("\nFile: %s", fpath); + + if (!stat(fpath, &st)) + { + prints("\nTime: %s", Btime(&st.st_mtime)); + prints("\nSize: %d", st.st_size); + } + + vmsg(NULL); + return gem_body(xo); + } + + return XO_NONE; +} + + +/* ----------------------------------------------------- */ +/* ¸ê®Æ¤§ÂsÄý¡Gedit / title */ +/* ----------------------------------------------------- */ + + +int /* -1:µLÅv */ +gem_link(brdname) /* Àˬd³sµ²¥h¨ä¥L¬ÝªOºëµØ°ÏªºÅv */ + char *brdname; +{ + int bno, level; + + if ((bno = brd_bno(brdname)) < 0 || !((bno = brd_bits[bno]) & BRD_R_BIT)) + return -1; + + level = 0; + if (bno & BRD_X_BIT) + level ^= GEM_W_BIT; + if (HAS_PERM(PERM_SYSOP)) + level ^= GEM_X_BIT; + if (bno & BRD_M_BIT) + level ^= GEM_M_BIT; + + return level; +} + + +static int +gem_browse(xo) + XO *xo; +{ + HDR *hdr; + int op, xmode; + char fpath[64], title[TTLEN + 1], *ptr; + + op = 0; + + for (;;) + { + if (!(hdr = gem_check(xo, fpath, op))) + break; + + xmode = hdr->xmode; + + /* browse folder */ + + if (xmode & GEM_FOLDER) + { + strcpy(title, hdr->title); + + if (xmode & GEM_BOARD) + { + if ((op = gem_link(hdr->xname)) < 0) + { + vmsg("¹ï¤£°_¡A¦¹ªOºëµØ°Ï¥uãªO¤Í¶i¤J¡A½Ð¦VªO¥D¥Ó½Ð¤J¹Ò³\\¥i"); + return XO_FOOT; + } + } + else /* ¤@¯ë¨÷©v¤~¦³¤pªO¥D */ + { + op = xo->key; /* Ä~©Ó¥À¨÷©vªºÅv */ + + /* itoc.011217: [userA/userB ªº¦h¦ì¤pªO¥D¼Ò¦¡¤]¾A¥Î */ + if ((ptr = strrchr(title, '[')) && is_bm(ptr + 1, cuser.userid)) + op |= GEM_W_BIT | GEM_M_BIT; + } + + XoGem(fpath, title, op); + return gem_init(xo); + } + + /* browse article */ + + /* Thor.990204: ¬°¦Ò¼{more ¶Ç¦^È */ + if ((xmode = more(fpath, FOOTER_GEM)) < 0) + break; + + op = GEM_PLAIN; + +re_key: + switch (xo_getch(xo, xmode)) + { + case XO_BODY: + continue; + + case '/': + if (vget(b_lines, 0, "·j´M¡G", hunt, sizeof(hunt), DOECHO)) + { + more(fpath, FOOTER_GEM); + goto re_key; + } + continue; + + case 'E': + return gem_edit(xo); + + case 'C': + { + FILE *fp; + if (fp = tbf_open()) + { + f_suck(fp, fpath); + fclose(fp); + } + } + break; + + case 'h': + xo_help("gem"); + break; + } + break; + } + + return gem_head(xo); +} + + +/* ----------------------------------------------------- */ +/* ºëµØ°Ï¤§§R°£ */ +/* ----------------------------------------------------- */ + + +static int +chkgem(hdr) + HDR *hdr; +{ + return (hdr->xmode & (GEM_RESTRICT | GEM_RESERVED)); +} + + +static int +vfygem(hdr, pos) + HDR *hdr; + int pos; +{ + return (Tagger(hdr->chrono, pos, TAG_NIN) || chkgem(hdr)); +} + + +static void +delgem(xo, hdr) + XO *xo; + HDR *hdr; +{ + char folder[64]; + HDR fhdr; + FILE *fp; + + if (hdr->xmode & GEM_FOLDER) /* ¨÷©v/¤ÀÃþ/¬ÝªO */ + { + hdr_fpath(folder, xo->dir, hdr); + + /* Kyo.050328: ©wÁã°Ï³Q§R°£®Én©ÞÁã */ + if (!strcmp(GemAnchor, folder)) + GemAnchor[0] = '\0'; + + /* ¨÷©vn¶i¤l¥Ø¿ý§R°£¡F¬ÝªO/¤ÀÃþ«h¤£»Ýn */ + if (hdr->xmode == GEM_FOLDER && hdr->xname[0] != '@') + { + if (fp = fopen(folder, "r")) + { + while (fread(&fhdr, sizeof(HDR), 1, fp) == 1) + delgem(xo, &fhdr); + + fclose(fp); + unlink(folder); + } + } + } + else /* ¤å³¹/¸ê®Æ */ + { + /* ¤å³¹n§R°£ÀɮסF¸ê®Æ«h¤£§R°£ÀÉ®× */ + if (hdr->xname[0] != '@') + { + hdr_fpath(folder, xo->dir, hdr); + unlink(folder); + } + } +} + + +static int +gem_delete(xo) + XO *xo; +{ + HDR *hdr; + int xmode; + + if (!(xo->key & GEM_W_BIT) || !gem_check(xo, NULL, 0)) + return XO_NONE; + + hdr = (HDR *) xo_pool + (xo->pos - xo->top); + xmode = hdr->xmode; + + if (hdr->xmode & (GEM_RESTRICT | GEM_RESERVED)) + return XO_NONE; + + if (vans(msg_del_ny) == 'y') + { + delgem(xo, hdr); + + if (!rec_del(xo->dir, sizeof(HDR), xo->pos, NULL)) + { + gem_log(xo->dir, "§R°£", hdr); + return gem_load(xo); + } + } + + return XO_FOOT; +} + + +static int +gem_rangedel(xo) /* itoc.010726: ´£¨Ñ°Ï¬q§R°£ */ + XO *xo; +{ + if (!(xo->key & GEM_W_BIT) || !gem_check(xo, NULL, 0)) + return XO_NONE; + + return xo_rangedel(xo, sizeof(HDR), chkgem, delgem); +} + + +static int +gem_prune(xo) + XO *xo; +{ + if (!(xo->key & GEM_W_BIT)) + return XO_NONE; + return xo_prune(xo, sizeof(HDR), vfygem, delgem); +} + + +/* ----------------------------------------------------- */ +/* ºëµØ°Ï¤§½Æ»s¡B¶K¤W¡B²¾°Ê */ +/* ----------------------------------------------------- */ + + +static char GemFolder[64]; + +static HDR *GemBuffer; +static int GemBufferSiz; +/* static int GemBufferNum; */ /* Thor.990414: ´£«e«Å§iµ¹gem_head¥Î */ + + +/* °t¸m¨¬°÷ªºªÅ¶¡©ñ¤J header */ + + +static HDR * +gbuf_malloc(num) + int num; +{ + HDR *gbuf; + + GemBufferNum = num; + if (gbuf = GemBuffer) + { + if (GemBufferSiz < num) + { + num += (num >> 1); + GemBufferSiz = num; + GemBuffer = gbuf = (HDR *) realloc(gbuf, sizeof(HDR) * num); + } + } + else + { + GemBufferSiz = num; + GemBuffer = gbuf = (HDR *) malloc(sizeof(HDR) * num); + } + + return gbuf; +} + + +/* static */ /* itoc.010924: µ¹ post_copy() ¥Î */ +void +gem_buffer(dir, hdr) + char *dir; + HDR *hdr; /* NULL ¥Nªí©ñ¤J TagList, §_«h±N¶Ç¤Jªº©ñ¤J */ +{ + int num, locus; + HDR *gbuf; + + if (hdr) + { + num = 1; + } + else + { + num = TagNum; + if (num <= 0) + return; + } + + gbuf = gbuf_malloc(num); + + if (hdr) + { + memcpy(gbuf, hdr, sizeof(HDR)); + } + else + { + locus = 0; + do + { + EnumTag(&gbuf[locus], dir, locus, sizeof(HDR)); + } while (++locus < num); + } + + strcpy(GemFolder, dir); +} + + +static int +gem_copy(xo) + XO *xo; +{ + HDR *hdr; + int tag; + + if (!(hdr = gem_check(xo, NULL, 0))) + return XO_NONE; + + tag = AskTag("ºëµØ°Ï«þ¨©"); + + if (tag < 0) + return XO_FOOT; + + gem_buffer(xo->dir, tag ? NULL : hdr); + + zmsg("«þ¨©§¹¦¨¡A¦ý¬O¥[±K¤å³¹¤£·|³Q«þ¨©¡C[ª`·N] ¶K¤W«á¤~¯à§R°£ì¤å¡I"); + + /* return XO_FOOT; */ + return gem_head(xo); /* Thor.990414: Åý°Å¶K½g¼Æ§ó·s */ +} + + +static inline int +gem_extend(xo, num) + XO *xo; + int num; +{ + char *dir, fpath[64], gpath[64]; + FILE *fp; + time_t chrono; + HDR *hdr; + + if (!(hdr = gem_check(xo, fpath, GEM_PLAIN))) + return -1; + + if (!(fp = fopen(fpath, "a"))) + return -1; + + dir = xo->dir; + chrono = hdr->chrono; + + for (hdr = GemBuffer; num--; hdr++) + { + if ((hdr->chrono != chrono) && !(hdr->xmode & (GEM_FOLDER | GEM_RESTRICT | GEM_RESERVED))) + { + hdr_fpath(gpath, GemFolder, hdr); /* itoc.010924: ×¥¿¤£¦P¥Ø¿ý·| extend ¥¢±Ñ */ + fputs(str_line, fp); + f_suck(fp, gpath); + } + } + + fclose(fp); + return 0; +} + + +static int /* 1: µL½a°j°é 0: ¦Xªk */ +invalid_loop(srcDir, dstDir, hdr, depth) /* itoc.010727: Àˬd¬O§_·|³y¦¨µL½a°j°é for gem_paste() */ + char *srcDir, *dstDir; + HDR *hdr; + int depth; /* 0: »¼°j²Ä¤@°é 1: »¼°j¤¤ */ +{ + static int valid; + + int fd; + char fpath1[64], fpath2[64]; + HDR fhdr; + + if (!depth) + { + if (!(hdr->xmode & GEM_FOLDER)) /* plain text */ + return 0; + + str_folder(fpath1, srcDir, fn_dir); + str_folder(fpath2, dstDir, fn_dir); + + if (strcmp(fpath1, fpath2)) /* ¸ó°Ï«þ¨©¤@©w¤£·|³y¦¨µL½a°j°é */ + return 0; + + hdr_fpath(fpath1, srcDir, hdr); /* §â¦Û¤v«þ¨ì¦Û¤v¸Ì± */ + if (!strcmp(fpath1, dstDir)) + return 1; + + valid = 0; + } + else + { + if (valid) /* ¦b¬Y¤@Ó»¼°j¤¤§ä¨ì«DªkÃÒ¾Ú´N°±¤î·jÃÒ¤u§@ */ + return 1; + + hdr_fpath(fpath1, srcDir, hdr); + } + + if ((fd = open(fpath1, O_RDONLY)) >= 0) + { + while (read(fd, &fhdr, sizeof(HDR)) == sizeof(HDR)) + { + if (fhdr.xmode & GEM_FOLDER) /* plain text ¤£·|³y¦¨µL½a°j°é */ + { + hdr_fpath(fpath2, srcDir, &fhdr); + if (!strcmp(fpath2, dstDir)) + { + valid = 1; + return 1; + } + + /* recursive ¦a¤@¼h¤@¼h¥Ø¿ý¶i¥hÀˬd¬O§_·|³y¦¨µL½a°j°é */ + invalid_loop(fpath1, dstDir, &fhdr, 1); + } + } + close(fd); + } + + return valid; +} + + +static void +gem_do_paste(srcDir, dstDir, hdr, pos) /* itoc.010725: for gem_paste() */ + char *srcDir; /* source folder */ + char *dstDir; /* destination folder */ + HDR *hdr; /* source hdr */ + int pos; /* -1: ªþ¥[¦b³Ì«á >=0: ¶K¤Wªº¦ì¸m */ +{ + int xmode, fsize; + char folder[64], fpath[64]; + HDR fhdr, *data, *head, *tail; + + xmode = hdr->xmode; + + if (xmode & (GEM_RESTRICT | GEM_RESERVED)) /* ¨î¯ÅºëµØ°Ï¤£¯à½Æ»s/¶K¤W */ + return; + + if (xmode & GEM_BOARD) /* ¬ÝªO¤£¯à³Q½Æ»s/¶K¤W */ + return; + + if (xmode & GEM_FOLDER) /* ¨÷©v/¤ÀÃþ */ + { + /* ¥ý·sÀɫإߦۤv³oÓ¤ÀÃþ/¨÷©v */ + + /* ¦b½Æ»s/¶K¤W«á¤@«ßÅܦ¨¨÷©v¡A¦]¬°¤ÀÃþ¬O¯¸ªø±M¥Î¯S®í¥Î³~ªº */ + if ((fsize = hdr_stamp(dstDir, 'F', &fhdr, fpath)) < 0) + return; + close(fsize); + + fhdr.xmode = GEM_FOLDER; + } + else /* ¤å³¹/¸ê®Æ */ + { + hdr_fpath(folder, srcDir, hdr); + + /* ¦b½Æ»s/¶K¤W«á¤@«ßÅܦ¨¤å³¹¡A¦]¬°¸ê®Æ¬O¯¸ªø±M¥Î¯S®í¥Î³~ªº */ + hdr_stamp(dstDir, HDR_COPY | 'A', &fhdr, folder); + } + + strcpy(fhdr.owner, cuser.userid); + strcpy(fhdr.title, hdr->title); + if (pos < 0) + rec_add(dstDir, &fhdr, sizeof(HDR)); + else + rec_ins(dstDir, &fhdr, sizeof(HDR), pos, 1); + gem_log(dstDir, "½Æ»s", &fhdr); + + if (xmode & GEM_FOLDER) /* ¨÷©v/¤ÀÃþ */ + { + /* «Ø¥ß§¹¦Û¤v³oÓ¨÷©v/¤ÀÃþ¥H«á¡A¦A recursive ¦a¤@¼h¤@¼h¥Ø¿ý¶i¥h¤@½g¤@½g¥t¦s·sÀÉ */ + hdr_fpath(folder, srcDir, hdr); + if (data = (HDR *) f_img(folder, &fsize)) + { + head = data; + tail = data + (fsize / sizeof(HDR)); + do + { + gem_do_paste(folder, fpath, head, -1); + } while (++head < tail); + + free(data); + } + } +} + + +static int +gem_paste(xo) + XO *xo; +{ + int num, ans, pos; + char *dir; + HDR *head, *tail; + + if (!(xo->key & GEM_W_BIT)) + return XO_NONE; + + if (!(num = GemBufferNum)) + { + zmsg("½Ð¥ý°õ¦æ copy ©R¥O«á¦A paste"); + /* return XO_NONE; */ + return XO_FOOT; /* itoc.010726: §â b_lines ¶ñ¤W feeter */ + } + + dir = xo->dir; + + /* switch (ans = vans("¦s©ñ¦ì¸m A)ppend I)nsert N)ext E)xtend Q)uit [A] ")) */ + switch (ans = vans("¦s©ñ¦ì¸m A)¥[¨ì³Ì«á I/N)´¡¤J¥Ø«e¦ì¸m E)ªþ¥[ÀÉ®× Q)Â÷¶} [A] ")) + { + case 'q': + return XO_FOOT; + + case 'e': + if (gem_extend(xo, num)) + zmsg("[Extend Àɮתþ¥[] °Ê§@¨Ã¥¼§¹¥þ¦¨¥\\"); + return XO_FOOT; + + default: + pos = (ans == 'n') ? xo->pos + 1 : (ans == 'i') ? xo->pos : -1; + + head = GemBuffer; + tail = head + num; + do + { + if (invalid_loop(GemFolder, dir, head, 0)) /* itoc.010727: ³y¦¨°j°éªÌ¤£¤¹³\¶K¤W */ + { + vmsg("³y¦¨°j°éªº¨÷©v±NµLªk¦¬¿ý"); + continue; + } + else + { + gem_do_paste(GemFolder, dir, head, pos); + if (pos >= 0) /* Insert/Next:nÄ~Äò©¹¤U¶K Append:¤@ª½¶K¦b³Ì«á */ + pos++; + } + } while (++head < tail); + } + + return gem_load(xo); +} + + +static int +gem_move(xo) + XO *xo; +{ + HDR *hdr; + char *dir, buf[40]; + int pos, newOrder; + + if (!(xo->key & GEM_W_BIT) || !(hdr = gem_check(xo, NULL, 0))) + return XO_NONE; + + pos = xo->pos; + sprintf(buf, "½Ð¿é¤J²Ä %d ¿ï¶µªº·s¦ì¸m¡G", pos + 1); + if (!vget(b_lines, 0, buf, buf, 5, DOECHO)) + return XO_FOOT; + + newOrder = atoi(buf) - 1; + if (newOrder < 0) + newOrder = 0; + else if (newOrder >= xo->max) + newOrder = xo->max - 1; + + if (newOrder != pos) + { + dir = xo->dir; + if (!rec_del(dir, sizeof(HDR), pos, NULL)) + { + rec_ins(dir, hdr, sizeof(HDR), newOrder, 1); + xo->pos = newOrder; + return gem_load(xo); + } + } + return XO_FOOT; +} + + +static int +gem_anchor(xo) + XO *xo; +{ + int ans; + char *folder; + + if (!(xo->key & GEM_W_BIT)) /* Thor.981020: ¥unªO¥D¥H¤W§Y¥i¨Ï¥Îanchor */ + return XO_NONE; /* Thor.981020: ¤£¶}©ñ¤@¯ë user ¨Ï¥Î¬O¬°¤F¨¾¤îªO¥D¸Õ¥X¥t¤@Ó¤p bug :P */ + + ans = vans("ºëµØ°Ï A)©wÁã D)©ÞÁã J)´N¦ì Q)¨ú®ø [A] "); + if (ans != 'q') + { + folder = GemAnchor; + + if (ans == 'j') + { + if (!*folder) /* ¨S¦³©wÁã */ + return XO_FOOT; + + XoGem(folder, "¡´ ºëµØ©wÁã°Ï ¡´", xo->key); + return gem_init(xo); + } + else if (ans == 'd') + { + *folder = '\0'; + } + else + { + strcpy(folder, xo->dir); + str_ncpy(GemSailor, xo->xyz, sizeof(GemSailor)); + } + + zmsg("Áã°Ê§@§¹¦¨"); + } + + /* return XO_NONE; */ + return XO_FOOT; /* itoc.010726: §â b_lines ¶ñ¤W feeter */ +} + + +int +gem_gather(xo) + XO *xo; +{ + HDR *hdr, *gbuf, ghdr, xhdr; + int tag, locus, index, rc, xmode; + char *dir, *folder, fpath[80]; + FILE *fp; + + folder = GemAnchor; + + if (!*folder) + { + zmsg("½Ð¥ý©wÁã¥H«á¦Aª½±µ¦¬¿ý¦Ü©wÁã°Ï"); + return XO_FOOT; + } + + sprintf(fpath, "¦¬¿ý¦Ü©wÁã°Ï (%s)", GemSailor); + tag = AskTag(fpath); + + if (tag < 0) + return XO_FOOT; + + fp = NULL; + + if (tag > 0) + { + switch (vans("¦ê¦C¤å³¹ 1)¦X¦¨¤@½g 2)¤À§O«ØÀÉ Q)¨ú®ø [1] ")) + { + case 'q': + return XO_FOOT; + + case '2': + break; + + default: + strcpy(xhdr.title, currtitle); + if (!vget(b_lines, 0, "¼ÐÃD¡G", xhdr.title, TTLEN + 1, GCARRY)) + return XO_FOOT; + fp = fdopen(hdr_stamp(folder, 'A', &ghdr, fpath), "w"); + strcpy(ghdr.owner, cuser.userid); + strcpy(ghdr.title, xhdr.title); + } + } + + dir = xo->dir; + hdr = tag ? &xhdr : (HDR *) xo_pool + xo->pos - xo->top; + rc = (*dir == 'g') ? XO_NONE : XO_FOOT; + + /* gather µø¦P copy¡A¥i·Ç³Æ§@ paste */ + + strcpy(GemFolder, folder); + gbuf = gbuf_malloc((fp != NULL || tag == 0) ? 1 : tag); + + /* itoc.010727.µù¸Ñ: Y¦X¦¨¤@½g©Î¥u¦¬¿ý¤@½g¡A«h GemBufferNum = 1¡A¤Ï¤§¬O tag ¼Æ¶q */ + + index = 0; + locus = 0; + + do + { + if (tag) + EnumTag(hdr, dir, locus, sizeof(HDR)); + + xmode = hdr->xmode; + + if (xmode & (GEM_RESTRICT | GEM_RESERVED)) /* ¨î¯ÅºëµØ°Ï¤£¯à©wÁ㦬¿ý */ + continue; + + if (!(xmode & GEM_FOLDER)) /* ¬d hdr ¬O§_ plain text (§Y¤å³¹/¸ê®Æ/µ·¸ô) */ + { + hdr_fpath(fpath, dir, hdr); + + if (fp) /* ¦X¦¨¤@½g */ + { + f_suck(fp, fpath); + fputs(str_line, fp); + } + else /* ¤À§O«ØÀÉ */ + { + hdr_stamp(folder, HDR_COPY | 'A', &ghdr, fpath); + strcpy(ghdr.owner, cuser.userid); /* ¦¬¿ý¥ÎªO¥D id */ + strcpy(ghdr.title, hdr->title); + ghdr.xmode = 0; /* xmode ¬O¤å³¹ */ + + gbuf[index] = ghdr; /* itoc.010727: ¸õ¹L¤£¬O plain text ªº */ + index++; + rec_add(folder, &ghdr, sizeof(HDR)); + gem_log(folder, "¦¬¿ý", &ghdr); + } + } + } while (++locus < tag); + + if (fp) + { + fclose(fp); + gbuf[0] = ghdr; + rec_add(folder, &ghdr, sizeof(HDR)); + gem_log(folder, "·s¼W", &ghdr); + } + else + { + /* itoc.010727: tag ¼Æ¶q¦©±¼¤£¬O plain text ªº¤~¬O¯u¬O°Å¶K諸½g¼Æ */ + /* itoc.010727.µù¸Ñ: ¦pªG GemBufferNum ¼Æ¥Ø¤£¹ï¡A¨º»ò gem_paste() ®É´N·|µo¥Í¿ù»~ */ + GemBufferNum = index; + } + + zmsg("¦¬¿ý§¹¦¨¡A¦ý¬O¥[±K¤å³¹¤£·|³Q¦¬¿ý"); + + if (rc == XO_NONE) /* ¦bºëµØ°Ï¤¤ gem_gather() ¤~n«Ã¸°Å¶Kï½g¼Æ¡A¦b¬ÝªO/«H½c¸Ì³£¤£¥Î */ + { + /* itoc.010727: «Ã¸°Å¶Kï½g¼Æ */ + move(1, 59); + clrtoeol(); + prints("(°Å¶Kï %d ½g)\n", GemBufferNum); + } + + return XO_FOOT; +} + + +static int +gem_tag(xo) + XO *xo; +{ + HDR *hdr; + int pos, tag; + + if ((hdr = gem_check(xo, NULL, 0)) && + (tag = Tagger(hdr->chrono, pos = xo->pos, TAG_TOGGLE))) + { + move(3 + pos - xo->top, 7); + outc(tag > 0 ? '*' : ' '); + } + + /* return XO_NONE; */ + return xo->pos + 1 + XO_MOVE; /* lkchu.981201: ¸õ¦Ü¤U¤@¶µ¡A¤è«K³sÄò tag */ +} + + +static int +gem_help(xo) + XO *xo; +{ + xo_help("gem"); + return gem_head(xo); +} + + +static KeyFunc gem_cb[] = +{ + XO_INIT, gem_init, + XO_LOAD, gem_load, + XO_HEAD, gem_head, + XO_BODY, gem_body, + + 'r', gem_browse, + + Ctrl('P'), gem_add_all, /* itoc.010723: gem_cb ªº¤Þ¼Æ¥u¦³ xo */ + 'a', gem_add_article, + 'f', gem_add_folder, + + 'E', gem_edit, + 'T', gem_title, + 'd', gem_delete, + 'D', gem_rangedel, /* itoc.010726: ´£¨Ñ°Ï¬q§R°£ */ + + 'c', gem_copy, + 'g', gem_gather, + + Ctrl('G'), gem_anchor, + Ctrl('V'), gem_paste, + 'p', gem_paste, /* itoc.010223: ¨Ï¥ÎªÌ²ßºD c/p ¦¬¿ýºëµØ°Ï */ + + 't', gem_tag, + 'x', post_cross, /* ¦b post/mbox ¤¤³£¬O¤p¼g x Âà¬ÝªO¡A¤j¼g X Âà¨Ï¥ÎªÌ */ + 'X', post_forward, + 'B', gem_toggle, + 'o', gem_refuse, + 'm', gem_move, + 'M', gem_move, + + 'S', gem_state, + + Ctrl('D'), gem_prune, +#if 0 + Ctrl('Q'), xo_uquery, /* ºëµØ°Ïªº hdr.owner ¤@¯ë¬O«ü¦¬¿ýªºªO¥D¡A¦Ó¤£¬O§@ªÌ */ + Ctrl('O'), xo_usetup, /* ºëµØ°Ïªº hdr.owner ¤@¯ë¬O«ü¦¬¿ýªºªO¥D¡A¦Ó¤£¬O§@ªÌ */ +#endif + + 'h', gem_help +}; + + +void +XoGem(folder, title, level) + char *folder; + char *title; + int level; +{ + XO *xo, *last; + + last = xz[XZ_GEM - XO_ZONE].xo; /* record */ + + xz[XZ_GEM - XO_ZONE].xo = xo = xo_new(folder); + xo->pos = 0; + xo->key = level; + xo->xyz = title; + + xover(XZ_GEM); + + free(xo); + + xz[XZ_GEM - XO_ZONE].xo = last; /* restore */ +} + + +void +gem_main() +{ + XO *xo; + + xz[XZ_GEM - XO_ZONE].xo = xo = xo_new("gem/"FN_DIR); + xz[XZ_GEM - XO_ZONE].cb = gem_cb; + xo->pos = 0; + /* ¬ÝªOÁ`ºÞ¦b (A)nnounce ¸Ì±¦³ GEM_X_BIT ¨Ó·s¼W¬ÝªO±¶®| */ + xo->key = (HAS_PERM(PERM_ALLBOARD) ? (GEM_W_BIT | GEM_X_BIT | GEM_M_BIT) : 0); + xo->xyz = ""; +} diff --git a/maple/mail.c b/maple/mail.c new file mode 100644 index 0000000..93f13f0 --- /dev/null +++ b/maple/mail.c @@ -0,0 +1,1943 @@ +/*-------------------------------------------------------*/ +/* mail.c ( NTHU CS MapleBBS Ver 2.36 ) */ +/*-------------------------------------------------------*/ +/* target : local/internet mail routines */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +extern XZ xz[]; +extern char xo_pool[]; + + +extern UCACHE *ushm; + + +/* ----------------------------------------------------- */ +/* Link List routines */ +/* ----------------------------------------------------- */ + + +LinkList *ll_head; /* head of link list */ +static LinkList *ll_tail; /* tail of link list */ + + +void +ll_new() +{ + LinkList *list, *next; + + list = ll_head; + + while (list) + { + next = list->next; + free(list); + list = next; + } + + ll_head = ll_tail = NULL; +} + + +void +ll_add(name) + char *name; +{ + LinkList *node; + int len; + + len = strlen(name) + 1; + node = (LinkList *) malloc(sizeof(LinkList) + len); + node->next = NULL; + memcpy(node->data, name, len); + + if (ll_head) + ll_tail->next = node; + else + ll_head = node; + ll_tail = node; +} + + +int +ll_del(name) + char *name; +{ + LinkList *list, *prev, *next; + + prev = NULL; + for (list = ll_head; list; list = next) + { + next = list->next; + if (!strcmp(list->data, name)) + { + if (prev == NULL) + ll_head = next; + else + prev->next = next; + + if (list == ll_tail) + ll_tail = prev; + + free(list); + return 1; + } + prev = list; + } + return 0; +} + + +int +ll_has(name) + char *name; +{ + LinkList *list; + + for (list = ll_head; list; list = list->next) + { + if (!strcmp(list->data, name)) + return 1; + } + return 0; +} + + +void +ll_out(row, column, msg) + int row, column; + char *msg; +{ + int len; + LinkList *list; + + move(row, column); + clrtobot(); + outs(msg); + + column = 80; + for (list = ll_head; list; list = list->next) + { + msg = list->data; + len = strlen(msg) + 1; + if (column + len > 78) + { + if (++row > b_lines - 2) + { + move(b_lines, 60); + outs("±ÚÁc¤£¤Î³Æ¸ü..."); + break; + } + else + { + column = len; + outc('\n'); + } + } + else + { + column += len; + outc(' '); + } + outs(msg); + } +} + + +/* ----------------------------------------------------- */ +/* (direct) SMTP */ +/* ----------------------------------------------------- */ + + +int /* >=0:¦¨¥\ <0:¥¢±Ñ */ +bsmtp(fpath, title, rcpt, method) + char *fpath, *title, *rcpt; + int method; +{ + int sock; + time_t stamp; + FILE *fp, *fr, *fw; + char *str, buf[512], from[80], msgid[80]; +#ifdef EMAIL_JUSTIFY + char subject[80]; +#endif + + cuser.numemails++; /* °O¿ý¨Ï¥ÎªÌ¦@±H¥X´X«Ê Internet E-mail */ + time(&stamp); + +#ifdef EMAIL_JUSTIFY + + /* --------------------------------------------------- */ + /* ¨¤À»{ÃÒ«H¨ç */ + /* --------------------------------------------------- */ + + if (method & MQ_JUSTIFY) + { + fpath = FN_ETC_VALID; + title = subject; + sprintf(from, "bbsreg@%s", str_host); + /* itoc.010820: ¥Î cuser.tvalid ¨Ó°µ time-seed¡A¥i¥H¬Ù±¼ cuser.vtime Äæ¦ì¡A + ÁÙ¥i¥H¨Ï¦b¦P¤@¦¸»{ÃҮɡA©Òµo¥X¥hªº»{ÃÒ«H¼ÐÃD³£¬Û¦P¡AÁ×§K¦³¤H¦Ñ¬O¤£ª¾¹Dn¦^³Ì«á¤@«Ê */ + archiv32(str_hash(rcpt, cuser.tvalid), buf); + sprintf(title, TAG_VALID " %s(%s) [VALID]", cuser.userid, buf); + } + else +#endif + { + sprintf(from, "%s.bbs@%s", cuser.userid, str_host); + } + + str = strchr(rcpt, '@') + 1; + sock = dns_smtp(str); + if (sock >= 0) + { + move(b_lines, 0); + clrtoeol(); + prints("¡¹ ±H«Hµ¹ %s \033[5m...\033[m", rcpt); + refresh(); + + sleep(1); /* wait for mail server response */ + + fr = fdopen(sock, "r"); + fw = fdopen(sock, "w"); + + fgets(buf, sizeof(buf), fr); + if (memcmp(buf, "220", 3)) + goto smtp_error; + while (buf[3] == '-') + fgets(buf, sizeof(buf), fr); + + fprintf(fw, "HELO %s\r\n", str_host); + fflush(fw); + do + { + fgets(buf, sizeof(buf), fr); + if (memcmp(buf, "250", 3)) + goto smtp_error; + } while (buf[3] == '-'); + + fprintf(fw, "MAIL FROM:<%s>\r\n", from); + fflush(fw); + do + { + fgets(buf, sizeof(buf), fr); + if (memcmp(buf, "250", 3)) + goto smtp_error; + } while (buf[3] == '-'); + + fprintf(fw, "RCPT TO:<%s>\r\n", rcpt); + fflush(fw); + do + { + fgets(buf, sizeof(buf), fr); + if (memcmp(buf, "250", 3)) + goto smtp_error; + } while (buf[3] == '-'); + + fprintf(fw, "DATA\r\n", rcpt); + fflush(fw); + do + { + fgets(buf, sizeof(buf), fr); + if (memcmp(buf, "354", 3)) + goto smtp_error; + } while (buf[3] == '-'); + + /* ------------------------------------------------- */ + /* begin of mail header */ + /* ------------------------------------------------- */ + + archiv32(stamp, msgid); + + /* Thor.990125: ¾¨¥i¯àªº¹³ RFC 822 ¤Î sendmail ªº§@ªk, §K±o§O¤H¤£±µ:p */ + fprintf(fw, "From: \"%s\" <%s>\r\nTo: %s\r\n", +#ifdef EMAIL_JUSTIFY + method & MQ_JUSTIFY ? "BBS Register" : +#endif + cuser.username, from, rcpt); + /* itoc.030411: mail ¿é¥X RFC 2047 */ + output_rfc2047_qp(fw, "Subject: ", title, MYCHARSET, "\r\n"); + /* itoc.030323: mail ¿é¥X RFC 2045 */ + fprintf(fw, "X-Sender: %s (%s)\r\n" + "Date: %s\r\nMessage-Id: <%s@%s>\r\n" + "Mime-Version: 1.0\r\n" + "Content-Type: %s; charset=%s\r\n" + "Content-Transfer-Encoding: 8bit\r\n" + "X-Disclaimer: [%s] ¹ï¥»«H¤º®e®¤¤£t³d\r\n\r\n", + cuser.userid, cuser.username, + Atime(&stamp), msgid, str_host, + method & MQ_ATTACH ? "application/x-gzip" : "text/plain", MYCHARSET, + str_site); + +#ifdef EMAIL_JUSTIFY + if (method & MQ_JUSTIFY) /* ¨¤À»{ÃÒ«H¨ç */ + { + fprintf(fw, " ID: %s (%s) E-mail: %s\r\n\r\n", + cuser.userid, cuser.username, rcpt); + } +#endif + + /* ------------------------------------------------- */ + /* begin of mail body */ + /* ------------------------------------------------- */ + + if (fp = fopen(fpath, "r")) + { + char *ptr; + + str = buf; + *str++ = '.'; + while (fgets(str, sizeof(buf) - 3, fp)) + { + if (ptr = strchr(str, '\n')) + { + *ptr++ = '\r'; + *ptr++ = '\n'; + *ptr = '\0'; + } + fputs((*str == '.' ? buf : str), fw); + } + fclose(fp); + } +#ifdef HAVE_SIGNED_MAIL + if (!(method & MQ_JUSTIFY) && !rec_get(FN_RUN_PRIVATE, buf, 8, 0)) + /* Thor.990413: °£¤F»{ÃÒ¨ç¥~, ¨ä¥L«H¥ó³£n¥[sign */ + { + time_t prichro; + + buf[8] = '\0'; /* Thor.990413: buf ¥Î¤£¨ì¤F¡AɨӥΥΠ*/ + prichro = chrono32(buf); + archiv32(str_hash(msgid, prichro), buf); + fprintf(fw,"¡° X-Sign: %s$%s %s\r\n", + msgid, genpasswd(buf), Btime(&stamp)); + } +#endif + fputs("\r\n.\r\n", fw); + fflush(fw); + + fgets(buf, sizeof(buf), fr); + if (memcmp(buf, "250", 3)) + goto smtp_error; + + fputs("QUIT\r\n", fw); + fflush(fw); + fclose(fw); + fclose(fr); + goto smtp_log; + +smtp_error: + + /* itoc.041128.µù¸Ñ: ¤Z¬O¨«¨ì³o¸Ìªº¡Abuf ¬O¹ï¤è¦^ÂЪº¿ù»~°T®§ */ + fclose(fr); + fclose(fw); + sprintf(from, "\t%.70s\n", buf); + sock = -1; + } + else + { + strcpy(from, "\tSMTP ³s½u¥¢±Ñ\n"); + } + +smtp_log: + + /* --------------------------------------------------- */ + /* °O¿ý±H«H */ + /* --------------------------------------------------- */ + + sprintf(buf, "%s %-13s%c> %s\n%s\t%s\n\t%s\n", + Btime(&stamp), cuser.userid, (method & MQ_JUSTIFY) ? '=' : '-', rcpt, + sock >= 0 ? "" : from, title, fpath); + f_cat(FN_RUN_MAIL_LOG, buf); + + return sock; +} + + +#ifdef HAVE_MAIL_ZIP + +/* ----------------------------------------------------- */ +/* Zip mbox & board gem */ +/* ----------------------------------------------------- */ + + +static void +do_forward(title, mode) + char *title; + int mode; +{ + int rc; + char *userid; + char addr[64], fpath[64], cmd[256]; + + strcpy(addr, cuser.email); + + if (!vget(b_lines, 0, "½Ð¿é¤JÂà±H¦a§}¡G", addr, 60, GCARRY)) + return; + + if (not_addr(addr)) + { + zmsg(err_email); + return; + } + + sprintf(fpath, "½T©w±Hµ¹ [%s] ¶Ü(Y/N)¡H[N] ", addr); + if (vans(fpath) != 'y') + return; + + userid = strchr(addr, '@') + 1; + if (dns_smtp(userid) >= 0) /* itoc.µù¸Ñ: ÁöµM bsmtp() ¤]·|°µ¡A¦ý¬O³oÃä¥ý°µ¡A¥H§KÀ£ÁY§¹¤~ª¾¹D¬OµL®Äªº¤u§@¯¸¦a§} */ + { + userid = cuser.userid; + + if (mode == '1') /* Ó¤H«H¥ó */ + { + /* usr_fpath(fpath, userid, "@"); */ + /* ¦]¬° .DIR ¤£¦b @/ ¸Ì¡An¤@°_¥´¥] */ + usr_fpath(cmd, userid, fn_dir); + usr_fpath(fpath, userid, "@"); + strcat(fpath, " "); + strcat(fpath, cmd); + } + else if (mode == '2') /* Ó¤HºëµØ°Ï */ + { + usr_fpath(fpath, userid, "gem"); + } + else if (mode == '3') /* ¬ÝªO¤å³¹ */ + { + brd_fpath(fpath, currboard, NULL); + } + else /* if (mode == '4') */ /* ¬ÝªOºëµØ°Ï */ + { + gem_fpath(fpath, currboard, NULL); + } + + sprintf(cmd, "tar cfz - %s | uuencode %s.tgz > tmp/%s.tgz", fpath, userid, userid); + system(cmd); + + sprintf(fpath, "tmp/%s.tgz", userid); + rc = bsmtp(fpath, title, addr, MQ_ATTACH); + unlink(fpath); + + if (rc >= 0) + { + vmsg(msg_sent_ok); + return; + } + } + + vmsg("«H¥óµLªk±H¹F"); +} + + +int +m_zip() /* itoc.010228: ¥´¥]¸ê®Æ */ +{ + int ans; + char *name, *item, buf[80]; + + ans = vans("¥´¥]¸ê®Æ 1)Ó¤H«H¥ó 2)Ó¤HºëµØ°Ï 3)¬ÝªO¤å³¹ 4)¬ÝªOºëµØ°Ï [Q] "); + + if (ans == '1' || ans == '2') + { + name = cuser.userid; + item = (ans == '1') ? "Ó¤H«H¥ó" : "Ó¤HºëµØ°Ï"; + } + else if (ans == '3' || ans == '4') + { + /* itoc.µù¸Ñ: ©w¥u¯à¥´¥]¥Ø«e¾\Ūªº¬ÝªO¡A¤£¯à¾\Ū¯µ±K¬ÝªOªº¤H´N¤£¯à¥´¥]¸ÓªO/ºëµØ°Ï */ + /* itoc.020612: ¬°¤F¨¾¤î POST_RESTRICT/GEM_RESTRICT ªº¤å³¹¥~¬y¡A«DªO¥D´N¤£¯à¥´¥] */ + + if (currbno < 0) + { + vmsg("½Ð¥ý¶i¤J±zn¥´¥]ªº¬ÝªO¡A¦A¨Ó¦¹¥´¥]"); + return XEASY; + } + + if ((ans == '3' && !(bbstate & STAT_BM)) || (ans == '4' && !(bbstate & STAT_BOARD))) + { + vmsg("¥u¦³ªO¥D¤~¯à¥´¥]¬ÝªO¤å³¹¤Î¬ÝªOºëµØ°Ï"); + return XEASY; + } + + name = currboard; + item = (ans == '3') ? "¬ÝªO¤å³¹" : "¬ÝªOºëµØ°Ï"; + } + else + { + return XEASY; + } + + sprintf(buf, "½T©wn¥´¥] %s %s¶Ü(Y/N)¡H[N] ", name, item); + if (vans(buf) == 'y') + { + sprintf(buf, "¡i" BBSNAME "¡j%s %s", name, item); + do_forward(buf, ans); + } + + return XEASY; +} +#endif /* HAVE_MAIL_ZIP */ + + +#ifdef HAVE_SIGNED_MAIL /* Thor.990413: ´£¨ÑÅçÃÒ¥\¯à */ +int +m_verify() +{ + time_t prichro; /* ¨t²Îªº private chrono */ + time_t chrono; + char key[9], sign[68], *p; + + vmsg("½Ð¿é¤J«H¥½ X-Sign ¥H¶i¦æÅçÃÒ"); + + if (!vget(b_lines, 0, "¡° X-Sign: ", sign, sizeof(sign), DOECHO)) + return XEASY; + + str_trim(sign); /* Thor: ¥h§À¤Ú¡Afor ptelnet ¦Û°Ê¥[ªÅ¥Õ */ + p = sign; + while (*p == ' ') /* Thor: ¥h«eÀYªºªÅ¥Õ */ + p++; + + if (strlen(p) < 7 + 1 + PASSLEN + 1) + { + vmsg("¹q¤lñ³¹¦³»~"); + return XEASY; + } + + /* ¨ú±o¨t²Îªº private chrono */ + if (rec_get(FN_RUN_PRIVATE, key, 8, 0)) + { + zmsg("¥»¨t²Î¨ÃµL¹q¤lñ³¹¡A½Ð¬¢¯¸ªø"); + return XEASY; + } + key[8] = '\0'; + prichro = chrono32(key); + + /* ¨ú±o¸Ó«Hªº chrono */ + p[7] = '\0'; + strcpy(key + 1, p); /* +1 for chrono32() ©Ònªº prefix */ + chrono = chrono32(key); + + /* ¨ú±o¸Ó«Hªº±KÆ_ */ + archiv32(str_hash(p, prichro), key); + p[7 + PASSLEN + 1] = '\0'; + + if (chkpasswd(p + 8, key) || strcmp(p + 8 + PASSLEN + 1, Btime(&chrono))) + vmsg("¦¹«H¨Ã«D¥Ñ¥»¯¸©Òµo¡A½Ð¬d·Ó¡I"); + else + vmsg("¦¹«H¥Ñ¥»¯¸©Òµo¥X"); + + return XEASY; +} +#endif + + +/* ----------------------------------------------------- */ +/* mail routines */ +/* ----------------------------------------------------- */ + + +static struct +{ + XO mail_xo; + char dir[32]; +} cmbox; + + +#ifdef OVERDUE_MAILDEL +usint +m_quota() +{ + usint status; + int fd, count, fsize, limit, xmode; + time_t mail_due, mark_due; + struct stat st; + HDR *head, *tail; + char *base, *folder, date[9]; + + if ((fd = open(folder = cmbox.dir, O_RDWR)) < 0) + return 0; + + status = 0; + fsize = limit = 0; + + if (!fstat(fd, &st) && (fsize = st.st_size) >= sizeof(HDR) && + (base = (char *) malloc(fsize))) + { + + /* flock(fd, LOCK_EX); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_exlock(fd); + + if ((fsize = read(fd, base, fsize)) >= sizeof(HDR)) + { + int prune; /* number of pruned mail */ + + limit = time(0); + mail_due = limit - MAIL_DUE * 86400; + mark_due = limit - MARK_DUE * 86400; + st.st_mtime = limit + CHECK_PERIOD; + str_stamp(date, &st.st_mtime); + + limit = cuser.userlevel; + limit = (limit & (PERM_ALLADMIN | PERM_MBOX)) ? MAX_BBSMAIL : (limit & PERM_VALID) ? MAX_VALIDMAIL : MAX_NOVALIDMAIL; + + count = fsize / sizeof(HDR); + + head = (HDR *) base; + tail = (HDR *) (base + fsize); + + prune = 0; + + do + { + /* itoc.011013.µù¸Ñ: ³o¦¸¥[¤W¤F MAIL_DELETE¡An¹L CHECK_PERIOD ¤U¤@¦¸¤~·|¯u¥¿§R°£ */ + /* itoc.011013.µù¸Ñ: °£¤F m_quota() ¥H¥~¡A¦b bpop3.c ¸Ì±¡AY¨ú«H®Én¨D±q¦øªA¾¹¤W§R°£¡A¤]·|¥[¤W MAIL_DELETE ªººX¼Ð */ + + xmode = head->xmode; + if (xmode & MAIL_DELETE) + { + char fpath[64]; + + hdr_fpath(fpath, folder, head); + unlink(fpath); + prune--; + continue; + } + + if (!(xmode & MAIL_READ)) + status |= STATUS_BIFF; + + if ((count > limit) || + (head->chrono <= (xmode & MAIL_MARKED ? mark_due : mail_due))) + { + count--; + head->xmode = xmode | MAIL_DELETE; + strcpy(head->date, date); + status |= STATUS_MQUOTA; + } + + if (prune) + head[prune] = head[0]; + + } while (++head < tail); + + fsize += (prune * sizeof(HDR)); + if ((fsize > 0) && (prune || (status & STATUS_MQUOTA))) + { + lseek(fd, 0, SEEK_SET); + write(fd, base, fsize); + ftruncate(fd, fsize); + } + } + + /* flock(fd, LOCK_UN); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_unlock(fd); + + free(base); + } + + close(fd); + + if (fsize > limit) + status ^= STATUS_MAILOVER; + else if (fsize < sizeof(HDR)) + unlink(folder); + + return status; +} +#endif + + +usint +m_query(userid) + char *userid; +{ + usint status; + int fsize, limit; + HDR *head, *tail; + char folder[64]; + + status = 0; + usr_fpath(folder, userid, fn_dir); + if (head = (HDR *) f_img(folder, &fsize)) + { + fsize /= sizeof(HDR); + tail = head + fsize; + + while (--tail >= head) + { + if (!(tail->xmode & MAIL_READ)) + { + status = STATUS_BIFF; + break; + } + } + free(head); + + limit = HAS_PERM(PERM_ALLADMIN | PERM_MBOX) ? MAX_BBSMAIL : HAS_PERM(PERM_VALID) ? MAX_VALIDMAIL : MAX_NOVALIDMAIL; + if (fsize > limit) + status ^= STATUS_MAILOVER; + } + + return status; +} + + +void +m_biff(userno) + int userno; +{ + UTMP *utmp, *uceil; + + utmp = ushm->uslot; + uceil = (void *) utmp + ushm->offset; + do + { + if (utmp->userno == userno) + { + utmp->status |= STATUS_BIFF; + +#ifdef BELL_ONCE_ONLY + return; +#endif + } + } while (++utmp <= uceil); +} + + +void +mail_hold(fpath, rcpt, title, hold) + char *fpath; + char *rcpt; + char *title; + int hold; /* -1:·í±H«H¥¢±Ñ®É¥i¥H±j¢«O¯d */ +{ + if (hold < 0 || vans("¬O§_¦Û¦s©³½Z(Y/N)¡H[N] ") == 'y') + { + char buf[256]; + + sprintf(buf, "<%s> %s", rcpt, title); + buf[TTLEN] = '\0'; + + mail_self(fpath, "[³Æ §Ñ ¿ý]", buf, MAIL_READ | MAIL_NOREPLY); + } +} + + +/* ----------------------------------------------------- */ +/* in boards/mail ¦^«Hµ¹ì§@ªÌ¡AÂà«H¯¸¥ç¥i */ +/* ----------------------------------------------------- */ + + +static inline int +is_host_alias(addr) + char *addr; +{ + int i; + char *str; + static char *alias[] = HOST_ALIASES; + + /* check the aliases */ + + for (i = 0; str = alias[i]; i++) + { + if (*str && !str_cmp(addr, str)) + return 1; + } + return 0; +} + + +/* static inline */ +int /* 1:internet mail 0:¯¸¤º±H«H(¶Ç¦^addr¬°userid) */ +mail_external(addr) + char *addr; +{ + char *str; + + str = strchr(addr, '@'); /* itoc.020125.µù¸Ñ: email ¦ì§}¥u¦³Ó ID¡Aªí¥Ü¬O¯¸¤º±H«H */ + if (!str) + return 0; + + if (!is_host_alias(str + 1)) /* itoc.020125: ¦pªG¤£¦b HOST_ALIAS ¤¤¡A¬°¯¸¥~±H«H */ + return 1; + + /* ¯¸¤º±H«H: ÄdºI xyz.bbs@mydomain¡A¦ý¤£¥]¬A xyz.brd@mydomain */ + + *str = '\0'; + if (str > addr + 4 && !strcmp(str - 4, ".bbs")) /* ".bbs" => 4 */ + { + str[-4] = '\0'; + return 0; + } + + return 1; /* Y¤£¬O *.bbs@mydomain¡A«h¥á¦^¥hÅý not_addr() µo¥Í¿ù»~ */ +} + + +int /* >=0:¦¨¥\ -1:¥¢±Ñ©Î¨ú®ø */ +mail_send(rcpt) + char *rcpt; +{ + /* Thor.981105: ¶i¤J«e»Ý³]¦n quote_file */ + /* itoc.041116: ¶i¤J«e»Ý³]¦n ve_title (¤§©Ò¥H¥Î ve_title ¬O§Æ±æ¦b vedit §ï¼ÐÃD®É¡A¤]¯à¤@°_§ï«H¥óÀÉÀYªº¼ÐÃD) */ + HDR hdr; + char fpath[64], folder[64], *msg; + int userno; /* 0:internet_mail >0:userno */ + FILE *fp; + + if (!mail_external(rcpt)) /* ¤¤³~ÄdºI */ + { + if ((userno = acct_userno(rcpt)) <= 0) + { + zmsg(err_uid); + return -1; + } + } + else + { + if (not_addr(rcpt)) + { + zmsg(err_email); + return -1; + } + userno = 0; + } + + utmp_mode(M_SMAIL); + fpath[0] = '\0'; + curredit = EDIT_MAIL; /* Thor.981105: ª½±µ«ü©w¼g«H */ + + if (vedit(fpath, userno ? 1 : 2) < 0) + { + unlink(fpath); + vmsg(msg_cancel); + return -1; + } + + if (userno) + { + usr_fpath(folder, rcpt, fn_dir); + hdr_stamp(folder, HDR_LINK, &hdr, fpath); + strcpy(hdr.owner, cuser.userid); + strcpy(hdr.nick, cuser.username); /* chuan: ¥[¤J nick */ + strcpy(hdr.title, ve_title); + rec_add(folder, &hdr, sizeof(HDR)); + + if (fp = fopen(FN_RUN_MAIL_LOG, "a")) + { + fprintf(fp, "%s %-13s-> %s\n\t%s\n", + Btime(&hdr.chrono), cuser.userid, rcpt, ve_title); + fclose(fp); + } + + msg = msg_sent_ok; + m_biff(userno); + mail_hold(fpath, rcpt, ve_title, 0); + } + else + { + clear(); + prints("«H¥ó§Y±N±Hµ¹ %s\n¼ÐÃD¬°¡G%s\n½T©wn±H¥X¶Ü(Y/N)¡H[Y] ", rcpt, ve_title); + switch (vkey()) + { + case 'n': + case 'N': + msg = msg_cancel; + userno = -1; + break; + + default: + outs("Y\n½ÐµyÔ¡A«H¥ó¶Ç»¼¤¤...\n"); + refresh(); + userno = bsmtp(fpath, ve_title, rcpt, 0); + msg = (userno >= 0) ? msg_sent_ok : "«H¥óµLªk±H¹F¡A©³½Z³Æ¥÷¦b«H½c"; + mail_hold(fpath, rcpt, ve_title, userno); + } + } + + unlink(fpath); + vmsg(msg); + return userno; +} + + +static void +mail_reply(hdr) + HDR *hdr; +{ + int xmode, prefix; + + vs_bar("¦^ «H"); + + /* make the title */ + + sprintf(ve_title, "Re: %.64s", str_ttl(hdr->title)); + if (!vget(2, 0, "¼ÐÃD¡G", ve_title, TTLEN + 1, GCARRY)) + return; + + prints("\n¦¬«H¤H: %s (%s)\n¼Ð ÃD: %s\n", quote_user, quote_nick, ve_title); + + /* Thor: ¬°¤F¬Ù¤@¦¸ rec_put ¦^«H«h°²³]¬Ý¹L¤º®e */ + + xmode = hdr->xmode | MAIL_READ; + prefix = quote_file[0]; + + /* edit, then send the mail */ + + if (mail_send(quote_user) >= 0) + xmode |= MAIL_REPLIED; + + if (prefix == 'u') /* user mail ¬Ý«H®É¤~¼Ð r */ + hdr->xmode = xmode; +} + + +int +my_send(userid) /* ¯¸¤º±H«Hµ¹ userid */ + char *userid; +{ + if (HAS_PERM(PERM_DENYMAIL) || !HAS_PERM(PERM_LOCAL)) + return XO_NONE; + + vs_bar("±H «H"); + prints("¦¬«H¤H¡G%s", userid); + if (vget(2, 0, "¼ÐÃD¡G", ve_title, TTLEN + 1, DOECHO)) + { + *quote_file = '\0'; + mail_send(userid); + } + return XO_HEAD; +} + + +int +m_send() +{ + ACCT acct; + + /* itoc.050604: ÁöµM¦b my_send() ¸Ì±·|Àˬd¡A¦ý¬OÀ³¸Ó¦b¦¹´N¥ý¾×±¼¡A³s ID ³£µLªk¿é¤J */ + if (HAS_PERM(PERM_DENYMAIL)) + return XEASY; + + if (acct_get(msg_uid, &acct) > 0) + my_send(acct.userid); + return 0; +} + + +int +m_internet() +{ + char rcpt[60]; + + if (HAS_PERM(PERM_DENYMAIL)) + return XEASY; + + move(MENU_XPOS, 0); + clrtobot(); + + if (vget(15, 0, "¦¬«H¤H¡G", rcpt, sizeof(rcpt), DOECHO) && + vget(17, 0, "¼ÐÃD¡G", ve_title, TTLEN + 1, DOECHO)) + { + *quote_file = '\0'; + mail_send(rcpt); + } + + return 0; +} + + +int +m_sysop() +{ + int fd; + + if ((fd = open(FN_ETC_SYSOP, O_RDONLY)) >= 0) + { + int i, j; + char *ptr, *str; + + struct SYSOPLIST + { + char userid[IDLEN + 1]; + char duty[40]; + } sysoplist[7]; /* °²³] 7 Ó¨¬¨o */ + + j = 0; + mgets(-1); + while (str = mgets(fd)) + { + if (ptr = strchr(str, ':')) + { + *ptr = '\0'; + do + { + i = *++ptr; + } while (i == ' ' || i == '\t'); + + if (i) + { + strcpy(sysoplist[j].userid, str); + strcpy(sysoplist[j++].duty, ptr); + } + } + } + close(fd); + + move(12, 0); + clrtobot(); + prints("%16s %-18sÅv³d¹º¤À\n%s\n", "½s¸¹", "¯¸ªø ID", msg_seperator); + + for (i = 0; i < j; i++) + { + prints("%15d. \033[1;%dm%-16s%s\033[m\n", + i + 1, 31 + i, sysoplist[i].userid, sysoplist[i].duty); + } + prints("%-14s0. \033[1;%dmÂ÷¶}\033[m", "", 31 + j); + + i = vans("½Ð¿é¤J¥N½X¡G[0] ") - '1'; + if (i >= 0 && i < j) + { + vs_bar("±H «H"); + prints("¦¬«H¤H¡G%s", sysoplist[i].userid); + + if (vget(2, 0, "¼ÐÃD¡G", ve_title, TTLEN + 1, DOECHO)) + { + *quote_file = '\0'; + mail_send(sysoplist[i].userid); + } + } + } + return 0; +} + + +void +mail_self(fpath, owner, title, xmode) /* itoc.011115: ±HÀÉ®×µ¹¦Û¤v */ + char *fpath; /* Àɮ׸ô®| */ + char *owner; /* ±H¥ó¤H */ + char *title; /* ¶l¥ó¼ÐÃD */ + usint xmode; +{ + HDR hdr; + char *folder; + + folder = cmbox.dir; + hdr_stamp(folder, HDR_COPY, &hdr, fpath); + strcpy(hdr.owner, owner); + strcpy(hdr.title, title); + hdr.xmode = xmode; + rec_add(folder, &hdr, sizeof(HDR)); +} + + +int +mail_him(fpath, rcpt, title, xmode) /* itoc.041111: ±HÀÉ®×µ¹¥L¤H */ + char *fpath; /* Àɮ׸ô®| */ + char *rcpt; /* ¦¬¥ó¤H */ + char *title; /* ¶l¥ó¼ÐÃD */ + usint xmode; +{ + int userno; + HDR hdr; + char folder[64]; + + if ((userno = acct_userno(rcpt)) > 0) /* ¦¬¥ó¤H¦³¥i¯à¤£¦s¦b */ + { + usr_fpath(folder, rcpt, fn_dir); + hdr_stamp(folder, HDR_COPY, &hdr, fpath); + strcpy(hdr.owner, cuser.userid); + strcpy(hdr.title, title); + hdr.xmode = xmode; + rec_add(folder, &hdr, sizeof(HDR)); + m_biff(userno); + } + return userno; +} + + +/* ----------------------------------------------------- */ +/* ¸s²Õ±H«H¡B¦^«H */ +/* ----------------------------------------------------- */ + + +#ifdef MULTI_MAIL /* Thor.981009: ¨¾¤î·R±¡©¯¹B«H */ + +static int +multi_send(title) + char *title; +{ + FILE *fp; + HDR hdr; + char buf[128], fpath[64], *userid; + int userno, reciper, listing; + LinkList *wp; + + vs_bar(title ? "¸s²Õ¦^«H" : "¸s²Õ±H«H"); + + ll_new(); + listing = reciper = 0; + + /* ¦^«H®ÉŪ¨ú mail list ¦W³æ */ + + if (*quote_file) + { + ll_add(quote_user); + reciper = 1; + + fp = fopen(quote_file, "r"); + while (fgets(buf, sizeof(buf), fp)) + { + if (memcmp(buf, "¡° ", 3)) + { + if (listing) + break; + } + else + { + userid = buf + 3; + if (listing) + { + strtok(userid, " \n\r"); + do + { + if ((userno = acct_userno(userid)) && (userno != cuser.userno) && + !ll_has(userid)) + { + ll_add(userid); + reciper++; + } + } while (userid = (char *) strtok(NULL, " \n\r")); + } + else if (!memcmp(userid, "[³q§i]", 6)) + listing = 1; + } + } + fclose(fp); + ll_out(3, 0, MSG_LL); + } + + /* ³]©w mail list ªº¦W³æ */ + + reciper = pal_list(reciper); + + /* ¶}©l±H«H */ + + move(1, 0); + clrtobot(); + + if (reciper == 1) + { + if (title) + sprintf(ve_title, "Re: %.64s", str_ttl(title)); + + if (!vget(2, 0, "¼ÐÃD¡G", ve_title, TTLEN + 1, title ? GCARRY : DOECHO)) + return -1; + mail_send(ll_head->data); + } + else if (reciper >= 2 && ve_subject(2, title, "[³q§i] ")) + { + usr_fpath(fpath, cuser.userid, fn_note); + + if (fp = fopen(fpath, "w")) + { + fprintf(fp, "¡° [³q§i] ¦@ %d ¤H¦¬¥ó", reciper); + listing = 80; + wp = ll_head; + + do + { + userid = wp->data; + reciper = strlen(userid) + 1; + + if (listing + reciper > 75) + { + listing = reciper; + fprintf(fp, "\n¡°"); + } + else + { + listing += reciper; + } + + fprintf(fp, " %s", userid); + } while (wp = wp->next); + + memset(buf, '-', 75); + buf[75] = '\0'; + fprintf(fp, "\n%s\n\n", buf); + fclose(fp); + } + + utmp_mode(M_SMAIL); + curredit = EDIT_MAIL | EDIT_LIST; + + if (vedit(fpath, 1) < 0) + { + vmsg(msg_cancel); + unlink(fpath); + return -1; + } + else + { + vs_bar("±H«H¤¤..."); + + listing = 80; + wp = ll_head; + title = ve_title; + userno = 2; /* ɥΠuserno ·í¦L¨ìþ¤@¦æ */ + + do + { + userid = wp->data; + if (userno < b_lines) /* ³Ì¦h¦L¨ì b_lines - 1 */ + { + /* ¦L¥X¥Ø«e±H¨ìþ¤@Ó id */ + reciper = strlen(userid) + 1; + if (listing + reciper > 75) + { + listing = reciper; + outc('\n'); + userno++; + } + else + { + listing += reciper; + outc(' '); + } + outs(userid); + } + + usr_fpath(buf, userid, fn_dir); + hdr_stamp(buf, HDR_LINK, &hdr, fpath); + strcpy(hdr.owner, cuser.userid); + strcpy(hdr.title, title); + hdr.xmode = MAIL_MULTI; + rec_add(buf, &hdr, sizeof(HDR)); + } while (wp = wp->next); + + if (fp = fopen(FN_RUN_MAIL_LOG, "a")) + { + fprintf(fp, "%s %-13s-> %s\n\t%s\n", + Btime(&hdr.chrono), cuser.userid, "¸s²Õ±H«H", title); + fclose(fp); + } + + mail_hold(fpath, "¸s²Õ±H«H", title, 0); + unlink(fpath); + vmsg(msg_sent_ok); + } + } + else + { + vmsg(msg_cancel); + return -1; + } + + return 0; +} + + +static void +multi_reply(hdr) + HDR *hdr; +{ + if (!multi_send(hdr->title)) + hdr->xmode |= (MAIL_REPLIED | MAIL_READ); +} + + +int +m_list() +{ + if (HAS_PERM(PERM_DENYMAIL)) + return XEASY; + + multi_send(NULL); + + return 0; +} + +#endif + + +int +do_mreply(hdr, noreply) + HDR *hdr; + int noreply; /* 1:n 0:¤£n Àˬd MAIL_NOREPLY */ +{ + if ((noreply && (hdr->xmode & MAIL_NOREPLY)) || + HAS_PERM(PERM_DENYMAIL) || + !HAS_PERM(strchr(hdr->owner, '@') ? PERM_INTERNET : PERM_LOCAL)) + { + return XO_FOOT; + } + + strcpy(quote_user, hdr->owner); + strcpy(quote_nick, hdr->nick); + +#ifdef MULTI_MAIL + /* itoc.001125: ±`¦³¤H»~«ö¸s²Õ±H«H¡A½T©w¤@¤U */ + if ((hdr->xmode & MAIL_MULTI) && vans(MSG_MULTIREPLY) == 'y') + multi_reply(hdr); + else +#endif + mail_reply(hdr); + + return XO_HEAD; +} + + +/* ----------------------------------------------------- */ +/* Mail Box call-back routines */ +/* ----------------------------------------------------- */ + + +static inline int +mbox_attr(type) + int type; +{ +#ifdef OVERDUE_MAILDEL + if (type & MAIL_DELETE) + return 'D'; +#endif + + if (type & MAIL_REPLIED) + return (type & MAIL_MARKED) ? 'R' : 'r'; + + return "+ Mm"[type & 3]; +} + + +static void +mbox_item(num, hdr) + int num; /* sequence number */ + HDR *hdr; +{ +#ifdef OVERDUE_MAILDEL + int xmode; + + xmode = hdr->xmode; + prints(xmode & MAIL_DELETE ? "%6d%c\033[1;5;37;41m%c\033[m " : "%6d%c%c ", + num, tag_char(hdr->chrono), mbox_attr(xmode)); +#else + prints("%6d%c%c ", num, tag_char(hdr->chrono), mbox_attr(hdr->xmode)); +#endif + + hdr_outs(hdr, d_cols + 47); +} + + +static int +mbox_body(xo) + XO *xo; +{ + HDR *hdr; + int num, max, tail; + + max = xo->max; + if (max <= 0) + { + vmsg("±z¨S¦³¨Ó«H"); + return XO_QUIT; + } + + num = xo->top; + hdr = (HDR *) xo_pool; + tail = num + XO_TALL; + if (max > tail) + max = tail; + + move(3, 0); + do + { + mbox_item(++num, hdr++); + } while (num < max); + clrtobot(); + + /* return XO_NONE; */ + return XO_FOOT; /* itoc.010403: §â b_lines ¶ñ¤W feeter */ +} + + +static int +mbox_head(xo) + XO *xo; +{ + if (HAS_STATUS(STATUS_BIFF)) /* ¤@¶i¤J«H½c´N®³±¼ STATUS_BIFF */ + cutmp->status ^= STATUS_BIFF; + + vs_head("¶l¥ó¿ï³æ", str_site); + prints(NECKER_MBOX, d_cols, ""); + return mbox_body(xo); +} + + +static int +mbox_load(xo) + XO *xo; +{ + xo_load(xo, sizeof(HDR)); + return mbox_body(xo); +} + + +static int +mbox_init(xo) + XO *xo; +{ + xo_load(xo, sizeof(HDR)); + return mbox_head(xo); +} + + +static int +mbox_delete(xo) + XO *xo; +{ + int pos; + HDR *hdr; + char fpath[64], *dir; + + pos = xo->pos; + hdr = (HDR *) xo_pool + (pos - xo->top); + +#ifdef OVERDUE_MAILDEL + /* Thor.980901: mark «áY³Q'D'°_¨Ó¡A«h¤@¼Ë¥i¥H delete¡A¥u¦³ MARK & no delete ¤~·|µL®Ä */ + if ((hdr->xmode & (MAIL_MARKED | MAIL_DELETE)) == MAIL_MARKED) +#else + if (hdr->xmode & MAIL_MARKED) +#endif + return XO_NONE; + + if (vans(msg_del_ny) == 'y') + { + dir = xo->dir; + currchrono = hdr->chrono; + if (!rec_del(dir, sizeof(HDR), xo->key == XZ_XPOST ? hdr->xid : pos, cmpchrono)) + { + hdr_fpath(fpath, dir, hdr); + unlink(fpath); + return XO_LOAD; + } + } + return XO_FOOT; +} + + +static int +chkmbox(hdr) + HDR *hdr; +{ + return (hdr->xmode & MAIL_MARKED); +} + + +static int +vfymbox(hdr, pos) + HDR *hdr; + int pos; +{ + return (Tagger(hdr->chrono, pos, TAG_NIN) || chkmbox(hdr)); +} + + +static void +delmbox(xo, hdr) + XO *xo; + HDR *hdr; +{ + char fpath[64]; + + hdr_fpath(fpath, xo->dir, hdr); + unlink(fpath); +} + + +static int +mbox_rangedel(xo) + XO *xo; +{ + return xo_rangedel(xo, sizeof(HDR), chkmbox, delmbox); +} + + +static int +mbox_prune(xo) + XO *xo; +{ + return xo_prune(xo, sizeof(HDR), vfymbox, delmbox); +} + + +static int +mbox_forward(xo) + XO *xo; +{ + if (HAS_PERM(PERM_DENYMAIL)) + return XO_NONE; + + return post_forward(xo); /* itoc.011230: »P post_forward() ¦@¥Î */ +} + + +static int +mbox_browse(xo) /* itoc.000513: Åý«HŪ¨ì¤@¥b¤]¯à reply mark delete */ + XO *xo; +{ + HDR *hdr; + int pos, xmode, nmode; + char *dir, fpath[64]; + + dir = xo->dir; + + for (;;) + { + pos = xo->pos; + hdr = (HDR *) xo_pool + (pos - xo->top); + xmode = hdr->xmode; + + hdr_fpath(fpath, dir, hdr); + + /* Thor.990204: ¬°¦Ò¼{more ¶Ç¦^È */ + if ((nmode = more(fpath, FOOTER_MAILER)) < 0) + break; + + /* itoc.010324: ¨q§¹¸Ó½g¥þ³¡¥H«án³]¬°¤wŪ¡A¥H§K¤@ª½«öªÅ¥Õ©¹¤UŪ¡A¥u§â³Ì«á¤@½g³]¤wŪ */ + if (nmode == 0 && !(xmode & MAIL_READ)) + { + hdr->xmode = xmode | MAIL_READ; + rec_put(dir, hdr, sizeof(HDR), pos, NULL); + } + + strcpy(currtitle, str_ttl(hdr->title)); + +re_key: + switch (xo_getch(xo, nmode)) + { + case XO_BODY: + continue; + + case 'y': + case 'r': + strcpy(quote_file, fpath); + do_mreply(hdr, 1); + break; + + case 'd': + if (mbox_delete(xo) == XO_LOAD) + return mbox_init(xo); + break; + + case 'm': + /* hdr->xmode ^= MAIL_MARKED; */ + /* ¦b mbox_browse ®É¬Ý¤£¨ì m °O¸¹¡A©Ò¥H¨î¥u¯à mark */ + hdr->xmode |= MAIL_MARKED; + break; + + case 'x': /* itoc.011231: mbox_browse ®É¥iÂà¿ý«H¥h¬ÝªO */ + post_cross(xo); + break; + + case 'X': + mbox_forward(xo); + break; + + case '/': + if (vget(b_lines, 0, "·j´M¡G", hunt, sizeof(hunt), DOECHO)) + { + more(fpath, FOOTER_MAILER); + goto re_key; + } + continue; + + case 'E': + return mbox_edit(xo); + + case 'C': /* itoc.000515: mbox_browse ®É¥i¦s¤J¼È¦sÀÉ */ + { + FILE *fp; + if (fp = tbf_open()) + { + f_suck(fp, fpath); + fclose(fp); + } + } + break; + + case 'h': + xo_help("mbox"); + break; + } + break; + } + + nmode = hdr->xmode | MAIL_READ; + if (xmode != nmode) + { + hdr->xmode = nmode; + rec_put(dir, hdr, sizeof(HDR), pos, NULL); + } + + return mbox_head(xo); +} + + +static int +mbox_reply(xo) + XO *xo; +{ + int pos, xmode; + HDR *hdr; + + pos = xo->pos; + hdr = (HDR *) xo_pool + pos - xo->top; + xmode = hdr->xmode; + + hdr_fpath(quote_file, xo->dir, hdr); + do_mreply(hdr, 1); + + if (hdr->xmode != xmode) + rec_put(xo->dir, hdr, sizeof(HDR), pos, NULL); + + return XO_HEAD; +} + + +int +mbox_edit(xo) /* itoc.010301: ¥i¥H½s¿è¦Û¤v«H½c¤¤ªº«H */ + XO *xo; +{ + char fpath[64]; + HDR *hdr; + + hdr = (HDR *) xo_pool + (xo->pos - xo->top); + hdr_fpath(fpath, xo->dir, hdr); + + curredit = EDIT_MAIL; /* Thor.981105: ª½±µ«ü©w¼g«H */ + + if (!strcmp(hdr->owner, cuser.userid) || HAS_PERM(PERM_ALLBOARD)) /* ¦Û¤v±Hµ¹¦Û¤vªº«H©Î¬O¯¸ªø */ + vedit(fpath, 0); + else + vedit(fpath, -1); /* ¥u¯à½s¿è¤£¥iÀx¦s */ + + /* return mbox_head(xo); */ + return XO_HEAD; /* itoc.041023: XZ_MBOX ©M XZ_XPOST ¦@¥Î mbox_edit() */ +} + + +static int +mbox_title(xo) /* itoc.020113: ¥i¥H§ï¦Û¤v«H½c¤¤ªº¼ÐÃD */ + XO *xo; +{ + HDR *fhdr, mhdr; + int pos, cur; + + pos = xo->pos; + cur = pos - xo->top; + fhdr = (HDR *) xo_pool + cur; + memcpy(&mhdr, fhdr, sizeof(HDR)); + + if (strcmp(cuser.userid, mhdr.owner) && !HAS_PERM(PERM_ALLBOARD)) + return XO_NONE; + + vget(b_lines, 0, "¼ÐÃD¡G", mhdr.title, TTLEN + 1, GCARRY); + + if (HAS_PERM(PERM_ALLBOARD)) /* itoc.000213: ì§@ªÌ¥u¯à§ï¼ÐÃD */ + { + vget(b_lines, 0, "§@ªÌ¡G", mhdr.owner, 73 /* sizeof(mhdr.owner) */, GCARRY); + /* Thor.980727: sizeof(mhdr.owner) = 80 ·|¶W¹L¤@¦æ */ + vget(b_lines, 0, "¼ÊºÙ¡G", mhdr.nick, sizeof(mhdr.nick), GCARRY); + vget(b_lines, 0, "¤é´Á¡G", mhdr.date, sizeof(mhdr.date), GCARRY); + } + + if (memcmp(fhdr, &mhdr, sizeof(HDR)) && vans(msg_sure_ny) == 'y') + { + *fhdr = mhdr; + rec_put(xo->dir, fhdr, sizeof(HDR), xo->key == XZ_XPOST ? fhdr->xid : pos, NULL); + move(3 + cur, 0); + mbox_item(++pos, fhdr); + + /* itoc.010709: ×§ï¤å³¹¼ÐÃD¶¶«Kק鷺¤åªº¼ÐÃD */ + header_replace(xo, fhdr); + } + return XO_FOOT; +} + + +static int +mbox_mark(xo) + XO *xo; +{ + HDR *hdr; + int cur, pos; + + pos = xo->pos; + cur = pos - xo->top; + hdr = (HDR *) xo_pool + cur; + move(3 + cur, 7); + outc(mbox_attr(hdr->xmode ^= MAIL_MARKED)); + rec_put(xo->dir, hdr, sizeof(HDR), xo->key == XZ_XPOST ? hdr->xid : pos, NULL); + return XO_NONE; +} + + +static int +mbox_tag(xo) + XO *xo; +{ + HDR *hdr; + int tag, pos, cur; + + pos = xo->pos; + cur = pos - xo->top; + hdr = (HDR *) xo_pool + cur; + + if (xo->key == XZ_XPOST) + pos = hdr->xid; + + if (tag = Tagger(hdr->chrono, pos, TAG_TOGGLE)) + { + move(3 + cur, 6); + outc(tag > 0 ? '*' : ' '); + } + + /* return XO_NONE; */ + return xo->pos + 1 + XO_MOVE; /* lkchu.981201: ¸õ¦Ü¤U¤@¶µ */ +} + + +static int +mbox_send(xo) + XO *xo; +{ + m_send(); + return mbox_head(xo); +} + + +static int +mbox_visit(xo) + XO *xo; +{ + int pos, fd; + char *dir; + HDR *hdr; + + pos = vans("³]©w©Ò¦³«H¥ó (V)¤wŪ (Q)¨ú®ø¡H[Q] "); + if (pos == 'v') + { + if (HAS_STATUS(STATUS_BIFF)) + cutmp->status ^= STATUS_BIFF; + + dir = xo->dir; + if ((fd = open(dir, O_RDONLY)) < 0) + return XO_FOOT; + + pos = 0; + mgets(-1); + while (hdr = mread(fd, sizeof(HDR))) + { + if (!(hdr->xmode & MAIL_READ)) + { + hdr->xmode |= MAIL_READ; + rec_put(dir, hdr, sizeof(HDR), pos, NULL); + } + pos++; + } + close(fd); + + return mbox_init(xo); + } + return XO_FOOT; +} + + +static int +mbox_sysop(xo) /* itoc.001029.µù¸Ñ: ¤è«K¦¬ sysop/guest ªº«H */ + XO *xo; +{ + if (xo == (XO *) &cmbox) /* Y¤w¸g¶i¤J²Ä¤G¤H«H½c¡A«h¤£¯à¦A¶i²Ä¤T¤H«H½c */ + { +#ifdef SYSOP_CHECK_MAIL + if (HAS_PERM(PERM_SYSOP)) /* itoc.001029: ¨î¥u¦³ SYSOPs ¥i¥H¬Ý user «H½c */ + { + ACCT acct; + XO *xt; + char fpath[64]; + + if (acct_get(msg_uid, &acct) > 0) + { + alog("¶i¤J«H½c", acct.userid); + usr_fpath(fpath, acct.userid, fn_dir); + xz[XZ_MBOX - XO_ZONE].xo = xt = xo_new(fpath); + xover(XZ_MBOX); + free(xt); + xz[XZ_MBOX - XO_ZONE].xo = xo; + } + return mbox_init(xo); + } +#else + if (HAS_PERM(PERM_ALLADMIN)) /* itoc.030914: Åý©Ò¦³ ADMINs ³£¥i¥H¬Ý sysop/guest «H½c */ + { + char *userid; + XO *xt; + char fpath[64]; + + sprintf(fpath, "¶i¤J (1)%s (2)%s ªº«H½c¡H[1] ", str_sysop, STR_GUEST); + userid = (vans(fpath) == '2') ? STR_GUEST : str_sysop; + alog("¶i¤J«H½c", userid); + usr_fpath(fpath, userid, fn_dir); + xz[XZ_MBOX - XO_ZONE].xo = xt = xo_new(fpath); + xover(XZ_MBOX); + free(xt); + xz[XZ_MBOX - XO_ZONE].xo = xo; + return mbox_init(xo); + } +#endif + } + + return XO_NONE; +} + + +static int +mbox_gem(xo) /* itoc.010727: ±NÓ¤HºëµØ°Ï©M¬ÝªOºëµØ°Ï¾ã¦X */ + XO *xo; +{ + char fpath[64]; + + usr_fpath(fpath, cuser.userid, "gem/"FN_DIR); + /* Ó¤HºëµØ°Ï¤£»Ýn GEM_X_BIT */ + XoGem(fpath, "Ó¤HºëµØ°Ï", GEM_W_BIT | GEM_M_BIT); + return mbox_init(xo); +} + + +static int +mbox_copy(xo) /* itoc.011025: ¨ú¥N gem_gather */ + XO *xo; +{ + int tag; + + tag = AskTag("«H½c¤å³¹«þ¨©"); + + if (tag < 0) + return XO_FOOT; + + gem_buffer(xo->dir, tag ? NULL : (HDR *) xo_pool + (xo->pos - xo->top)); + + zmsg("Àɮ׼аO§¹¦¨¡C[ª`·N] «þ¨©«á¤~¯à§R°£ì¤å¡I"); + return mbox_gem(xo); /* «þ¨©§¹ª½±µ¶iºëµØ°Ï */ +} + + +static int +mbox_help(xo) + XO *xo; +{ + xo_help("mbox"); + return mbox_head(xo); +} + + +static KeyFunc mbox_cb[] = +{ + XO_INIT, mbox_init, + XO_LOAD, mbox_load, + XO_HEAD, mbox_head, + XO_BODY, mbox_body, + + 'r', mbox_browse, + 's', mbox_send, + 'd', mbox_delete, + 'D', mbox_rangedel, + 'x', post_cross, + 'X', mbox_forward, + 'E', mbox_edit, + 'T', mbox_title, + 'm', mbox_mark, + 'R', mbox_reply, + 'y', mbox_reply, + 'v', mbox_visit, + 'w', post_write, /* itoc.010408: ɥΠpost_write §Y¥i */ + + // KEY_TAB, mbox_sysop, /* mp607: ¨S¦b¥Î¤F®³±¼ */ + 'z', mbox_gem, + 'c', mbox_copy, + 'g', gem_gather, + + 't', mbox_tag, + + '~', XoXselect, /* itoc.001220: ·j´M§@ªÌ/¼ÐÃD */ + 'S', XoXsearch, /* itoc.001220: ·j´M¬Û¦P¼ÐÃD¤å³¹ */ + 'a', XoXauthor, /* itoc.001220: ·j´M§@ªÌ */ + '/', XoXtitle, /* itoc.001220: ·j´M¼ÐÃD */ + 'f', XoXfull, /* itoc.030608: ¥þ¤å·j´M */ + 'G', XoXmark, /* itoc.010325: ·j´M mark ¤å³¹ */ + 'i', XoXrestrict, /* chensc.060827: ·j´M¥[±K¤å³¹ */ + 'L', XoXlocal, /* itoc.010822: ·j´M¥»¦a¤å³¹ */ + + Ctrl('D'), mbox_prune, + Ctrl('Q'), xo_uquery, + Ctrl('O'), xo_usetup, + + 'h', mbox_help +}; + + +void +mbox_main() +{ + cmbox.mail_xo.pos = XO_TAIL; + cmbox.mail_xo.xyz = str_site; + usr_fpath(cmbox.dir, cuser.userid, fn_dir); + xz[XZ_MBOX - XO_ZONE].xo = (XO *) &cmbox; + xz[XZ_MBOX - XO_ZONE].cb = mbox_cb; +} + + +KeyFunc xmbox_cb[] = +{ + XO_INIT, xpost_init, + XO_LOAD, xpost_load, + XO_HEAD, xpost_head, + XO_BODY, mbox_body, /* Thor.980911: ¦@¥Î§Y¥i */ + + 'r', xmbox_browse, + 'y', mbox_reply, + 's', mbox_send, + 'x', post_cross, + 'X', post_forward, + 'E', mbox_edit, + 'T', mbox_title, + 'm', mbox_mark, + 'd', mbox_delete, + 'w', post_write, /* itoc.010408: ɥΠpost_write §Y¥i */ + + 'c', mbox_copy, + 'g', gem_gather, + + 't', mbox_tag, + + '~', XoXselect, + 'S', XoXsearch, + 'a', XoXauthor, + '/', XoXtitle, + 'f', XoXfull, + 'G', XoXmark, + 'i', XoXrestrict, + 'L', XoXlocal, + + Ctrl('Q'), xo_uquery, + Ctrl('O'), xo_usetup, + + 'h', mbox_help +}; diff --git a/maple/maple.p b/maple/maple.p new file mode 100644 index 0000000..2a00057 --- /dev/null +++ b/maple/maple.p @@ -0,0 +1,276 @@ +/* acct.c */ +int acct_load(ACCT *acct, char *userid); +void acct_save(ACCT *acct); +int acct_userno(char *userid); +int acct_get(char *msg, ACCT *acct); +void bitmsg(char *msg, char *str, int level); +usint bitset(usint pbits, int count, int maxon, char *msg, char *perms[]); +void acct_show(ACCT *u, int adm); +void acct_setup(ACCT *u, int adm); +void acct_setperm(ACCT *u, usint leveup, usint leveldown); +void addmoney(int addend); +void addgold(int addend); +int brd_new(BRD *brd); +void brd_edit(int bno); +void brd_title(int bno); +void x_file(int mode, char *xlist[], char *flist[]); +int m_trace(void); + +/* bbsd.c */ +void alog(char *mode, char *msg); +void blog(char *mode, char *msg); +void u_exit(char *mode); +void abort_bbs(void); +int belong_list(char *filelist, char *key, char *desc); + +/* bmw.c */ +int can_override(UTMP *up); +int can_see(UTMP *my, UTMP *up); +int bmw_send(UTMP *callee, BMW *bmw); +void bmw_edit(UTMP *up, char *hint, BMW *bmw); +int bmw_reply_CtrlRT(int ch); +void bmw_reply(void); +void bmw_rqst(void); +void do_write(UTMP *up); +void bmw_log(void); +int t_bmw(void); +int t_display(void); + +/* board.c */ +void brh_get(time_t bstamp, int bhno); +int brh_unread(time_t chrono); +void brh_visit(int mode); +int brh_add(time_t prev, time_t chrono, time_t next); +int bstamp2bno(time_t stamp); +void brh_save(void); +void brd_force(void); +void class_item(int num, int bno, int brdpost); +int is_bm(char *list, char *userid); +int XoPost(int bno); +int Select(void); +int Class(void); +void board_main(void); +int Boards(void); +BRD *has_personalbrd (char *bname); +void brd_editlock(const char* fpath); +void brd_viewlock(const char* fpath); +void brd_getlockinfo(const char* fpath, char* type, char* userid, char* reason); +void brd_setlockinfo(const char* fpath, char type, const char* userid, const char* reason); + +/* cache.c */ +void ushm_init(void); +void utmp_mode(int mode); +int utmp_new(UTMP *up); +void utmp_free(UTMP *up); +UTMP *utmp_find(int userno); +UTMP *utmp_get(int userno, char *userid); +UTMP *utmp_seek(HDR *hdr); +void utmp_admset(int userno, usint status); +int utmp_count(int userno, int show); +UTMP *utmp_search(int userno, int order); +void bshm_init(void); +void bshm_reload(void); +int brd_bno(char *bname); +void fshm_init(void); +void film_out(int tag, int row); + +/* edit.c */ +char *tbf_ask(void); +FILE *tbf_open(void); +void ve_backup(void); +void ve_recover(void); +void ve_header(FILE *fp); +void ve_banner(FILE *fp, int modify); +int ve_subject(int row, char *topic, char *dft); +int vedit(char *fpath, int ve_op); + +/* favor.c */ +void mf_fpath(char *fpath, char *userid, char *fname); +int MyFavorite(void); +void XoMF(char *folder); +void mf_main(void); + +/* gem.c */ +int gem_link(char *brdname); +void brd2gem(BRD *brd, HDR *gem); +void gem_buffer(char *dir, HDR *ghdr); +int gem_gather(XO *xo); +void XoGem(char *folder, char *title, int level); +void gem_main(void); + +/* mail.c */ +void ll_new(void); +void ll_add(char *name); +int ll_del(char *name); +int ll_has(char *name); +void ll_out(int row, int column, char *msg); +int bsmtp(char *fpath, char *title, char *rcpt, int method); +int m_zip(void); +int m_verify(void); +usint m_quota(void); +usint m_query(char *userid); +void m_biff(int userno); +void mail_hold(char *fpath, char *rcpt, char *title, int hold); +int mail_external(char *addr); +int mail_send(char *rcpt); +int my_send(char *userid); +int m_send(void); +int m_internet(void); +int m_sysop(void); +void mail_self(char *fpath, char *owner, char *title, usint xmode); +int mail_him(char *fpath, char *rcpt, char *title, usint xmode); +int m_list(void); +int do_mreply(HDR *hdr, int noreply); +int mbox_edit(XO *xo); +void mbox_main(void); + +/* menu.c */ +int pad_view(void); +void vs_head(char *title, char *mid); +void movie(void); +void menu(void); + +/* more.c */ +char *mgets(int fd); +void *mread(int fd, int len); +int more(char *fpath, char *footer); + +/* pal.c */ +int is_mygood(int userno); +int is_mybad(int userno); +int is_ogood(UTMP *up); +int is_obad(UTMP *up); +int is_bgood(BPAL *bpal); +int is_bbad(BPAL *bpal); +int image_pal(char *fpath, int *pool); +void pal_cache(void); +void pal_sync(char *fpath); +int pal_list(int reciper); +void pal_edit(int key, PAL *pal, int echo); +int pal_find(char *fpath, int userno); +int t_pal(void); +int t_list(void); + +/* post.c */ +int cmpchrono(HDR *hdr); +void btime_update(int bno); +void cancel_post(HDR *hdr); +void add_post(char *brdname, char *fpath, char *title); +int do_reply(XO *xo, HDR *hdr); +int tag_char(int chrono); +void hdr_outs(HDR *hdr, int cc); +int post_edit(XO *xo); +void header_replace(XO *xo, HDR *fhdr); +int post_cross(XO *xo); +int post_forward(XO *xo); +int post_write(XO *xo); +int post_score(XO *xo); +void do_binfo(BRD* brd); + +/* talk.c */ +char *bmode(UTMP *up, int simple); +void frienz_sync(char *fpath); +void aloha(); +void loginNotify(); +void my_query(char *userid); +int t_loginNotify(void); +void loginNotify(void); +int talk_page(UTMP *up); +int t_pager(void); +int t_cloak(void); +int t_query(void); +int t_talk(void); +void talk_rqst(void); + +/* ulist.c */ +void talk_main(void); + +/* user.c */ +void justify_log(char *userid, char *justify); +int u_addr(void); +int u_register(void); +int u_verify(void); +int u_deny(void); +int u_info(void); +int u_setup(void); +int u_lock(void); +int u_log(void); +int u_xfile(void); + +/* visio.c */ +int is_zhc_low(char *str, int pos); +void prints(char *fmt, ...); +void bell(void); +void move(int x, int y); +void refresh(void); +void clear(void); +void clrtoeol(void); +void clrtobot(void); +void outc(int ch); +void outs(uschar *str); +void outx(uschar *str); +void outz(uschar *str); +void outf(uschar *str); +void scroll(void); +void rscroll(void); +void cursor_save(void); +void cursor_restore(void); +void save_foot(screenline *slp); +void restore_foot(screenline *slp, int line); +int vs_save(screenline *slp); +void vs_restore(screenline *slp); +int vmsg(char *msg); +void zmsg(char *msg); +void vs_bar(char *title); +void vio_save(void); +void vio_restore(void); +int vio_holdon(void); +void add_io(int fd, int timeout); +int igetch(void); +BRD *ask_board(char *board, int perm, char *msg); +int vget(int line, int col, uschar *prompt, uschar *data, int max, int echo); +int vans(char *prompt); +int vkey(void); + +/* window.c */ +int pans(int x, int y, char *title, char **desc); +int pmsg(char *msg); + +/* xover.c */ +XO *xo_new(char *path); +XO *xo_get(char *path); +XO *xo_get_post(char *path, BRD *brd); +void xo_load(XO *xo, int recsiz); +int xo_rangedel(XO *xo, int size, int (*fchk) (), void (*fdel) ()); +int Tagger(time_t chrono, int recno, int op); +void EnumTag(void *data, char *dir, int locus, int size); +int AskTag(char *msg); +int xo_prune(XO *xo, int size, int (*fvfy) (), void (*fdel) ()); +int xo_uquery(XO *xo); +int xo_usetup(XO *xo); +int xo_getch(XO *xo, int ch); +void xover(int cmd); +int every_Z(int zone); +int every_U(int zone); +int xo_cursor(int ch, int pagemax, int num, int *pageno, int *pos, int *redraw); +void xo_help(char *path); + +/* xpost.c */ +int xpost_head(XO *xo); +int xpost_init(XO *xo); +int xpost_load(XO *xo); +int xpost_browse(XO *xo); +int xmbox_browse(XO *xo); +int XoXselect(XO *xo); +int XoXsearch(XO *xo); +int XoXauthor(XO *xo); +int XoXtitle(XO *xo); +int XoXfull(XO *xo); +int XoXmark(XO *xo); +int XoXrestrict(XO *xo); +int XoXscore(XO *xo); +int XoXlocal(XO *xo); +int news_head(XO *xo); +int news_init(XO *xo); +int news_load(XO *xo); +int XoNews(XO *xo); diff --git a/maple/menu.c b/maple/menu.c new file mode 100644 index 0000000..3beed19 --- /dev/null +++ b/maple/menu.c @@ -0,0 +1,1287 @@ +/*-------------------------------------------------------*/ +/* menu.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : menu/help/movie routines */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +extern UCACHE *ushm; +extern FCACHE *fshm; + + +#ifndef ENHANCED_VISIT +extern time_t brd_visit[]; +#endif + + +/* ----------------------------------------------------- */ +/* Â÷¶} BBS ¯¸ */ +/* ----------------------------------------------------- */ + + +#define FN_RUN_NOTE_PAD "run/note.pad" +#define FN_RUN_NOTE_TMP "run/note.tmp" + + +typedef struct +{ + time_t tpad; + char msg[400]; +} Pad; + + +int +pad_view() +{ + int fd, count; + Pad *pad; + + if ((fd = open(FN_RUN_NOTE_PAD, O_RDONLY)) < 0) + return XEASY; + + count = 0; + mgets(-1); + + for (;;) + { + pad = mread(fd, sizeof(Pad)); + if (!pad) + { + vmsg(NULL); + break; + } + else if (!(count % 5)) /* itoc.020122: ¦³ pad ¤~¦L */ + { + clear(); + move(0, 23); + prints("¡i »Ä ²¢ W »¶ ¯d ¨¥ ªO ¡j ²Ä %d ¶\n\n", count / 5 + 1); + } + + outs(pad->msg); + count++; + + if (!(count % 5)) + { + move(b_lines, 0); + outs("½Ð«ö [SPACE] Ä~ÄòÆ[½à¡A©Î«ö¨ä¥LÁäµ²§ô¡G "); + /* itoc.010127: ×¥¿¦b°»´ú¥ª¥kÁä¥þ§Î¤U¡A«ö¥ªÁä·|¸õÂ÷¤G¼h¿ï³æªº°ÝÃD */ + + if (vkey() != ' ') + break; + } + } + + close(fd); + return 0; +} + + +static int +pad_draw() +{ + int i, cc, fdr, color; + FILE *fpw; + Pad pad; + char *str, buf[3][71]; + + /* itoc.µù¸Ñ: ¤£·Q¥Î°ª±m«×¡A¤Óªá */ + static char pcolors[6] = {31, 32, 33, 34, 35, 36}; + + /* itoc.010309: ¯d¨¥ªO´£¨Ñ¤£¦PªºÃC¦â */ + color = vans("¤ß±¡ÃC¦â 1) \033[41m \033[m 2) \033[42m \033[m 3) \033[43m \033[m " + "4) \033[44m \033[m 5) \033[45m \033[m 6) \033[46m \033[m [Q] "); + + if (color < '1' || color > '6') + return XEASY; + else + color -= '1'; + + do + { + buf[0][0] = buf[1][0] = buf[2][0] = '\0'; + move(MENU_XPOS, 0); + clrtobot(); + outs("\n½Ð¯d¨¥ (¦Ü¦h¤T¦æ)¡A«ö[Enter]µ²§ô"); + for (i = 0; (i < 3) && + vget(16 + i, 0, "¡G", buf[i], 71, DOECHO); i++); + cc = vans("(S)¦sÀÉÆ[½à (E)«·s¨Ó¹L (Q)ºâ¤F¡H[S] "); + if (cc == 'q' || i == 0) + return 0; + } while (cc == 'e'); + + time(&pad.tpad); + + /* itoc.020812.µù¸Ñ: §ïª©±ªº®ÉÔnª`·N struct Pad.msg[] ¬O§_°÷¤j */ + str = pad.msg; + sprintf(str, "¢~¢t\033[1;46m %s ¡Ð %s \033[m¢u", cuser.userid, cuser.username); + + for (cc = strlen(str); cc < 60; cc += 2) + strcpy(str + cc, "¢w"); + if (cc == 60) + str[cc++] = ' '; + + sprintf(str + cc, + "\033[1;44m %s \033[m¢¡\n" + "¢x \033[1;%dm%-70s\033[m ¢x\n" + "¢x \033[1;%dm%-70s\033[m ¢x\n" + "¢¢ \033[1;%dm%-70s\033[m ¢£\n", + Btime(&pad.tpad), + pcolors[color], buf[0], + pcolors[color], buf[1], + pcolors[color], buf[2]); + + f_cat(FN_RUN_NOTE_ALL, str); + + if (!(fpw = fopen(FN_RUN_NOTE_TMP, "w"))) + return 0; + + fwrite(&pad, sizeof(pad), 1, fpw); + + if ((fdr = open(FN_RUN_NOTE_PAD, O_RDONLY)) >= 0) + { + Pad *pp; + + i = 0; + cc = pad.tpad - NOTE_DUE * 60 * 60; + mgets(-1); + while (pp = mread(fdr, sizeof(Pad))) + { + fwrite(pp, sizeof(Pad), 1, fpw); + if ((++i > NOTE_MAX) || (pp->tpad < cc)) + break; + } + close(fdr); + } + + fclose(fpw); + + rename(FN_RUN_NOTE_TMP, FN_RUN_NOTE_PAD); + pad_view(); + return 0; +} + + +static int +goodbye() +{ + /* itoc.010803: ¨q±iÂ÷¯¸ªº¹Ï */ + clear(); + film_out(FILM_GOODBYE, 0); + + switch (vans("G)ÀH·¦Ó³u M)³ø§i¯¸ªø N)¯d¨¥ªO Q)¨ú®ø¡H[Q] ")) + { + /* lkchu.990428: ¤º©w§ï¬°¤£Â÷¯¸ */ + case 'g': + case 'y': + break; + + case 'm': + m_sysop(); + break; + + case 'n': + /* if (cuser.userlevel) */ + if (HAS_PERM(PERM_POST)) /* Thor.990118: n¯àpost¤~¯à¯d¨¥, ´£°ªªùÂe */ + pad_draw(); + break; + + case 'q': + default: + /* return XEASY; */ + return 0; /* itoc.010803: ¨q¤F FILM_GOODBYE n«Ã¸ */ + } + +#ifdef LOG_BMW + bmw_log(); /* lkchu.981201: ¤ô²y°O¿ý³B²z */ +#endif + + if (!(cuser.ufo & UFO_MOTD)) /* itoc.000407: Â÷¯¸µe±¤@¨Ö²¤Æ */ + { + clear(); + prints("¿Ë·Rªº \033[32m%s(%s)\033[m¡A§O§Ñ¤F¦A«×¥úÁ{¡i %s ¡j\n" + "¥H¤U¬O±z¦b¯¸¤ºªºµù¥U¸ê®Æ¡G\n", + cuser.userid, cuser.username, str_site); + acct_show(&cuser, 0); + vmsg(NULL); + } + + u_exit("EXIT "); + exit(0); +} + + +/* ----------------------------------------------------- */ +/* help & menu processring */ +/* ----------------------------------------------------- */ + + +void +vs_head(title, mid) + char *title, *mid; +{ + char buf[40], ttl[60]; + static char fcheck[64]; + int spc, len; + + if (mid) /* xxxx_head() ³£¬O¥Î vs_head(title, str_site); */ + { + clear(); + } + else /* menu() ¤¤¤~¥Î vs_head(title, NULL); ¿ï³æ¤¤µL»Ý clear() */ + { + move(0, 0); + clrtoeol(); + mid = str_site; + } + + len = d_cols + 69 - strlen(title) - strlen(currboard); + + if (!fcheck[0]) + usr_fpath(fcheck, cuser.userid, FN_PAYCHECK); + + if (HAS_STATUS(STATUS_BIFF)) + { + mid = "\033[5;41m ¶l®t¨Ó«ö¹a¤F \033[m"; + spc = 14; + } + else if (dashf(fcheck)) + { + mid = "\033[5;43m ±z¦³·s¤ä²¼³á \033[m"; + spc = 14; + } + else if (HAS_PERM(PERM_ALLREG) && + rec_num(FN_RUN_RFORM, sizeof(RFORM))) + { + mid = "\033[5;41m ¦³¤H¶ñµù¥U³æ \033[m"; + spc = 14; + } + else + { + if ((spc = strlen(mid)) > len) + { + spc = len; + memcpy(ttl, mid, spc); + mid = ttl; + mid[spc] = '\0'; + } + } + + spc = 2 + len - spc; + len = 1 - spc & 1; + memset(buf, ' ', spc >>= 1); + buf[spc] = '\0'; + +#ifdef COLOR_HEADER + spc = (time(0) % 7) + '1'; + prints("\033[1;4%cm¡i%s¡j%s\033[33m%s\033[1;37;4%cm%s¡m%s¡n\033[m\n", + spc, title, buf, mid, spc, buf + len, currboard); +#else + prints("\033[1;42m¡i%s¡j%s\033[33m%s\033[1;37;42m%s¡m%s¡n\033[m\n", + title, buf, mid, buf + len, currboard); +#endif +} + + +/* ------------------------------------- */ +/* °Êµe³B²z */ +/* ------------------------------------- */ + + +static char feeter[160]; + + +/* itoc.010403: §â feeter ªº status ¿W¥ß¥X¨Ó¡A¹w³Æ¨Ñ¨ä¥L function ¥s¥Î */ + +static void +status_foot() +{ + static int orig_flag = -1; + static time_t uptime = -1; + static int orig_money = -1; + static int orig_gold = -1; + static char flagmsg[16]; + static char coinmsg[20]; + + int ufo; + time_t now; + + ufo = cuser.ufo; + time(&now); + + /* Thor: ¦P®É Åã¥Ü ©I¥s¾¹ ¤W¯¸³qª¾ Áô¨ */ + +#ifdef HAVE_ALOHA + ufo &= UFO_PAGER | UFO_ALOHA | UFO_CLOAK | UFO_QUIET; + if (orig_flag != ufo) + { + orig_flag = ufo; + sprintf(flagmsg, + "%s%s%s%s", + (ufo & UFO_PAGER) ? "Ãö" : "¶}", + (ufo & UFO_ALOHA) ? "¤W" : " ", + (ufo & UFO_QUIET) ? "ÀR" : " ", + (ufo & UFO_CLOAK) ? "Áô" : " "); + } +#else + ufo &= UFO_PAGER | UFO_CLOAK | UFO_QUIET; + if (orig_flag != ufo) + { + orig_flag = ufo; + sprintf(flagmsg, + "%s%s%s ", + (ufo & UFO_PAGER) ? "Ãö" : "¶}", + (ufo & UFO_QUIET) ? "ÀR" : " ", + (ufo & UFO_CLOAK) ? "Áô" : " "); + } +#endif + + if (now > uptime) /* ¹L¤F¤l©]n§ó·s¥Í¤éºX¼Ð */ + { + struct tm *ptime; + + ptime = localtime(&now); + + if (cuser.day == ptime->tm_mday && cuser.month == ptime->tm_mon + 1) + cutmp->status |= STATUS_BIRTHDAY; + else + cutmp->status &= ~STATUS_BIRTHDAY; + + uptime = now + 86400 - ptime->tm_hour * 3600 - ptime->tm_min * 60 - ptime->tm_sec; + } + + if (cuser.money != orig_money) + { + orig_money = cuser.money; + sprintf(coinmsg, "»È%4d%c", + (orig_money & 0x7FF00000) ? (orig_money >> 20) : (orig_money & 0x7FFFFC00) ? (orig_money >> 10) : orig_money, + (orig_money & 0x7FF00000) ? 'M' : (orig_money & 0x7FFFFC00) ? 'K' : ' '); + coinmsg[7] = ' '; + } + if (cuser.gold != orig_gold) + { + orig_gold = cuser.gold; + sprintf(coinmsg + 8, "ª÷%4d%c ", + (orig_gold & 0x7FF00000) ? (orig_gold >> 20) : (orig_gold & 0x7FFFFC00) ? (orig_gold >> 10) : orig_gold, + (orig_gold & 0x7FF00000) ? 'M' : (orig_gold & 0x7FFFFC00) ? 'K' : ' '); + } + + /* Thor.980913.µù¸Ñ: ³Ì±`¨£©I¥s status_foot() ªº®É¾÷¬O¨C¦¸§ó·s film¡A¦b 60 ¬í¥H¤W¡A + ¬G¤£»Ý°w¹ï hh:mm ¨Ó¯S§O§@¤@¦r¦êÀx¦s¥H¥[³t */ + + ufo = (now - (uptime - 86400)) / 60; /* ɥΠufo ¨Ó°µ®É¶¡(¤À) */ + + /* itoc.010717: §ï¤@¤U feeter ¨Ïªø«×©M FEETER_XXX ¤@P */ + sprintf(feeter, COLOR1 " %8.8s %02d:%02d " COLOR2 " ¤H¼Æ %-4d §Ú¬O %-12s %s [©I¥s]%-9s ", + fshm->today, ufo / 60, ufo % 60, total_user, cuser.userid, coinmsg, flagmsg); + outf(feeter); +} + + +void +movie() +{ + /* Thor: it is depend on which state */ + + if ((bbsmode <= M_XMENU) && (cuser.ufo & UFO_MOVIE)) + film_out(FILM_MOVIE, MENU_XNOTE); + + /* itoc.010403: §â feeter ªº status ¿W¥ß¥X¨Ó */ + status_foot(); +} + + +typedef struct +{ + void *func; + /* int (*func) (); */ + usint level; + int umode; + char *desc; +} MENU; + + +#define MENU_LOAD 1 +#define MENU_DRAW 2 +#define MENU_FILM 4 + + +#define PERM_MENU PERM_PURGE + + +static MENU menu_main[]; + + +/* ----------------------------------------------------- */ +/* administrator's maintain menu */ +/* ----------------------------------------------------- */ + + +static MENU menu_admin[] = +{ + "bin/admutil.so:a_user", PERM_ALLACCT, - M_SYSTEM, + "User ¢« ÅU«È¸ê®Æ ¢¨", + + "bin/admutil.so:a_search", PERM_ALLACCT, - M_SYSTEM, + "Hunt ¢« ·j´M¤ÞÀº ¢¨", + + "bin/admutil.so:a_editbrd", PERM_ALLBOARD, - M_SYSTEM, + "QSetBoard ¢« ³]©w¬ÝªO ¢¨", + + "bin/innbbs.so:a_innbbs", PERM_ALLBOARD, - M_SYSTEM, + "InnBBS ¢« Âà«H³]©w ¢¨", + +#ifdef HAVE_REGISTER_FORM + "bin/admutil.so:a_register", PERM_ALLREG, - M_SYSTEM, + "Register ¢« ¼fµù¥U³æ ¢¨", + + "bin/admutil.so:a_regmerge", PERM_ALLREG, - M_SYSTEM, + "Merge ¢« ´_ì¼f®Ö ¢¨", +#endif + + "bin/admutil.so:a_xfile", PERM_SYSOP, - M_XFILES, + "Xfile ¢« ¨t²ÎÀÉ®× ¢¨", + + "bin/admutil.so:a_resetsys", PERM_ALLADMIN, - M_SYSTEM, + "BBSreset ¢« «¸m¨t²Î ¢¨", + + "bin/admutil.so:a_restore", PERM_SYSOP, - M_SYSTEM, + "TRestore ¢« ÁÙì³Æ¥÷ ¢¨", + + "bin/admutil.so:a_sysload", PERM_ALLADMIN, -M_SYSTEM, + "Load ¢« ¨t²Ît¸ü ¢¨", + + menu_main, PERM_MENU + Ctrl('A'), M_AMENU, + "¨t²ÎºûÅ@" +}; + + +/* ----------------------------------------------------- */ +/* mail menu */ +/* ----------------------------------------------------- */ + + +static int +XoMbox() +{ + xover(XZ_MBOX); + return 0; +} + + +static MENU menu_mail[] = +{ + XoMbox, PERM_BASIC, M_RMAIL, + "Read ¢u ¾\\Ū«H¥ó ¢t", + + m_send, PERM_LOCAL, M_SMAIL, + "Mail ¢u ¯¸¤º±H«H ¢t", + +#ifdef MULTI_MAIL /* Thor.981009: ¨¾¤î·R±¡©¯¹B«H */ + m_list, PERM_LOCAL, M_SMAIL, + "List ¢u ¸s²Õ±H«H ¢t", +#endif + + m_internet, PERM_INTERNET, M_SMAIL, + "Internet ¢u ±H¨Ì©f¨à ¢t", + +#ifdef HAVE_SIGNED_MAIL + m_verify, 0, M_XMODE, + "Verify ¢u ÅçÃÒ«H¥ó ¢t", +#endif + +#ifdef HAVE_MAIL_ZIP + m_zip, PERM_INTERNET, M_SMAIL, + "Zip ¢u ¥´¥]¸ê®Æ ¢t", +#endif + + m_sysop, 0, M_SMAIL, + "Yes Sir! ¢u §ë®Ñ¯¸ªø ¢t", + + "bin/admutil.so:m_bm", PERM_ALLADMIN, - M_SMAIL, + "BM All ¢u ªO¥D³q§i ¢t", /* itoc.000512: ·s¼W m_bm */ + + "bin/admutil.so:m_all", PERM_ALLADMIN, - M_SMAIL, + "User All ¢u ¥þ¯¸³q§i ¢t", /* itoc.000512: ·s¼W m_all */ + + menu_main, PERM_MENU + Ctrl('A'), M_MMENU, /* itoc.020829: ©È guest ¨S¿ï¶µ */ + "¹q¤l¶l¥ó" +}; + + +/* ----------------------------------------------------- */ +/* talk menu */ +/* ----------------------------------------------------- */ + + +static int +XoUlist() +{ + xover(XZ_ULIST); + return 0; +} + + +static MENU menu_talk[]; + + + /* --------------------------------------------------- */ + /* list menu */ + /* --------------------------------------------------- */ + +static MENU menu_list[] = +{ + t_pal, PERM_BASIC, M_PAL, + "Pal ¡÷ ªB¤Í¦W³æ ¡ö", + +#ifdef HAVE_LIST + t_list, PERM_BASIC, M_PAL, + "List ¡÷ ¯S§O¦W³æ ¡ö", +#endif + +#ifdef HAVE_ALOHA + "bin/aloha.so:t_aloha", PERM_PAGE, - M_PAL, + "Aloha ¡÷ ¤W¯¸³qª¾ ¡ö", +#endif + +#ifdef LOGIN_NOTIFY + t_loginNotify, PERM_PAGE, M_PAL, + "Notify ¡÷ ¨t²Î¨ó´M ¡ö", +#endif + + menu_talk, PERM_MENU + 'P', M_TMENU, + "¦UÃþ¦W³æ" +}; + + +static MENU menu_talk[] = +{ + XoUlist, 0, M_LUSERS, + "Users ¡÷ ¹C«È¦W³æ ¡ö", + + menu_list, PERM_BASIC, M_TMENU, + "ListMenu ¡÷ ³]©w¦W³æ ¡ö", + + t_pager, PERM_BASIC, M_XMODE, + "Pager ¡÷ ¤Á´«©I¥s ¡ö", + + t_cloak, PERM_CLOAK, M_XMODE, + "Invis ¡÷ Áô¨±Kªk ¡ö", + + t_query, 0, M_QUERY, + "Query ¡÷ ¬d¸ßºô¤Í ¡ö", + + t_talk, PERM_PAGE, M_PAGE, + "Talk ¡÷ ±¡¸Üºøºø ¡ö", + + /* Thor.990220: §ï±Ä¥~±¾ */ + "bin/chat.so:t_chat", PERM_CHAT, - M_CHAT, + "ChatRoom ¡÷ ²³¤fÅàª÷ ¡ö", + + t_display, PERM_BASIC, M_BMW, + "Display ¡÷ ÂsÄý¤ô²y ¡ö", + + t_bmw, PERM_BASIC, M_BMW, + "Write ¡÷ ¦^ÅU¤ô²y ¡ö", + + menu_main, PERM_MENU + 'U', M_TMENU, + "¥ð¶¢²á¤Ñ" +}; + + +/* ----------------------------------------------------- */ +/* user menu */ +/* ----------------------------------------------------- */ + + +static MENU menu_user[]; + + + /* --------------------------------------------------- */ + /* register menu */ + /* --------------------------------------------------- */ + +static MENU menu_register[] = +{ +// u_addr, PERM_BASIC, M_XMODE, +// "Address ¡m ¹q¤l«H½c ¡n", + + +#ifdef HAVE_REGISTER_FORM + u_register, PERM_BASIC, M_UFILES, + "Register ¡m ¶ñµù¥U³æ ¡n", +#endif + +#ifdef HAVE_REGKEY_CHECK +// u_verify, PERM_BASIC, M_UFILES, +// "Verify ¡m ¶ñ»{ÃÒ½X ¡n", +#endif + + u_deny, PERM_BASIC, M_XMODE, + "Perm ¡m «ì´_Åv ¡n", + + menu_user, PERM_MENU + 'R', M_UMENU, + "µù¥U¿ï³æ" +}; + + +static MENU menu_user[] = +{ +// "bin/dict.so:main_yahoo", 0, -M_XMODE, +// "Dictionary ¡m ^º~¦r¨å ¡n", + + u_info, PERM_BASIC, M_XMODE, + "Info ¡m Ó¤H¸ê®Æ ¡n", + + u_setup, 0, M_UFILES, + "Habit ¡m ³ß¦n¼Ò¦¡ ¡n", + + menu_register, PERM_BASIC, M_UMENU, + "Register ¡m µù¥U¿ï³æ ¡n", + + pad_view, 0, M_READA, + "Note ¡m Æ[¬Ý¯d¨¥ ¡n", + + /* itoc.010309: ¤£¥²Â÷¯¸¥i¥H¼g¯d¨¥ªO */ + pad_draw, PERM_POST, M_POST, + "Pad ¡m ¤ß±¡¶î¾~ ¡n", + + u_lock, PERM_BASIC, M_IDLE, + "Lock ¡m Âê©w¿Ã¹õ ¡n", + + u_xfile, PERM_BASIC, M_UFILES, + "Xfile ¡m Ó¤HÀÉ®× ¡n", + + u_log, PERM_BASIC, M_UFILES, + "ViewLog ¡m ¤W¯¸°O¿ý ¡n", + + menu_main, PERM_MENU + 'H', M_UMENU, + "Ó¤H³]©w" +}; + + +#ifdef HAVE_EXTERNAL + +/* ----------------------------------------------------- */ +/* tool menu */ +/* ----------------------------------------------------- */ + + +static MENU menu_tool[]; + + +#ifdef HAVE_SONG + /* --------------------------------------------------- */ + /* song menu */ + /* --------------------------------------------------- */ + +static MENU menu_song[] = +{ + "bin/song.so:XoSongLog", 0, - M_XMODE, + "KTV ¡ñ ÂIºq¬ö¿ý ¡ð", + + "bin/song.so:XoSongMain", 0, - M_XMODE, + "Book ¡ñ °Û©Ò±ý¨¥ ¡ð", + + "bin/song.so:XoSongSub", 0, - M_XMODE, + "Note ¡ñ ºq¥»§ë½Z ¡ð", + + menu_tool, PERM_MENU + 'K', M_XMENU, + "ª±ÂIºq¾÷" +}; +#endif + + +#ifdef HAVE_GAME + +#if 0 + + itoc.010426.µù¸Ñ: + ¯q´¼¹CÀ¸¤£¥Î½äª÷¨î«×¡AÅýª±®aª±¦nª±ªº¡A¥u¥[¿ú¡A¤£´î¿ú¡C + + itoc.010714.µù¸Ñ: + (a) ¨C¦¸ª±¹CÀ¸ªºÁ`´Á±æÈÀ³¦b 1.01¡A¤@ӱߤW¬ù¥iª± 100 ¦¸¹CÀ¸¡A + Y±NÁ`°]²£§ë¤J¥hª±¹CÀ¸¡A«h 1.01^100 = 2.7 ¿/¨Cª±¤@ӱߤW¡C + (b) Y¦U¶µ¾÷²v¤£§¡µ¥¡A¤]À³ºû«ù¦b 1.0 ~ 1.02 ¤§¶¡¡AÅýª±®a¤@©w¯àÁÈ¿ú¡A + ¥BY¤@ª½©ã³Ì°ª´Á±æÈªº¨º¤@¶µ¡A¤]¤£·|Áȱo¹L©óÂ÷ÃСC + (c) ì«h¤W¡A¾÷²v¶V§CªÌ¨ä´Á±æÈÀ³¬° 1.02¡A¾÷²v¸û°ªªÌ¨ä´Á±æÈÀ³¬° 1.01¡C + + itoc.011011.µù¸Ñ: + ¬°¤FÁ×§K user multi-login ª±¨Ó¬~¿ú¡A + ©Ò¥H¦bª±¹CÀ¸ªº¶}©l´NnÀˬd¬O§_«ÂÐ login §Y if (HAS_STATUS(STATUS_COINLOCK))¡C + +#endif + + /* --------------------------------------------------- */ + /* game menu */ + /* --------------------------------------------------- */ + +static MENU menu_game[]; + +static MENU menu_game1[] = +{ + "bin/liteon.so:main_liteon", 0, - M_GAME, + "0LightOn ¡ñ ©Ð¶¡¶}¿O ¡ð", + + "bin/guessnum.so:guessNum", 0, - M_GAME, + "1GuessNum ¡ñ ª±²q¼Æ¦r ¡ð", + + "bin/guessnum.so:fightNum", 0, - M_GAME, + "2FightNum ¡ñ ¤¬²q¼Æ¦r ¡ð", + + "bin/km.so:main_km", 0, - M_GAME, + "3KongMing ¡ñ ¤Õ©ú´ÑÃÐ ¡ð", + + "bin/recall.so:main_recall", 0, - M_GAME, + "4Recall ¡ñ ¦^¾Ð¤§§Z ¡ð", + + "bin/mine.so:main_mine", 0, - M_GAME, + "5Mine ¡ñ ¶Ã½ò¦a¹p ¡ð", + + "bin/fantan.so:main_fantan", 0, - M_GAME, + "6Fantan ¡ñ µfÅu±µÀs ¡ð", + + "bin/dragon.so:main_dragon", 0, - M_GAME, + "7Dragon ¡ñ ±µÀs¹CÀ¸ ¡ð", + + "bin/nine.so:main_nine", 0, - M_GAME, + "8Nine ¡ñ ¤Ñ¦a¤E¤E ¡ð", + + menu_game, PERM_MENU + '0', M_XMENU, + "¯q´¼ªÅ¶¡" +}; + +static MENU menu_game2[] = +{ + "bin/dice.so:main_dice", 0, - M_GAME, + "0Dice ¡ñ ¨gÂY»ë¤l ¡ð", + + "bin/gp.so:main_gp", 0, - M_GAME, + "1GoldPoker ¡ñ ª÷µP¼³§J ¡ð", + + "bin/bj.so:main_bj", 0, - M_GAME, + "2BlackJack ¡ñ ¤G¤Q¤@ÂI ¡ð", + + "bin/chessmj.so:main_chessmj", 0, - M_GAME, + "3ChessMJ ¡ñ ¶H´Ñ³Â±N ¡ð", + + "bin/seven.so:main_seven", 0, - M_GAME, + "4Seven ¡ñ ½ä«°¤C±i ¡ð", + + "bin/race.so:main_race", 0, - M_GAME, + "5Race ¡ñ ¶iÁɰ¨³õ ¡ð", + + "bin/bingo.so:main_bingo", 0, - M_GAME, + "6Bingo ¡ñ »«ªG¤j¾Ô ¡ð", + + "bin/marie.so:main_marie", 0, - M_GAME, + "7Marie ¡ñ ¤j¤pº¿²ú ¡ð", + + "bin/bar.so:main_bar", 0, - M_GAME, + "8Bar ¡ñ §a¥xº¿²ú ¡ð", + + menu_game, PERM_MENU + '0', M_XMENU, + "¹CÀ¸¼Ö¶é" +}; + +static MENU menu_game3[] = +{ + "bin/pip.so:main_pip", PERM_BASIC, - M_GAME, + "0Chicken ¡ñ ¹q¤l¤pÂû ¡ð", + + "bin/pushbox.so:main_pushbox", 0, - M_GAME, + "1PushBox ¡ñ Ü®wµfµf ¡ð", + + "bin/tetris.so:main_tetris", 0, - M_GAME, + "2Tetris ¡ñ «Xù´µ¶ô ¡ð", + + "bin/gray.so:main_gray", 0, - M_GAME, + "3Gray ¡ñ ²L¦Ç¤j¾Ô ¡ð", + + menu_game, PERM_MENU + '0', M_XMENU, + "¤Ï¤æ¯S°Ï" +}; + +static MENU menu_game[] = +{ + menu_game1, PERM_BASIC, M_XMENU, + "1Game ¡i ¯q´¼¤Ñ°ó ¡j", + + menu_game2, PERM_BASIC, M_XMENU, + "2Game ¡i ¹CÀ¸¼Ö¶é ¡j", + + menu_game3, PERM_BASIC, M_XMENU, + "3Game ¡i ¤Ï¤æ¯S°Ï ¡j", + + menu_tool, PERM_MENU + '1', M_XMENU, + "¹CÀ¸¤H¥Í" +}; +#endif + + +#ifdef HAVE_BUY + /* --------------------------------------------------- */ + /* buy menu */ + /* --------------------------------------------------- */ + +static MENU menu_buy[] = +{ + "bin/bank.so:x_bank", PERM_BASIC, - M_GAME, + "Bank ¡ñ «H°U»È¦æ ¡ð", + + "bin/bank.so:b_invis", PERM_BASIC, - M_GAME, + "Invis ¡ñ Áô§Î²{¨ ¡ð", + +// "bin/bank.so:b_cloak", PERM_BASIC, - M_GAME, +// "Cloak ¡ñ µLÁô§Î ¡ð", + + "bin/bank.so:b_changeid", PERM_BASIC, - M_GAME, + "ModifyID ¡ñ ¥i¥H§ïID ¡ð", + + + "bin/bank.so:b_mbox", PERM_BASIC, - M_GAME, + "Mbox ¡ñ «H½cµL ¡ð", + + "bin/bank.so:b_xempt", PERM_BASIC, - M_GAME, + "Xempt ¡ñ ¥Ã¤[«O¯d ¡ð", + + menu_tool, PERM_MENU + 'B', M_XMENU, + "ª÷¿Ä¥«³õ" +}; +#endif + + + /* --------------------------------------------------- */ + /* other tools menu */ + /* --------------------------------------------------- */ + +static MENU menu_other[] = +{ + "bin/vote.so:vote_all", PERM_BASIC, - M_VOTE, /* itoc.010414: §ë²¼¤¤¤ß */ + "VoteAll ¡ñ §ë²¼¤¤¤ß ¡ð", + +#ifdef HAVE_TIP + "bin/xyz.so:x_tip", 0, - M_READA, + "Tip ¡ñ ±Ð¾ÇºëÆF ¡ð", +#endif + +#ifdef HAVE_LOVELETTER + "bin/xyz.so:x_loveletter", 0, - M_READA, + "LoveLetter ¡ñ ±¡®Ñ¼¶¼g ¡ð", +#endif + + "bin/xyz.so:x_password", PERM_VALID, - M_XMODE, + "Password ¡ñ §Ñ°O±K½X ¡ð", + +#ifdef HAVE_CLASSTABLE + "bin/classtable.so:main_classtable", PERM_BASIC, - M_XMODE, + "ClassTable ¡ñ ¥\\½Ò®É¬q ¡ð", +#endif + +#ifdef HAVE_CREDIT + "bin/credit.so:main_credit", PERM_BASIC, - M_XMODE, + "MoneyNote ¡ñ °O±b¤â¥¾ ¡ð", +#endif + +#ifdef HAVE_CALENDAR + "bin/todo.so:main_todo", PERM_BASIC, - M_XMODE, + "XTodo ¡ñ Ó¤H¦æµ{ ¡ð", + + "bin/calendar.so:main_calendar", 0, - M_XMODE, + "YCalendar ¡ñ ¸U¦~¤ë¾ä ¡ð", +#endif + + menu_tool, PERM_MENU + Ctrl('A'), M_XMENU, /* itoc.020829: ©È guest ¨S¿ï¶µ */ + "¨ä¥L¥\\¯à" +}; + + +static MENU menu_tool[] = +{ +#ifdef HAVE_SONG + menu_song, 0, M_XMENU, + "KTV ¡i ¯u±¡ÂIºq ¡j", +#endif + +#ifdef HAVE_COSIGN + "bin/newbrd.so:XoNewBoard", PERM_VALID, - M_XMODE, + "Join ¡i ¬ÝªO³s¸p ¡j", +#endif + +#ifdef HAVE_GAME + menu_game, PERM_BASIC, M_XMENU, + "Game ¡i ¹CÀ¸¤H¥Í ¡j", +#endif + +#ifdef HAVE_BUY + menu_buy, PERM_BASIC, M_XMENU, + "Market ¡i ª÷¿Ä¥«³õ ¡j", +#endif + + menu_other, 0, M_XMENU, + "Other ¡i Âø¤CÂø¤K ¡j", + + menu_main, PERM_MENU + Ctrl('A'), M_XMENU, /* itoc.020829: ©È guest ¨S¿ï¶µ */ + "Ó¤H¤u¨ã" +}; + +#endif /* HAVE_EXTERNAL */ + + +/* ----------------------------------------------------- */ +/* main menu */ +/* ----------------------------------------------------- */ + + +static int +Gem() +{ + /* itoc.001109: ¬ÝªOÁ`ºÞ¦b (A)nnounce ¤U¦³ GEM_X_BIT¡A¤è«K¶}ªO */ + XoGem("gem/"FN_DIR, "ºëµØ§G§iÄæ", (HAS_PERM(PERM_ALLBOARD) ? (GEM_W_BIT | GEM_X_BIT | GEM_M_BIT) : 0)); + return 0; +} + + +static MENU menu_main[] = +{ + menu_admin, PERM_ALLADMIN, M_AMENU, + "0Admin £X ¨t²ÎºûÅ@°Ï £X", + + Gem, 0, M_GEM, + "Announce £i ºëµØ¤½§GÄæ £i", + + Boards, 0, M_BOARD, + "Boards £[ §G§i°Q½×°Ï £[", + + Class, 0, M_BOARD, + "Class £p ¤À²Õ°Q½×¶° £p", + +#ifdef MY_FAVORITE + MyFavorite, PERM_BASIC, M_MF, + "Favorite £b §Úªº³Ì·R¸s £b", +#endif + + menu_mail, 0, M_MMENU, + "Mail £g «H¥ó¨åÂò° £g", + + menu_talk, 0, M_TMENU, + "Talk £s ¥ð¶¢²á¤Ñ¦a £s", + + menu_user, 0, M_UMENU, + "User £k Ó¤H¤u¨ã§{ £k", + +#ifdef HAVE_EXTERNAL + menu_tool, 0, M_XMENU, + "Xyz £c ¯S®í©Û«Ý©Ò £c", +#endif + +#if 0 /* itoc.010209: ¿ï³æ«ö s ª½±µ¶i¤J Select() ´î¤Ö¿ï³æªø«× */ + Select, 0, M_BOARD, + "Select £m ¿ï¾Ü¥D¬ÝªO £m", +#endif + + goodbye, 0, M_XMODE, + "Goodbye £_ ¤U¦¸¦A·|§a £_", + + NULL, PERM_MENU + 'B', M_0MENU, + "¥D¥\\¯àªí" +}; + + +void +menu() +{ + MENU *menu, *mptr, *table[12]; + usint level, mode; + int cc, cx; /* current / previous cursor position */ + int max, mmx; /* current / previous menu max */ + int cmd, depth; + char *str; + + mode = MENU_LOAD | MENU_DRAW | MENU_FILM; + menu = menu_main; + level = cuser.userlevel; + depth = mmx = 0; + + for (;;) + { + if (mode & MENU_LOAD) + { + for (max = -1;; menu++) + { + cc = menu->level; + if (cc & PERM_MENU) + { + +#ifdef MENU_VERBOSE + if (max < 0) /* §ä¤£¨ì¾A¦XÅv¤§¥\¯à¡A¦^¤W¤@¼h¥\¯àªí */ + { + menu = (MENU *) menu->func; + continue; + } +#endif + + break; + } + if (cc && !(cc & level)) /* ¦³¸ÓÅv¤~¨q¥X */ + continue; + + table[++max] = menu; + } + + if (mmx < max) + mmx = max; + + if ((depth == 0) && HAS_STATUS(STATUS_BIFF)) /* ²Ä¤@¦¸¤W¯¸Y¦³·s«H¡A¶i¤J Mail ¿ï³æ */ + cmd = 'M'; + else + cmd = cc ^ PERM_MENU; /* default command */ + utmp_mode(menu->umode); + } + + if (mode & MENU_DRAW) + { + if (mode & MENU_FILM) + { + clear(); + movie(); + cx = -1; + } + + vs_head(menu->desc, NULL); + + mode = 0; + do + { + move(MENU_XPOS + mode, MENU_YPOS + 2); + if (mode <= max) + { + mptr = table[mode]; + str = mptr->desc; + prints("(\033[1;36m%c\033[m)", *str++); + outs(str); + } + clrtoeol(); + } while (++mode <= mmx); + + mmx = max; + mode = 0; + } + + switch (cmd) + { + case KEY_DOWN: + cc = (cc == max) ? 0 : cc + 1; + break; + + case KEY_UP: + cc = (cc == 0) ? max : cc - 1; + break; + + case Ctrl('A'): /* itoc.020829: ¹w³]¿ï¶µ²Ä¤@Ó */ + case KEY_HOME: + cc = 0; + break; + + case KEY_END: + cc = max; + break; + + case KEY_PGUP: + cc = (cc == 0) ? max : 0; + break; + + case KEY_PGDN: + cc = (cc == max) ? 0 : max; + break; + + case '\n': + case KEY_RIGHT: + mptr = table[cc]; + cmd = mptr->umode; +#if 1 + /* Thor.990212: dynamic load , with negative umode */ + if (cmd < 0) + { + void *p = DL_get(mptr->func); + if (!p) + break; + mptr->func = p; + cmd = -cmd; + mptr->umode = cmd; + } +#endif + utmp_mode(cmd); + + if (cmd <= M_XMENU) /* ¤l¥Ø¿ýªº mode n <= M_XMENU */ + { + menu->level = PERM_MENU + mptr->desc[0]; + menu = (MENU *) mptr->func; + + mode = MENU_LOAD | MENU_DRAW; + /* mode = MENU_LOAD | MENU_DRAW | MENU_FILM; /* itoc.010304: ¶i¤J¤l¿ï³æ«¼· movie */ + + depth++; + continue; + } + + { + int (*func) (); + + func = mptr->func; + mode = (*func) (); + } + + utmp_mode(menu->umode); + + if (mode == XEASY) + { + outf(feeter); + mode = 0; + } + else + { + mode = MENU_DRAW | MENU_FILM; + } + + cmd = mptr->desc[0]; + continue; + +#ifdef EVERY_Z + case Ctrl('Z'): + every_Z(0); + goto every_key; + + case Ctrl('U'): + every_U(0); + goto every_key; +#endif + + /* itoc.010911: Select everywhere¡A¤£¦A¨î¬O¦b M_0MENU */ + case 's': + case Ctrl('S'): + utmp_mode(M_BOARD); + Select(); + goto every_key; + +#ifdef MY_FAVORITE + /* itoc.010911: Favorite everywhere¡A¤£¦A¨î¬O¦b M_0MENU */ + case 'f': + case Ctrl('F'): + if (cuser.userlevel) /* itoc.010407: nÀˬdÅv */ + { + utmp_mode(M_MF); + MyFavorite(); + } + goto every_key; +#endif + + /* itoc.020301: Read currboard in M_0MENU */ + case 'r': + if (bbsmode == M_0MENU) + { + if (currbno >= 0) + { + utmp_mode(M_BOARD); + XoPost(currbno); + xover(XZ_POST); +#ifndef ENHANCED_VISIT + time(&brd_visit[currbno]); +#endif + } + goto every_key; + } + goto default_key; /* Y¤£¦b M_0MENU ¤¤«ö r ªº¸Ü¡Anµø¬°¤@¯ë«öÁä */ + +every_key: /* ¯S®íÁä³B²zµ²§ô */ + utmp_mode(menu->umode); + mode = MENU_DRAW | MENU_FILM; + cmd = table[cc]->desc[0]; + continue; + + case KEY_LEFT: + case 'e': + if (depth > 0) + { + menu->level = PERM_MENU + table[cc]->desc[0]; + menu = (MENU *) menu->func; + mode = MENU_LOAD | MENU_DRAW; + /* mode = MENU_LOAD | MENU_DRAW | MENU_FILM; /* itoc.010304: °h¥X¤l¿ï³æ«¼· movie */ + depth--; + continue; + } + cmd = 'G'; + +default_key: + default: + + if (cmd >= 'a' && cmd <= 'z') + cmd ^= 0x20; /* Åܤj¼g */ + + cc = 0; + for (;;) + { + if (table[cc]->desc[0] == cmd) + break; + if (++cc > max) + { + cc = cx; + goto menu_key; + } + } + } + + if (cc != cx) /* Y´å¼Ð²¾°Ê¦ì¸m */ + { +#ifdef CURSOR_BAR + if (cx >= 0) + { + move(MENU_XPOS + cx, MENU_YPOS); + if (cx <= max) + { + mptr = table[cx]; + str = mptr->desc; + prints(" (\033[1;36m%c\033[m)%s ", *str, str + 1); + } + else + { + outs(" "); + } + } + move(MENU_XPOS + cc, MENU_YPOS); + mptr = table[cc]; + str = mptr->desc; + prints(COLOR4 "> (%c)%s \033[m", *str, str + 1); + cx = cc; +#else /* ¨S¦³ CURSOR_BAR */ + if (cx >= 0) + { + move(MENU_XPOS + cx, MENU_YPOS); + outc(' '); + } + move(MENU_XPOS + cc, MENU_YPOS); + outc('>'); + cx = cc; +#endif + } + else /* Y´å¼Ðªº¦ì¸m¨S¦³ÅÜ */ + { +#ifdef CURSOR_BAR + move(MENU_XPOS + cc, MENU_YPOS); + mptr = table[cc]; + str = mptr->desc; + prints(COLOR4 "> (%c)%s \033[m", *str, str + 1); +#else + move(MENU_XPOS + cc, MENU_YPOS + 1); +#endif + } + +menu_key: + + cmd = vkey(); + } +} diff --git a/maple/more.c b/maple/more.c new file mode 100644 index 0000000..5f133ae --- /dev/null +++ b/maple/more.c @@ -0,0 +1,835 @@ +/*-------------------------------------------------------*/ +/* more.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : simple & beautiful ANSI/Chinese browser */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +/* ----------------------------------------------------- */ +/* buffered file read */ +/* ----------------------------------------------------- */ + + +#define MORE_BUFSIZE 4096 + + +static uschar more_pool[MORE_BUFSIZE]; +static int more_base; /* more_pool[more_base ~ more_base+more_size] ¦³È */ +static int more_size; + + +/* ----------------------------------------------------- */ +/* mget ¾\Ū¤å¦rÀÉ¡Fmread ¾\Ū¤G¶i¦ìÀÉ */ +/* ----------------------------------------------------- */ + + +/* itoc.041226.µù¸Ñ: mgets() ©M more_line() ¤£¤@¼Ëªº³¡¤À¦³ + 1. mgets ª½±µ¥Î more_pool ªºªÅ¶¡¡Fmore_line «h¬O·|§âȼg¤J¤@¶ô buffer + 2. mgets ¤£·|¦Û°ÊÂ_¦æ¡Fmore_line «h¬O·|¦Û°ÊÂ_¦æ¦b b_cols + ©Ò¥H mgets ¬O®³¥Î¦b¤@¨Ç¨t²ÎÀɳB²z©Î¬O edit.c¡A¦Ó more_line ¥u¥Î¦b more() + */ + + +char * +mgets(fd) + int fd; +{ + char *pool, *base, *head, *tail; + int ch; + + if (fd < 0) + { + more_base = more_size = 0; + return NULL; + } + + pool = more_pool; + base = pool + more_base; + tail = pool + more_size; + head = base; + + for (;;) + { + if (head >= tail) + { + if (ch = head - base) + memcpy(pool, base, ch); + + head = pool + ch; + ch = read(fd, head, MORE_BUFSIZE - ch); + + if (ch <= 0) + return NULL; + + base = pool; + tail = head + ch; + more_size = tail - pool; + } + + ch = *head; + + if (ch == '\n') + { + *head++ = '\0'; + more_base = head - pool; + return base; + } + + head++; + } +} + + +/* use mgets(-1) to reset */ + + +void * +mread(fd, len) + int fd, len; +{ + char *pool; + int base, size; + + base = more_base; + size = more_size; + pool = more_pool; + + if (size < len) + { + if (size) + memcpy(pool, pool + base, size); + + base = read(fd, pool + size, MORE_BUFSIZE - size); + + if (base <= 0) + return NULL; + + size += base; + base = 0; + } + + more_base = base + len; + more_size = size - len; + + return pool + base; +} + + +/* ----------------------------------------------------- */ +/* more ¾\Ū¤å¦rÀÉ */ +/* ----------------------------------------------------- */ + + +#define STR_ANSICODE "[0123456789;" + + +static uschar *fimage; /* file image begin */ +static uschar *fend; /* file image end */ +static uschar *foff; /* ¥Ø«eŪ¨ìþ¸Ì */ + + +static int +more_line(buf) + char *buf; +{ + int ch, len, bytes, in_ansi, in_chi; + + len = bytes = in_ansi = in_chi = 0; + + for (;;) + { + if (foff >= fend) + break; + + ch = *foff; + + /* weiyu.040802: ¦pªG³o½X¬O¤¤¤å¦rªºº½X¡A¦ý¬O¥u³Ñ¤U¤@½XªºªÅ¶¡¥i¥H¦L¡A¨º»ò¤£n¦L³o½X */ + if (in_chi || IS_ZHC_HI(ch)) + in_chi ^= 1; + if (in_chi && (len >= b_cols - 1 || bytes >= ANSILINELEN - 2)) + break; + + foff++; + bytes++; + + if (ch == '\n') + break; + + if (ch == KEY_ESC) + { + in_ansi = 1; + } + else if (in_ansi) + { + if (!strchr(STR_ANSICODE, ch)) + in_ansi = 0; + } + else if (isprint2(ch)) + { + len++; + } + else + { + ch = ' '; /* ¦L¥X¤£¨Óªº³£´«¦¨ªÅ¥Õ */ + len++; + } + + *buf++ = ch; + + /* Y¤£§t±±¨î½Xªºªø«×¤w¹F b_cols ¦r¡A©Î§t±±¨î½Xªºªø«×¤w¹F ANSILINELEN-1¡A¨º»òÂ÷¶}°j°é */ + if (len >= b_cols || bytes >= ANSILINELEN - 1) + { + /* itoc.031123: ¦pªG¬O±±¨î½X¡A§Y¨Ï¤£§t±±¨î½Xªºªø«×¤w¹F b_cols ¤F¡AÁÙ¥i¥HÄ~Äò¦Y */ + if ((in_ansi || (foff < fend && *foff == KEY_ESC)) && bytes < ANSILINELEN - 1) + continue; + + /* itoc.031123: ¦AÀˬd¤U¤@Ó¦r¬O¤£¬O '\n'¡AÁ×§K«ê¦n¬O b_cols ©Î ANSILINELEN-1 ®É¡A·|¦h¸õ¤@¦CªÅ¥Õ */ + if (foff < fend && *foff == '\n') + { + foff++; + bytes++; + } + break; + } + } + + *buf = '\0'; + + return bytes; +} + + +static void +outs_line(str) /* ¦L¥X¤@¯ë¤º®e */ + char *str; +{ + int ch1, ch2, ansi; + + /* ¡°³B²z¤Þ¥ÎªÌ & ¤Þ¨¥ */ + + ch1 = str[0]; + ch2 = str[1]; + + if (ch2 == ' ' && (ch1 == QUOTE_CHAR1 || ch1 == QUOTE_CHAR2)) /* ¤Þ¨¥ */ + { + ansi = 1; + ch1 = str[2]; + outs((ch1 == QUOTE_CHAR1 || ch1 == QUOTE_CHAR2) ? "\033[33m" : "\033[36m"); /* ¤Þ¥Î¤@¼h/¤G¼h¤£¦PÃC¦â */ + } + else if (ch1 == '\241' && ch2 == '\260') /* ¡° ¤Þ¨¥ªÌ */ + { + ansi = 1; + outs("\033[1;36m"); + } + else if ((ch1 == '/') && (ch2 == '/')) /* duck.050629: ¥[¤J"ª`¸Ñ"*/ + { + ansi = 1; + outs("\033[1;30m"); + } + else + ansi = 0; + + /* ¦L¥X¤º®e */ + + if (!hunt[0]) + { + outx(str); + } + else + { + int len; + char buf[ANSILINELEN]; + char *ptr1, *ptr2; + + len = strlen(hunt); + ptr2 = buf; + while (1) + { + if (!(ptr1 = str_sub(str, hunt))) + { + strcpy(ptr2, str); + break; + } + + if (buf + ANSILINELEN - 1 <= ptr2 + (ptr1 - str) + (len + 7)) /* buf ªÅ¶¡¤£°÷ */ + break; + + str_ncpy(ptr2, str, ptr1 - str + 1); + ptr2 += ptr1 - str; + sprintf(ptr2, "\033[7m%.*s\033[m", len, ptr1); + ptr2 += len + 7; + str = ptr1 + len; + } + + outx(buf); + } + + if (ansi) + outs(str_ransi); +} + + +static void +outs_header(str, header_len) /* ¦L¥XÀÉÀY */ + char *str; + int header_len; +{ + static char header1[LINE_HEADER][LEN_AUTHOR1] = {"§@ªÌ", "¼ÐÃD", "®É¶¡"}; + static char header2[LINE_HEADER][LEN_AUTHOR2] = {"µo«H¤H", "¼Ð ÃD", "µo«H¯¸"}; + int i; + char *ptr, *word; + + /* ³B²zÀÉÀY */ + + if ((header_len == LEN_AUTHOR1 && !memcmp(str, header1[0], LEN_AUTHOR1 - 1)) || + (header_len == LEN_AUTHOR2 && !memcmp(str, header2[0], LEN_AUTHOR2 - 1))) + { + /* §@ªÌ/¬ÝªO ÀÉÀY¦³¤GÄæ¡A¯S§O³B²z */ + word = str + header_len; + if ((ptr = strstr(word, str_post1)) || (ptr = strstr(word, str_post2))) + { + ptr[-1] = ptr[4] = '\0'; + prints(COLOR5 " %s " COLOR6 "%-*.*s" COLOR5 " %s " COLOR6 "%-13s\033[m", + header1[0], d_cols + 53, d_cols + 53, word, ptr, ptr + 5); + } + else + { + /* ¤Ö¬ÝªO³oÄæ */ + prints(COLOR5 " %s " COLOR6 "%-*.*s\033[m", + header1[0], d_cols + 72, d_cols + 72, word); + } + return; + } + + for (i = 1; i < LINE_HEADER; i++) + { + if ((header_len == LEN_AUTHOR1 && !memcmp(str, header1[i], LEN_AUTHOR1 - 1)) || + (header_len == LEN_AUTHOR2 && !memcmp(str, header2[i], LEN_AUTHOR2 - 1))) + { + /* ¨ä¥LÀÉÀY³£¥u¦³¤@Äæ */ + word = str + header_len; + prints(COLOR5 " %s " COLOR6 "%-*.*s\033[m", + header1[i], d_cols + 72, d_cols + 72, word); + return; + } + } + + /* ¦pªG¤£¬OÀÉÀY¡A´N·í¤@¯ë¤å¦r¦L¥X */ + outs_line(str); +} + + +static inline void +outs_footer(buf, lino, fsize) + char *buf; + int lino; + int fsize; +{ + int i; + + /* P.1 ¦³ (PAGE_SCROLL + 1) ¦C¡A¨ä¥L Page ³£¬O PAGE_SCROLL ¦C */ + + /* prints(FOOTER_MORE, (lino - 2) / PAGE_SCROLL + 1, ((foff - fimage) * 100) / fsize); */ + + /* itoc.010821: ¬°¤F©M FOOTER ¹ï»ô */ + sprintf(buf, FOOTER_MORE, (lino - 2) / PAGE_SCROLL + 1, ((foff - fimage) * 100) / fsize); + outs(buf); + + for (i = b_cols + sizeof(COLOR1) + sizeof(COLOR2) - strlen(buf); i > 3; i--) + { + /* ¶ñº¡³Ì«áªºªÅ¥ÕÃC¦â¡A³Ì«á¯d¤@ÓªÅ¥Õ */ + outc(' '); + } + outs(str_ransi); +} + + +#ifdef SLIDE_SHOW +static int slideshow; /* !=0: ¼½©ñ movie ªº³t«× */ + +static int +more_slideshow() +{ + int ch; + + if (!slideshow) + { + ch = vkey(); + + if (ch == '@') + { + slideshow = vans("½Ð¿ï¾Ü©ñ¬Mªº³t«× 1(³ÌºC)¡ã9(³Ì§Ö)¡H¼½©ñ¤¤«ö¥ô·NÁä¥i°±¤î¼½©ñ¡G") - '0'; + if (slideshow < 1 || slideshow > 9) + slideshow = 5; + + ch = KEY_PGDN; + } + } + else + { + struct timeval tv[9] = + { + {4, 0}, {3, 0}, {2, 0}, {1, 500000}, {1, 0}, + {0, 800000}, {0, 600000}, {0, 400000}, {0, 200000} + }; + + refresh(); + ch = 1; + if (select(1, (fd_set *) &ch, NULL, NULL, tv + slideshow - 1) > 0) + { + /* Y¼½©ñ¤¤«ö¥ô·NÁä¡A«h°±¤î¼½©ñ */ + slideshow = 0; + ch = vkey(); + } + else + { + ch = KEY_PGDN; + } + } + + return ch; +} +#endif + + +#define END_MASK 0x200 /* «ö KEY_END ª½¹F³Ì«á¤@¶ */ + +#define HUNT_MASK 0x400 +#define HUNT_NEXT 0x001 /* «ö n ·j´M¤U¤@µ§ */ +#define HUNT_FOUND 0x002 /* «ö / ¶}©l·j´M¡A¥B¤w¸g§ä¨ì match ªº¦r¦ê */ +#define HUNT_START 0x004 /* «ö / ¶}©l·j´M¡A¥B©|¥¼§ä¨ì match ªº¦r¦ê */ + +#define MAXBLOCK 256 /* °O¿ý´XÓ block ªº offset¡C¥i¥[³t MAXBLOCK*32 ¦C¥H¤ºªºªø¤å¦b¤W±²/½®Éªº³t«× */ + +/* Thor.990204: ¶Ç¦^È -1 ¬°µLªkshow¥X + 0 ¬°¥þ¼Æshow§¹ + >0 ¬°¥¼¥þshow¡A¤¤Â_©Ò«öªºkey */ +int +more(fpath, footer) + char *fpath; + char *footer; +{ + char buf[ANSILINELEN]; + int i; + + uschar *headend; /* ÀÉÀYµ²§ô */ + + int shift; /* ÁÙ»Ýn©¹¤U²¾°Ê´X¦C */ + int lino; /* ¥Ø«e line number */ + int header_len; /* ÀÉÀYªºªø«×¡A¦P®É¤]¬O¯¸¤º/¯¸¥~«Hªº°Ï§O */ + int key; /* «öÁä */ + int cmd; /* ¤¤Â_®É©Ò«öªºÁä */ + + int fsize; /* Àɮפj¤p */ + static off_t block[MAXBLOCK]; /* ¨C 32 ¦C¬°¤@Ó block¡A°O¿ý¦¹ block ªº offset */ + + if (!(fimage = f_img(fpath, &fsize))) + return -1; + + foff = fimage; + fend = fimage + fsize; + + /* §äÀÉÀYµ²§ôªº¦a¤è */ + for (i = 0; i < LINE_HEADER; i++) + { + if (!more_line(buf)) + break; + + /* Ū¥XÀɮײĤ@¦C¡A¨Ó§PÂ_¯¸¤º«HÁÙ¬O¯¸¥~«H */ + if (i == 0) + { + header_len = + !memcmp(buf, str_author1, LEN_AUTHOR1) ? LEN_AUTHOR1 : /* ¡u§@ªÌ:¡vªí¯¸¤º¤å³¹ */ + !memcmp(buf, str_author2, LEN_AUTHOR2) ? LEN_AUTHOR2 : /* ¡uµo«H¤H:¡vªíÂà«H¤å³¹ */ + 0; /* ¨S¦³ÀÉÀY */ + } + + if (!*buf) /* ²Ä¤@¦¸ "\n\n" ¬OÀÉÀYªºµ²§À */ + break; + } + headend = foff; + + /* Âk¹s */ + foff = fimage; + + lino = cmd = 0; + block[0] = 0; + +#ifdef SLIDE_SHOW + slideshow = 0; +#endif + + if (hunt[0]) /* ¦b xxxx_browse() ½Ð¨D·j´M¦r¦ê */ + { + str_lowest(hunt, hunt); + shift = HUNT_MASK | HUNT_START; + } + else + { + shift = b_lines; + } + + clear(); + + while (more_line(buf)) + { + /* ------------------------------------------------- */ + /* ¦L¥X¤@¦Cªº¤å¦r */ + /* ------------------------------------------------- */ + + /* º¶«e´X¦C¤~»Ýn³B²zÀÉÀY */ + if (foff <= headend) + outs_header(buf, header_len); + else + outs_line(buf); + + outc('\n'); + + /* ------------------------------------------------- */ + /* ¨Ì shift ¨Ó¨M©w°Ê§@ */ + /* ------------------------------------------------- */ + + /* itoc.030303.µù¸Ñ: shift ¦b¦¹ªº·N¸q + >0: ÁÙ»Ýn©¹¤U²¾´X¦C + <0: ÁÙ»Ýn©¹¤W²¾´X¦C + =0: µ²§ô³o¶¡Aµ¥«Ý¨Ï¥ÎªÌ«öÁä */ + + if (shift > 0) /* ÁÙn¤U²¾ shift ¦C */ + { + if (lino >= b_lines) /* ¥u¦³¦bè¶i more¡A²Ä¤@¦¸¦L²Ä¤@¶®É¤~¥i¯à lino <= b_lines */ + scroll(); + + lino++; + + if ((lino % 32 == 0) && ((i = lino >> 5) < MAXBLOCK)) + block[i] = foff - fimage; + + + if (!(shift & (HUNT_MASK | END_MASK))) /* ¤@¯ë¸ê®ÆÅª¨ú */ + { + shift--; + } + else if (shift & HUNT_MASK) /* ¦r¦ê·j´M */ + { + if (shift & HUNT_NEXT) /* «ö n ·j´M¤U¤@µ§ */ + { + /* ¤@§ä¨ì´N°±©ó¸Ó¦C */ + if (str_sub(buf, hunt)) + shift = 0; + } + else /* «ö / ¶}©l·j´M */ + { + /* Y¦b²Ä¤G¶¥H«á§ä¨ì¡A¤@§ä¨ì´N°±©ó¸Ó¦C¡F + Y¦b²Ä¤@¶§ä¨ì¡A¥²¶·µ¥¨ìŪ§¹²Ä¤@¶¤~¯à°±¤î */ + if (shift & HUNT_START && str_sub(buf, hunt)) + shift ^= HUNT_START | HUNT_FOUND; /* ®³±¼ HUNT_START ¨Ã¥[¤W HUNT_FOUND */ + if (shift & HUNT_FOUND && lino >= b_lines) + shift = 0; + } + } + } + else if (shift < 0) /* ÁÙn¤W²¾ -shift ¦C */ + { + shift++; + + if (!shift) + { + move(b_lines, 0); + clrtoeol(); + + /* ³Ñ¤U b_lines+shift ¦C¬O rscroll¡Aoffsect ¥h¥¿½T¦ì¸m¡F³o¸Ìªº i ¬OÁ`¦@n shift ªº¦C¼Æ */ + for (i += b_lines; i > 0; i--) + more_line(buf); + } + } + + if (foff >= fend) /* ¤w¸gŪ§¹¥þ³¡ªºÀÉ®× */ + { + /* ÕY¬O«ö End ²¾¨ì³Ì«á¤@¶¡A¨º»ò°±¯d¦b 100% ¦Ó¤£µ²§ô¡F§_«h¤@«ßµ²§ô */ + if (!(shift & END_MASK)) + break; + shift = 0; + } + + if (shift) /* ÁÙ»ÝnÄ~ÄòŪ¸ê®Æ */ + continue; + + /* ------------------------------------------------- */ + /* ¨ì¦¹¦L§¹©Ò»Ýªº shift ¦C¡A±µ¤U¨Ó¦L¥X footer ¨Ãµ¥«Ý */ + /* ¨Ï¥ÎªÌ«öÁä */ + /* ------------------------------------------------- */ + +re_key: + + outs_footer(buf, lino, fsize); + +#ifdef SLIDE_SHOW + key = more_slideshow(); +#else + key = vkey(); +#endif + + if (key == ' ' || key == KEY_PGDN || key == KEY_RIGHT || key == Ctrl('F')) + { + shift = PAGE_SCROLL; + } + + else if (key == KEY_DOWN || key == '\n') + { + shift = 1; + } + + else if (key == KEY_PGUP || key == Ctrl('B') || key == KEY_DEL) + { + /* itoc.010324: ¨ì¤F³Ì¶}©l¦A¤W±²ªí¥ÜÂ÷¶}¡A¨Ã¦^¶Ç 'k' (keymap[] ©w¸q¤W¤@½g) */ + if (lino <= b_lines) + { + cmd = 'k'; + break; + } + /* ³Ì¦h¥u¯à¤W±²¨ì¤@¶}©l */ + i = b_lines - lino; + shift = BMAX(-PAGE_SCROLL, i); + } + + else if (key == KEY_UP) + { + /* itoc.010324: ¨ì¤F³Ì¶}©l¦A¤W±²ªí¥ÜÂ÷¶}¡A¨Ã¦^¶Ç 'k' (keymap[] ©w¸q¤W¤@½g) */ + if (lino <= b_lines) + { + cmd = 'k'; + break; + } + shift = -1; + } + + else if (key == KEY_END || key == '$') + { + shift = END_MASK; + } + + else if (key == KEY_HOME || key == '0') + { + if (lino <= b_lines) /* ¤w¸g¦b³Ì¶}©l¤F */ + shift = 0; + else + shift = -PAGE_SCROLL - 1; + } + + else if (key == '/' || key == 'n') + { + if (key == 'n' && hunt[0]) /* ¦pªG«ö n «o¥¼¿é¤J¹L·j´M¦r¦ê¡A¨º»òµø¦P«ö / */ + { + shift = HUNT_MASK | HUNT_NEXT; + } + else if (vget(b_lines, 0, "·j´M¡G", hunt, sizeof(hunt), DOECHO)) + { + str_lowest(hunt, hunt); + shift = HUNT_MASK | HUNT_START; + } + else /* ¦pªG¨ú®ø·j´Mªº¸Ü¡A«Ã¸ footer §Y¥i */ + { + shift = 0; + } + } + + else if (key == 'C') /* Thor.980405: more ®É¥i¦s¤J¼È¦sÀÉ */ + { + FILE *fp; + if (fp = tbf_open()) + { + f_suck(fp, fpath); + fclose(fp); + } + shift = 0; /* «Ã¸ footer */ + } + + else if (key == 'h') + { + screenline slt[T_LINES]; + uschar *tmp_fimage; + uschar *tmp_fend; + uschar *tmp_foff; + off_t tmp_block[MAXBLOCK]; + + /* itoc.060420: xo_help() ·|¶i¤J²Ä¤G¦¸ more()¡A©Ò¥Hn§â©Ò¦³ static «Å§iªº³£°O¿ý¤U¨Ó */ + tmp_fimage = fimage; + tmp_fend = fend; + tmp_foff = foff; + memcpy(tmp_block, block, sizeof(tmp_block)); + + vs_save(slt); + xo_help("post"); + vs_restore(slt); + + fimage = tmp_fimage; + fend = tmp_fend; + foff = tmp_foff; + memcpy(block, tmp_block, sizeof(block)); + + shift = 0; + } + + else /* ¨ä¥LÁä³£¬O¨Ï¥ÎªÌ¤¤Â_ */ + { + /* itoc.041006: ¨Ï¥ÎªÌ¤¤Â_ªº«öÁän > 0 (¦Ó KEY_LEFT ¬O < 0) */ + cmd = key > 0 ? key : 'q'; + break; + } + + /* ------------------------------------------------- */ + /* ¨Ï¥ÎªÌ¤w«öÁä¡AY break «hÂ÷¶}°j°é¡F§_«h¨Ì·Ó shift */ + /* ªººØÃþ (¥ç§Y«öÁ䪺ºØÃþ) ¦Ó°µ¤£¦Pªº°Ê§@ */ + /* ------------------------------------------------- */ + + if (shift > 0) /* ·Ç³Æ¤U²¾ shift ¦C */ + { + if (shift < (HUNT_MASK | HUNT_START)) /* ¤@¯ë¤U²¾ */ + { + /* itoc.041114.µù¸Ñ: ¥Ø¼Ð¬O¨q¥X lino-b_lines+1+shift ~ lino+shift ¦Cªº¤º®e¡G + ´N¥un²M footer §Y¥i¡A¨ä¥Lªº´N¥æµ¹«e±´`§Ç¦L shift ¦Cªºµ{¦¡ */ + + move(b_lines, 0); + clrtoeol(); + +#if 1 + /* itoc.041116: End ªº§@ªk¨ä¹ê©M¤@¯ë¤U²¾¥i¥H¬O§¹¥þ¤@¼Ëªº¡A¦ý¬O¦pªG¹J¨ì¶Wªø¤å³¹®É¡A + ·|³y¦¨«e±´`§Ç¦L shift ¦Cªºµ{¦¡´N±o¤@ª½Â½¡Aª½¨ì§ä¨ì³Ì«á¤@¶¡A³o¼Ë·|°µ¤Ó¦h outs_line() ¥Õ¤u¡A + ©Ò¥H¦b¦¹¯S§OÀˬd¶Wªø¤å³¹®É¡A´N¥ý¥h§ä³Ì«á¤@¶©Ò¦b */ + + if ((shift & END_MASK) && (fend - foff >= MORE_BUFSIZE)) /* ÁÙ¦³¤@°ï¨SŪ¹L¡A¤~¯S§O³B²z */ + { + int totallino = lino; + + /* ¥ýŪ¨ì³Ì«á¤@¦C¬Ý¬Ý¥þ³¡¦³´X¦C */ + while (more_line(buf)) + { + totallino++; + if ((totallino % 32 == 0) && ((i = totallino >> 5) < MAXBLOCK)) + block[i] = foff - fimage; + } + + /* ¥ý¦ì²¾¨ì¤W¤@Ó block ªº§ÀºÝ */ + i = (totallino - b_lines) >> 5; + if (i >= MAXBLOCK) + i = MAXBLOCK - 1; + foff = fimage + block[i]; + i = i << 5; + + /* ¦A±q¤W¤@Ó block ªº§ÀºÝ¦ì²¾¨ì totallino-b_lines+1 ¦C */ + for (i = totallino - b_lines - i; i > 0; i--) + more_line(buf); + + lino = totallino - b_lines; + } +#endif + } + else + { + /* '/' ±qÀY¶}©l·j´M */ + lino = 0; + foff = fimage; + clear(); + } + } + else if (shift < 0) /* ·Ç³Æ¤W²¾ -shift ¦C */ + { + if (shift >= -PAGE_SCROLL) /* ¤W±²¼Æ¦C */ + { + lino += shift; + + /* itoc.041114.µù¸Ñ: ¥Ø¼Ð¬O¨q¥X lino-b_lines+1 ~ lino ¦Cªº¤º®e¡G + 1. ¥ý±qÀY¦ì²¾¨ì lino-b_lines+1 ¦C + 2. ¨ä¤¤¦³ b_lines+shift ¦C¬O¤£Åܪº¤º®e¡A¥Î rscroll ¹F¦¨ + 3. ¦b«e±ªº outs_line() ªº¦a¤è¦L¥X -shift ¦C + 4. ³Ì«á¦A¦ì²¾è¤~ rscroll ªº¦C¼Æ + */ + + /* ¥ý¦ì²¾¨ì¤W¤@Ó block ªº§ÀºÝ */ + i = (lino - b_lines) >> 5; + if (i >= MAXBLOCK) + i = MAXBLOCK - 1; + foff = fimage + block[i]; + i = i << 5; + + /* ¦A±q¤W¤@Ó block ªº§ÀºÝ¦ì²¾¨ì lino-b_lines+1 ¦C */ + for (i = lino - b_lines - i; i > 0; i--) + more_line(buf); + + for (i = shift; i < 0; i++) + { + rscroll(); + move(0, 0); + clrtoeol(); + } + + i = shift; + } + else /* Home */ + { + /* itoc.041226.µù¸Ñ: ¥Ø¼Ð¬O¨q¥X 1 ~ b_lines ¦Cªº¤º®e¡G + §@ªk´N¬O¥þ³¡³£Âk¹s¡A±qÀY¦A¦L b_lines ¦C§Y¥i */ + + clear(); + + foff = fimage; + lino = 0; + shift = b_lines; + } + } + else /* «Ã¸ footer ¨Ã re-key */ + { + move(b_lines, 0); + clrtoeol(); + goto re_key; + } + } /* while °j°éªºµ²§ô */ + + /* --------------------------------------------------- */ + /* Àɮפw¸g¨q§¹ (cmd = 0) ©Î ¨Ï¥ÎªÌ¤¤Â_ (cmd != 0) */ + /* --------------------------------------------------- */ + + free(fimage); + + if (!cmd) /* ÀÉ®×¥¿±`¨q§¹¡An³B²z footer */ + { + if (footer) /* ¦³ footer */ + { + if (footer != (char *) -1) + outf(footer); + else + outs(str_ransi); + } + else /* ¨S¦³ footer n vmsg() */ + { + /* lkchu.981201: ¥ý²M¤@¦¸¥H§K«Å|Åã¥Ü */ + move(b_lines, 0); + clrtoeol(); + + if (vmsg(NULL) == 'C') /* Thor.990204: ¯S§Oª`·NY¦^¶Ç 'C' ªí¥Ü¼È¦sÀÉ */ + { + FILE *fp; + + if (fp = tbf_open()) + { + f_suck(fp, fpath); + fclose(fp); + } + } + } + } + else /* ¨Ï¥ÎªÌ¤¤Â_¡Aª½±µÂ÷¶} */ + { + outs(str_ransi); + } + + hunt[0] = '\0'; + + /* Thor.990204: Åýkey¥i¦^¶Ç¦Ümore¥~ */ + return cmd; +} diff --git a/maple/pal.c b/maple/pal.c new file mode 100644 index 0000000..5a6e62e --- /dev/null +++ b/maple/pal.c @@ -0,0 +1,907 @@ +/*-------------------------------------------------------*/ +/* pal.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : pal routines */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +extern XZ xz[]; +extern char xo_pool[]; + + +static int pal_max = 0; /* §Y cutmp->pal_max¡A¦]¬°¤Ó±`ÀˬdªB¤Í¦W³æ¡A©Ò¥H°O¤U¨Ó¥[³t */ +static int *pal_pool = NULL; /* §Y cutmp->pal_spool¡A¦]¬°¤Ó±`ÀˬdªB¤Í¦W³æ¡A©Ò¥H°O¤U¨Ó¥[³t */ + + +/* ----------------------------------------------------- */ +/* ªB¤Í§P§O */ +/* ----------------------------------------------------- */ + + +static int /* 1: userno ¦b pool ¦W³æ¤W */ +belong_pal(pool, max, userno) + int *pool; + int max; + int userno; +{ + int *up, datum, mid; + + up = pool; + while (max > 0) + { + datum = up[mid = max >> 1]; + if (userno == datum) + { + return 1; + } + if (userno > datum) + { + up += (++mid); + max -= mid; + } + else + { + max = mid; + } + } + return 0; +} + + +int +is_mygood(userno) /* 1: §Ú³]¹ï¤è¬°¦n¤Í */ + int userno; +{ + return belong_pal(pal_pool, pal_max, userno); +} + + +int +is_mybad(userno) /* 1: §Ú³]¹ï¤è¬°Ãa¤H */ + int userno; +{ +#ifdef HAVE_BADPAL + return belong_pal(pal_pool, pal_max, -userno); +#else + return 0; +#endif +} + + +int +is_ogood(up) /* 1: ¹ï¤è³]§Ú¬°¦n¤Í */ + UTMP *up; +{ + return belong_pal(up->pal_spool, up->pal_max, cuser.userno); +} + + +int +is_obad(up) /* 1: ¹ï¤è³]§Ú¬°Ãa¤H */ + UTMP *up; +{ +#ifdef HAVE_BADPAL + return belong_pal(up->pal_spool, up->pal_max, -cuser.userno); +#else + return 0; +#endif +} + + +#ifdef HAVE_MODERATED_BOARD +int +is_bgood(bpal) /* 1: §Ú¬O¸ÓªOªºªO¦n */ + BPAL *bpal; +{ + return belong_pal(bpal->pal_spool, bpal->pal_max, cuser.userno); +} + + +int +is_bbad(bpal) /* 1: §Ú¬O¸ÓªOªºªOÃa */ + BPAL *bpal; +{ +#ifdef HAVE_BADPAL + return belong_pal(bpal->pal_spool, bpal->pal_max, -cuser.userno); +#else + return 0; +#endif +} +#endif + + +/* ----------------------------------------------------- */ +/* ªB¤Í¦W³æ¡G·s¼W¡B§R°£¡B×§ï¡B¸ü¤J¡B¦P¨B */ +/* ----------------------------------------------------- */ + + +static int +int_cmp(a, b) + int *a; + int *b; +{ + return *a - *b; +} + + +int +image_pal(fpath, pool) + char *fpath; + int *pool; +{ + int fsize; + int *plist; + PAL *phead, *ptail; + char *fimage; + + if (fimage = f_img(fpath, &fsize)) + { + if (fsize <= PAL_MAX * sizeof(PAL)) /* ¦pªG¶W¹L PAL_MAX¡A´N¤£¸ü¤J */ + { + plist = pool; + phead = (PAL *) fimage; + ptail = (PAL *) (fimage + fsize); + fsize /= sizeof(PAL); + + do + { + /* Y¬OÃa¤H¡A¦s -userno¡FY¬O¦n¤Í¡A¦s +userno */ + *plist++ = (phead->ftype & PAL_BAD) ? -(phead->userno) : phead->userno; + } while (++phead < ptail); + + if (fsize > 1) + qsort(pool, fsize, sizeof(int), int_cmp); + } + else + { + fsize = 0; + } + free(fimage); + } + else + { + fsize = 0; + } + + return fsize; +} + + +void +pal_cache() +{ + char fpath[64]; + + if (!pal_pool) /* ²Ä¤@¦¸³]©w¡A¬O¦b utmp_new() ¸Ì± */ + pal_pool = cutmp->pal_spool; + + usr_fpath(fpath, cuser.userid, fn_pal); + + pal_max = image_pal(fpath, pal_pool); + cutmp->pal_max = pal_max; +} + + +static int +chkpal(pal) + PAL *pal; +{ + int userno; + + userno = pal->userno; + return (userno > 0 && userno == acct_userno(pal->userid)); +} + + +void +pal_sync(fpath) + char *fpath; +{ + int fsize; + + fsize = rec_sync(fpath, sizeof(PAL), str_cmp, chkpal); + + if (fsize > PAL_MAX * sizeof(PAL)) + vmsg(msg_list_over); +} + + +int +pal_list(reciper) + int reciper; +{ + int userno, fd; + char buf[32], fpath[64]; + ACCT acct; +#ifdef HAVE_LIST + int ch; +#endif + + userno = 0; + + for (;;) + { +#ifdef HAVE_LIST + switch (ch = vget(1, 0, "(A)¼W¥[ (D)§R°£ (F)¦n¤Í (G)¸s²Õ (M)©w®× (1~5)¯S§O¦W³æ (Q)¨ú®ø¡H[M] ", buf, 3, LCECHO)) +#else + switch (vget(1, 0, "(A)¼W¥[ (D)§R°£ (F)¦n¤Í (G)¸s²Õ (M)©w®× (Q)¨ú®ø¡H[M] ", buf, 3, LCECHO)) +#endif + { + case 'a': + while (acct_get("½Ð¿é¤J¥N¸¹(¥u«ö ENTER µ²§ô·s¼W): ", &acct) > 0) + { + if (!ll_has(acct.userid)) + { + ll_add(acct.userid); + reciper++; + ll_out(3, 0, MSG_LL); + } + } + break; + + case 'd': + while (reciper) + { + if (!vget(1, 0, "½Ð¿é¤J¥N¸¹(¥u«ö ENTER µ²§ô§R°£): ", buf, IDLEN + 1, GET_LIST)) + break; + if (ll_del(buf)) + reciper--; + ll_out(3, 0, MSG_LL); + } + break; + +#ifdef HAVE_LIST + case '1': + case '2': + case '3': + case '4': + case '5': + /* itoc.010923: ¤Þ¥Î¯S§O¦W³æ¡A¶¶«K¨Ï¥Î¸s²Õ±ø¥ó */ + sprintf(buf, "%s.%c", FN_LIST, ch); + usr_fpath(fpath, cuser.userid, buf); +#endif + + case 'g': + if (userno = vget(b_lines, 0, "¸s²Õ±ø¥ó¡G", buf, 16, DOECHO)) + str_lowest(buf, buf); + + case 'f': +#ifdef HAVE_LIST + if (ch == 'g' || ch == 'f') +#endif + usr_fpath(fpath, cuser.userid, fn_pal); + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + PAL *pal; + char *userid; + + mgets(-1); + while (pal = mread(fd, sizeof(PAL))) + { + userid = pal->userid; + if (!ll_has(userid) && + !(pal->ftype & PAL_BAD) && + (!userno || str_sub(pal->ship, buf))) + { + ll_add(userid); + reciper++; + } + } + close(fd); + } + ll_out(3, 0, MSG_LL); + userno = 0; + break; + + case 'q': + return 0; + + default: + return reciper; + } + } +} + + + +/* ----------------------------------------------------- */ +/* ªB¤Í¦W³æ¡G¿ï³æ¦¡¾Þ§@¬É±´yz */ +/* ----------------------------------------------------- */ + + +static int pal_add(); + + +static void +pal_item(num, pal) + int num; + PAL *pal; +{ +#ifdef CHECK_ONLINE + UTMP *online = utmp_get(pal->userno, NULL); + + prints("%6d%c%-3s%s%-14s%s%s\n", + num, tag_char(pal->userno), pal->ftype & PAL_BAD ? "¢æ" : "", + online ? COLOR7 : "", pal->userid, online ? str_ransi : "", pal->ship); +#else + prints("%6d%c%-3s%-14s%s\n", + num, tag_char(pal->userno), pal->ftype & PAL_BAD ? "¢æ" : "", pal->userid, pal->ship); +#endif +} + + +static int +pal_body(xo) + XO *xo; +{ + PAL *pal; + int num, max, tail; + + max = xo->max; + if (max <= 0) + { + if (vans("n¥æ·sªB¤Í¶Ü(Y/N)¡H[N] ") == 'y') + return pal_add(xo); + return XO_QUIT; + } + + pal = (PAL *) xo_pool; + num = xo->top; + tail = num + XO_TALL; + if (max > tail) + max = tail; + + move(3, 0); + do + { + pal_item(++num, pal++); + } while (num < max); + clrtobot(); + + /* return XO_NONE; */ + return XO_FOOT; /* itoc.010403: §â b_lines ¶ñ¤W feeter */ +} + + +static int +pal_head(xo) + XO *xo; +{ + char *head[] = {"ªB¤Í¦W³æ", "¸s²Õ¦W³æ", "ªO¤Í¦W³æ", "¨î§ë²¼¦W³æ"}; + + vs_head(head[xo->key], str_site); + prints(NECKER_PAL, d_cols, ""); + return pal_body(xo); +} + + +static int +pal_load(xo) + XO *xo; +{ + xo_load(xo, sizeof(PAL)); + return pal_body(xo); +} + + +static int +pal_init(xo) + XO *xo; +{ + xo_load(xo, sizeof(PAL)); + return pal_head(xo); +} + + +void +pal_edit(key, pal, echo) + int key; + PAL *pal; + int echo; +{ + if (echo == DOECHO) + memset(pal, 0, sizeof(PAL)); + vget(b_lines, 0, "¤Í½Ë¡G", pal->ship, sizeof(pal->ship), echo); +#ifdef HAVE_BADPAL + if (key != PALTYPE_VOTE) /* ¨î§ë²¼¦W³æ¨S¦³Ãa¤H */ + { + char buf[40]; + sprintf (buf, "%s(Y/N)¡H[N] ", key == PALTYPE_BPAL ? "¤ô±í" : "Ãa¤H"); +// pal->ftype = vans("Ãa¤H(Y/N)¡H[N] ") == 'y' ? PAL_BAD : 0; + pal->ftype = vans (buf) == 'y' ? PAL_BAD : 0; + } + else +#endif + pal->ftype = 0; +} + + +/* static */ /* itoc.020117: µ¹ vote.c ¥Î */ +int +pal_find(fpath, userno) /* itoc.010923: ªB¤Í¦W³æ¤¤¬O§_¤w¦³¦¹¤H */ + char *fpath; + int userno; +{ + PAL old; + int fd; + int rc = 0; + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + while (read(fd, &old, sizeof(PAL)) == sizeof(PAL)) + { + if (userno == old.userno) + { + rc = 1; + break; + } + } + close(fd); + } + return rc; +} + + +static int +pal_add(xo) + XO *xo; +{ + ACCT acct; + int userno; + + if (xo->max >= PAL_MAX) + { + vmsg(msg_list_over); + return XO_FOOT; + } + + userno = acct_get(msg_uid, &acct); + + if (userno == cuser.userno) /* lkchu.981201: ªB¤Í¦W³æ¤£¥i¥[¦Û¤v */ + { + vmsg("¦Û¤v¤£¶·¥[¤JªB¤Í¦W³æ¤¤"); + } + else if (pal_find(xo->dir, userno)) + { + vmsg("¦W³æ¤¤¤w¦³¦¹¤H"); + } + else if (userno > 0) + { + PAL pal; + + pal_edit(xo->key, &pal, DOECHO); + strcpy(pal.userid, acct.userid); + pal.userno = userno; + rec_add(xo->dir, &pal, sizeof(PAL)); + + if (xo->key == PALTYPE_PAL) + utmp_admset(userno, STATUS_PALDIRTY); + + if (xo->dir[0] == 'b' && /* ªO¤Í¤~»Ýn±H«H */ + vans("¬O§_µo¨ç³qª¾¥L(Y/N)¡H[N] ") == 'y') + { + char fpath[64], *title; + FILE *fp; + + sprintf(fpath, "tmp/pal_add.%s", cuser.userid); /* ¼È¦sÀÉ */ + if (fp = fopen(fpath, "w")) + { + title = "¥[¤JªO¤Í³qª¾"; + + /* ¤å³¹ÀÉÀY */ + fprintf(fp, "%s %s (%s)\n", + str_author1, cuser.userid, cuser.username); + fprintf(fp, "¼ÐÃD: %s\n®É¶¡: %s\n\n", title, Now()); + + /* ¤å³¹¤º®e */ + fprintf(fp, "%s ±N±z¥[¤J [%s] ªºªO¤Í\n\n", cuser.userid, currboard); + fclose(fp); + + mail_him(fpath, acct.userid, title, 0); + unlink(fpath); + } + } + xo->pos = XO_TAIL; /* ©ñ¦b³Ì«á */ + return pal_init(xo); + } + + return pal_head(xo); +} + + +static int +pal_delete(xo) + XO *xo; +{ + if (vans(msg_del_ny) == 'y') + { + if (!rec_del(xo->dir, sizeof(PAL), xo->pos, NULL)) + { + if (xo->key == PALTYPE_PAL) + { + PAL *pal; + pal = (PAL *) xo_pool + (xo->pos - xo->top); + utmp_admset(pal->userno, STATUS_PALDIRTY); + } + return pal_load(xo); + } + } + return XO_FOOT; +} + + +static void +changestatus(xo, pal) + XO *xo; + PAL *pal; +{ + if (xo->key == PALTYPE_PAL) + utmp_admset(pal->userno, STATUS_PALDIRTY); +} + + +static int +pal_rangedel(xo) + XO *xo; +{ + return xo_rangedel(xo, sizeof(PAL), NULL, changestatus); +} + + +static int +vfypal(pal, pos) + PAL *pal; + int pos; +{ + return Tagger(pal->userno, pos, TAG_NIN); +} + + +static int +pal_prune(xo) + XO *xo; +{ + return xo_prune(xo, sizeof(PAL), vfypal, changestatus); +} + + +static int +pal_change(xo) + XO *xo; +{ + PAL *pal, oldpal; + int pos, cur; + + pos = xo->pos; + cur = pos - xo->top; + pal = (PAL *) xo_pool + cur; + + memcpy(&oldpal, pal, sizeof(PAL)); + pal_edit(xo->key, pal, GCARRY); + + if (memcmp(&oldpal, pal, sizeof(PAL))) + { + rec_put(xo->dir, pal, sizeof(PAL), pos, NULL); + if (xo->key == PALTYPE_PAL) + utmp_admset(pal->userno, STATUS_PALDIRTY); + move(3 + cur, 0); + pal_item(++pos, pal); + } + + return XO_FOOT; +} + + +static int +pal_mail(xo) + XO *xo; +{ + PAL *pal; + + pal = (PAL *) xo_pool + (xo->pos - xo->top); + return my_send(pal->userid); +} + + +static int +pal_write(xo) + XO *xo; +{ + if (HAS_PERM(PERM_PAGE)) + { + PAL *pal; + UTMP *up; + + pal = (PAL *) xo_pool + (xo->pos - xo->top); + + if (up = utmp_find(pal->userno)) + do_write(up); + } + return XO_NONE; +} + + +static int +pal_broadcast(xo) + XO *xo; +{ + int fd; + BMW bmw; + PAL *pal; + UTMP *up; + + if (!HAS_PERM(PERM_PAGE)) + return XO_NONE; + + bmw.caller = NULL; + bmw_edit(NULL, "¡¹¼s¼½¡G", &bmw); + + if (bmw.caller) /* bmw_edit() ¤¤¦^µª Yes n°e¥X¼s¼½ */ + { + /* itoc.000213: ¥[ "> " ¬°¤F»P¤@¯ë¤ô²y°Ï¤À */ + sprintf(bmw.userid, "%s> ", cuser.userid); + + if ((fd = open(xo->dir, O_RDONLY)) >= 0) + { + mgets(-1); + while (pal = mread(fd, sizeof(PAL))) + { + if (pal->ftype & PAL_BAD) + continue; + + if (!(up = utmp_find(pal->userno))) + continue; + +#ifdef HAVE_NOBROAD + if (up->ufo & UFO_RCVER) + continue; +#endif + + if (can_override(up)) + { + bmw.recver = up->userno; + bmw_send(up, &bmw); + } + } + close(fd); + } + } + + return XO_NONE; +} + + +#if (defined(HAVE_MODERATED_BOARD) || defined(HAVE_LIST)) +static int +pal_cite(xo) + XO *xo; +{ + int fd, num; + char fpath[64], *dir; + PAL *pal; + + fd = vans("n¤Þ¤J (P)ªB¤Í¦W³æ " +#ifdef HAVE_MODERATED_BOARD + "(B)ªO¤Í¦W³æ " +#endif +#ifdef HAVE_LIST + "(1-5)¯S§O¦W³æ" +#endif + "¡H[Q] "); + + if (fd == 'p') + { + usr_fpath(fpath, cuser.userid, fn_pal); + } +#ifdef HAVE_MODERATED_BOARD + else if (fd == 'b') + { + if (currbno < 0 || !(bbstate & STAT_BOARD)) + { + vmsg("±z©|¥¼¿ï©w¬ÝªO¡A©Î¬O±z¤£¬O¸ÓªOªºªO¥D"); + return XO_FOOT; + } + brd_fpath(fpath, currboard, fn_pal); + } +#endif +#ifdef HAVE_LIST + else if (fd >= '1' && fd <= '5') + { + char buf[32]; + sprintf(buf, "%s.%c", FN_LIST, fd); + usr_fpath(fpath, cuser.userid, buf); + } +#endif + else + { + return XO_FOOT; + } + + dir = xo->dir; + if (!strcmp(dir, fpath)) + { + vmsg("¤£¯à¤Þ¤J¦P¤@¥÷¦W³æ"); + return XO_FOOT; + } + + if ((fd = open(fpath, O_RDONLY)) < 0) + return XO_FOOT; + + num = PAL_MAX - xo->max; + + mgets(-1); + while (pal = mread(fd, sizeof(PAL))) + { + if (!(pal->ftype & PAL_BAD) && !pal_find(dir, pal->userno)) + { + if (--num < 0) /* itoc.001224: ¤Þ¤J¦W³æ¥u¥[¨ì PAL_MAX */ + break; + + rec_add(dir, pal, sizeof(PAL)); + xo->pos = XO_TAIL; /* Y¦³¤Þ¤J¦W³æ¡A´N§â´å¼Ð©ñ¦b³Ì«á */ + } + } + close(fd); + + return pal_load(xo); +} +#endif + + +static int +pal_sort(xo) + XO *xo; +{ + pal_sync(xo->dir); + return pal_load(xo); +} + + +static int +pal_query(xo) + XO *xo; +{ + PAL *pal; + + pal = (PAL *) xo_pool + (xo->pos - xo->top); + move(1, 0); + clrtobot(); + my_query(pal->userid); + return pal_head(xo); +} + + +static int +pal_tag(xo) + XO *xo; +{ + PAL *pal; + int tag, pos, cur; + + pos = xo->pos; + cur = pos - xo->top; + pal = (PAL *) xo_pool + cur; + + if (tag = Tagger(pal->userno, pos, TAG_TOGGLE)) + { + move(3 + cur, 6); + outc(tag > 0 ? '*' : ' '); + } + + /* return XO_NONE; */ + return xo->pos + 1 + XO_MOVE; /* lkchu.981201: ¸õ¦Ü¤U¤@¶µ */ +} + + +static int +pal_help(xo) + XO *xo; +{ + xo_help("pal"); + return pal_head(xo); +} + + +KeyFunc pal_cb[] = +{ + XO_INIT, pal_init, + XO_LOAD, pal_load, + XO_HEAD, pal_head, + XO_BODY, pal_body, + + 'a', pal_add, + 'c', pal_change, + 'd', pal_delete, + 'D', pal_rangedel, + 'm', pal_mail, + 'w', pal_write, + 'B', pal_broadcast, + 'r', pal_query, + Ctrl('Q'), pal_query, + 's', pal_sort, + 't', pal_tag, + Ctrl('D'), pal_prune, + +#if (defined(HAVE_MODERATED_BOARD) || defined(HAVE_LIST)) + 'f', pal_cite, +#endif + + 'h', pal_help +}; + + +int +t_pal() +{ + XO *xo; + char fpath[64]; + + usr_fpath(fpath, cuser.userid, fn_pal); + xz[XZ_PAL - XO_ZONE].xo = xo = xo_new(fpath); + xo->key = PALTYPE_PAL; + xover(XZ_PAL); + free(xo); + + /* itoc.041211.µù¸Ñ: ¦bÂ÷¶}ªB¤Í¦W³æ¦A¤@¨Ö¦P¨B cache ¬O¦³°ÝÃDªº¡A + ·í§Ú©|¥¼Â÷¶}ªB¤Í¦W³æ®É¡A¦¹®É cutmp->pal_spool ©|¥¼¦P¨B¡A + ¦ý³Q§Ú²§°ÊªB¤Íª¬ºAªº¹ï¤è¤w¸g¥[¤J¤F STATUS_PALDIRTY¡A + Y¹ï¤è¦b§Ú©|¥¼Â÷¶}ªB¤Í¦W³æ®É´N¥ý¦æ¶i¤J¨Ï¥ÎªÌ¦W³æ¡A + ³o®ÉÁöµM¥L¤w¸g¦¬¨ì§Úµ¹¥Lªº STATUS_PALDIRTY¡AµM¦Ó«o¦]¬°§Úªº pal_spool ©|¥¼¦P¨B¡A + ©ó¬O¥L¨Ã¨S¦³¦¨¥\Åܧó§ÚªºªB¤Íª¬ºA¡A¦ý STATUS_PALDIRTY ¤w®ø¥¢¡C + n¸Ñ¨M³oÓ°ÝÃD¡A±o¦b²§°Ê¨C¤@µ§ªB¤Í®Éªº utmp_admset(STATUS_PALDIRTY) ¤§«e´N¥ý pal_cache()¡A + ¤£¹L²{¦bÁÙ¨S¦³¤H©ê«è³o°ÝÃD¡A©Ò¥H´N¬ÙÂI¤u¦n¤F :p */ + + pal_cache(); /* itoc.010923: Â÷¶}ªB¤Í¦W³æ¦A¤@¨Ö¦P¨B cache */ + + return 0; +} + + +#ifdef HAVE_LIST +int +t_list() +{ + int n; + char fpath[64], buf[8]; + XO *xo; + + move(MENU_XPOS, 0); + clrtobot(); + + for (n = 1; n <= 5; n++) + { + move(n + MENU_XPOS - 1, MENU_YPOS - 1); + prints("(\033[1;36m%d\033[m) ¸s²Õ¦W³æ.%d", n, n); + } + + n = vans("½Ð¿ï¾ÜÀÉ®×½s¸¹¡A©Î«ö [0] ¨ú®ø¡G") - '0'; + if (n <= 0 || n > 5) + return 0; + + sprintf(buf, "%s.%d", FN_LIST, n); + usr_fpath(fpath, cuser.userid, buf); + + switch (vget(b_lines, 36, "(D)§R°£ (E)½s¿è [Q]¨ú®ø¡H", buf, 3, LCECHO)) + { + case 'd': + unlink(fpath); + break; + + case 'e': + /* ɥΠXZ_PAL §Y¥i */ + xz[XZ_PAL - XO_ZONE].xo = xo = xo_new(fpath); + xo->key = PALTYPE_LIST; + xover(XZ_PAL); + free(xo); + break; + } + + return 0; +} +#endif diff --git a/maple/post.c b/maple/post.c new file mode 100644 index 0000000..a62d6b5 --- /dev/null +++ b/maple/post.c @@ -0,0 +1,2730 @@ +/*-------------------------------------------------------*/ +/* post.c ( NTHU CS MapleBBS Ver 2.39 ) */ +/*-------------------------------------------------------*/ +/* target : bulletin boards' routines */ +/* create : 95/03/29 */ +/* update : 96/04/05 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" +#include <sys/wait.h> + + +extern BCACHE *bshm; +extern XZ xz[]; + + +extern int wordsnum; /* itoc.010408: pºâ¤å³¹¦r¼Æ */ +extern int TagNum; +extern char xo_pool[]; +extern char brd_bits[]; + + +#ifdef HAVE_ANONYMOUS +extern char anonymousid[]; /* itoc.010717: ¦Û©w°Î¦W ID */ +#endif + + +int +cmpchrono(hdr) + HDR *hdr; +{ + return hdr->chrono == currchrono; +} + + +/* ----------------------------------------------------- */ +/* §ï¨} innbbsd Âà¥X«H¥ó¡B³s½u¬å«H¤§³B²zµ{§Ç */ +/* ----------------------------------------------------- */ + + +void +btime_update(bno) + int bno; +{ + if (bno >= 0) + (bshm->bcache + bno)->btime = -1; /* Åý class_item() §ó·s¥Î */ +} + + +#ifndef HAVE_NETTOOL +static /* µ¹ enews.c ¥Î */ +#endif +void +outgo_post(hdr, board) + HDR *hdr; + char *board; +{ + bntp_t bntp; + + memset(&bntp, 0, sizeof(bntp_t)); + + if (board) /* ·s«H */ + { + bntp.chrono = hdr->chrono; + } + else /* cancel */ + { + bntp.chrono = -1; + board = currboard; + } + strcpy(bntp.board, board); + strcpy(bntp.xname, hdr->xname); + strcpy(bntp.owner, hdr->owner); + strcpy(bntp.nick, hdr->nick); + strcpy(bntp.title, hdr->title); + rec_add("innd/out.bntp", &bntp, sizeof(bntp_t)); +} + + +void +cancel_post(hdr) + HDR *hdr; +{ + if ((hdr->xmode & POST_OUTGO) && /* ¥~Âà«H¥ó */ + (hdr->chrono > ap_start - 7 * 86400)) /* 7 ¤Ñ¤§¤º¦³®Ä */ + { + outgo_post(hdr, NULL); + } +} + + +static inline int /* ¦^¶Ç¤å³¹ size ¥h¦©¿ú */ +move_post(hdr, folder, by_bm) /* ±N hdr ±q folder ·h¨ì§OªºªO */ + HDR *hdr; + char *folder; + int by_bm; +{ + HDR post; + int xmode; + char fpath[64], fnew[64], *board; + struct stat st; + + xmode = hdr->xmode; + hdr_fpath(fpath, folder, hdr); + + if (!(xmode & POST_BOTTOM)) /* ¸m©³¤å³Q¬å¤£¥Î move_post */ + { +#ifdef HAVE_REFUSEMARK + board = by_bm && !(xmode & POST_RESTRICT) ? BN_DELETED : BN_JUNK; /* ¥[±K¤å³¹¥á¥h junk */ +#else + board = by_bm ? BN_DELETED : BN_JUNK; +#endif + + brd_fpath(fnew, board, fn_dir); + hdr_stamp(fnew, HDR_LINK | 'A', &post, fpath); + + /* ª½±µ½Æ»s trailing data¡Gowner(§t)¥H¤U©Ò¦³Äæ¦ì */ + + memcpy(post.owner, hdr->owner, sizeof(HDR) - + (sizeof(post.chrono) + sizeof(post.xmode) + sizeof(post.xid) + sizeof(post.xname))); + + if (by_bm) + sprintf(post.title, "%-13s%.59s", cuser.userid, hdr->title); + + if (hdr->xmode & POST_RESTRICT) post.xmode |= POST_RESTRICT; + + rec_bot(fnew, &post, sizeof(HDR)); + btime_update(brd_bno(board)); + } + + by_bm = stat(fpath, &st) ? 0 : st.st_size; + + unlink(fpath); + btime_update(currbno); + cancel_post(hdr); + + return by_bm; +} + + +#ifdef HAVE_DETECT_CROSSPOST +/* ----------------------------------------------------- */ +/* §ï¨} cross post °±Åv */ +/* ----------------------------------------------------- */ + + +#define MAX_CHECKSUM_POST 20 /* °O¿ý³Ìªñ 20 ½g¤å³¹ªº checksum */ +#define MAX_CHECKSUM_LINE 6 /* ¥u¨ú¤å³¹«e 6 ¦æ¨Óºâ checksum */ + + +typedef struct +{ + int sum; /* ¤å³¹ªº checksum */ + int total; /* ¦¹¤å³¹¤wµoªí´X½g */ +} CHECKSUM; + + +static CHECKSUM checksum[MAX_CHECKSUM_POST]; +static int checknum = 0; + + +static inline int +checksum_add(str) /* ¦^¶Ç¥»¦æ¤å¦rªº checksum */ + char *str; +{ + int sum, i, len; + char *ptr; + + ptr = str; + len = strlen(str) >> 2; /* ¥uºâ«e¥|¤À¤§¤@ */ + + sum = 0; + for (i = 0; i < len; i++) + sum += *ptr++; + + return sum; +} + + +static inline int /* 1:¬Ocross-post 0:¤£¬Ocross-post */ +checksum_put(sum) + int sum; +{ + int i; + + if (sum) + { + for (i = 0; i < MAX_CHECKSUM_POST; i++) + { + if (checksum[i].sum == sum) + { + checksum[i].total++; + + if (checksum[i].total > MAX_CROSS_POST) + return 1; + return 0; /* total <= MAX_CROSS_POST */ + } + } + + if (++checknum >= MAX_CHECKSUM_POST) + checknum = 0; + checksum[checknum].sum = sum; + checksum[checknum].total = 1; + } + return 0; +} + + +static int /* 1:¬Ocross-post 0:¤£¬Ocross-post */ +checksum_find(fpath) + char *fpath; +{ + int i, sum; + char buf[ANSILINELEN]; + FILE *fp; + + sum = 0; + if (fp = fopen(fpath, "r")) + { + for (i = -4;;) /* «e¥|¦C¬OÀÉÀY */ + { + if (!fgets(buf, ANSILINELEN, fp)) + break; + + if (i < 0) /* ¸õ¹LÀÉÀY */ + { + i++; + continue; + } + + if (*buf == QUOTE_CHAR1 || *buf == '\n' || !strncmp(buf, "¡°", 2)) /* ¸õ¹L¤Þ¨¥ */ + continue; + + sum += checksum_add(buf); + if (++i >= MAX_CHECKSUM_LINE) + break; + } + + fclose(fp); + } + + return checksum_put(sum); +} + + +static int +check_crosspost(fpath, bno) + char *fpath; + int bno; /* nÂà¥hªº¬ÝªO */ +{ + char *blist, folder[64]; + ACCT acct; + HDR hdr; + + if (HAS_PERM(PERM_ALLADMIN)) + return 0; + + /* ªO¥D¦b¦Û¤vºÞ²zªº¬ÝªO¤£¦C¤J¸ó¶KÀˬd */ + blist = (bshm->bcache + bno)->BM; + if (HAS_PERM(PERM_BM) && blist[0] > ' ' && is_bm(blist, cuser.userid)) + return 0; + + if (checksum_find(fpath)) + { + /* ¦pªG¬O cross-post¡A¨º»òÂà¥h BN_SECURITY ¨Ãª½±µ°±Åv */ + brd_fpath(folder, BN_SECURITY, fn_dir); + hdr_stamp(folder, HDR_COPY | 'A', &hdr, fpath); + strcpy(hdr.owner, cuser.userid); + strcpy(hdr.nick, cuser.username); + sprintf(hdr.title, "%s %s Cross-Post", cuser.userid, Now()); + rec_bot(folder, &hdr, sizeof(HDR)); + btime_update(brd_bno(BN_SECURITY)); + + bbstate &= ~STAT_POST; + cuser.userlevel &= ~PERM_POST; + cuser.userlevel |= PERM_DENYPOST; + if (acct_load(&acct, cuser.userid) >= 0) + { + acct.tvalid = time(NULL) + CROSSPOST_DENY_DAY * 86400; + acct_setperm(&acct, PERM_DENYPOST, PERM_POST); + } + board_main(); + mail_self(FN_ETC_CROSSPOST, str_sysop, "Cross-Post °±Åv", 0); + vmsg("±z¦]¬°¹L«× Cross-Post ¤w³Q°±Åv"); + return 1; + } + return 0; +} +#endif /* HAVE_DETECT_CROSSPOST */ + + +/* ----------------------------------------------------- */ +/* µoªí¡B¦^À³¡B½s¿è¡BÂà¿ý¤å³¹ */ +/* ----------------------------------------------------- */ + + +#ifdef HAVE_ANONYMOUS +static void +log_anonymous(fname) + char *fname; +{ + char buf[512]; + + sprintf(buf, "%s %-13s(%s)\n%-13s %s %s\n", + Now(), cuser.userid, fromhost, currboard, fname, ve_title); + f_cat(FN_RUN_ANONYMOUS, buf); +} +#endif + + +#ifdef HAVE_UNANONYMOUS_BOARD +static void +do_unanonymous(fpath) + char *fpath; +{ + HDR hdr; + char folder[64]; + + brd_fpath(folder, BN_UNANONYMOUS, fn_dir); + hdr_stamp(folder, HDR_LINK | 'A', &hdr, fpath); + + strcpy(hdr.owner, cuser.userid); + strcpy(hdr.title, ve_title); + + rec_bot(folder, &hdr, sizeof(HDR)); + btime_update(brd_bno(BN_UNANONYMOUS)); +} +#endif + +void +add_post(brdname, fpath, title) /* µo¤å¨ì¬ÝªO */ + char *brdname; /* ±ý post ªº¬ÝªO */ + char *fpath; /* Àɮ׸ô®| */ + char *title; /* ¤å³¹¼ÐÃD */ +{ + HDR hdr; + char folder[64]; + + brd_fpath(folder, brdname, fn_dir); + hdr_stamp(folder, HDR_LINK | 'A', &hdr, fpath); + strcpy(hdr.owner, cuser.userid); + strcpy(hdr.nick, cuser.username); + strcpy(hdr.title, title); + rec_bot(folder, &hdr, sizeof(HDR)); + + btime_update(brd_bno(brdname)); +} + +static int +do_post(xo, title) + XO *xo; + char *title; +{ + /* Thor.981105: ¶i¤J«e»Ý³]¦n curredit ¤Î quote_file */ + HDR hdr, buf; + char fpath[64], *folder, *nick, *rcpt; + int mode; + time_t spendtime, prev, chrono; + + if (!(bbstate & STAT_POST)) + { +#ifdef NEWUSER_LIMIT + if (cuser.lastlogin - cuser.firstlogin < 3 * 86400) + vmsg("·s¤â¤W¸ô¡A¤T¤é«á©l¥i±i¶K¤å³¹"); + else +#endif + vmsg("¹ï¤£°_¡A±z¨S¦³¦b¦¹µoªí¤å³¹ªºÅv"); + return XO_FOOT; + } + brd_fpath(fpath, currboard, FN_POSTLAW); + if (more(fpath, (char *) -1) < 0) + film_out(FILM_POST, 0); + + prints("µoªí¤å³¹©ó¡i %s ¡j¬ÝªO", currboard); + +#ifdef POST_PREFIX + /* ɥΠmode¡Brcpt¡Bfpath */ + + if (title) + { + rcpt = NULL; + } + else /* itoc.020113: ·s¤å³¹¿ï¾Ü¼ÐÃD¤ÀÃþ */ + { +#define NUM_PREFIX 9 + + #if 0 + char *prefix[NUM_PREFIX] = {"[¤½§i] ", "[·s»D] ", "[¶¢²á] ", "[¤å¥ó] ", "[°ÝÃD] ", "[´ú¸Õ] "}; + + move(21, 0); + outs("Ãþ§O¡G"); + for (mode = 0; mode < NUM_PREFIX; mode++) + prints("%d.%s", mode + 1, prefix[mode]); + + mode = vget(20, 0, "½Ð¿ï¾Ü¤å³¹Ãþ§O¡]«ö Enter ¸õ¹L¡^¡G", fpath, 3, DOECHO) - '1'; + if (mode >= 0 && mode < NUM_PREFIX) /* ¿é¤J¼Æ¦r¿ï¶µ */ + rcpt = prefix[mode]; + else /* ªÅ¥Õ¸õ¹L */ + rcpt = NULL; + } + + #endif + + FILE *fp; + char prefix[NUM_PREFIX][10]; + + brd_fpath(fpath, currboard, "prefix"); + if (fp = fopen(fpath, "r")) + { + move(21, 0); +// outs("Ãþ§O¡G"); + for (mode = 0; mode < NUM_PREFIX; mode++) + { + //if (fscanf(fp, "%9s", fpath) != 1) + if (fgets(fpath, 11, fp) == NULL) + break; + fpath[strlen(fpath)-1] = 0; + /* hrs:¦]¬°³Ì«á¤@ÓŪ¤Jªº¦r¤¸¬O\n ´«¦æ¦r¤¸ n¥h°£±¼ */ + strcpy(prefix[mode], fpath); + if(mode == NUM_PREFIX/2) + move(22, 0); + prints("%d:\033[1;33m%s\033[m ", mode + 1, fpath); + } + + fclose(fp); + mode = vget(20, 0, "½Ð¿ï¾Ü¤å³¹Ãþ§O¡]«ö Enter ¸õ¹L¡^¡G", + fpath, 3, DOECHO) - '1'; + if (mode >= 0 && mode < NUM_PREFIX) /* ¿é¤J¼Æ¦r¿ï¶µ */ +// rcpt = prefix[mode]; + rcpt = strcat (prefix[mode], " "); + else /* ªÅ¥Õ¸õ¹L */ + rcpt = NULL; + } + else + { + rcpt = NULL; + } + } + if (!ve_subject(21, title, rcpt)) +#else + if (!ve_subject(21, title, NULL)) +#endif + return XO_HEAD; + + /* ¥¼¨ã³Æ Internet ÅvªÌ¡A¥u¯à¦b¯¸¤ºµoªí¤å³¹ */ + /* Thor.990111: ¨SÂà«H¥X¥hªº¬ÝªO, ¤]¥u¯à¦b¯¸¤ºµoªí¤å³¹ */ + + if (!HAS_PERM(PERM_INTERNET) || (currbattr & BRD_NOTRAN)) + curredit &= ~EDIT_OUTGO; + + utmp_mode(M_POST); + fpath[0] = '\0'; + time(&spendtime); + if (vedit(fpath, 1) < 0) + { + unlink(fpath); + vmsg(msg_cancel); + return XO_HEAD; + } + spendtime = time(0) - spendtime; /* itoc.010712: Á`¦@ªáªº®É¶¡(¬í¼Æ) */ + + /* build filename */ + + folder = xo->dir; + hdr_stamp(folder, HDR_LINK | 'A', &hdr, fpath); + + /* set owner to anonymous for anonymous board */ + +#ifdef HAVE_ANONYMOUS + /* Thor.980727: lkchu·s¼W¤§[²³æªº¿ï¾Ü©Ê°Î¦W¥\¯à] */ + if (curredit & EDIT_ANONYMOUS) + { + rcpt = anonymousid; /* itoc.010717: ¦Û©w°Î¦W ID */ + nick = STR_ANONYMOUS; + + /* Thor.980727: lkchu patch: log anonymous post */ + /* Thor.980909: gc patch: log anonymous post filename */ + //log_anonymous(hdr.xname); + +#ifdef HAVE_UNANONYMOUS_BOARD + do_unanonymous(fpath); +#endif + } + else +#endif + { + rcpt = cuser.userid; + nick = cuser.username; + } + title = ve_title; + mode = (curredit & EDIT_OUTGO) ? POST_OUTGO : 0; +#ifdef HAVE_REFUSEMARK + if (curredit & EDIT_RESTRICT) + mode |= POST_RESTRICT; +#endif + + if (!(currbattr & BRD_NOCOUNT || wordsnum < 30)) + mode |= POST_RECORDED; + + + hdr.xmode = mode; + strcpy(hdr.owner, rcpt); + strcpy(hdr.nick, nick); + strcpy(hdr.title, title); + + rec_bot(folder, &hdr, sizeof(HDR)); + btime_update(currbno); + + if (mode & POST_OUTGO) + outgo_post(&hdr, currboard); + +#if 1 /* itoc.010205: post §¹¤å³¹´N°O¿ý¡A¨Ï¤£¥X²{¥¼¾\Ūªº¡Ï¸¹ */ + chrono = hdr.chrono; + prev = ((mode = rec_num(folder, sizeof(HDR)) - 2) >= 0 && !rec_get(folder, &buf, sizeof(HDR), mode)) ? buf.chrono : chrono; + brh_add(prev, chrono, chrono); +#endif + + clear(); + outs("¶¶§Q¶K¥X¤å³¹¡A"); + +// if (currbattr & BRD_NOCOUNT || wordsnum < 30) + if (!(hdr.xmode & POST_RECORDED)) + { /* itoc.010408: ¥H¦¹´î¤ÖÄé¤ô²{¶H */ + outs("¤å³¹¤£¦C¤J¬ö¿ý¡A·q½Ð¥]²[¡C"); + } + else + { + /* itoc.010408: ¨Ì¤å³¹ªø«×/©Ò¶O®É¶¡¨Ó¨M©wnµ¹¦h¤Ö¿ú¡F¹ô¨î¤~·|¦³·N¸q */ + mode = BMIN(wordsnum, spendtime) / 10; /* ¨C¤Q¦r/¬í ¤@¤¸ */ + prints("³o¬O±zªº²Ä %d ½g¤å³¹¡A±o %d »È¡C", ++cuser.numposts, mode); + addmoney(mode); + } + + /* ¦^À³¨ìì§@ªÌ«H½c */ + + if (curredit & EDIT_BOTH) + { + rcpt = quote_user; + + if (strchr(rcpt, '@')) /* ¯¸¥~ */ + mode = bsmtp(fpath, title, rcpt, 0); + else /* ¯¸¤º¨Ï¥ÎªÌ */ + mode = mail_him(fpath, rcpt, title, 0); + + outs(mode >= 0 ? "\n\n¦¨¥\\¦^À³¦Ü§@ªÌ«H½c" : "\n\n§@ªÌµLªk¦¬«H"); + } + + unlink(fpath); + + vmsg(NULL); + + return XO_INIT; +} + + +int +do_reply(xo, hdr) + XO *xo; + HDR *hdr; +{ + curredit = 0; + + switch (vans("¡¶ ¦^À³¦Ü (F)¬ÝªO (M)§@ªÌ«H½c (B)¤GªÌ¬Ò¬O (Q)¨ú®ø¡H[F] ")) + { + case 'm': + hdr_fpath(quote_file, xo->dir, hdr); + return do_mreply(hdr, 0); + + case 'q': + return XO_FOOT; + + case 'b': + /* YµL±H«HªºÅv¡A«h¥u¦^¬ÝªO */ + if (HAS_PERM(strchr(hdr->owner, '@') ? PERM_INTERNET : PERM_LOCAL)) + curredit = EDIT_BOTH; + break; + } + + /* Thor.981105: ¤£½×¬OÂà¶iªº, ©Î¬OnÂà¥Xªº, ³£¬O§O¯¸¥i¬Ý¨ìªº, ©Ò¥H¦^«H¤]³£À³¸ÓÂà¥X */ + if (hdr->xmode & (POST_INCOME | POST_OUTGO)) + curredit |= EDIT_OUTGO; + + hdr_fpath(quote_file, xo->dir, hdr); + strcpy(quote_user, hdr->owner); + strcpy(quote_nick, hdr->nick); + return do_post(xo, hdr->title); +} + + +static int +post_reply(xo) + XO *xo; +{ + if (bbstate & STAT_POST) + { + HDR *hdr; + + hdr = (HDR *) xo_pool + (xo->pos - xo->top); + +#ifdef HAVE_REFUSEMARK + if ((hdr->xmode & POST_RESTRICT) && + strcmp(hdr->owner, cuser.userid) && !(bbstate & STAT_BM)) + return XO_NONE; +#endif + + return do_reply(xo, hdr); + } + return XO_NONE; +} + + +static int +post_add(xo) + XO *xo; +{ + curredit = EDIT_OUTGO; + *quote_file = '\0'; + return do_post(xo, NULL); +} + + +/* ----------------------------------------------------- */ +/* ¦L¥X hdr ¼ÐÃD */ +/* ----------------------------------------------------- */ + + +int +tag_char(chrono) + int chrono; +{ + return TagNum && !Tagger(chrono, 0, TAG_NIN) ? '*' : ' '; +} + + +#ifdef HAVE_DECLARE +static inline int +cal_day(date) /* itoc.010217: pºâ¬P´Á´X */ + char *date; +{ +#if 0 + ½²°Ç¤½¦¡¬O¤@Ó±Àºâþ¤@¤Ñ¬O¬P´Á´Xªº¤½¦¡. + ³o¤½¦¡¬O: + c y 26(m+1) + W= [---] - 2c + y + [---] + [---------] + d - 1 + 4 4 10 + W ¡÷ ¬°©Ò¨D¤é´Áªº¬P´Á¼Æ. (¬P´Á¤é: 0 ¬P´Á¤@: 1 ... ¬P´Á¤»: 6) + c ¡÷ ¬°¤wª¾¤½¤¸¦~¥÷ªº«e¨â¦ì¼Æ¦r. + y ¡÷ ¬°¤wª¾¤½¤¸¦~¥÷ªº«á¨â¦ì¼Æ¦r. + m ¡÷ ¬°¤ë¼Æ + d ¡÷ ¬°¤é¼Æ + [] ¡÷ ªí¥Ü¥u¨ú¸Ó¼Æªº¾ã¼Æ³¡¤À (¦aªO¨ç¼Æ) + ps.©Ò¨Dªº¤ë¥÷¦pªG¬O1¤ë©Î2¤ë,«hÀ³µø¬°¤W¤@¦~ªº13¤ë©Î14¤ë. + ©Ò¥H¤½¦¡¤¤mªº¨úȽd³ò¤£¬O1¨ì12,¦Ó¬O3¨ì14 +#endif + + /* ¾A¥Î 2000/03/01 ¦Ü 2099/12/31 */ + + int y, m, d; + + y = 10 * ((int) (date[0] - '0')) + ((int) (date[1] - '0')); + d = 10 * ((int) (date[6] - '0')) + ((int) (date[7] - '0')); + if (date[3] == '0' && (date[4] == '1' || date[4] == '2')) + { + y -= 1; + m = 12 + (int) (date[4] - '0'); + } + else + { + m = 10 * ((int) (date[3] - '0')) + ((int) (date[4] - '0')); + } + return (-1 + y + y / 4 + 26 * (m + 1) / 10 + d) % 7; +} +#endif + + +void +hdr_outs(hdr, cc) /* print HDR's subject */ + HDR *hdr; + int cc; /* ¦L¥X³Ì¦h cc - 1 ¦rªº¼ÐÃD */ +{ + /* ¦^ÂÐ/Âà¿ý/ì³Ð/¾\Ū¤¤ªº¦P¥DÃD¦^ÂÐ/¾\Ū¤¤ªº¦P¥DÃDÂà¿ý/¾\Ū¤¤ªº¦P¥DÃDì³Ð */ + static char *type[6] = {"Re", "Fw", "¡º", "\033[1;33m=>", "\033[1;33m=>", "\033[1;32m¡»"}; + uschar *title, *mark; + int ch, len; +#ifdef HAVE_DECLARE + int square; +#endif +#ifdef CHECK_ONLINE + UTMP *online; +#endif + + /* --------------------------------------------------- */ + /* ¦L¥X¤é´Á */ + /* --------------------------------------------------- */ + +#ifdef HAVE_DECLARE + /* itoc.010217: §ï¥Î¬P´Á´X¨Ó¤W¦â */ + prints("\033[1;3%dm%s\033[m ", cal_day(hdr->date) + 1, hdr->date + 3); +#else + outs(hdr->date + 3); + outc(' '); +#endif + + /* --------------------------------------------------- */ + /* ¦L¥X§@ªÌ */ + /* --------------------------------------------------- */ + +#ifdef CHECK_ONLINE + if (online = utmp_seek(hdr)) + outs(COLOR7); +#endif + + mark = hdr->owner; + len = IDLEN + 1; + + while (ch = *mark) + { + if ((--len <= 0) || (ch == '@')) /* ¯¸¥~ªº§@ªÌ§â '@' ´«¦¨ '.' */ + ch = '.'; + outc(ch); + + if (ch == '.') + break; + + mark++; + } + + while (len--) + { + outc(' '); + } + +#ifdef CHECK_ONLINE + if (online) + outs(str_ransi); +#endif + + /* --------------------------------------------------- */ + /* ¦L¥X¼ÐÃDªººØÃþ */ + /* --------------------------------------------------- */ + + title = str_ttl(mark = hdr->title); + ch = (title == mark) ? 2 : (*mark == 'R') ? 0 : 1; + if (!strcmp(currtitle, title)) + ch += 3; + outs(type[ch]); + outc(' '); + + /* --------------------------------------------------- */ + /* ¦L¥X¼ÐÃD */ + /* --------------------------------------------------- */ + + mark = title + cc; + +#ifdef HAVE_DECLARE /* Thor.980508: Declaration, ¹Á¸Õ¨Ï¬Y¨Çtitle§ó©úÅã */ + square = 0; /* 0:¤£³B²z¤è¬A 1:n³B²z¤è¬A */ + if (ch < 3) + { + if (*title == '[') + { + outs("\033[1m"); + square = 1; + } + } +#endif + + while ((cc = *title++) && (title < mark)) + { +#ifdef HAVE_DECLARE + if (square) + { + if (IS_ZHC_HI(square) || IS_ZHC_HI(cc)) /* ¤¤¤å¦rªº²Ä¤G½XY¬O ']' ¤£ºâ¬O¤è¬A */ + square ^= 0x80; + else if (cc == ']') + { + outs("]\033[m"); + square = 0; + continue; + } + } +#endif + + outc(cc); + } + +#ifdef HAVE_DECLARE + if (square || ch >= 3) /* Thor.980508: ÅܦâÁÙì¥Î */ +#else + if (ch >= 3) +#endif + outs("\033[m"); + + outc('\n'); +} + + +/* ----------------------------------------------------- */ +/* ¬ÝªO¥\¯àªí */ +/* ----------------------------------------------------- */ + + +static int post_body(); +static int post_head(); + + +static int +post_init(xo) + XO *xo; +{ + xo_load(xo, sizeof(HDR)); + return post_head(xo); +} + + +static int +post_load(xo) + XO *xo; +{ + xo_load(xo, sizeof(HDR)); + return post_body(xo); +} + + +static int +post_attr(hdr) + HDR *hdr; +{ + int mode, attr; + + mode = hdr->xmode; + + /* ¥Ñ©ó¸m©³¤å¨S¦³¾\Ū°O¿ý¡A©Ò¥Hµø¬°¤wŪ */ + attr = !(mode & POST_BOTTOM) && brh_unread(hdr->chrono) ? 0 : 0x20; /* ¤w¾\Ū¬°¤p¼g¡A¥¼¾\Ū¬°¤j¼g */ + +#ifdef HAVE_REFUSEMARK + if (mode & POST_RESTRICT) + attr |= 'X'; + else +#endif +#ifdef HAVE_LABELMARK + if (mode & POST_DELETE) + attr |= 'T'; + else +#endif + if (mode & POST_MARKED) + attr |= 'M'; + else if (!attr) + attr = '+'; + + return attr; +} + + +static void +post_item(num, hdr) + int num; + HDR *hdr; +{ +#ifdef HAVE_SCORE + static char scorelist[36] = + { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z' + }; + +// prints("%6d%c%c", (hdr->xmode & POST_BOTTOM) ? -1 : num, tag_char(hdr->chrono), post_attr(hdr)); + +// prints("%6d%c%s%c%s", (hdr->xmode & POST_BOTTOM) ? -1 : num, tag_char(hdr->chrono), +// hdr->xmode & (POST_MARKED | POST_RESTRICT ) ? "\033[1;33m" : "", post_attr(hdr), +// hdr->xmode & (POST_MARKED | POST_RESTRICT) ? "\033[m" : ""); + + if (hdr->xmode & POST_BOTTOM) + prints(" \033[1;33m¡¹\033[m%c%s%c%s", tag_char(hdr->chrono), + hdr->xmode & POST_MARKED && hdr->xmode & POST_RESTRICT ? "\033[1m" : "", post_attr(hdr), + hdr->xmode & POST_MARKED && hdr->xmode & POST_RESTRICT ? "\033[m" : ""); + else + prints("%6d%c%s%c%s", num, tag_char(hdr->chrono), + hdr->xmode & POST_MARKED && hdr->xmode & POST_RESTRICT ? "\033[1m" : "", post_attr(hdr), + hdr->xmode & POST_MARKED && hdr->xmode & POST_RESTRICT ? "\033[m" : ""); + + if (hdr->xmode & POST_SCORE) + { + num = hdr->score; +// prints("\033[1;3%cm%c\033[m ", num >= 0 ? '1' : '2', scorelist[abs(num)]); + if (num < 36 && num > -36) /* qazq.031013: ¥i¥H±À¨ì"Ãz"*/ + prints("\033[1;3%cm%c\033[m ", num >= 0 ? '1' : '2', scorelist[abs(num)]); + else + prints("\033[1;3%s\033[m", num >= 0 ? "1m¡Û" : "2m¡Û"); + + } + else + { + outs(" "); + } + hdr_outs(hdr, d_cols + 46); /* ¤Ö¤@®æ¨Ó©ñ¤À¼Æ */ +#else + prints("%6d%c%c ", (hdr->xmode & POST_BOTTOM) ? -1 : num, tag_char(hdr->chrono), post_attr(hdr)); + hdr_outs(hdr, d_cols + 47); +#endif +} + + +static int +post_body(xo) + XO *xo; +{ + HDR *hdr; + int num, max, tail; + + max = xo->max; + if (max <= 0) + { + if (bbstate & STAT_POST) + { + if (vans("n·s¼W¸ê®Æ¶Ü(Y/N)¡H[N] ") == 'y') + return post_add(xo); + } + else + { + vmsg("¥»¬ÝªO©|µL¤å³¹"); + } + return XO_QUIT; + } + + hdr = (HDR *) xo_pool; + num = xo->top; + tail = num + XO_TALL; + if (max > tail) + max = tail; + + move(3, 0); + do + { + post_item(++num, hdr++); + } while (num < max); + clrtobot(); + + /* return XO_NONE; */ + return XO_FOOT; /* itoc.010403: §â b_lines ¶ñ¤W feeter */ +} + + +static int +post_head(xo) + XO *xo; +{ + vs_head(currBM, xo->xyz); + prints(NECKER_POST, d_cols, "", + currbattr & BRD_NOPHONETIC ? "¢®" : "¡³", + currbattr & BRD_NOSCORE ? "¢®" : "¡³", bshm->mantime[currbno]); + return post_body(xo); +} + + +/* ----------------------------------------------------- */ +/* ¸ê®Æ¤§ÂsÄý¡Gbrowse / history */ +/* ----------------------------------------------------- */ + + +static int +post_visit(xo) + XO *xo; +{ + int ans, row, max; + HDR *hdr; + + ans = vans("³]©w©Ò¦³¤å³¹ (U)¥¼Åª (V)¤wŪ (W)«e¤wŪ«á¥¼Åª (Q)¨ú®ø¡H[Q] "); + if (ans == 'v' || ans == 'u' || ans == 'w') + { + row = xo->top; + max = xo->max - row + 3; + if (max > b_lines) + max = b_lines; + + hdr = (HDR *) xo_pool + (xo->pos - row); + /* brh_visit(ans == 'w' ? hdr->chrono : ans == 'u'); */ + /* weiyu.041010: ¦b¸m©³¤å¤W¿ï w µø¬°¥þ³¡¤wŪ */ + brh_visit((ans == 'u') ? 1 : (ans == 'w' && !(hdr->xmode & POST_BOTTOM)) ? hdr->chrono : 0); + + hdr = (HDR *) xo_pool; + +#if 0 + row = 3; + do + { + move(row, 7); + outc(post_attr(hdr++)); + } while (++row < max); +#endif + return post_body(xo); + } + return XO_FOOT; +} + + +static void +post_history(xo, hdr) /* ±N hdr ³o½g¥[¤J brh */ + XO *xo; + HDR *hdr; +{ + time_t prev, chrono, next; + int pos, top; + char *dir; + HDR buf; + + if (hdr->xmode & POST_BOTTOM) /* ¸m©³¤å¤£¥[¤J¾\Ū°O¿ý */ + return; + + chrono = hdr->chrono; + if (!brh_unread(chrono)) /* ¦pªG¤w¦b brh ¤¤¡A´NµL»Ý°Ê§@ */ + return; + + dir = xo->dir; + pos = xo->pos; + top = xo->top; + + pos--; + if (pos >= top) + { + prev = hdr[-1].chrono; + } + else + { + /* amaki.040302.µù¸Ñ: ¦bµe±¥H¤W¡A¥u¦nŪµwºÐ */ + if (!rec_get(dir, &buf, sizeof(HDR), pos)) + prev = buf.chrono; + else + prev = chrono; + } + + pos += 2; + if (pos < top + XO_TALL && pos < xo->max) + { + next = hdr[1].chrono; + } + else + { + /* amaki.040302.µù¸Ñ: ¦bµe±¥H¤U¡A¥u¦nŪµwºÐ */ + if (!rec_get(dir, &buf, sizeof(HDR), pos)) + next = buf.chrono; + else + next = chrono; + } + + brh_add(prev, chrono, next); +} + + +static int +post_browse(xo) + XO *xo; +{ + HDR *hdr; + int xmode, pos, key; + char *dir, fpath[64]; + + dir = xo->dir; + + for (;;) + { + pos = xo->pos; + hdr = (HDR *) xo_pool + (pos - xo->top); + xmode = hdr->xmode; + +#ifdef HAVE_REFUSEMARK + if ((xmode & POST_RESTRICT) && + strcmp(hdr->owner, cuser.userid) && !(bbstate & STAT_BM)) + break; +#endif + + hdr_fpath(fpath, dir, hdr); + + /* Thor.990204: ¬°¦Ò¼{more ¶Ç¦^È */ + if ((key = more(fpath, FOOTER_POST)) < 0) + break; + + post_history(xo, hdr); + strcpy(currtitle, str_ttl(hdr->title)); + +re_key: + switch (xo_getch(xo, key)) + { + case XO_BODY: + continue; + + case 'y': + case 'r': + if (bbstate & STAT_POST) + { + if (do_reply(xo, hdr) == XO_INIT) /* ¦³¦¨¥\¦a post ¥X¥h¤F */ + return post_init(xo); + } + break; + + case 'm': + if ((bbstate & STAT_BOARD) && !(xmode & POST_MARKED)) + { + /* hdr->xmode = xmode ^ POST_MARKED; */ + /* ¦b post_browse ®É¬Ý¤£¨ì m °O¸¹¡A©Ò¥H¨î¥u¯à mark */ + hdr->xmode = xmode | POST_MARKED; + currchrono = hdr->chrono; + rec_put(dir, hdr, sizeof(HDR), pos, cmpchrono); + } + break; + +#ifdef HAVE_SCORE + case '%': + post_score(xo); + return post_init(xo); +#endif + + case '/': + if (vget(b_lines, 0, "·j´M¡G", hunt, sizeof(hunt), DOECHO)) + { + more(fpath, FOOTER_POST); + goto re_key; + } + continue; + + case 'E': + return post_edit(xo); + + case 'C': /* itoc.000515: post_browse ®É¥i¦s¤J¼È¦sÀÉ */ + { + FILE *fp; + if (fp = tbf_open()) + { + f_suck(fp, fpath); + fclose(fp); + } + } + break; + + case 'h': + xo_help("post"); + break; + } + break; + } + + return post_head(xo); +} + + +/* ----------------------------------------------------- */ +/* ºëµØ°Ï */ +/* ----------------------------------------------------- */ + + +static int +post_gem(xo) + XO *xo; +{ + int level; + char fpath[64]; + + strcpy(fpath, "gem/"); + strcpy(fpath + 4, xo->dir); + + level = 0; + if (bbstate & STAT_BOARD) + level ^= GEM_W_BIT; + if (HAS_PERM(PERM_SYSOP)) + level ^= GEM_X_BIT; + if (bbstate & STAT_BM) + level ^= GEM_M_BIT; + + XoGem(fpath, "ºëµØ°Ï", level); + return post_init(xo); +} + + +/* ----------------------------------------------------- */ +/* ¶iªOµe± */ +/* ----------------------------------------------------- */ + + +static int +post_memo(xo) + XO *xo; +{ + char fpath[64]; + + brd_fpath(fpath, currboard, fn_note); + /* Thor.990204: ¬°¦Ò¼{more ¶Ç¦^È */ + if (more(fpath, NULL) < 0) + { + vmsg("¥»¬ÝªO©|µL¡u¶iªOµe±¡v"); + return XO_FOOT; + } + + return post_head(xo); +} + + +/* ----------------------------------------------------- */ +/* ¥\¯à¡Gtag / switch / cross / forward */ +/* ----------------------------------------------------- */ + + +static int +post_tag(xo) + XO *xo; +{ + HDR *hdr; + int tag, pos, cur; + + pos = xo->pos; + cur = pos - xo->top; + hdr = (HDR *) xo_pool + cur; + + if (xo->key == XZ_XPOST) + pos = hdr->xid; + + if (tag = Tagger(hdr->chrono, pos, TAG_TOGGLE)) + { + move(3 + cur, 6); + outc(tag > 0 ? '*' : ' '); + } + + /* return XO_NONE; */ + return xo->pos + 1 + XO_MOVE; /* lkchu.981201: ¸õ¦Ü¤U¤@¶µ */ +} + + +static int +post_switch(xo) + XO *xo; +{ + int bno; + BRD *brd; + char bname[BNLEN + 1]; + + if (brd = ask_board(bname, BRD_R_BIT, NULL)) + { + if ((bno = brd - bshm->bcache) >= 0 && currbno != bno) + { + XoPost(bno); + return XZ_POST; + } + } + else + { + vmsg(err_bid); + } + return post_head(xo); +} + + +int +post_cross(xo) + XO *xo; +{ + /* ¨Ó·½¬ÝªO */ + char *dir, *ptr; + HDR *hdr, xhdr; + + /* ±ýÂà¥hªº¬ÝªO */ + int xbno; + usint xbattr; + char xboard[BNLEN + 1], xfolder[64]; + HDR xpost; + + int tag, rc, locus, finish; + int method; /* 0:ì¤åÂà¸ü 1:±q¤½¶}¬ÝªO/ºëµØ°Ï/«H½cÂà¿ý¤å³¹ 2:±q¯µ±K¬ÝªOÂà¿ý¤å³¹ */ + usint tmpbattr; + char tmpboard[BNLEN + 1]; + char fpath[64], buf[ANSILINELEN]; + FILE *fpr, *fpw; + + if (!cuser.userlevel) /* itoc.000213: Á×§K guest Âà¿ý¥h sysop ªO */ + return XO_NONE; + + tag = AskTag("Âà¿ý"); + if (tag < 0) + return XO_FOOT; + + dir = xo->dir; + + if (!ask_board(xboard, BRD_W_BIT, "\n\n\033[1;33m½Ð¬D¿ï¾A·íªº¬ÝªO¡A¤Á¤ÅÂà¿ý¶W¹L¤TªO¡C\033[m\n\n") || + (*dir == 'b' && !strcmp(xboard, currboard))) /* «H½c¡BºëµØ°Ï¤¤¥i¥HÂà¿ý¦Ücurrboard */ + return XO_HEAD; + + hdr = tag ? &xhdr : (HDR *) xo_pool + (xo->pos - xo->top); /* lkchu.981201: ¾ã§åÂà¿ý */ + + /* ì§@ªÌÂà¿ý¦Û¤v¤å³¹®É¡A¥i¥H¿ï¾Ü¡uì¤åÂà¸ü¡v */ + method = ((!tag && !strcmp(hdr->owner, cuser.userid))) && + (vget(2, 0, "(1)ì¤åÂà¸ü (2)Âà¿ý¤å³¹¡H[1] ", buf, 3, DOECHO) != '2') ? 0 : 1; + + if (!tag) /* lkchu.981201: ¾ã§åÂà¿ý´N¤£n¤@¤@¸ß°Ý */ + { + if (method) + sprintf(ve_title, "[Âà¿ý] %.65s", str_ttl(hdr->title)); /* ¤w¦³ Re:/Fw: ¦r¼Ë´N¥un¤@Ó Fw: */ + else + strcpy(ve_title, hdr->title); + + if (!vget(2, 0, "¼ÐÃD¡G", ve_title, TTLEN + 1, GCARRY)) + return XO_HEAD; + } + +#ifdef HAVE_REFUSEMARK + rc = vget(2, 0, "(S)¦sÀÉ (L)¯¸¤º (X)±K«Ê (Q)¨ú®ø¡H[Q] ", buf, 3, LCECHO); + if (rc != 'l' && rc != 's' && rc != 'x') +#else + rc = vget(2, 0, "(S)¦sÀÉ (L)¯¸¤º (Q)¨ú®ø¡H[Q] ", buf, 3, LCECHO); + if (rc != 'l' && rc != 's') +#endif + return XO_HEAD; + + if (method && *dir == 'b') /* ±q¬ÝªOÂà¥X¡A¥ýÀˬd¦¹¬ÝªO¬O§_¬°¯µ±KªO */ + { + /* ɥΠtmpbattr */ + tmpbattr = (bshm->bcache + currbno)->readlevel; + if (tmpbattr == PERM_SYSOP || tmpbattr == PERM_BOARD) + method = 2; + } + + + xbno = brd_bno(xboard); + xbattr = (bshm->bcache + xbno)->battr; + + int xmethod = 0; + /* ɥΠtmpbattr */ + tmpbattr = (bshm->bcache + xbno)->readlevel; + if (tmpbattr == PERM_SYSOP || tmpbattr == PERM_BOARD) + xmethod = 2; + + + /* Thor.990111: ¦b¥i¥HÂà¥X«e¡AnÀˬd¦³¨S¦³Âà¥XªºÅv¤O? */ + if ((rc == 's') && (!HAS_PERM(PERM_INTERNET) || (xbattr & BRD_NOTRAN))) + rc = 'l'; + + /* ³Æ¥÷ currboard */ + if (method) + { + /* itoc.030325: ¤@¯ëÂà¿ý©I¥s ve_header¡A·|¨Ï¥Î¨ì currboard¡Bcurrbattr¡A¥ý³Æ¥÷°_¨Ó */ + strcpy(tmpboard, currboard); + strcpy(currboard, xboard); + tmpbattr = currbattr; + currbattr = xbattr; + } + + locus = 0; + do /* lkchu.981201: ¾ã§åÂà¿ý */ + { + if (tag) + { + EnumTag(hdr, dir, locus, sizeof(HDR)); + + if (method) + sprintf(ve_title, "[Âà¿ý] %.65s", str_ttl(hdr->title)); /* ¤w¦³ Re:/Fw: ¦r¼Ë´N¥un¤@Ó Fw: */ + else + strcpy(ve_title, hdr->title); + } + + if (hdr->xmode & GEM_FOLDER) /* «D plain text ¤£¯àÂà */ + continue; + +#ifdef HAVE_REFUSEMARK + if (hdr->xmode & POST_RESTRICT) + continue; +#endif + + hdr_fpath(fpath, dir, hdr); + +#ifdef HAVE_DETECT_CROSSPOST + if (check_crosspost(fpath, xbno)) + break; +#endif + + brd_fpath(xfolder, xboard, fn_dir); + + time_t now; + time (&now); + + if (method) /* ¤@¯ëÂà¿ý */ + { + /* itoc.030325: ¤@¯ëÂà¿ýn«·s¥[¤W header */ + fpw = fdopen(hdr_stamp(xfolder, 'A', &xpost, buf), "w"); + ve_header(fpw); + + /* itoc.040228: ¦pªG¬O±qºëµØ°ÏÂà¿ý¥X¨Óªº¸Ü¡A·|Åã¥ÜÂà¿ý¦Û [currboard] ¬ÝªO¡A + µM¦Ó currboard ¥¼¥²¬O¸ÓºëµØ°Ïªº¬ÝªO¡C¤£¹L¤£¬O«Ü«nªº°ÝÃD¡A©Ò¥H´N¤£ºÞ¤F :p */ + fprintf(fpw, "¡° ¥»¤åÂà¿ý¦Û [%s] %s\n\n", + *dir == 'u' ? cuser.userid : method == 2 ? "¯µ±K" : tmpboard, + *dir == 'u' ? "«H½c" : "¬ÝªO"); + + /* Kyo.051117: Y¬O±q¯µ±K¬ÝªOÂà¥Xªº¤å³¹¡A§R°£¤å³¹²Ä¤@¦æ©Ò°O¿ýªº¬ÝªO¦WºÙ */ + finish = 0; + if ((method == 2) && (fpr = fopen(fpath, "r"))) + { + if (fgets(buf, sizeof(buf), fpr) && + ((ptr = strstr(buf, str_post1)) || (ptr = strstr(buf, str_post2))) && (ptr > buf)) + { + ptr[-1] = '\n'; + *ptr = '\0'; + + do + { + fputs(buf, fpw); + } while (fgets(buf, sizeof(buf), fpr)); + finish = 1; + } + fclose(fpr); + } + if (!finish) + f_suck(fpw, fpath); + + fprintf(fpw, "£p \033[1;30m%s \033[0;36mÂà\033[m:±q [%s] %s¡A¤_ %s \033[m\n", + cuser.userid, + *dir == 'u' ? cuser.userid : method == 2 ? "¬YÁôÂÃ" : tmpboard, + *dir == 'u' ? "«H½c" : "¬ÝªO", + Btime (&now)); + + fclose(fpw); + + strcpy(xpost.owner, cuser.userid); + strcpy(xpost.nick, cuser.username); + + if (*dir != 'u' && *dir !='g') + { + fpw = fopen(fpath, "a+"); + fprintf (fpw, "£p \033[1;30m%s \033[0;36mÂà\033[m:¨ì [%s] ¬ÝªO¡A¤_ %s \033[m\n", + cuser.userid, +// (xbattr == PERM_SYSOP || xbattr == PERM_BOARD) ? "¬YÁôÂÃ" : xboard, + xmethod == 2 ? "¬YÁôÂÃ" : xboard, + Btime (&now)); + fclose (fpw); + } + + } + else /* ì¤åÂà¿ý */ + { + /* itoc.030325: ì¤åÂà¿ýª½±µ copy §Y¥i */ + hdr_stamp(xfolder, HDR_COPY | 'A', &xpost, fpath); + + strcpy(xpost.owner, hdr->owner); + strcpy(xpost.nick, hdr->nick); + strcpy(xpost.date, hdr->date); /* ì¤åÂà¸ü«O¯dì¤é´Á */ + } + + strcpy(xpost.title, ve_title); + + if (rc == 's') + xpost.xmode = POST_OUTGO; +#ifdef HAVE_REFUSEMARK + else if (rc == 'x') + xpost.xmode = POST_RESTRICT; +#endif + + rec_bot(xfolder, &xpost, sizeof(HDR)); + + if (rc == 's') + outgo_post(&xpost, xboard); + } while (++locus < tag); + + btime_update(xbno); + + /* Thor.981205: check ³QÂ઺ªO¦³¨S¦³¦C¤J¬ö¿ý? */ + if (!(xbattr & BRD_NOCOUNT)) + cuser.numposts += tag ? tag : 1; /* lkchu.981201: nºâ tag */ + + /* ´_ì currboard¡Bcurrbattr */ + if (method) + { + strcpy(currboard, tmpboard); + currbattr = tmpbattr; + } + + vmsg("Âà¿ý§¹¦¨"); + return XO_HEAD; +} + + +int +post_forward(xo) + XO *xo; +{ + ACCT muser; + int pos; + HDR *hdr; + + if (!HAS_PERM(PERM_LOCAL)) + return XO_NONE; + + pos = xo->pos; + hdr = (HDR *) xo_pool + (pos - xo->top); + + if (hdr->xmode & GEM_FOLDER) /* «D plain text ¤£¯àÂà */ + return XO_NONE; + +#ifdef HAVE_REFUSEMARK + if ((hdr->xmode & POST_RESTRICT) && + strcmp(hdr->owner, cuser.userid) && !(bbstate & STAT_BM)) + return XO_NONE; +#endif + + if (acct_get("Âà¹F«H¥óµ¹¡G", &muser) > 0) + { + strcpy(quote_user, hdr->owner); + strcpy(quote_nick, hdr->nick); + hdr_fpath(quote_file, xo->dir, hdr); + sprintf(ve_title, "%.64s (fwd)", hdr->title); + move(1, 0); + clrtobot(); + prints("Âà¹Fµ¹: %s (%s)\n¼Ð ÃD: %s\n", muser.userid, muser.username, ve_title); + + mail_send(muser.userid); + *quote_file = '\0'; + } + return XO_HEAD; +} + + +/* ----------------------------------------------------- */ +/* ªO¥D¥\¯à¡Gmark / delete / label */ +/* ----------------------------------------------------- */ + + +static int +post_mark(xo) + XO *xo; +{ + if (bbstate & STAT_BOARD) + { + HDR *hdr; + int pos, cur, xmode; + + pos = xo->pos; + cur = pos - xo->top; + hdr = (HDR *) xo_pool + cur; + xmode = hdr->xmode; + +#ifdef HAVE_LABELMARK + if (xmode & POST_DELETE) /* «Ý¬åªº¤å³¹¤£¯à mark */ + return XO_NONE; +#endif + + hdr->xmode = xmode ^ POST_MARKED; + currchrono = hdr->chrono; + rec_put(xo->dir, hdr, sizeof(HDR), xo->key == XZ_XPOST ? hdr->xid : pos, cmpchrono); + +// move(3 + cur, 7); +// outc(post_attr(hdr)); + move (3 + cur, 0); + post_item(pos + 1, hdr); + } +// return XO_NONE; + return xo->pos + 1 + XO_MOVE; /* lkchu.981201: ¸õ¦Ü¤U¤@¶µ */ + +} + + +static int +post_bottom(xo) + XO *xo; +{ + + if (bbstate & STAT_BOARD) + { + HDR *hdr, post; + char fpath[64]; + +#define MAX_BOTTOM 7 + int fd, fsize; + struct stat st; + + if ((fd = open(xo->dir, O_RDONLY)) >= 0) + { + if (!fstat(fd, &st)) + { + fsize = st.st_size; + while ((fsize -= sizeof(HDR)) >= 0) + { + lseek(fd, fsize, SEEK_SET); + read(fd, &post, sizeof(HDR)); + if (!(post.xmode & POST_BOTTOM)) + break; + } + } + close(fd); + if ((st.st_size - fsize) / sizeof(HDR) > MAX_BOTTOM) + { + vmsg("¸m©³¤å¤£¯à¶W¹L 7 ½g¡C"); + return XO_FOOT; + } + } +#undef MAX_BOTTOM + hdr = (HDR *) xo_pool + (xo->pos - xo->top); + + hdr_fpath(fpath, xo->dir, hdr); + hdr_stamp(xo->dir, HDR_LINK | 'A', &post, fpath); +#ifdef HAVE_REFUSEMARK + post.xmode = POST_BOTTOM | (hdr->xmode & POST_RESTRICT); +#else + post.xmode = POST_BOTTOM; +#endif + strcpy(post.owner, hdr->owner); + strcpy(post.nick, hdr->nick); + strcpy(post.title, hdr->title); + + rec_add(xo->dir, &post, sizeof(HDR)); + /* btime_update(currbno); */ /* ¤£»Ýn¡A¦]¬°¸m©³¤å³¹¤£¦C¤J¥¼Åª */ + + return post_load(xo); /* ¥ß¨èÅã¥Ü¸m©³¤å³¹ */ + } + return XO_NONE; +} + + +#ifdef HAVE_REFUSEMARK +static int +post_refuse(xo) /* itoc.010602: ¤å³¹¥[±K */ + XO *xo; +{ + HDR *hdr; + int pos, cur; + + if (!cuser.userlevel) /* itoc.020114: guest ¤£¯à¹ï¨ä¥L guest ªº¤å³¹¥[±K */ + return XO_NONE; + + pos = xo->pos; + cur = pos - xo->top; + hdr = (HDR *) xo_pool + cur; + + if (!strcmp(hdr->owner, cuser.userid) || (bbstate & STAT_BM)) + { + hdr->xmode ^= POST_RESTRICT; + currchrono = hdr->chrono; + rec_put(xo->dir, hdr, sizeof(HDR), xo->key == XZ_XPOST ? hdr->xid : pos, cmpchrono); + +// move(3 + cur, 7); +// outc(post_attr(hdr)); + move (3 + cur, 0); + post_item(pos + 1, hdr); + } + + return XO_NONE; +} +#endif + + +#ifdef HAVE_LABELMARK +static int +post_label(xo) + XO *xo; +{ + if (bbstate & STAT_BOARD) + { + HDR *hdr; + int pos, cur, xmode; + + pos = xo->pos; + cur = pos - xo->top; + hdr = (HDR *) xo_pool + cur; + xmode = hdr->xmode; + + if (xmode & (POST_MARKED | POST_RESTRICT | POST_BOTTOM)) /* mark ©Î ¥[±Kªº¤å³¹¤£¯à«Ý¬å */ + return XO_NONE; + + hdr->xmode = xmode ^ POST_DELETE; + currchrono = hdr->chrono; + rec_put(xo->dir, hdr, sizeof(HDR), xo->key == XZ_XPOST ? hdr->xid : pos, cmpchrono); + +// move(3 + cur, 7); +// outc(post_attr(hdr)); + move (3 + cur, 0); + post_item(pos + 1, hdr); + + return pos + 1 + XO_MOVE; /* ¸õ¦Ü¤U¤@¶µ */ + } + + return XO_NONE; +} + + +static int +post_delabel(xo) + XO *xo; +{ + int fdr, fsize, xmode; + char fnew[64], fold[64], *folder; + HDR *hdr; + FILE *fpw; + + if (!(bbstate & STAT_BOARD)) + return XO_NONE; + + if (vans("½T©wn§R°£«Ý¬å¤å³¹¶Ü(Y/N)¡H[N] ") != 'y') + return XO_FOOT; + + folder = xo->dir; + if ((fdr = open(folder, O_RDONLY)) < 0) + return XO_FOOT; + + if (!(fpw = f_new(folder, fnew))) + { + close(fdr); + return XO_FOOT; + } + + fsize = 0; + mgets(-1); + while (hdr = mread(fdr, sizeof(HDR))) + { + xmode = hdr->xmode; + + if (!(xmode & POST_DELETE)) + { + if ((fwrite(hdr, sizeof(HDR), 1, fpw) != 1)) + { + close(fdr); + fclose(fpw); + unlink(fnew); + return XO_FOOT; + } + fsize++; + } + else + { + /* ³s½u¬å«H */ + cancel_post(hdr); + + hdr_fpath(fold, folder, hdr); + unlink(fold); + } + } + close(fdr); + fclose(fpw); + + sprintf(fold, "%s.o", folder); + rename(folder, fold); + if (fsize) + rename(fnew, folder); + else + unlink(fnew); + + btime_update(currbno); + + return post_load(xo); +} +#endif + + +static int +post_delete(xo) + XO *xo; +{ + int pos, cur, by_BM; + HDR *hdr; + char buf[80]; + + if (!cuser.userlevel || + !strcmp(currboard, BN_DELETED) || + !strcmp(currboard, BN_JUNK)) + return XO_NONE; + + pos = xo->pos; + cur = pos - xo->top; + hdr = (HDR *) xo_pool + cur; + + if ((hdr->xmode & POST_MARKED) || + (!(bbstate & STAT_BOARD) && strcmp(hdr->owner, cuser.userid))) + return XO_NONE; + + by_BM = bbstate & STAT_BOARD; + + if (vans(msg_del_ny) == 'y') + { + currchrono = hdr->chrono; + + if (!rec_del(xo->dir, sizeof(HDR), xo->key == XZ_XPOST ? hdr->xid : pos, cmpchrono)) + { + pos = move_post(hdr, xo->dir, by_BM); + + if (!by_BM && !(currbattr & BRD_NOCOUNT)) + { + /* itoc.010711: ¬å¤å³¹n¦©¿ú¡AºâÀɮפj¤p */ + pos = pos >> 3; /* ¬Û¹ï©ó post ®É wordsnum / 10 */ + + /* itoc.010830.µù¸Ñ: º|¬}: Y multi-login ¬å¤£¨ì¥t¤@°¦ªº¿ú */ + if (cuser.money > pos) + cuser.money -= pos; + else + cuser.money = 0; + + if (hdr->xmode & POST_RECORDED) + { + if (cuser.numposts > 0) + cuser.numposts--; + sprintf(buf, "%s¡A±zªº¤å³¹´î¬° %d ½g", MSG_DEL_OK, cuser.numposts); + vmsg(buf); + } + } + + + if (xo->key == XZ_XPOST) + { + vmsg("ì¦Cªí¸g§R°£«á²V¶Ã¡A½Ð«¶i¦ê±µ¼Ò¦¡¡I"); + return XO_QUIT; + } + return XO_LOAD; + } + } + return XO_FOOT; +} + + +static int +chkpost(hdr) + HDR *hdr; +{ + return (hdr->xmode & POST_MARKED); +} + + +static int +vfypost(hdr, pos) + HDR *hdr; + int pos; +{ + return (Tagger(hdr->chrono, pos, TAG_NIN) || chkpost(hdr)); +} + + +static void +delpost(xo, hdr) + XO *xo; + HDR *hdr; +{ + char fpath[64]; + + cancel_post(hdr); + hdr_fpath(fpath, xo->dir, hdr); + unlink(fpath); +} + + +static int +post_rangedel(xo) + XO *xo; +{ + if (!(bbstate & STAT_BOARD)) + return XO_NONE; + + btime_update(currbno); + + return xo_rangedel(xo, sizeof(HDR), chkpost, delpost); +} + + +static int +post_prune(xo) + XO *xo; +{ + int ret; + + if (!(bbstate & STAT_BOARD)) + return XO_NONE; + + ret = xo_prune(xo, sizeof(HDR), vfypost, delpost); + + btime_update(currbno); + + if (xo->key == XZ_XPOST && ret == XO_LOAD) + { + vmsg("ì¦Cªí¸g§å¦¸§R°£«á²V¶Ã¡A½Ð«¶i¦ê±µ¼Ò¦¡¡I"); + return XO_QUIT; + } + + return ret; +} + + +static int +post_copy(xo) /* itoc.010924: ¨ú¥N gem_gather */ + XO *xo; +{ + int tag; + HDR *hdr; + + tag = AskTag("¬ÝªO¤å³¹«þ¨©"); + + if (tag < 0) + return XO_FOOT; + + hdr = (HDR *) xo_pool + (xo->pos - xo->top); + + gem_buffer(xo->dir, tag ? NULL : hdr); + + if (bbstate & STAT_BOARD) + { +#ifdef XZ_XPOST + if (xo->key == XZ_XPOST) + { + zmsg("Àɮ׼аO§¹¦¨¡C[ª`·N] ±z¥²¶·¥ýÂ÷¶}¦ê±µ¼Ò¦¡¤~¯à¶i¤JºëµØ°Ï¡C"); + return XO_FOOT; + } + else +#endif + { + zmsg("«þ¨©§¹¦¨¡A¦ý¬O¥[±K¤å³¹¤£·|³Q«þ¨©¡C[ª`·N] ¶K¤W«á¤~¯à§R°£ì¤å¡I"); + return post_gem(xo); /* «þ¨©§¹ª½±µ¶iºëµØ°Ï */ + } + } + + zmsg("Àɮ׼аO§¹¦¨¡C[ª`·N] ±z¥u¯à¦b¾á¥ô(¤p)ªO¥D©Ò¦b©ÎÓ¤HºëµØ°Ï¶K¤W¡C"); + return XO_FOOT; +} + + +/* ----------------------------------------------------- */ +/* ¯¸ªø¥\¯à¡Gedit / title */ +/* ----------------------------------------------------- */ + + +int +post_edit(xo) + XO *xo; +{ + char fpath[64]; + HDR *hdr; + FILE *fp; + + hdr = (HDR *) xo_pool + (xo->pos - xo->top); + + hdr_fpath(fpath, xo->dir, hdr); + +#if 0 + if (HAS_PERM(PERM_ALLBOARD)) /* ¯¸ªø×§ï */ + { +#ifdef HAVE_REFUSEMARK + if ((hdr->xmode & POST_RESTRICT) && !(bbstate & STAT_BM) && strcmp(hdr->owner, cuser.userid)) + return XO_NONE; +#endif +// vedit(fpath, 0); + if (!vedit(fpath, 0)) /* Y«D¨ú®ø«h¥[¤W×§ï¸ê°T */ + { + if (fp = fopen(fpath, "a")) + { + ve_banner(fp, 1); + fclose(fp); + } + } + } + else +#endif + if (cuser.userlevel && !strcmp(hdr->owner, cuser.userid)) /* ì§@ªÌ×§ï */ + { + if (!vedit(fpath, 0)) /* Y«D¨ú®ø«h¥[¤W×§ï¸ê°T */ + { + if (fp = fopen(fpath, "a")) + { + ve_banner(fp, 1); + fclose(fp); + } + } + } + else /* itoc.010301: ´£¨Ñ¨Ï¥ÎªÌ×§ï(¦ý¤£¯àÀx¦s)¨ä¥L¤Hµoªíªº¤å³¹ */ + { +#ifdef HAVE_REFUSEMARK + if (hdr->xmode & POST_RESTRICT) + return XO_NONE; +#endif + vedit(fpath, -1); + } + + /* return post_head(xo); */ + return XO_HEAD; /* itoc.021226: XZ_POST ©M XZ_XPOST ¦@¥Î post_edit() */ +} + + +void +header_replace(xo, hdr) /* itoc.010709: ×§ï¤å³¹¼ÐÃD¶¶«Kק鷺¤åªº¼ÐÃD */ + XO *xo; + HDR *hdr; +{ + FILE *fpr, *fpw; + char srcfile[64], tmpfile[64], buf[ANSILINELEN]; + + hdr_fpath(srcfile, xo->dir, hdr); + strcpy(tmpfile, "tmp/"); + strcat(tmpfile, hdr->xname); + f_cp(srcfile, tmpfile, O_TRUNC); + + if (!(fpr = fopen(tmpfile, "r"))) + return; + + if (!(fpw = fopen(srcfile, "w"))) + { + fclose(fpr); + return; + } + + fgets(buf, sizeof(buf), fpr); /* ¥[¤J§@ªÌ */ + fputs(buf, fpw); + + fgets(buf, sizeof(buf), fpr); /* ¥[¤J¼ÐÃD */ + if (!str_ncmp(buf, "¼Ð", 2)) /* ¦pªG¦³ header ¤~§ï */ + { + strcpy(buf, buf[2] == ' ' ? "¼Ð ÃD: " : "¼ÐÃD: "); + strcat(buf, hdr->title); + strcat(buf, "\n"); + } + fputs(buf, fpw); + + while(fgets(buf, sizeof(buf), fpr)) /* ¥[¤J¨ä¥L */ + fputs(buf, fpw); + + fclose(fpr); + fclose(fpw); + f_rm(tmpfile); +} + + +static int +post_title(xo) + XO *xo; +{ + HDR *fhdr, mhdr; + int pos, cur; + + if (!cuser.userlevel) /* itoc.000213: Á×§K guest ¦b sysop ªO§ï¼ÐÃD */ + return XO_NONE; + + pos = xo->pos; + cur = pos - xo->top; + fhdr = (HDR *) xo_pool + cur; + memcpy(&mhdr, fhdr, sizeof(HDR)); + + if (strcmp(cuser.userid, mhdr.owner) && !HAS_PERM(PERM_ALLADMIN)) + return XO_NONE; + + vget(b_lines, 0, "¼ÐÃD¡G", mhdr.title, TTLEN + 1, GCARRY); + + + if (HAS_PERM(PERM_ALLADMIN)) /* itoc.000213: ì§@ªÌ¥u¯à§ï¼ÐÃD */ + { + vget(b_lines, 0, "§@ªÌ¡G", mhdr.owner, 73 /* sizeof(mhdr.owner) */, GCARRY); + /* Thor.980727: sizeof(mhdr.owner) = 80 ·|¶W¹L¤@¦æ */ + vget(b_lines, 0, "¼ÊºÙ¡G", mhdr.nick, sizeof(mhdr.nick), GCARRY); + vget(b_lines, 0, "¤é´Á¡G", mhdr.date, sizeof(mhdr.date), GCARRY); + } + + if (memcmp(fhdr, &mhdr, sizeof(HDR)) && vans(msg_sure_ny) == 'y') + { + memcpy(fhdr, &mhdr, sizeof(HDR)); + currchrono = fhdr->chrono; + rec_put(xo->dir, fhdr, sizeof(HDR), xo->key == XZ_XPOST ? fhdr->xid : pos, cmpchrono); + + move(3 + cur, 0); + post_item(++pos, fhdr); + + /* itoc.010709: ×§ï¤å³¹¼ÐÃD¶¶«Kק鷺¤åªº¼ÐÃD */ + header_replace(xo, fhdr); + } + return XO_FOOT; +} + + +/* ----------------------------------------------------- */ +/* ÃB¥~¥\¯à¡Gwrite / score */ +/* ----------------------------------------------------- */ + + +int +post_write(xo) /* itoc.010328: ¥á½u¤W§@ªÌ¤ô²y */ + XO *xo; +{ + if (HAS_PERM(PERM_PAGE)) + { + HDR *hdr; + UTMP *up; + + hdr = (HDR *) xo_pool + (xo->pos - xo->top); + + if (!(hdr->xmode & POST_INCOME) && (up = utmp_seek(hdr))) + do_write(up); + } + return XO_NONE; +} + + +#ifdef HAVE_SCORE + +static int curraddscore; +static int newchrono; +static char *newxname; + +static void +addscore(hdd, ram) + HDR *hdd, *ram; +{ + /* itoc.030618: ³y¤@Ó·sªº chrono ¤Î xname */ + hdd->chrono = newchrono; + strcpy(hdd->xname, newxname); + + hdd->xmode |= POST_SCORE; + if (curraddscore == 1) + { + if (hdd->score < 36) + hdd->score++; + } + else if (curraddscore == -1) + { + if (hdd->score > -36) + hdd->score--; + } +} + +static +int post_mscore(xo) + XO *xo; +{ + char *blist; + BRD *brd; + brd = bshm->bcache + currbno; + blist = brd->BM; +/*if(!HAS_PERM(PERM_ALLADMIN) || strcmp(brd->class,"¯¸°È")){ + if (is_bm(blist, cuser.userid) != 1) + { + vmsg("¥u¦³¥¿ª©¥D¥i¥H×§ï±À¤å¼Æ"); + return XO_NONE; + } + }*/ + if(!HAS_PERM(PERM_ALLBOARD)){ + if(!is_bm(blist, cuser.userid)){ + vmsg("±z¤£¬OªO¥D¡AµLªk×§ï±À¤å¼Æ"); + return XO_NONE; + } + if(!HAS_PERM(PERM_MSCORE)){ + vmsg("±z¨S¦³×§ï±À¤å¼ÆªºÅv"); + return XO_NONE; + } + } + int pos = xo->pos; + int cur = pos - xo->top; + HDR* hdr = (HDR *) xo_pool + cur; + HDR post=*hdr; + char togask; + char scoremod=0; + togask=vans("¬O§_ÁôÂñÀ¤å¼Æ(Y/N)¡H[N] "); + if(!togask){ + togask='n'; + } + if(post.xmode & POST_SCORE){ + if(togask == 'y'){ + scoremod=1; + post.xmode ^= POST_SCORE; + } + }else{ + if(togask == 'n'){ + scoremod=1; + post.xmode ^= POST_SCORE; + } + } + char tmpscore[4]; + sprintf(tmpscore,"%d",post.score); + vget(b_lines, 0, "±À¤å¼Æ(Y¬°©A¤å½Ð³]©wt¼Æ)¡G", tmpscore, 4, GCARRY); + post.score=atoi(tmpscore); + if(post.score > 36){ + post.score = 36; + }else if(post.score < -36){ + post.score = -36; + } + if(post.score != hdr->score){ + scoremod=1; + } + if(scoremod && vans(msg_sure_ny)=='y'){ + memcpy(hdr,&post,sizeof(HDR)); + currchrono=post.chrono; + rec_put(xo->dir, hdr, sizeof(HDR), xo->pos, cmpchrono); + post_body(xo); + } + return XO_FOOT; +} + +int +post_score(xo) + XO *xo; +{ + static time_t next = 0; /* ¤U¦¸¥iµû¤À®É¶¡ */ + HDR *hdr; + HDR post; + int pos, cur, ans, vtlen, maxlen; + char *dir, *userid, *verb, fpath[64], reason[80], vtbuf[12], prompt[20]; + FILE *fp; +#ifdef HAVE_ANONYMOUS + char uid[IDLEN + 1]; +#endif + + if ((currbattr & BRD_NOSCORE) || !cuser.userlevel || !(bbstate & STAT_POST)) /* µû¤Àµø¦Pµoªí¤å³¹ */ + return XO_NONE; + + pos = xo->pos; + cur = pos - xo->top; + hdr = (HDR *) xo_pool + cur; + +#ifdef HAVE_REFUSEMARK + if ((hdr->xmode & POST_RESTRICT) && + strcmp(hdr->owner, cuser.userid) && !(bbstate & STAT_BM)) + return XO_NONE; +#endif + + switch (ans = vans("¡· µû¤À 0)±µ¸Ü 1)±À¤å 2)©A¤å 3)¦Û©w±À 4)¦Û©w©A¡H [Q] ")) + { + case '0': + verb = "3m»¡"; + vtlen = 2; + break; + + case '1': + verb = "1m±À"; + vtlen = 2; + break; + + case '2': + verb = "2m©A"; + vtlen = 2; + break; + + case '3': + case '4': + if (!vget(b_lines, 0, "½Ð¿é¤J°Êµü¡G", fpath, 7, DOECHO)) + return XO_FOOT; + vtlen = strlen(fpath); + sprintf(verb = vtbuf, "%cm%s", ans - 2, fpath); + break; + + default: + return XO_FOOT; + } + + if (ans != '0' && (next - time(NULL)) > 0) + { + sprintf(fpath, "ÁÙ¦³ %d ¬í¤~¯àµû¤À³á", next - time(NULL)); + vmsg(fpath); + return XO_FOOT; + } + +#ifdef HAVE_ANONYMOUS + if (currbattr & BRD_ANONYMOUS) + maxlen = 63 - IDLEN - vtlen; + else +#endif + maxlen = 63 - strlen(cuser.userid) - vtlen; + +#ifdef HAVE_ANONYMOUS + if (currbattr & BRD_ANONYMOUS) + { + userid = uid; + if (!vget(b_lines, 0, "½Ð¿é¤J±z·Q¥ÎªºID¡A¤]¥iª½±µ«ö[Enter]¡A©Î¬O«ö[r]¥Î¯u¦W¡G", userid, IDLEN, DOECHO)) + userid = STR_ANONYMOUS; + else if (userid[0] == 'r' && userid[1] == '\0') + userid = cuser.userid; + else + strcat(userid, "."); /* ¦Û©wªº¸Ü¡A³Ì«á¥[ '.' */ + maxlen = 63 - strlen(userid) - vtlen; + } + else +#endif + userid = cuser.userid; + + sprintf (prompt, "¡÷ %s %-*s:", userid, strlen(verb) - 2, ""); + + if (!vget(b_lines, 0, prompt, reason, maxlen, DOECHO)) + return XO_FOOT; + + + dir = xo->dir; + hdr_fpath(fpath, dir, hdr); + + if (fp = fopen(fpath, "a")) + { + time_t now; + struct tm *ptime; + + time(&now); + ptime = localtime(&now); + + fprintf(fp, "¡÷ \033[36m%s \033[3%s\033[m:%-*s%02d%02d %02d:%02d\n", + userid, verb, maxlen, reason, + ptime->tm_mon + 1, ptime->tm_mday, ptime->tm_hour, ptime->tm_min); + fclose(fp); + } + + ans -= '0'; + curraddscore = 0; + if (ans == 0) /* »¡¸Ü */ + { + curraddscore = 0; + } + if (ans == 1 || ans == 3) /* ¥[¤À */ + { + if (hdr->score <= 35) + curraddscore = 1; + } + else if (ans == 2 || ans == 4) /* ¦©¤À */ + { + if (hdr->score >= -35) + curraddscore = -1; + } + + if (curraddscore) + next = time(NULL) + 3; /* ¨C 3 ¬í¤è¥iµû¤À¤@¦¸ */ + + /* ««Ø¤@Ó post */ + hdr_fpath(fpath, dir, hdr); + hdr_stamp(dir, HDR_LINK | 'A', &post, fpath); + +/* ¤£¬å±¼ì¥ýªº¤å³¹ÀɮסA¦pªG¨ä¥L¤H xo_pool ¬Oªº¡A¤]¤£·|¥X²{¼È®É©Ê¥ÛÀY¤å? + ¤SÂà«H out.bntp ¤¤¼gªºÀɦW¤]¬O¦W¡A©Ò¥H«O¯dÂÂÀÉ¥i¨ÏÂà«H¦¨¥\¡F + ¦ý³o¼Ë·|¯d¤U .DIR ¤¤¨S¦³«ü¦VªºÂÂÀÉ¡A¥u¦n¦b expire.c ¤¤²M°£¡C */ +/* unlink(fpath); */ + + currchrono = hdr->chrono; + newchrono = post.chrono; + newxname = post.xname; + rec_ref(dir, hdr, sizeof(HDR), xo->key == XZ_XPOST ? + hdr->xid : pos, cmpchrono, addscore); + + /* ¥[¤J¦Û¤vªº¾\Ū°O¿ý */ + brh_add(newchrono, newchrono, newchrono); + btime_update(currbno); + + return XO_LOAD; + +} +#endif /* HAVE_SCORE */ + + +static int +post_help(xo) + XO *xo; +{ + xo_help("post"); + /* return post_head(xo); */ + return XO_HEAD; /* itoc.001029: »P xpost_help ¦@¥Î */ +} + +static int +post_redir(xo) + XO *xo; +{ + + char *blist; + BRD *brd; + + brd = bshm->bcache + currbno; + + blist = brd->BM; + if (strcmp(brd->class, "¯¸°È") || !HAS_PERM(PERM_ALLADMIN)) + { + if (is_bm(blist, cuser.userid) != 1) /* ¥u¦³¥¿ªO¥D¥i¥H */ + { + vmsg("¥u¦³¥¿ª©¥D¥i¥H««Ø¬ÝªO¯Á¤Þ"); + return XO_NONE; + } + } + + if (bbstate & STAT_BOARD) + { + if (vans("½T©w««Ø¬ÝªO¯Á¤Þ¶Ü¡A¤£©úÁA¦¹¥\\¯à°õ·N¨Ï¥ÎªÌ«áªG¦Ût[N]¡H(y/N) ") == 'y') + { + if (vans("¯uªºn««Ø³á¡H¤å³¹§Ç·|¶Ã±¼¡B±À¤å¼Æ¦r·|¤£¨£³é¡I[N] («ör°õ¦æ¤§) ") == 'r') + { + char fpath[64]; + brd_fpath(fpath, brd->brdname, fn_lock); + if(fork()==0){ + pid_t child=fork(); + if(child==0){ + char buf[100]; + sprintf (buf, "/home/bbs/brd/%s", currboard); + chdir(buf); + execl(BBSHOME"/bin/redir", "redir", "-b", NULL); + vmsg("µLªk°õ¦æ¯Á¤Þ««Øµ{¦¡"); + exit(1); + }else{ + brd_setlockinfo(fpath, '0', cuser.userid, "¥¿¦b°õ¦æ¬ÝªO¯Á¤Þ««Ø"); + int status; + waitpid(child,&status,0); + unlink(fpath); + exit(WEXITSTATUS(status)); + } + } + return XO_INIT; + } + } + else + { + return XO_INIT; + } + } + return XO_NONE; +} + +static int +post_move(xo) + XO *xo; +{ +char *blist; + BRD *brd; + + brd = bshm->bcache + currbno; + + blist = brd->BM; + + if(!HAS_PERM(PERM_ALLADMIN) || strcmp(brd->class,"¯¸°È")){ + if (is_bm(blist, cuser.userid) != 1) /* ¥u¦³¥¿ªO¥D¥i¥H */ + { + vmsg("¥u¦³¥¿ª©¥D¥i¥H²¾°Ê¤å³¹"); + return; + } + } + HDR *hdr; + char *dir, buf[40]; + int pos, newOrder; + + pos = xo->pos; + hdr = (HDR *) xo_pool + (pos - xo->top); + + sprintf(buf, "½Ð¿é¤J²Ä %d ¿ï¶µªº·s¦ì¸m¡G", pos + 1); + if (!vget(b_lines, 0, buf, buf, 5, DOECHO)) + return XO_FOOT; + + newOrder = atoi(buf) - 1; + if (newOrder < 0) + newOrder = 0; + else if (newOrder >= xo->max) + newOrder = xo->max - 1; + + dir = xo->dir; + if (newOrder != pos) + { + if (!rec_del(dir, sizeof(HDR), pos, NULL)) + { + rec_ins(dir, hdr, sizeof(HDR), newOrder, 1); + xo->pos = newOrder; + return XO_LOAD; + } + } + + return XO_FOOT; +} + +static int post_ainfo(xo) + XO *xo; +{ + char *blist; + BRD *brd; + brd = bshm->bcache + currbno; + blist = brd->BM; + int pos = xo->pos; + int cur = pos - xo->top; + HDR* hdr = (HDR *) xo_pool + cur; + move(19,0); + clrtobot(),refresh(); + outs("\n"); + prints("\033[1;33m[¤å³¹¼ÐÃD]\033[m %s\n",hdr->title); + outs("\033[1;33m[¤å³¹µû¤À]\033[m "); + if(hdr->score <= -36){ + outs("³Q¼NÃz"); + }else if(hdr->score >= 36){ + outs("³Q±ÀÃz"); + }else{ + prints("%hhd",hdr->score); + } + move(21,30); + outs("\033[1;33m[ÀɮצWºÙ]\033[m "); + struct stat st; + char fpath[80],tosend[20]; + sprintf(tosend,"%c/%s",hdr->xname[7],hdr->xname); + brd_fpath(fpath,brd->brdname,tosend); + if(HAS_PERM(PERM_ALLADMIN) || is_bm(blist,cuser.userid)) { + outs(hdr->xname); + move(21,65); + outs("\033[1;33m[Àɮפj¤p]\033[m "); + if(stat(fpath,&st)){ + outs("Àɮ׬ÛÃö¸ê°TŪ¨ú¥¢±Ñ"); + }else{ + prints("%d",st.st_size); + } + }else{ + outs("¥u¦³ªO¥D¥i¥HÆ[¬Ý"); + } + outs("\n\033[1;33m[¤å³¹ÄÝ©Ê]\033[m "); + outs((hdr->xmode & POST_MARKED) ? "\033[1;32m¦³\033[m" : "\033[1;31mµL\033[m" ); + outs(" mark "); + outs((hdr->xmode & POST_DELETE) ? "\033[1;32m¬O\033[m" : "\033[1;31m¤£¬O\033[m" ); + outs("«Ý¬å¤å³¹ "); + outs((hdr->xmode & POST_SCORE) ? "\033[1;32m¦³\033[m" : "\033[1;31mµL\033[m" ); + outs("µû¤À "); + outs((hdr->xmode & POST_RECORDED) ? "\033[1;32m¦³\033[m" : "\033[1;31mµL\033[m" ); + outs("½Z¶O "); + outs((hdr->xmode & POST_BOTTOM) ? "\033[1;32m¬O\033[m" : "\033[1;31m¤£¬O\033[m" ); + outs("¸m©³¤å³¹ "); + outs((hdr->xmode & POST_INCOME) ? "\033[1;32m¬O\033[m" : "\033[1;31m¤£¬O\033[m" ); + outs("¯¸¥~«H "); + outs((hdr->xmode & POST_OUTGO) ? "\033[1;32mn\033[m" : "\033[1;31m¤£\033[m" ); + outs("Âà«H¥X¥h"); + vmsg(NULL); + return post_init(xo); +} + +static int post_binfo(xo) + XO *xo; +{ + BRD *brd; + brd = bshm->bcache + currbno; + do_binfo(brd); + return post_init(xo); +} + +void do_binfo(brd) + BRD* brd; +{ + move(1,0); + clrtobot(); + prints("\n\n\033[1;33m[¬ÝªO¦WºÙ]\033[m %s" + "\n\033[1;33m[¬ÝªO»¡©ú]\033[m [%s] %s" + "\n\033[1;33m[¬ÝªOÃþ«¬]\033[m %s" +#ifdef HAVE_MODERATED_BOARD + "\n\033[1;33m[µoªíÅv]\033[m %s" +#endif + "\n\033[1;33m[ªO¥D¦W³æ]\033[m %s" + ,brd->brdname, brd->class, brd->title +#ifdef HAVE_MODERATED_BOARD + ,(brd->readlevel == PERM_SYSOP) ? "ÁôÂìݪO" : + (brd->readlevel == PERM_BOARD) ? "¦n¤Í¬ÝªO" : + (!brd->readlevel) ? "¤½¶}¬ÝªO" : "¯S®íÅv¬ÝªO" +#endif + ,(!brd->postlevel) ? "©Ò¦³±b¸¹§¡¥iµoªí" : + (brd->postlevel == PERM_BASIC) ? "°£ guest ¥~§¡¥iµoªí" : + (brd->postlevel == PERM_POST) ? "³q¹L¨¤À»{ÃÒ¤~¥iµoªí" : "¯S®íµoªíÅv" + ,brd->BM); + struct tm* tmptp; + tmptp=localtime(&(brd->bstamp)); + prints("\n\033[1;33m[¬ÝªO«Ø¥ß®É¶¡]\033[m %04d/%02d/%02d %02d:%02d:%02d", + tmptp->tm_year+1900,tmptp->tm_mon+1,tmptp->tm_mday,tmptp->tm_hour,tmptp->tm_min,tmptp->tm_sec); + tmptp=localtime(&(brd->blast)); + prints("\n\033[1;33m[³Ì«áµoªí®É¶¡]\033[m %04d/%02d/%02d %02d:%02d:%02d", + tmptp->tm_year+1900,tmptp->tm_mon+1,tmptp->tm_mday,tmptp->tm_hour,tmptp->tm_min,tmptp->tm_sec); + prints("\n\033[1;33m[¤å³¹Á`¼Æ]\033[m %d" + "\n\033[1;33m[§ë²¼ª¬ºA]\033[m %s" + ,brd->bpost,(brd->bvote == -1) ? "¦³½ä½L" : (brd->bvote == 1) ? "¦³§ë²¼" : "µL§ë²¼"); + outs("\n\033[1;33m[Âê©wª¬ºA]\033[m "); + char fpath[64]; + brd_fpath(fpath, brd->brdname, fn_lock); + struct stat tmpstat; + if(stat(fpath, &tmpstat)<0){ + outs("¥¼Âê©w"); + }else{ + char userid[IDLEN + 1], reason[73]; + char type; + brd_getlockinfo(fpath, &type, userid, reason); + prints("¥Ø«e¥Ñ %s Âê©w", userid); + prints("\n\033[1;33m[Âê©w²z¥Ñ]\033[m %s", reason); + } + outs("\n\n\033[1;33m[¬ÝªOÄÝ©Ê]\033[m "); + outs((brd->battr & BRD_NOTRAN) ? "\033[1;31mµL" : "\033[1;32m¦³" ); + outs("\033[mÂà«H\n "); + outs((brd->battr & BRD_LOCAL) ? "\033[1;31m©Úµ´" : "\033[1;32m±µ¨ü" ); + outs("\033[m¯¸¥~±H«Hµo¤å\n "); + outs((brd->battr & BRD_NOSTAT) ? "\033[1;31m¤£" : "\033[1;32mn" ); + outs("\033[m²Îp¼öªù¸ÜÃD\n "); + outs((brd->battr & BRD_NOVOTE) ? "\033[1;31m¤£" : "\033[1;32mn" ); + outs("\033[m¤½§i§ë²¼µ²ªG\n "); + outs((brd->battr & BRD_ANONYMOUS) ? "\033[1;32m¥i" : "\033[1;31m¤£¥i" ); + outs("\033[m°Î¦Wµo¤å\n "); +#ifdef HAVE_SCORE + outs((brd->battr & BRD_NOSCORE) ? "\033[1;31m¤£¥i" : "\033[1;32m¥i" ); + outs("\033[mµû¤À\n "); +#endif +#ifdef ANTI_PHONETIC + outs((brd->battr & BRD_NOPHONETIC) ? "\033[1;31m¤£¥i" : "\033[1;32m¥i" ); + outs("\033[m¨Ï¥Îª`µ¤å\n "); +#endif + vmsg(NULL); +} + +KeyFunc post_cb[] = +{ + XO_INIT, post_init, + XO_LOAD, post_load, + XO_HEAD, post_head, + XO_BODY, post_body, + + 'r', post_browse, + 's', post_switch, + KEY_TAB, post_gem, + 'z', post_gem, + + 'y', post_reply, + 'd', post_delete, + 'v', post_visit, + 'x', post_cross, /* ¦b post/mbox ¤¤³£¬O¤p¼g x Âà¬ÝªO¡A¤j¼g X Âà¨Ï¥ÎªÌ */ + 'X', post_forward, + 't', post_tag, + 'E', post_edit, + 'T', post_title, + 'm', post_mark, + '_', post_bottom, + '*', post_bottom, + 'D', post_rangedel, + +#ifdef HAVE_SCORE + '%', post_score, + '#', post_mscore, +#endif + + 'w', post_write, + + 'b', post_memo, + 'c', post_copy, + 'g', gem_gather, + + 'I', post_ainfo, + 'W', post_binfo, + + + Ctrl('P'), post_add, + Ctrl('D'), post_prune, + Ctrl('Q'), xo_uquery, + Ctrl('O'), xo_usetup, + +#ifdef HAVE_REFUSEMARK + Ctrl('Y'), post_refuse, +#endif + +#ifdef HAVE_LABELMARK + 'n', post_label, + Ctrl('N'), post_delabel, +#endif + + 'B' | XO_DL, (void *) "bin/manage.so:post_manage", + 'R' | XO_DL, (void *) "bin/vote.so:vote_result", + 'V' | XO_DL, (void *) "bin/vote.so:XoVote", + +#ifdef HAVE_TERMINATOR + Ctrl('X') | XO_DL, (void *) "bin/manage.so:post_terminator", +#endif + + '~', XoXselect, /* itoc.001220: ·j´M§@ªÌ/¼ÐÃD */ + 'S', XoXsearch, /* itoc.001220: ·j´M¬Û¦P¼ÐÃD¤å³¹ */ + 'a', XoXauthor, /* itoc.001220: ·j´M§@ªÌ */ + '/', XoXtitle, /* itoc.001220: ·j´M¼ÐÃD */ + 'f', XoXfull, /* itoc.030608: ¥þ¤å·j´M */ + 'G', XoXmark, /* itoc.010325: ·j´M mark ¤å³¹ */ + 'L', XoXlocal, /* itoc.010822: ·j´M¥»¦a¤å³¹ */ + 'i', XoXrestrict, /* chensc.060827: ·j´M¥[±K¤å³¹ */ + 'l', XoXscore, /* chensc.060827: ·j´M³Q±ÀÂˤ峹 */ + +#ifdef HAVE_XYNEWS + 'u', XoNews, /* itoc.010822: ·s»D¾\Ū¼Ò¦¡ */ +#endif + + Ctrl('G'), post_redir, + 'M', post_move, + 'h', post_help +}; + + +KeyFunc xpost_cb[] = +{ + XO_INIT, xpost_init, + XO_LOAD, xpost_load, + XO_HEAD, xpost_head, + XO_BODY, post_body, /* Thor.980911: ¦@¥Î§Y¥i */ + + 'r', xpost_browse, + 'y', post_reply, + 't', post_tag, + 'x', post_cross, + 'X', post_forward, + 'c', post_copy, + 'g', gem_gather, + 'm', post_mark, + 'd', post_delete, /* Thor.980911: ¤è«KªO¥D */ + 'E', post_edit, /* itoc.010716: ´£¨Ñ XPOST ¤¤¥i¥H½s¿è¼ÐÃD¡B¤å³¹¡A¥[±K */ + 'T', post_title, +#ifdef HAVE_SCORE + '%', post_score, + '#', post_mscore, +#endif + 'w', post_write, +#ifdef HAVE_REFUSEMARK + Ctrl('Y'), post_refuse, +#endif +#ifdef HAVE_LABELMARK + 'n', post_label, +#endif + + '~', XoXselect, + 'S', XoXsearch, + 'a', XoXauthor, + '/', XoXtitle, + 'f', XoXfull, + 'G', XoXmark, + 'L', XoXlocal, + 'i', XoXrestrict, + 'l', XoXscore, + + 'I', post_ainfo, + 'W', post_binfo, + + Ctrl('P'), post_add, + Ctrl('D'), post_prune, + Ctrl('Q'), xo_uquery, + Ctrl('O'), xo_usetup, + + 'h', post_help /* itoc.030511: ¦@¥Î§Y¥i */ +}; + + +#ifdef HAVE_XYNEWS +KeyFunc news_cb[] = +{ + XO_INIT, news_init, + XO_LOAD, news_load, + XO_HEAD, news_head, + XO_BODY, post_body, + + 'r', XoXsearch, + + 'h', post_help /* itoc.030511: ¦@¥Î§Y¥i */ +}; +#endif /* HAVE_XYNEWS */ diff --git a/maple/talk.c b/maple/talk.c new file mode 100644 index 0000000..d5f654f --- /dev/null +++ b/maple/talk.c @@ -0,0 +1,1424 @@ +/*-------------------------------------------------------*/ +/* talk.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : talk/query routines */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ + + +#define _MODES_C_ + + +#include "bbs.h" +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> + + +extern UCACHE *ushm; + + +typedef struct +{ + int curcol, curln; + int sline, eline; +#ifdef HAVE_MULTI_BYTE + int zhc; +#endif +} talk_win; + + +/* ------------------------------------- */ +/* ¯u¹ê°Ê§@ */ +/* ------------------------------------- */ + + +char * +bmode(up, simple) + UTMP *up; + int simple; +{ + static char modestr[32]; + int mode; + char *word, *mateid; + + word = ModeTypeTable[mode = up->mode]; + + if (simple) + return word; + +#ifdef BMW_COUNT + if (simple = up->bmw_count) /* ɥΠsimple */ + { + sprintf(modestr, "%d Ó¤ô²y", simple); + return modestr; + } +#endif + + + if (mode < M_TALK || mode > M_IDLE) /* M_TALK(§t) »P M_IDLE(§t) ¶¡±µ mateid */ + return word; + + mateid = up->mateid; + + if (mode == M_TALK) + { + /* itoc.020829: up ¦b Talk ®É¡AY up->mateid Áô§Î«h¬Ý¤£¨£ */ + if (!utmp_get(0, mateid)) + mateid = "µL¦W¤ó"; + } + +// sprintf(modestr, "%s:%s", word, mateid); + sprintf (modestr, "%s", word); + return modestr; +} + + +static void +showplans(userid) + char *userid; +{ + int i; + FILE *fp; + char buf[ANSILINELEN]; + + usr_fpath(buf, userid, fn_plans); + if (fp = fopen(buf, "r")) + { + i = MAXQUERYLINES; + while (i-- && fgets(buf, sizeof(buf), fp)) + outx(buf); + fclose(fp); + } +} + +static void +do_query(acct) + ACCT *acct; +{ + UTMP *up; + int userno, rich; + char *userid; + char fortune[4][9] = {"¨ª³h¤^¤¢", "¤@¯ëÓÅé", "®a¹Ò¤p±d", "°]»Ö¦a¥D"}; + BRD *pbrd = has_personalbrd (acct->userid); + + utmp_mode(M_QUERY); + + userno = acct->userno; + userid = acct->userid; +// strcpy(cutmp->mateid, userid); + + up = utmp_find(userno); + rich = acct->money >= 1000000 ? (acct->gold >= 100 ? 3 : 2) : (acct->money >= 50000 ? 1 : 0); + + prints("\033[1;33m[±b¸¹]\033[m %-12s \033[1;33m[¼ÊºÙ]\033[m %-16.16s \033[1;33m[¤W¯¸]\033[m %5d ¦¸ \033[1;33m[¤å³¹]\033[m %5d ½g\n", + userid, acct->username, acct->numlogins, acct->numposts); + + prints("\033[1;33m[»{ÃÒ]\033[m %s³q¹L»{ÃÒ \033[1;33m[°ÊºA]\033[m %-16.16s \033[1;33m[°]²£]\033[m %s \033[1;33m[ÓªO]\033[m %s\n", + acct->userlevel & PERM_VALID ? "¤w¸g" : "©|¥¼", + (up && can_see(cutmp, up)) ? bmode(up, 1) : "¤£¦b¯¸¤W", + fortune[rich], + (pbrd && !strcmp(pbrd->class, "Ó¤H") && pbrd->readlevel != PERM_SYSOP ? "¦³" : "¨S¦³©ÎÁôªO")/*, + (m_query(userid) & STATUS_BIFF) ? "¦³·s«H¥ó" : "³£¬Ý¹L¤F"*/ ); + + prints("\033[1;33m[¨Ó·½]\033[m (%s) %s\n", + Btime(&acct->lastlogin), acct->lasthost); + +/* prints ("\033[1;33m[¤W¯¸®É¼Æ]\033[m %s\n", + Bdifftime((int)difftime(time(NULL), acct->firstlogin)));*/ + + showplans(userid); + vmsg(NULL); +} + + +void +my_query(userid) + char *userid; +{ + ACCT acct; + + if (acct_load(&acct, userid) >= 0) + do_query(&acct); + else + vmsg(err_uid); +} + + +#ifdef HAVE_ALOHA +static int +chkfrienz(frienz) + FRIENZ *frienz; +{ + int userno; + + userno = frienz->userno; + return (userno > 0 && userno == acct_userno(frienz->userid)); +} + + +static int +frienz_cmp(a, b) + FRIENZ *a, *b; +{ + return a->userno - b->userno; +} + + +void +frienz_sync(fpath) + char *fpath; +{ + rec_sync(fpath, sizeof(FRIENZ), frienz_cmp, chkfrienz); +} + + +void +aloha() +{ + UTMP *up; + int fd; + char fpath[64]; + BMW bmw; + FRIENZ *frienz; + int userno; + + usr_fpath(fpath, cuser.userid, FN_FRIENZ); + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + bmw.caller = cutmp; + /* bmw.sender = cuser.userno; */ /* bmw.sender ¨Ì¹ï¤è¥i¥H call §Ú¡A«Ý·|¦A¨M©w */ + strcpy(bmw.userid, cuser.userid); + strcpy(bmw.msg, "¡· èè½ñ¶i"BBSNAME"ªºªù [¤W¯¸³qª¾] ¡·"); + + mgets(-1); + while (frienz = mread(fd, sizeof(FRIENZ))) + { + userno = frienz->userno; + up = utmp_find(userno); + + if (up && (up->ufo & UFO_ALOHA) && !(up->status & STATUS_REJECT) && can_see(up, cutmp)) /* ¹ï¤è¬Ý¤£¨£§Ú¤£³qª¾ */ + { + /* ¦n¤Í¥B¦Û¤v¨S¦³»·Â÷¹ÐÄÛ¤~¥i¥H reply */ + bmw.sender = (is_mygood(userno) && !(cuser.ufo & UFO_QUIET)) ? cuser.userno : 0; + bmw.recver = userno; + bmw_send(up, &bmw); + } + } + close(fd); + } +} +#endif + + +#ifdef LOGIN_NOTIFY +extern LinkList *ll_head; + + +int +t_loginNotify() +{ + LinkList *wp; + BENZ benz; + char fpath[64]; + + /* ³]©w list ªº¦W³æ */ + + vs_bar("¨t²Î¨ó´Mºô¤Í"); + + ll_new(); + + if (pal_list(0)) + { + wp = ll_head; + benz.userno = cuser.userno; + strcpy(benz.userid, cuser.userid); + + do + { + if (strcmp(cuser.userid, wp->data)) /* ¤£¥i¨ó´M¦Û¤v */ + { + usr_fpath(fpath, wp->data, FN_BENZ); + rec_add(fpath, &benz, sizeof(BENZ)); + } + } while (wp = wp->next); + + vmsg("¨ó´M³]©w§¹¦¨¡A¹ï¤è¤W¯¸®É¨t²Î·|³qª¾±z"); + } + return 0; +} + + +void +loginNotify() +{ + UTMP *up; + int fd; + char fpath[64]; + BMW bmw; + BENZ *benz; + int userno; + int row, col; /* pºâ¦L¨ìþ */ + + usr_fpath(fpath, cuser.userid, FN_BENZ); + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + vs_bar("¨t²Î¨ó´Mºô¤Í"); + + bmw.caller = cutmp; + /* bmw.sender = cuser.userno; */ /* bmw.sender ¨Ì¹ï¤è¥i¥H call §Ú¡A«Ý·|¦A¨M©w */ + strcpy(bmw.userid, cuser.userid); + strcpy(bmw.msg, "¡· èè½ñ¶i"BBSNAME"ªºªù [¨t²Î¨ó´M] ¡·"); + + row = 1; + col = 0; + mgets(-1); + while (benz = mread(fd, sizeof(BENZ))) + { + /* ¦L¥Xþ¨Ç¤H¦b§ä§Ú */ + if (row < b_lines) + { + move(row, col); + outs(benz->userid); + col += IDLEN + 1; + if (col > b_cols - IDLEN - 1) /* Á`¦@¥i¥H©ñ b_cols / (IDLEN + 1) Äæ */ + { + row++; + col = 0; + } + } + + userno = benz->userno; + up = utmp_find(userno); + + if (up && !(up->status & STATUS_REJECT) && can_see(up, cutmp)) /* ¹ï¤è¬Ý¤£¨£§Ú¤£³qª¾ */ + { + /* ¦n¤Í¥B¦Û¤v¨S¦³»·Â÷¹ÐÄÛ¤~¥i¥H reply */ + bmw.sender = (is_mygood(userno) && !(cuser.ufo & UFO_QUIET)) ? cuser.userno : 0; + bmw.recver = userno; + bmw_send(up, &bmw); + outc('*'); /* Thor.980707: ¦³³qª¾¨ìªº¦³©Ò¤£¦P */ + } + } + close(fd); + unlink(fpath); + vmsg("³o¨Ç¨Ï¥ÎªÌ³]±z¬°¤W¯¸¨ó´M¡A¥´ * ªí¥Ü¥Ø«e¦b¯¸¤W"); + } +} +#endif + + +#ifdef LOG_TALK +static void +talk_save() +{ + char fpath[64]; + + /* lkchu.981201: ©ñ¶i¨p¤H«H½c¤º/²M°£ */ + usr_fpath(fpath, cuser.userid, FN_TALK_LOG); + + if (!(cuser.ufo & UFO_NTLOG) && vans("¥»¦¸²á¤Ñ¬ö¿ý³B²z (M)³Æ§Ñ¿ý (C)²M°£¡H[M] ") != 'c') + mail_self(fpath, cuser.userid, "[³Æ §Ñ ¿ý] ²á¤Ñ¬ö¿ý", MAIL_READ | MAIL_NOREPLY); + + unlink(fpath); +} +#endif + + +/* ----------------------------------------------------- */ +/* talk sub-routines */ +/* ----------------------------------------------------- */ + + +static char page_requestor[40]; +#ifdef HAVE_MULTI_BYTE +static int page_requestor_zhc; +#endif + +#ifdef HAVE_MULTI_BYTE +static uschar talk_pic[T_LINES][SCR_WIDTH + 1]; /* ¨C¦C¥i¥H¿é¤Jªº¦r¼Æ¬° SCR_WIDTH - 1 («O¯d¤GӪťÕ) */ +#else +static uschar talk_pic[T_LINES][SCR_WIDTH]; /* ¨C¦C¥i¥H¿é¤Jªº¦r¼Æ¬° SCR_WIDTH - 1 («O¯d¤@ӪťÕ) */ +#endif +static int talk_len[T_LINES]; /* ¨C¦C¥Ø«e¤w¿é¤J¦h¤Ö¦r */ + + +static void +talk_clearline(ln, col) + int ln, col; +{ + int i, len; + + len = talk_len[ln]; + for (i = col; i < len; i++) + talk_pic[ln][i] = ' '; + + talk_len[ln] = col; +} + + +static void +talk_outs(str, len) + uschar *str; + int len; +{ + int ch; + uschar *end; + + /* ©M¤@¯ëªº outs() ¬O¬Û¦P¡A¥u¬O¨î¦L len Ó¦r */ + end = str + len; + while (ch = *str) + { + outc(ch); + if (++str >= end) + break; + } +} + + +static void +talk_nextline(twin) + talk_win *twin; +{ + int curln, max, len, i; + + curln = twin->curln; + if (curln != twin->eline) + { + twin->curln = ++curln; + } + else /* ¤w¸g¬O³Ì«á¤@¦C¡An¦V¤W±²°Ê */ + { + max = twin->eline; + for (curln = twin->sline; curln < max; curln++) + { + len = BMAX(talk_len[curln], talk_len[curln + 1]); + for (i = 0; i < len; i++) + talk_pic[curln][i] = talk_pic[curln + 1][i]; + talk_len[curln] = talk_len[curln + 1]; + move(curln, 0); + talk_outs(talk_pic[curln], talk_len[curln]); + clrtoeol(); + } + } + + /* ·sªº¤@¦C */ + talk_clearline(curln, 0); + + twin->curcol = 0; + move(curln, 0); + clrtoeol(); +} + + +static void +talk_char(twin, ch) + talk_win *twin; + int ch; +{ + int col, ln, len, i; + + col = twin->curcol; + ln = twin->curln; + len = talk_len[ln]; + + if (isprint2(ch)) + { + if (col >= SCR_WIDTH - 1) /* Y¤w¸g¥´¨ì¦C§À¡A¥ý´«¦C */ + { + talk_nextline(twin); + col = twin->curcol; + ln = twin->curln; + len = talk_len[ln]; + } + + move(ln, col); + if (col >= len) + { + talk_pic[ln][col] = ch; + outc(ch); + twin->curcol = ++col; + talk_len[ln] = col; + } + else /* n insert */ + { + for (i = SCR_WIDTH - 2; i > col; i--) + talk_pic[ln][i] = talk_pic[ln][i - 1]; + talk_pic[ln][col] = ch; + if (len < SCR_WIDTH - 1) + len++; + talk_len[ln] = len; + talk_outs(talk_pic[ln] + col, len - col); + twin->curcol = ++col; + move(ln, col); + } + } + else + { + switch (ch) + { + case '\n': + talk_nextline(twin); + break; + + case KEY_BKSP: /* backspace */ + if (col > 0) + { + if (col > len) + { + /* °µ©M KEY_LEFT ¤@¼Ëªº¨Æ */ + twin->curcol = --col; + move(ln, col); + } + else + { + col--; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: §PÂ_²{¦b§R°£ªº¦ì¸m¬O§_¬°º~¦rªº«á¥b¬q¡AY¬O§R¤G¦r¤¸ */ + if (twin->zhc && col && IS_ZHC_LO(talk_pic[ln], col)) + { + col--; + ch = 2; + } + else +#endif + ch = 1; + for (i = col; i < SCR_WIDTH - 1; i++) + talk_pic[ln][i] = talk_pic[ln][i + ch]; + move(ln, col); + talk_outs(talk_pic[ln] + col, len - col); + twin->curcol = col; + talk_len[ln] = len - ch; + move(ln, col); + } + } + break; + + case Ctrl('D'): /* KEY_DEL */ + if (col < len) + { +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: §PÂ_²{¦b§R°£ªº¦ì¸m¬O§_¬°º~¦rªº«e¥b¬q¡AY¬O§R¤G¦r¤¸ */ + if (twin->zhc && col < len - 1 && IS_ZHC_HI(talk_pic[ln][col])) + ch = 2; + else +#endif + ch = 1; + for (i = col; i < SCR_WIDTH - 1; i++) + talk_pic[ln][i] = talk_pic[ln][i + ch]; + move(ln, col); + talk_outs(talk_pic[ln] + col, len - col); + talk_len[ln] = len - ch; + move(ln, col); + } + break; + + case Ctrl('B'): /* KEY_LEFT */ + if (col > 0) + { + col--; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: ¥ª²¾®É¸I¨ìº~¦r²¾Âù®æ */ + if (twin->zhc && col && IS_ZHC_LO(talk_pic[ln], col)) + col--; +#endif + twin->curcol = col; + move(ln, col); + } + break; + + case Ctrl('F'): /* KEY_RIGHT */ + if (col < SCR_WIDTH - 1) + { + col++; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: ¥k²¾®É¸I¨ìº~¦r²¾Âù®æ */ + if (twin->zhc && col < SCR_WIDTH - 1 && IS_ZHC_HI(talk_pic[ln][col - 1])) + col++; +#endif + twin->curcol = col; + move(ln, col); + } + break; + + case Ctrl('P'): /* KEY_UP */ + if (ln > twin->sline) + { + twin->curln = --ln; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: º~¦r¾ã¦r½Õ¸` */ + if (twin->zhc && col < SCR_WIDTH - 1 && IS_ZHC_LO(talk_pic[ln], col)) + col++; +#endif + move(ln, col); + } + break; + + case Ctrl('N'): /* KEY_DOWN */ + if (ln < twin->eline) + { + twin->curln = ++ln; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: º~¦r¾ã¦r½Õ¸` */ + if (twin->zhc && col < SCR_WIDTH - 1 && IS_ZHC_LO(talk_pic[ln], col)) + col++; +#endif + move(ln, col); + } + break; + + case Ctrl('A'): /* KEY_HOME */ + twin->curcol = 0; + move(ln, 0); + break; + + case Ctrl('E'): /* KEY_END */ + twin->curcol = len; + move(ln, len); + break; + + case Ctrl('Y'): /* clear this line */ + talk_clearline(ln, 0); + twin->curcol = 0; + move(ln, 0); + clrtoeol(); + break; + + case Ctrl('K'): /* clear to end of line */ + talk_clearline(ln, col); + move(ln, col); + clrtoeol(); + break; + + case Ctrl('G'): /* bell */ + bell(); + break; + } + } +} + + +static void +talk_string(twin, str) + talk_win *twin; + uschar *str; +{ + int ch; + + while (ch = *str) + { + talk_char(twin, ch); + str++; + } +} + + +static void +talk_speak(fd) + int fd; +{ + talk_win mywin, itswin; + uschar data[80]; + char buf[80]; + int i, ch; +#ifdef LOG_TALK + char mywords[80], itswords[80], itsuserid[40]; + FILE *fp; + +#if 0 /* talk log ªº algo */ + ¹ï¸Ü¨â¤è¤À§O¬° mywin & itswin, ¥un¨ä¤@¦³ recv ªº¸Ü´N·|°e¤W¹ïÀ³ªº win, + ©Ò¥H§ÚÌ¥²¶·n¥ý§â¦Û¤v¥´ªº¦r»P¹ï¤è¥´ªº¦r¤À¶}¨Ó. + + ©ó¬O´N¥ý«Ø¨âÓ spool, ¤À§O±N mywin/itswin recv ªº char ©¹¦U¦Ûªº spool + ¸Ì¥á, ¥Ø«e³] spool è¦n¬O¤@¦Cªº¤j¤p, ©Ò¥H¥un¬O spool º¡¤F, ©Î¬O¸I¨ì´« + ¦æ¦r¤¸, ´N§â spool ¸Ìªº¸ê®Æ¼g¦^ log, µM«á²M±¼ spool, ¦p¦¹Ä~Äò :) +#endif + + /* lkchu: make sure that's empty */ + mywords[0] = itswords[0] = '\0'; + + strcpy(itsuserid, page_requestor); + strtok(itsuserid, " ("); +#endif + + utmp_mode(M_TALK); + + ch = 58 - strlen(page_requestor); + + sprintf(buf, "%s¡i%s", cuser.userid, cuser.username); + + i = ch - strlen(buf); + if (i >= 0) + { + i = (i >> 1) + 1; + } + else + { + buf[ch] = '\0'; + i = 1; + } + memset(data, ' ', i); + data[i] = '\0'; + + memset(&mywin, 0, sizeof(mywin)); + memset(&itswin, 0, sizeof(itswin)); + + i = b_lines >> 1; + mywin.eline = i - 1; +#ifdef HAVE_MULTI_BYTE + mywin.zhc = cuser.ufo & UFO_ZHC; +#endif + itswin.curln = itswin.sline = i + 1; + itswin.eline = b_lines - 1; +#ifdef HAVE_MULTI_BYTE + itswin.zhc = page_requestor_zhc; +#endif + + clear(); + move(i, 0); + prints("\033[1;46;37m ½Í¤Ñ»¡¦a \033[45m%s%s¡j ¡» %s%s\033[m", + data, buf, page_requestor, data); + outf(FOOTER_TALK); + move(0, 0); + + /* talk_pic °O¿ý¾ãÓµe±ªº¤å¦r¡Aªì©lȬOªÅ¥Õ */ + memset(talk_pic, ' ', sizeof(talk_pic)); + /* talk_len °O¿ý¾ãÓµe±¦U¦C¤w¸g¥Î¤F¦h¤Ö¦r */ + memset(talk_len, 0, sizeof(talk_len)); + +#ifdef LOG_TALK /* lkchu.981201: ²á¤Ñ°O¿ý */ + usr_fpath(buf, cuser.userid, FN_TALK_LOG); + if (fp = fopen(buf, "a+")) + { + fprintf(fp, "¡i %s »P %s ¤§²á¤Ñ°O¿ý ¡j\n", cuser.userid, page_requestor); + fprintf(fp, "¶}©l²á¤Ñ®É¶¡ [%s]\n", Now()); /* itoc.010108: °O¿ý¶}©l²á¤Ñ®É¶¡ */ + } +#endif + + add_io(fd, 60); + + for (;;) + { + ch = vkey(); + +#ifdef EVERY_Z + /* Thor.980725: talk¤¤, ctrl-z */ + if (ch == Ctrl('Z')) + { + char buf[IDLEN + 1]; + screenline slt[T_LINES]; + + /* Thor.980731: ¼È¦s mateid, ¦]¬°¥X¥h®É¥i¯à·|¥Î±¼ mateid */ + strcpy(buf, cutmp->mateid); + + vio_save(); /* Thor.980727: ¼È¦s vio_fd */ + vs_save(slt); + every_Z(0); + vs_restore(slt); + vio_restore(); /* Thor.980727: ÁÙì vio_fd */ + + /* Thor.980731: ÁÙì mateid, ¦]¬°¥X¥h®É¥i¯à·|¥Î±¼ mateid */ + strcpy(cutmp->mateid, buf); + continue; + } +#endif + + if (ch == Ctrl('D') || ch == Ctrl('C')) + break; + + if (ch == I_OTHERDATA) + { + ch = recv(fd, data, 80, 0); + if (ch <= 0) + break; + +#ifdef HAVE_GAME + if (data[0] == Ctrl('O')) + { /* Thor.990219: ©I¥s¥~±¾´Ñ½L */ + if (DL_func("bin/bwboard.so:vaBWboard", fd, 1) == -2) + break; + continue; + } +#endif + for (i = 0; i < ch; i++) + { + talk_char(&itswin, data[i]); + +#ifdef LOG_TALK /* ¹ï¤è»¡ªº¸Ü */ + switch (data[i]) + { + case '\n': + /* lkchu.981201: ¦³´«¦C´N§â itswords ¦L¥X²M±¼ */ + if (itswords[0] != '\0') + { + fprintf(fp, "\033[32m%s¡G%s\033[m\n", itsuserid, itswords); + itswords[0] = '\0'; + } + break; + + case KEY_BKSP: /* lkchu.981201: backspace */ + itswords[strlen(itswords) - 1] = '\0'; + break; + + default: + if (isprint2(data[i])) + { + if (strlen(itswords) < sizeof(itswords)) + { + strncat(itswords, (char *)&data[i], 1); + } + else /* lkchu.981201: itswords ¸Ëº¡¤F */ + { + fprintf(fp, "\033[32m%s¡G%s%c\033[m\n", itsuserid, itswords, data[i]); + itswords[0] = '\0'; + } + } + break; + } +#endif + + } + } + +#ifdef HAVE_GAME + else if (ch == Ctrl('O')) + { /* Thor.990219: ©I¥s¥~±¾´Ñ½L */ + data[0] = ch; + if (send(fd, data, 1, 0) != 1) + break; + if (DL_func("bin/bwboard.so:vaBWboard", fd, 0) == -2) + break; + } +#endif + + else if (ch == Ctrl('T')) + { + if (cuser.userlevel) /* guest ¦³¥i¯à³Q¯¸ªøÁܽРTalk */ + { + cuser.ufo ^= UFO_PAGER; + cutmp->ufo = cuser.ufo; + talk_string(&mywin, (cuser.ufo & UFO_PAGER) ? "¡» Ãö³¬©I¥s¾¹\n" : "¡» ¥´¶}©I¥s¾¹\n"); + } + } + + else + { + switch (ch) + { + case KEY_DEL: + ch = Ctrl('D'); + break; + + case KEY_LEFT: + ch = Ctrl('B'); + break; + + case KEY_RIGHT: + ch = Ctrl('F'); + break; + + case KEY_UP: + ch = Ctrl('P'); + break; + + case KEY_DOWN: + ch = Ctrl('N'); + break; + + case KEY_HOME: + ch = Ctrl('A'); + break; + + case KEY_END: + ch = Ctrl('E'); + break; + } + + data[0] = ch; + if (send(fd, data, 1, 0) != 1) + break; + + talk_char(&mywin, ch); + +#ifdef LOG_TALK /* ¦Û¤v»¡ªº¸Ü */ + switch (ch) + { + case '\n': + if (mywords[0] != '\0') + { + fprintf(fp, "%s¡G%s\n", cuser.userid, mywords); + mywords[0] = '\0'; + } + break; + + case KEY_BKSP: + mywords[strlen(mywords) - 1] = '\0'; + break; + + default: + if (isprint2(ch)) + { + if (strlen(mywords) < sizeof(mywords)) + { + strncat(mywords, (char *)&ch, 1); + } + else + { + fprintf(fp, "%s¡G%s%c\n", cuser.userid, mywords, ch); + mywords[0] = '\0'; + } + } + break; + } +#endif + +#ifdef EVERY_BIFF + /* Thor.980805: ¦³¤H¦b®ÇÃä«öenter¤~»Ýncheck biff */ + if (ch == '\n') + { + static int old_biff; + int biff = HAS_STATUS(STATUS_BIFF); + if (biff && !old_biff) + talk_string(&mywin, "¡» ¾´¡I¶l®t¨Ó«ö¹a¤F¡I\n"); + old_biff = biff; + } +#endif + } + } + +#ifdef LOG_TALK + /* itoc.021205: ³Ì«á¤@¥y¸ÜY¨S¦³«ö ENTER ´N¤£·|³Q°O¿ý¶i talk.log¡A + ¦b¦¹¯S§O³B²z¡A¶¶§Ç©w¬°¥ý myword ¦A itsword¡A¦ý¥i¯à·|¬Û¤Ï */ + if (mywords[0] != '\0') + fprintf(fp, "%s¡G%s\n", cuser.userid, mywords); + if (itswords[0] != '\0') + fprintf(fp, "\033[32m%s¡G%s\033[m\n", itsuserid, itswords); + + fclose(fp); +#endif + + add_io(0, 60); +} + + +static void +talk_hangup(sock) + int sock; +{ + cutmp->sockport = 0; + add_io(0, 60); + close(sock); +} + + +static char *talk_reason[] = +{ + "¹ï¤£°_¡A§Ú¦³¨Æ±¡¤£¯à¸ò±z talk", + "§Ú²{¦b«Ü¦£¡A½Ðµ¥¤@·|¨à¦A call §Ú", + "²{¦b¦£¤£¹L¨Ó¡Aµ¥¤@¤U§Ú·|¥D°Ê page ±z", + "§Ú²{¦b¤£·Q talk °Õ", + "«Ü·Ð«¨¡A§Ú¹ê¦b¤£·Q talk", + +#ifdef EVERY_Z + "§Úªº¼L¤Ú¥¿¦£µÛ©M§O¤HÁ¿¸Ü©O¡A¨S¦³ªÅªº¼L¤Ú¤F" + /* Thor.980725: for chat&talk ¥Î^z §@·Ç³Æ */ +#endif +}; + + +/* return 0: ¨S¦³ talk, 1: ¦³ talk, -1: ¨ä¥L */ + + +int +talk_page(up) + UTMP *up; +{ + int sock, msgsock; + struct sockaddr_in sin; + pid_t pid; + int ans, length; + char buf[60]; +#if defined(__OpenBSD__) + struct hostent *h; +#endif + +#ifdef EVERY_Z + /* Thor.980725: ¬° talk & chat ¥i¥Î ^z §@·Ç³Æ */ + if (vio_holdon()) + { + vmsg("±zÁ¿¸ÜÁ¿¤@¥bÁÙ¨SÁ¿§¹C"); + return 0; + } +#endif + + pid = up->mode; + if (pid >= M_SYSTEM && pid <= M_CHAT) + { + vmsg("¹ï¤èµL·v²á¤Ñ"); + return 0; + } + + if (!(pid = up->pid) || kill(pid, 0)) + { + vmsg(MSG_USR_LEFT); + return 0; + } + + /* showplans(up->userid); */ + + if (vans("½T©wn©M¥L/¦o½Í¤Ñ¶Ü(Y/N)¡H[N] ") != 'y') + return 0; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) + return 0; + +#if defined(__OpenBSD__) /* lkchu */ + + if (!(h = gethostbyname(str_host))) + return -1; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = 0; + memcpy(&sin.sin_addr, h->h_addr, h->h_length); + +#else + + sin.sin_family = AF_INET; + sin.sin_port = 0; + sin.sin_addr.s_addr = INADDR_ANY; + memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); + +#endif + + length = sizeof(sin); + if (bind(sock, (struct sockaddr *) &sin, length) < 0 || + getsockname(sock, (struct sockaddr *) &sin, &length) < 0) + { + close(sock); + return 0; + } + + cutmp->sockport = sin.sin_port; + strcpy(cutmp->mateid, up->userid); + up->talker = cutmp; + utmp_mode(M_PAGE); + kill(pid, SIGUSR1); + + clear(); + prints("º«×©I¥s %s ...\n¥i«ö Ctrl-D ¤¤¤î", up->userid); + + listen(sock, 1); + add_io(sock, 20); + do + { + msgsock = igetch(); + + if (msgsock == Ctrl('D')) + { + talk_hangup(sock); + return -1; + } + + if (msgsock == I_TIMEOUT) + { + move(0, 0); + outs("¦A"); + bell(); + + if (kill(pid, SIGUSR1)) + /* Thor.990201.µù¸Ñ: ¨ä¹ê³oÓ kill¡A¤]¥u¬O¬Ý¬Ý¹ï¤è¬O¤£¬OÁÙ¦b½u¤W¦Ó¤w¡A«µosignal¨ä¹ê¦ü¥G talk_rqst ¤£·|¦A³Q¥s */ + { + talk_hangup(sock); + vmsg(MSG_USR_LEFT); + return -1; + } + } + } while (msgsock != I_OTHERDATA); + + msgsock = accept(sock, NULL, NULL); + talk_hangup(sock); + if (msgsock == -1) + return -1; + + length = read(msgsock, buf, sizeof(buf)); + ans = buf[0]; + if (ans == 'y') + { + sprintf(page_requestor, "%s (%s)", up->userid, up->username); +#ifdef HAVE_MULTI_BYTE + page_requestor_zhc = up->ufo & UFO_ZHC; +#endif + + /* Thor.980814.ª`·N: ¦b¦¹¦³¤@ÓÂû¦PÀnÁ¿ªº¥i¯à±¡ªp, ¦pªG A ¥ý page B, ¦ý¦b B ¦^À³«e«o°¨¤WÂ÷¶}, ´« page C, + C ©|¥¼¦^À³«e, ¦pªG B ¦^À³¤F, B ´N·|³Q accept, ¦Ó¤£¬O C. + ¦¹®É¦b¿Ã¹õ¤¤¥¡, ¬Ý¨ìªº page_requestor·|¬O C, ¥i¬O¨Æ¹ê¤W, talkªº¹ï¶H¬O B, ³y¦¨Âû¦PÀnÁ¿! + ¼È®É¤£¤©×¥¿, ¥H§@¬°ªá¤ßªÌªºÃg»@ :P */ + + talk_speak(msgsock); + } + else + { + char *reply; + + if (ans == ' ') + { + reply = buf; + reply[length] = '\0'; + } + else + reply = talk_reason[ans - '1']; + + move(4, 0); + outs("¡i¦^µ¡j"); + outs(reply); + } + + close(msgsock); + cutmp->talker = NULL; +#ifdef LOG_TALK + if (ans == 'y') /* itoc.000512: ¨¾¤îTalk³Q©Úµ´®É¡A²£¥Í²á¤Ñ°O¿ýªºrecord */ + talk_save(); /* lkchu.981201: talk °O¿ý³B²z */ +#endif + vmsg("²á¤Ñµ²§ô"); + return 1; +} + + +/* ----------------------------------------------------- */ +/* talk main-routines */ +/* ----------------------------------------------------- */ + + +int +t_pager() +{ +#if 0 /* itoc.010923: Á×§K»~«ö¡A¤À²M·¡¤@ÂI */ + ¢z¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢{ + ¢x ¢x UFO_PAGER¢x UFO_RCVER¢x UFO_QUIET¢x + ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢t + ¢x§¹¥þ¶}©ñ¢x ¢x ¢x ¢x + ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢t + ¢x¦n¤Í±M½u¢x ¡³ ¢x ¢x ¢x + ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢t + ¢x»·Â÷¹ÐÄÛ¢x ¡³ ¢x ¡³ ¢x ¡³ ¢x + ¢|¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢} +#endif + + switch (vans("¤Á´«¦©¾÷¬° 1)§¹¥þ¶}©ñ 2)¦n¤Í±M½u 3)»·Â÷¹ÐÄÛ [Q] ")) + { + case '1': +#ifdef HAVE_NOBROAD + cuser.ufo &= ~(UFO_PAGER | UFO_RCVER | UFO_QUIET); +#else + cuser.ufo &= ~(UFO_PAGER | UFO_QUIET); +#endif + cutmp->ufo = cuser.ufo; + return 0; /* itoc.010923: ÁöµM¤£»Ýn«Ã¸¿Ã¹õ¡A¦ý¬O±j¢«Ã¸¤~¯à§ó·s feeter ¤¤ªº pager ¼Ò¦¡ */ + + case '2': + cuser.ufo |= UFO_PAGER; +#ifdef HAVE_NOBROAD + cuser.ufo &= ~(UFO_RCVER | UFO_QUIET); +#else + cuser.ufo &= ~UFO_QUIET; +#endif + cutmp->ufo = cuser.ufo; + return 0; + + case '3': +#ifdef HAVE_NOBROAD + cuser.ufo |= (UFO_PAGER | UFO_RCVER | UFO_QUIET); +#else + cuser.ufo |= (UFO_PAGER | UFO_QUIET); +#endif + cutmp->ufo = cuser.ufo; + return 0; + } + + return XEASY; +} + + +int +t_cloak() +{ +#ifdef HAVE_SUPERCLOAK + if (HAS_PERM(PERM_ALLADMIN)) + { + switch (vans("Áô¨¼Ò¦¡ 1)¤@¯ëÁô§Î 2)µµ¦âÁô§Î 3)¤£Áô§Î [Q] ")) + { + case '1': + cuser.ufo |= UFO_CLOAK; + cuser.ufo &= ~UFO_SUPERCLOAK; + vmsg("¼K¼K¡A¸ú°_¨ÓÅo¡I"); + break; + + case '2': + cuser.ufo |= (UFO_CLOAK | UFO_SUPERCLOAK); + vmsg("¼K¼K¡AÂð_¨ÓÅo¡A¨ä¥L¯¸ªø¤]¬Ý¤£¨ì§Ú¡I"); + break; + + case '3': + cuser.ufo &= ~(UFO_CLOAK | UFO_SUPERCLOAK); + vmsg("«²{¦¿´ò¤F"); + break; + } + } + else +#endif + if (HAS_PERM(PERM_CLOAK)) + { + cuser.ufo ^= UFO_CLOAK; + vmsg(cuser.ufo & UFO_CLOAK ? "¼K¼K¡A¸ú°_¨ÓÅo¡I" : "«²{¦¿´ò¤F"); + } + + cutmp->ufo = cuser.ufo; + return XEASY; +} + + +int +t_query() +{ + ACCT acct; + + vs_bar("¬d¸ßºô¤Í"); + if (acct_get(msg_uid, &acct) > 0) + { + move(1, 0); + clrtobot(); + do_query(&acct); + } + + return 0; +} + + +static int +talk_choose() +{ + UTMP *up, *ubase, *uceil; + int self; + char userid[IDLEN + 1]; + + ll_new(); + + self = cuser.userno; + ubase = up = ushm->uslot; + /* uceil = ushm->uceil; */ + uceil = ubase + ushm->count; + do + { + if (up->pid && up->userno != self && up->userlevel && can_see(cutmp, up)) + ll_add(up->userid); + } while (++up <= uceil); + + if (!vget(1, 0, msg_uid, userid, IDLEN + 1, GET_LIST)) + return 0; + + up = ubase; + do + { + if (!str_cmp(userid, up->userid)) + return up->userno; + } while (++up <= uceil); + + return 0; +} + + +int +t_talk() +{ + int tuid, unum, ucount; + UTMP *up; + char ans[4]; + + if (total_user <= 1) + { + zmsg("¥Ø«e½u¤W¥u¦³±z¤@¤H¡A§ÖÁܽФj®a¨Ó¥úÁ{¡i" BBSNAME "¡j§a¡I"); + return XEASY; + } + + tuid = talk_choose(); + if (!tuid) + return 0; + + /* ----------------- */ + /* multi-login check */ + /* ----------------- */ + + move(3, 0); + unum = 1; + while ((ucount = utmp_count(tuid, 0)) > 1) + { + outs("(0) ¤£·Q talk ¤F...\n"); + utmp_count(tuid, 1); + vget(1, 33, "½Ð¿ï¾Ü¤@Ó²á¤Ñ¹ï¶H [0]¡G", ans, 3, DOECHO); + unum = atoi(ans); + if (unum == 0) + return 0; + move(3, 0); + clrtobot(); + if (unum > 0 && unum <= ucount) + break; + } + + if (up = utmp_search(tuid, unum)) + { + if (can_override(up)) + { + if (tuid != up->userno) + vmsg(MSG_USR_LEFT); + else + talk_page(up); + } + else + { + vmsg("¹ï¤èÃö±¼©I¥s¾¹¤F"); + } + } + + return 0; +} + + +/* ------------------------------------- */ +/* ¦³¤H¨Ó¦êªù¤l¤F¡A¦^À³©I¥s¾¹ */ +/* ------------------------------------- */ + + +void +talk_rqst() +{ + UTMP *up; + int mode, sock, ans, len, port; + char buf[80]; + struct sockaddr_in sin; + screenline sl[T_LINES]; +#if defined(__OpenBSD__) + struct hostent *h; +#endif + + up = cutmp->talker; + if (!up) + return; + + port = up->sockport; + if (!port) + return; + + mode = bbsmode; + utmp_mode(M_TRQST); + + vs_save(sl); + + clear(); + sprintf(page_requestor, "%s (%s)", up->userid, up->username); + +#ifdef EVERY_Z + /* Thor.980725: ¬° talk & chat ¥i¥Î ^z §@·Ç³Æ */ + + if (vio_holdon()) + { + sprintf(buf, "%s ·Q©M±z²á¡A¤£¹L±z¥u¦³¤@±i¼L", page_requestor); + vmsg(buf); + buf[0] = ans = '6'; /* Thor.980725: ¥u¦³¤@±i¼L */ + len = 1; + goto over_for; + } +#endif + + bell(); + prints("±z·Q¸ò %s ²á¤Ñ¶Ü¡H(¨Ó¦Û %s)", page_requestor, up->from); + for (;;) /* Åý¨Ï¥ÎªÌ¥i¥H¥ý¬d¸ßn¨D²á¤Ñªº¹ï¤è */ + { + ans = vget(1, 0, "==> Q)¬d¸ß Y)²á¤Ñ N)¨ú®ø¡H[Y] ", buf, 3, LCECHO); + if (ans == 'q') + my_query(up->userid); + else + break; + } + + len = 1; + + if (ans == 'n') + { + move(2, 0); + clrtobot(); + for (ans = 0; ans < 5; ans++) + prints("\n (%d) %s", ans + 1, talk_reason[ans]); + ans = vget(10, 0, "½Ð¿é¤J¿ï¶µ©Î¨ä¥L±¡¥Ñ [1]¡G\n==> ", buf + 1, 60, DOECHO); + + if (ans == 0) + ans = '1'; + + if (ans >= '1' && ans <= '5') + { + buf[0] = ans; + } + else + { + buf[0] = ans = ' '; + len = strlen(buf); + } + } + else + { + buf[0] = ans = 'y'; + } + +#ifdef EVERY_Z +over_for: +#endif + + sock = socket(AF_INET, SOCK_STREAM, 0); + +#if defined(__OpenBSD__) /* lkchu */ + + if (!(h = gethostbyname(str_host))) + return; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = port; + memcpy(&sin.sin_addr, h->h_addr, h->h_length); + +#else + + sin.sin_family = AF_INET; + sin.sin_port = port; + /* sin.sin_addr.s_addr = INADDR_LOOPBACK; */ + /* sin.sin_addr.s_addr = INADDR_ANY; */ + /* For FreeBSD 4.x */ + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); + +#endif + + if (!connect(sock, (struct sockaddr *) & sin, sizeof(sin))) + { + send(sock, buf, len, 0); + + if (ans == 'y') + { + strcpy(cutmp->mateid, up->userid); +#ifdef HAVE_MULTI_BYTE + page_requestor_zhc = up->ufo & UFO_ZHC; +#endif + + talk_speak(sock); + } + } + + close(sock); +#ifdef LOG_TALK + if (ans == 'y') /* mat.991011: ¨¾¤îTalk³Q©Úµ´®É¡A²£¥Í²á¤Ñ°O¿ýªºrecord */ + talk_save(); /* lkchu.981201: talk °O¿ý³B²z */ +#endif + vs_restore(sl); + utmp_mode(mode); +} diff --git a/maple/ulist.c b/maple/ulist.c new file mode 100644 index 0000000..c55fd19 --- /dev/null +++ b/maple/ulist.c @@ -0,0 +1,1243 @@ +/*-------------------------------------------------------*/ +/* ulist.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : ulist routines */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +extern UCACHE *ushm; +extern XZ xz[]; + + +/*-------------------------------------------------------*/ +/* ¿ï³æ¦¡²á¤Ñ¤¶± */ +/*-------------------------------------------------------*/ + + +static int pickup_ship = 0; /* 0:¬G¶m !=0:¤Í½Ë±Ôz */ + +typedef UTMP *pickup; + +/* ¦¹¶¶§Ç§Y¬°±Æ§Çªº¶¶§Ç */ + +#define FTYPE_SELF 0x01 +#define FTYPE_BOTHGOOD 0x02 +#define FTYPE_MYGOOD 0x04 +#define FTYPE_OGOOD 0x08 +#define FTYPE_NORMAL 0x10 +#define FTYPE_MYBAD 0x20 + + +static int mygood_num; /* ¹ï¤è³]§Ú¬°¦n¤Í */ +static int ogood_num; /* §Ú³]¹ï¤è¬°¦n¤Í */ +static int brdmate_num; /* ¹ï¤è»P§Ú¬OªO¦ñ */ + +static pickup ulist_pool[MAXACTIVE]; +/* static */ int ulist_userno[MAXACTIVE]; /* ¹ïÀ³ ushm ¤¤¦UÄæªº userno */ +static int ulist_ftype[MAXACTIVE]; /* ¹ïÀ³ ushm ¤¤¦UÄæªºªB¤ÍºØÃþ */ + +static int ulist_init(); +static int ulist_head(); +static XO ulist_xo; + + +#if 0 +static char * +pal_ship(ftype, userno) /* itoc.020811: ¶Ç¦^ªB¤Í±Ôz */ + int ftype, userno; +{ + int fd; + PAL *pal; + char fpath[64]; + static char palship[46]; + + if (ftype & (FTYPE_BOTHGOOD | FTYPE_MYGOOD | FTYPE_MYBAD)) /* ¤¬³]¦n¤Í¡B§Úªº¦n¤Í¡BÃa¤H¤~¦³¤Í½Ë±Ôz */ + { + usr_fpath(fpath, cuser.userid, fn_pal); + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + mgets(-1); + while (pal = mread(fd, sizeof(PAL))) + { + if (userno == pal->userno) + { + strcpy(palship, pal->ship); + close(fd); + return palship; + } + } + close(fd); + } + } + return ""; +} +#endif + + +#if 1 /* itoc.020901: ¥Î cache ÁöµM¤ñ¸û¦n¡A¦ý¬OÆZ®ö¶O°O¾ÐÅ骺 */ +typedef struct +{ + int userno; + char ship[20]; /* ¤£»Ýn©M PAL.ship ¤@¼Ë¤j¡A¥un°÷ ulist_body() Åã¥Ü§Y¥i */ +} PALSHIP; + + +static char * +pal_ship(ftype, userno) /* itoc.020811: ¶Ç¦^ªB¤Í±Ôz */ + int ftype, userno; +{ + static PALSHIP palship[PAL_MAX] = {0}; + PALSHIP *pp; + + /* itoc.020901: §â palship ¦¬¶i°O¾ÐÅé¡A¤£n¤@ª½ I/O ¤F */ + if (!palship[0].userno) /* initialize *palship[] */ + { + int fd; + char fpath[64]; + PAL *pal; + + /* ¬°¨D®Ä²v¡A¨C¦¸¤W¯¸¶È°µ¤@¦¸¡A¬GY§ïÅܪB¤Í±Ôz¡An«·s¤W¯¸¤~¥Í®Ä */ + usr_fpath(fpath, cuser.userid, fn_pal); + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + pp = palship; + mgets(-1); + while (pal = mread(fd, sizeof(PAL))) + { + if (pal->ship[0]) /* ¦³¤Í½Ë¤~¦¬¤J palship[] */ + { + pp->userno = pal->userno; + str_ncpy(pp->ship, pal->ship, sizeof(pp->ship)); + pp++; + } + } + close(fd); + } + } + + if (ftype & (FTYPE_BOTHGOOD | FTYPE_MYGOOD | FTYPE_MYBAD)) /* ¤¬³]¦n¤Í¡B§Úªº¦n¤Í¡BÃa¤H¤~¦³¤Í½Ë±Ôz */ + { + /* ¸g pal_sync ¥H«áªºªB¤Í¦W³æ¬O¨Ì ID ±Æ§Çªº¡A¦Ò¼{¬O§_¥Î binary search? */ + pp = palship; + while (pp->userno) + { + if (pp->userno == userno) + return pp->ship; + pp++; + } + } + return ""; +} +#endif + +static int /* qazq.030719: ¨Ï¥ÎªÌ¿ï³æ¥i¥Hª½±µ¶¢¸m */ +ulist_lock(xo) + XO *xo; +{ + utmp_mode(M_IDLE); + u_lock(); + return ulist_init(xo); +} + +static void +ulist_item(num, up, slot, now, sysop) + int num; + UTMP *up; + int slot; + time_t now; + int sysop; +{ + time_t diff, ftype; + int userno, ufo; + char pager, buf[30], *fcolor; + + if (!(userno = up->userno)) + { + outs(" < ¦¹¦ìºô¤Í¥¿¥©Â÷¶} >\n"); + return; + } + + /* itoc.011022: Y¥Í¤é·í¤Ñ¤W¯¸¡AɥΠidle Äæ¦ì¨Ó©ñ¹Ø¬P */ + if (up->status & STATUS_BIRTHDAY) + { + strcpy(buf, "\033[1;31m Ã~µV\033[m"); + } + else + { + /* duck.050729: ¦Ñ¤H¼Ð°O.. */ + if (up->userlevel & PERM_ROBOT) + strcpy (buf, "\033[1;34m ¾÷¾¹\033[m"); + else + if (up->userlevel & PERM_ELDER) + strcpy (buf, "\033[32m ¦Ñ¤H\033[m"); + else + if (up->userlevel & PERM_ALLADMIN) + strcpy (buf, "\033[1;33m ¤u¤Í\033[m"); + else + +#ifdef DETAIL_IDLETIME + if ((diff = now - up->idle_time) >= 60) /* ¶W¹L 60 ¬í¤~ºâ¶¢¸m */ + sprintf(buf, "%3d'%02d", diff / 60, diff % 60); +#else + if (diff = up->idle_time) + sprintf(buf, "%2d", diff); +#endif + else + buf[0] = '\0'; + } + + ufo = up->ufo; + + /* pager ª¬ºA */ + /* #¡G¤£±µ¨ü¥ô¦ó¤H©I¥s¡A¤]¤£±µ¨ü¥ô¦ó¤H¼s¼½ */ + /* *¡G¥u±µ¨ü¦n¤Í©I¥s¡A¥B¥u±µ¨ü¦n¤Í¼s¼½ */ + /* !¡G¥u±µ¨ü¦n¤Í©I¥s¡A¦ý¤£±µ¨ü¥ô¦ó¤H¼s¼½ */ + /* -¡G±µ¨ü¥ô¦ó¤H©I¥s¡A¦ý¤£±µ¨ü¥ô¦ó¤H¼s¼½ */ + /* ¡G³£¨S¦³´N¬O¨S¦³¨î°Õ */ + if (ufo & UFO_QUIET) + { + pager = '#'; + } + else if (ufo & UFO_PAGER) + { +#ifdef HAVE_NOBROAD + if (ufo & UFO_RCVER) + pager = '!'; + else +#endif + pager = '*'; + } +#ifdef HAVE_NOBROAD + else if (ufo & UFO_RCVER) + { + pager = '-'; + } +#endif + else + { + pager = ' '; + } + + ftype = ulist_ftype[slot]; + + fcolor = +#ifdef HAVE_BRDMATE +# ifdef HAVE_ANONYMOUS + up->mode == M_READA && !(currbattr & BRD_ANONYMOUS) && !strcmp(currboard, up->reading) ? COLOR_BRDMATE : +# else + up->mode == M_READA && !strcmp(currboard, up->reading) ? COLOR_BRDMATE : +# endif +#endif + ftype & FTYPE_NORMAL ? COLOR_NORMAL : + ftype & FTYPE_BOTHGOOD ? COLOR_BOTHGOOD : + ftype & FTYPE_MYGOOD ? COLOR_MYGOOD : + ftype & FTYPE_OGOOD ? COLOR_OGOOD : + ftype & FTYPE_SELF ? COLOR_SELF : + ftype & FTYPE_MYBAD ? COLOR_MYBAD : + ""; + + prints("%6d%s%c\033[m%c%s%-13s%-*.*s\033[m%-*.*s%-11.10s%s\n", +// num, ufo & UFO_CLOAK ? ')' : ' ', pager, + num, + ufo & UFO_SUPERCLOAK ? "\033[35m" : "" , + tag_char(up->pid) == '*' ? '*' : ufo & UFO_CLOAK ? ')' : ' ', + pager, + fcolor, up->userid, + (d_cols >> 1) + 21, (d_cols >> 1) + 20, up->username, + d_cols - (d_cols >> 1) + 19, d_cols - (d_cols >> 1) + 18, + pickup_ship ? pal_ship(ftype, up->userno) : +#ifdef GUEST_WHERE + (pager == ' ' || sysop || ftype & (FTYPE_SELF | FTYPE_BOTHGOOD | FTYPE_OGOOD) || !up->userlevel) ? /* ¥i¬Ý¨£ guest ªº¬G¶m */ +#else + (pager == ' ' || sysop || ftype & (FTYPE_SELF | FTYPE_BOTHGOOD | FTYPE_OGOOD)) ? /* ¹ï¤è³]§Ú¬°¦n¤Í¥i¬Ý¨£¹ï¤è¨Ó·½ */ +#endif + up->from : "*", bmode(up, 0), buf); +} + + +static int +ulist_body(xo) + XO *xo; +{ + pickup *pp; + UTMP *up; + int num, max, tail, sysop, seecloak, slot; +#ifdef HAVE_SUPERCLOAK + int seesupercloak; +#endif +#ifdef DETAIL_IDLETIME + time_t now; +#endif + + max = xo->max; + if (max <= 0) + { + if (vans("¥Ø«e¨S¦³¦n¤Í¤W¯¸¡An¬Ý¬Ý¨ä¥L¨Ï¥ÎªÌ¶Ü(Y/N)¡H[Y] ") != 'n') + { + cuser.ufo ^= UFO_PAL; + cutmp->ufo = cuser.ufo; + return ulist_init(xo); + } + return XO_QUIT; + } + + num = xo->top; + pp = &ulist_pool[num]; + tail = num + XO_TALL; + if (max > tail) + max = tail; + + sysop = HAS_PERM(PERM_ALLACCT); + seecloak = HAS_PERM(PERM_SEECLOAK); +#ifdef HAVE_SUPERCLOAK + seesupercloak = cuser.ufo & UFO_SUPERCLOAK; +#endif +#ifdef DETAIL_IDLETIME + time(&now); +#endif + + move(3, 0); + do + { + up = *pp; + slot = up - ushm->uslot; + + /* itoc.011124: ¦pªG¦b ulist_body() ¤¤µo²{ userno ¤£¦X¡Aªí¥Ü¤â¤W³o¥÷¦W³æ¹ê¦b¤Ó¤F¡A±j¢§ó·s */ + if (ulist_userno[slot] != up->userno) + return ulist_init(xo); + +#ifdef DETAIL_IDLETIME + ulist_item(++num, up, slot, now, sysop); +#else + ulist_item(++num, up, slot, NULL, sysop); +#endif + + pp++; + } while (num < max); + clrtobot(); + + /* return XO_NONE; */ + return XO_FOOT; /* itoc.010403: §â b_lines ¶ñ¤W feeter */ +} + + +static int +ulist_cmp_userid(i, j) + UTMP **i, **j; +{ + int k = ulist_ftype[(*i) - ushm->uslot] - ulist_ftype[(*j) - ushm->uslot]; + return k ? k : str_cmp((*i)->userid, (*j)->userid); +} + + +static int +ulist_cmp_host(i, j) + UTMP **i, **j; +{ + int k = ulist_ftype[(*i) - ushm->uslot] - ulist_ftype[(*j) - ushm->uslot]; + /* return k ? k : (*i)->in_addr - (*j)->in_addr; */ + /* Kyo.050112: in_addr ¬O unsigned int (u_long)¡Aª½±µ´î·|³y¦¨ int »~§P */ + return k ? k : (*i)->in_addr > (*j)->in_addr ? 1 : (*i)->in_addr < (*j)->in_addr ? -1 : 0; +} + + +static int +ulist_cmp_mode(i, j) + UTMP **i, **j; +{ + int k = ulist_ftype[(*i) - ushm->uslot] - ulist_ftype[(*j) - ushm->uslot]; + return k ? k : (*i)->mode - (*j)->mode; +} + + +#ifdef HAVE_BRDMATE +static int +ulist_cmp_brdmate(i, j) + UTMP **i, **j; +{ +#ifdef HAVE_ANONYMOUS + if (!(currbattr & BRD_ANONYMOUS) || HAS_PERM(PERM_SYSOP)) /* ¾\Ū°Î¦WªO«h¤£¦C¤J */ +#endif + { + int ibrdmate = (*i)->mode == M_READA && !strcmp(currboard, (*i)->reading); + int jbrdmate = (*j)->mode == M_READA && !strcmp(currboard, (*j)->reading); + + /* ªO¦ñÀu¥ý */ + if (ibrdmate && !jbrdmate) + return -1; + if (jbrdmate && !ibrdmate) + return 1; + } + + /* ³£¤£¬O©Î³£¬OªO¦ñªº¸Ü¡A«ö ID ±Æ§Ç */ + return ulist_cmp_userid(i, j); +} +#endif + + +#ifdef HAVE_BRDMATE +#define PICKUP_WAYS 4 +#else +#define PICKUP_WAYS 3 +#endif + +static int pickup_way = 0; /* ¹w³]±Æ¦C¤è¦¡ 0:¥N¸¹ 1:¬G¶m 2:°ÊºA 3:ªO¦ñ */ + + +static int (*ulist_cmp[PICKUP_WAYS]) () = +{ + ulist_cmp_userid, + ulist_cmp_host, + ulist_cmp_mode, +#ifdef HAVE_BRDMATE + ulist_cmp_brdmate, +#endif +}; + + +static char *msg_pickup_way[PICKUP_WAYS] = +{ + "ºô¤Í¥N¸¹", + "«È³~¬G¶m", + "ºô¤Í°ÊºA", +#ifdef HAVE_BRDMATE + "ªO¦ñ¥N¸¹", +#endif +}; + + +static int +ulist_paltype(up) /* ªB¤ÍºØÃþ */ + UTMP *up; +{ + const int userno = up->userno; + + if (userno == cuser.userno) + return FTYPE_SELF; + if (is_mybad(userno)) + return FTYPE_MYBAD; + if (is_mygood(userno)) + return is_ogood(up) ? FTYPE_BOTHGOOD : FTYPE_MYGOOD; + return is_ogood(up) ? FTYPE_OGOOD : FTYPE_NORMAL; +} + + +#if 0 /* itoc.041001: ulist_init() µù¸Ñ */ + + 1. ushm->uslot °O¿ý¥þ¯¸ªº UTMP (¨Ï¥ÎªÌ¦W³æ¸ê®Æ)¡A³o¬OÅý©Ò¦³¤H¦@¥Îªº + + 2. ¨CÓ¤H¤â¤W¡A¦U¦³¥H¤U¤T¥÷¡G + ulist_pool ¬O ushm->uslot ªº¯Á¤Þ¡A°O¿ýµÛ§Ú¥i¥H¬Ý¨ìþ¨Ç¤H + ulist_userno[i] °O¿ýµÛ ushm->uslot[i] ³o¦ì¤l§¤¤F½Ö + ulist_ftype[i] °O¿ýµÛ ushm->uslot[i] ³o¦ì¤l¬O§Úªº ¦n¤Í/Ãa¤H/¤@¯ë¤H + + 3. ¦b ulist_init() ¸Ì±¥h ushm->uslot ÂsÄý©Ò¦³¦ì¤l¡A¦Ò¼{ ushm->uslot[i] + ¦pªG§Ú¥i¥H¬Ý¨ì³oÓ¤H¡A´N§â¥¦§Û¶i¨Ó ulist_pool + Y ushm->uslot[i].userno != ulist_userno[i]¡Aªí¥Ü³oÓ¦ì¤l§¤¤F¤@Ó·s¤W¯¸ªº¤H¡A + §Ú´N¥h¬d¥L¬O¤£¬O§Úªº¦n¤Í/Ãa¤H¡A¨Ã°O¿ý¦b ulist_ftype[i]¡F + Y ushm->uslot[i].userno == ulist_userno[i]¡Aªí¥Ü³oÓ¦ì¤l¨S´«¤H¡A + §Ú´Nª½±µ®³ ulist_ftype[i] ¨Ó·í§@ªB¤ÍºØÃþ + + 4. ¦³¤F ulist_pool[] ¥H«á¡A¦A§â ulist_pool[] ¨Ì§Ú·Qnªº¤è¦¡±Æ§Ç¡A + ¦b ulist_item() ¦L¥X¨ÓªºÃC¦â«h¬O°Ñ·Ó ulist_ftype[] + + 5. Y¦³¤H±N§Ú¦b¥LªºªB¤Í¦W³æ¤¤²§°Ê¡A¨º¥L·|§ó°Ê§Úªº cutmp->status¡A + ©Ò¥H·í§ÚÀˬd¨ì HAS_STATUS(STATUS_PALDIRTY)¡A§Ú´Nn«¾ã§Úªº ulist_ftype[] + +#endif + + +static int +ulist_init(xo) + XO *xo; +{ + UTMP *up, *uceil; + pickup *pp; + int filter, slot, userno, paldirty; + + pp = ulist_pool; + filter = cuser.ufo & UFO_PAL; + if (paldirty = HAS_STATUS(STATUS_PALDIRTY)) + cutmp->status ^= STATUS_PALDIRTY; + + slot = 0; + up = ushm->uslot; + uceil = (void *) up + ushm->offset; + + mygood_num = ogood_num = brdmate_num = 0; + + /* ±q ushm->uslot[] §Û¨ì ulist_pool[] */ + do + { + userno = up->userno; + + if (userno > 0) + { + /* ·s¤W¯¸ªº¨Ï¥ÎªÌ¡A¬Ý¬Ý¥L¬Oþ¤@ÃþªºªB¤Í¡FSTATUS_PALDIRTY «¾ã ulist_ftype[] */ + if (ulist_userno[slot] != userno || paldirty) + { + ulist_userno[slot] = userno; + ulist_ftype[slot] = ulist_paltype(up); + } + + if (can_see(cutmp, up)) + { + userno = ulist_ftype[slot]; + if (!filter || userno & (FTYPE_SELF | FTYPE_BOTHGOOD | FTYPE_MYGOOD)) + *pp++ = up; + + /* ºâ¦³´XÓ¦n¤Í */ + if (userno & (FTYPE_BOTHGOOD | FTYPE_MYGOOD)) + mygood_num++; + if (userno & (FTYPE_BOTHGOOD | FTYPE_OGOOD)) + ogood_num++; + /* ºâ¦³´XÓªO¦ñ */ +#ifdef HAVE_ANONYMOUS + if (up->mode == M_READA && !(currbattr & BRD_ANONYMOUS) && + !strcmp(currboard, up->reading)) +#else + if (up->mode == M_READA && !strcmp(currboard, up->reading)) +#endif + brdmate_num++; + } + } + slot++; + } while (++up <= uceil); + + xo->max = slot = pp - ulist_pool; + + if (xo->pos >= slot) + xo->pos = xo->top = 0; + + if (slot > 1) + qsort(ulist_pool, slot, sizeof(pickup), ulist_cmp[pickup_way]); + + /* itoc.010928: ¥Ñ©ó ushm->count ±`¤£¹ï¡A©Ò¥H¥Î total_user ¨Ó®Õ¥¿¡A + è¤W¯¸®É´N±Ò©l¤Æ total_user ¬° ushm->count¡A¦¹«áY¨Ï¥ÎªÌ¨S¦³¨Ó¨Ï¥ÎªÌ¦W³æ¡A´N¤£§ó·s total_user */ + if (!filter) + total_user = slot; + + return ulist_head(xo); +} + + +static int +ulist_neck(xo) + XO *xo; +{ + move(1, 0); + + prints(" ±Æ¦C¤è¦¡¡G[\033[1m%s/%s\033[m] ¯¸¤W¤H¼Æ¡G%d " + COLOR_MYGOOD " §Úªº¦n¤Í¡G%d " COLOR_OGOOD " »P§Ú¬°¤Í¡G%d\033[m" + COLOR_BRDMATE " ªO¦ñ¡G%d\033[m", + msg_pickup_way[pickup_way], + cuser.ufo & UFO_PAL ? "¦n¤Í" : "¥þ³¡", + total_user, mygood_num, ogood_num, brdmate_num); + + prints(NECKER_ULIST, d_cols >> 1, "", d_cols - (d_cols >> 1) + 4, pickup_ship ? "¤Í½Ë" : "¬G¶m"); + return ulist_body(xo); +} + + +static int +ulist_head(xo) + XO *xo; +{ + vs_head("ºô¤Í¦Cªí", str_site); + return ulist_neck(xo); +} + + +static int +ulist_toggle(xo) + XO *xo; +{ + int ans, max; + +#ifdef HAVE_BRDMATE + ans = vans("±Æ¦C¤è¦¡ [1]¥N¸¹ [2]¨Ó·½ [3]°ÊºA [4]ªO¦ñ ") - '1'; +#else + ans = vans("±Æ¦C¤è¦¡ [1]¥N¸¹ [2]¨Ó·½ [3]°ÊºA ") - '1'; +#endif + if (ans >= 0 && ans < PICKUP_WAYS && ans != pickup_way) /* Thor.980705: from 0 .. PICKUP_WAYS-1 */ + { + pickup_way = ans; + max = xo->max; + + if (max > 1) + { + qsort(ulist_pool, max, sizeof(pickup), ulist_cmp[pickup_way]); + return ulist_neck(xo); + } + } + + return XO_FOOT; +} + + +static int +ulist_pal(xo) + XO *xo; +{ + cuser.ufo ^= UFO_PAL; + cutmp->ufo = cuser.ufo; + return ulist_init(xo); +} + + +static int +ulist_search(xo, step) + XO *xo; + int step; +{ + int num, pos, max; + pickup *pp; + char buf[IDLEN + 1]; + + + if (vget(b_lines, 0, "½Ð¿é¤J¥N¸¹©Î¼ÊºÙ¡G", buf, IDLEN + 1, DOECHO)) + { + str_lowest(buf, buf); + + pos = num = xo->pos; + max = xo->max; + pp = ulist_pool; + do + { + pos += step; + if (pos < 0) /* Thor.990124: °²³] max ¤£¬°0 */ + pos = max - 1; + else if (pos >= max) + pos = 0; + + if (str_str(pp[pos]->userid, buf) || /* lkchu.990127: §ä³¡¥÷ id ¦n¹³¤ñ¸û¦n¥Î :p */ + str_sub(pp[pos]->username, buf)) /* Thor.990124: ¥i¥H§ä ³¡¤À nickname */ + { + outf(FEETER_ULIST); /* itoc.010913: §â b_lines ¶ñ¤W feeter */ + return pos + XO_MOVE; + } + + } while (pos != num); + } + + return XO_FOOT; +} + + +static int +ulist_search_forward(xo) + XO *xo; +{ + return ulist_search(xo, 1); /* step = +1 */ +} + + +static int +ulist_search_backward(xo) + XO *xo; +{ + return ulist_search(xo, -1); /* step = -1 */ +} + + +static int +ulist_addpal(xo) + XO *xo; +{ + if (cuser.userlevel) + { + UTMP *up; + int userno; + + up = ulist_pool[xo->pos]; + userno = up->userno; + if (userno > 0 && (userno != cuser.userno) && /* lkchu.981217: ¦Û¤v¤£¥i¬°ªB¤Í */ + !is_mygood(userno) && !is_mybad(userno)) /* ©|¥¼¦C¤JªB¤Í¦W³æ */ + { + PAL pal; + char fpath[64]; + + pal_edit(PALTYPE_PAL, &pal, DOECHO); + pal.userno = userno; + strcpy(pal.userid, up->userid); + usr_fpath(fpath, cuser.userid, fn_pal); + + /* itoc.001222: ÀˬdªB¤ÍÓ¼Æ */ + if (rec_num(fpath, sizeof(PAL)) < PAL_MAX) + { + rec_add(fpath, &pal, sizeof(PAL)); + pal_cache(); /* ªB¤Í¦W³æ¦P¨B */ + utmp_admset(userno, STATUS_PALDIRTY); + return ulist_init(xo); + } + else + { + vmsg("±zªºªB¤Í¦W³æ¤Ó¦h¡A½Ðµ½¥[¾ã²z"); + return XO_FOOT; + } + } + } + return XO_NONE; +} + + +static int +cmppal(pal) + PAL *pal; +{ + return pal->userno == currchrono; +} + + +static int +ulist_delpal(xo) + XO *xo; +{ + if (cuser.userlevel) + { + UTMP *up; + int userno; + + up = ulist_pool[xo->pos]; + userno = up->userno; + if (userno > 0 && (is_mygood(userno) || is_mybad(userno))) /* ¦bªB¤Í¦W³æ¤¤ */ + { + if (vans(msg_del_ny) == 'y') + { + char fpath[64]; + + usr_fpath(fpath, cuser.userid, fn_pal); + + currchrono = userno; + if (!rec_del(fpath, sizeof(PAL), 0, cmppal)) + { + pal_cache(); /* ªB¤Í¦W³æ¦P¨B */ + utmp_admset(userno, STATUS_PALDIRTY); + return ulist_init(xo); + } + } + return XO_FOOT; + } + } + return XO_NONE; +} + + +static int +ulist_mail(xo) + XO *xo; +{ + char userid[IDLEN + 1]; + + /* ¥ý½Æ»s¤@¥÷¨ì¤â¤W¡A¥H§K¦b¼g«H®É ushm ÅܰʤF */ + strcpy(userid, ulist_pool[xo->pos]->userid); + + if (!*userid) + { + vmsg(MSG_USR_LEFT); + return XO_FOOT; + } + + return my_send(userid); +} + + +static int +ulist_query(xo) + XO *xo; +{ + move(1, 0); + clrtobot(); + char *userid,*realid; + char buf[80]; + int userno; + userid=ulist_pool[xo->pos]->userid; + realid=ulist_pool[xo->pos]->realid; + userno=ulist_pool[xo->pos]->userno; + if(strcmp(userid,realid)){ + if(HAS_PERM(PERM_ALLADMIN) || cuser.userno == userno){ + sprintf(buf,"§ïID Åv¡G%s ¡÷ %s",realid,userid); + vmsg(buf); + move(1, 0); + my_query(realid); + }else{ + vmsg("³o¦ì¨Ï¥ÎªÌ¨Ï¥Î¤F§ï ID Åv¡A¦ý±z¨S¦³ÅvÀ˵øì©l ID"); + } + }else{ + my_query(userid); + } + return ulist_neck(xo); +} + + +static int +ulist_broadcast(xo) + XO *xo; +{ + int num, sysop; + pickup *pp; + UTMP *up; + BMW bmw; + + num = cuser.userlevel; + sysop = num & PERM_CAST; + if (!sysop && (!(num & PERM_PAGE) || !(cuser.ufo & UFO_PAL))) + return XO_NONE; + + num = xo->max; + if (num <= 1) /* ¦pªG¥u¦³¦Û¤v¡A¤£¯à¼s¼½ */ + return XO_NONE; + + /* itoc.030101: ¦pªG¯¸ªø¥Îªº¬O¦n¤Í¼s¼½¡Aµø¦P¤@¯ë ID ¼s¼½ */ + sysop = sysop && !(cuser.ufo & UFO_PAL); + + bmw.caller = NULL; + bmw_edit(NULL, "¡¹¼s¼½¡G", &bmw); + + if (bmw.caller) /* bmw_edit() ¤¤¦^µª Yes n°e¥X¼s¼½ */ + { + /* itoc.000213: ¥[ "> " ¬°¤F»P¤@¯ë¤ô²y°Ï¤À */ + sprintf(bmw.userid, "%s> ", cuser.userid); + + pp = ulist_pool; + while (--num >= 0) + { + up = pp[num]; + + if (!sysop) + { +#ifdef HAVE_NOBROAD + if (up->ufo & UFO_RCVER) + continue; +#endif + + /* itoc.011126: Y up-> ¤w¤U¯¸¡A³Q¨ä¥L user ©Ò¨ú¥N®É¡A + ·|¦³¼s¼½»~´Óªº°ÝÃD¡A±o«·sÀˬd¬O§_¬°§Úªº¦n¤Í */ + if (!is_mygood(up->userno)) + continue; + } + + if (can_override(up)) + { + bmw.recver = up->userno; + bmw_send(up, &bmw); + } + } + } + + return XO_NONE; +} + +static int +ulist_widecast(xo) + XO *xo; +{ + int tag, locus, pos; + BMW benz; + UTMP *up; + extern TagItem TagList[]; + + if (!HAS_PERM(PERM_PAGE)) + return XO_NONE; + + tag = AskTag("¯S©w¹ï¶H¼s¼½"); + + if (tag < 0) + return XO_FOOT; + + if (!tag) /* ¦n¤Í¼s¼½©Î¯¸ªø¥þ¯¸¼s¼½ */ + return ulist_broadcast(xo); + + benz.caller = NULL; + bmw_edit(NULL, "¡¹¼s¼½¡G", &benz); + if (!benz.caller) /* bmw_edit() ¤¤¦^µª No ¤£°e¥X¼s¼½ */ + return XO_FOOT; + + /* itoc.000213: ¥[ "> " ¬°¤F»P¤@¯ë¤ô²y°Ï¤À */ + sprintf(benz.userid, "%s> ", cuser.userid); + + locus = 0; + + do + { + pos = TagList[locus].recno; + up = ulist_pool[pos]; + if (up->pid != TagList[locus].chrono) /* ¸Ó¦ì¤l´«¤H¤F */ + continue; + +#ifdef HAVE_NOBROAD + if (up->ufo & UFO_RCVER) + continue; +#endif + + if (can_override(up)) + { + benz.recver = up->userno; + bmw_send(up, &benz); + } + } while (++locus < tag); + + return XO_FOOT; +} + + +static int +ulist_talk(xo) + XO *xo; +{ + if (HAS_PERM(PERM_PAGE)) + { + UTMP *up; + + up = ulist_pool[xo->pos]; + if (can_override(up)) + return talk_page(up) ? ulist_head(xo) : XO_FOOT; + } + return XO_NONE; +} + + +static int +ulist_write(xo) + XO *xo; +{ + if (HAS_PERM(PERM_PAGE)) + { + UTMP *up; + + if (up = ulist_pool[xo->pos]) + do_write(up); + } + return XO_NONE; +} + + +static int +ulist_edit(xo) /* Thor: ¥i½u¤W¬d¬Ý¤Î×§ï¨Ï¥ÎªÌ */ + XO *xo; +{ + ACCT acct; + char* userid=ulist_pool[xo->pos]->userid; + char* realid=ulist_pool[xo->pos]->realid; + char buf[80]; + if(strcmp(userid,realid)){ + sprintf(buf,"§ïID Åv¡G%s ¡÷ %s",realid,userid); + vmsg(buf); + } + + if (!HAS_PERM(PERM_ALLACCT) || acct_load(&acct, ulist_pool[xo->pos]->realid) < 0) + return XO_NONE; + + vs_bar("¨Ï¥ÎªÌ³]©w"); + acct_setup(&acct, 1); + return ulist_head(xo); +} + + +static int +ulist_kick(xo) + XO *xo; +{ + if (HAS_PERM(PERM_ALLACCT) || (HAS_PERM(PERM_ALLADMIN) && ulist_pool[xo->pos]->userno == cuser.userno )) + { + UTMP *up; + pid_t pid; + char buf[80]; + + up = ulist_pool[xo->pos]; + if (pid = up->pid) + { + if (vans(msg_sure_ny) != 'y' || pid != up->pid) + return XO_FOOT; + + sprintf(buf, "%s (%s)", up->userid, up->username); + + if ((kill(pid, SIGTERM) == -1) && (errno == ESRCH)) + utmp_free(up); + else + sleep(3); /* ³Q½ðªº¤H³o®ÉÔ¥¿¦b¦Û§Ú¤FÂ_ */ + + blog("KICK", buf); + alog("±j¨îÂ÷½u",up->userid); + return ulist_init(xo); + } + } + return XO_NONE; +} + + +#ifdef HAVE_CHANGE_NICK +static int +ulist_nickchange(xo) + XO *xo; +{ + char *str, buf[UNLEN + 1]; + + if (!cuser.userlevel) + return XO_NONE; + + strcpy(buf, str = cutmp->username); + if (vget(b_lines, 0, "½Ð¿é¤J·sªº¼ÊºÙ¡G", buf, UNLEN + 1, GCARRY)) + { + if (strcmp(buf, str)) + { + strcpy(str, buf); + strcpy(cuser.username, buf); /* ¼ÊºÙ¤]¤@¨Ö§ó´« cuser. */ + return ulist_body(xo); + } + } + return XO_FOOT; +} +#endif + + + +#ifdef HAVE_CHANGE_FROM +static int +ulist_fromchange(xo) + XO *xo; +{ + char *str, buf[34]; + + if (!cuser.userlevel) + return XO_NONE; + + strcpy(buf, str = cutmp->from); + if (vget(b_lines, 0, "½Ð¿é¤J·sªº¬G¶m¡G", buf, sizeof(cutmp->from), GCARRY)) + { + if (strcmp(buf, str)) + { + strcpy(str, buf); + return ulist_body(xo); + } + } + + return XO_FOOT; +} +#endif + +#ifdef HAVE_CHANGE_ID +static int +ulist_idchange(xo) + XO *xo; +{ + char *str, buf[IDLEN + 1]; + + /* itoc.010717.µù¸Ñ: ³o¥\¯à´£¨Ñ¯¸ªø¥i¥H¦b¨Ï¥ÎªÌ¦W³æ¼È®É§ï¦Û¤vªº ID¡A + ¦ý¬O¥Ñ©ó ulist ¤j³¡¤À¬O¥Î userno ¨Ó§PÂ_¡A©Ò¥H¥u¦³¦n¬Ý¦Ó¤w */ + + if (!HAS_PERM(PERM_ALLADMIN) && !HAS_PERM(PERM_CHANGEID)) + return XO_NONE; + + strcpy(buf, str = cutmp->userid); + if (vget(b_lines, 0, "½Ð¿é¤J·sªº¢×¢Ò¡G", buf, IDLEN + 1 , GCARRY)) + { + if (strcmp(buf, str)) + { + if (!HAS_PERM(PERM_ALLADMIN)) + { + if (!strcmp(buf,cuser.userid)) + strcpy(buf,cuser.userid); + else + strcat(buf,","); + } + + strcpy (str, buf); + return ulist_body(xo); + } + } + + return XO_FOOT; +} +#endif + + +static int +ulist_cloak(xo) /* itoc.010908: §Ö³tÁô¨ */ + XO *xo; +{ + if (HAS_PERM(PERM_CLOAK)) + { + cuser.ufo ^= UFO_CLOAK; + cutmp->ufo = cuser.ufo; + return ulist_init(xo); + } + return XO_NONE; +} + + +#ifdef HAVE_SUPERCLOAK +static int +ulist_supercloak(xo) /* itoc.010908: §Ö³tµµÁô */ + XO *xo; +{ + if (cuser.ufo & UFO_SUPERCLOAK) /* ¨ú®øµµÁô¡A¤£¥²ºÞÅv */ + { + cuser.ufo &= ~(UFO_CLOAK | UFO_SUPERCLOAK); + cutmp->ufo = cuser.ufo; + return ulist_init(xo); + } + else if (HAS_PERM(PERM_ALLADMIN)) /* ¶i¤JµµÁô */ + { + cuser.ufo |= (UFO_CLOAK | UFO_SUPERCLOAK); + cutmp->ufo = cuser.ufo; + return ulist_init(xo); + } + return XO_NONE; +} +#endif + + +static int +ulist_ship(xo) + XO *xo; +{ + pickup_ship = ~pickup_ship; + return ulist_neck(xo); +} + + +static int +ulist_recall(xo) + XO *xo; +{ + if (cuser.userlevel) + { + t_bmw(); + return ulist_head(xo); + } + return XO_NONE; +} + + +static int +ulist_display(xo) + XO *xo; +{ + if (cuser.userlevel) + { + t_display(); + return ulist_head(xo); + } + return XO_NONE; +} + + +static int +ulist_tag(xo) + XO *xo; +{ + UTMP *up; + int tag, pos, cur; + + pos = xo->pos; + cur = pos - xo->top; + up = ulist_pool[pos]; + + if (!up->pid) + return XO_NONE; + + if (tag = Tagger(up->pid, pos, TAG_TOGGLE)) + { + move(3 + cur, 6); + if(up->ufo & UFO_SUPERCLOAK) outs("\033[35m"); + outc(tag > 0 ? '*' : up->ufo & UFO_CLOAK ? ')' : ' '); + if(up->ufo & UFO_SUPERCLOAK) outs("\033[m"); + } + + /* return XO_NONE; */ + return xo->pos + 1 + XO_MOVE; /* lkchu.981201: ¸õ¦Ü¤U¤@¶µ */ +} + +static int +ulist_help(xo) + XO *xo; +{ +#if 1 /* ¯¸ªø´c·d :p */ + if (HAS_PERM(PERM_ROBOT)) + { + char ans[20]; + if (vget(b_lines, 0, "nµ¹¥L´XÓ¤ô²y¡H", ans, 10, DOECHO)) + { + ulist_pool[xo->pos]->bmw_count = atoi(ans); + return ulist_body(xo); + } + } +#endif + xo_help("ulist"); + return ulist_head(xo); +} + + +static KeyFunc ulist_cb[] = +{ + XO_INIT, ulist_init, + XO_LOAD, ulist_body, + XO_HEAD, ulist_head, + /* XO_BODY, ulist_body, */ /* ¨S¦³¥Î¨ì */ + + 'f', ulist_pal, + 'y', ulist_pal, /* itoc.010205: ¦³¤H·|§â yank ªº·N«ä¥Î¦b³o */ + 'a', ulist_addpal, + 'd', ulist_delpal, + 'T', ulist_talk, + 'w', ulist_write, + 'l', ulist_recall, /* ¤ô²y¦^ÅU */ + 'L', ulist_display, + 'r', ulist_query, + 'q', ulist_query, /* itoc.020109: ¨Ï¥ÎªÌ²ßºD¥Î q ¬d¸ß */ +// 'B', ulist_broadcast, + 'B', ulist_widecast, + 's', ulist_init, /* refresh status Thor: À³usern¨D */ + 'S', ulist_ship, + 'I', ulist_lock, /* qazq.030719: ¨Ï¥ÎªÌ¿ï³æª½±µ¶¢¸m */ + Ctrl('K'), ulist_kick, + Ctrl('O'), ulist_edit, + Ctrl('Q'), ulist_query, + +#ifdef HAVE_CHANGE_NICK + Ctrl('N'), ulist_nickchange, +#endif +#ifdef HAVE_CHANGE_FROM + Ctrl('F'), ulist_fromchange, +#endif +#ifdef HAVE_CHANGE_ID + Ctrl('D'), ulist_idchange, +#endif + +#if 0 + '/', ulist_search, +#endif + /* Thor.990125: ¥i«e«á·j´M, id or nickname */ + '/', ulist_search_forward, + '?', ulist_search_backward, + + 'm', ulist_mail, + KEY_TAB, ulist_toggle, + + 'i', ulist_cloak, +#ifdef HAVE_SUPERCLOAK + 'H', ulist_supercloak, +#endif + 't', ulist_tag, + 'h', ulist_help +}; + + +void +talk_main() +{ + char fpath[64]; + + xz[XZ_ULIST - XO_ZONE].xo = &ulist_xo; + xz[XZ_ULIST - XO_ZONE].cb = ulist_cb; + + /* itoc.010715: ¥Ñ©ó erevy_Z ¥i¥Hª½±µ¶i¤J bmw¡A©Ò¥H¤@¤W¯¸´Nn¸ü¤J */ + usr_fpath(fpath, cuser.userid, fn_bmw); + xz[XZ_BMW - XO_ZONE].xo = xo_new(fpath); +} diff --git a/maple/user.c b/maple/user.c new file mode 100644 index 0000000..4695911 --- /dev/null +++ b/maple/user.c @@ -0,0 +1,834 @@ +/*-------------------------------------------------------*/ +/* user.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : account / user routines */ +/* create : 95/03/29 */ +/* update : 96/04/05 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +extern char *ufo_tbl[]; + + +/* ----------------------------------------------------- */ +/* »{ÃҥΨ禡 */ +/* ----------------------------------------------------- */ + + +void +justify_log(userid, justify) /* itoc.010822: ®³±¼ .ACCT ¤¤ justify ³oÄæ¦ì¡A§ï°O¿ý¦b FN_JUSTIFY */ + char *userid; + char *justify; /* »{ÃÒ¸ê®Æ RPY:email-reply KEY:»{ÃÒ½X POP:pop3»{ÃÒ REG:µù¥U³æ */ +{ + char fpath[64]; + FILE *fp; + + usr_fpath(fpath, userid, FN_JUSTIFY); + if (fp = fopen(fpath, "a")) /* ¥Îªþ¥[ÀɮסA¥i¥H«O¦s¾ú¦¸»{ÃÒ°O¿ý */ + { + fprintf(fp, "%s\n", justify); + fclose(fp); + } +} + + +static int +ban_addr(addr) + char *addr; +{ + char *host; + char foo[128]; /* SoC: ©ñ¸m«ÝÀˬdªº email address */ + + /* Thor.991112: °O¿ý¥Î¨Ó»{ÃÒªºemail */ + sprintf(foo, "%s # %s (%s)\n", addr, cuser.userid, Now()); + f_cat(FN_RUN_EMAILREG, foo); + + /* SoC: «O«ùì email ªº¤j¤p¼g */ + str_lower(foo, addr); + + /* check for acl (lower case filter) */ + + host = (char *) strchr(foo, '@'); + *host = '\0'; + + /* *.bbs@xx.yy.zz¡B*.brd@xx.yy.zz ¤@«ß¤£±µ¨ü */ + if (host > foo + 4 && (!str_cmp(host - 4, ".bbs") || !str_cmp(host - 4, ".brd"))) + return 1; + + /* ¤£¦b¥Õ¦W³æ¤W©Î¦b¶Â¦W³æ¤W */ + return (!acl_has(TRUST_ACLFILE, foo, host + 1) || + acl_has(UNTRUST_ACLFILE, foo, host + 1) > 0); +} + + +/* ----------------------------------------------------- */ +/* POP3 »{ÃÒ */ +/* ----------------------------------------------------- */ + + +#ifdef HAVE_POP3_CHECK + +static int /* >=0:socket -1:³s½u¥¢±Ñ */ +Get_Socket(site) /* site for hostname */ + char *site; +{ + int sock; + struct sockaddr_in sin; + struct hostent *host; + + sock = 110; + + /* Getting remote-site data */ + + memset((char *) &sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(sock); + + if (!(host = gethostbyname(site))) + sin.sin_addr.s_addr = inet_addr(site); + else + memcpy(&sin.sin_addr.s_addr, host->h_addr, host->h_length); + + /* Getting a socket */ + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + return -1; + } + + /* perform connecting */ + + if (connect(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) + { + close(sock); + return -1; + } + + return sock; +} + + +static int /* 0:¦¨¥\ */ +POP3_Check(sock, account, passwd) + int sock; + char *account, *passwd; +{ + FILE *fsock; + char buf[512]; + + if (!(fsock = fdopen(sock, "r+"))) + { + outs("\n¶Ç¦^¿ù»~È¡A½Ð«¸Õ´X¦¸¬Ý¬Ý\n"); + return -1; + } + + sock = 1; + + while (1) + { + switch (sock) + { + case 1: /* Welcome Message */ + fgets(buf, sizeof(buf), fsock); + break; + + case 2: /* Verify Account */ + fprintf(fsock, "user %s\r\n", account); + fflush(fsock); + fgets(buf, sizeof(buf), fsock); + break; + + case 3: /* Verify Password */ + fprintf(fsock, "pass %s\r\n", passwd); + fflush(fsock); + fgets(buf, sizeof(buf), fsock); + sock = -1; + break; + + default: /* 0:Successful 4:Failure */ + fprintf(fsock, "quit\r\n"); + fclose(fsock); + return sock; + } + + if (!strncmp(buf, "+OK", 3)) + { + sock++; + } + else + { + outs("\n»·ºÝ¨t²Î¶Ç¦^¿ù»~°T®§¦p¤U¡G\n"); + prints("%s\n", buf); + sock = -1; + } + } +} + + +static int /* -1:¤£¤ä´© 0:±K½X¿ù»~ 1:¦¨¥\ */ +do_pop3(addr) /* itoc.010821: §ï¼g¤@¤U :) */ + char *addr; +{ + int sock, i; + char *ptr, *str, buf[80], username[80]; + char *alias[] = {"", "pop3.", "mail.", NULL}; + ACCT acct; + + strcpy(username, addr); + *(ptr = strchr(username, '@')) = '\0'; + ptr++; + + clear(); + move(2, 0); + prints("¥D¾÷: %s\n±b¸¹: %s\n", ptr, username); + outs("\033[1;5;36m³s½u»·ºÝ¥D¾÷¤¤...½ÐµyÔ\033[m\n"); + refresh(); + + for (i = 0; str = alias[i]; i++) + { + sprintf(buf, "%s%s", str, ptr); /* itoc.020120: ¥D¾÷¦WºÙ¥[¤W pop3. ¸Õ¸Õ¬Ý */ + if ((sock = Get_Socket(buf)) >= 0) /* §ä¨ì³o¾÷¾¹¥B¹ï¤è¤ä´© POP3 */ + break; + } + + if (sock < 0) + { + outs("±zªº¹q¤l¶l¥ó¨t²Î¤£¤ä´© POP3 »{ÃÒ¡A¨Ï¥Î»{ÃÒ«H¨ç¨¤À½T»{\n\n\033[1;36;5m¨t²Î°e«H¤¤...\033[m"); + return -1; + } + + if (vget(15, 0, "½Ð¿é¤J¥H¤W©Ò¦C¥X¤§¤u§@¯¸±b¸¹ªº±K½X¡G", buf, 20, NOECHO)) + { + move(17, 0); + outs("\033[5;37m¨¤À½T»{¤¤...½ÐµyÔ\033[m\n"); + + if (!POP3_Check(sock, username, buf)) /* POP3 »{ÃÒ¦¨¥\ */ + { + /* ´£¤ÉÅv */ + sprintf(buf, "POP: %s", addr); + justify_log(cuser.userid, buf); + strcpy(cuser.email, addr); + if (acct_load(&acct, cuser.userid) >= 0) + { + time(&acct.tvalid); + acct_setperm(&acct, PERM_VALID, 0); + } + + /* ±H«H³qª¾¨Ï¥ÎªÌ */ + mail_self(FN_ETC_JUSTIFIED, str_sysop, msg_reg_valid, 0); + cutmp->status |= STATUS_BIFF; + vmsg(msg_reg_valid); + + close(sock); + return 1; + } + } + + close(sock); + + /* POP3 »{ÃÒ¥¢±Ñ */ + outs("±zªº±K½X©Î³\\¥´¿ù¤F¡A¨Ï¥Î»{ÃÒ«H¨ç¨¤À½T»{\n\n\033[1;36;5m¨t²Î°e«H¤¤...\033[m"); + return 0; +} +#endif + + +/* ----------------------------------------------------- */ +/* ³]©w E-mail address */ +/* ----------------------------------------------------- */ + + +int +u_addr() +{ + char *msg, addr[64]; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + /* itoc.050405: ¤£¯àÅý°±ÅvªÌ«·s»{ÃÒ¡A¦]¬°·|§ï±¼¥Lªº tvalid (°±Åv¨ì´Á®É¶¡) */ + if (HAS_PERM(PERM_ALLDENY)) + { + vmsg("±z³Q°±Åv¡AµLªk§ï«H½c"); + return XEASY; + } + + film_out(FILM_EMAIL, 0); + + if (vget(b_lines - 2, 0, "E-mail ¦a§}¡G", addr, sizeof(cuser.email), DOECHO)) + { + if (not_addr(addr)) + { + msg = err_email; + } + else if (ban_addr(addr)) + { + msg = "¥»¯¸¤£±µ¨ü±zªº«H½c°µ¬°»{ÃÒ¦a§}"; + } + else + { +#ifdef EMAIL_JUSTIFY + if (vans("×§ï E-mail n«·s»{ÃÒ¡A½T©wn×§ï¶Ü(Y/N)¡H[Y] ") == 'n') + return 0; + +# ifdef HAVE_POP3_CHECK + if (vans("¬O§_¨Ï¥Î POP3 »{ÃÒ(Y/N)¡H[N] ") == 'y') + { + if (do_pop3(addr) > 0) /* Y POP3 »{ÃÒ¦¨¥\¡A«hÂ÷¶}¡A§_«h¥H»{ÃÒ«H±H¥X */ + return 0; + } +# endif + + if (bsmtp(NULL, NULL, addr, MQ_JUSTIFY) < 0) + { + msg = "¨¤À»{ÃÒ«H¨çµLªk±H¥X¡A½Ð¥¿½T¶ñ¼g E-mail address"; + } + else + { + ACCT acct; + + strcpy(cuser.email, addr); + cuser.userlevel &= ~PERM_ALLVALID; + if (acct_load(&acct, cuser.userid) >= 0) + { + strcpy(acct.email, addr); + acct_setperm(&acct, 0, PERM_ALLVALID); + } + + film_out(FILM_JUSTIFY, 0); + prints("\n%s(%s)±z¦n¡A¥Ñ©ó±z§ó·s E-mail address ªº³]©w¡A\n\n" + "½Ð±z¾¨§Ö¨ì \033[44m%s\033[m ©Ò¦bªº¤u§@¯¸¦^ÂСy¨¤À»{ÃÒ«H¨ç¡z¡C", + cuser.userid, cuser.username, addr); + msg = NULL; + } +#else + msg = NULL; +#endif + + } + vmsg(msg); + } + + return 0; +} + + +/* ----------------------------------------------------- */ +/* ¶ñ¼gµù¥U³æ */ +/* ----------------------------------------------------- */ + + +#ifdef HAVE_REGISTER_FORM + +static void +getfield(line, len, buf, desc, hint) + int line, len; + char *hint, *desc, *buf; +{ + move(line, 0); + prints("%s%s", desc, hint); + vget(line + 1, 0, desc, buf, len, GCARRY); +} + + +int +u_register() +{ + FILE *fn; + int ans; + RFORM rform; + +#ifdef JUSTIFY_PERIODICAL + if ((HAS_PERM(PERM_VALID) && cuser.tvalid + VALID_PERIOD - INVALID_NOTICE_PERIOD >= ap_start) || HAS_PERM(PERM_ALLADMIN)) +#else + if (HAS_PERM(PERM_VALID)) +#endif + { + zmsg("±zªº¨¤À½T»{¤w¸g§¹¦¨¡A¤£»Ý¶ñ¼g¥Ó½Ðªí"); + return XEASY; + } + + if (fn = fopen(FN_RUN_RFORM, "rb")) + { + while (fread(&rform, sizeof(RFORM), 1, fn)) + { + if ((rform.userno == cuser.userno) && !strcmp(rform.userid, cuser.userid)) + { + fclose(fn); + zmsg("±zªºµù¥U¥Ó½Ð³æ©|¦b³B²z¤¤¡A½Ð@¤ßµ¥Ô"); + return XEASY; + } + } + fclose(fn); + } + + if (vans("±z½T©wn¶ñ¼gµù¥U³æ¶Ü(Y/N)¡H[N] ") != 'y') + return XEASY; + + move(1, 0); + clrtobot(); + prints("\n%s(%s) ±z¦n¡A½Ð¾Ú¹ê¶ñ¼g¥H¤Uªº¸ê®Æ¡G\n(«ö [Enter] ±µ¨üªì©l³]©w)", + cuser.userid, cuser.username); + + vmsg("ª`·N¡Gµù¥U³æ¥²¶·¥Î¤¤¤å¶ñ¼g¡A°£«D¦í§}¡B¾Ç®Õ©ÎªA°È³æ¦ì¦b°ê¥~"); + vmsg("ªA°È³æ¦ìÀ³Á×§K¨Ï¥Î¤TÓ¦r¤ºÂ²ºÙ¡A§_«h¦³¥i¯à³Q°h¥ó"); + memset(&rform, 0, sizeof(RFORM)); + for (;;) + { + move (5, 0); + prints ("\n\033[1;36m¡mªA°È³æ¦ì¡n\033[m\n"); + prints ("\033[1;30m½d¨Ò: \033[37m¥x«n¤@¤¤98¯Å\033[30m " \ + "©Î \033[37m¥xÆW\¤j¾Ç¸ê¤u¨t97¯Å\033[m¡A½Ð¶ñ¡u¯Å¼Æ¡v¡A¤£n¶ñ¦~¯Å¡AÁÂÁ¡C\n"); + + getfield(8, 50, rform.career, "ªA°È³æ¦ì", "¾Ç®Õ¨t¯Å©Î³æ¦ì¾ºÙ"); + + prints ("\n\033[1;36m¡m¥Ø«e¦í§}¡n\033[m\n"); + prints ("\033[1;30m½d¨Ò: \033[37m¥x«n¥«¥Á±Ú¸ô¤@¬q1¸¹\033[30m " \ + "©Î \033[37m¦¨¥\\¤j¾Ç·q¤@ªÙ1001©Ð\033[m\n"); + getfield(13, 60, rform.address, "¥Ø«e¦í§}", "¥]¬A¹ì«Ç©ÎªùµP¸¹½X"); + + prints ("\n\033[1;36m¡mÁpµ¸¹q¸Ü¡n\033[m\n"); + prints ("\033[1;30m½d¨Ò: \033[37m06-2371206\033[30m " \ + "©Î \033[37m0912345678\033[m\n"); + getfield(18, 20, rform.phone, "³sµ¸¹q¸Ü", "¥]¬Aªø³~¼·¸¹°Ï°ì½X"); + ans = vans("¥H¤W¸ê®Æ¬O§_¥¿½T(Y/N/Q)¡H[N] "); + if (ans == 'q') + return 0; + if (ans == 'y') + break; + } +/* + memset(&rform, 0, sizeof(RFORM)); + for (;;) + { + getfield(5, 50, rform.career, "ªA°È³æ¦ì¡G", "¾Ç®Õ¨t¯Å©Î³æ¦ì¾ºÙ"); + getfield(8, 60, rform.address, "¥Ø«e¦í§}¡G", "¥]¬A¹ì«Ç©ÎªùµP¸¹½X"); + getfield(11, 20, rform.phone, "³sµ¸¹q¸Ü¡G", "¥]¬Aªø³~¼·¸¹°Ï°ì½X"); + ans = vans("¥H¤W¸ê®Æ¬O§_¥¿½T(Y/N/Q)¡H[N] "); + if (ans == 'q') + return 0; + if (ans == 'y') + break; + } +*/ + rform.userno = cuser.userno; + strcpy(rform.userid, cuser.userid); + time(&rform.rtime); + rec_add(FN_RUN_RFORM, &rform, sizeof(RFORM)); + return 0; +} +#endif + + +/* ----------------------------------------------------- */ +/* ¶ñ¼gµù»{½X */ +/* ----------------------------------------------------- */ + + +#ifdef HAVE_REGKEY_CHECK +int +u_verify() +{ + char buf[80], key[10]; + ACCT acct; + + if (HAS_PERM(PERM_VALID)) + { + zmsg("±zªº¨¤À½T»{¤w¸g§¹¦¨¡A¤£»Ý¶ñ¼g»{ÃÒ½X"); + } + else + { + if (vget(b_lines, 0, "½Ð¿é¤J»{ÃÒ½X¡G", buf, 8, DOECHO)) + { + archiv32(str_hash(cuser.email, cuser.tvalid), key); /* itoc.010825: ¤£¥Î¶}ÀɤF¡Aª½±µ®³ tvalid ¨Ó¤ñ´N¬O¤F */ + + if (str_ncmp(key, buf, 7)) + { + zmsg("©êºp¡A±zªº»{ÃÒ½X¿ù»~"); + } + else + { + /* ´£¤ÉÅv */ + sprintf(buf, "KEY: %s", cuser.email); + justify_log(cuser.userid, buf); + if (acct_load(&acct, cuser.userid) >= 0) + { + time(&acct.tvalid); + acct_setperm(&acct, PERM_VALID, 0); + } + + /* ±H«H³qª¾¨Ï¥ÎªÌ */ + mail_self(FN_ETC_JUSTIFIED, str_sysop, msg_reg_valid, 0); + cutmp->status |= STATUS_BIFF; + vmsg(msg_reg_valid); + } + } + } + + return XEASY; +} +#endif + + +/* ----------------------------------------------------- */ +/* «ì´_Åv */ +/* ----------------------------------------------------- */ + + +int +u_deny() +{ + ACCT acct; + time_t diff; + struct tm *ptime; + char msg[80]; + + if (!HAS_PERM(PERM_ALLDENY)) + { + zmsg("±z¨S³Q°±Åv¡A¤£»Ý´_Åv"); + } + else + { + if ((diff = cuser.tvalid - time(0)) < 0) /* °±Åv®É¶¡¨ì¤F */ + { + if (acct_load(&acct, cuser.userid) >= 0) + { + time(&acct.tvalid); +#ifdef JUSTIFY_PERIODICAL + /* xeon.050112: ¦b»{ÃÒ§Ö¨ì´Á«e®É Cross-Post¡AµM«á tvalid ´N·|³Q³]©w¨ì¥¼¨Ó®É¶¡¡A + µ¥´_Åv®É¶¡¨ì¤F¥h´_Åv¡A³o¼Ë´N¥i¥HÁ×¹L«·s»{ÃÒ¡A©Ò¥H´_Åv«án«·s»{ÃÒ¡C */ + acct_setperm(&acct, 0, PERM_ALLVALID | PERM_ALLDENY); +#else + acct_setperm(&acct, 0, PERM_ALLDENY); +#endif + vmsg("¤U¦¸½Ð¤Å¦A¥Ç¡A½Ð«·s¤W¯¸"); + } + } + else + { + ptime = gmtime(&diff); + sprintf(msg, "±zÁÙnµ¥ %d ¦~ %d ¤Ñ %d ®É %d ¤À %d ¬í¤~¯à¥Ó½Ð´_Åv", + ptime->tm_year - 70, ptime->tm_yday, ptime->tm_hour, ptime->tm_min, ptime->tm_sec); + vmsg(msg); + } + } + + return XEASY; +} + + +/* ----------------------------------------------------- */ +/* Ó¤H¤u¨ã */ +/* ----------------------------------------------------- */ + + +int +u_info() +{ + char *str, username[UNLEN + 1]; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + move(1, 0); + strcpy(username, str = cuser.username); + acct_setup(&cuser, 0); + if (strcmp(username, str)) + memcpy(cutmp->username, str, UNLEN + 1); + return 0; +} + + +int +u_setup() +{ + usint ulevel; + int len; + + /* itoc.000320: ¼W´î¶µ¥Øn§ó§ï len ¤j¤p, ¤]§O§Ñ¤F§ï ufo.h ªººX¼Ð STR_UFO */ + + ulevel = cuser.userlevel; + if (!ulevel) + len = NUMUFOS_GUEST; + else if (ulevel & PERM_ALLADMIN) + len = NUMUFOS; /* ADMIN °£¤F¥i¥Î acl¡AÁÙ¶¶«K¤]¥i¥H¥ÎÁô¨³N */ + else if (ulevel & PERM_CLOAK) + len = NUMUFOS - 2; /* ¤£¯à¥ÎµµÁô¡Bacl */ + else + len = NUMUFOS_USER; + + cuser.ufo = cutmp->ufo = bitset(cuser.ufo, len, len, MSG_USERUFO, ufo_tbl); + + return 0; +} + + +int +u_lock() +{ + char buf[PSWDLEN + 1]; + + switch (vans("¬O§_¶i¤J¿Ã¹õÂê©wª¬ºA¡A±N¤£¯à¶Ç°e/±µ¦¬¤ô²y(Y/N/C)¡H[N] ")) + { + case 'c': /* itoc.011226: ¥i¦Û¦æ¿é¤Jµo§bªº²z¥Ñ */ + if (vget(b_lines, 0, "½Ð¿é¤Jµo§bªº²z¥Ñ¡G", cutmp->mateid, IDLEN + 1, DOECHO)) + break; + + case 'y': + strcpy(cutmp->mateid, "±¾¯¸"); + break; + + default: + return XEASY; + } + + bbstate |= STAT_LOCK; /* lkchu.990513: Âê©w®É¤£¥i¦^¤ô²y */ + cutmp->status |= STATUS_REJECT; /* Âê©w®É¤£¦¬¤ô²y */ + + clear(); + move(5, 20); + prints("\033[1;33m" BBSNAME " ¶¢¸m/Âê©wª¬ºA\033[m [%s]", cuser.userid); + + do + { + vget(b_lines, 0, "¡» ½Ð¿é¤J±K½X¡A¥H¸Ñ°£¿Ã¹õÂê©w¡G", buf, PSWDLEN + 1, NOECHO); + } while (chkpasswd(cuser.passwd, buf)); + + cutmp->status ^= STATUS_REJECT; + bbstate ^= STAT_LOCK; + + return 0; +} + + +int +u_log() +{ + char fpath[64]; + + usr_fpath(fpath, cuser.userid, FN_LOG); + more(fpath, NULL); + return 0; +} + + +/* ----------------------------------------------------- */ +/* ³]©wÀÉ®× */ +/* ----------------------------------------------------- */ + +void +do_diff(oldfile, filesize, newpath) + const void* oldfile; /* Àx¦s´NÀɮתº°O¾ÐÅé¦ì¸m */ + const int filesize; /* ÂÂÀɮפj¤p */ + const char* newpath; /* ·sÀɮצWºÙ */ +{ + char folder[64], fpath[64], title[64]; + char* board="log"; + HDR hdr; + brd_fpath(folder, board, FN_DIR); + int fd = hdr_stamp(folder, 'A', &hdr, fpath); + if(fd < 0){ + vmsg("·s¼W¤å³¹¥¢±Ñ"); + return; + } + FILE* fp = fdopen(fd, "w"); + sprintf(title,"¨t²ÎÀÉ®× %s ×§ï¬ö¿ý (%s)",newpath,cuser.userid); + fprintf(fp, "§@ªÌ: %s (%s)\n¼ÐÃD: %s\n®É¶¡: %s\n\n", + STR_SYSOP, SYSOPNICK, title, Btime(&hdr.chrono)); + fflush(fp); + int fdin[2]; + pipe(fdin); + pid_t child; + child=fork(); + if(child == 0){ + close(fdin[1]); + dup2(fdin[0],0); /* «·s¾É¦V stdin */ + dup2(fd,1); /* «·s¾É¦V stdout */ + execlp("diff","diff","-u","-",newpath,NULL); + }else{ + close(fdin[0]); + write(fdin[1],oldfile,filesize); + close(fdin[1]); + } +#if 0 + /* lantw44: ¤£»Ýnµ¥ */ + waitpid(child,NULL,0); /* µ¥µ{¦¡¶]§¹ */ +#endif + close(fd); + + /* ³o¬q¬O±q util/account.c -> keeplog() §Û¨Óªº */ + + strcpy(hdr.title, title); + strcpy(hdr.owner, STR_SYSOP); + rec_bot(folder, &hdr, sizeof(HDR)); +} + + + + +/* static */ /* itoc.010110: µ¹ a_xfile() ¥Î */ +void +x_file(mode, xlist, flist) + int mode; /* M_XFILES / M_UFILES */ + char *xlist[]; /* description list */ + char *flist[]; /* filename list */ +{ + int n, i; + char *fpath, *desc; + char buf[64]; + int noedit; + + /* lantw44: diff ¥Îªº´XÓÅܼơA×§ï¨t²ÎÀɮɤ~¥Î */ + void* oldfile; + int filesize; + struct stat st; + + move(MENU_XPOS, 0); + clrtobot(); + n = 0; + while (desc = xlist[n]) + { + n++; + if (n <= 9) /* itoc.020123: ¤À¤GÄæ¡A¤@Äæ¤EÓ */ + { + move(n + MENU_XPOS - 1, 0); + clrtoeol(); + move(n + MENU_XPOS - 1, 2); + } + else + { + move(n + MENU_XPOS - 10, 40); + } + prints("(%d) %s", n, desc); + + if (mode == M_XFILES) /* Thor.980806.µù¸Ñ: ¦L¥XÀɦW */ + { + if (n <= 9) + move(n + MENU_XPOS - 1, 22); + else + move(n + MENU_XPOS - 10, 62); + outs(flist[n - 1]); + } + } + + vget(b_lines, 0, "½Ð¿ï¾ÜÀÉ®×½s¸¹¡A©Î«ö [0] ¨ú®ø¡G", buf, 3, DOECHO); + i = atoi(buf); + if (i <= 0 || i > n) + return; + + n = vget(b_lines, 36, "(D)§R°£ (E)½s¿è (V)À˵ø [Q]¨ú®ø¡H", buf, 3, LCECHO); + if (n != 'd' && n != 'e' && n !='v') + return; + + fpath = flist[--i]; + if (mode == M_UFILES) + usr_fpath(buf, cuser.userid, fpath); + else{ + strcpy(buf, fpath); + } + + if (n == 'd') + { + if (vans(msg_sure_ny) == 'y'){ + unlink(buf); + if( mode == M_XFILES ){ + alog("§R¨t²ÎÀÉ", fpath); + } + } + }else if(n == 'v'){ + if(more(buf, (char*)0)<0){ + vmsg("ÀÉ®×¶}±Ò¥¢±Ñ (¥i¯àÀɮפ£¦s¦b)"); + } + return; + } + else + { + char nodiff=0; + if(mode == M_XFILES){ + if(stat(fpath,&st)<0){ + vmsg("Àɮ׬ÛÃö¸ê°TŪ¨ú¥¢±Ñ¡A²¤¹L°õ¦æ diff"); + nodiff=1; + }else{ + filesize=st.st_size; + oldfile=malloc(filesize); + if(oldfile==NULL){ + vmsg("malloc ¥¢±Ñ¡A²¤¹L°õ¦æ diff"); + nodiff=1; + }else{ + FILE* fp; + if((fp=fopen(fpath,"r"))==NULL){ + vmsg("ÀÉ®×¶}±Ò¥¢±Ñ¡A²¤¹L°õ¦æ diff"); + nodiff=1; + }else{ + fread(oldfile,1,filesize,fp); + fclose(fp); + } + } + } + } + noedit=vedit(buf, 0); + vmsg(noedit ? "ì«Ê¤£°Ê" : "§ó·s§¹²¦"); /* Thor.981020: ª`·N³Qtalkªº°ÝÃD */ + if(noedit == 0 && mode == M_XFILES){ + alog("§ï¨t²ÎÀÉ", fpath); + if(!nodiff){ + do_diff(oldfile,filesize,fpath); + free(oldfile); + } + } + } +} + + +int +u_xfile() +{ + int i; + + static char *desc[] = + { + "¤W¯¸¦aÂI³]©wÀÉ", + "¦W¤ùÀÉ", + "ñ¦WÀÉ.1", + "ñ¦WÀÉ.2", + "ñ¦WÀÉ.3", + "ñ¦WÀÉ.4", + "ñ¦WÀÉ.5", + "ñ¦WÀÉ.6", + "¼È¦sÀÉ.1", + "¼È¦sÀÉ.2", + "¼È¦sÀÉ.3", + "¼È¦sÀÉ.4", + "¼È¦sÀÉ.5", + NULL + }; + + static char *path[] = + { + "acl", + "plans", + FN_SIGN ".1", + FN_SIGN ".2", + FN_SIGN ".3", + FN_SIGN ".4", + FN_SIGN ".5", + FN_SIGN ".6", + "buf.1", + "buf.2", + "buf.3", + "buf.4", + "buf.5" + }; + + i = HAS_PERM(PERM_ALLADMIN) ? 0 : 1; + x_file(M_UFILES, &desc[i], &path[i]); + return 0; +} diff --git a/maple/visio.c b/maple/visio.c new file mode 100644 index 0000000..ca247df --- /dev/null +++ b/maple/visio.c @@ -0,0 +1,2071 @@ +/*-------------------------------------------------------*/ +/* visio.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : VIrtual Screen Input Output routines */ +/* create : 95/03/29 */ +/* update : 96/10/10 */ +/*-------------------------------------------------------*/ + + +#include <stdarg.h> +#include <arpa/telnet.h> + + +#include "bbs.h" + + +#define VO_MAX 3072 /* output buffer ¤j¤p */ +#define VI_MAX 256 /* input buffer ¤j¤p */ + + +#define INPUT_ACTIVE 0 +#define INPUT_IDLE 1 + + +static int cur_row, cur_col; +static int cur_pos; /* current position with ANSI codes */ + + +/* ----------------------------------------------------- */ +/* º~¦r (zh-char) §PÂ_ */ +/* ----------------------------------------------------- */ + + +#ifdef HAVE_MULTI_BYTE +int /* 1:¬O 0:¤£¬O */ +is_zhc_low(str, n) /* hightman.060504: §PÂ_¦r¦ê¤¤ªº²Ä n Ó¦r²Å¬O§_¬°º~¦rªº«á¥b¦r */ + char *str; + int n; +{ + char *end; + + end = str + n; + while (str < end) + { + if (IS_ZHC_HI(*str)) + str++; + str++; + } + + return (str - end); +} +#endif + + +/* ----------------------------------------------------- */ +/* output routines */ +/* ----------------------------------------------------- */ + + +static uschar vo_pool[VO_MAX]; +static int vo_size; + + +#ifdef VERBOSE +static void +telnet_flush(data, size) + char *data; + int size; +{ + int oset; + + oset = 1; + + if (select(1, NULL, &oset, NULL, NULL) <= 0) + { + abort_bbs(); + } + + xwrite(0, data, size); +} + +#else + +# define telnet_flush(data, size) send(0, data, size, 0) +#endif + + +static void +oflush() +{ + int size; + + if (size = vo_size) + { + telnet_flush(vo_pool, size); + vo_size = 0; + } +} + + +static void +output(str, len) + uschar *str; + int len; +{ + int size, ch; + uschar *data; + + size = vo_size; + data = vo_pool; + if (size + len > VO_MAX - 8) + { + telnet_flush(data, size); + size = len; + } + else + { + data += size; + size += len; + } + + while (--len >= 0) + { + ch = *str++; + *data++ = ch; + if (ch == IAC) + { + *data++ = ch; + size++; + } + } + vo_size = size; +} + + +static void +ochar(ch) + int ch; +{ + uschar *data; + int size; + + data = vo_pool; + size = vo_size; + if (size > VO_MAX - 2) + { + telnet_flush(data, size); + size = 0; + } + data[size++] = ch; + vo_size = size; +} + + +void +bell() +{ + static char sound[1] = {Ctrl('G')}; + + telnet_flush(sound, sizeof(sound)); +} + + +/* ----------------------------------------------------- */ +/* virtual screen */ +/* ----------------------------------------------------- */ + + +#define o_ansi(x) output(x, sizeof(x)-1) + +#define o_clear() o_ansi("\033[;H\033[2J") +#define o_cleol() o_ansi("\033[K") +#define o_standup() o_ansi("\033[7m") +#define o_standdown() o_ansi("\033[m") + + +static int docls; +static int roll; +static int scrollcnt, tc_col, tc_row; + + +static screenline vbuf[T_LINES]; +static screenline *cur_slp; /* current screen line pointer */ + + +/* itoc.020611.µù¸Ñ: ®y¼ÐÀ³¸Ó¬O (x, y) ¦Ó¤£¬O (y, x) + ¦]¬° row ¬O ¦V¤U¬°¥¿¡Acolumn ¬O¦V¥k¬°¥¿¡A + ¦Ó +x cross +y = +z ¬O¥X¿Ã¹õ± */ + +void +move(x, y) + int x; /* row */ + int y; /* column */ +{ + screenline *cslp; + + if (x > b_lines) + return; + + if (y >= b_cols) + y = 0; + + cur_row = x; + if ((x += roll) > b_lines) + x -= b_lines + 1; + cur_slp = cslp = &vbuf[x]; + cur_col = y; + +#if 0 + + /* ------------------------------------- */ + /* ¹LÂo ANSI codes¡Apºâ´å¼Ð¯u¥¿©Ò¦b¦ì¸m */ + /* ------------------------------------- */ + + if (y) + { + int ch, ansi; + int len; + uschar *str; + + ansi = 0; + x = y; + len = cslp->len; + str = cslp->data; + str[len] = '\0'; + while (len && (ch = *str)) + { + str++; + len--; + + if (ansi) + { + x++; + if (ch == 'm') + ansi = 0; + continue; + } + if (ch == KEY_ESC) + { + x++; + ansi = 1; + continue; + } + y--; + if (y <= 0) + break; + } + y = x; + } +#endif + + cur_pos = y; +} + + +#if 0 +static void +getxy(x, y) + int *x, *y; +{ + *x = cur_row; + *y = cur_col; +} +#endif + + +/*-------------------------------------------------------*/ +/* pºâ slp ¤¤ len ¤§³Bªº´å¼Ð column ©Ò¦b */ +/*-------------------------------------------------------*/ + + +#if 0 +static int +ansicol(slp, len) + screenline *slp; + int len; +{ + uschar *str; + int ch, ansi, col; + + if (!len || !(slp->mode & SL_ANSICODE)) + return len; + + ansi = col = 0; + str = slp->data; + + while (len-- && (ch = *str++)) + { + if (ch == KEY_ESC && *str == '[') + { + ansi = 1; + continue; + } + if (ansi) + { + if (ch == 'm') + ansi = 0; + continue; + } + col++; + } + return col; +} +#endif + + +static void +rel_move(new_col, new_row) + int new_col, new_row; +{ + int was_col, was_row; + char buf[16]; + + if (new_row > b_lines || new_col >= b_cols) + return; + + was_col = tc_col; + was_row = tc_row; + + tc_col = new_col; + tc_row = new_row; + + if (new_col == 0) + { + if (new_row == was_row) + { + if (was_col) + ochar('\r'); + return; + } + else if (new_row == was_row + 1) + { + ochar('\n'); + if (was_col) + ochar('\r'); + return; + } + } + + if (new_row == was_row) + { + if (was_col == new_col) + return; + + if (new_col == was_col - 1) + { + ochar(KEY_BKSP); + return; + } + } + + sprintf(buf, "\033[%d;%dH", new_row + 1, new_col + 1); + output(buf, strlen(buf)); +} + + +static void +standoutput(slp, ds, de) + screenline *slp; + int ds, de; +{ + uschar *data; + int sso, eso; + + data = slp->data; + sso = slp->sso; + eso = slp->eso; + + if (eso <= ds || sso >= de) + { + output(data + ds, de - ds); + return; + } + + if (sso > ds) + output(data + ds, sso - ds); + else + sso = ds; + + o_standup(); + output(data + sso, BMIN(eso, de) - sso); + o_standdown(); + + if (de > eso) + output(data + eso, de - eso); +} + + +#define STANDOUT cur_slp->sso = cur_pos; cur_slp->mode |= SL_STANDOUT; +#define STANDEND cur_slp->eso = cur_pos; + + +#if 0 +static int standing; + + +static void +standout() +{ + if (!standing) + { + standing = 1; + cur_slp->sso = cur_slp->eso = cur_pos; + cur_slp->mode |= SL_STANDOUT; + } +} + + +static void +standend() +{ + if (standing) + { + standing = 0; + if (cur_slp->eso < cur_pos) + cur_slp->eso = cur_pos; + } +} +#endif + + +static void +vs_redraw() +{ + screenline *slp; + int i, j, len, mode, width; + + tc_col = tc_row = docls = scrollcnt = vo_size = i = 0; + o_clear(); + for (slp = &vbuf[j = roll]; i <= b_lines; i++, j++, slp++) + { + if (j > b_lines) + { + j = 0; + slp = vbuf; + } + + len = slp->len; + width = slp->width; + slp->oldlen = width; + mode = slp->mode &= + (len <= slp->sso) ? ~(SL_MODIFIED | SL_STANDOUT) : ~(SL_MODIFIED); + if (len) + { + rel_move(0, i); + + if (mode & SL_STANDOUT) + standoutput(slp, 0, len); + else + output(slp->data, len); + + tc_col = width; + } + } + rel_move(cur_col, cur_row); + oflush(); +} + + +void +refresh() +{ + screenline *slp; + int i, j, len, mode, width, smod, emod; + + i = scrollcnt; + + if (docls || abs(i) >= b_lines) + { + vs_redraw(); + return; + } + + if (i) + { + char buf[T_LINES]; + + scrollcnt = j = 0; + if (i < 0) + { + sprintf(buf, "\033[%dL", -i); + i = strlen(buf); + } + else + { + do + { + buf[j] = '\n'; + } while (++j < i); + j = b_lines; + } + rel_move(0, j); + output(buf, i); + } + + for (i = 0, slp = &vbuf[j = roll]; i <= b_lines; i++, j++, slp++) + { + if (j > b_lines) + { + j = 0; + slp = vbuf; + } + + len = slp->len; + width = slp->width; + mode = slp->mode; + + if (mode & SL_MODIFIED) + { + slp->mode = mode &= + (len <= slp->sso) ? ~(SL_MODIFIED | SL_STANDOUT) : ~(SL_MODIFIED); + + if ((smod = slp->smod) < len) + { + emod = slp->emod + 1; + if (emod >= len) + emod = len; + + rel_move(smod, i); + + /* rel_move(ansicol(slp, smod), i); */ + + if (mode & SL_STANDOUT) + standoutput(slp, smod, emod); + else + output(&slp->data[smod], emod - smod); + + /* tc_col = ansicol(slp, emod); */ + +#if 0 + if (mode & SL_ANSICODE) + { + uschar *data; + + data = slp->data; + mode = 0; + len = emod; + + while (len--) + { + smod = *data++; + if (smod == KEY_ESC) + { + mode = 1; + emod--; + continue; + } + + if (mode) + { + if (smod == 'm') + mode = 0; + emod--; + } + } + } + + tc_col = emod; +#endif + + tc_col = (width != len) ? width : emod; + } + } + + if (slp->oldlen > width) + { + rel_move(width, i); + o_cleol(); + } + slp->oldlen = width; + } + rel_move(cur_col, cur_row); + oflush(); +} + + +void +clear() +{ + int i; + screenline *slp; + + docls = 1; + cur_pos = cur_col = cur_row = roll = i = 0; + cur_slp = slp = vbuf; + while (i++ <= b_lines) + { + /* memset(slp, 0, sizeof(screenline)); */ + /* ¥u»Ý slp->data[0] = '\0' §Y¥i¡A¤£»Ý²M¾ãÓ ANSILINELEN */ + memset(slp, 0, sizeof(screenline) - ANSILINELEN + 1); + slp++; + } +} + + +void +clrtoeol() /* clear screen to end of line (¦C§À) */ +{ + screenline *slp = cur_slp; + int len; + + if (len = cur_pos) + { + slp->len = len; + slp->width = cur_col; + } + else + { + /* ²M±¼ oldlen ¥H«áªº¥þ³¡¡Fdata ¥u»Ý²Mº byte §Y¥i */ + memset((char *) slp + sizeof(slp->oldlen), 0, sizeof(screenline) - ANSILINELEN + 1 - sizeof(slp->oldlen)); + } +} + + +void +clrtobot() /* clear screen to bottom (¿Ã¹õ©³³¡) */ +{ + screenline *slp; + int i, j; + + i = cur_row; + j = i + roll; + slp = cur_slp; + while (i <= b_lines) + { + if (j > b_lines) + { + j = 0; + slp = vbuf; + } + /* ²M±¼ oldlen ¥H«áªº¥þ³¡¡Fdata ¥u»Ý²Mº byte §Y¥i */ + memset((char *) slp + sizeof(slp->oldlen), 0, sizeof(screenline) - ANSILINELEN + 1 - sizeof(slp->oldlen)); + + i++; + j++; + slp++; + } +} + + +void +outc(ch) + int ch; +{ + screenline *slp; + uschar *data; + int i, cy, pos; + + static char ansibuf[16] = "\033"; + static int ansipos = 0; + + slp = cur_slp; + pos = cur_pos; + + if (ch == '\n') + { + cy = cur_col; + +new_line: + + ansipos = 0; + if (pos) + { + slp->len = pos; + slp->width = cy; + +#if 0 + if (standing) + { + standing = 0; + if (pos <= slp->sso) + slp->mode &= ~SL_STANDOUT; + else if (slp->eso < pos) + slp->eso = pos; + } +#endif + } + else + { + /* ²M±¼ oldlen ¥H«áªº¥þ³¡¡Fdata ¥u»Ý²Mº byte §Y¥i */ + memset((char *) slp + sizeof(slp->oldlen), 0, sizeof(screenline) - ANSILINELEN + 1 - sizeof(slp->oldlen)); + } + + move(cur_row + 1, 0); + return; + } + + if (ch < 0x20) + { + if (ch == KEY_ESC) + ansipos = 1; + + return; + } + + data = &(slp->data[pos]); /* «ü¦V¥Ø«e¿é¥X¦ì¸m */ + + /* -------------------- */ + /* ¸É¨¬©Ò»ÝnªºªÅ¥Õ¦r¤¸ */ + /* -------------------- */ + + cy = slp->len - pos; + if (cy > 0) + { + cy = *data; + } + else + { + while (cy < 0) + { + data[cy++] = ' '; + } + + slp->len = /* slp->width = */ pos + 1; + } + + /* ---------------------------- */ + /* ANSI control code ¤§¯S§O³B²z */ + /* ---------------------------- */ + + if (i = ansipos) + { + if ((i < 15) && + ((ch >= '0' && ch <= '9') || ch == '[' || ch == 'm' || ch == ';')) + { + ansibuf[i++] = ch; + + if (ch != 'm') + { + ansipos = i; + return; + } + + ch = i + pos; + if (ch < ANSILINELEN - 1) + { + memcpy(data, ansibuf, i); + slp->len = slp->emod = cur_pos = ch; + slp->mode |= SL_MODIFIED; + if (slp->smod > pos) + slp->smod = pos; + } + } + ansipos = 0; + return; + } + + /* ---------------------------- */ + /* §P©wþ¨Ç¤å¦r»Ýn«·s°e¥X¿Ã¹õ */ + /* ---------------------------- */ + + if ( /* !(slp->mode & SL_ANSICODE) && */ (ch != cy)) + { + *data = ch; + cy = slp->mode; + if (cy & SL_MODIFIED) + { + if (slp->smod > pos) + slp->smod = pos; + if (slp->emod < pos) + slp->emod = pos; + } + else + { + slp->mode = cy | SL_MODIFIED; + slp->smod = slp->emod = pos; + } + } + + cur_pos = ++pos; + cy = ++cur_col; + + if ((pos >= ANSILINELEN) /* || (cy >= b_cols) */ ) + goto new_line; + + if (slp->width < cy) + slp->width = cy; +} + + +void +outs(str) + uschar *str; +{ + int ch; + + while (ch = *str) + { + outc(ch); + str++; + } +} + + +/* ----------------------------------------------------- */ +/* eXtended output: ¨q¥X user ªº name ©M nick */ +/* ----------------------------------------------------- */ + + +#ifdef SHOW_USER_IN_TEXT +void +outx(str) + uschar *str; +{ + int ch; + + while (ch = *str) + { + /* itoc.020301: ESC + * + s µ¥±±¨î½X */ + if (ch == KEY_ESC && str[1] == '*') + { + switch (str[2]) + { + case 's': /* **s Åã¥Ü ID */ + outs(cuser.userid); + str += 3; + continue; + case 'n': /* **n Åã¥Ü¼ÊºÙ */ + outs(cuser.username); + str += 3; + continue; + case 'r': /* **r Åã¥Ü¯u¹ê©m¦W */ + outs(cuser.realname); + str += 3; + continue; + } + } + outc(ch); + str++; + } +} +#endif + + +/* ----------------------------------------------------- */ +/* clear the bottom line and show the message */ +/* ----------------------------------------------------- */ + + +void +outz(str) + uschar *str; +{ + move(b_lines, 0); + clrtoeol(); + outs(str); +} + + +void +outf(str) + uschar *str; +{ + outz(str); + prints("%*s\033[m", d_cols, ""); +} + + +void +prints(char *fmt, ...) +{ + va_list args; + uschar buf[512], *str; /* ³Ìªø¥u¯à¦L 512 ¦r */ + int cc; + + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + for (str = buf; cc = *str; str++) + outc(cc); +} + + +void +scroll() +{ + scrollcnt++; + if (++roll > b_lines) + roll = 0; + move(b_lines, 0); + clrtoeol(); +} + + +void +rscroll() +{ + scrollcnt--; + if (--roll < 0) + roll = b_lines; + move(0, 0); + clrtoeol(); +} + + +/* ----------------------------------------------------- */ + + +static int old_col, old_row, old_roll; +static int old_pos; /* Thor.990401: ¦h¦s¤@Ó */ + + +/* static void */ +void /* Thor.981028: ¬°¤FÅý talk.c ¦³¤H©I¥s®É·|show¦r */ +cursor_save() +{ + old_col = cur_col; + old_row = cur_row; + + old_pos = cur_pos; /* Thor.990401: ¦h¦s¤@Ó */ +} + + +/* static void */ +void /* Thor.981028: ¬°¤FÅý talk.c ¦³¤H©I¥s®É·|show¦r */ +cursor_restore() +{ + move(old_row, old_col); + + cur_pos = old_pos; /* Thor.990401: ¦hÁÙì¤@Ó */ +} + + +void +save_foot(slp) + screenline *slp; +{ + int i; + int lines[3] = {0, b_lines, b_lines - 1}; /* Àx¦s³o¤T¦C */ + + for (i = 0; i < 3; i++) + { + move(lines[i], 0); + memcpy(slp + i, cur_slp, sizeof(screenline)); + slp[i].smod = 0; + slp[i].emod = ANSILINELEN; /* Thor.990125:¤£½×³Ì«á¤@¦¸§ï¨ìþ, ¥þ³¡nø¤W */ + slp[i].oldlen = ANSILINELEN; + slp[i].mode |= SL_MODIFIED; + } +} + + +void +restore_foot(slp, line) + screenline *slp; + int line; /* n«ì´_ lines[] ¸Ì±ªº«e´X¦C */ +{ + int i; + int lines[3] = {0, b_lines, b_lines - 1}; /* «ì´_³o¤T¦C */ + + for (i = 0; i < line; i++) + { + move(lines[i], 0); + memcpy(cur_slp, slp + i, sizeof(screenline)); + } +} + + +int +vs_save(slp) + screenline *slp; +{ + old_roll = roll; + memcpy(slp, vbuf, sizeof(screenline) * (b_lines + 1)); + return old_roll; /* itoc.030723: ¶Ç¦^¥Ø«eªº roll */ +} + + +void +vs_restore(slp) + screenline *slp; +{ + memcpy(vbuf, slp, sizeof(screenline) * (b_lines + 1)); + roll = old_roll; + vs_redraw(); +} + + +#if 0 +int +imsg(msg) /* itoc.010827: «n°T®§Åã¥Ü important message */ + char *msg; /* length <= 54 */ +{ + int i; + time_t now; + char scroller[128], spacebar[60], buf[80]; + char alphabet[26][3] = + { + "¢é", "¢ê", "¢ë", "¢ì", "¢í", "¢î", "¢ï", "¢ð", "¢ñ", + "¢ò", "¢ó", "¢ô", "¢õ", "¢ö", "¢÷", "¢ø", "¢ù", "¢ú", + "¢û", "¢ü", "¢ý", "¢þ", "£@", "£A", "£B", "£C" + }; + + time(&now); /* ¥Î®É¶¡¨Ó random */ + +#if 1 /* §Q¥Î¶]°¨¿O®ÄªG¨Ó´£¥Ü«n°T®§ */ + i = now % 6 + 1; /* ÃC¦â½X */ + sprintf(spacebar, "\033[%d;H", b_lines + 1); /* ²¾¦ì½X */ + sprintf(buf, "\033[3%dm¢j¢k¢l¢m¢n¢o\033[1;37;4%dm «n°T®§½Ðª`·N \033[m", i, i); + + /* ¤£²M°£ b_lines¡A¨Ï¦³²H¥Xªº®ÄªG */ + for (i = 1; i <= 47; i += 2) + { + sprintf(scroller, "%s%s", spacebar, buf); /* scroller ¶]°¨¿O */ + strcat(spacebar, " "); /* ¤@¦¸¸õ¤G®æ¡A¼W¥[³t«× */ + telnet_flush(scroller, strlen(scroller) + 1); /* §Y®É¿é¥X¡A¶]°¨¿O®ÄªG */ + usleep(1000); + } +#endif + + i = now % 26; /* 'a' ~ 'z' ¶Ã¨ú¤@Áä */ + + if (msg) + { + move(b_lines, 0); + clrtoeol(); + prints(COLOR1 " ¡» %-55s " COLOR2 " [½Ð«ö %s ÁäÄ~Äò] \033[m", msg, alphabet[i]); + } + else + { + move(b_lines, 27); + prints(COLOR1 " ¡´ ½Ð«ö %s ÁäÄ~Äò ¡´ \033[m", alphabet[i]); + } + + i += 'a'; + while (vkey() != i) + ; + + return i; +} +#endif /* VIEW_IMSG */ + + +#ifdef POPUP_MESSAGE +int +vmsg(msg) + char *msg; /* length <= 54 */ +{ + if (msg) + return pmsg(msg); + + move(b_lines, 0); + outs(VMSG_NULL); + move(b_lines, 0); /* itoc.010127: ×¥¿¦b°»´ú¥ª¥kÁä¥þ§Î¤U¡A«ö¥ªÁä·|¸õÂ÷¤G¼h¿ï³æªº°ÝÃD */ + return vkey(); +} +#else +int +vmsg(msg) + char *msg; /* length <= 54 */ +{ + if (msg) + { + move(b_lines, 0); + clrtoeol(); + prints(COLOR1 " ¡» %-55s " COLOR2 " [½Ð«ö¥ô·NÁäÄ~Äò] \033[m", msg); + } + else + { + move(b_lines, 0); + outs(VMSG_NULL); + move(b_lines, 0); /* itoc.010127: ×¥¿¦b°»´ú¥ª¥kÁä¥þ§Î¤U¡A«ö¥ªÁä·|¸õÂ÷¤G¼h¿ï³æªº°ÝÃD */ + } + return vkey(); +} +#endif + + +static inline void +zkey() /* press any key or timeout */ +{ + /* static */ struct timeval tv = {1, 100}; + /* Thor.980806: man page °²³] timeval struct¬O·|§ïÅܪº */ + + int rset; + + rset = 1; + select(1, (fd_set *) &rset, NULL, NULL, &tv); + +#if 0 + if (select(1, &rset, NULL, NULL, &tv) > 0) + { + recv(0, &rset, sizeof(&rset), 0); + } +#endif +} + + +void +zmsg(msg) /* easy message */ + char *msg; +{ + outz(msg); + move(b_lines, 0); /* itoc.031029: ×¥¿¦b°»´ú¥ª¥kÁä¥þ§Î¤U¡A«ö¥ªÁä·|¸õÂ÷¤G¼h¿ï³æªº°ÝÃD */ + + refresh(); + zkey(); +} + + +void +vs_bar(title) + char *title; +{ + clear(); + prints("\033[1;33;44m¡i %s ¡j\033[m\n", title); +} + + +static void +vs_line(msg) + char *msg; +{ + int head, tail; + + if (msg) + head = (strlen(msg) + 1) >> 1; + else + head = 0; + + tail = head; + + while (head++ < 38) + outc('-'); + + if (tail) + { + outc(' '); + outs(msg); + outc(' '); + } + + while (tail++ < 38) + outc('-'); + outc('\n'); +} + + +/* ----------------------------------------------------- */ +/* input routines */ +/* ----------------------------------------------------- */ + + +static uschar vi_pool[VI_MAX]; +static int vi_size; +static int vi_head; + + +static int vio_fd; + + +#ifdef EVERY_Z + +static int holdon_fd; /* Thor.980727: ¸õ¥Xchat&talk¼È¦svio_fd¥Î */ + + +void +vio_save() +{ + holdon_fd = vio_fd; + vio_fd = 0; +} + + +void +vio_restore() +{ + vio_fd = holdon_fd; + holdon_fd = 0; +} + + +int +vio_holdon() +{ + return holdon_fd; +} +#endif + + +#if 0 +struct timeval +{ + int tv_sec; /* timeval second */ + int tv_usec; /* timeval micro-second */ +}; +#endif + +static struct timeval vio_to = {60, 0}; + + +void +add_io(fd, timeout) + int fd; + int timeout; +{ + vio_fd = fd; + vio_to.tv_sec = timeout; +} + + +static inline int +iac_count(current) + uschar *current; +{ + switch (*(current + 1)) + { + case DO: + case DONT: + case WILL: + case WONT: + return 3; + + case SB: /* loop forever looking for the SE */ + { + uschar *look = current + 2; + + /* fuse.030518: ½u¤W½Õ¾ãµe±¤j¤p¡A«§ì b_lines */ + if ((*look) == TELOPT_NAWS) + { + b_lines = ntohs(* (short *) (look + 3)) - 1; + b_cols = ntohs(* (short *) (look + 1)) - 1; + if (b_lines >= T_LINES) + b_lines = T_LINES - 1; + else if (b_lines < 23) + b_lines = 23; + if (b_cols >= T_COLS) + b_cols = T_COLS - 1; + else if (b_cols < 79) + b_cols = 79; + d_cols = b_cols - 79; + } + + for (;;) + { + if ((*look++) == IAC) + { + if ((*look++) == SE) + { + return look - current; + } + } + } + } + } + return 1; +} + + +int +igetch() +{ + +#define IM_TRAIL 0x01 +#define IM_REPLY 0x02 /* ^R */ +#define IM_TALK 0x04 + + static int imode = 0; + static int idle = 0; + + int cc, fd, nfds, rset; + uschar *data; + + data = vi_pool; + nfds = 0; + + for (;;) + { + if (vi_size <= vi_head) + { + if (nfds == 0) + { + refresh(); + fd = (imode & IM_REPLY) ? 0 : vio_fd; + nfds = fd + 1; + if (fd) + fd = 1 << fd; + } + + for (;;) + { + struct timeval tv = vio_to; + /* Thor.980806: man page °²³] timeval ¬O·|§ïÅܪº */ + + rset = 1 | fd; + cc = select(nfds, (fd_set *) & rset, NULL, NULL, &tv /*&vio_to*/); + /* Thor.980806: man page °²³] timeval ¬O·|§ïÅܪº */ + + if (cc > 0) + { + if (fd & rset) + return I_OTHERDATA; + + cc = recv(0, data, VI_MAX, 0); + if (cc > 0) + { + vi_head = (*data) == IAC ? iac_count(data) : 0; + if (vi_head >= cc) + continue; + vi_size = cc; + +#ifdef DETAIL_IDLETIME + if (cutmp) +#else + if (idle && cutmp) +#endif + { + idle = 0; + +#ifdef DETAIL_IDLETIME + time(&cutmp->idle_time); /* Y #define DETAIL_IDLETIME¡A«h idle_time ªí¥Ü¶}©l¶¢¸mªº®É¶¡(¬í) */ +#else + cutmp->idle_time = 0; /* Y #undef DETAIL_IDLETIME¡A«h idle_time ªí¥Ü¤w¸g¶¢¸m¤F¦h¤[(¤À) */ +#endif + +#ifdef BMW_COUNT + /* itoc.010421: «ö¥ô¤@Áä«á±µ¦¬¤ô²y¼Æ¦^Âk 0 */ + cutmp->bmw_count = 0; +#endif + } + break; + } + if ((cc == 0) || (errno != EINTR)) + abort_bbs(); + } + else if (cc == 0) + { + cc = vio_to.tv_sec; + if (cc < 60) /* paging timeout : ¨C 60 ¬í§ó·s¤@¦¸ idle */ + return I_TIMEOUT; + + idle += cc / 60; + vio_to.tv_sec = cc + 60; /* Thor.980806: ¨C¦¸timeout³£¼W¥[60¬í¡A©Ò¥H¤ù¤l·U´«·UºC¡A¦nÃi:p */ + /* Thor.990201.µù¸Ñ: °£¤Ftalk_rqst¡Bchat¤§¥~¡A»Ýn¦b°Ê¤@°Ê¤§«á¡A«³]tv_sec¬°60¬í¶Ü? (¹w³]È) */ + +#ifdef TIME_KICKER + if (idle > IDLE_TIMEOUT) + { + outs("¡¹ ¶W¹L¶¢¸m®É¶¡¡I"); + refresh(); + abort_bbs(); + } + else if (idle >= IDLE_TIMEOUT - IDLE_WARNOUT) /* itoc.001222: ¶¢¸m¹L¤[ĵ§i */ + { + bell(); /* itoc.010315: ¥s¤@¤U :p */ + prints("\033[1;5;31mĵ§i\033[m±z¤w¸g¶¢¸m¹L¤[¡A¨t²Î±N¦b %d ¤ÀÄÁ«á§â±z½ð°£¡I", IDLE_WARNOUT); + refresh(); + } +#endif + +#ifndef DETAIL_IDLETIME + cutmp->idle_time = idle; +#endif + + if (bbsmode < M_XMENU) /* ¦b menu ¸Ì±n´« movie */ + { + movie(); + refresh(); + } + } + else + { + if (errno != EINTR) + abort_bbs(); + } + } + } + + cc = data[vi_head++]; + if (imode & IM_TRAIL) + { + imode ^= IM_TRAIL; + if (cc == 0 || cc == 0x0a) + continue; + } + + if (cc == 0x0d) + { + imode |= IM_TRAIL; + return '\n'; + } + + if (cc == 0x7f) + { + return KEY_BKSP; + } + + if (cc == Ctrl('L')) + { + vs_redraw(); + continue; + } + + if ((cc == Ctrl('R')) && (bbstate & STAT_STARTED) && !(bbstate & STAT_LOCK) && !(imode & IM_REPLY)) + /* lkchu.990513: Âê©w®É¤£¥i¦^°T */ + { + signal(SIGUSR1, SIG_IGN); + + /* Thor.980307: ¦b ^R ®É talk ·|¦]¨S¦³ vio_fd ¬Ý¤£¨ì I_OTHERDATA¡A¦Ó¬Ý¤£¨ì¹ï¤è¥´ªº¦r¡A©Ò¥H¦b ^R ®É¸T¤î talk */ + imode |= IM_REPLY; + bmw_reply(); + imode ^= IM_REPLY; + + signal(SIGUSR1, (void *) talk_rqst); + +#ifdef BMW_COUNT + /* itoc.010907: «ö¥ô¤@Áä«á±µ¦¬¤ô²y¼Æ¦^Âk 0 */ + cutmp->bmw_count = 0; +#endif + continue; + } + + return (cc); + } +} + + +#define MATCH_END 0x8000 +/* Thor.990204.µù¸Ñ: ¥NªíMATCH§¹µ², n¹À´N¸É¨¬, n¹À´Nºû«ù쪬, ¤£¨q¥X¥i¯àªºÈ¤F */ + +static void +match_title() +{ + move(2, 0); + clrtobot(); + vs_line("¬ÛÃö¸ê°T¤@Äýªí"); +} + + +static int +match_getch() +{ + int ch; + + outs("\n¡¹ ¦Cªí(C)Ä~Äò (Q)µ²§ô¡H[C] "); + ch = vkey(); + if (ch == 'q' || ch == 'Q') + return ch; + + move(3, 0); + clrtobot(); + return 0; +} + + +/* ----------------------------------------------------- */ +/* ¿ï¾Ü board */ +/* ----------------------------------------------------- */ + + +static BRD *xbrd; + + +BRD * +ask_board(board, perm, msg) + char *board; + int perm; + char *msg; +{ + if (msg) + { + move(2, 0); + outs(msg); + } + + if (vget(1, 0, "½Ð¿é¤J¬ÝªO¦WºÙ(«öªÅ¥ÕÁä¦Û°Ê·j´M)¡G", board, BNLEN + 1, GET_BRD | perm)) + return xbrd; + + return NULL; +} + + +static int +vget_match(prefix, len, op) + char *prefix; + int len; + int op; +{ + char *data, *hit; + char newprefix[BNLEN + 1]; /* Ä~Äò¸É§¹ªºªO¦W */ + int row, col, match; + int rlen; /* ¥i¸É§¹ªº³Ñ¾lªø«× */ + + row = 3; + col = match = rlen = 0; + + if (op & GET_BRD) + { + usint perm; + int i; + char *bits, *n, *b; + BRD *head, *tail; + + extern BCACHE *bshm; + extern char brd_bits[]; + + perm = op & (BRD_L_BIT | BRD_R_BIT | BRD_W_BIT); + bits = brd_bits; + head = bshm->bcache; + tail = head + bshm->number; + + do + { + if (perm & *bits++) + { + data = head->brdname; + + if (str_ncmp(prefix, data, len)) + continue; + + xbrd = head; + + if ((op & MATCH_END) && !data[len]) + { + strcpy(prefix, data); + return len; + } + + match++; + hit = data; + + if (op & MATCH_END) + continue; + + if (match == 1) + { + match_title(); + if (data[len]) + { + strcpy(newprefix, data); + rlen = strlen(data + len); + } + } + else if (rlen) /* LHD.051014: ÁÙ¦³¥i¸É§¹ªº¾l¦a */ + { + n = newprefix + len; + b = data + len; + for (i = 0; i < rlen && ((*n | 0x20) == (*b | 0x20)); i++, n++, b++) + ; + *n = '\0'; + rlen = i; + } + + move(row, col); + outs(data); + + col += BNLEN + 1; + if (col > b_cols - BNLEN - 1) /* Á`¦@¥i¥H©ñ b_cols / (BNLEN + 1) Äæ */ + { + col = 0; + if (++row >= b_lines) + { + if (match_getch() == 'q') + break; + + move(row = 3, 0); + clrtobot(); + } + } + } + } while (++head < tail); + } + else if (op & GET_USER) + { + struct dirent *de; + DIR *dirp; + int cc; + char fpath[16]; + + /* Thor.981203: USER name¦Ü¤Ö¥´¤@¦r, ¥Î"<="·|¤ñ¸û¦n¶Ü? */ + if (len == 0) + return 0; + + cc = *prefix; + if (cc >= 'A' && cc <= 'Z') + cc |= 0x20; + if (cc < 'a' || cc > 'z') + return 0; + + sprintf(fpath, "usr/%c", cc); + dirp = opendir(fpath); + while (de = readdir(dirp)) + { + data = de->d_name; + if (str_ncmp(prefix, data, len)) + continue; + + if (!match++) + { + match_title(); + strcpy(hit = fpath, data); /* ²Ä¤@µ§²Å¦Xªº¸ê®Æ */ + } + + move(row, col); + outs(data); + + col += IDLEN + 1; + if (col > b_cols - IDLEN - 1) /* Á`¦@¥i¥H©ñ b_cols / (IDLEN + 1) Äæ */ + { + col = 0; + if (++row >= b_lines) + { + if (match_getch()) + break; + row = 3; + } + } + } + + closedir(dirp); + } + else /* Thor.990203.µù¸Ñ: GET_LIST */ + { + LinkList *list; + extern LinkList *ll_head; + + for (list = ll_head; list; list = list->next) + { + data = list->data; + + if (str_ncmp(prefix, data, len)) + continue; + + if ((op & MATCH_END) && !data[len]) + { + strcpy(prefix, data); + return len; + } + + match++; + hit = data; + + if (op & MATCH_END) + continue; + + if (match == 1) + match_title(); + + move(row, col); + outs(data); + + col += IDLEN + 1; + if (col > b_cols - IDLEN - 1) /* Á`¦@¥i¥H©ñ b_cols / (IDLEN + 1) Äæ */ + { + col = 0; + if (++row >= b_lines) + { + if (match_getch()) + break; + row = 3; + } + } + } + } + + if (match == 1) + { + strcpy(prefix, hit); + return strlen(hit); + } + else if (rlen) + { + strcpy(prefix, newprefix); + return len + rlen; + } + + return 0; +} + + +char lastcmd[MAXLASTCMD][80]; + + +/* bbs.h: Flags to getdata input function */ +/* NOECHO 0x0000 ¤£Åã¥Ü¡A¥Î©ó±K½X¨ú±o */ +/* DOECHO 0x0100 ¤@¯ëÅã¥Ü */ +/* LCECHO 0x0200 low case echo¡A´«¦¨¤p¼g */ +/* GCARRY 0x0400 ·|Åã¥Ü¤W¤@¦¸/¥Ø«eªºÈ */ + +int +vget(line, col, prompt, data, max, echo) + int line, col; + uschar *prompt, *data; + int max, echo; +{ + int ch, len; + int x, y; + int i, next; + int vlen, hlen; + + /* itoc.010312: ¥ý¬ö¿ý¦ì¸m ¦]¬°«á± line ©M prompt ³£³Q§ó§ï¤F */ + vlen = line; + hlen = col + strlen(prompt); + + if (prompt) + { + move(line, col); + clrtoeol(); + outs(prompt); + } + else + { + clrtoeol(); + } + + STANDOUT; + + x = cur_row; + y = cur_col; + + if (echo & GCARRY) + { + if (len = strlen(data)) + outs(data); + } + else + { + len = 0; + } + + /* --------------------------------------------------- */ + /* ¨ú±o board / userid / on-line user */ + /* --------------------------------------------------- */ + + ch = len; + do + { + outc(' '); + } while (++ch < max); + + STANDEND; + + line = -1; + col = len; + max--; + + for (;;) + { + move(x, y + col); + ch = vkey(); + if (ch == '\n') + { + data[len] = '\0'; + if ((echo & (GET_BRD | GET_LIST)) && len > 0) + /* Thor.990204:n¨D¿é¤J¥ô¤@¦r¤~¥Nªí¦Û°Ê match, §_«hºâcancel */ + { + ch = len; + len = vget_match(data, len, echo | MATCH_END); + if (len > ch) + { + move(x, y); + outs(data); + } + else if (len == 0) + { + data[0] = '\0'; + } + } + break; + } + if (ch == Ctrl('U')) + ch = KEY_ESC; + + if (isprint2(ch)) + { + if (ch == ' ' && (echo & (GET_USER | GET_BRD | GET_LIST))) + { + ch = vget_match(data, len, echo); + if (ch > len) + { + move(x, y); + outs(data); + col = len = ch; + } + continue; + } + + if (len >= max) + continue; + + /* ----------------------------------------------- */ + /* insert data and display it */ + /* ----------------------------------------------- */ + + prompt = &data[col]; + i = col; + move(x, y + col); + + for (;;) + { +// outc(echo ? ch : '*'); + outc((echo && ch != KEY_ESC) ? ch : '*'); + next = *prompt; + *prompt++ = ch; + if (i >= len) + break; + i++; + ch = next; + } + col++; + len++; + continue; + } + + /* ----------------------------------------------- */ + /* ¿é¤J password ®É¥u¯à«ö BackSpace */ + /* ----------------------------------------------- */ + + if (!echo && ch != KEY_BKSP) + continue; + + switch (ch) + { + case Ctrl('D'): + + if (col >= len) + continue; + + col++; + + case KEY_BKSP: + + if (!col) + continue; + + /* ----------------------------------------------- */ + /* remove data and display it */ + /* ----------------------------------------------- */ + + len--; + col--; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: §PÂ_²{¦b§R°£ªº¦ì¸m¬O§_¬°º~¦rªº«á¥b¬q¡AY¬O§R¤G¦r¤¸ */ + if ((cuser.ufo & UFO_ZHC) && echo && col && IS_ZHC_LO(data, col)) + { + len--; + col--; + next = 2; + } + else +#endif + next = 1; + move(x, y + col); + for (i = col; i < len; i++) + { + data[i] = ch = data[i + next]; + outc(echo ? ch : '*'); + } + while (next--) + outc(' '); + break; + + case KEY_DEL: + + if (col >= len) + continue; + + /* ----------------------------------------------- */ + /* remove data and display it */ + /* ----------------------------------------------- */ + + len--; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: §PÂ_²{¦b§R°£ªº¦ì¸m¬O§_¬°º~¦rªº«e¥b¬q¡AY¬O§R¤G¦r¤¸ */ + if ((cuser.ufo & UFO_ZHC) && col < len && IS_ZHC_HI(data[col])) + { + len--; + next = 2; + } + else +#endif + next = 1; + for (i = col; i < len; i++) + { + data[i] = ch = data[i + next]; + outc(ch); + } + while (next--) + outc(' '); + break; + + case KEY_LEFT: + case Ctrl('B'): + if (col) + { + col--; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: ¥ª²¾®É¸I¨ìº~¦r²¾Âù®æ */ + if ((cuser.ufo & UFO_ZHC) && col && IS_ZHC_LO(data, col)) + col--; +#endif + } + break; + + case KEY_RIGHT: + case Ctrl('F'): + if (col < len) + { + col++; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: ¥k²¾®É¸I¨ìº~¦r²¾Âù®æ */ + if ((cuser.ufo & UFO_ZHC) && col < len && IS_ZHC_HI(data[col - 1])) + col++; +#endif + } + break; + + case KEY_HOME: + case Ctrl('A'): + col = 0; + break; + + case KEY_END: + case Ctrl('E'): + col = len; + break; + + case Ctrl('C'): /* clear / reset */ + if (len) + { + move(x, y); + for (ch = 0; ch < len; ch++) + outc(' '); + col = len = 0; + } + break; + + case KEY_DOWN: + case Ctrl('N'): + + line += MAXLASTCMD - 2; + + case KEY_UP: + case Ctrl('P'): + + line = (line + 1) % MAXLASTCMD; + prompt = lastcmd[line]; + col = 0; + move(x, y); + + do + { + if (!(ch = *prompt++)) + { + /* clrtoeol */ + + for (ch = col; ch < len; ch++) + outc(' '); + break; + } + +#if 0 /* ¤£»Ýn¡A¦]¬° bmtad/receive_article ·| strip ¨ì ansi code */ + if (ch == KEY_ESC) /* itoc.020601: ¤£±o¨Ï¥Î±±¨î½X */ + ch = '*'; +#endif + + outc(ch); + data[col] = ch; + } while (++col < max); + + len = col; + break; + + case Ctrl('K'): /* delete to end of line */ + if (col < len) + { + move(x, y + col); + for (ch = col; ch < len; ch++) + outc(' '); + len = col; + } + break; + case Ctrl('G'): + /* lantw44: ¥þ«¬¦r°»´ú¤Á´« (Ctrl Áä ³£³Q¥Î¥ú¤F©Ò¥H¥Î³oÓ) */ + cuser.ufo ^= UFO_ZHC; + if(cuser.ufo & UFO_ZHC){ + vmsg("¥þ«¬¦r°»´ú¶}±Ò"); + }else{ + vmsg("¥þ«¬¦r°»´úÃö³¬"); + } + break; + + /* itoc.030619: Åý vget ¤¤ÁÙ¯à«ö ^R ¿ï¤ô²y */ + case Ctrl('R'): + case Ctrl('T'): + if (bbsmode == M_BMW_REPLY) + { + if (bmw_reply_CtrlRT(ch)) /* ¦³¦hÁû¤ô²y */ + { + data[len] = '\0'; + return ch; + } + } + break; + } + } + + if (len >= 2 && echo) + { + for (line = MAXLASTCMD - 1; line; line--) + strcpy(lastcmd[line], lastcmd[line - 1]); + strcpy(lastcmd[0], data); + } + + move(vlen, strlen(data) + hlen); /* itoc.010312: ©T©w²¾¨ì¸Ó¦C¦C§À¦A¦L¥X'\n' */ + outc('\n'); + + ch = data[0]; + if ((echo & LCECHO) && (ch >= 'A' && ch <= 'Z')) + data[0] = (ch |= 0x20); + + return ch; +} + + +int +vans(prompt) + char *prompt; +{ + char ans[3]; + + /* itoc.010812.µù¸Ñ: ·|¦Û°Ê´«¦¨¤p¼gªº */ + return vget(b_lines, 0, prompt, ans, sizeof(ans), LCECHO); +} + + +int +vkey() +{ + int mode; + int ch, last; + + mode = last = 0; + for (;;) + { + ch = igetch(); + if (mode == 0) /* Normal Key */ + { + if (ch == KEY_ESC) + mode = 1; + else + return ch; + } + else if (mode == 1) /* Escape sequence */ + { + if (ch == '[' || ch == 'O') + mode = 2; + else if (ch == '1' || ch == '4') + mode = 3; + else + return Esc(ch); + } + else if (mode == 2) /* Cursor key */ + { + if (ch >= 'A' && ch <= 'D') + return KEY_UP - (ch - 'A'); + else if (ch >= '1' && ch <= '6') + mode = 3; + else + return ch; + } + else if (mode == 3) /* Ins Del Home End PgUp PgDn */ + { + if (ch == '~') + return KEY_HOME - (last - '1'); + else + return ch; + } + last = ch; + } +} diff --git a/maple/window.c b/maple/window.c new file mode 100644 index 0000000..d5f9dee --- /dev/null +++ b/maple/window.c @@ -0,0 +1,439 @@ +/*-------------------------------------------------------*/ +/* window.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : popup window menu */ +/* create : 03/02/12 */ +/* update : 03/07/23 */ +/* author : verit.bbs@bbs.yzu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_POPUPMENU + +static screenline slt[T_LINES]; +static int x_roll; + + +/* ----------------------------------------------------- */ +/* µe±Ã¸»s */ +/* ----------------------------------------------------- */ + + +static void +draw_line(x, y, msg) /* ¦b (x, y) ªº¦ì¸m¶ë¤J msg¡A¥ª¥k¤´n¦L¥Xì¨Óªº±m¦â¤å¦r */ + int x, y; + uschar *msg; +{ + uschar *str, *ptr; + uschar data[ANSILINELEN]; + char color[4]; + int ch, i; + int len; + int ansi; /* 1: ¦b ANSI ¤¤ */ + int in_chi = 0; /* 1: ¦b¤¤¤å¦r¤¤ */ + int fg, bg, hl; /* «e´º/I´º/°ª±m */ + + hl = 0; + fg = 37; + bg = 40; + + i = x + x_roll; + if (i > b_lines) + i -= b_lines + 1; + + memset(data, 0, sizeof(data)); + strncpy(data, slt[i].data, slt[i].len); + str = data; + + move(x, 0); + clrtoeol(); + + /* ¦L¥X (x, 0) ¦Ü (x, y - 1) */ + ansi = 0; + len = 0; /* ¤w¦L¥X´XÓ¦r (¤£§t±±¨î½X) */ + while (ch = *str++) + { + if (ch == KEY_ESC) + { + ansi = 1; + i = 0; + } + else if (ansi) + { + if (ch == '[') + { + } + else if (ch >= '0' && ch <= '9') + { + color[i] = ch; + if (++i >= 4) + i = 0; + } + else + { + color[i] = 0; + + i = atoi(color); + if (i == 0) + { + hl = 0; + fg = 37; + bg = 40; + } + else if (i == 1) + hl = 1; + else if (i >= 30 && i <= 37) + fg = i; + else if (i >= 40 && i <= 47) + bg = i; + + i = 0; + + if (ch != ';') + ansi = 0; + } + } + else + { + if (++len >= y) + { + /* ³Ì«á¤@¦rY¬O¤¤¤å¦rªºº½X¡A´N¤£¦L */ + if (!in_chi && IS_ZHC_HI(ch)) + { + outc(' '); + in_chi = 1; + } + else + { + outc(ch); + in_chi = 0; + } + outs(str_ransi); + break; + } + + if (in_chi || IS_ZHC_HI(ch)) + in_chi ^= 1; + } + + outc(ch); + } + while (len++ < y) + outc(' '); + + /* ¦L¥X (x, y) ¦Ü (x, y + strip_ansi_len(msg) - 1) */ + ptr = msg; + ansi = 0; + len = 0; /* msg ªºªø«×(¤£§t±±¨î½X) */ + while (ch = *ptr++) + { + if (ch == KEY_ESC) + { + ansi = 1; + } + else if (ansi) + { + if ((ch < '0' || ch > '9') && ch != ';' && ch != '[') + ansi = 0; + } + else + { + len++; + } + outc(ch); + } + + /* ¸õ±¼ str ¤¤¶¡¤@¾ã¬q¡A¨Ã¨ú¥X³Ì«áªºÃC¦â */ + ansi = 0; + while (ch = *str++) + { + if (ch == KEY_ESC) + { + ansi = 1; + i = 0; + } + else if (ansi) + { + if (ch == '[') + continue; + if (ch >= '0' && ch <= '9') + { + color[i] = ch; + if (++i >= 4) + i = 0; + } + else + { + color[i] = 0; + + i = atoi(color); + if (i == 0) + { + hl = 0; + fg = 37; + bg = 40; + } + else if (i == 1) + hl = 1; + else if (i >= 30 && i <= 37) + fg = i; + else if (i >= 40 && i <= 47) + bg = i; + + i = 0; + + if (ch != ';') + ansi = 0; + } + } + else + { + if (--len < 0) /* ¸õ¹L strip_ansi_len(msg) ªºªø«× */ + break; + + if (in_chi || IS_ZHC_HI(ch)) + in_chi ^= 1; + } + } + + /* ¦L¥X (x, y + strip_ansi_len(msg)) ³oÓ¦r¤Î«á±ªº±±¨î½X */ + prints("\033[%d;%d;%dm", hl, fg, bg); + /* ¦¹¦rY¬O¤¤¤å¦rªº§À½X¡A´N¤£¦L */ + outc(in_chi ? ' ' : ch); + + /* ¦L¥X (x, y + strip_ansi_len(msg) + 1) ¦Ü ¦æ§À */ + outs(str); + outs(str_ransi); +} + + +#ifdef POPUP_ANSWER + +/* ----------------------------------------------------- */ +/* ¿ï¶µÃ¸»s */ +/* ----------------------------------------------------- */ + + +static int +draw_item(x, y, desc, hotkey, mode) + int x, y; + char *desc; + char hotkey; + int mode; /* 0:²M°£¥ú´Î 1:µe¤W¥ú´Î */ +{ + char buf[128]; + + sprintf(buf, " ¢x%s%c %c%c%c%-25s \033[m¢x ", + mode ? COLOR4 : "\033[30;47m", mode ? '>' : ' ', + (hotkey == *desc) ? '[' : '(', *desc, + (hotkey == *desc) ? ']' : ')', desc + 1); + + draw_line(x, y, buf); +} + + +static int /* ¦^¶ÇÁ`¦@¦³´XÓ¿ï¶µ */ +draw_menu(x, y, title, desc, hotkey, cur) + int x, y; + char *title; + char *desc[]; + char hotkey; + int *cur; /* ¦^¶Ç¹w³]ȩҦb¦ì¸m */ +{ + int i, meet; + char buf[128]; + + draw_line(x++, y, " ¢~¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢¡ "); + + sprintf(buf, " ¢x" COLOR4 " %-28s \033[m¢x ", title); + draw_line(x++, y, buf); + + draw_line(x++, y, " ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t "); + + for (i = 1; desc[i]; i++) + { + meet = (desc[i][0] == hotkey); + draw_item(x++, y, desc[i], hotkey, meet); + if (meet) + *cur = i; + } + + draw_line(x, y, " ¢¢¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢£ "); + + /* Á×§K¦b°»´ú¥ª¥kÁä¥þ§Î¤U¡A«ö¥ªÁä·|¸õÂ÷¤G¼h¿ï³æªº°ÝÃD */ + move(b_lines, 0); + + return i - 1; +} + + +/* ----------------------------------------------------- */ +/* §ä¿ï¶µ */ +/* ----------------------------------------------------- */ + + +static int /* -1:§ä¤£¨ì >=0:²Ä´XÓ¿ï¶µ */ +find_cur(ch, max, desc) /* §ä ch ³oÓ«öÁä¬O²Ä´XÓ¿ï¶µ */ + int ch, max; + char *desc[]; +{ + int i, cc; + + if (ch >= 'A' && ch <= 'Z') + ch |= 0x20; /* ´«¤p¼g */ + + for (i = 1; i <= max; i++) + { + cc = desc[i][0]; + if (cc >= 'A' && cc <= 'Z') + cc |= 0x20; /* ´«¤p¼g */ + + if (ch == cc) + return i; + } + + return -1; +} + + +/*------------------------------------------------------ */ +/* ¸ß°Ý¿ï¶µ¡A¥i¥Î¨Ó¨ú¥N vans() */ +/*------------------------------------------------------ */ +/* x, y ¬OÂÛ¥Xµøµ¡¥ª¤W¨¤ªº (x, y) ¦ì¸m */ +/* title ¬Oµøµ¡ªº¼ÐÃD */ +/* desc ¬O¿ï¶µªº±Ôz¡G */ +/* ²Ä¤@Ó¦r¦ê¥²¶·¬°¨âÓ char */ +/* ²Ä¤@Ó¦r¤¸¥Nªí¤@¶}©l´å¼Ð°±ªº¦ì¸m */ +/* ²Ä¤GÓ¦r¤¸¥Nªí«ö¤U KEY_LEFT ªº¹w³]¦^¶ÇÈ */ +/* ¤¤¶¡ªº¦r¦ê¬O¨CÓ¿ï¶µªº±Ôz (º¦r¥À¬°¼öÁä) */ +/* ³Ì«á¤@Ó¦r¦ê¥²¶·¬° NULL */ +/*------------------------------------------------------ */ + + +int /* ¶Ç¦^¤p¼g¦r¥À©Î¼Æ¦r */ +pans(x, y, title, desc) + int x, y; + char *title; + char *desc[]; +{ + int cur, old_cur, max, ch; + char hotkey; + + x_roll = vs_save(slt); + + hotkey = desc[0][0]; + + /* µe¥X¾ãÓ¿ï³æ */ + max = draw_menu(x, y, title, desc, hotkey, &cur); + x += 2; + + /* ¤@¶i¤J¡A´å¼Ð°±¦b¹w³]È */ + old_cur = cur; + + while (1) + { + switch (ch = vkey()) + { + case KEY_LEFT: + case KEY_RIGHT: + case '\n': + vs_restore(slt); + ch = (ch == KEY_LEFT) ? desc[0][1] : desc[cur][0]; + if (ch >= 'A' && ch <= 'Z') + ch |= 0x20; /* ¦^¶Ç¤p¼g */ + return ch; + + case KEY_UP: + cur = (cur == 1) ? max : cur - 1; + break; + + case KEY_DOWN: + cur = (cur == max) ? 1 : cur + 1; + break; + + case KEY_HOME: + cur = 1; + break; + + case KEY_END: + cur = max; + break; + + default: /* ¥h§ä©Ò«öÁä¬Oþ¤@Ó¿ï¶µ */ + if ((ch = find_cur(ch, max, desc)) > 0) + cur = ch; + break; + } + + if (old_cur != cur) /* ´å¼ÐÅܰʦì¸m¤~»Ýn«Ã¸ */ + { + draw_item(x + old_cur, y, desc[old_cur], hotkey, 0); + draw_item(x + cur, y, desc[cur], hotkey, 1); + old_cur = cur; + /* Á×§K¦b°»´ú¥ª¥kÁä¥þ§Î¤U¡A«ö¥ªÁä·|¸õÂ÷¤G¼h¿ï³æªº°ÝÃD */ + move(b_lines, 0); + } + } +} +#endif /* POPUP_ANSWER */ + + +#ifdef POPUP_MESSAGE +/*------------------------------------------------------ */ +/* ÂÛ¥X¦¡µøµ¡°T®§¡A¥i¥Î¨Ó¨ú¥N vmsg() */ +/*------------------------------------------------------ */ + + +int +pmsg(msg) + char *msg; /* ¤£¥i¬° NULL */ +{ + int len, x, y, i; + char buf[80]; + + x_roll = vs_save(slt); + + len = strlen(msg); + if (len < 16) /* ¨ú msg title ¨ä¤¤¸ûªøªÌ¬° len */ + len = 16; + if (len % 2) /* Åܦ¨°¸¼Æ */ + len++; + x = (b_lines - 4) >> 1; /* ¸m¤¤ */ + y = (b_cols - 8 - len) >> 1; + + strcpy(buf, "¢~"); + for (i = -4; i < len; i += 2) + strcat(buf, "¢w"); + strcat(buf, "¢¡"); + draw_line(x++, y, buf); + + sprintf(buf, "¢x" COLOR4 " %-*s \033[m¢x", len, "½Ð«ö¥ô·NÁäÄ~Äò.."); + draw_line(x++, y, buf); + + strcpy(buf, "¢u"); + for (i = -4; i < len; i += 2) + strcat(buf, "¢w"); + strcat(buf, "¢t"); + draw_line(x++, y, buf); + + sprintf(buf, "¢x\033[30;47m %-*s \033[m¢x", len, msg); + draw_line(x++, y, buf); + + strcpy(buf, "¢¢"); + for (i = -4; i < len; i += 2) + strcat(buf, "¢w"); + strcat(buf, "¢£"); + draw_line(x++, y, buf); + + move(b_lines, 0); + + x = vkey(); + vs_restore(slt); + return x; +} +#endif /* POPUP_MESSAGE */ + +#endif /* HAVE_POPUPMENU */ diff --git a/maple/xover.c b/maple/xover.c new file mode 100644 index 0000000..3329972 --- /dev/null +++ b/maple/xover.c @@ -0,0 +1,1788 @@ +/*-------------------------------------------------------*/ +/* xover.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : board/mail interactive reading routines */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef MY_FAVORITE +#define MSG_ZONE_SWITCH "§Ö³t¤Á´«¡G(A)ºëµØ (B)¤å³¹ (C)¬ÝªO (F)³Ì·R (M)«H¥ó (U)¨Ï¥ÎªÌ (W)¤ô²y (S)Â^«Ì¡G" +#else +#define MSG_ZONE_SWITCH "§Ö³t¤Á´«¡G(A)ºëµØ (B)¤å³¹ (C)¬ÝªO (M)«H¥ó (U)¨Ï¥ÎªÌ (W)¤ô²y (S)Â^«Ì¡G" +#endif + + +/* ----------------------------------------------------- */ +/* keep xover record */ +/* ----------------------------------------------------- */ + + +static XO *xo_root; /* root of overview list */ + + +XO * +xo_new(path) + char *path; +{ + XO *xo; + int len; + + len = strlen(path) + 1; + + xo = (XO *) malloc(sizeof(XO) + len); + + memcpy(xo->dir, path, len); + + return xo; +} + + +XO * +xo_get(path) + char *path; +{ + XO *xo; + + for (xo = xo_root; xo; xo = xo->nxt) + { + if (!strcmp(xo->dir, path)) + return xo; + } + + xo = xo_new(path); + xo->nxt = xo_root; + xo_root = xo; + xo->xyz = NULL; + xo->pos = XO_TAIL; /* ²Ä¤@¦¸¶i¤J®É¡A±N´å¼Ð©ñ¦b³Ì«á± */ + + return xo; +} + + +#ifdef AUTO_JUMPPOST +XO * +xo_get_post(path, brd) /* itoc.010910: °Ñ¦Ò xover.c xo_get()¡A¬° XoPost ¶q¨¥´³y */ + char *path; + BRD *brd; +{ + XO *xo; + time_t chrono; + int fd; + int pos, locus, mid; /* locus:¥ª«ü¼Ð mid:¤¤«ü¼Ð pos:¥k«ü¼Ð */ + + for (xo = xo_root; xo; xo = xo->nxt) + { + if (!strcmp(xo->dir, path)) + return xo; + } + + xo = xo_new(path); + xo->nxt = xo_root; + xo_root = xo; + xo->xyz = NULL; + + /* ©|¥¼§ó·s brd->blast ©Î ³Ì«á¤@½g¤wŪ ©Î ¥u¦³¤@½g¡A«h´å¼Ðª½±µ©ñ³Ì«á */ + if (brd->btime < 0 || !brh_unread(brd->blast) || + (pos = rec_num(path, sizeof(HDR))) <= 1 || (fd = open(path, O_RDONLY)) < 0) + { + xo->pos = XO_TAIL; /* ´å¼Ð©ñ¦b³Ì«á± */ + return xo; + } + + /* §ä²Ä¤@½g¥¼Åª binary search */ + pos--; + locus = 0; + while (1) + { + if (pos <= locus + 1) + break; + + mid = locus + ((pos - locus) >> 1); + lseek(fd, (off_t) (sizeof(HDR) * mid), SEEK_SET); + if (read(fd, &chrono, sizeof(time_t)) == sizeof(time_t)) + { + if (brh_unread(chrono)) + pos = mid; + else + locus = mid; + } + else + { + break; + } + } + + /* ¯S¨Ò: ¦pªG¥k«ü¼Ð°±¯d¦b 1¡A¦³¤GºØ¥i¯à¡A¤@¬O«êŪ¨ì²Ä¤G½g¡A¥t¤@¬°³s²Ä¤@½g³£¨SŪ */ + if (pos == 1) + { + /* Àˬd²Ä¤@½g¬O§_¤wŪ */ + lseek(fd, (off_t) 0, SEEK_SET); + if (read(fd, &chrono, sizeof(time_t)) == sizeof(time_t)) + { + if (brh_unread(chrono)) /* Y³s²Ä¤@½g¤]¥¼Åª¡Apos ½Õ¦^¥h²Ä¤@½g */ + pos = 0; + } + } + + close(fd); + xo->pos = pos; /* ²Ä¤@¦¸¶i¤J®É¡A±N´å¼Ð©ñ¦b²Ä¤@½g¥¼Åª */ + + return xo; +} +#endif + + +#if 0 +void +xo_free(xo) + XO *xo; +{ + char *ptr; + + if (ptr = xo->xyz) + free(ptr); + free(xo); +} +#endif + + +/* ----------------------------------------------------- */ +/* interactive menu routines */ +/* ----------------------------------------------------- */ + + +char xo_pool[(T_LINES - 4) * XO_RSIZ]; /* XO's data I/O pool */ + + +void +xo_load(xo, recsiz) + XO *xo; + int recsiz; +{ + int fd, max; + + max = 0; + if ((fd = open(xo->dir, O_RDONLY)) >= 0) + { + int pos, top; + struct stat st; + + fstat(fd, &st); + max = st.st_size / recsiz; + if (max > 0) + { + pos = xo->pos; + if (pos <= 0) + { + pos = top = 0; + } + else + { + top = max - 1; + if (pos > top) + pos = top; + top = (pos / XO_TALL) * XO_TALL; + } + xo->pos = pos; + xo->top = top; + + lseek(fd, (off_t) (recsiz * top), SEEK_SET); + read(fd, xo_pool, recsiz * XO_TALL); + } + close(fd); + } + + xo->max = max; +} + + +int /* XO_LOAD:§R°£ XO_FOOT:¨ú®ø */ +xo_rangedel(xo, size, fchk, fdel) /* itoc.031001: °Ï¬q§R°£ */ + XO *xo; + int size; + int (*fchk) (); /* Àˬd°Ï¬q¤¤¬O§_¦³³Q«OÅ@ªº°O¿ý 0:§R°£ 1:«OÅ@ */ + void (*fdel) (); /* °£¤F§R°£°O¿ý¥H¥~¡AÁÙn°µ¨Ç¤°»ò¨Æ */ +{ + char ans[8]; + int head, tail; + + vget(b_lines, 0, "[³]©w§R°£½d³ò] °_ÂI¡G", ans, 6, DOECHO); + head = atoi(ans); + if (head <= 0) + { + zmsg("°_ÂI¦³»~"); + return XO_FOOT; + } + + vget(b_lines, 28, "²×ÂI¡G", ans, 6, DOECHO); + tail = atoi(ans); + if (tail < head) + { + zmsg("²×ÂI¦³»~"); + return XO_FOOT; + } + + if (vget(b_lines, 41, msg_sure_ny, ans, 3, LCECHO) == 'y') + { + int fd, total; + char *data, *phead, *ptail; + struct stat st; + + if ((fd = open(xo->dir, O_RDONLY)) < 0) + return XO_FOOT; + + fstat(fd, &st); + total = st.st_size; + head = (head - 1) * size; + tail = tail * size; + if (head > total) + { + close(fd); + return XO_FOOT; + } + if (tail > total) + tail = total; + + data = (char *) malloc(total); + read(fd, data, total); + close(fd); + + total -= tail; + phead = data + head; + ptail = data + tail; + + if (fchk || fdel) + { + char *ptr; + for (ptr = phead; ptr < ptail; ptr += size) + { + if (fchk && fchk(ptr)) /* ³oµ§°O¿ý«OÅ@¤£³Q¬å */ + { + memcpy(phead, ptr, size); + phead += size; + head += size; + } + else if (fdel) /* °£¤F§R°£°O¿ý¡AÁÙn°µ fdel() */ + { + fdel(xo, ptr); + } + } + } + + memcpy(phead, ptail, total); + + if ((fd = open(xo->dir, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0) + { + write(fd, data, total + head); + close(fd); + } + + free(data); + return XO_LOAD; + } + return XO_FOOT; +} + + +/* ----------------------------------------------------- */ +/* Tag List ¼ÐÅÒ */ +/* ----------------------------------------------------- */ + + +int TagNum; /* tag's number */ +TagItem TagList[TAG_MAX]; /* ascending list */ + + +int +Tagger(chrono, recno, op) + time_t chrono; + int recno; + int op; /* op : TAG_NIN / TOGGLE / INSERT */ +/* ----------------------------------------------------- */ +/* return 0 : not found / full */ +/* 1 : add */ +/* -1 : remove */ +/* ----------------------------------------------------- */ +{ + int head, tail, pos, cmp; + TagItem *tagp; + + for (head = 0, tail = TagNum - 1, tagp = TagList, cmp = 1; head <= tail;) + { + pos = (head + tail) >> 1; + cmp = tagp[pos].chrono - chrono; + if (!cmp) + { + break; + } + else if (cmp < 0) + { + head = pos + 1; + } + else + { + tail = pos - 1; + } + } + + if (op == TAG_NIN) + { + if (!cmp && recno) /* µ´¹ïÄYÂÔ¡G³s recno ¤@°_¤ñ¹ï */ + cmp = recno - tagp[pos].recno; + return cmp; + } + + tail = TagNum; + + if (!cmp) + { + if (op != TAG_TOGGLE) + return 0; + + TagNum = --tail; + memcpy(&tagp[pos], &tagp[pos + 1], (tail - pos) * sizeof(TagItem)); + return -1; + } + + if (tail < TAG_MAX) + { + TagItem buf[TAG_MAX]; + + TagNum = tail + 1; + tail = (tail - head) * sizeof(TagItem); + tagp += head; + memcpy(buf, tagp, tail); + tagp->chrono = chrono; + tagp->recno = recno; + memcpy(++tagp, buf, tail); + return 1; + } + + /* TagList is full */ + + bell(); + return 0; +} + + +void +EnumTag(data, dir, locus, size) + void *data; + char *dir; + int locus; + int size; +{ + rec_get(dir, data, size, TagList[locus].recno); +} + + +int +AskTag(msg) + char *msg; +/* ----------------------------------------------------- */ +/* return value : */ +/* -1 : ¨ú®ø */ +/* 0 : single article */ +/* o.w. : whole tag list */ +/* ----------------------------------------------------- */ +{ + char buf[80]; + int num; + + num = TagNum; + + if (num) /* itoc.020130: ¦³ TagNum ¤~°Ý */ + { + sprintf(buf, "¡» %s A)³æ½g¤å³¹ T)¼Ð°O¤å³¹ Q)Â÷¶}¡H[%c] ", msg, num ? 'T' : 'A'); + switch (vans(buf)) + { + case 'q': + return -1; + + case 'a': + return 0; + } + } + return num; +} + + +/* ----------------------------------------------------- */ +/* tag articles according to title / author */ +/* ----------------------------------------------------- */ + + +static int +xo_tag(xo, op) + XO *xo; + int op; +{ + int fsize, count; + char *token, *fimage; + HDR *head, *tail; + + fimage = f_map(xo->dir, &fsize); + if (fimage == (char *) -1) + return XO_NONE; + + head = (HDR *) xo_pool + (xo->pos - xo->top); + if (op == Ctrl('A')) + { + token = head->owner; + op = 0; + } + else + { + token = str_ttl(head->title); + op = 1; + } + + head = (HDR *) fimage; + tail = (HDR *) (fimage + fsize); + + count = 0; + + do + { + if (!strcmp(token, op ? str_ttl(head->title) : head->owner)) + { + if (!Tagger(head->chrono, count, TAG_INSERT)) + break; + } + count++; + } while (++head < tail); + + munmap(fimage, fsize); + return XO_BODY; +} + + +int /* XO_LOAD:§R°£ XO_FOOT/XO_NONE:¨ú®ø */ +xo_prune(xo, size, fvfy, fdel) /* itoc.031003: ¼ÐÅÒ§R°£ */ + XO *xo; + int size; + int (*fvfy) (); /* Àˬd°Ï¬q¤¤¬O§_¦³³Q«OÅ@ªº°O¿ý 0:§R°£ 1:«OÅ@ */ + void (*fdel) (); /* °£¤F§R°£°O¿ý¥H¥~¡AÁÙn°µ¨Ç¤°»ò¨Æ */ +{ + int fd, total, pos; + char *data, *phead, *ptail, *ptr; + char buf[80]; + struct stat st; + + if (!TagNum) + return XO_NONE; + + sprintf(buf, "½T©wn§R°£ %d ½g¼ÐÅÒ¶Ü(Y/N)¡H[N] ", TagNum); + if (vans(buf) != 'y') + return XO_FOOT; + + if ((fd = open(xo->dir, O_RDONLY)) < 0) + return XO_FOOT; + + fstat(fd, &st); + data = (char *) malloc(total = st.st_size); + total = read(fd, data, total); + close(fd); + + phead = data; + ptail = data + total; + pos = 0; + total = 0; + + for (ptr = phead; ptr < ptail; ptr += size) + { + if (fvfy(ptr, pos)) /* ³oµ§°O¿ý«OÅ@¤£³Q¬å */ + { + memcpy(phead, ptr, size); + phead += size; + total += size; + } + else if (fdel) /* °£¤F§R°£°O¿ý¡AÁÙn°µ fdel() */ + { + fdel(xo, ptr); + } + pos++; + } + + if ((fd = open(xo->dir, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0) + { + write(fd, data, total); + close(fd); + } + + free(data); + + TagNum = 0; + + return XO_LOAD; +} + + +/* ----------------------------------------------------- */ +/* Tag's batch operation routines */ +/* ----------------------------------------------------- */ + + +extern BCACHE *bshm; /* lkchu.981229 */ + + +static int +xo_tbf(xo) + XO *xo; +{ + char fpath[128], *dir; + HDR *hdr, xhdr; + int tag, locus, xmode; + FILE *fp; + + if (!cuser.userlevel) + return XO_NONE; + + tag = AskTag("«þ¨©¨ì¼È¦sÀÉ"); + if (tag < 0) + return XO_FOOT; + + if (!(fp = tbf_open())) + return XO_FOOT; + + hdr = tag ? &xhdr : (HDR *) xo_pool + xo->pos - xo->top; + + locus = 0; + dir = xo->dir; + + do + { + if (tag) + { + fputs(str_line, fp); + EnumTag(hdr, dir, locus, sizeof(HDR)); + } + + xmode = hdr->xmode; + + /* itoc.000319: ×¥¿¨î¯Å¤å³¹¤£±o¶×¤J¼È¦sÀÉ */ + /* itoc.010602: GEM_RESTRICT ©M POST_RESTRICT ¤Ç°t¡A©Ò¥H¥[±K¤å³¹¤]¤£±o¶×¤J¼È¦sÀÉ */ + if (xmode & (GEM_RESTRICT | GEM_RESERVED)) + continue; + + if (!(xmode & GEM_FOLDER)) /* ¬d hdr ¬O§_ plain text */ + { + hdr_fpath(fpath, dir, hdr); + f_suck(fp, fpath); + } + } while (++locus < tag); + + fclose(fp); + zmsg("«þ¨©§¹¦¨"); + + return XO_FOOT; +} + + +static int +xo_forward(xo) + XO *xo; +{ + static char rcpt[64]; + char fpath[64], folder[64], *dir, *title, *userid; + HDR *hdr, xhdr; + int tag, locus, userno, cc, xmode; + int method; /* Âà±H¨ì 0:¯¸¥~ >0:¦Û¤v <0:¨ä¥L¯¸¤º¨Ï¥ÎªÌ */ + + if (!cuser.userlevel || HAS_PERM(PERM_DENYMAIL)) + return XO_NONE; + + tag = AskTag("Âà±H"); + if (tag < 0) + return XO_FOOT; + + if (!rcpt[0]) + strcpy(rcpt, cuser.email); + + if (!vget(b_lines, 0, "¥Øªº¦a¡G", rcpt, sizeof(rcpt), GCARRY)) + return XO_FOOT; + + userid = cuser.userid; + userno = 0; + + if (!mail_external(rcpt)) /* ¤¤³~ÄdºI */ + { + if (!str_cmp(rcpt, userid)) + { + /* userno = cuser.userno; */ /* Thor.981027: ±Hºë¿ï¶°µ¹¦Û¤v¤£³qª¾¦Û¤v */ + method = 1; + } + else + { + if (!HAS_PERM(PERM_LOCAL)) + return XO_FOOT; + + if ((userno = acct_userno(rcpt)) <= 0) + { + zmsg(err_uid); + return XO_FOOT; + } + method = -1; + } + + usr_fpath(folder, rcpt, fn_dir); + } + else + { + if (!HAS_PERM(PERM_INTERNET)) + { + vmsg("±zµLªk±H«H¨ì¯¸¥~"); + return XO_FOOT; + } + + if (not_addr(rcpt)) + { + zmsg(err_email); + return XO_FOOT; + } + + method = 0; + } + + hdr = tag ? &xhdr : (HDR *) xo_pool + xo->pos - xo->top; + + dir = xo->dir; + title = hdr->title; + locus = 0; + cc = -1; + + do + { + if (tag) + EnumTag(hdr, dir, locus, sizeof(HDR)); + + xmode = hdr->xmode; + + /* itoc.000319: ×¥¿¨î¯Å¤å³¹¤£±oÂà±H */ + /* itoc.010602: GEM_RESTRICT ©M POST_RESTRICT ¤Ç°t¡A©Ò¥H¥[±K¤å³¹¤]¤£±oÂà±H */ + if (xmode & (GEM_RESTRICT | GEM_RESERVED)) + continue; + + if (!(xmode & GEM_FOLDER)) /* ¬d hdr ¬O§_ plain text */ + { + hdr_fpath(fpath, dir, hdr); + + if (method) /* Âà±H¯¸¤º */ + { + HDR mhdr; + + if ((cc = hdr_stamp(folder, HDR_COPY, &mhdr, fpath)) < 0) + break; + + if (method > 0) /* Âà±H¦Û¤v */ + { + strcpy(mhdr.owner, "[ºë ¿ï ¶°]"); + mhdr.xmode = MAIL_READ | MAIL_NOREPLY; + } + else /* Âà±H¨ä¥L¨Ï¥ÎªÌ */ + { + strcpy(mhdr.owner, userid); + } + strcpy(mhdr.nick, cuser.username); + strcpy(mhdr.title, title); + if ((cc = rec_add(folder, &mhdr, sizeof(HDR))) < 0) + break; + } + else /* Âà±H¯¸¥~ */ + { + if ((cc = bsmtp(fpath, title, rcpt, 0)) < 0) + break; + } + } + } while (++locus < tag); + + if (userno > 0 && cc >= 0) + m_biff(userno); + + zmsg(cc >= 0 ? msg_sent_ok : "³¡¥÷«H¥óµLªk±H¹F"); + + return XO_FOOT; +} + + +/* ----------------------------------------------------- */ +/* ¤å³¹§@ªÌ¬d¸ß¡BÅv³]©w */ +/* ----------------------------------------------------- */ + + +int +xo_uquery(xo) + XO *xo; +{ + HDR *hdr; + char *userid; + + hdr = (HDR *) xo_pool + (xo->pos - xo->top); + userid = hdr->owner; + if (strchr(userid, '.')) + return XO_NONE; + + move(1, 0); + clrtobot(); + my_query(userid); + return XO_HEAD; +} + + +int +xo_usetup(xo) + XO *xo; +{ + HDR *hdr; + char *userid; + ACCT acct; + + if (!HAS_PERM(PERM_ALLACCT)) + return XO_NONE; + + hdr = (HDR *) xo_pool + (xo->pos - xo->top); + userid = hdr->owner; + if (strchr(userid, '.') || (acct_load(&acct, userid) < 0)) + return XO_NONE; + + move(3, 0); + acct_setup(&acct, 1); + return XO_HEAD; +} + + +/* ----------------------------------------------------- */ +/* ¥DÃD¦¡¾\Ū */ +/* ----------------------------------------------------- */ + + +#define RS_TITLE 0x001 /* author/title */ +#define RS_FORWARD 0x002 /* backward */ +#define RS_RELATED 0x004 +#define RS_FIRST 0x008 /* find first article */ +#define RS_CURRENT 0x010 /* match current read article */ +#define RS_THREAD 0x020 /* search the first article */ +#define RS_SEQUENT 0x040 /* sequential read */ +#define RS_MARKED 0x080 /* marked article */ +#define RS_UNREAD 0x100 /* unread article */ +#define RS_BOARD 0x1000 /* ¥Î©ó RS_UNREAD¡A¸ò«e±ªº¤£¥i«Å| */ + +#define CURSOR_FIRST (RS_RELATED | RS_TITLE | RS_FIRST) +#define CURSOR_NEXT (RS_RELATED | RS_TITLE | RS_FORWARD) +#define CURSOR_PREV (RS_RELATED | RS_TITLE) +#define RELATE_FIRST (RS_RELATED | RS_TITLE | RS_FIRST | RS_CURRENT) +#define RELATE_NEXT (RS_RELATED | RS_TITLE | RS_FORWARD | RS_CURRENT) +#define RELATE_PREV (RS_RELATED | RS_TITLE | RS_CURRENT) +#define THREAD_NEXT (RS_THREAD | RS_FORWARD) +#define THREAD_PREV (RS_THREAD) + +/* Thor: «e«á§ämark¤å³¹, ¤è«Kª¾¹D¦³¤°»ò°ÝÃD¥¼³B²z */ + +#define MARK_NEXT (RS_MARKED | RS_FORWARD | RS_CURRENT) +#define MARK_PREV (RS_MARKED | RS_CURRENT) + + +typedef struct +{ + int key; /* key stroke */ + int map; /* the mapped threading op-code */ +} KeyMap; + + +static KeyMap keymap[] = +{ + /* search title / author */ + + '?', RS_TITLE | RS_FORWARD, + '|', RS_TITLE, + 'A', RS_FORWARD, + 'Q', 0, + + /* thread : currtitle */ + + '[', RS_RELATED | RS_TITLE | RS_CURRENT, + ']', RS_RELATED | RS_TITLE | RS_FORWARD | RS_CURRENT, + '=', RS_RELATED | RS_TITLE | RS_FIRST | RS_CURRENT, + + /* i.e. < > : make life easier */ + + ',', RS_THREAD, + '.', RS_THREAD | RS_FORWARD, + + /* thread : cursor */ + + '-', RS_RELATED | RS_TITLE, + '+', RS_RELATED | RS_TITLE | RS_FORWARD, + '\\', RS_RELATED | RS_TITLE | RS_FIRST, + + /* Thor: marked : cursor */ + '\'', RS_MARKED | RS_FORWARD | RS_CURRENT, + ';', RS_MARKED | RS_CURRENT, + + /* Thor: ¦V«e§ä²Ä¤@½g¥¼Åªªº¤å³¹ */ + /* Thor.980909: ¦V«e§äº½g¥¼Åª, ©Î¥½½g¤wŪ */ + '`', RS_UNREAD /* | RS_FIRST */, + + /* sequential */ + + ' ', RS_SEQUENT | RS_FORWARD, + KEY_RIGHT, RS_SEQUENT | RS_FORWARD, + KEY_PGDN, RS_SEQUENT | RS_FORWARD, + KEY_DOWN, RS_SEQUENT | RS_FORWARD, + /* Thor.990208: ¬°¤F¤è«K¬Ý¤å³¹¹Lµ{¤¤, ²¾¦Ü¤U½g, ÁöµM¤W¼h³Qxover¦Y±¼¤F:p */ + 'j', RS_SEQUENT | RS_FORWARD, + + KEY_UP, RS_SEQUENT, + KEY_PGUP, RS_SEQUENT, + /* Thor.990208: ¬°¤F¤è«K¬Ý¤å³¹¹Lµ{¤¤, ²¾¦Ü¤W½g, ÁöµM¤W¼h³Qxover¦Y±¼¤F:p */ + 'k', RS_SEQUENT, + + /* end of keymap */ + + (char) NULL, -1 +}; + + +static int +xo_keymap(key) + int key; +{ + KeyMap *km; + int ch; + + km = keymap; + while (ch = km->key) + { + if (ch == key) + break; + km++; + } + return km->map; +} + + +/* itoc.010913: xo_thread() ¦^¶ÇÈ */ +/* XO_NONE: ¨S§ä¨ì©Î´N¬O´å¼Ð©Ò¦b¡A¤£¥Î²M b_lines */ +/* XO_FOOT: ¨S§ä¨ì©Î´N¬O´å¼Ð©Ò¦b¡A»Ýn²M b_lines */ +/* XO_BODY: §ä¨ì¤F¡A¦ý¦b§O¶ */ +/* -XO_NONE: §ä¨ì¤F¡A´N¦b¥»¶¡A¤£¥Î²M b_lines */ +/* -XO_FOOT: §ä¨ì¤F¡A´N¦b¥»¶¡A»Ýn²M b_lines */ + + +static int +xo_thread(xo, op) + XO *xo; + int op; +{ + static char s_author[16], s_title[32], s_unread[2] = "0"; + char buf[80]; + + char *tag, *query, *title; + const int origpos = xo->pos, origtop = xo->top, max = xo->max; + int pos, match, near, neartop; /* Thor: neartop »P near ¦¨¹ï¥Î */ + int top, bottom, step, len; + HDR *pool, *hdr; + + match = XO_NONE; + pos = origpos; + top = origtop; + pool = (HDR *) xo_pool; + hdr = pool + (pos - top); + near = 0; + step = (op & RS_FORWARD) - 1; /* (op & RS_FORWARD) ? 1 : -1 */ + + if (op & RS_RELATED) + { + tag = hdr->title; + if (op & RS_CURRENT) + { + query = currtitle; + if (op & RS_FIRST) + { + if (!strcmp(query, tag)) /* ¥Ø«eªº´N¬O²Ä¤@µ§¤F */ + return XO_NONE; + near = -1; + } + } + else + { + title = str_ttl(tag); + if (op & RS_FIRST) + { + if (title == tag) + return XO_NONE; + near = -1; + } + strcpy(query = buf, title); + } + } + else if (op & RS_UNREAD) + { + /* Thor.980909: ¸ß°Ý "º½g¥¼Åª" ©Î "¥½½g¤wŪ" */ + + near = xo->dir[0]; + if (near != 'b' && near != 'u') /* itoc.010913: ¥u¤¹³\¦b¬ÝªO/«H½c·j´M */ + return XO_NONE; /* itoc.040916.bug: ¨S¦³¨î¦b«H½cºëµØ°Ï·j´M */ + + if (!vget(b_lines, 0, "¦V«e§ä´M 0)º½g¥¼Åª 1)¥½½g¤wŪ ", s_unread, sizeof(s_unread), GCARRY)) + return XO_FOOT; + + if (*s_unread == '0') + op |= RS_FIRST; + + if (near == 'b') /* search board */ + op |= RS_BOARD; + + near = -1; + } + else if (!(op & (RS_THREAD | RS_SEQUENT | RS_MARKED))) + { + if (op & RS_TITLE) + { + title = "¼ÐÃD"; + tag = s_title; + len = sizeof(s_title); + } + else + { + title = "§@ªÌ"; + tag = s_author; + len = sizeof(s_author); + } + + sprintf(query = buf, "·j´M%s(%s)¡G", title, (step > 0) ? "¡õ" : "¡ô"); + if (!vget(b_lines, 0, query, tag, len, GCARRY)) + return XO_FOOT; + + str_lowest(query, tag); + } + + bottom = top + XO_TALL; + if (bottom > max) + bottom = max; + + for (;;) + { + if (step > 0) + { + if (++pos >= max) + break; + } + else + { + if (--pos < 0) + break; + } + + /* buffer I/O : shift sliding window scope */ + + if (pos < top || pos >= bottom) + { + xo->pos = pos; + xo_load(xo, sizeof(HDR)); + + top = xo->top; + bottom = top + XO_TALL; + if (bottom > max) + bottom = max; + + hdr = pool + (pos - top); + } + else + { + hdr += step; + } + +#ifdef HAVE_REFUSEMARK + if ((hdr->xmode & POST_RESTRICT) && + strcmp(hdr->owner, cuser.userid) && !(bbstate & STAT_BM)) + continue; +#endif + + if (op & RS_SEQUENT) + { + match = -1; + break; + } + + /* Thor: «e«á search marked ¤å³¹ */ + + if (op & RS_MARKED) + { + if (hdr->xmode & POST_MARKED) + { + match = -1; + break; + } + continue; + } + + /* ¦V«e§ä´M§ä´M¥¼Åª/¤wۤ峹 */ + + if (op & RS_UNREAD) + { +#define UNREAD_FUNC() (op & RS_BOARD ? brh_unread(hdr->chrono) : !(hdr->xmode & MAIL_READ)) + if (op & RS_FIRST) /* º½g¥¼Åª */ + { + if (UNREAD_FUNC()) + { + near = pos; + neartop = top; + continue; + } + } + else /* ¥½½g¤wŪ */ + { + if (!UNREAD_FUNC()) + { + match = -1; + break; + } + } + continue; + } + + /* ------------------------------------------------- */ + /* ¥H¤U·j´M title / author */ + /* ------------------------------------------------- */ + + if (op & (RS_TITLE | RS_THREAD)) + { + title = hdr->title; /* title «ü¦V [title] field */ + tag = str_ttl(title); /* tag «ü¦V thread's subject */ + + if (op & RS_THREAD) + { + if (tag == title) + { + match = -1; + break; + } + continue; + } + } + else + { + tag = hdr->owner; /* tag «ü¦V [owner] field */ + } + + if (((op & RS_RELATED) && !strncmp(tag, query, 40)) || + (!(op & RS_RELATED) && str_sub(tag, query))) + { + if ((op & RS_FIRST) && tag != title) + { + near = pos; /* °O¤U³Ì±µªñ°_ÂIªº¦ì¸m */ + neartop = top; + continue; + } + + match = -1; + break; + } + } + + /* top = xo->top = buffering ªº top */ + /* ¦pªG match = -1 ªí¥Ü§ä¨ì¤F¡A¦Ó pos, top = n¥hªº¦a¤è */ + /* ¦pªG RS_FIRST && near >= 0 ªí¥Ü§ä¨ì¤F¡A¦Ó near, neartop = n¥hªº¦a¤è */ + +#define CLEAR_FOOT() (!(op & RS_RELATED) && ((op & RS_UNREAD) || !(op & (RS_THREAD | RS_SEQUENT | RS_MARKED)))) + + if (match < 0) /* §ä¨ì¤F */ + { + xo->pos = pos; /* §ân¥hªº¦ì¸m¶ñ¶i¥h */ + + if (top != origtop) /* ¦b§O¶§ä¨ì¤F */ + match = XO_BODY; + else /* ¦b¥»¶§ä¨ì¤F */ + match = CLEAR_FOOT() ? -XO_FOOT : -XO_NONE; + } + else if ((op & RS_FIRST) && near >= 0)/* §ä¨ì¤F */ + { + xo->pos = near; /* §ân¥hªº¦ì¸m¶ñ¶i¥h */ + + /* ¥Ñ©ó¬O RS_FIRST §ä²Ä¤@½g¡A©Ò¥H buffering ªº top ¥i¯à§ä¨ì¤ñ³Ì«áµ²ªG neartop §ó«e± */ + if (top != neartop) + xo_load(xo, sizeof(HDR)); + + if (xo->top != origtop) /* ¦b§O¶§ä¨ì¤F */ + match = XO_BODY; + else /* ¦b¥»¶§ä¨ì¤F */ + match = CLEAR_FOOT() ? -XO_FOOT : -XO_NONE; + } + else /* §ä¤£¨ì */ + { + xo->pos = origpos; /* ÁÙìì¨Ó¦ì¸m */ + + if (top != origtop) /* ¦^¥Ø«e©Ò¦b¶ */ + xo_load(xo, sizeof(HDR)); + + match = CLEAR_FOOT() ? XO_FOOT : XO_NONE; + } + + return match; +} + + +/* Thor.990204: ¬°¦Ò¼{more ¶Ç¦^È, ¥H«K¬Ý¤@¥b¥i¥H¥Î []... + ch ¬°¥ý«emore()¤¤©Ò«öªºkey */ +int +xo_getch(xo, ch) + XO *xo; + int ch; +{ + int op; + + if (!ch) + ch = vkey(); + + op = xo_keymap(ch); + if (op >= 0) + { + ch = xo_thread(xo, op); + if (ch != XO_NONE) + ch = XO_BODY; /* Ä~ÄòÂsÄý */ + } + + return ch; +} + + +/* ----------------------------------------------------- */ +/* XZ */ +/* ----------------------------------------------------- */ + + +extern KeyFunc pal_cb[]; +extern KeyFunc bmw_cb[]; +extern KeyFunc post_cb[]; + + +XZ xz[] = +{ + {NULL, NULL, M_BOARD, FEETER_CLASS}, /* XZ_CLASS */ + {NULL, NULL, M_LUSERS, FEETER_ULIST}, /* XZ_ULIST */ + {NULL, pal_cb, M_PAL, FEETER_PAL}, /* XZ_PAL */ + {NULL, NULL, M_PAL, FEETER_ALOHA}, /* XZ_ALOHA */ + {NULL, NULL, M_VOTE, FEETER_VOTE}, /* XZ_VOTE */ + {NULL, bmw_cb, M_BMW, FEETER_BMW}, /* XZ_BMW */ + {NULL, NULL, M_MF, FEETER_MF}, /* XZ_MF */ + {NULL, NULL, M_COSIGN, FEETER_COSIGN}, /* XZ_COSIGN */ + {NULL, NULL, M_SONG, FEETER_SONG}, /* XZ_SONG */ + {NULL, NULL, M_READA, FEETER_NEWS}, /* XZ_NEWS */ + {NULL, NULL, M_READA, FEETER_XPOST}, /* XZ_XPOST */ + {NULL, NULL, M_RMAIL, FEETER_MBOX}, /* XZ_MBOX */ + {NULL, post_cb, M_READA, FEETER_POST}, /* XZ_POST */ + {NULL, NULL, M_GEM, FEETER_GEM} /* XZ_GEM */ +}; + + +static int +xo_jump(pos, zone) + int pos; /* ²¾°Ê´å¼Ð¨ì number ©Ò¦bªº¯S©w¦ì¸m */ + int zone; /* itoc.010403: §â zone ¤]¶Ç¶i¨Ó */ +{ + char buf[6]; + + buf[0] = pos; + buf[1] = '\0'; + vget(b_lines, 0, "¸õ¦Ü²Ä´X¶µ¡G", buf, sizeof(buf), GCARRY); + +#if 0 + move(b_lines, 0); + clrtoeol(); +#endif + outf(xz[zone].feeter); /* itoc.010403: §â b_lines ¶ñ¤W feeter */ + + pos = atoi(buf); + + if (pos > 0) + return XO_MOVE + pos - 1; + + return XO_NONE; +} + + +/* ----------------------------------------------------- */ +/* interactive menu routines */ +/* ----------------------------------------------------- */ + + +void +xover(cmd) + int cmd; +{ + int pos, num, zone, sysmode; + XO *xo; + KeyFunc *xcmd, *cb; + + for (;;) + { + while (cmd != XO_NONE) + { + if (cmd == XO_FOOT) + { + outf(xz[zone].feeter); /* itoc.010403: §â b_lines ¶ñ¤W feeter */ + break; + } + + if (cmd >= XO_ZONE) + { + /* --------------------------------------------- */ + /* switch zone */ + /* --------------------------------------------- */ + + zone = cmd; + cmd -= XO_ZONE; + xo = xz[cmd].xo; + xcmd = xz[cmd].cb; + sysmode = xz[cmd].mode; + + TagNum = 0; /* clear TagList */ + cmd = XO_INIT; + utmp_mode(sysmode); + } + else if (cmd >= XO_MOVE - XO_TALL) + { + /* --------------------------------------------- */ + /* calc cursor pos and show cursor correctly */ + /* --------------------------------------------- */ + + /* cmd >= XO_MOVE - XO_TALL so ... :chuan: °²³] cmd = -1 ?? */ + + /* fix cursor's range */ + + num = xo->max - 1; + + /* pos = (cmd | XO_WRAP) - (XO_MOVE + XO_WRAP); */ + /* cmd &= XO_WRAP; */ + /* itoc.020124: ×¥¿¦b²Ä¤@¶«ö PGUP¡B³Ì«á¤@¶«ö PGDN¡B²Ä¤@¶µ«ö UP¡B³Ì«á¤@¶µ«ö DOWN ·|§â XO_WRAP ºX¼Ð®ø¥¢ */ + + if (cmd > XO_MOVE + (XO_WRAP >> 1)) /* XO_WRAP >> 1 »·¤j¹L¤å³¹¼Æ */ + { + pos = cmd - (XO_MOVE + XO_WRAP); + cmd = 1; /* «ö KEY_UP ©Î KEY_DOWN */ + } + else + { + pos = cmd - XO_MOVE; + cmd = 0; + } + + /* pos: n¸õ¥hªº¶µ¥Ø cmd: ¬O§_¬° KEY_UP ©Î KEY_DOWN */ + + if (pos < 0) + { + /* pos = (zone == XZ_POST) ? 0 : num; *//* itoc.000304: ¾\Ū¨ì²Ä¤@½g«ö KEY_UP ©Î KEY_PGUP ¤£·|½¨ì³Ì«á */ + pos = num ; /* itoc.020124: ½¨ì³Ì«á¤ñ¸û¤è«K¡AÀ³¸Ó¤£·|¦³¤H¬O©¹¤WŪªº :P */ + } + else if (pos > num) + { + if (zone == XZ_POST) + pos = num; /* itoc.000304: ¾\Ū¨ì³Ì«á¤@½g«ö KEY_DOWN ©Î KEY_PGDN ¤£·|½¨ì³Ì«e */ + else + pos = (cmd || pos == num + XO_TALL) ? 0 : num; /* itoc.020124: nÁ×§K¦pªG¦b˼ƲĤG¶«ö KEY_PGDN¡A + ¦Ó³Ì«á¤@¶½g¼Æ¤Ó¤Ö·|ª½±µ¸õ¥h²Ä¤@¶¡A¨Ï¥ÎªÌ·| + ¤£ª¾¹D¦³³Ì«á¤@¶¡A¬G¥ý¦b³Ì«á¤@¶µ°±¤@¤U */ + } + + /* check cursor's range */ + + cmd = xo->pos; + + if (cmd == pos) + break; + + xo->pos = pos; + num = xo->top; + if ((pos < num) || (pos >= num + XO_TALL)) + { + xo->top = (pos / XO_TALL) * XO_TALL; + cmd = XO_LOAD; /* ¸ü¤J¸ê®Æ¨Ã¤©¥HÅã¥Ü */ + } + else + { + move(3 + cmd - num, 0); + outc(' '); + + break; /* ¥u²¾°Ê´å¼Ð */ + } + } + + /* ----------------------------------------------- */ + /* °õ¦æ call-back routines */ + /* ----------------------------------------------- */ + + cb = xcmd; + num = cmd | XO_DL; /* Thor.990220: for dynamic load */ + for (;;) + { + pos = cb->key; +#if 1 + /* Thor.990220: dynamic load , with key | XO_DL */ + if (pos == num) + { + void *p = DL_get((char *) cb->func); + if (p) + { + cb->func = p; + pos = cb->key = cmd; + } + else + { + cmd = XO_NONE; + break; + } + } +#endif + if (pos == cmd) + { + cmd = (*(cb->func)) (xo); + + if (cmd == XO_QUIT) + return; + + break; + } + + if (pos == 'h') /* itoc.001029: 'h' ¬O¤@¯S¨Ò¡A¥Nªí *_cb ªºµ²§ô */ + { + cmd = XO_NONE; /* itoc.001029: ¥Nªí§ä¤£¨ì call-back, ¤£§@¤F! */ + break; + } + + cb++; + } + + } /* Thor.990220.µù¸Ñ: end of while (cmd!=XO_NONE) */ + + utmp_mode(sysmode); + /* Thor.990220:µù¸Ñ:¥Î¨Ó¦^´_ event handle routine ¦^¨Ó«áªº¼Ò¦¡ */ + + pos = xo->pos; + + if (xo->max > 0) /* Thor: Y¬OµLªF¦è´N¤£show¤F */ + { + num = 3 + pos - xo->top; + move(num, 0); + outc('>'); + } + + cmd = vkey(); + + /* itoc.µù¸Ñ: ¥H¤U©w¸q¤F°ò¥»«öÁä¡A©Ò¿×°ò¥»«öÁä¡A´N¬O²¾°Êªº¤§Ãþªº¡A³q¥Î©ó©Ò¦³ XZ_ ªº¦a¤è */ + + /* ------------------------------------------------- */ + /* °ò¥»ªº´å¼Ð²¾°Ê routines */ + /* ------------------------------------------------- */ + + if (cmd == KEY_LEFT || cmd == 'e') + { + TagNum = 0; /* itoc.050413: ±qºëµØ°Ï¦^¨ì¤å³¹¦Cªí®Én²M°£ tag */ + return; + } + else if (xo->max <= 0) /* Thor: µLªF¦è«hµLªk²¾´å¼Ð */ + { + continue; + } + else if (cmd == KEY_UP || cmd == 'k') + { + cmd = pos - 1 + XO_MOVE + XO_WRAP; + } + else if (cmd == KEY_DOWN || cmd == 'j') + { + cmd = pos + 1 + XO_MOVE + XO_WRAP; + } + else if (cmd == ' ' || cmd == KEY_PGDN || cmd == 'N') + { + cmd = pos + XO_TALL + XO_MOVE; + } + else if (cmd == KEY_PGUP || cmd == 'P') + { + cmd = pos - XO_TALL + XO_MOVE; + } + else if (cmd == KEY_HOME || cmd == '0') + { + cmd = XO_MOVE; + } + else if (cmd == KEY_END || cmd == '$') + { + cmd = xo->max - 1 + XO_MOVE ; + } + else if (cmd >= '1' && cmd <= '9') + { + cmd = xo_jump(cmd, zone); + } + else if (cmd == KEY_RIGHT || cmd == '\n') + { + cmd = 'r'; + } + + /* ------------------------------------------------- */ + /* switch Zone */ + /* ------------------------------------------------- */ + +#ifdef EVERY_Z + else if (cmd == Ctrl('Z')) + { + cmd = every_Z(zone); + } + else if (cmd == Ctrl('U')) + { + cmd = every_U(zone); + } +#endif + + /* ------------------------------------------------- */ + /* ¨ä¾lªº«öÁä */ + /* ------------------------------------------------- */ + + else + { + if (zone >= XZ_XPOST) /* xo_pool ¤¤©ñªº¬O HDR */ + { + /* --------------------------------------------- */ + /* Tag */ + /* --------------------------------------------- */ + + if (cmd == 'C') + { + cmd = xo_tbf(xo); + } + else if (cmd == 'F') + { + cmd = xo_forward(xo); + } + else if (cmd == Ctrl('C')) + { + if (TagNum) + { + TagNum = 0; + cmd = XO_BODY; + } + else + cmd = XO_NONE; + } + else if (cmd == Ctrl('A') || cmd == Ctrl('T')) + { + cmd = xo_tag(xo, cmd); + } + + /* --------------------------------------------- */ + /* ¥DÃD¦¡¾\Ū */ + /* --------------------------------------------- */ + + if (zone == XZ_XPOST) /* ¦ê±µ¤¤¤£¤ä´©¥DÃD¦¡¾\Ū */ + continue; + + pos = xo_keymap(cmd); + if (pos >= 0) /* ¦pªG¤£¬O«ö¤è¦VÁä */ + { + cmd = xo_thread(xo, pos); /* ¥h¬d¬d¬Oþ¤@ºØ thread ·j´M */ + + if (cmd < 0) /* ¦b¥»¶§ä¨ì match */ + { + move(num, 0); + outc(' '); + /* cmd = XO_NONE; */ + /* itoc.010913: ¬Y¨Ç·j´Mn§â b_lines ¶ñ¤W feeter */ + cmd = -cmd; + } + } + } + + /* ----------------------------------------------- */ + /* ¨ä¥Lªº¥æµ¹ call-back routine ¥h³B²z */ + /* ----------------------------------------------- */ + + } /* Thor.990220.µù¸Ñ: end of vkey() handling */ + } +} + + +/* ----------------------------------------------------- */ +/* Thor.980725: ctrl Z everywhere */ +/* ----------------------------------------------------- */ + + +#ifdef EVERY_Z +int z_status = 0; /* ¶i¤J´X¼h */ + +int +every_Z(zone) + int zone; /* ¶Ç¤J©Ò¦b XZ_ZONE¡AY¶Ç¤J 0¡Aªí¥Ü¤£¦b xover() ¤¤ */ +{ + int cmd, tmpbno, tmpmode; + + /* itoc.000319: ³Ì¦h every_Z ¤@¼h */ + if (z_status >= 1) + return XO_NONE; + else + z_status++; + + cmd = zone; + outz(MSG_ZONE_SWITCH); + + tmpbno = vkey(); /* ɥΠtmpbno ¨Ó´«¦¨¤p¼g */ + if (tmpbno >= 'A' && tmpbno <= 'Z') + tmpbno |= 0x20; + switch (tmpbno) + { + case 'a': + cmd = XZ_GEM; + break; + + case 'b': + if (currbno >= 0) /* Y¤w¿ï©w¬ÝªO¡A¶i¤J¬ÝªO¡A§_«h¨ì¬ÝªO¦Cªí */ + { + cmd = XZ_POST; + break; + } + + case 'c': + cmd = XZ_CLASS; + break; + +#ifdef MY_FAVORITE + case 'f': + if (cuser.userlevel) + cmd = XZ_MF; + break; +#endif + + case 'm': + if (cuser.userlevel) + cmd = XZ_MBOX; + break; + + case 'u': + cmd = XZ_ULIST; + break; + + case 'w': + if (cuser.userlevel) + cmd = XZ_BMW; + break; + + case 's': + { + FILE *fp; + int i; + screenline slt[24]; + + vs_save(slt); + + if (!(fp = tbf_open())) + { + vmsg("¼È¦sÀɶ}±Ò¿ù»~"); + break; + } + + for (i = 0; i <= b_lines; i++) + { + slt[i].data[slt[i].len] = '\0'; + fprintf(fp, "%s\n", slt[i].data); + } + + fclose(fp); + } + break; + } + + if (cmd == zone) /* ©M¥Ø«e©Ò¦b zone ¤@¼Ë¡A©Î¨ú®ø */ + { + z_status--; + return XO_FOOT; /* Y¦b xover() ¤¤¨ú®ø©I¥s every_Z() «h°e¦^ XO_FOOT §Y¥i«Ã¸ */ + } + + if (cmd == XZ_POST) + XoPost(currbno); + +#ifdef MY_FAVORITE + if (zone == XZ_POST && (cmd == XZ_CLASS || cmd == XZ_MF)) +#else + if (zone == XZ_POST && cmd == XZ_CLASS) +#endif + tmpbno = currbno; + else + tmpbno = -1; + + tmpmode = bbsmode; + xover(cmd); + utmp_mode(tmpmode); + + if (tmpbno >= 0) /* itoc.030731: ¦³¥i¯à¶i¤J§OªºªO¡A´N»Ýn«·s XoPost¡A·|¦A¬Ý¤@¦¸¶iªOµe± */ + XoPost(tmpbno); + + z_status--; + return XO_INIT; /* »Ýn«·s¸ü¤J xo_pool¡AY¦b xover() ¤¤¤]¥iÂǦ¹«Ã¸ */ +} + + +int +every_U(zone) + int zone; /* ¶Ç¤J©Ò¦b XZ_ZONE¡AY¶Ç¤J 0¡Aªí¥Ü¤£¦b xover() ¤¤ */ +{ + /* itoc.000319: ³Ì¦h every_Z ¤@¼h */ + if (z_status >= 1) + return XO_NONE; + + if (zone != XZ_ULIST) + { + int tmpmode; + + z_status++; + tmpmode = bbsmode; + xover(XZ_ULIST); + utmp_mode(tmpmode); + z_status--; + } + return XO_INIT; +} +#endif + + +/* ----------------------------------------------------- */ +/* Ãþ XZ_* µ²ºcªº´å¼Ð²¾°Ê */ +/* ----------------------------------------------------- */ + + +/* ¶Ç¤J: ch, pagemax, num, pageno, cur, redraw */ +/* ¶Ç¥X: ch, pageno, cur, redraw */ +int +xo_cursor(ch, pagemax, num, pageno, cur, redraw) + int ch, pagemax, num; + int *pageno, *cur, *redraw; +{ + switch (ch) + { + case KEY_LEFT: + case 'q': + return 'q'; + + case KEY_PGUP: + if (pagemax != 0) + { + if (*pageno) + { + (*pageno)--; + } + else + { + *pageno = pagemax; + *cur = num % XO_TALL; + } + *redraw = 1; + } + break; + + case KEY_PGDN: + if (pagemax != 0) + { + if (*pageno == pagemax) + { + /* ¦b³Ì«á¤@¶µ°±¤@¤U */ + if (*cur != num % XO_TALL) + { + *cur = num % XO_TALL; + } + else + { + *pageno = 0; + *cur = 0; + } + } + else + { + (*pageno)++; + if (*pageno == pagemax && *cur > num % XO_TALL) + *cur = num % XO_TALL; + } + *redraw = 1; + } + break; + + case KEY_UP: + case 'k': + if (*cur == 0) + { + if (*pageno != 0) + { + *cur = XO_TALL - 1; + *pageno = *pageno - 1; + } + else + { + *cur = num % XO_TALL; + *pageno = pagemax; + } + *redraw = 1; + } + else + { + move(3 + *cur, 0); + outc(' '); + (*cur)--; + move(3 + *cur, 0); + outc('>'); + } + break; + + case KEY_DOWN: + case 'j': + if (*cur == XO_TALL - 1) + { + *cur = 0; + *pageno = (*pageno == pagemax) ? 0 : *pageno + 1; + *redraw = 1; + } + else if (*pageno == pagemax && *cur == num % XO_TALL) + { + *cur = 0; + *pageno = 0; + *redraw = 1; + } + else + { + move(3 + *cur, 0); + outc(' '); + (*cur)++; + move(3 + *cur, 0); + outc('>'); + } + break; + + case KEY_HOME: + case '0': + *pageno = 0; + *cur = 0; + *redraw = 1; + break; + + case KEY_END: + case '$': + *pageno = pagemax; + *cur = num % XO_TALL; + *redraw = 1; + break; + } + + return ch; +} + + +/* ----------------------------------------------------- */ +/* »¡©ú¤å¥ó */ +/* ----------------------------------------------------- */ + + +void +xo_help(path) /* itoc.021122: »¡©ú¤å¥ó */ + char *path; +{ + /* itoc.030510: ©ñ¨ì so ¸Ì± */ + DL_func("bin/help.so:vaHelp", path); +} diff --git a/maple/xpost.c b/maple/xpost.c new file mode 100644 index 0000000..426be6f --- /dev/null +++ b/maple/xpost.c @@ -0,0 +1,1203 @@ +/*-------------------------------------------------------*/ +/* xpost.c ( NTHU CS MapleBBS Ver 2.39 ) */ +/*-------------------------------------------------------*/ +/* target : bulletin boards' routines */ +/* create : 95/03/29 */ +/* update : 96/04/05 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +extern XZ xz[]; + +extern char xo_pool[]; + + +/*------------------------------------------------------------------------ + Thor.980509: + ·sªº ¤å³¹·j´M¼Ò¦¡ ¥i«ü©w¤@ keyword, ¦C¥X©Ò¦³keyword¬ÛÃö¤§¤å³¹¦Cªí + + ¦b tmp/ ¤U¶} xpost.{pid} §@¬° folder, ¥t«Ø¤@map°}¦C, ¥Î§@»Pì post §@ map + °O¸ü¸Ó¤å³¹¬O¦bì post ªº¦ó³B, ¦p¦¹¥i§@ mark, gem, edit, title µ¥¥\¯à, + ¥B¯àÂ÷¶}®É¦^¦Ü¹ïÀ³¤å³¹³B + <¥H¤W·Qªk obsolete...> + + Thor.980510: + «Ø¥ß¤å³¹°Q½×¦ê, like tin, ±N¤å³¹¦ê index ©ñ¤J memory ¤¤, + ¤£¨Ï¥Î thread, ¦]¬° threadn¥Î folder ÀÉ... + + ¤À¬°¨âºØ Mode, Title & post list + + ¦ý¦Ò¼{´£¨Ñ²¤Æªº ¤W¤UÁä²¾°Ê.. + + O->O->O->... + | | | + o o o + | | | + + index§tfield {next, text} §¡¬°int, °t¸m¤]¥Î int + ²Ä¤@¼h sorted by title, ´¡¤J®É¥Î binary search + ¥B MMAP only , ²Ä¤@¼hÅã¥Ü # and + + + ¤£´£¨Ñ¥ô¦ó°Ï¬q§R°£°Ê§@, Á×§K²V¶Ã +-------------------------------------------------------------------------*/ + +#if 0 /* itoc.060206.µù¸Ñ */ + + ·í¨Ï¥ÎªÌ¿é¤J·j´M±ø¥ó«á¡A·|¶i¤J XoXpost() ±N xo->dir ³oÀɮפ¤©Ò°O¿ýªº©Ò¦³ HDR + ¤@¤@ÂsÄý¡AµM«á±Nº¡¨¬±ø¥óªº HDR ¦b xo->dir ¤¤©Ò¹ïÀ³¦ì¸m°O¿ý¦b xpostIndex[]¡A + ±µµÛ¶i¤J xover(XZ_XPOST) ·|©I¥s xpost_init()¡A¦A©ó xpost_pick() ±N xpostIndex[] + ©Ò°O¿ýªº¦ì¸m±q xo->dir §Û¨ì xo_pool[]¡C + + ·í¼W¥[±ø¥ó°µ¤G¦¸·j´M®É¡A¦¹®É¤£»Ýn±½¾ãÓ xo->dir ¤ºªº©Ò¦³ HDR¡A¥uÂsÄý°O¿ý¦b + xpostIndex[] ¸Ì±ªº¨º¨Ç¡C¥Ñ©ó¤G¦¸·j´M®Én¬Ý¦P¤@Ó xo->dir¡A©Ò¥H every_Z ®É + n¸T¤î¶i¤J XZ_XPOST ¤G¦¸¡C + + ¤wª¾°ÝÃD¬O¡G·í¨Ï¥ÎªÌÁÙ¦b XZ_XPOST ¸Ì±®É¡AY xo->dir ªº¶¶§Ç¦³²§°Ê®É (¨Ò¦p§R°£)¡A + ¦Ó¨Ï¥ÎªÌn¨D xpick_pick() ®É (¨Ò¦p½¶¡B¤G¦¸·j´M)¡A¥Ñ©ó xpostIndex[] °O¿ýªº¬O¦b + xo->dir ªº¦ì¸m¡A¦¹®Éµ²ªG·|¥X¿ù¡C + +#endif + +/* ----------------------------------------------------- */ +/* ¦ê¦C·j´M¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +#ifdef EVERY_Z +#define MSG_XYDENY "½Ð¥ý°h¥X¨Ï¥Î ^Z ¥H«eªº¦ê±µ/·s»D¥\\¯à" +extern int z_status; +#endif + +extern KeyFunc xpost_cb[]; +extern KeyFunc xmbox_cb[]; + +static int *xpostIndex; /* Thor: first ypost pos in ypost_xo.key */ +static int comebackPos; /* °O¿ý³Ì«á */ + + +static char HintWord[TTLEN + 1]; +static char HintAuthor[IDLEN + 1]; + + +static int +XoXpost(xo, hdr, on, off, fchk) /* Thor: eXtended post : call from post_cb */ + XO *xo; + HDR *hdr; /* ·j´Mªº±ø¥ó */ + int on, off; /* ·j´Mªº½d³ò (on~off-1) */ + int (*fchk) (); /* ·j´Mªº¨ç¦¡ */ +{ + int *list, fsize, max, locus, count, i; + char *fimage; + HDR *head; + XO *xt; +#ifdef HAVE_XYNEWS + int returnPos; +#endif + + if (xo->max <= 0) /* Thor.980911: µù¸Ñ: ¥H¨¾¸U¤@ */ + return XO_FOOT; + + /* build index according to input condition */ + + fimage = f_map(xo->dir, &fsize); + + if (fimage == (char *) -1) + { + vmsg("¥Ø«eµLªk¶}±Ò¯Á¤ÞÀÉ"); + return XO_FOOT; + } + + /* allocate index memory, remember free first */ + + /* Thor.990113: ©È°Ýtitle, authorªºÀþ¶¡¤S¦³¤Hpost */ + max = xpostIndex ? xo->max : fsize / sizeof(HDR); + list = (int *) malloc(sizeof(int) * max); + + count = 0; /* Á`¦@¦³´X½gº¡¨¬±ø¥ó */ + + if (max > off) + max = off; + + for (i = on; i < max; i++) + { + if (xpostIndex) /* ¼W¥[±ø¥ó¦A¦¸·j´M®É¡A¥u»Ýn§ä¦b xpostIndex[] ¸Ì±ªº */ + locus = xpostIndex[i]; + else /* ¾ãÓ xo->dir ³£±½¤@¦¸ */ + locus = i; + + head = (HDR *) fimage + locus; + +#ifdef HAVE_REFUSEMARK + if ((head->xmode & POST_RESTRICT) && + strcmp(head->owner, cuser.userid) && !(bbstate & STAT_BM)) + continue; +#endif + + /* check condition */ + if (!(* fchk) (head, hdr)) + continue; + + list[count++] = locus; + } + + munmap(fimage, fsize); + + if (count <= 0) + { + free(list); + vmsg(MSG_XY_NONE); + return XO_FOOT; + } + + /* ¼W¥[±ø¥ó¦A¦¸·j´M */ + if (xpostIndex) + { + free(xpostIndex); + xpostIndex = list; + + xo->pos = 0; + xo->max = count; + + return xpost_init(xo); + } + + /* º¦¸·j´M */ + xpostIndex = list; + + /* build XO for xpost_xo */ + + comebackPos = xo->pos; /* Thor: record pos, future use */ +#ifdef HAVE_XYNEWS + returnPos = comebackPos; +#endif + + xz[XZ_XPOST - XO_ZONE].xo = xt = xo_new(xo->dir); + xz[XZ_XPOST - XO_ZONE].cb = (xo->dir[0] == 'b') ? xpost_cb : xmbox_cb; + xt->pos = 0; + xt->max = count; + xt->xyz = xo->xyz; + xt->key = XZ_XPOST; + + xover(XZ_XPOST); + + /* set xo->pos for new location */ + +#ifdef HAVE_XYNEWS + if (xz[XZ_NEWS - XO_ZONE].xo) + xo->pos = returnPos; /* ±q XZ_XPOST ¦^¨ì XZ_NEWS ´å¼Ð²¾¥hì¨Óªº¦a¤è */ + else +#endif + xo->pos = comebackPos; /* ±q XZ_XPOST ¦^¨ì XZ_POST ´å¼Ð²¾¥hì¨Óªº¦a¤è©Î©Ò¾\ۤ峹ªº¯u¥¿¦ì¸m */ + + /* free xpost_xo */ + + if (xt = xz[XZ_XPOST - XO_ZONE].xo) + { + free(xt); + xz[XZ_XPOST - XO_ZONE].xo = NULL; + } + + /* free index memory, remember check free pointer */ + + if (list) + { + free(list); + xpostIndex = NULL; + } + + return XO_INIT; +} + + + /* --------------------------------------------------- */ + /* ·j´M§@ªÌ/¼ÐÃD */ + /* --------------------------------------------------- */ + + +static int /* 0:¤£º¡¨¬±ø¥ó !=0:º¡¨¬±ø¥ó */ +filter_select(head, hdr) + HDR *head; /* «Ý´úª« */ + HDR *hdr; /* ±ø¥ó */ +{ + char *title; + usint str4; + + /* ɥΠhdr->xid ·í strlen(hdr->owner) */ + + /* Thor.981109: ¯S§Oª`·N¡A¬°¤F°§C load¡Aauthor ¬O±qÀY match¡A¤£¬O substr match */ + if (hdr->xid && str_ncmp(head->owner, hdr->owner, hdr->xid)) + return 0; + + if (hdr->title[0]) + { + title = head->title; + str4 = STR4(title); + if (str4 == STR4(STR_REPLY) || str4 == STR4(STR_FORWARD)) /* Thor.980911: ¥ý§â Re:/Fw: °£¥~ */ + title += 4; + if (!str_sub(title, hdr->title)) + return 0; + } + + return 1; +} + + +int +XoXselect(xo) + XO *xo; +{ + HDR hdr; + char *key; + +#ifdef EVERY_Z + if (z_status && xz[XZ_XPOST - XO_ZONE].xo) /* itoc.020308: ¤£±o²Ö¿n¶i¤J¤G¦¸ */ + { + vmsg(MSG_XYDENY); + return XO_FOOT; + } +#endif + + /* input condition */ + + key = hdr.title; + if (vget(b_lines, 0, MSG_XYPOST1, key, 30, DOECHO)) + { + strcpy(HintWord, key); + str_lowest(key, key); + } + else + { + HintWord[0] = '\0'; + } + + key = hdr.owner; + if (vget(b_lines, 0, MSG_XYPOST2, key, IDLEN + 1, DOECHO)) + { + strcpy(HintAuthor, key); + str_lower(key, key); + hdr.xid = strlen(key); + } + else + { + HintAuthor[0] = '\0'; + hdr.xid = 0; + } + + if (!hdr.title[0] && !hdr.xid) + return XO_FOOT; + + return XoXpost(xo, &hdr, 0, INT_MAX, filter_select); +} + + + /* --------------------------------------------------- */ + /* ·j´M§@ªÌ */ + /* --------------------------------------------------- */ + + +int +XoXauthor(xo) + XO *xo; +{ + HDR hdr; + char *author; + +#ifdef EVERY_Z + if (z_status && xz[XZ_XPOST - XO_ZONE].xo) /* itoc.020308: ¤£±o²Ö¿n¶i¤J¤G¦¸ */ + { + vmsg(MSG_XYDENY); + return XO_FOOT; + } +#endif + + author = hdr.owner; + if (!vget(b_lines, 0, MSG_XYPOST2, author, IDLEN + 1, DOECHO)) + return XO_FOOT; + + HintWord[0] = '\0'; + strcpy(HintAuthor, author); + + hdr.title[0] = '\0'; + str_lower(author, author); + hdr.xid = strlen(author); + + return XoXpost(xo, &hdr, 0, INT_MAX, filter_select); +} + + + /* --------------------------------------------------- */ + /* ·j´M¼ÐÃD */ + /* --------------------------------------------------- */ + + +int +XoXtitle(xo) + XO *xo; +{ + HDR hdr; + char *title; + +#ifdef EVERY_Z + if (z_status && xz[XZ_XPOST - XO_ZONE].xo) /* itoc.020308: ¤£±o²Ö¿n¶i¤J¤G¦¸ */ + { + vmsg(MSG_XYDENY); + return XO_FOOT; + } +#endif + + title = hdr.title; + if (!vget(b_lines, 0, MSG_XYPOST1, title, 30, DOECHO)) + return XO_FOOT; + + strcpy(HintWord, title); + HintAuthor[0] = '\0'; + + str_lowest(title, title); + hdr.xid = 0; + + return XoXpost(xo, &hdr, 0, INT_MAX, filter_select); +} + + + /* --------------------------------------------------- */ + /* ·j´M¬Û¦P¼ÐÃD */ + /* --------------------------------------------------- */ + + +static int /* 0:¤£º¡¨¬±ø¥ó !=0:º¡¨¬±ø¥ó */ +filter_search(head, hdr) + HDR *head; /* «Ý´úª« */ + HDR *hdr; /* ±ø¥ó */ +{ + char *title, buf[TTLEN + 1]; + usint str4; + + title = head->title; + str4 = STR4(title); + if (str4 == STR4(STR_REPLY) || str4 == STR4(STR_FORWARD)) /* Thor.980911: ¥ý§â Re:/Fw: °£¥~ */ + title += 4; + str_lowest(buf, title); + return !strcmp(buf, hdr->title); +} + + +int +XoXsearch(xo) + XO *xo; +{ + HDR hdr, *mhdr; + char *title; + usint str4; + +#ifdef EVERY_Z + if (z_status && xz[XZ_XPOST - XO_ZONE].xo) /* itoc.020308: ¤£±o²Ö¿n¶i¤J¤G¦¸ */ + { + vmsg(MSG_XYDENY); + return XO_FOOT; + } +#endif + + mhdr = (HDR *) xo_pool + (xo->pos - xo->top); + + title = mhdr->title; + str4 = STR4(title); + if (str4 == STR4(STR_REPLY) || str4 == STR4(STR_FORWARD)) /* Thor.980911: ¥ý§â Re:/Fw: °£¥~ */ + title += 4; + + strcpy(HintWord, title); + HintAuthor[0] = '\0'; + + str_lowest(hdr.title, title); + + return XoXpost(xo, &hdr, 0, INT_MAX, filter_search); +} + + + /* --------------------------------------------------- */ + /* ¥þ¤å·j´M */ + /* --------------------------------------------------- */ + + +static char *search_folder; +static int search_fit; /* >=0:§ä¨ì´X½g -1:¤¤Â_·j´M */ +static int search_all; /* ¤w·j´M´X½g */ + +static int /* 0:¤£º¡¨¬±ø¥ó !=0:º¡¨¬±ø¥ó */ +filter_full(head, hdr) + HDR *head; /* «Ý´úª« */ + HDR *hdr; /* ±ø¥ó */ +{ + char buf[80], *fimage; + int rc, fsize; + struct timeval tv = {0, 10}; + + if (search_fit < 0) /* ¤¤Â_·j´M */ + return 0; + + if (search_all % 100 == 0) /* ¨C 100 ½g¤~³ø§i¤@¦¸¶i«× */ + { + sprintf(buf, "¥Ø«e§ä¨ì \033[1;33m%d / %d\033[m ½g¡A¥þ¤å·j´M¤¤\033[5m...\033[m«ö¥ô·NÁ䤤Â_", + search_fit, search_all); + outz(buf); + refresh(); + } + search_all++; + + hdr_fpath(buf, search_folder, head); + + fimage = f_map(buf, &fsize); + if (fimage == (char *) -1) + return 0; + + rc = 0; + if (str_sub(fimage, hdr->title)) + { + rc = 1; + search_fit++; + } + + munmap(fimage, fsize); + + /* ¨Ï¥ÎªÌ¥i¥H¤¤Â_·j´M */ + fsize = 1; + if (select(1, (fd_set *) &fsize, NULL, NULL, &tv) > 0) + { + vkey(); + search_fit = -1; + } + + return rc; +} + + +int +XoXfull(xo) + XO *xo; +{ + HDR hdr; + char *key, ans[8]; + int head, tail; + +#ifdef EVERY_Z + if (z_status && xz[XZ_XPOST - XO_ZONE].xo) /* itoc.020308: ¤£±o²Ö¿n¶i¤J¤G¦¸ */ + { + vmsg(MSG_XYDENY); + return XO_FOOT; + } +#endif + + /* input condition */ + + key = hdr.title; + if (!vget(b_lines, 0, "¤º¤åÃöÁä¦r¡G", key, 30, DOECHO)) + return XO_FOOT; + + vget(b_lines, 0, "[³]©w·j´M½d³ò] °_ÂI¡G(Enter)±qÀY¶}©l ", ans, 6, DOECHO); + if ((head = atoi(ans)) <= 0) + head = 1; + + vget(b_lines, 44, "²×ÂI¡G(Enter)§ä¨ì³Ì«á ", ans, 6, DOECHO); + if ((tail = atoi(ans)) < head) + tail = INT_MAX; + + head--; + + sprintf(HintWord, "[¥þ¤å·j´M] %s", key); + HintAuthor[0] = '\0'; + str_lowest(key, key); + + search_folder = xo->dir; + search_fit = 0; + search_all = 0; + + return XoXpost(xo, &hdr, head, tail, filter_full); +} + + + /* --------------------------------------------------- */ + /* ·j´M mark ¡B¥[±K¡B³Q±ÀÂˤ峹 */ + /* --------------------------------------------------- */ + + +static int /* 0:¤£º¡¨¬±ø¥ó !=0:º¡¨¬±ø¥ó */ +filter_mark(head, hdr) + HDR *head; /* «Ý´úª« */ + HDR *hdr; /* ±ø¥ó */ +{ + return (head->xmode & POST_MARKED); +} + +static int +filter_restrict(head, hdr) + HDR *head; + HDR *hdr; +{ + return (head->xmode & POST_RESTRICT); +} + +static int +filter_score(head, hdr) + HDR *head; + HDR *hdr; +{ + return (head->xmode & POST_SCORE); +} + + +int +XoXmark(xo) + XO *xo; +{ +#ifdef EVERY_Z + if (z_status && xz[XZ_XPOST - XO_ZONE].xo) /* itoc.020308: ¤£±o²Ö¿n¶i¤J¤G¦¸ */ + { + vmsg(MSG_XYDENY); + return XO_FOOT; + } +#endif + + strcpy(HintWord, "\033[1;33m©Ò¦³ mark ¤å³¹\033[m"); + HintAuthor[0] = '\0'; + + return XoXpost(xo, NULL, 0, INT_MAX, filter_mark); +} + +int +XoXrestrict(xo) + XO *xo; +{ +#ifdef EVERY_Z + if (z_status && xz[XZ_XPOST - XO_ZONE].xo) + { + vmsg(MSG_XYDENY); + return XO_FOOT; + } +#endif + + strcpy(HintWord, "\033[1;33m©Ò¦³¥[±K¤å³¹\033[m"); + HintAuthor[0] = '\0'; + + return XoXpost(xo, NULL, 0, INT_MAX, filter_restrict); +} + +int +XoXscore(xo) + XO *xo; +{ +#ifdef EVERY_Z + if (z_status && xz[XZ_XPOST - XO_ZONE].xo) + { + vmsg(MSG_XYDENY); + return XO_FOOT; + } +#endif + + strcpy(HintWord, "\033[1;33m©Ò¦³³Q±ÀÂˤ峹\033[m"); + HintAuthor[0] = '\0'; + + return XoXpost(xo, NULL, 0, INT_MAX, filter_score); +} + + + /* --------------------------------------------------- */ + /* ·j´M¥»¦a */ + /* --------------------------------------------------- */ + + +static int /* 0:¤£º¡¨¬±ø¥ó !=0:º¡¨¬±ø¥ó */ +filter_local(head, hdr) + HDR *head; /* «Ý´úª« */ + HDR *hdr; /* ±ø¥ó */ +{ + return !(head->xmode & POST_INCOME); +} + + +int +XoXlocal(xo) + XO *xo; +{ + if (currbattr & BRD_NOTRAN) + { + vmsg("¥»ªO¬°¤£Âà«HªO¡A¥þ³¡³£¬O¥»¦a¤å³¹"); + return XO_FOOT; + } + +#ifdef EVERY_Z + if (z_status && xz[XZ_XPOST - XO_ZONE].xo) /* itoc.020308: ¤£±o²Ö¿n¶i¤J¤G¦¸ */ + { + vmsg(MSG_XYDENY); + return XO_FOOT; + } +#endif + + strcpy(HintWord, "\033[1;33m©Ò¦³«DÂà¶i¤å³¹\033[m"); + HintAuthor[0] = '\0'; + + return XoXpost(xo, NULL, 0, INT_MAX, filter_local); +} + + +/* ----------------------------------------------------- */ +/* ¦ê¦C·j´M¬É± */ +/* ----------------------------------------------------- */ + + +int +xpost_head(xo) + XO *xo; +{ + vs_head("¥DÃD¦ê¦C", xo->xyz); + + /* itoc.010323: ¦P®É´£¥Ü§@ªÌ/¥DÃD */ + outs("[¦ê±µ¨t¦C] "); + if (*HintAuthor) + prints("§@ªÌ¡G%-13s ", HintAuthor); + if (*HintWord) + prints("¼ÐÃD¡G%.30s", HintWord); + + prints(NECKER_XPOST, d_cols, "", + currbattr & BRD_NOPHONETIC ? "¢®" : "¡³", + currbattr & BRD_NOSCORE ? "¢®" : "¡³"); + + return XO_BODY; +} + + +static void +xpost_pick(xo) + XO *xo; +{ + int *list, fsize, pos, max, top, num; + HDR *fimage, *hdr; + + fimage = (HDR *) f_map(xo->dir, &fsize); + if (fimage == (HDR *) - 1) + return; + + hdr = (HDR *) xo_pool; + list = xpostIndex; + + pos = xo->pos; + xo->top = top = (pos / XO_TALL) * XO_TALL; + max = xo->max; + pos = top + XO_TALL; + if (max > pos) + max = pos; + num = fsize / sizeof(HDR); + + do + { + pos = list[top++]; + if (pos >= num) /* hightman.030528: Á×§K .DIR ³Q§R´î®É¡A·|¨S¦³¤å³¹¥i¥HÅã¥Ü */ + continue; + memcpy(hdr, fimage + pos, sizeof(HDR)); + hdr->xid = pos; /* ¥Î hdr->xid ¨Ó°O¿ý¨äì¥ý¦b¬ÝªO¤¤ªº pos */ + hdr++; + } while (top < max); + + munmap(fimage, fsize); +} + + +int +xpost_init(xo) + XO *xo; +{ + /* load into pool */ + + xpost_pick(xo); + + return xpost_head(xo); +} + + +int +xpost_load(xo) + XO *xo; +{ + /* load into pool */ + + xpost_pick(xo); + + return XO_BODY; +} + + +static void +xpost_history(xo, fhdr) /* ±N fhdr ³o½g¥[¤J brh */ + XO *xo; + HDR *fhdr; +{ + time_t prev, chrono, next; + int pos; + char *dir; + HDR buf; + + chrono = fhdr->chrono; + if (!brh_unread(chrono)) /* ¦pªG¤w¦b brh ¤¤¡A´NµL»Ý°Ê§@ */ + return; + + dir = xo->dir; + pos = fhdr->xid; + + if (!rec_get(dir, &buf, sizeof(HDR), pos - 1)) + prev = buf.chrono; + else + prev = chrono; + + if (!rec_get(dir, &buf, sizeof(HDR), pos + 1)) + next = buf.chrono; + else + next = chrono; + + brh_add(prev, chrono, next); +} + + +int +xpost_browse(xo) + XO *xo; +{ + HDR *hdr; + int key; + char *dir, fpath[64]; + + dir = xo->dir; + + for (;;) + { + hdr = (HDR *) xo_pool + (xo->pos - xo->top); + +#if 0 /* itoc.010822: ¤£»Ýn¡A¦b XoXpost() ¤¤¤w³Qç°£ */ +#ifdef HAVE_REFUSEMARK + xmode = hdr->xmode; + if ((xmode & POST_RESTRICT) && + strcmp(hdr->owner, cuser.userid) && !(bbstate & STAT_BM)) + continue; +#endif +#endif + + hdr_fpath(fpath, dir, hdr); + + /* Thor.990204: ¬°¦Ò¼{more ¶Ç¦^È */ + if ((key = more(fpath, FOOTER_POST)) < 0) + break; + + comebackPos = hdr->xid; + /* Thor.980911: ±q¦ê±µ¼Ò¦¡¦^¨Ó®Én¦^¨ì¬Ý¹Lªº¨º½g¤å³¹¦ì¸m */ + + xpost_history(xo, hdr); + strcpy(currtitle, str_ttl(hdr->title)); + +re_key: + /* Thor.990204: ¬°¦Ò¼{more ¶Ç¦^È */ + if (!key) + key = vkey(); + + switch (key) + { + case KEY_UP: + case KEY_PGUP: + case '[': /* itoc.000227: ¦ê¦C·j´M¤¤¡A¦³®É·Q¥Î [ ¬Ý¤W¤@½g¤å³¹ */ + case 'k': /* itoc.000227: ¦ê¦C·j´M¤¤¡A¦³®É·Q¥Î k ¬Ý¤W¤@½g¤å³¹ */ + { + int pos = xo->pos - 1; + + /* itoc.000227: Á×§K¬Ý¹LÀY */ + if (pos < 0) + return xpost_head(xo); + + xo->pos = pos; + + if (pos <= xo->top) + xpost_pick(xo); + + continue; + } + + case KEY_DOWN: + case KEY_PGDN: + case ']': /* Thor.990204: ¦ê¦C·j´M¤¤¡A¦³®É·Q¥Î ] ¬Ý¤U¤@½g¤å³¹ */ + case 'j': /* Thor.990204: ¦ê¦C·j´M¤¤¡A¦³®É·Q¥Î j ¬Ý¤U¤@½g¤å³¹ */ + case ' ': + { + int pos = xo->pos + 1; + + /* Thor.980727: ×¥¿¬Ý¹LÀYªºbug */ + + if (pos >= xo->max) + return xpost_head(xo); + + xo->pos = pos; + + if (pos >= xo->top + XO_TALL) + xpost_pick(xo); + + continue; + } + + case 'y': + case 'r': + if (bbstate & STAT_POST) + { + if (do_reply(xo, hdr) == XO_INIT) /* ¦³¦¨¥\¦a post ¥X¥h¤F */ + return xpost_init(xo); + } + break; + + case 'm': + if ((bbstate & STAT_BOARD) && !(hdr->xmode & POST_MARKED)) + { + /* ¦b xpost_browse ®É¬Ý¤£¨ì m °O¸¹¡A©Ò¥H¨î¥u¯à mark */ + hdr->xmode ^= POST_MARKED; + currchrono = hdr->chrono; + rec_put(dir, hdr, sizeof(HDR), hdr->xid, cmpchrono); + } + break; + +#ifdef HAVE_SCORE + case '%': + post_score(xo); + return xpost_init(xo); +#endif + + case '/': + if (vget(b_lines, 0, "·j´M¡G", hunt, sizeof(hunt), DOECHO)) + { + key = more(fpath, FOOTER_POST); + goto re_key; + } + continue; + + case 'E': + return post_edit(xo); + + case 'C': /* itoc.000515: xpost_browse ®É¥i¦s¤J¼È¦sÀÉ */ + { + FILE *fp; + if (fp = tbf_open()) + { + f_suck(fp, fpath); + fclose(fp); + } + } + break; + + case 'h': + xo_help("post"); + break; + } + break; + } + + return xpost_head(xo); +} + + +int +xmbox_browse(xo) + XO *xo; +{ + HDR *hdr; + char *dir, fpath[64]; + + int key; + + dir = xo->dir; + + for (;;) + { + hdr = (HDR *) xo_pool + (xo->pos - xo->top); + + hdr_fpath(fpath, dir, hdr); + + /* Thor.990204: ¬°¦Ò¼{more ¶Ç¦^È */ + if ((key = more(fpath, FOOTER_MAILER)) < 0) + break; + + comebackPos = hdr->xid; + /* Thor.980911: ±q¦ê±µ¼Ò¦¡¦^¨Ó®Én¦^¨ì¬Ý¹Lªº¨º½g¤å³¹¦ì¸m */ + + strcpy(currtitle, str_ttl(hdr->title)); + +re_key: + /* Thor.990204: ¬°¦Ò¼{more ¶Ç¦^È */ + if (!key) + key = vkey(); + + switch (key) + { + case KEY_UP: + case KEY_PGUP: + case '[': /* itoc.000227: ¦ê¦C·j´M¤¤¡A¦³®É·Q¥Î [ ¬Ý¤W¤@½g¤å³¹ */ + case 'k': /* itoc.000227: ¦ê¦C·j´M¤¤¡A¦³®É·Q¥Î k ¬Ý¤W¤@½g¤å³¹ */ + { + int pos = xo->pos - 1; + + /* itoc.000227: Á×§K¬Ý¹LÀY */ + if (pos < 0) + return xpost_head(xo); + + xo->pos = pos; + + if (pos <= xo->top) + xpost_pick(xo); + + continue; + } + + case KEY_DOWN: + case KEY_PGDN: + case ']': /* Thor.990204: ¦ê¦C·j´M¤¤¡A¦³®É·Q¥Î ] ¬Ý¤U¤@½g¤å³¹ */ + case 'j': /* Thor.990204: ¦ê¦C·j´M¤¤¡A¦³®É·Q¥Î j ¬Ý¤U¤@½g¤å³¹ */ + case ' ': + { + int pos = xo->pos + 1; + + /* Thor.980727: ×¥¿¬Ý¹LÀYªºbug */ + + if (pos >= xo->max) + return xpost_head(xo); + + xo->pos = pos; + + if (pos >= xo->top + XO_TALL) + xpost_pick(xo); + + continue; + } + + case 'y': + case 'r': + strcpy(quote_file, fpath); + do_mreply(hdr, 1); + break; + + case 'm': + if (!(hdr->xmode & POST_MARKED)) + { + /* ¦b xmbox_browse ®É¬Ý¤£¨ì m °O¸¹¡A©Ò¥H¨î¥u¯à mark */ + hdr->xmode ^= POST_MARKED; + currchrono = hdr->chrono; + rec_put(dir, hdr, sizeof(HDR), hdr->xid, cmpchrono); + } + break; + + case '/': + if (vget(b_lines, 0, "·j´M¡G", hunt, sizeof(hunt), DOECHO)) + { + key = more(fpath, FOOTER_MAILER); + goto re_key; + } + continue; + + case 'E': + return mbox_edit(xo); + + case 'C': /* itoc.000515: xmbox_browse ®É¥i¦s¤J¼È¦sÀÉ */ + { + FILE *fp; + if (fp = tbf_open()) + { + f_suck(fp, fpath); + fclose(fp); + } + } + break; + + case 'h': + xo_help("mbox"); + break; + } + break; + } + + return xpost_head(xo); +} + + +#ifdef HAVE_XYNEWS /* itoc.010822: news ¾\Ū¼Ò¦¡ */ + +#if 0 /* ºc·Q */ + +¦b¤j¬ÝªO(³s½u¬ÝªO)¤¤±`±`¦³«Ü¦hÄé¤ô¤å³¹¡A¥é·Ó news ªº¾\Ū¤è¦¡¡A +§â©Ò¦³ reply ªº¤å³¹³£¥ýÁôÂáA¥uÅã¥Ü²Ä¤@«Êµo¤å¡C + +²Ä¤@½ü§Q¥Î XoNews ¨Óç°£ reply ¤å³¹ +²Ä¤G½ü§Q¥Î즳ªº XoXsearch ·j´M¦P¥DÃD¤å³¹ +¦p¦¹´N¥i¥H¹F¨ì·s»D¾\Ū¼Ò¦¡ªº®ÄªG + +#endif + + +static int *newsIndex; + +extern KeyFunc news_cb[]; + + +int +news_head(xo) + XO *xo; +{ + vs_head("·s»D¾\\Ū", xo->xyz); + prints(NECKER_NEWS, d_cols, ""); + return XO_BODY; +} + + +static void +news_pick(xo) + XO *xo; +{ + int *list, fsize, pos, max, top; + HDR *fimage, *hdr; + + fimage = (HDR *) f_map(xo->dir, &fsize); + if (fimage == (HDR *) - 1) + return; + + hdr = (HDR *) xo_pool; + list = newsIndex; + + pos = xo->pos; + xo->top = top = (pos / XO_TALL) * XO_TALL; + max = xo->max; + pos = top + XO_TALL; + if (max > pos) + max = pos; + + do + { + pos = list[top++]; + memcpy(hdr, fimage + pos, sizeof(HDR)); + /* hdr->xid = pos; */ /* ¦b XZ_NEWS ¨S¥Î¨ì xid¡A¥i¥H¦Ò¼{«O¯dµ¹ reply ½g¼Æ */ + hdr++; + } while (top < max); + + munmap(fimage, fsize); +} + + +int +news_init(xo) + XO *xo; +{ + /* load into pool */ + news_pick(xo); + return news_head(xo); +} + + +int +news_load(xo) + XO *xo; +{ + /* load into pool */ + news_pick(xo); + return XO_BODY; +} + + +int +XoNews(xo) /* itoc: News reader : call from post_cb */ + XO *xo; +{ + int returnPos; + int *list, fsize, max, count, i; + char *fimage; + HDR *head; + XO *xt; + + if (xo->max <= 0) /* Thor.980911: µù¸Ñ: ¥H¨¾¸U¤@ */ + return XO_FOOT; + +#ifdef EVERY_Z /* itoc.060206: ¥u¦³¥Î ^Z ¤~¥i¯à±q¤£¦P¬ÝªO¶i¤J·s»D¼Ò¦¡ */ + if (xz[XZ_NEWS - XO_ZONE].xo) /* itoc.020308: ¤£±o²Ö¿n¶i¤J¤G¦¸ */ + { + vmsg(MSG_XYDENY); + return XO_FOOT; + } +#endif + + /* build index according to input condition */ + + fimage = f_map(xo->dir, &fsize); + + if (fimage == (char *) -1) + { + vmsg("¥Ø«eµLªk¶}±Ò¯Á¤ÞÀÉ"); + return XO_FOOT; + } + + /* allocate index memory, remember free first */ + + /* Thor.990113: ©È°Ýtitle, authorªºÀþ¶¡¤S¦³¤Hpost */ + max = fsize / sizeof(HDR); + list = (int *) malloc(sizeof(int) * max); + + count = 0; + + for (i = 0; i < max; i++) + { + head = (HDR *) fimage + i; + +#ifdef HAVE_REFUSEMARK + if ((head->xmode & POST_RESTRICT) && + strcmp(head->owner, cuser.userid) && !(bbstate & STAT_BM)) + continue; +#endif + + /* check condition */ + if (STR4(head->title) == STR4(STR_REPLY)) /* reply ªº¤å³¹¤£n */ + continue; + + list[count++] = i; + } + + munmap(fimage, fsize); + + if (count <= 0) + { + free(list); + vmsg(MSG_XY_NONE); + return XO_FOOT; + } + + newsIndex = list; + + /* build XO for news_xo */ + + returnPos = xo->pos; /* Thor: record pos, future use */ + xz[XZ_NEWS - XO_ZONE].xo = xt = xo_new(xo->dir); + xz[XZ_NEWS - XO_ZONE].cb = news_cb; + xt->pos = 0; + xt->max = count; + xt->xyz = xo->xyz; + xt->key = XZ_NEWS; + + xover(XZ_NEWS); + + /* set xo->pos for new location */ + + xo->pos = returnPos; /* ±q XZ_NEWS ¦^¨ì XZ_POST ´å¼Ð²¾¥hì¨Óªº¦a¤è */ + + /* free news_xo */ + + if (xt = xz[XZ_NEWS - XO_ZONE].xo) + { + free(xt); + xz[XZ_NEWS - XO_ZONE].xo = NULL; + } + + /* free index memory, remember check free pointer */ + + if (list) + free(list); + + return XO_INIT; +} +#endif /* HAVE_XYNEWS */ diff --git a/pip/Makefile b/pip/Makefile new file mode 100644 index 0000000..0ba0650 --- /dev/null +++ b/pip/Makefile @@ -0,0 +1,64 @@ +# ------------------------------------------------------ # +# Makefile ( NTHU CS MapleBBS Ver 3.10 ) # +# ------------------------------------------------------ # +# author : itoc.bbs@bbs.tnfsh.tn.edu.tw # +# target : Makefile for PIP GAME main programs # +# create : 01/07/24 # +# update : / / # +# ------------------------------------------------------ # + + +# ------------------------------------------------------ # +# ¤U¦Cªº make rules ¤£»Ý×§ï # +# ------------------------------------------------------ # + + +OBJ = pip_basic.o pip_ending.o pip_fight.o pip_item.o pip_job.o \ + pip_menu.o pip_pk.o pip_play.o pip_prac.o pip_quest.o pip_race.o \ + pip_royal.o pip_stuff.o pip_visio.o pip_weapon.o pip.o + + +SO = pip.so + + +all: + @echo "Please enter 'make sys-type', " + @echo " make sun : for Sun-OS 4.x and maybe some BSD systems, cc or gcc" + @echo " make linux : for Linux" + @echo " make solaris : for Sun-OS 5.x gcc" + @echo " make sol-x86 : for Solaris 7 x86" + @echo " make freebsd : for BSD 4.4 systems" + @echo " make bsd : for BSD systems, cc or gcc, if not in the above lists" + @echo " make cygwin : for Microsoft Windows and Cygwin gcc" + +sun: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -fomit-frame-pointer -Wunused -I../include" $(SO) + +linux: + @$(MAKE) CC=gcc CFLAGS="-DLINUX -O2 -pipe -fomit-frame-pointer -Wunused -I../include" $(SO) + +solaris: + @$(MAKE) CC=gcc CFLAGS="-DSOLARIS -DSYSV -O2 -pipe -fomit-frame-pointer -Wunused -I../include" $(SO) + +sol-x86: + @$(MAKE) CC=gcc CFLAGS="-DSOLARIS -DSYSV -O2 -fomit-frame-pointer -Wunused -I../include" $(SO) + +freebsd: + @$(MAKE) CC=gcc CFLAGS="-DBSD44 -O2 -pipe -fomit-frame-pointer -Wunused -I../include" $(SO) + +bsd: + @$(MAKE) CC=gcc CFLAGS="-DBSD44 -O2 -pipe -fomit-frame-pointer -Wunused -I../include" $(SO) + +cygwin: + @cd ../maple; make cygwin + + +pip.so: $(OBJ) + ld -s -G $(OBJ) -o pip.so -L../lib -ldao + + +install: $(SO) + install -m 0700 $? $(HOME)/bin + +clean: + rm -f $(SO) *.o *~ diff --git a/pip/pip.c b/pip/pip.c new file mode 100644 index 0000000..83a8ac3 --- /dev/null +++ b/pip/pip.c @@ -0,0 +1,241 @@ +/*-------------------------------------------------------*/ +/* pip.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¾i¤pÂû¹CÀ¸ */ +/* create : / / */ +/* update : 01/08/14 */ +/* author : dsyan.bbs@forever.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + + +#define _PIPMAIN_C_ /* ¥ý define _PIPMAIN_C_ ¦A¤Þ¶i pip.h */ + +#include "pip.h" + + +/*-------------------------------------------------------*/ +/* ¥Dµ{¦¡ */ +/*-------------------------------------------------------*/ + +#define ALIVE (9/10) /* ´_¬¡¥H«áªº¯à¤O¬Oì¨Óªº 90% */ + +static void +pip_live_again() +{ + vs_head("¤pÂû´_¬¡¤â³N¤¤", str_site); + + /* itoc.010814: ´_¬¡¥H«ánÅýª±®aÁÙª±ªº¤U¥h¡A©Ò¥H¤£°µ¡u¯}Ãa©Ê¡v + ªº°ÄݩʡA¹³ maxhp..µ¥¤£ÅÜ */ + + /* °ò¥»ªº¸ê®Æ */ + d.death = 0; + d.liveagain++; + + /* ª¬ºAªº¼ÆÈ */ + d.relation = 0; /* ¤H©MÃdª«ªº¤¬°Ê´c¤Æ */ + d.happy = 20; /* Åܱo¤£§Ö¼Ö */ + d.satisfy = 20; /* Åܱo¤£º¡·N */ + + /* ¨Å骺°Ñ¼Æ */ + d.weight = (rand() % 10) + 55 + (d.bbtime / 180); + d.tired = 20; + d.sick = 20; + d.shit = 20; + + /* µû»ù´î¤Ö */ + d.social = d.social * ALIVE; + d.family = d.family * ALIVE; + d.hexp = d.hexp * ALIVE; + d.mexp = d.mexp * ALIVE; + + /* Âk¹s */ + d.hp = d.maxhp; + d.mp = 0; + d.vp = 0; + d.sp = 0; + + vmsg("¤pÂû¤S´_¬¡¤F¡A¤£n¦A§â¨e¾i¦º¤F³á¡I"); + + pip_write_file(); +} + + +static int /* 1:¥Ó½Ð¦¨¥\ 0:¥¢±Ñ */ +pip_apply() /* ·s¤pÂû¥Ó½Ð */ +{ + time_t now; + struct tm *ptime; + + memset(&d, 0, sizeof(d)); + + vs_head(BBSNAME PIPNAME, str_site); + + /* ¤pÂû©R¦W */ + if (!vget(2, 0, " À°¤pÂû¨úÓ¦nÅ¥ªº¦W¦r§a¡G", d.name, IDLEN + 1, DOECHO)) + return 0; + + /* 1:¤½ 2:¥À */ + d.sex = (ians(4, 3, "©Ê§O¡G(1) ¤p¤½Âû¡ñ (2) ¤p¥ÀÂû¡ð (1/2)¡H[1] ") == '2') ? 2 : 1; + + move(6, 0); + outs(" " BBSNAME PIPNAME "ªº¹CÀ¸²{¤µ¤À¦¨¨âºØª±ªk\n"); + outs(" ¿ï¦³µ²§½·|¦b¤pÂû 20 ·³®Éµ²§ô¹CÀ¸¡A¨Ã§iª¾¤pÂû«áÄòªºµo®i\n"); + outs(" ¿ï¨S¦³µ²§½«h¤@ª½¾i¨ì¤pÂû¦º¤`¤~µ²§ô¹CÀ¸...."); + + /* 1:¤£n¥B¥¼±B 4:n¥B¥¼±B */ + d.wantend = (ians(9, 0, " ±z§Æ±æ¤pÂû¹CÀ¸¬O§_n¦³ 20 ·³µ²§½(Y/N)¡H[Y] ") == 'n') ? 1 : 4; + + /* ¶}ÀYµe± */ + show_basic_pic(0); + vmsg("¤pÂû²×©ó½Ï¥Í¤F¡A½Ð¦n¦n·R¥L...."); + + /* ¶}ÀY³]©w¡G¨S¦³³]©wªºÄæ¦ì³£¬O¹w³] 0 */ + time(&now); + ptime = localtime(&now); + sprintf(d.birth, "%02d/%02d/%02d", ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday); + + /* °ò¥»¸ê®Æ */ + d.year = ptime->tm_year; + d.month = ptime->tm_mon + 1; + d.day = ptime->tm_mday; + + /* ¨Åé°Ñ¼Æ */ + d.weight = rand() % 10 + 50; + + /* µû»ù°Ñ¼Æ : ¹w³] 0 */ + + /* ¾Ô°«°Ñ¼Æ */ + d.level = 1; + d.hp = d.maxhp = rand() % 20 + 40; + d.mp = d.maxmp = rand() % 20 + 40; + d.vp = d.maxvp = rand() % 20 + 40; + d.sp = d.maxsp = rand() % 20 + 40; + + /* §Þ¯à°Ñ¼Æ : ¹w³] 0 */ + /* ªZ¾¹°Ñ¼Æ : ¹w³] 0 */ + /* ¯à¤O°Ñ¼Æ : ¹w³] 0 */ + + /* ª¬ºA¼ÆÈ */ + d.happy = rand() % 10 + 45; + d.satisfy = rand() % 10 + 45; + + /* ¹ª«°Ñ¼Æ */ + d.food = 20; + d.cookie = 2; + + /* ª««~°Ñ¼Æ : ¹w³] 0 */ + d.money = 1000; + + /* ²q®±°Ñ¼Æ : ¹w³] 0 */ + + /* °Ñ¨£¤ý¦Ú */ + d.seeroyalJ = 1; + + /* ±µ¨ü¨D±B·R¤H : ¹w³] 0 */ + /* ¤u§@«ü¼Æ : ¹w³] 0 */ + + /* ¤@¥Í¥u¯à¾Ç±o¤@¶µ¯S®í§Þ¯à */ + pip_learn_skill(0); + + pip_write_file(); + return 1; +} + + +static int +pip_reborn() /* ¤pÂû«¥Í */ +{ + vs_head(BBSNAME PIPNAME, str_site); + move(4, 0); + outs(" Åwªï¨Ó¨ì\033[1;33m" BBSNAME "¥Íª«¬ì§Þ¬ã¨s°|\033[m\n\n"); + outs(" ¸g§Ú̽լdÅã¥Ü ¥ý«e±z¦³¾i¹L¤pÂû³á ¥i¬O³Q±z¾i¦º¤F\n\n"); + + if (ians(7, 3, "±zn§ÚÌÅý¨e«¥Í¶Ü(Y/N)¡H[N] ") == 'y') + { + pip_live_again(); + return 1; + } + else + { + if (pip_apply()) + return 1; + } + + return 0; +} + + +/* ¹CÀ¸¥Dµ{¦¡ */ +int +main_pip() +{ + int ch; + char fpath[64]; + + /* more(PIP_PICHOME "pip.welcome", NULL); */ + vs_head("¹q¤l¾i¤pÂû", str_site); + + usr_fpath(fpath, cuser.userid, fn_pip); + + if (!dashf(fpath)) /* ¤§«e¨Sª±¹L¤pÂû */ + { + show_system_pic(11); + + if (vkey() == 'q') + return 0; + + if (!pip_apply()) + return 0; + } + else + { + show_system_pic(12); + + if ((ch = vkey()) == 'r') + { + if (!pip_read_backup()) + return 0; + } + else if (ch == 'q') + { + return 0; + } + else + { + pip_read_file(cuser.userid, &d); + + if (d.death == 1) /* ª±¦º¤F¥i¿ï¾Ü«¥Í */ + { + if (!pip_reborn()) + return 0; + } + else if (d.death) /* ©ñ¥Í©Îµ²§ôªº¸Ün«·s¶}©l */ + { + if (!pip_apply()) + return 0; + } + } + } + + start_time = time(0); + last_time = start_time; + + /* itoc.010816: ¥Ñ©ó²Ä¤@¦¸¶i¤J¥D¿ï³æ¨S¦³¤¤¶¡ªº¤pÂû¹Ï¡A©Ò¥Hn¥t¥~µ¹ */ + clrfromto(5, 18); + outs("\033[34m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m"); + show_basic_pic(21); + move(18, 0); + outs("\033[34m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m"); + + pip_main_menu(); + + pip_write_file(); /* Â÷¶}¹CÀ¸¦Û°Ê¦sÀÉ */ + return 0; +} +#endif /* HAVE_GAME */ diff --git a/pip/pip.h b/pip/pip.h new file mode 100644 index 0000000..da145c7 --- /dev/null +++ b/pip/pip.h @@ -0,0 +1,63 @@ +/* ----------------------------------------------------- */ +/* pip.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/* ----------------------------------------------------- */ +/* target : ¤pÂû data structure */ +/* create : 01/08/16 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/* ----------------------------------------------------- */ + + +#ifndef _PIP_H_ +#define _PIP_H_ + + +#if 0 /* ª©Åv«Å§i */ + + ®Ú¾Ú§Úªº¦ÒÃÒ¡A¹q¤lÂûªº³Ì«e¨¬O¥Ñ [¤Ñªø¦a¤[ dsyan] ©Ò¼¶¼g¡A + ±µµÛ¦b [¶³³¾¤Ñ°ó fennet] ¤â¤¤°µ¤F¤@¨ÇÅܰʡA + «á¨Ó¦b [¬PªÅ¤Uªº©]¸Ì chiyuan] ¤j§ïª©¡A§Î¦¨¤F¬PªÅ¾Ô°«Âû¡C + + ¨ä«á [·¤§¶ð visor] ±N³oµ{¦¡ port ¨ì WindTopBBS ¨Ó¨Ï¥Î¡A + ¥Ø«e [»P«n¦@»R itoc] ¦b¥H³oª©µ{¦¡¬°°ò¦¤U¡A°µ¤F¤j´T«×ªº§ïª©¡C + + ¦UÀɮפw¸g³Q§Ú§¹¾ã¦a§ï¹L¤F¡A¦b¬Y¨Ç¤è±°µ¤F¤@¨Ç³Ì¨Î¤Æ¡A + ¥]¬Aµ{¦¡ªº«·s¼¶¼g¡B·s idea ªº¥[¤Jµ¥µ¥¡A¤ñ¸û«nªºÅܰʻ¡©ú©ó¤U¡G + + 1) ±N¤@Óªñ¸U¦æªºµ{¦¡¼Ò²Õ¤Æ¡A©î´²¨ì¦U *.c ¤¤¡A¥H«á¦b°µ×§ï®É¯à§ó¤è«K¡C + 2) ±N¦Uµ{¦¡¥H indent ±Æª©¡A¤O¨D¨t²ÎºûÅ@ªÌ¾\Ūµ{¦¡ªº«K§Q¡C + 3) struct °µÅܰʡA¥[¤J¤@¨Ç·sªºÄæ¦ì¡C + 4) ¾Ô°«/צæ¥[´îÄݩʤ½¦¡¤§ÅܰʡC + 5) ¼¶¼g©ÇÃ~²£¥Í¾¹ªºµ{¦¡¡C + 6) ¼¶¼g¦a¹Ï²£¥Í¾¹ªºµ{¦¡¡C + 7) «·s³Ð³y·sªº§Þ¯à¬[ºc¡C + 8) ·s¼W¤@¨Ç¶Ã¼Æ¨Æ¥ó¡A¹³¬O¾Ç¨ì§Þ¯à©Î¬O¹J¨ì¯¸ªøµ¥¡C + 9) ·s¼W¥ô°È¬[ºc¡A¤É¯Ån¸Ñ¥ô°È¡C + 10) §ïµ½ªZ¾¹¨t²Î¡AÅý¨CÓ¤HªºªZ¾¹¦h¼Ë¤Æ¡C + 11) ²Î¤@©Ò¦³ªº¥Î¦r¤Îµe±³B²z¡C + 12) ¥[¤J¤j¶qªºµù¸Ñ¡C + 13) ¤j´T«×´î¤Ö¤£¥²nªº«Ã¸¡C + 14) ¨ä¥L.. + + §Æ±æ³o¨Ç§V¤O¡A¯àµ¹±z±a¨Ó³\¦h«K§Q¡A¦pªG¦³¤°»ò·N¨£¡A¤]Åwªï¨Ó«H«ü±Ð¡C + + ¥x«n¤@¤¤ »P«n¦@»R itoc.bbs@bbs.tnfsh.tn.edu.tw 2001.08.16 + +#endif + +/* include Àɧ¡©R¦W¬° pipxxx.h C Àɧ¡©R¦W¬° pip_xxx.c */ +#include "pipglobal.h" +#include "pipstruct.h" + + +#define PIP_PICHOME "etc/game/pip/" + + +#define LEARN_LEVEL ((d.happy+d.satisfy)/100) /* ¾Ç²ß®ÄªG»P§Ö¼Ö¤Îº¡¨¬¦¨¥¿¤ñ */ + + +/* itoc.010801: ¨q¥X³Ì«á¤G¦Cªº«ü¥O¦C */ +#define out_cmd(cmd_1,cmd_2) { move(b_lines - 1, 0); clrtoeol(); outs(cmd_1); \ + move(b_lines, 0); clrtoeol(); outs(cmd_2); } + +#endif /* _PIP_H_ */ diff --git a/pip/pip_basic.c b/pip/pip_basic.c new file mode 100644 index 0000000..dd3b51f --- /dev/null +++ b/pip/pip_basic.c @@ -0,0 +1,350 @@ +/*-------------------------------------------------------*/ +/* pip_basic.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : °ò¥»¿ï³æ */ +/* create : / / */ +/* update : 01/08/14 */ +/* author : dsyan.bbs@forever.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#include "pip.h" + + +/*-------------------------------------------------------*/ +/* °ò¥»¿ï³æ:Áý¹ ²M¼ä ¿Ë¿Ë ¥ð®§ ´«Âûª÷ */ +/*-------------------------------------------------------*/ + + +int /* 1: ¨S¦Y¹ª«¡A©ñ±ó 0: ¦Y¤F */ +pip_basic_feed() /* Áý¹ */ +{ + int ch; + int nodone; /* itoc.010731: °O¿ý¬O§_¦³¦æ°Ê */ + + nodone = 1; + + do + { + out_cmd(COLOR1 " ¤@¯ë " COLOR2 " [1]¦Y¶º [2]¹s¹ [3]®Ñ¥» [4]ª±¨ã [5]Ūª« [Q]¸õ¥X \033[m", + COLOR1 " ÃÄ«~ " COLOR2 " [a]¤jÁÙ [b]ÆFªÛ [c]¸É¤Y [d]¤Hçx [e]¶Â¥É [f]³·½¬ [Q]¸õ¥X \033[m"); + + switch (ch = vkey()) + { + case '1': /* ¦Y¶º */ + if (d.food <= 0) + { + vmsg("¨S¦³¹ª«Åo..§Ö¥h¶R§a¡I"); + break; + } + d.food--; + d.hp += 50; + if (d.hp > d.maxhp) + { + d.hp = d.maxhp; + d.weight += rand() % 2; + } + nodone = 0; + if ((d.bbtime / 60 / 30) < 3) /* ¥¼º¡¤T·³ */ + show_feed_pic(11); + else + show_feed_pic(12); + vmsg("¨C¦Y¤@¦¸¹ª«·|«ì´_Åé¤O50³á!"); + break; + + case '2': /* ¹s¹ */ + if (d.cookie <= 0) + { + vmsg("¹s¹¦Y¥úÅo..§Ö¥h¶R§a¡I"); + break; + } + d.cookie--; + d.hp += 100; + if (d.hp > d.maxhp) + { + d.hp = d.maxhp; + d.weight += rand() % 2 + 2; + } + else + { + d.weight += (rand() % 2 + 1); + } + d.happy += (rand() % 3 + 4); + d.satisfy += rand() % 3 + 2; + nodone = 0; + if (rand() % 2) + show_feed_pic(21); + else + show_feed_pic(22); + vmsg("¦Y¹s¹®e©öD³á..."); + break; + + case '3': /* ®Ñ¥» */ + if (d.book <= 0) + { + vmsg("¨S¦³®Ñ¥»Åo..§Ö¥h¶R§a¡I"); + break; + } + d.book--; + d.happy -= 5; + d.wisdom+= 20; + d.art += 20; + nodone = 0; + show_feed_pic(31); + vmsg("¶}¨÷¦³¯q"); + break; + + case '4': /* ª±¨ã */ + if (d.toy <= 0) + { + vmsg("¨S¦³ª±¨ãÅo..§Ö¥h¶R§a¡I"); + break; + } + d.toy--; + d.happy += 20; + d.satisfy += 20; + nodone = 0; + show_feed_pic(41); + vmsg("ª±ª±¨ãªº¤p«Ä¤£·|ÅÜÃa"); + break; + + case '5': /* Ūª« */ + if (d.playboy <= 0) + { + vmsg("¨S¦³½Ò¥~Ūª«Åo..§Ö¥h¶R§a¡I"); + break; + } + if ((d.bbtime / 60 / 30) < 5) + { + /* itoc.010801: ¤·³¥H«á¤~¯à¬Ý :p */ + vmsg("«Ê±¤W¼gµÛ 5 ¸T ¢æ"); + break; + } + d.playboy--; + /* itoc.010801: ¼W¥[¸o´c¡A¦ý§Ö¼Ö/º¡·N¤j¶q¤W¤É */ + d.happy = 100; + d.satisfy = 100; + d.art += 5; + d.sin += 30; + nodone = 0; + show_feed_pic(51); + vmsg("©I©I¡AÁÙ¦n¨S¤H¬Ý¨£"); + break; + + case 'a': /* ¤jÁÙ */ + if (d.pill <= 0) + { + vmsg("¨S¦³¤jÁÙ¤¦Åo..§Ö¥h¶R§a¡I"); + break; + } + d.pill--; + d.hp += 1000; + if (d.hp > d.maxhp) + d.hp = d.maxhp; + nodone = 0; + show_feed_pic(61); + vmsg("¨C¦Y¤@¦¸¤jÁÙ¤¦·|«ì´_Åé¤O 1000 ³á!"); + break; + + case 'b': + if (d.medicine <= 0) + { + vmsg("¨S¦³ÆFªÛÅo..§Ö¥h¶R§a¡I"); + break; + } + d.medicine--; + d.mp += 1000; + if (d.mp > d.maxmp) + d.mp = d.maxmp; + nodone = 0; + show_feed_pic(71); + vmsg("¨C¦Y¤@¦¸ÆFªÛ·|«ì´_ªk¤O 1000 ³á!"); + break; + + case 'c': /* ¸É¤Y */ + if (d.burger <= 0) + { + vmsg("¨S¦³¤j¸É¤Y¤FC! §Ö¥h¶R§a.."); + break; + } + d.burger--; + d.vp += 1000; + if (d.vp > d.maxvp) + d.vp = d.maxvp; + nodone = 0; + show_feed_pic(81); + vmsg("¨C¦Y¤@¦¸¸É¤Y·|«ì´_²¾°Ê 1000 ³á!"); + break; + + case 'd': /* ¤Hçx */ + if (d.ginseng <= 0) + { + vmsg("¨S¦³¤d¦~¤HçxC! §Ö¥h¶R§a.."); + break; + } + d.ginseng--; + d.sp += 1000; + if (d.sp > d.maxsp) + d.sp = d.maxsp; + nodone = 0; + show_feed_pic(91); + vmsg("¨C¦Y¤@¦¸¤Hçx·|«ì´_¤º¤O 1000 ³á!"); + break; + + case 'e': /* ¶Â¥É */ + if (d.paste <= 0) + { + vmsg("¨S¦³¶Â¥ÉÂ_Äò»IC! §Ö¥h¶R§a.."); + break; + } + d.snowgrass--; + d.hp = d.maxhp; + d.tired = 0; + d.sick = 0; + nodone = 0; + show_feed_pic(101); + vmsg("¶Â¥ÉÂ_Äò»I..¶W·¥´Îªºò..."); + break; + + case 'f': /* ³·½¬ */ + if (d.snowgrass <= 0) + { + vmsg("¨S¦³¤Ñ¤s³·½¬C! §Ö¥h¶R§a.."); + break; + } + d.snowgrass--; + d.hp = d.maxhp; + d.mp = d.maxmp; + d.vp = d.maxvp; + d.sp = d.maxsp; + d.tired = 0; + d.sick = 0; + nodone = 0; + show_feed_pic(111); + vmsg("¤Ñ¤s³·½¬..¶W·¥´Îªºò..."); + break; + } + } while (ch != 'q' && ch != KEY_LEFT); + + return nodone; +} + + +int +pip_basic_takeshower() /* ¬~¾þ */ +{ + d.shit -= 20; + if (d.shit < 0) + d.shit = 0; + + d.hp -= rand() % 2 + 3; + + switch(rand() % 3) + { + case 0: + show_usual_pic(1); + vmsg("§Ú¬O°®²bªº¤pÂû cccc...."); + break; + + case 1: + show_usual_pic(7); + vmsg("°¨±í ¶â¡ã¡ã"); + break; + + case 2: + show_usual_pic(2); + vmsg("§Ú·R¬~¾þ lalala...."); + break; + } + return 0; +} + + +int +pip_basic_takerest() /* ¥ð®§ */ +{ + count_tired(5, 20, 1, 100, 0); /* «ì´_¯h³Ò */ + d.shit++; + d.hp += d.maxhp / 10; + if (d.hp > d.maxhp) + d.hp = d.maxhp; + + show_usual_pic(5); + vmsg("¦A«ö¤@¤U§Ú´N°_§ÉÅo...."); + show_usual_pic(6); + vmsg("³Þ³Þ³Þ..¸Ó°_§ÉÅo......"); + return 0; +} + + +int +pip_basic_kiss() /* ¿Ë¿Ë */ +{ + if (rand() % 2) + { + d.happy += rand() % 3 + 4; + d.satisfy += rand() % 2 + 1; + } + else + { + d.happy += rand() % 2 + 1; + d.satisfy += rand() % 3 + 4; + } + count_tired(1, 2, 0, 100, 1); + d.shit += rand() % 5 + 4; + d.relation += rand() % 2; + + show_usual_pic(3); + + if (d.shit < 60) + vmsg("¨Ó¹À! Ôq¤@Ó....."); + else + vmsg("¿Ë¤Ó¦h¤]¬O·|ż¦ºªº³á...."); + + return 0; +} + + +int +pip_money() +{ + int money; + char buf[80]; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return 0; + } + + /* itoc.µù¸Ñ: ¤§©Ò¥H¤£´£¨Ñ¤pÂû¹ô´«»È¹ôªºì¦]¬O¦]¬°¤pÂû¥i¥HÀx¦s/Ū¨ú¶i«× */ + + clrfromto(6, 18); + prints("±z¨¤W¦³ %d »È¹ô,Âûª÷ %d ¤¸\n", cuser.money, d.money); + outs("\n¤@»È¹ô´«¤@Âûª÷ò¡I\n"); + + do + { + if (!vget(10, 0, "n´«¦h¤Ö»È¹ô¡H[Q] ", buf, 10, DOECHO)) + return 0; + money = atol(buf); + } while (money <= 0 || money > cuser.money); + + sprintf(buf, "¬O§_nÂà´« %d »È¹ô ¬° %d Âûª÷(Y/N)¡H[N] ", money, money); + if (ians(11, 0, buf) == 'y') + { + cuser.money -= money; + d.money += money; + sprintf(buf, "±z¨¤W¦³ %d ¦¸»È¹ô,Âûª÷ %d ¤¸", cuser.money, d.money); + vmsg(buf); + return 1; + } + vmsg("¨ú®ø...."); + return 0; +} +#endif /* HAVE_GAME */ diff --git a/pip/pip_ending.c b/pip/pip_ending.c new file mode 100644 index 0000000..25a981d --- /dev/null +++ b/pip/pip_ending.c @@ -0,0 +1,1040 @@ +/*-------------------------------------------------------*/ +/* pip_ending.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : µ²§½¨ç¦¡ */ +/* create : / / */ +/* update : 01/08/14 */ +/* author : dsyan.bbs@forever.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#include "pip.h" + + +/* ------------------------------------------------------- */ +/* µ²§½°Ñ¼Æ³]©w */ +/* ------------------------------------------------------- */ + + +struct endingset +{ + char *girl; /* ¤k¥Íµ²§½ªºÂ¾·~ */ + char *boy; /* ¨k¥Íµ²§½ªºÂ¾·~ */ + int grade; /* µû¤À */ +}; +typedef struct endingset endingset; + + +/* ¸U¯àÃþ */ +struct endingset endmodeallpurpose[] = +{ + "¤k©Ê¾·~", "¨k¥Í¾·~", 0, + "¦¨¬°³oÓ°ê®a·s¤k¤ý", "¦¨¬°³oÓ°ê®a·s°ê¤ý", 500, + "¦¨¬°°ê®aªº®_¬Û", "¦¨¬°°ê®aªº®_¬Û", 400, + "¦¨¬°±Ð·|¤¤ªº¤j¥D±Ð", "¦¨¬°±Ð·|¤¤ªº±Ð©v", 350, + "¦¨¬°°ê®aªº¤j¦Ú", "¦¨¬°°ê®aªº¤j¦Ú", 320, + "¦¨¬°¤@¦ì³Õ¤h", "¦¨¬°¤@¦ì³Õ¤h", 300, + "¦¨¬°±Ð·|¤¤ªº×¤k", "¦¨¬°±Ð·|¤¤ªº¯«¤÷", 150, + "¦¨¬°ªk®x¤Wªºªk©x", "¦¨¬°ªk®x¤Wªºªk©x", 200, + "¦¨¬°ª¾¦Wªº¾ÇªÌ", "¦¨¬°ª¾¦Wªº¾ÇªÌ", 120, + "¦¨¬°¤@¦W¤k©x", "¦¨¬°¤@¦W¨k©x", 100, + "¦b¨|¥®°|¤u§@", "¦b¨|¥®°|¤u§@", 100, + "¦b®ÈÀ]¤u§@", "¦b®ÈÀ]¤u§@", 100, + "¦b¹A³õ¤u§@", "¦b¹A³õ¤u§@", 100, + "¦bÀ\\ÆU¤u§@", "¦bÀ\\ÆU¤u§@", 100, + "¦b±Ð°ó¤u§@", "¦b±Ð°ó¤u§@", 100, + "¦b¦aÅu¤u§@", "¦b¦aÅu¤u§@", 100, + "¦b¥ï¤ì³õ¤u§@", "¦b¥ï¤ì³õ¤u§@", 100, + "¦b¬ü®e°|¤u§@", "¦b¬ü®e°|¤u§@", 100, + "¦b¬¼Ây°Ï¤u§@", "¦b¬¼Ây°Ï¤u§@", 100, + "¦b¤u¦a¤u§@", "¦b¤u¦a¤u§@", 100, + "¦b¹Ó¶é¤u§@", "¦b¹Ó¶é¤u§@", 100, + "¾á¥ô®a®x±Ð®v¤u§@", "¾á¥ô®a®x±Ð®v¤u§@", 100, + "¦b°s®a¤u§@", "¦b°s®a¤u§@", 100, + "¦b°s©±¤u§@", "¦b°s©±¤u§@", 100, + "¦b¤j©]Á`·|¤u§@", "¦b¤j©]Á`·|¤u§@", 100, + "¦b®a¤¤À°¦£", "¦b®a¤¤À°¦£", 50, + "¦b¨|¥®°|Ý®t", "¦b¨|¥®°|Ý®t", 50, + "¦b®ÈÀ]Ý®t", "¦b®ÈÀ]Ý®t", 50, + "¦b¹A³õÝ®t", "¦b¹A³õÝ®t", 50, + "¦bÀ\\ÆUÝ®t", "¦bÀ\\ÆUÝ®t", 50, + "¦b±Ð°óÝ®t", "¦b±Ð°óÝ®t", 50, + "¦b¦aÅuÝ®t", "¦b¦aÅuÝ®t", 50, + "¦b¥ï¤ì³õÝ®t", "¦b¥ï¤ì³õÝ®t", 50, + "¦b¬ü®e°|Ý®t", "¦b¬ü®e°|Ý®t", 50, + "¦b¬¼Ây°ÏÝ®t", "¦b¬¼Ây°ÏÝ®t", 50, + "¦b¤u¦aÝ®t", "¦b¤u¦aÝ®t", 50, + "¦b¹Ó¶éÝ®t", "¦b¹Ó¶éÝ®t", 50, + "¾á¥ô®a®x±Ð®vÝ®t", "¾á¥ô®a®x±Ð®vÝ®t", 50, + "¦b°s®aÝ®t", "¦b°s®aÝ®t", 50, + "¦b°s©±Ý®t", "¦b°s©±Ý®t", 50, + "¦b¤j©]Á`·|Ý®t", "¦b¤j©]Á`·|Ý®t", 50, + NULL, NULL, 0 +}; + + +/* ¾Ô°«Ãþ */ +struct endingset endmodecombat[] = +{ + "¤k©Ê¾·~", "¨k¥Í¾·~", 0, + "³Q«Ê¬°«iªÌ ¾Ô¤h«¬", "³Q«Ê¬°«iªÌ ¾Ô¤h«¬", 420, + "³Q©ÞÀ¬°¤@°êªº±Nx", "³Q©ÞÀ¬°¤@°êªº±Nx", 300, + "·í¤W°ê®aªñ½Ã¶¤¶¤ªø", "·í¤W°ê®aªñ½Ã¶¤¶¤ªø", 200, + "·í¤FªZ³N¦Ñ®v", "·í¤FªZ³N¦Ñ®v", 150, + "Åܦ¨ÃM¤h³ø®Ä°ê®a", "Åܦ¨ÃM¤h³ø®Ä°ê®a", 160, + "§ë¨x®È¦¨¬°¤h§L", "§ë¨x®È¦¨¬°¤h§L", 80, + "Åܦ¨¼úª÷Ây¤H", "Åܦ¨¼úª÷Ây¤H", 10, + "¥H¶Ä§L¤u§@ºû¥Í", "¥H¶Ä§L¤u§@ºû¥Í", 10, + NULL, NULL, 0 +}; + + +/* Å]ªkÃþ */ +struct endingset endmodemagic[] = +{ + "¤k©Ê¾·~", "¨k¥Í¾·~", 0, + "³Q«Ê¬°«iªÌ Å]ªk«¬", "³Q«Ê¬°«iªÌ Å]ªk«¬", 420, + "³Q¸u¬°¤ý®cÅ]ªk®v", "³Q¸u¬°¤ý©xÅ]ªk®v", 280, + "·í¤FÅ]ªk¦Ñ®v", "·í¤FÅ]ªk¦Ñ®v", 160, + "Åܦ¨¤@¦ìÅ]¾É¤h", "Åܦ¨¤@¦ìÅ]¾É¤h", 180, + "·í¤FÅ]ªk®v", "·í¤FÅ]ªk®v", 120, + "¥H¥e¤RÀ°¤Hºâ©R¬°¥Í", "¥H¥e¤RÀ°¤Hºâ©R¬°¥Í", 40, + "¦¨¬°¤@ÓÅ]³N®v", "¦¨¬°¤@ÓÅ]³N®v", 20, + "¦¨¬°µóÀYÃÀ¤H", "¦¨¬°µóÀYÃÀ¤H", 10, + NULL, NULL, 0 +}; + + +/* ªÀ¥æÃþ */ +struct endingset endmodesocial[] = +{ + "¤k©Ê¾·~", "¨k¥Í¾·~", 0, + "¦¨¬°°ê¤ýªºÃd¦m", "¦¨¬°¤k¤ýªº¾t°¨·Ý", 170, + "³Q¬D¿ï¦¨¬°¤ý¦m", "³Q¿ï¤¤·í¤k¤ýªº¤Ò´B", 260, + "¦¨¬°§BÀ諸¤Ò¤H", "¦¨¬°¤F¤k§BÀ諸¤Ò´B", 130, + "¦¨¬°´I»¨ªº©d¤l", "¦¨¬°¤k´I»¨ªº¤Ò´B", 100, + "¦¨¬°°Ó¤Hªº©d¤l", "¦¨¬°¤k°Ó¤Hªº¤Ò´B", 80, + "¦¨¬°¹A¤Hªº©d¤l", "¦¨¬°¤k¹A¤Hªº¤Ò´B", 80, + "¦¨¬°¦a¥Dªº±¡°ü", "¦¨¬°¤k¦a¥Dªº±¡¤Ò", -40, + NULL, NULL, 0 +}; + + +/* ÃÀ³NÃþ */ +struct endingset endmodeart[] = +{ + "¤k©Ê¾·~", "¨k¥Í¾·~", 0, + "¦¨¬°¤F¤p¤¡", "¦¨¬°¤F¤p¤¡", 100, + "¦¨¬°¤F§@®a", "¦¨¬°¤F§@®a", 100, + "¦¨¬°¤Fµe®a", "¦¨¬°¤Fµe®a", 100, + "¦¨¬°¤F»RÁЮa", "¦¨¬°¤F»RÁЮa", 100, + NULL, NULL, 0 +}; + + +/* ·t¶ÂÃþ */ +struct endingset endmodeblack[] = +{ + "¤k©Ê¾·~", "¨k¥Í¾·~", 0, + "Åܦ¨¤F¤kÅ]¤ý", "Åܦ¨¤F¤jÅ]¤ý", -1000, + "²V¦¨¤F¤Ó©f", "²V¦¨¤F¬yª]", -350, + "°µ¤F¢á¢Û¤k¤ýªº¤u§@", "°µ¤F¢á¢Û°ê¤ýªº¤u§@", -150, + "·í¤F¶Âµóªº¤j©j", "·í¤F¶Âµóªº¦Ñ¤j", -500, + "Åܦ¨°ª¯Å±@°ü", "Åܦ¨°ª¯Å±¡¤Ò", -350, + "Åܦ¨¶B´Û®v¶B´Û§O¤H", "Åܦ¨ª÷¥úÄÒÄF§O¤H¿ú", -350, + "¥H¬yÅaªº¤u§@¥Í¬¡", "¥H¤û¦ªº¤u§@¥Í¬¡", -350, + NULL, NULL, 0 +}; + + +/* ®a¨ÆÃþ */ +struct endingset endmodefamily[] = +{ + "¤k©Ê¾·~", "¨k¥Í¾·~", 0, + "¥¿¦b·s®Qצæ", "¥¿¦b·s¦×¦æ", 50, + "¥¿¦b®a¸Ì¶¢®Ì", "¥¿¦b®a¸Ì¶¢®Ì", 10, + NULL, NULL, 0 +}; + + +/*-------------------------------------------------------*/ +/* µ²§½¨ç¦¡ */ +/*-------------------------------------------------------*/ + + +/* ¤u§@³õ©Ò§PÂ_ */ +static int +pip_max_worktime() /* workind: ¦bþ¸Ì¤u§@³Ì¦h¦¸ */ +{ + int workind, times; /* ´X¦¸ */ + + times = 20; /* Y¨S¦³¶W¹L 20 ¦¸ªº¤u§@³õ©Ò¡A«h¶Ç¦^ workind = 0 */ + workind = 0; + + if (d.workA > times) + { + times = d.workA; + workind = 1; + } + if (d.workB > times) + { + times = d.workB; + workind = 2; + } + if (d.workC > times) + { + times = d.workC; + workind = 3; + } + if (d.workD > times) + { + times = d.workD; + workind = 4; + } + if (d.workE > times) + { + times = d.workE; + workind = 5; + } + if (d.workF > times) + { + times = d.workF; + workind = 6; + } + if (d.workG > times) + { + times = d.workG; + workind = 7; + } + if (d.workH > times) + { + times = d.workH; + workind = 8; + } + if (d.workI > times) + { + times = d.workI; + workind = 9; + } + if (d.workJ > times) + { + times = d.workJ; + workind = 10; + } + if (d.workK > times) + { + times = d.workK; + workind = 11; + } + if (d.workL > times) + { + times = d.workL; + workind = 12; + } + if (d.workM > times) + { + times = d.workM; + workind = 13; + } + if (d.workN > times) + { + times = d.workN; + workind = 14; + } + if (d.workO > times) + { + times = d.workO; + workind = 16; + } + if (d.workP > times) + { + times = d.workP; + workind = 16; + } + + return workind; +} + + +/* µ²§½§PÂ_ */ +static int /* return 1:·t¶Â 2:ÃÀ³N 3:¸U¯à 4:¾Ô¤h 5:Å]ªk 6:ªÀ¥æ 7:®a¨Æ */ +pip_future_decide(modeallpurpose) + int *modeallpurpose; /* ¦pªG¬O¸U¯àµ²§½¡A¨º»òÁÙn return ¬Oþ¤@Ãþªº¸U¯à */ +{ + *modeallpurpose = 0; /* ¹w³] 0 */ + + /* ·t¶Â */ + if ((d.etchics == 0 && d.sin >= 100) || (d.etchics > 0 && d.etchics < 50 && d.sin >= 250)) + { + return 1; + } + + /* ÃÀ³N */ + if (d.art > d.hexp && d.art > d.mexp && d.art > d.hskill && + d.art > d.mskill && d.art > d.social && d.art > d.family && + d.art > d.homework && d.art > d.wisdom && d.art > d.charm && + d.art > d.belief && d.art > d.manners && d.art > d.speech && + d.art > d.cook && d.art > d.love) + { + return 2; + } + + /* ¾Ô°« */ + if (d.hexp >= d.social && d.hexp >= d.mexp && d.hexp >= d.family) + { + *modeallpurpose = 1; + if (d.hexp > d.social + 50 || d.hexp > d.mexp + 50 || d.hexp > d.family + 50) + return 4; + return 3; + } + + /* Å]ªk */ + if (d.mexp >= d.hexp && d.mexp >= d.social && d.mexp >= d.family) + { + *modeallpurpose = 2; + if (d.mexp > d.hexp || d.mexp > d.social || d.mexp > d.family) + return 5; + return 3; + } + + /* ªÀ¥æ */ + if (d.social >= d.hexp && d.social >= d.mexp && d.social >= d.family) + { + *modeallpurpose = 3; + if (d.social > d.hexp + 50 || d.social > d.mexp + 50 || d.social > d.family + 50) + return 6; + return 3; + } + + /* ®a¨Æ */ + *modeallpurpose = 4; + if (d.family > d.hexp + 50 || d.family > d.mexp + 50 || d.family > d.social + 50) + return 7; + return 3; +} + + +/* µ²±Bªº§PÂ_ */ +static int /* return grade */ +pip_marry_decide() +{ + if (d.lover) /* °Ó¤H */ + { + /* d.lover = 3 4 5 6 7:°Ó¤H */ + return 80; + } + + if (d.royalJ >= d.relation) + { + if (d.royalJ >= 100) + { + d.lover = 1; /* ¤ý¤l */ + return 200; + } + } + else + { + if (d.relation >= 100) + { + d.lover = 2; /* ¤÷¿Ë©Î¥À¿Ë */ + return 0; + } + } + + /* d.lover = 0; */ /* ³æ¨ */ + return 40; +} + + +static int +pip_endwith_black(buf) /* ·t¶Â */ + char *buf; +{ + int m; + + if (d.sin > 500 && d.mexp > 500) /* Å]¤ý */ + m = 1; + else if (d.hexp > 600) /* ¬yª] */ + m = 2; + else if (d.speech > 100 && d.art >= 80) /* SM */ + m = 3; + else if (d.hexp > 320 && d.character > 200 && d.charm < 200) /* ¶Âµó¦Ñ¤j */ + m = 4; + else if (d.character > 200 && d.charm > 200 && d.speech > 70 && d.toman > 70) /* °ª¯Å±@°ü */ + m = 5; + else if (d.wisdom > 450) /* ¶BÄF®v */ + m = 6; + else /* ¬yÅa */ + m = 7; + + if (d.sex == 1) + strcpy(buf, endmodeblack[m].boy); + else + strcpy(buf, endmodeblack[m].girl); + + return endmodeblack[m].grade; +} + + +static int +pip_endwith_social(buf) /* ªÀ¥æ */ + char *buf; +{ + int m; + + if (d.social > 600) + m = (d.charm > 500) ? 1 : 2; + else if (d.social > 450) + m = 1; + else if (d.social > 380) + m = (d.character > d.charm) ? 3 : 4; + else if (d.social > 250) + m = (d.wisdom > d.affect) ? 5 : 6; + else + m = 7; + + d.lover = 10; + + if (d.sex == 1) + strcpy(buf, endmodesocial[m].boy); + else + strcpy(buf, endmodesocial[m].girl); + + return endmodesocial[m].grade; +} + + +static int +pip_endwith_magic(buf) /* Å]ªk */ + char *buf; +{ + int m; + + if (d.mexp > 800) + m = (d.affect > d.wisdom && d.affect > d.belief && d.etchics > 100) ? 1 : 2; + else if (d.mexp > 600) + m = (d.speech >= 350) ? 3 : 4; + else if (d.mexp > 500) + m = 5; + else if (d.mexp > 300) + m = 6; + else + m = (d.character > 200) ? 7 : 8; + + if (d.sex == 1) + strcpy(buf, endmodemagic[m].boy); + else + strcpy(buf, endmodemagic[m].girl); + + return endmodemagic[m].grade; +} + + +static int +pip_endwith_combat(buf) /* ¾Ô°« */ + char *buf; +{ + int m; + + if (d.hexp > 1500) + m = (d.affect > d.wisdom && d.affect > d.belief && d.etchics > 100) ? 1 : 2; + else if (d.hexp > 1000) + m = (d.character > 300 && d.etchics > 50) ? 3 : 4; + else if (d.hexp > 800) + m = (d.vp > 500) ? 5 : 6; + else + m = (d.attack > 200) ? 7 : 8; + + if (d.sex == 1) + strcpy(buf, endmodecombat[m].boy); + else + strcpy(buf, endmodecombat[m].girl); + + return endmodecombat[m].grade; +} + + +static int +pip_endwith_family(buf) /* ®a¨Æ */ + char *buf; +{ + int m; + + if (d.relation < 50) + m = 1; + else + m = 2; + + if (d.sex == 1) + strcpy(buf, endmodefamily[m].boy); + else + strcpy(buf, endmodefamily[m].girl); + + return endmodefamily[m].grade; +} + + +static int +pip_endwith_allpurpose(buf, mode) /* ¸U¯à */ + char *buf; + int mode; +{ + int m; + int point, workind; + + /* ¨Ì¬Oþ¤@Ãþªº¸U¯à¡A¨Ó¨M©w point ÂI¼Æ */ + + if (mode == 1) + point = d.hexp; + else if (mode == 2) + point = d.mexp; + else if (mode == 3) + point = d.social; + else if (mode == 4) + point = d.family; + + if (point > 1000) + { + m = (d.character > 1000) ? 1 : 2; + } + else if (point > 800) + { + m = (d.belief > d.etchics && d.belief > d.wisdom) ? 3 : + (d.etchics > d.belief && d.etchics > d.wisdom) ? 4 : 5; + } + else if (point > 500) + { + m = (d.belief > d.etchics && d.belief > d.wisdom) ? 6 : + (d.etchics > d.belief && d.etchics > d.wisdom) ? 7 : 8; + } + else if (point > 300) + { + workind = pip_max_worktime(); + m = (workind < 2) ? 9 : 8 + workind; + } + else + { + workind = pip_max_worktime(); + m = (workind < 2) ? 25 : 24 + workind; + } + + if (d.sex == 1) + strcpy(buf, endmodeallpurpose[m].boy); + else + strcpy(buf, endmodeallpurpose[m].girl); + + return endmodeallpurpose[m].grade; +} + + +static int +pip_endwith_art(buf) /* ÃÀ³N */ + char *buf; +{ + int m; + + if (d.speech > 100) + m = 1; + else if (d.wisdom > 400) + m = 2; + else if (d.classI > d.classJ) + m = 3; + else + m = 4; + + if (d.sex == 1) + strcpy(buf, endmodeart[m].boy); + else + strcpy(buf, endmodeart[m].girl); + + return endmodeart[m].grade; +} + + +/* ------------------------------------------------------- */ +/* µ²§½¨M©w */ +/* ------------------------------------------------------- */ + +static void +pip_endwith_decide(endbuf1, endbuf2, endmode, endgrade) + char *endbuf1, *endbuf2; + int *endmode, *endgrade; +{ + char *name[8][2] = + { + {"¨kªº", "¤kªº"}, + {"¶ùµ¹¤ý¤l", "°ù¤F¤½¥D"}, + {"¶ùµ¹±z", "°ù¤F±z"}, + {"¶ùµ¹°Ó¤H¢Ï", "°ù¤F¤k°Ó¤H¢Ï"}, + {"¶ùµ¹°Ó¤H¢Ð", "°ù¤F¤k°Ó¤H¢Ð"}, + {"¶ùµ¹°Ó¤H¢Ñ", "°ù¤F¤k°Ó¤H¢Ñ"}, + {"¶ùµ¹°Ó¤H¢Ò", "°ù¤F¤k°Ó¤H¢Ò"}, + {"¶ùµ¹°Ó¤H¢Ó", "°ù¤F¤k°Ó¤H¢Ó"} + }; + + int modeallpurpose; + + /* ³B²z endbuf1 */ + *endmode = pip_future_decide(&modeallpurpose); + switch (*endmode) + { + /* 1:·t¶Â 2:ÃÀ³N 3:¸U¯à 4:¾Ô¤h 5:Å]ªk 6:ªÀ¥æ 7:®a¨Æ */ + case 1: + *endgrade = pip_endwith_black(endbuf1); + break; + case 2: + *endgrade = pip_endwith_art(endbuf1); + break; + case 3: + *endgrade = pip_endwith_allpurpose(endbuf1, modeallpurpose); + break; + case 4: + *endgrade = pip_endwith_combat(endbuf1); + break; + case 5: + *endgrade = pip_endwith_magic(endbuf1); + break; + case 6: + *endgrade = pip_endwith_social(endbuf1); + break; + case 7: + *endgrade = pip_endwith_family(endbuf1); + break; + } + + *endgrade += pip_marry_decide(); + + /* ³B²z endbuf2 */ + if (d.lover >= 1 && d.lover <= 7) + { + if (d.sex == 1) + strcpy(endbuf2, name[d.lover][1]); + else + strcpy(endbuf2, name[d.lover][0]); + } + else if (d.lover == 10) /* ªÀ¥æÃþªºÂ¾·~¦P®É¤]¬O±B«Ãª¬ªp */ + { + strcpy(endbuf2, endbuf1); + } + else /* if (d.lover == 0) */ + { + if (d.sex == 1) + strcpy(endbuf2, "°ù¤F¦P¦æªº¤k«Ä"); + else + strcpy(endbuf2, "¶ùµ¹¤F¦P¦æªº¨k¥Í"); + } +} + + +static void +pip_ending_grade(endgrade) + int endgrade; +{ + clrfromto(1, 23); + move(8, 17); + outs("\033[1;36m·PÁ±zª±§¹¾ãÓ" BBSNAME "¤pÂûªº¹CÀ¸\033[m"); + move(10, 17); + outs("\033[1;37m¸g¹L¨t²Îpºâªºµ²ªG¡G\033[m"); + move(12, 17); + prints("\033[1;36m±zªº¤pÂû\033[37m%s\033[36mÁ`±o¤À¡×\033[1;5;33m%d\033[m", d.name, endgrade); +} + + +int +pip_ending_screen() /* µ²§½µe± */ +{ + char endbuf1[50], endbuf2[50]; + int endgrade = 0; + int endmode = 0; + + pip_endwith_decide(endbuf1, endbuf2, &endmode, &endgrade); + + clear(); + move(1, 0); + outs(" \033[1;33mùÝùùùùùùùßùÝùùùù¢¡ùßùÝùùùùùù¢¡ùÝùùùùùùùßùÝùùùù¢¡ùߢ~ùùùùùù¢¡\033[m\n"); + outs(" \033[1;37mùø ùøùø ùøùøùø ùøùø ùøùø ùøùøùø ùø\033[m\n"); + outs(" \033[1;33mùø ùùùâùø ùøùøùø ¢~¢¡ùøùãùùùßùÝùåùø ùøùøùø ùÝùùùß\033[m\n"); + outs(" \033[1;32mùø ùùùâùø ùø ùøùø ¢¢¢£ùøùÝùùùåùãùßùø ùø ùøùø ¢¢¢£ùø\033[m\n"); + outs(" \033[1;37mùø ùøùø ùø ùøùø ùøùø ùøùø ùø ùøùø ùø\033[m\n"); + outs(" \033[1;35mùãùùùùùùùåùãùù¢¢ùùùåùãùùùùùù¢£ùãùùùùùùùåùãùù¢¢ùùù墢ùùùùùù¢£\033[m\n"); + outs(" \033[1;31m¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\033[41;37m " BBSNAME PIPNAME "µ²§½³ø§i\033[0;1;31m¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\033[m\n"); + outs(" \033[1;36m ³oӮɶ¡¤£ª¾¤£Ä±¦aÁÙ¬O¨ìÁ{¤F..\033[m\n"); + prints(" \033[1;37m \033[33m%s\033[37m ±oÂ÷¶}±zªº·Å·xÃh©ê¡A¦Û¤v¤@°¦Âû¦b¥~±¨D¥Í¦s¤F..\033[m\n", d.name); + outs(" \033[1;36m ¦b±z·ÓÅU±Ð¾É¥Lªº³o¬q®É¥ú¡AÅý¥L±µÄ²¤F«Ü¦h»â°ì¡A°ö¾i¤F«Ü¦hªº¯à¤O..\033[m\n"); + prints(" \033[1;37m ¦]¬°³o¨Ç¡AÅý¤pÂû \033[33m%s\033[37m ¤§«áªº¥Í¬¡¡AÅܱo§ó¦hªö¦h«º¤F..\033[m\n", d.name); + outs(" \033[1;36m ¹ï©ó±zªºÃö¤ß¡A±zªº¥I¥X¡A±z©Ò¦³ªº·R..\033[m\n"); + prints(" \033[1;37m \033[33m%s\033[37m ·|¥Ã»·³£»Ê°O¦b¤ßªº..\033[m", d.name); + vmsg("±µ¤U¨Ó¬Ý¥¼¨Óµo®i"); + + clrfromto(7, 19); + outs(" \033[1;34m¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\033[44;37m " BBSNAME PIPNAME "¥¼¨Óµo®i\033[0;1;34m¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\033[m\n"); + prints(" \033[1;36m ³z¹L¤ô´¹²y¡AÅý§Ṳ́@°_¨Ó¬Ý \033[33m%s\033[36m ªº¥¼¨Óµo®i§a..\033[m\n", d.name); + prints(" \033[1;37m¤pÂû \033[33m%s\033[37m «á¨Ó%s..\033[m\n", d.name, endbuf1); + prints(" \033[1;37m¦Ü©ó¤pÂûªº±B«Ãª¬ªp¡A¥L«á¨Ó%s¡A±B«Ãºâ¬O«Ü¬üº¡..\033[m\n", endbuf2); + outs(" \033[1;36m¶â..³o¬O¤@Ó¤£¿ùªºµ²§½ò..\033[m"); + vmsg("§Ú·Q±z¤@©w«Ü·P°Ê§a"); + + show_ending_pic(0); + vmsg("¬Ý¤@¬Ý¤À¼ÆÅo"); + + pip_ending_grade(endgrade); + vmsg("¤U¤@¶¬O¤pÂû¸ê®Æ¡A»°§Ö copy ¤U¨Ó°µ¬ö©À"); + + pip_query_self(); + vmsg("Åwªï¦A¨Ó¬D¾Ô.."); + + pipdie("\033[1;31m¹CÀ¸µ²§ôÅo..\033[m ", 3); + return 0; +} + + +/* ------------------------------------------------------- */ +/* ÀH¾÷¾÷½t */ +/* ------------------------------------------------------- */ + + +int /* 1:±µ¨ü¨D±B 0:©Úµ´¨D±B */ +pip_marriage_offer() /* ¨D±B */ +{ + char buf[128]; + int money, who; + char *name[5][2] = {{"¤k°Ó¤H¢Ï", "°Ó¤H¢Ï"}, {"¤k°Ó¤H¢Ð", "°Ó¤H¢Ð"}, {"¤k°Ó¤H¢Ñ", "°Ó¤H¢Ñ"}, {"¤k°Ó¤H¢Ò", "°Ó¤H¢Ò"}, {"¤k°Ó¤H¢Ó", "°Ó¤H¢Ó"}}; + + do + { + who = rand() % 5; + } while (d.lover == (who + 3)); /* ¨Ó¨D±BªÌn¤£¬O²{¦bªº¥¼±B©d */ + + money = rand() % 5000 + 4000; + sprintf(buf, " %s±a¨Ó¤Fª÷¿ú %d¡An¦V±zªº¤pÂû¨D±B¡A±zÄ@·N¶Ü(Y/N)¡H[N] ", name[who][d.sex - 1], money); + if (ians(b_lines - 1, 0, buf) == 'y') + { + if (d.wantend != 1 && d.wantend != 4) + { + sprintf(buf, " £«¡ã¤§«e¤w¸g¦³±B¬ù¤F¡A±z½T©wn¸Ñ°£Â±B¬ù¡A§ï¥ß±B¬ù¶Ü(Y/N)¡H[N] "); + if (ians(b_lines - 1, 0, buf) != 'y') + { + d.social += 10; /* ºû«ù±B¬ù¥[ªÀ¥æ */ + vmsg("ÁÙ¬Oºû«ù±B¬ù¦n¤F.."); + return 0; + } + d.social -= rand() % 50 + 100; /* ¤ù±·´±ó±B¬ù°ªÀ¥æ */ + } + d.charm -= rand() % 5 + 20; + d.lover = who + 3; + d.relation -= 20; + if (d.relation < 0) + d.relation = 0; + if (d.wantend < 4) + d.wantend = 2; + else + d.wantend = 5; + vmsg("§Ú·Q¹ï¤è¬O¤@ӫܦnªº¦ñ«Q.."); + d.money += money; + return 1; + } + else + { + d.charm += rand() % 5 + 20; + d.relation += 20; + if (d.wantend == 1 || d.wantend == 4) + vmsg("§ÚÁÙ¦~»´..¤ß±¡ÁÙ¤£©w.."); + else + vmsg("§Ú¦¤w¦³±B¬ù¤F..¹ï¤£°_.."); + return 0; + } +} + + +int /* 1:³Q¥e¤R 0:©ñ±ó©Î¨S¿ú */ +pip_meet_divine() /* ¥e¤R®v¨Ó³X */ +{ + char buf[80]; + int money; + + clrfromto(6, 17); + move(7, 14); + outs("\033[1;33;5m¥n¥n¥n..\033[0;1;37m¬ðµM¶Ç¨Ó°}°}ªººVªùÁn..\033[m"); + move(9, 14); + outs("\033[1;37;46m ì¨Ó¬O¶³¹C¥|®üªº¥e¤R®v¨Ó³X¤F....... \033[m"); + vmsg("¶}ªùÅý¥L¶i¨Ó§a.."); + + money = 300 * (d.bbtime / 60 / 30 + 1); /* ¦~¬ö¶V¤j¡Anªáªº¿ú¶V¦h */ + if (d.money >= money) + { + sprintf(buf, "±znªá %d ¤¸¥e¤R¶Ü(Y/N)¡H[N] ", money); + if (ians(11, 14, buf) == 'y') + { + sprintf(buf, "±zªº¤pÂû%s¥H«á¥i¯àªº¨¤À¬O", d.name); + switch (rand() % 4) /* ÀH«K§Ë¤@ºØ */ + { + /* ¥H¤U©Ò strcat ªº end message ¬O¨k¤k¬Û¦Pªº */ + case 0: + strcat(buf, endmodemagic[2 + rand() % 5].girl); + break; + case 1: + strcat(buf, endmodecombat[2 + rand() % 6].girl); + break; + case 2: + strcat(buf, endmodeart[2 + rand() % 6].girl); + break; + case 3: + strcat(buf, endmodeallpurpose[6 + rand() % 15].girl); + break; + } + d.money -= money; + + move(13, 14); + outs("\033[1;33m¦b§Ú¥e¤Rµ²ªG¬Ý¨Ó..\033[m"); + move(15, 14); + outs(buf); + vmsg("ÁÂÁ´fÅU¡A¦³½t¦A¨£±¤F¡A¤£·Ç¤£¯à©Ç§Ú³á"); + return 1; + } + else + { + vmsg("±z¤£·Q¥e¤R°Ú¡H..¯u¥i±¤..¨º¥u¦³µ¥¤U¦¸§a.."); + } + } + else + { + vmsg("±zªº¿ú¤£°÷³á..¯u¬O¥i±¤..µ¥¤U¦¸§a.."); + } + return 0; +} + + +int +pip_meet_sysop() /* itoc.000416: ¹J¤W¯¸ªø¤j¤j */ +{ + char msg[5][40] = + { + "¬ðµM¤ô±¾_°Ê¤F°_¨Ó..", "¤@°}»®ðÀH·¦Ó¦Ü..", + "³ç..¦³¤H©ç©ç±zªºªÓ»H..", "©P³ò¬ðµM¼ö¾x¤F°_¨Ó..", + "»·»·¦a¬Ý¨ì¤@Ó¤H¼v.." + }; + + clrfromto(6, 17); + move(7, 14); + outs(msg[rand() % 5]); /* ¶Ã¼Æ¨M©w¥X³õ±Ôz */ + vmsg("ì¨Ó¬O»®»®¦³¦Wªº" SYSOPNICK "¥X²{¤F"); + move(9, 14); + + switch (rand() % 4) /* ÀH¾÷¨M©w¯¸ªø¨Æ¥ó (¥H¤£¦P¶Ã¼Æ¼W¥[½ì¨ý) */ + { + case 0: + if (d.weight > 50) + { + d.weight -= 20; + outs("±z¤ÓD¤F¡A§Ú¬°±z¶i¦æ©â¯×¤â³N.."); + } + else + { + d.weight += 20; + outs("±z¤Ó½G¤F¡A§Ú¬°±z¶i¦æ¼WªÎ¤â³N.."); + } + break; + + case 1: + d.money += 1000; + outs("¯¸ªø¤µ¤Ñ¤ß±¡¦n¡A°e±z¤@¨ÇÂûª÷·í¦n®Æªº.."); + break; + + case 2: + d.hp = d.maxhp; + d.mp = d.maxmp; + d.vp = d.maxvp; + d.sp = d.maxsp; + outs(SYSOPNICK "°e±z¤@Áû¤d¦~¯QÂû¤Y¡A±zªºÅé¤O§¹¥þ«ì´_.."); + break; + + case 3: + if (d.money >= 100000) + { + if (ians(9, 14, "±znªá 100000 ¤¸±µ¨ü±K©v³e³»¤jªk¶Ü(Y/N)¡H[N] ") == 'y') + { + /* ÄݩʤW¤É 5% */ + d.money -= 100000; + d.maxhp = d.maxhp * 105 / 100; + d.maxmp = d.maxmp * 105 / 100; + d.maxsp = d.maxsp * 105 / 100; + d.maxsp = d.maxsp * 105 / 100; + d.attack = d.attack * 105 / 100; + d.resist = d.resist * 105 / 100; + d.speed = d.speed * 105 / 100; + d.character = d.character * 105 / 100; + d.love = d.love * 105 / 100; + d.wisdom = d.wisdom * 105 / 100; + d.art = d.art * 105 / 100; + d.brave = d.brave * 105 / 100; + d.homework = d.homework * 105 / 100; + move(11, 14); + outs("¸g¹L¤j¯«ªº³e³»¤§«á¡A±zµo²{©Ò¦³¯à¤O³£¤Wª@¤F.."); + } + else + { + move(11, 14); + outs("±z¤£·Qn°Ú¡H..¯u¥i±¤¡A¨º¥u¦³µ¥¤U¦¸§a.."); + } + } + else + { + outs("¤j¯«Ä±±o©M±z¨S¦³½t¥÷.."); + } + break; + } + + vmsg("¤@Â಴¡A" SYSOPNICK "´N¤£¨£¤F.."); + return 0; +} + + +int +pip_meet_smith() /* itoc.021101: ¹J¤WÅK¦K */ +{ + int randnum; + char *equip; + + clrfromto(6, 17); + move(7, 14); + outs("¤p¥ë¤ln¥hþ¨à°Ú¡H"); + vmsg("¦³¤H¦bI«á¥s¤F±z¤@Án¡Aì¨ÓÅK¦K¥ý¥Í"); + move(9, 14); + outs("±z¥Îªº¬O¤°»òÄê¸Ë³Æ¡AÅý§Ú°e±z¤@¥ó·sªº§a"); + + randnum = rand(); + + switch (randnum % 5) + { + case 0: /* ÀY³¡ªZ¾¹ */ + randnum = randnum % 10; + d.weaponhead += randnum; + pip_weapon_wear(0, randnum); + equip = d.equiphead; + if (!*equip) + strcpy(equip, "ÅK¦Kªº¿Oªw"); + break; + + case 1: /* ¤â³¡ªZ¾¹ */ + randnum = randnum % 10; + d.weaponhand += randnum; + pip_weapon_wear(1, randnum); + equip = d.equiphand; + if (!*equip) + strcpy(equip, "ÅK¦Kªº®±®M"); + break; + + case 2: /* ¬ÞµPªZ¾¹ */ + randnum = randnum % 10; + d.weaponshield += randnum; + pip_weapon_wear(2, randnum); + equip = d.equipshield; + if (!*equip) + strcpy(equip, "ÅK¦Kªº¬Þ¥Ò"); + break; + + case 3: /* ¨ÅéªZ¾¹ */ + randnum = randnum % 10; + d.weaponbody += randnum; + pip_weapon_wear(3, randnum); + equip = d.equipbody; + if (!*equip) + strcpy(equip, "ÅK¦Kªº¹D³T"); + break; + + case 4: /* ¸}³¡ªZ¾¹ */ + randnum = randnum % 10; + d.weaponfoot += randnum; + pip_weapon_wear(4, randnum); + equip = d.equipfoot; + if (!*equip) + strcpy(equip, "ÅK¦KªºÅ@×H"); + break; + } + + while (!vget(b_lines, 0, "½Ð¬°¸Ë³Æ¨úÓ·s¦W¦r¡G", equip, 11, GCARRY)) + ; + + vmsg("ÅK¦K©ç©ç±zªºªÓ»H¡A²H²HÂ÷¶}"); + return 0; +} + + +int +pip_meet_angel() /* itoc.010814: ¹J¨ì¤Ñ¨Ï */ +{ + clear(); + show_system_pic(0); + move(17, 10); + prints("\033[1;36m¿Ë·Rªº\033[1;33m%s ¡ã\033[m", d.name); + move(18, 10); + outs("\033[1;37m¬Ý¨ì±z³o¼Ë§V¤Oªº°ö¾i¦Û¤vªº¯à¤O Åý§Ú¤ß¤¤¤Q¤Àªº°ª¿³³á..\033[m"); + move(19, 10); + outs("\033[1;36m¤p¤Ñ¨Ï§Ú¨M©wµ¹±z¼ú½à¹ªÀy¹ªÀy °½°½¦aÀ°§U±z¤@¤U..^_^\033[m"); + move(20, 10); + + switch (rand() % 8) + { + case 1: + outs("\033[1;33m§Ú±NÀ°±zªº¦U¶µ¯à¤O¥þ³¡´£¤É¦Ê¤À¤§¤³á..\033[m"); + d.maxhp = d.maxhp * 105 / 100; + d.hp = d.maxhp; + d.maxmp = d.maxmp * 105 / 100; + d.mp = d.maxmp; + d.maxvp = d.maxvp * 105 / 100; + d.vp = d.maxvp; + d.maxsp = d.maxsp * 105 / 100; + d.sp = d.maxsp; + d.attack = d.attack * 105 / 100; + d.resist = d.resist * 105 / 100; + d.speed = d.speed * 105 / 100; + d.character = d.character * 105 / 100; + d.love = d.love * 105 / 100; + d.wisdom = d.wisdom * 105 / 100; + d.art = d.art * 105 / 100; + d.brave = d.brave * 105 / 100; + d.homework = d.homework * 105 / 100; + break; + + case 2: + case 3: + outs("\033[1;33m§Ú±NÀ°±zªº¾Ô°«¯à¤O¥þ³¡´£¤É¦Ê¤À¤§¤Q³á..\033[m"); + d.attack = d.attack * 110 / 100; + d.resist = d.resist * 110 / 100; + d.speed = d.speed * 110 / 100; + d.brave = d.brave * 110 / 100; + break; + + case 4: + case 5: + outs("\033[1;33m§Ú±NÀ°±zªº¥Í©R¡Bªk¤O¡B²¾°Ê¡B¤º¤O¥þ³¡´£¤É¦Ê¤À¤§¤K³á..\033[m"); + d.maxhp = d.maxhp * 108 / 100; + d.hp = d.maxhp; + d.maxmp = d.maxmp * 108 / 100; + d.mp = d.maxmp; + d.maxvp = d.maxvp * 108 / 100; + d.vp = d.maxvp; + d.maxsp = d.maxsp * 108 / 100; + d.sp = d.maxsp; + break; + + case 6: + case 7: + outs("\033[1;33m§Ú±NÀ°±zªº·P¨ü¯à¤O¥þ³¡´£¤É¦Ê¤À¤§¤G¤Q³á..\033[m"); + d.character = d.character * 120 / 100; + d.love = d.love * 120 / 100; + d.wisdom = d.wisdom * 120 / 100; + d.art = d.art * 120 / 100; + d.homework = d.homework * 120 / 100; + break; + } + + vmsg("½ÐÄ~Äò¥[ªo³á.."); + return 0; +} +#endif /* HAVE_GAME */ diff --git a/pip/pip_fight.c b/pip/pip_fight.c new file mode 100644 index 0000000..b19d311 --- /dev/null +++ b/pip/pip_fight.c @@ -0,0 +1,1888 @@ +/* ----------------------------------------------------- */ +/* pip_fight.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/* ----------------------------------------------------- */ +/* target : ¾Ô°«¿ï³æ */ +/* create : / / */ +/* update : 01/08/14 */ +/* author : dsyan.bbs@forever.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/* ----------------------------------------------------- */ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#include "pip.h" + + +/*-------------------------------------------------------*/ +/* ¤É¯Å¨ç¦¡ */ +/*-------------------------------------------------------*/ + + +void +pip_levelup(success) + int success; /* 1:¦¨¥\¸Ñ¨M¤É¯Å¥ô°È 0:¥¢±Ñ */ +{ + int level; + + d.quest = 0; + + level = d.level; + d.exp -= level * 100; + d.level = ++level; + + /* itoc.010730: ¬°¤F¼W¥[¾Ô°«ªº¥²n©Ê¡Amaxhp maxmp maxvp maxsp + ³o¨ÇÄÝ©ÊÀ³¸Ó¥u¦b exp ¼W¥[¤É¯Å«á¡A¤~¯à¤j¶q¼W¥[ */ + + /* itoc.010730: ¦b³]©w©Çª«®É½Ðª`·N¡G¦b¨C¦¸³£¦¨¥\¸Ñ¨M¤É¯Å¥ô°È¤§¤U + level ¬O n ¯Åªº¤pÂû¡A¨ä maxhp/maxmp/maxvp/maxsp ´Á±æÈ¬ù¬O 0.75*(n^2) */ + + d.maxhp += rand() % level; + d.maxmp += rand() % level; + d.maxvp += rand() % level; + d.maxsp += rand() % level; + + if (success) /* ¦pªG¦¨¥\¸Ñ¨M¤É¯Å¥ô°È¡A¦å¥[¤ñ¸û¦h */ + { + d.maxhp += level; + d.maxmp += level; + d.maxvp += level; + d.maxsp += level; + vmsg("¥ô°È§¹¦¨¡Aµ¥¯Å´£¤É¤F"); + } + else + { + vmsg("¥ô°È¥¢±Ñ¡Aµ¥¯Å´£¤É¤F"); + } + + /* ¤É¯Å«á¸Éº¡¦å */ + d.hp = d.maxhp; + d.mp = d.maxmp; + d.vp = d.maxvp; + d.sp = d.maxsp; +} + + +/* itoc.010731: Àˬd¸gÅçȬO§_¤w¸g¹F¤É¯Å¼Ð·Ç */ +static void +pip_check_levelup() +{ + /* itoc.010731: ¨C¤É¤@¯Ån (µ¥¯Å * 100) ªº¸gÅçÈ */ + /* µ¥¯Å n ©Çª«ªº exp = n*5 (ì«h¤W¥´20°¦©Çª«¤É¤@¯Å) */ + + /* itoc.020114: ¨îµ¥¯Å¤W¡A¦]¬°©~µM¦³¤Hª±¨ì¼Æ¦Ê¸U¯Å¡A¹CÀ¸ªº³]p³£³Q¯}Ãa¤F */ + + if ((d.level < 100) && (d.exp >= d.level * 100)) + { + /* itoc.021031: ¹F¤É¯Å¼Ð·Ç®É·|¨ú±o¤@Ӥɯťô°È¡A¸Ñ§¹¥ô°È¤~¯à¤É¯Å */ + if (d.quest) + vmsg("¤w¹F¤É¯Å¼Ð·Ç¡A¦ý±z¥²¶·°õ¦æ©Î©ñ±ó¥ô°È¤~¯à¤É¯Å"); + else + pip_quest_new(); + } +} + + +/*-------------------------------------------------------*/ +/* ¾Ô°«¯S°Ï */ +/*-------------------------------------------------------*/ + + +/* itoc.010731.µù¸Ñ: ¥H¤U©Ò¦³Ãþ¦ü value * (110 - rand() % 20) / 100; ªºªF¦è + ´N¬O½d³ò¦b value ªº 90% ~ 110%¡A¨ä´Á±æÈ¬° value */ + +/* itoc.010731: ¥[±j¨¾¿m */ +/* resistmore = 40 ªí¥Ü¹ï¤è§ðÀ»Åܬ° 60%¡Aresistmore = -20 ªí¥Ü¹ï¤è§ðÀ»Åܬ° 120% */ + +static int d_resistmore; /* ¤pÂû¥[±j¨¾¿m */ +static int m_resistmore; /* ©Çª«¥[±j¨¾¿m */ + +static int d_nodone; /* 1:¤pÂûÁÙ¨S°Ê§@ 0:¤pÂû¤w°õ¦æ§¹²¦ */ + + + /*-----------------------------------------------------*/ + /* ©Çª«²£¥Í¾¹ */ + /*-----------------------------------------------------*/ + + +/* m.name[13] attribute hp maxhp attack spirit magic armor dodge money exp pic */ +static playrule m; /* °O¿ý©Çª« */ + + +/* itoc.010731: ¬°¤FÁ×§K©Çª«ªº¸ê®Æ¤ÓÃe¤j¡A¦Y¤Ó¦h¸ê·½¡A¼g¤@¤ä©Çª«²£¥Í¾¹ */ +static void +badman_generate(area) + int area; /* ¶Ç¤J°Ï°ì¨Ó²£¥Í©Çª« */ +{ + int level; /* ©Çª«ªºµ¥¯Å */ + + level = rand(); /* ɥΠlevel·í¶Ã¼Æ¡A¦]¬°¦P¾lªº¼Æ³£¤£¦P¡A©Ò¥H¥u¥Î¤@¦¸ rand() ´N¦n¤F */ + + memset(&m, 0, sizeof(playrule)); /* ªì©l¤Æ */ + + /* [1]ª¢¤§¬}¸] [2]¥_¤è¦Bì [3]¥j¥N¿ò¸ñ [4]¤H¤u®qÀ¬ [5]¦aº»¤§ªù [6]ª÷±e¸s«L */ + /* itoc.010731: ¦U°Ï©Çª«ªº name/attribute/pic ¤£¦P¡A¥H¤Îµ¥¯Å½d³ò¤]¤£¦P */ + + /* itoc.010731: µ¥¯Å¬° n ¯Åªº©Çª«¡A¨ä´Á±æ + maxhp = 0.75*(n^2) (©Mª±®a¤@¼Ë) + attack/spirit/magic/armor/dodge = n*10 + money = n*10 + exp = n*5 (ì«h¤W¥´20°¦©Çª«¤É¤@¯Å) */ + + /* itoc.010731: ª`·N m.name ªø«×¬O 13 (¤»Ó¤¤¤å¦r) */ + /* itoc.010731: ²{¦b¦U¦a°Ï³£¥u¦³¤@±i¹Ï¡A©Ò¥H m.pic ¥u¦n¥Î«ü©wªº */ + + switch (area) + { + case '1': + { + char race[3][7] = {"Às¤H", "ª¢Å]", "¤õµK"}; + char title[4][7] = {"©x§L", "¦u½Ã", "¤h§L", "Åo¹Æ"}; + + sprintf(m.name, "%s%s", race[level % 3], title[level % 4]); + level = d.level - 10 + level % 5; /* Ãø¼y§C */ + if (level <= 5) + level = 5; + m.maxhp = level * level / 2 + 30; + m.attack = level * 8; + m.spirit = level * 8; + m.magic = level * 8; + m.armor = level * 8; + m.dodge = level * 8; + m.money = level * 8; + m.exp = level * 3; /* ©Ò¦³Äݩʳ£¤ñ¸û®t¡A·íµM¸gÅçȤñ´Á±æÈ¤Ö */ + m.attribute = -4; /* ª¢¨t */ + m.pic = 101 + rand() % 3; + } + break; + + case '2': + { + char color[7][5] = {"¶Â", "¥Õ", "¬õ", "ºñ", "ÂÅ", "ª÷", "¤W¥j"}; + char race[4][9] = {"¦BÅ]", "³·©Ç", "¦BÅú", "ªø¤ò¶H"}; + + sprintf(m.name, "%s%s", color[level % 7], race[level % 4]); + level = d.level - 10 + level % 10; /* Ãø«×§C */ + if (level <= 5) + level = 5; + m.maxhp = level * level + 30; /* ¦å¤ñ´Á±æÈ¦h */ + m.attack = level * 10; + m.spirit = level * 10; + m.magic = level * 10; + m.armor = level * 10; + m.dodge = level * 10; + m.money = level * 12; /* ¿ú¤ñ¸û¦h */ + m.exp = level * 5; + m.attribute = -3; /* ¦B¨t */ + m.pic = 201 + rand() % 3; + } + break; + + case '3': + { + char color[5][3] = {"ª÷", "¤ì", "¤ô", "¤õ", "¤g"}; + + sprintf(m.name, "%s¤¸¯À", color[level % 5]); + level = d.level - 10 + level % 20; /* Ãø«×¤¤ */ + if (level <= 5) + level = 5; + m.maxhp = level * level * 3 / 4 + 30; + m.attack = level * 12; /* ª«²z§ðÀ»¤ñ´Á±æÈ±j */ + m.spirit = level * 8; /* ¤º¤O«ü¼Æ¤ñ´Á±æÈ®t */ + m.magic = level * 15; /* Å]ªk¤O¶q¤ñ´Á±æÈ±j«Ü¦h */ + m.armor = level * 8; /* Å@¥Ò±j«×¤ñ´Á±æÈ®t */ + m.dodge = level * 10; + m.money = level * 10; + m.exp = level * 6; /* ¸gÅçȤñ¸û¦h */ + m.attribute = 0; + m.pic = 301 + rand() % 3; + } + break; + + case '4': + { + char title[5][5] = {"^«i", "¯«ªZ", "¦Ê¾Ô", "±`³Ó", "¸U¯à"}; + char race[8][5] = {"ÃM¤h", "ªZ¤h", "§ÔªÌ", "¼C«È", "µs¸é", "¹¬«Q", "§Å®v", "ªª®v"}; + + sprintf(m.name, "%s%s", title[level % 5], race[level % 8]); + level = d.level + level % 10; /* Ãø«×°ª */ + m.maxhp = level * level * 2 + 30; /* ¦å¤ñ´Á±æÈ¦h«Ü¦h */ + m.attack = level * 10; + m.spirit = level * 10; + m.magic = level * 10; + m.armor = level * 12; /* Å@¥Ò±j«×¤ñ´Á±æÈ°ª */ + m.dodge = level * 12; /* °{Á׫ü¼Æ¤ñ´Á±æÈ°ª */ + m.money = level * 10; + m.exp = level * 13 / 2; /* ¸gÅçȤñ¸û¦h */ + m.attribute = 0; + m.pic = 401 + rand() % 3; + } + break; + + case '5': + { + char title[3][7] = {"³g¦Yªº", "¸ô¹Lªº", "·Rª±ªº"}; + char race[5][7] = {"«ÕÆF", "§l¦å°", "¶ÂµL±`", "¥ÕµL±`", "¤p°"}; + + sprintf(m.name, "%s%s", title[level % 3], race[level % 5]); + level = d.level + level % 20; /* Ãø«×°ª */ + m.maxhp = level * level * 3 / 2 + 30; /* ¥þ³¡³£«Ü±j */ + m.attack = level * 15; + m.spirit = level * 15; + m.magic = level * 15; + m.armor = level * 15; + m.dodge = level * 15; + m.money = level * 15; /* ¿ú¦h«Ü¦h */ + m.exp = level * 7; /* ¸gÅçȦh«Ü¦h */ + m.attribute = 0; + m.pic = 501 + rand() % 3; + } + break; + + case '6': + { + /* itoc.010814: ª÷±e¸s«L¶Ç */ + int num; + char name[27][13] = + { + "³¤pÄ_", "¬qÅA", "¨f¶³", "´å©Z¤§", "µê¦Ë", + "¤pÀs¤k", "J´´", "¼}®e´_", "²ö¤j", "©¨¤£¸s", + "°K©Ó§Ó", "¶À»T", "¥Û¯}¤Ñ", "¥ª§NÁI", "ª÷½üªk¤ý", + "¥Oª°¨R", "±iµL§Ò", "¤@¿O", "·¨¹L", "¬x¤C¤½", + "¶ÀÃÄ®v", "¼Ú¶§®p", "³ì®p", "³¢¹t", "¥ô§Ú¦æ", + "©P§B³q", "ªF¤è¤£±Ñ" + }; + + /* m.attr: +1:Å@¨ +2:blitz +3:§lºë +4:®± +5:¼C +6:¤M +7:·t¾¹ (°Ñ¦Ò pip_attack_skill()) + -1:ªvÀø -2:¹p -3:¦B -4:ª¢ -5:¤g -6:· -7:¨s·¥ */ + + int attr[27] = + { + +7, +3, +6, +3, +4, + +5, +6, -7, +6, +3, + +5, -1, -4, -3, -5, + +5, +4, +4, +5, +4, + -1, +2, +4, +4, +3, + +4, -6 + }; + + num = level % 27; /* «ü©w¤@°¦ */ + strcpy(m.name, name[num]); + m.attribute = attr[num]; /* «ü©w¾Õªø§Þ¯à */ + num++; /* Á×§K«Ý·|¦P¾l¼Æ¬° 0 */ + + level = d.level + num + rand() % 20; /* ¶V«á±ªº¤Hª«¡AÃø«×¶V°ª */ + m.maxhp = level * level * 2 + 500 * (rand() % num); + m.attack = level * (15 + (rand() % num)); + m.spirit = level * (15 + (rand() % num)); + m.magic = level * (15 + (rand() % num)); + m.armor = level * (15 + (rand() % num)); + m.dodge = level * (15 + (rand() % num)); + m.money = level * 20; /* ¿ú¦h«Ü¦h */ + m.exp = level * 10; /* ¸gÅçȦh«Ü¦h */ + m.pic = 101 + 100 * (rand() % 5) + rand() % 3; /* 101~501 102~502 103~503 ¤Q¤¿ï¤@ */ + } + break; + } + + m.hp = m.maxhp; /* ¦å¸Éº¡ */ +} + + + /*-----------------------------------------------------*/ + /* ¾Ô°«§Þ¯à°Ñ¼Æ */ + /*-----------------------------------------------------*/ + + +/* skillset: smode sno sbasic name[13] needhp needmp needvp needsp addtired effect pic message[41] */ + +/* itoc.010820: ¯S®íÂø¶µ§Þ¯à */ + +struct skillset skillXYZlist[] = +{ + /* Âø¶µªº®ÄªG¬Oµ{¦¡q©w hp mp vp sp tir eff pic message */ + +0, 0x0000, 7, "¯S®í§Þ¯à", 0, 0, 0, 0, 0, 0, 0, "¯S®í§Þ¯à", + +0, 0x0001, 0x0000, "¥ª¥k¤¬·i", 0, 0, 0, 0, 0, 0, 0, "±z¦bµL²á¤§»Ú¡A¦Û³Ð¤F¥ª¤â©M¥k¤â¥´¬[ªº¤èªk", /* d_dr ¤j¶q¤W¤É */ + +0, 0x0002, 0x0000, "¤O©Þ¤sªe", 0, 0, 0, 0, 0, 0, 0, "±zªºÅé½è¯àÅý±z¶°®ð¬Æ§Ö", /* d_sr ¤j¶q¤W¤É */ + +0, 0x0004, 0x0000, "Å]³êºëÆF", 0, 0, 0, 0, 0, 0, 0, "±z©M¤Ñ¦aºëÆFñ¤U«´¬ù¡A¬I®iÅ]ªk«Â¤O¤j¼W", /* d_mr ¤j¶q¤W¤É */ + +0, 0x0008, 0x0000, "§Ö°¨¥[Ã@", 0, 0, 0, 0, 0, 0, 0, "±z¥i¦b¼Ä§Ú¤§¶¡§Ö³t¬ï±ô¡A¦p¤JµL¤H¤§¦a", /* d_hr ¤j¶q¤W¤É */ + + +0, 0x0010, 0x0000, "´MÀs³Z", 0, 0, 0, 0, 0, 0, 0, "´MÀs³ôÀ¬¤§¾Ç¡A¤µ¤é¥þ³Q±z®©³z¤F", /* ¾Ô°«¸ô¤W¥i¥H¦^´_¦å */ + +0, 0x0020, 0x0000, "±o¨Ó³t", 0, 0, 0, 0, 0, 0, 0, "±z¦b³Á·í³Ò«eÅé·|¤F³t¹ªº§Þ¥©", /* ¾Ô°«¤¤¦YªF¦è¤£¯Ó¦^¦X¼Æ */ + +0, 0x0040, 0x0000, "Àu¥ý§ðÀ»", 0, 0, 0, 0, 0, 0, 0, "±q¦¹¥H«á¡A¾Ô³õ¤W±zÁ`¯à§Ö¤H¤@¨B", /* ¨C¦¸¾Ô°«¥²¥ý§ðÀ» */ +}; + + +/* itoc.010801: ±j«×³]©w: ¥Ñ¯ÓÂI (mp/vp/sp) Á`¦X¨Ó¨M©w®ÄªG (effect)¡Aneedmp->effect¡A¹ïÀ³¦p¤U + 20->10 30->20 50->40 70->100 100->150 250->350 400->600 600->900 900->1500 ½Ð¾A·í¨Ï¥Î¤º´¡ªk + Y¸Ó§Þ¯à¯ÓÂI¥§¡¦b¤GºØ¥H¤WªºÂI¼Æ¡A¨º»ò®ÄªGn¥´Ó§é¦©¡A§Y¯ÂªZ¥\©Î¯ÂÅ]ªk¤ñ¸û±j */ + +/* ¤TºØªZ¥\ skillA ~ skillC */ + +struct skillset skillAlist[] = +{ + /* Å@¨ªº®ÄªG¬O¼W¥[ d_resistmore hp mp vp sp tir eff pic message */ + +1, 0x0000, 4, "Å@¨", 0, 0, 0, 0, 0, 0, 0, "Å@¨¦Cªí", + +1, 0x0001, 0x0000, "ÅK¥¬m", 0, 0, 0, 80, 6, 60, 100, "¥þ¨¤W¤U³ò¶µÛ¤@°}ª÷¥ú", + +1, 0x0002, 0x0001, "ª÷ÄÁ¸n", 0, 0, 0, 150, 7, 80, 100, "¤ÖªLª÷褣Ãa¤§¨", + + +1, 0x0004, 0x0000, "¤æÂà¬P²¾", 0, 0, 90, 5, 6, 70, 100, "¤æÂà¬P²¾¡A¤G»ö¤Æ¥|¶H", + +1, 0x0008, 0x0004, "°®©[¤j®¿²¾", 0, 0, 120, 100, 7, 90, 100, "°®©[¤j®¿²¾¡A¥|¶H¤Æ¤K¨ö", +}; + +struct skillset skillBlist[] = +{ + /* »´¥\¯Ó¤º¤O¡A¦^´_²¾°Ê¤O hp mp vp sp tir eff pic message */ + +2, 0x0000, 3, "»´¥\\", 0, 0, 0, 0, 0, 0, 0, "»´¥\\¦Cªí", + +2, 0x0001, 0x0000, "ªZ·íÂܶ³±è", 0, 0, -30, 15, 2, 0, 110, "ªZ·í§Ì¤l©Ò¾ÕªøªºÂܶ³±è", + +2, 0x0002, 0x0001, "¯«¦æ¦ÊÅÜ", 0, 0,-100, 60, 3, 0, 110, "§ÚÅܧÚÅܧÚÅÜÅÜÅÜ", + +2, 0x0004, 0x0003, "âªi·L¨B", 0, 0,-200, 110, 3, 0, 110, "«ö·Ó¤K¨ö¡A±z¨Ï¥Xâªi·L¨B", +}; + +struct skillset skillClist[] = +{ + /* ¤ßªk¼W¥[¯h³Ò¡A¦^´_¤º¤O hp mp vp sp tir eff pic message */ + +3, 0x0000, 12, "¤ßªk", 0, 0, 0, 0, 0, 0, 0, "¤ßªk¦Cªí", + +3, 0x0001, 0x0000, "¯«·Ó¸g", 0, 0, 0, -20, 10, 50, 120, "¶g¨¹B°_¤F¯«·Ó¯u¸g", + +3, 0x0002, 0x0000, "µµÁø¯«¥\\", 0, 0, 0, -60, 20, 50, 120, "±z¹B°_µµÁø¯«¥\\¡AÁy¦â¬õ¼í", + +3, 0x0004, 0x0000, "¤E³±¯u¸g", 0, 0, 0,-200, 28, 50, 120, "¤ý«¶§ªº±o·Nµ´©Û¡Ð¤E³±¯u¸g", + +3, 0x0008, 0x0000, "¤E¶§¯u¸g", 0, 0, 0,-250, 30, 50, 120, "¤E¶§¯«¥\\¡AÀH¤ß¦Óµo", + + +3, 0x0010, 0x0000, "¤pµL¬Û¥\\", 0, 0, 0, -40, 15, 50, 120, "¤pµL¬Û¥\\¡A³±¶§½Õ©M", + +3, 0x0020, 0x0010, "¬~Åè¸g", 0, 0, 0, -80, 23, 50, 120, "±z¬I®i¥X¶Ç»¡¤¤ªº¬~Åè¸g", + +3, 0x0040, 0x0030, "¤Q¤Kªd°¸", 0, 0, 0,-180, 27, 50, 120, "±z±q¤Q¤K´Lªd°¸¤¤©Ò°Ñ³zªº¤º¥\\", + +3, 0x0080, 0x0070, "©öµ¬¸g", 0, 0, 0,-360, 35, 50, 120, "¤ÖªL¤£¶Ç¤§¾Ç¡Ð¹F¼¯©öµ¬", + + /* ¥Î¨ä¥L´« sp */ + +3, 0x0100, 0x0000, "¯«¤ì¤ý¹©", 15, 0, 0, -30, 1, 50, 120, "±z¨Ï¥X¬r¡A¨Ã¦ø¾÷§l¤F¹ï¤è¤@¨Ç¤º¤O", + +3, 0x0200, 0x0100, "¤Æ¥\\¤jªk", 0, 35, 0, -60, 1, 50, 120, "±z±q¼Ä¤â¨¤W¤Æ¨Ó¤F¤@µ·µ·¤º¤O", + +3, 0x0400, 0x0300, "§l¬P¤jªk", 0, 55, 0,-150, 7, 50, 120, "¦b§l¯Ç¹ï¤è¤º¤O¤§¾l¡A±z±o¦n¦n¥ð®§¤@µf", + +3, 0x0800, 0x0700, "¥_߯«¥\\", 0, 100, 0,-180, 1, 50, 120, "µL·N¤§¤¤¡A±z±q¹ï¤è§l¨ú¤F¤j¶q¤º¤O", +}; + +struct skillset skillDlist[] = +{ + /* ®±ªk¥Dn¯Ó¤º¤O hp mp vp sp tir eff pic message */ + +4, 0x0000, 16, "®±ªk", 0, 0, 0, 0, 0, 0, 0, "®±ªk¦Cªí", + +4, 0x0001, 0x0000, "¤ÖªLªø®±", 0, 0, 0, 50, 10, 40, 130, "¤ÖªLªø®±¡Aªêªê¥Í·", /* ¤ÖªL¨t´xªk¥þ«÷¤º¤O */ + +4, 0x0002, 0x0001, "ùº~®±", 0, 0, 0, 70, 10, 100, 130, "¤ÖªL¤Q¤Kùº~", + +4, 0x0004, 0x0003, "¥ñªê®±", 0, 0, 0, 100, 10, 150, 130, "«n¤s¥ñªê", + +4, 0x0008, 0x0007, "¯ëY´x", 0, 0, 0, 150, 10, 200, 130, "¤ÖªL¯ëY´x", + +4, 0x0010, 0x000F, "¤j¤Oª÷è«ü", 0, 0, 0, 250, 10, 350, 130, "¤ÖªL¤j¤Oª÷è«ü", + +4, 0x0020, 0x001F, "µL¬Û§T«ü", 0, 0, 0, 400, 10, 600, 130, "¤ÖªLµL¬Û§T«ü", + +4, 0x0040, 0x001F, "¤»¯ß¯«¼C", 0, 0, 200, 100, 7, 400, 130, "¤j²z¬q®a¤»¯ß¯«¼C", + +4, 0x0080, 0x0003, "ÅfµM®ø»î´x", 30, 0, 0, 100, 12, 300, 130, "±z¶Ë¤ß¦aÀ»¥X¤@´x", /* ݯӦå! */ + + +4, 0x0100, 0x0000, "ªZ·í´xªk", 0, 0, 30, 30, 6, 40, 130, "±z¥´¥XªZ·í¬£³Ì°ò¥»ªº´xªk", /* ªZ·í¨t´xªkݯӲ¾°Ê¤O */ + +4, 0x0200, 0x0100, "¤Ó·¥®±", 0, 0, 180, 80, 6, 350, 130, "¤Ó·¥®±ªk¡A¥H¬X§Jè", + +4, 0x0400, 0x0100, "¾K®±", 0, 0, 120, 60, 10, 200, 130, "³Ü¤F¤@¤f°s¡A±zÁx¤l¤j¤F°_¨Ó", + + +4, 0x0800, 0x0000, "¤Ñ°¨¬y¬P®±", 0, 30, 30, 30, 8, 120, 130, "°Ú°Ú¡A¤Ñ°¨¬y¡¹®±", /* ©Ç©ÇÃþ´xªkݯӲ¾°Ê¤O¤Îªk¤O */ + +4, 0x1000, 0x0800, "Àt¬£®ð¥\\", 0, 60, 60, 60, 8, 200, 130, "¦Y§Ú¤@°OÀt¬£®ð¥\\", + +4, 0x2000, 0x1800, "¤¸®ð¥É", 0, 120, 120, 120, 8, 450, 130, "¤@¶ô¤¸®ð¸¥X", + +4, 0x4000, 0x3800, "¬É¤ý®±", 0, 240, 240, 240, 8, 950, 130, "¬Ý§Ú¤¿ªº¬É¤ý®±", + + +4, 0x8000, 0x7FFF, "°Às¤Q¤K´x", 0, 0, 0, 900, 15, 1500,130, "¤®Às¦³®¬¡I", /* ²×·¥®±ªk¡A¤º¤On²`«p°Ú */ +}; + +struct skillset skillElist[] = +{ + /* ¼Cªk¥Dn¯Ó²¾°Ê¤O¡A¨ä¦¸¤º¤O hp mp vp sp tir eff pic message */ + +5, 0x0000, 16, "¼Cªk", 0, 0, 0, 0, 0, 0, 0, "¼Cªk¦Cªí", + +5, 0x0001, 0x0000, "ªZ·í¼Cªk", 0, 0, 30, 20, 6, 35, 140, "ªZ·í¼Cªk¡A»D¦W¤Ñ¤U", /* ªZ·í¨t¼Cªk¡Aº«²¾°Ê¤O */ + +5, 0x0002, 0x0001, "µê¼v¼Cªk", 0, 0, 50, 20, 6, 90, 140, "µê¼v¼Cªk¡A¼C¦Ü¼v¦Ü", + +5, 0x0004, 0x0003, "¥ñ¿ª¼Cªk", 0, 0, 70, 20, 6, 120, 140, "¥ñ¿ª³±¶§¡A¼C¦b¤H¦b", + +5, 0x0008, 0x0007, "¥È¶§¼Cªk", 0, 0, 100, 30, 6, 150, 140, "¥È¶§µ´¤õ¡A¼Cµo®ðµo", + +5, 0x0010, 0x000F, "¨Rµê¼Cªk", 0, 0, 150, 30, 6, 220, 140, "¨Rµê¼Cªk¡A¤@®ð¨þ¦¨", + +5, 0x0020, 0x001F, "¨â»ö¼Cªk", 0, 0, 250, 30, 6, 365, 140, "¨â»ö¼Cªk¡A¨â»ö¥|¶H", + +5, 0x0040, 0x003F, "¤Ó·¥¼Cªk", 0, 0, 400, 30, 5, 620, 140, "¤Ó·¥¼Cªk¡A¥H¬X§Jè", + +5, 0x0080, 0x003F, "§P©xµ§", 0, 0, 200, 200, 7, 580, 140, "§P©x¤§µ§¡Aµ´¤£¤â³n", + + +5, 0x0100, 0x0000, "¤Ñ¤k´²ªá", 10, 0, 30, 20, 6, 40, 140, "¤Ñ¤k´²ªá¡A¤Ñªá¶Ã¼Y", + +5, 0x0200, 0x0100, "¨gªá¼Cªk", 40, 0, 100, 40, 7, 250, 140, "¨gªá¼Cªk¡A¼C¤£µêµo", + +5, 0x0400, 0x0300, "¥ÈÅK¼Cªk", 80, 0, 70, 120, 7, 350, 140, "¥È¼C«¼C¡A¤O¹D¤Q¨¬", + +5, 0x0800, 0x0700, "¿W©t¤E¼C", 0, 0, 250, 70, 12, 400, 140, "¿W©t¤E¼C¡A¨D±Ñ¤£¯à", + + +5, 0x1000, 0x0000, "¹@¨¸¼Cªk", 100, 0, 100, 100, 15, 450, 140, "±ý½m¯«¥\\¡A¥²¥ý¦Û®c", /* ¯Ó¤£¤Ö¦å¡A©Ò¥H«Â¤O¥[±j */ + +5, 0x2000, 0x1000, "¸ªªáÄ_¨å", 300, 0, 250, 200, 15, 1200,140, "Y¤£¦Û®c¡A¤]¯à¦¨¥\\", + + +5, 0x4000, 0x3000, "µL¦W¼C³Z", 0, 50, 250, 200, 6, 700, 140, "µL¦W^¶¯¡A¤Q¤ÀÅQ¹D", + +5, 0x8000, 0x7FFF, "¸U¼CÂk©v", 0, 150, 700, 150, 5, 1500,140, "¦¹¨èµL¼C³Ó¦³¼C", /* ²×·¥¼Cªk¡AÄÝ©Ên¸U¯à°Ú */ +}; + +struct skillset skillFlist[] = +{ + /* ¤MªkݯӲ¾°Ê¤O¤Î¤º¤O hp mp vp sp tir eff pic message */ + +6, 0x0000, 5, "¤Mªk", 0, 0, 0, 0, 0, 0, 0, "¤Mªk¦Cªí", + +6, 0x0001, 0x0000, "¦è¥Ê¤Mªk", 0, 0, 40, 40, 6, 100, 150, "±z¥Ñ¤Á¦è¥Ê¤¤©ÒÅé·|ªº¤Mªk", + +6, 0x0002, 0x0000, "¦å¤M¸g", 15, 0, 70, 70, 7, 200, 152, "¦å¤MªgµÛ±zªº¦å¡A¨g®«µL¤ñ", + +6, 0x0004, 0x0000, "J®a¤Mªk", 0, 0, 170, 160, 6, 400, 152, "J®a®a¶Ç¤Mªk", + +6, 0x0008, 0x0000, "°aÁÕµæ¤M", 0, 0, 210, 230, 6, 600, 151, "¤W¥j¶À«Ò®É¥N©Ò¬y¶Ç¤U¨Óªº¤Mªk", + +6, 0x0010, 0x0000, "²r¤û«CÀs±Ù", 0, 50, 400, 150, 7, 800, 153, "¶Â·t®Æ²z¬É³Ì±jµ´§Þ", + +6, 0x0020, 0x0000, "ÅRÆE¨g¤M", 25, 30, 300, 350, 7, 1000,152, "ÅRÆE¨g¤M¡A¤@¬y", +}; + + +struct skillset skillGlist[] = +{ + /* ·t¾¹¥Dn¯Ó²¾°Ê¤O¡A¬rÝ·l¤@ÂI¦å hp mp vp sp tir eff pic message */ + /* ·t¾¹ªº¤½¦¡¤ñ¸û¤£¤@¼Ë¡A¾A¦X§C¯à¤OªÌ¨Ï¥Î¡A¦P¼Ë¯ÓÂI¤U¡Aeffect ¤ñ¥¿±`Ȱª¤@¨Ç */ + +7, 0x0000, 5, "·t¾¹£»¬r", 0, 0, 0, 0, 0, 0, 0, "·t¾¹¦Cªí", + +7, 0x0001, 0x0000, "»X¦½ÃÄ", 5, 0, 20, 0, 5, 25, 160, "¨Ï¤H©ü°g¤@¬q®É¶¡ªº»X¦½ÃÄ", + +7, 0x0002, 0x0001, "Àn¤ù", 10, 0, 40, 0, 5, 55, 160, "¨Ï¤H¤WÅ}ªºÀn¤ù", + +7, 0x0004, 0x0003, "·nÀY¤Y", 40, 0, 160, 0, 5, 350, 160, "§tµÛ¥¤¼Lªº·nÀY¤½¤l", + +7, 0x0008, 0x0007, "¦w«D¥L©R", 80, 0, 320, 0, 5, 650, 160, "«UºÙ¦B¶ôªº¦w¤½¤l", + + +7, 0x0010, 0x0000, "³S¸Ì¼C", 0, 0, 20, 5, 5, 25, 161, "³S¤f¤¤®g¥X±z¨Æ¥ýÂænªº§Ö¼C", + +7, 0x0020, 0x0010, "¸½À¨«¥Û", 0, 0, 40, 10, 5, 55, 161, "±zÂY¥Xº¡¤Ñªº¦º·×¥Û", + +7, 0x0040, 0x0030, "¯º¸ÌÂäM", 0, 0, 160, 40, 5, 350, 161, "·L¯º¤§¶¡¡A±z¬ðµMѶ¥X¤@¤M", + +7, 0x0080, 0x0070, "§t¨F®g¼v", 0, 0, 320, 80, 5, 650, 162, "º©¤Ñ¸¨F¤§¤¤¡A¥u¨£¼Ä¤H¤¤¤F±zªº·t¾¹", +}; + + +/* ¤CÃþªk³N spellA ~ spellG */ +/* Y needhp <0 «hªí¥Ü¸É hp¡A¾lÃþ±À */ +/* itoc.010801: ¦U¨tªº Top ªk³N»¡©ún©ãÃý :p */ + +struct skillset spellAlist[] = +{ + /* ªvÀøªk³N hp mp vp sp tir eff pic message */ + -1, 0x0000, 12, "ªvÀøªk³N", 0, 0, 0, 0, 0, 0, 0, "ªvÀøªk³N", + + /* ¸É¦åÅ]ªk */ + -1, 0x0001, 0x0000, "°ò¥»®ðÀø", -40, 50, 0, 0, 2, 0, 200, "±z·Pı¨ì·x©M¤F¨Ç", + -1, 0x0002, 0x0001, "¾®¯«Âk¤¸", -150, 100, 0, 0, 2, 0, 200, "³¬¥Ø¾i¯«¡A·Pı¦n¤F¤@ÂI", + -1, 0x0004, 0x0002, "¤¸ÆFÂk¤ß", -350, 250, 0, 0, 2, 0, 200, "ºë¯«±M¤ß¤F°_¨Ó", + -1, 0x0008, 0x0004, "¤®ð´Â¤¸", -900, 600, 0, 0, 2, 0, 200, "±z§l¦¬¤F¤j¦ÛµMªº¤O¶q", + + /* ¸É²¾°Ê¤O/¯h³ÒÅ]ªk */ + -1, 0x0010, 0x0000, "²M¤ßÅ]©G", 0, 50, -40, 0, -5, 0, 200, "±zªº¯h³Ò«ì´_¤F", + -1, 0x0020, 0x0010, "¤k¯«§È¯§", 0, 100, -150, 0, -10, 0, 200, "±z·Pı¨ì¦³¤H°½°½¦a«OÅ@µÛ±z", + -1, 0x0040, 0x0030, "¦Ü¸t¥ú¨~", 0, 250, -350, 0, -15, 0, 200, "¤@°}¸t¥ú³ò¶¨®Ç", + -1, 0x0080, 0x0070, "¤Ñ¨Ï¥[«ù", 0, 600, -900, 0, -20, 0, 200, "¤Ñ¨Ïªº¤O¶q¥[«ù¦b±z¨¤W", + + /* ¸É¦å/²¾°Ê¤O/¯h³ÒÅ]ªk¡An¥ý¾Ç·|«e±¤GºØ¹ïÀ³ªºªk³N */ + -1, 0x0100, 0x0011, "¸t¦ö", -40, 120, -40, 0, -5, 0, 200, "±z±o¨ì¨Ó¦Û¤W«Òªº¯¬ºÖ", + -1, 0x0200, 0x0033, "·¶³", -150, 240, -150, 0, -5, 0, 200, "±z±o¨ì¨Ó¦Û·¶³ªº¯¬ºÖ", + -1, 0x0400, 0x0077, "¬PªÅ", -350, 600, -350, 0, -5, 0, 200, "±z±o¨ì¨Ó¦Û¬PªÅªº¯¬ºÖ", + -1, 0x0800, 0x00FF, "¥Õªê", -9999, 2000, -9999, 0, -999, 0, 200, "¥Õªê¤Ñ°¡A¤ß¤§©Ò¦V", /* ¥þº¡ */ +}; + +struct skillset spellBlist[] = +{ + /* ¹p¨tªk³N hp mp vp sp tir eff pic message */ + -2, 0x0000, 7, "¹p¨tªk³N", 0, 0, 0, 0, 0, 0, 0, "¹p¨tªk³N", + -2, 0x0001, 0x0000, "¹p©G", 0, 30, 0, 0, 2, 20, 210, "±z¬I®i¤F¹p©G", + -2, 0x0002, 0x0001, "¤¹p©G", 0, 50, 0, 0, 2, 40, 210, "±z¬I®i¤F¤¹p©G", + -2, 0x0004, 0x0003, "¤Ñ¹pºô", 0, 70, 0, 0, 2, 100, 210, "±z¬I®i¤F¤Ñ¹pºô", + -2, 0x0008, 0x0007, "ºÆ¨g¤§¹p", 0, 100, 0, 0, 3, 150, 210, "±z¬I®i¤FºÆ¨g¤§¹p", + -2, 0x0010, 0x000F, "¹p¯«¤§»R", 0, 150, 0, 0, 3, 200, 210, "±z¬I®i¤F¹p¯«¤§»R", + -2, 0x0020, 0x001F, "Ãz¹p°Á{", 0, 250, 0, 0, 3, 300, 210, "±z¬I®i¤FÃz¹p°Á{", + -2, 0x0040, 0x003F, "¯«Às", 0, 400, 0, 0, 4, 600, 210, "¯«ÀsÂ\\§À¡A¹p¹q¬ÛÀH", +}; + +struct skillset spellClist[] = +{ + /* ¦B¨tªk³N hp mp vp sp tir eff pic message */ + -3, 0x0000, 7, "¦B¨tªk³N", 0, 0, 0, 0, 0, 0, 0, "¦B¨tªk³N", + -3, 0x0001, 0x0000, "¦B©G", 0, 30, 0, 0, 2, 20, 220, "±z¬I®i¤F¦B©G", + -3, 0x0002, 0x0001, "´H¦B©G", 0, 50, 0, 0, 2, 40, 220, "±z¬I®i¤F´H¦B©G", + -3, 0x0004, 0x0003, "¥È¦B©G", 0, 70, 0, 0, 2, 100, 220, "±z¬I®i¤F¥È¦B©G", + -3, 0x0008, 0x0007, "¦B·¼É", 0, 100, 0, 0, 3, 150, 220, "±z¬I®i¤F¦B·¼É", + -3, 0x0010, 0x000F, "·¹p¦B¤Ñ", 0, 150, 0, 0, 3, 200, 220, "±z¬I®i¤F·¹p¦B¤Ñ", + -3, 0x0020, 0x001F, "µ´¹ï¹s«×", 0, 250, 0, 0, 3, 300, 220, "±z¬I®i¤Fµ´¹ï¹s«×", + -3, 0x0040, 0x003F, "¦B¯«", 0, 400, 0, 0, 4, 600, 220, "¦B¯«¤§»R¡A·«BµLªý", +}; + +struct skillset spellDlist[] = +{ + /* ª¢¨tªk³N hp mp vp sp tir eff pic message */ + -4, 0x0000, 7, "ª¢¨tªk³N", 0, 0, 0, 0, 0, 0, 0, "ª¢¨tªk³N", + -4, 0x0001, 0x0000, "ª¢©G", 0, 30, 0, 0, 2, 20, 230, "±z¬I®i¤Fª¢©G", + -4, 0x0002, 0x0001, "ª¢±þ©G", 0, 50, 0, 0, 2, 40, 230, "±z¬I®i¤Fª¢±þ©G", + -4, 0x0004, 0x0003, "·Òº»¯u¤õ", 0, 70, 0, 0, 2, 100, 230, "±z¬I®i¤F·Òº»¯u¤õ", + -4, 0x0008, 0x0007, "¦aº»·~¤õ", 0, 100, 0, 0, 3, 150, 230, "±z¬I®i¤F¦aº»·~¤õ", + -4, 0x0010, 0x000F, "ª¢Å]¦aº»", 0, 150, 0, 0, 3, 200, 230, "±z¬I®i¤Fª¢Å]¦aº»", + -4, 0x0020, 0x001F, "¤õÀs©Û³ê", 0, 250, 0, 0, 3, 300, 230, "±z¬I®i¤F¤õÀs©Û³ê", + -4, 0x0040, 0x003F, "¦¶³¶", 0, 400, 0, 0, 4, 600, 230, "¦¶³¶®i¯Í¡A¨ÓªÌ¥²¦º", +}; + +struct skillset spellElist[] = +{ + /* ¤g¨tªk³N hp mp vp sp tir eff pic message */ + -5, 0x0000, 7, "¤g¨tªk³N", 0, 0, 0, 0, 0, 0, 0, "¤g¨tªk³N", + -5, 0x0001, 0x0000, "¤g©G", 0, 30, 0, 0, 2, 20, 240, "±z¬I®i¤F¤g©G", + -5, 0x0002, 0x0001, "¸©¥³N", 0, 50, 0, 0, 2, 40, 240, "±z¬I®i¤F¸©¥³N", + -5, 0x0004, 0x0003, "¦aµõ¤Ñ±Y", 0, 70, 0, 0, 2, 100, 240, "±z¬I®i¤F¦aµõ¤Ñ±Y", + -5, 0x0008, 0x0007, "®õ¤sÀ£³»", 0, 100, 0, 0, 3, 150, 240, "±z¬I®i¤F®õ¤sÀ£³»", + -5, 0x0010, 0x000F, "¤gÀs¥l³ê", 0, 150, 0, 0, 3, 200, 240, "±z¬I®i¤F¤gÀs¥l³ê", + -5, 0x0020, 0x001F, "¤g¦a¯«©ú", 0, 250, 0, 0, 3, 300, 240, "±z¬I®i¤F¤g¦a¯«©ú", + -5, 0x0040, 0x003F, "¥ÈªZ", 0, 400, 0, 0, 4, 600, 240, "¥ÈªZ¦A²{¡A§ðÀ»µL", +}; + +struct skillset spellFlist[] = +{ + /* ·¨tªk³N hp mp vp sp tir eff pic message */ + -6, 0x0000, 7, "·¨tªk³N", 0, 0, 0, 0, 0, 0, 0, "·¨tªk³N", + -6, 0x0001, 0x0000, "·©G", 0, 30, 0, 0, 2, 20, 250, "±z¬I®i¤F·©G", + -6, 0x0002, 0x0001, "±Û·©G", 0, 50, 0, 0, 2, 40, 250, "±z¬I®i¤F±Û·©G", + -6, 0x0004, 0x0003, "¨g·³N", 0, 70, 0, 0, 2, 100, 250, "±z¬I®i¤F¨g·³N", + -6, 0x0008, 0x0007, "Às±²·", 0, 100, 0, 0, 3, 150, 250, "±z¬I®i¤FÀs±²·", + -6, 0x0010, 0x000F, "·±²´Ý¶³", 0, 150, 0, 0, 3, 200, 250, "±z¬I®i¤F·±²´Ý¶³", + -6, 0x0020, 0x001F, "·ªá³·¤ë", 0, 250, 0, 0, 3, 300, 250, "±z¬I®i¤F·ªá³·¤ë", + -6, 0x0040, 0x003F, "«CÀs", 0, 400, 0, 0, 4, 600, 250, "«CÀs·í¤¤¡A¯«·¯S§ð", +}; + +struct skillset spellGlist[] = +{ + /* ¨s·¥ªk³N hp mp vp sp tir eff pic message */ + -7, 0x0000, 6, "¨s·¥ªk³N", 0, 0, 0, 0, 0, 0, 0, "¨s·¥ªk³N", /* ´c·d¨tªºÅ]ªk :p */ + -7, 0x0001, 0x0000, "®½¦å¤¤¤ß", 0,2000, 9999, 9999, 0, 0, 260, "®½¦å¤@©R¡A±Ï¤H¤@³U", /* ªvÀø */ + -7, 0x0002, 0x0000, "¤â¾÷", 0, 800, 0, 0, 0, 1200,260, "T28 ¥[¤¤µØ¹q«H¡A¶W±j¹qºÏªi", /* ¹p */ + -7, 0x0004, 0x0000, "¤ô§N¦¡·®°", 0, 800, 0, 0, 0, 1200,260, "¶WÀWµ´¹ï¨S°ÝÃD", /* ¦B */ + -7, 0x0008, 0x0000, "®Ö¼u¿Ä¦X", 0, 800, 0, 0, 0, 1200,260, "®Ö¤l¼uÃz¬µ¤F", /* ª¢ */ + -7, 0x0010, 0x0000, "¤g¥Û¬y", 0, 800, 0, 0, 0, 1200,260, "¥xÆW¦W²£¡Ð¤g¥Û¬y", /* ¤g */ + -7, 0x0020, 0x0000, "·s¦Ë·", 0, 800, 0, 0, 0, 1200,260, "³y´N¤F·s¦Ë¦Ì¯»", /* · */ +}; + + + /*-----------------------------------------------------*/ + /* §Þ¯à¾Ç²ß¨ç¦¡ */ + /*-----------------------------------------------------*/ + + +/* itoc.010801: ¾Ç¨ì·s§Þ¯à */ +int /* 0:¨S¦³¾Ç¨ì 1:¾Ç¨ì */ +pip_learn_skill(smode) + int smode; /* skill mode 0:Âø¶µ >0:ªZ¥\ <0:Å]ªk */ +{ + int num; + char buf[80]; + + /* itoc.010801: ¥ý¶Ã¼Æ¨M©w¸Ó¨t§Þ¯àªº¨ä¤¤¤@¶µ¡AµM«áÀˬd¤pÂû¬O§_¤w¸g·|³o§Þ¯à¤F */ + /* ¦pªG¤£·|¦Ó¥B¤w¸g¾Ç¨ì¦¹§Þ¯à¤§°ò¥»§Þ¯à¡A¨º»ò±NÀò±o¦¹¤@·s§Þ¯à */ + + /* itoc.020129.³]p§Þ¥©: Y skill?list[].sno = skill?list[].sbasic¡A¨º»ò¨Ï¥ÎªÌ´NµLªk±q + pip_learn_skill() ¾Ç¨ì¦¹§Þ¯à¡A©Ò¥H¥i¥H¥Ñ¯S®í¨Æ¥ó¨Ó¾Ç²ß */ + + switch (smode) + { + case 0: /* ¯S®í */ + num = rand() % skillXYZlist[0].sbasic + 1; + if ((d.skillXYZ & skillXYZlist[num].sno) || ((d.skillXYZ & skillXYZlist[num].sbasic) != skillXYZlist[num].sbasic)) + return 0; + d.skillXYZ |= skillXYZlist[num].sno; + strcpy(buf, skillXYZlist[num].msg); + break; + + case 1: /* Å@¨ */ + num = rand() % skillAlist[0].sbasic + 1; + if ((d.skillA & skillAlist[num].sno) || ((d.skillA & skillAlist[num].sbasic) != skillAlist[num].sbasic)) + return 0; + d.skillA |= skillAlist[num].sno; + sprintf(buf, "±z»â®©¤FÅ@¨¡Ð%s", skillAlist[num].name); + break; + + case 2: /* »´¥\ */ + num = rand() % skillBlist[0].sbasic + 1; + if ((d.skillB & skillBlist[num].sno) || ((d.skillB & skillBlist[num].sbasic) != skillBlist[num].sbasic)) + return 0; + d.skillB |= skillBlist[num].sno; + sprintf(buf, "±z»â®©¤F»´¥\\¡Ð%s", skillBlist[num].name); + break; + + case 3: /* ¤ßªk */ + num = rand() % skillClist[0].sbasic + 1; + if ((d.skillC & skillClist[num].sno) || ((d.skillC & skillClist[num].sbasic) != skillClist[num].sbasic)) + return 0; + d.skillC |= skillClist[num].sno; + sprintf(buf, "±z»â®©¤F¤ßªk¡Ð%s", skillClist[num].name); + break; + + case 4: /* ®±ªk */ + num = rand() % skillDlist[0].sbasic + 1; + if ((d.skillD & skillDlist[num].sno) || ((d.skillD & skillDlist[num].sbasic) != skillDlist[num].sbasic)) + return 0; + d.skillD |= skillDlist[num].sno; + sprintf(buf, "±z»â®©¤F®±ªk¡Ð%s", skillDlist[num].name); + break; + + case 5: /* ¼Cªk */ + num = rand() % skillElist[0].sbasic + 1; + if ((d.skillE & skillElist[num].sno) || ((d.skillE & skillElist[num].sbasic) != skillElist[num].sbasic)) + return 0; + d.skillE |= skillElist[num].sno; + sprintf(buf, "±z»â®©¤F¼Cªk¡Ð%s", skillElist[num].name); + break; + + case 6: /* ¤Mªk */ + num = rand() % skillFlist[0].sbasic + 1; + if ((d.skillF & skillFlist[num].sno) || ((d.skillF & skillFlist[num].sbasic) != skillFlist[num].sbasic)) + return 0; + d.skillF |= skillFlist[num].sno; + sprintf(buf, "±z»â®©¤F¤Mªk¡Ð%s", skillFlist[num].name); + break; + + case 7: /* ·t¾¹ */ + num = rand() % skillGlist[0].sbasic + 1; + if ((d.skillG & skillGlist[num].sno) || ((d.skillG & skillGlist[num].sbasic) != skillGlist[num].sbasic)) + return 0; + d.skillG |= skillGlist[num].sno; + sprintf(buf, "±z»â®©·t¾¹¡Ð%s", skillGlist[num].name); + break; + + + case -1: /* ªvÀøªk³N */ + num = rand() % spellAlist[0].sbasic + 1; + if ((d.spellA & spellAlist[num].sno) || ((d.spellA & spellAlist[num].sbasic) != spellAlist[num].sbasic)) + return 0; + d.spellA |= spellAlist[num].sno; + sprintf(buf, "±z¾Ç·|¤F¥ÕÅ]ªk¡Ð%s", spellAlist[num].name); + break; + + case -2: /* ¹p¨tªk³N */ + num = rand() % spellBlist[0].sbasic + 1; + if ((d.spellB & spellBlist[num].sno) || ((d.spellB & spellBlist[num].sbasic) != spellBlist[num].sbasic)) + return 0; + d.spellB |= spellBlist[num].sno; + sprintf(buf, "±z¾Ç·|¤F¹pÅ]ªk¡Ð%s", spellBlist[num].name); + break; + + case -3: /* ¦B¨tªk³N */ + num = rand() % spellClist[0].sbasic + 1; + if ((d.spellC & spellClist[num].sno) || ((d.spellC & spellClist[num].sbasic) != spellClist[num].sbasic)) + return 0; + d.spellC |= spellClist[num].sno; + sprintf(buf, "±z¾Ç·|¤F¦BÅ]ªk¡Ð%s", spellClist[num].name); + break; + + + case -4: /* ª¢¨tªk³N */ + num = rand() % spellDlist[0].sbasic + 1; + if ((d.spellD & spellDlist[num].sno) || ((d.spellD & spellDlist[num].sbasic) != spellDlist[num].sbasic)) + return 0; + d.spellD |= spellDlist[num].sno; + sprintf(buf, "±z¾Ç·|¤F¤õÅ]ªk¡Ð%s", spellDlist[num].name); + break; + + case -5: /* ¤g¨tªk³N */ + num = rand() % spellElist[0].sbasic + 1; + if ((d.spellE & spellElist[num].sno) || ((d.spellE & spellElist[num].sbasic) != spellElist[num].sbasic)) + return 0; + d.spellE |= spellElist[num].sno; + sprintf(buf, "±z¾Ç·|¤F¤gÅ]ªk¡Ð%s", spellElist[num].name); + break; + + case -6: /* ·¨tªk³N */ + num = rand() % spellFlist[0].sbasic + 1; + if ((d.spellF & spellFlist[num].sno) || ((d.spellF & spellFlist[num].sbasic) != spellFlist[num].sbasic)) + return 0; + d.spellF |= spellFlist[num].sno; + sprintf(buf, "±z¾Ç·|¤F·Å]ªk¡Ð%s", spellFlist[num].name); + break; + + case -7: /* ¨s·¥ªk³N */ + num = rand() % spellGlist[0].sbasic + 1; + if ((d.spellG & spellGlist[num].sno) || ((d.spellG & spellGlist[num].sbasic) != spellGlist[num].sbasic)) + return 0; + d.spellG |= spellGlist[num].sno; + sprintf(buf, "±zÁA¸Ñ¤F¶ÂÅ]ªk¡Ð%s", spellGlist[num].name); + break; + } + + vmsg(buf); + return 1; +} + + + /*-----------------------------------------------------*/ + /* ¾Ô°«§Þ¯à¿ï³æ */ + /*-----------------------------------------------------*/ + + +/* ¦³¾Ç·|¸Ó§Þ¯à¡A¥B¦å¡Bªk¤O°÷¤~¯à¬I®i */ +#define can_useskill(n) ((skill & p[n].sno) && (p[n].needhp < d.hp) && (p[n].needmp <= d.mp) && (p[n].needvp <= d.vp) && (p[n].needsp <= d.sp)) + + +/* itoc.010729: §Þ¯àµøµ¡ */ +static void +pip_skill_doing_menu(p, dr, sr, mr, hr) /* §Þ¯àµe± */ + struct skillset *p; + int dr; /* ¶Ë®`¤O damage rate */ + int sr; /* ¤º¤O±j«× spirit rate */ + int mr; /* Å]ªk±j«× magic rate */ + int hr; /* ©R¤¤²v hit rate */ +{ + int n, ch; + char ans[5]; + usint skill; + + switch (p[0].smode) + { + case 1: /* Å@¨ */ + skill = d.skillA; + break; + + case 2: /* »´¥\ */ + skill = d.skillB; + break; + + case 3: /* ¤ßªk */ + skill = d.skillC; + break; + + case 4: /* ®±¥\ */ + skill = d.skillD; + break; + + case 5: /* ¼Cªk */ + skill = d.skillE; + break; + + case 6: /* ¤Mªk */ + skill = d.skillF; + break; + + case 7: /* ·t¾¹ */ + skill = d.skillG; + break; + + case -1: /* ªvÀøªk³N */ + skill = d.spellA; + break; + + case -2: /* ¹p¨tªk³N */ + skill = d.spellB; + break; + + case -3: /* ¦B¨tªk³N */ + skill = d.spellC; + break; + + case -4: /* ª¢¨tªk³N */ + skill = d.spellD; + break; + + case -5: /* ¤g¨tªk³N */ + skill = d.spellE; + break; + + case -6: /* ·¨tªk³N */ + skill = d.spellF; + break; + + case -7: /* ¨s·¥ªk³N */ + skill = d.spellG; + break; + + default: /* ¥H§K·N¥~µo¥Í */ + skill = 0; + } + + clrfromto(7, 16); + prints("\033[1;31m¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t\033[37;41m ¥i¥Î[%s]¤@Äýªí \033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\033[m", p[0].name); + + n = 1; + while (n <= p[0].sbasic) /* p[0].sbasic Àx¦s¦³³o¨t¦³´XÓ§Þ¯à */ + { + if (can_useskill(n)) + { + /* ¤À¥|Äæ¡A¨CÄæ¤KÓ¡A¦U¨t§Þ¯à³Ì¦h 32 Ó */ + if (n <= 8) + move(n + 7, 4); + else if (n <= 16) + move(n - 1, 20); + else if (n <= 24) + move(n - 9, 36); + else + move(n - 17, 52); + + prints("%2d.%s", n, p[n].name); + } + + n++; + } + + while (1) + { + if (vget(16, 0, " ±z·Q¨Ï¥Î¨º¤@©Û©O¡H[Q]©ñ±ó¡G", ans, 3, DOECHO)) + { + if (ans[0] == 'q') + { + show_badman_pic(m.pic); + return; + } + else + { + ch = atoi(ans); + if (ch > 0 && ch < n && can_useskill(ch)) + { + break; + } + } + } + } + + d.hp -= p[ch].needhp; + d.mp -= p[ch].needmp; + d.vp -= p[ch].needvp; + d.sp -= p[ch].needsp; + d.tired += p[ch].addtired; + + /* itoc.010801: ¥u»ÝnÀˬd¬O§_Ãz¤W¡A¤£¥²Àˬd¬O§_ < 0¡A¦]¬°«e±Àˬd¹L¤F */ + if (d.hp > d.maxhp) + d.hp = d.maxhp; + if (d.mp > d.maxmp) + d.mp = d.maxmp; + if (d.vp > d.maxvp) + d.vp = d.maxvp; + if (d.sp > d.maxsp) + d.sp = d.maxsp; + if (d.tired < 0) + d.tired = 0; + + /* itoc.010801: ¤ñ¸û */ + /* ¦b©Çª«¨S¦³¨¾¿m¤U¡A´¶³q§ðÀ»ªº´Á±æ¶Ë®`¬° d_dr */ + /* ¦b©Çª«¨S¦³¨¾¿m¤U¡A¥þ¤O¤@À»ªº´Á±æ¶Ë®`¬° 120% * d_dr */ + /* ¦b©Çª«¨S¦³¨¾¿m¤U¡A§Þ¯à§ðÀ»ªº´Á±æ¶Ë®`¬° p[ch].effect + d_dr (©Î d_mr d_sr d_hr)*/ + + switch (p[ch].smode) + { + /* itoc.010729: random ÅܤƶV¤jªº¡A´N®e©ö miss */ + + case 1: /* Å@¨: ¥Î¤F¥H«á¥[±j¨¾¿m */ + /* ¥[±j¨¾¿m¬O d_resistmore + 40%¡A©Ò¥H p[ch].effect À³¦Ü¤Ö > 40 */ + d_resistmore = p[ch].effect * (125 - rand() % 50) / 100; /* ì®ÄªGªº 75% ~ 125% */ + if (d_resistmore >= 100) + d_resistmore = 99; /* Y d_resistmore > 100¡A¤Ï¦ÓÅÜ¥[¦å¤F! */ + break; + + case 2: /* »´¥\ */ + /* vp¦b«e±¤w¸g¥[¹L */ + break; + + case 3: /* ¤ßªk */ + /* sp¦b«e±¤w¸g¥[¹L */ + break; + + case 4: /* ®±ªk */ + m.hp -= p[ch].effect * (120 - rand() % 40) / 100 + (dr + sr) / 2; + break; + + case 5: /* ¼Cªk */ + m.hp -= p[ch].effect * (140 - rand() % 80) / 100 + (dr + hr) / 2; + break; + + case 6: /* ¤Mªk */ + m.hp -= p[ch].effect * (160 - rand() % 120) / 100 + (sr + hr) / 2; + break; + + case 7: /* ·t¾¹ */ + /* ·t¾¹»P¯à¤O¤jPµLÃö¡A¾A¦X§C¯à¤OªÌ¨Ï¥Î */ + if (hr > d.level * 5) + m.hp -= p[ch].effect * (120 - rand() % 40) / 100; /* 100% effect */ + else if (hr > 0) + m.hp -= p[ch].effect * (80 - rand() % 40) / 100; /* 60% effect */ + else + m.hp -= p[ch].effect * (50 - rand() % 40) / 100; /* 30% effect */ + break; + + + case -1: /* ªvÀøªk³N */ + /* hp¦b«e±¤w¸g¥[¹L */ + break; + + case -2: /* ¹p¨tªk³N */ + m.hp -= p[ch].effect * (140 - rand() % 80) / 100 + mr; + break; + + case -3: /* ¦B¨tªk³N */ + m.hp -= p[ch].effect * (120 - rand() % 40) / 100 + mr; + break; + + case -4: /* ª¢¨tªk³N */ + m.hp -= p[ch].effect * (200 - rand() % 200) / 100 + mr; /* ì®ÄªGªº 1% ~ 200%¡AÅܤƶW¤j! */ + break; + + case -5: /* ¤g¨tªk³N */ + m.hp -= p[ch].effect * (110 - rand() % 20) / 100 + mr; + break; + + case -6: /* ·¨tªk³N */ + m.hp -= p[ch].effect * (130 - rand() % 60) / 100 + mr; + break; + + case -7: /* ¨s·¥ªk³N */ + /* itoc.010801: ©M¤@¯ëÅ]ªk¤£¦Pªº¬O¡A¨s·¥ªk³N¤£³æ¬Ý mr ¤]¬Ý dr sr hr */ + m.hp -= p[ch].effect * (140 - rand() % 80) / 100 + (mr * 2 + dr + sr + hr) / 5; + break; + } + + show_fight_pic(p[ch].pic); + vmsg(p[ch].msg); + d_nodone = 0; /* ¦æ°Êµ²§ô */ +} + + +/* itoc.010729: ¶i¤J¨Ï¥Î§Þ¯à¿ï³æ */ +static void +pip_skill_menu(dr, sr, mr, hr) /* ¾Ô°«¤¤§Þ¯àªºÀ³¥Î */ + int dr; /* ¶Ë®`¤O damage rate */ + int sr; /* ¤º¤O±j«× spirit rate */ + int mr; /* Å]ªk±j«× magic rate */ + int hr; /* ©R¤¤²v hit rate */ +{ + while (d_nodone) + { + out_cmd(COLOR1 " ªZ¥\\¿ï³æ " COLOR2 " [1]Å@¨ [2]»´¥\\ [3]¤ßªk [4]®±ªk [5]¼Cªk [6]¤Mªk [7]·t¾¹ [Q]©ñ±ó \033[m", + COLOR1 " ªk³N¿ï³æ " COLOR2 " [A]ªvÀø [B]¹p¨t [C]¦B¨t [D]ª¢¨t [E]¤g¨t [F]·¨t [G]¯S®í [Q]©ñ±ó \033[m"); + + switch (vkey()) + { + case 'q': + return; + + case '1': + pip_skill_doing_menu(skillAlist, dr, sr, mr, hr); + break; + + case '2': + pip_skill_doing_menu(skillBlist, dr, sr, mr, hr); + break; + + case '3': + pip_skill_doing_menu(skillClist, dr, sr, mr, hr); + break; + + case '4': + pip_skill_doing_menu(skillDlist, dr, sr, mr, hr); + break; + + case '5': + pip_skill_doing_menu(skillElist, dr, sr, mr, hr); + break; + + case '6': + pip_skill_doing_menu(skillFlist, dr, sr, mr, hr); + break; + + case '7': + pip_skill_doing_menu(skillGlist, dr, sr, mr, hr); + break; + + case 'a': + pip_skill_doing_menu(spellAlist, dr, sr, mr, hr); + break; + + case 'b': + pip_skill_doing_menu(spellBlist, dr, sr, mr, hr); + break; + + case 'c': + pip_skill_doing_menu(spellClist, dr, sr, mr, hr); + break; + + case 'd': + pip_skill_doing_menu(spellDlist, dr, sr, mr, hr); + break; + + case 'e': + pip_skill_doing_menu(spellElist, dr, sr, mr, hr); + break; + + case 'f': + pip_skill_doing_menu(spellFlist, dr, sr, mr, hr); + break; + + case 'g': + pip_skill_doing_menu(spellGlist, dr, sr, mr, hr); + break; + } + } +} + + + /*-----------------------------------------------------*/ + /* ¾Ô°«©Çª«§Þ¯à§ðÀ» */ + /*-----------------------------------------------------*/ + + +/* itoc.010801: ¥Ñ©ó©Çª«§Þ¯à§ðÀ»¡A¤£»Ýn¿ï³æ¡A©Ò¥Hn©M¤pÂû§Þ¯à§ðÀ»¤À¶}¼g */ + +static void +pip_attack_skill(dr, sr, mr, hr) /* ©Çª«§Þ¯à§ðÀ» */ + int dr; /* ¶Ë®`¤O damage rate */ + int sr; /* ¤º¤O±j«× spirit rate */ + int mr; /* Å]ªk±j«× magic rate */ + int hr; /* ©R¤¤²v hit rate */ +{ + int num, mankey; + char buf[80]; + + num = rand(); /* itoc.010801: ¦]¬°¦P¾lªº¼Æ¤£¦P¡A©Ò¥H¥Î¦P¤@ӶüƨӬٸ귽 */ + + /* itoc.010801: ©Çª«ªº§Þ¯à¤£±Ä¥Î¦© mp/vp/sp ³oºØ¨î«×¡A¦Ó¬O¥Ñ¾÷²v¨Ó¬I®i */ + + if (m.attribute && (num % 2)) + { + mankey = m.attribute; /* 50% ©Çª«¨Ï¥Î¦Û¤v©Ò¾Õªøªº§Þ¯à */ + } + else + { + mankey = rand() % 14 - 7; /* ¦pªG¨S¦³«ü©w¾Õªø§Þ¯à¡A¨º»ò´N¶Ã¼Æ²£¥Í¤@¨t§Þ¯à */ + if (!mankey) + mankey = 7; + } + + /* itoc.010801: ¤ñ¸û */ + /* ¦b¤pÂû¨S¦³¨¾¿m¤U¡A©Çª«´¶³q§ðÀ»ªº´Á±æ¶Ë®`¬° m_dr */ + /* ¦b¤pÂû¨S¦³¨¾¿m¤U¡A©Çª«¥þ¤O¤@À»ªº´Á±æ¶Ë®`¬° 120% * m_dr */ + /* ¦b¤pÂû¨S¦³¨¾¿m¤U¡A©Çª«§Þ¯à§ðÀ»ªº´Á±æ¶Ë®`¬° 150% * m_mr (©Î m_dr¡Bm_sr) */ + + /* itoc.010814: ©Çª«ªº§Þ¯à¤jP¤W©M¤pÂû¤@¼Ë¡A¥u¬O©Çª«¨S¦³¸É vp/sp¡A©Ò¥H»´¥\/¤ßªkn´«¦¨§Oªº */ + + switch (mankey) + { + case 1: /* Å@¨ */ + /* ¥[±j¨¾¿m¬O m_resistmore + 40%¡A©Ò¥H»´¥\ effect À³¦Ü¤Ö > 40¡A¥Bn < 100 */ + m_resistmore = 40 + num % 60; + vmsg("¹ï¤è¥[±j¨¾¿m¡A¥þ¨°Ê¤F°_¨Ó"); + break; + + case 2: /* »´¥\ ¡Ð °{¹qŧÀ» */ + if (hr * (100 - num % 30) / 10 > d.level) + { + /* °{¹q©_ŧªº¯S¦â´N¬O©M©Çª«¥»¨¦Û¤vªº¯à¤O¨Ã¨S¦³Ãö«Y(¦pªG©_ŧ¦¨¥\ªº¸Ü) */ + d.hp -= d.maxhp / 3; + vmsg("¢Ð¢ô¢ñ¢ü£C¡I¹ï¤è¦V±z°{¹qŧÀ»"); + } + else + { + m.hp -= m.maxhp / 5; + if (m.hp <= 0) + m.hp = 1; + vmsg("¹ï¤è¥ø¹Ïµo°Ê°{¹q©_ŧ¡A¦ý¨S¯à¦¨¥\\¡A¤Ï¦Ó³y¦¨¥L¦Û¤vªº·l¶Ë"); + } + break; + + case 3: /* ¤ßªk ¡Ð §lºë */ + /* itoc.010801: ©Çª«¦å¶V¦h¡A§l±o¶V¦h */ + m.hp += m.maxhp / 8; + d.hp -= m.maxhp / 8; + d.mp -= m.maxhp / 10; + d.vp -= m.maxhp / 12; + d.sp -= m.maxhp / 14; + if (m.hp > m.maxhp) + m.hp = m.maxhp; + if (d.mp < 0) + d.mp = 0; + if (d.vp < 0) + d.vp = 0; + if (d.sp < 0) + d.sp = 0; + sprintf(buf, "%s¬½¬½¦a«r¤F±z¤@¤f¡AÃø¹D³o´N¬O¶Ç»¡¤¤ªº§lºë³N¡H", m.name); + vmsg(buf); + break; + + case 4: /* ®±ªk */ + vmsg("¹j¤s¥´¤û¡A¹ï¤è¥´±o±z§¾ºu§¿¬y"); + d.hp -= (dr + sr) * (125 + num % 50) / 200; + break; + + case 5: /* ¼Cªk */ + if (num % 3 == 0) + { + /* itoc.010801: °µ¤@¨Ç©Ç©Çªº®ÄªG */ + char name[3][9] = {"¤@Â_³gÜÒ", "¤GÂ_·R±ý", "¤TÂ_·Ð´o"}; + + for (num = 0; num < 3; num++) + { + sprintf(buf, "¤Ñ¹P¯«¼C %s", name[num]); /* itoc: §f¬}»«£»¤Ñ¹P¯«¼C */ + vmsg(buf); + } + } + else + { + vmsg("º¡¤Ñªá«B¡A±z¤¤¤F¹ï¤è¤@¼C"); + } + d.hp -= (dr + hr) * (125 + num % 50) / 200; + break; + + case 6: /* ¤Mªk */ + vmsg("±z¤¤¤F¹ï¤âªº¤Ñ´Ý¤Mªk¡I"); + d.hp -= (sr + hr) * (125 + num % 50) / 200; + break; + + case 7: /* ·t¾¹ */ + vmsg("²¨©¿¤§¤¤¡A±z¤¤¤F¹ï¤âªº·t¾¹¡I"); + d.hp -= hr * (85 + num % 30) / 100; /* ¤@¯ë§Þ¯à§ðÀ»¬O 150% m_hr¡A¦ý·t¾¹¤ñ¸û®t¡A¥u¦³ 100% */ + break; + + case -1: /* ªvÀøªk³N */ + m.hp += m.maxhp * (40 + rand() % 30) / 100; /* ¦^´_ 40%~70% ªº¦å */ + if (m.hp > m.maxhp) + { + m.hp = m.maxhp; + vmsg("¤@°}¸t¥ú·ÓÄ£¹ï¤è¡A¥Lªºª¬ªp§¹¥þ«ì´_¤F"); + } + else + { + vmsg("¹ï¤è¨Ï¥ÎÅ]ªkªvÀø¤F¦Û¤v"); + } + break; + + case -2: /* ¹p¨tªk³N */ + case -3: /* ¦B¨tªk³N */ + case -4: /* ª¢¨tªk³N */ + case -5: /* ¤g¨tªk³N */ + case -6: /* ·¨tªk³N */ + /* itoc.010814: ©Ò¦³ªº§ðÀ»ªk³N¦X¨Ö¦b¤@°_³B²z */ + { + /* itoc.010814: ¨C¨tªk³N¦U 2 °¦¥H°t¦X mankey ¨Ó¿ï¥l³êÃ~ */ + char name[10][9] = {"¹q®ð½Þ", "¹p¥úÃ~", "´H¦B°", "á¤ô©Ç", "¼ö¤õÅ]", "¤õµK²y", "«ã¤g¦ä", "¥ÛÀY©Ç", "¼É·§¯", "°g»î°"}; + + num = mr * (125 + num % 50) / 100; /* ɥΠnum ·í¶Ë®`ÂI¼Æ */ + d.hp -= num; + sprintf(buf, "¹ï¤è©Û´«¤F%s¡A±z¨ü¶Ë¤F %d ÂI", name[-2 * (mankey + 2) + (num % 2)], num); + vmsg(buf); + } + break; + + case -7: /* ¨s·¥ªk³N */ + /* ¸Éº¡¦å¤S§ðÀ»! */ + m.hp = m.maxhp; + d.hp -= (dr + sr + mr + hr) * (75 + num % 50) / 800; + sprintf(buf, "%s¨Ï¥Î¤F¤ÑÅ]¸ÑÅé¡A±z§¹¥þ¤£¬O¹ï¤â", m.name); + vmsg(buf); + break; + + default: + /* itoc.010814: ¤£¸Ó¦³¤£¦A¤W¦C½d³ò¤¤ªº³á :p */ + sprintf(buf, "½Ð§i¶D¯¸ªø¡A¡i%s¡jªºÄݩʡi%d¡j³]©w¿ù»~", m.name, m.attribute); + vmsg(buf); + break; + } +} + + + /*-----------------------------------------------------*/ + /* ¾Ô°«ª«²z§ðÀ» */ + /*-----------------------------------------------------*/ + + +/* itoc.010731: ©Çª«©M¤pÂûªºª«²z§ðÀ»¡A¥i¥H¼g¦¨¦P¤@¤ä¨ç¦¡ */ + +static void +pip_attack_normal(who, dr, hr) /* itoc.010731: ´¶³q§ðÀ» */ + int who; /* §Ú¬O½Ö 1: ¤pÂû¤U§ðÀ»«ü¥O 0: ©Çª«¤U§ðÀ»«ü¥O */ + int dr; /* ¶Ë®`¤O damage rate */ + int hr; /* ©R¤¤²v hit rate */ +{ + int injure; + char buf[80]; + + injure = hr * (150 - rand() % 100) / 100; /* ¨M©w¬O§_©R¤¤ */ + + if (who) /* ¤pÂû§ðÀ» */ + { + d_resistmore = 0; + d_nodone = 0; + d.tired += 1 + rand() % 2; + + if (hr > d.level * 10) + { + /* ¦b¹ï¤è¨S¦³¨¾¿m¤U¡A´¶³q§ðÀ»ªº´Á±æ¶Ë®`¬° dr */ + injure = dr * (110 - rand() % 20) * (100 - m_resistmore) / 10000; + + if (injure > 0) + { + m.hp -= injure; + d.hexp += rand() % 2 + 2; + d.hskill += rand() % 2 + 1; + sprintf(buf, "´¶³q§ðÀ»¡A%s¥Í©R¤O´î§C %d", m.name, injure); + } + else + { + sprintf(buf, "±zªº§ðÀ»Â²ª½¬O´À%s§ìÄo", m.name); + } + } + else + { + strcpy(buf, "³ºµM¨S¥´¤¤"); + } + } + else /* ©Çª«§ðÀ» */ + { + m_resistmore = 0; + + if (injure > d.level * 10) + { + injure = dr * (110 - rand() % 20) * (100 - d_resistmore) / 10000; + + if (injure > 0) + { + d.hp -= injure; + sprintf(buf, "%s´¶³q§ðÀ»¡A±z¥Í©R¤O´î§C %d", m.name, injure); + } + else + { + strcpy(buf, "±z§¹¥þ¬Ý¤£°_¹ï¤èªº§ðÀ»"); + } + } + else + { + strcpy(buf, "±z°{¸ú¹L¹ï¤èªº§ðÀ»"); + } + } + + vmsg(buf); +} + + +static void +pip_attack_aggressive(who, dr, hr) /* itoc.010731: ¥þ¤O¤@À» */ + int who; /* §Ú¬O½Ö 1: ¤pÂû¤U§ðÀ»«ü¥O 0: ©Çª«¤U§ðÀ»«ü¥O */ + int dr; /* ¶Ë®`¤O damage rate */ + int hr; /* ©R¤¤²v hit rate */ +{ + int injure; + char buf[80]; + + injure = hr * (200 - rand() % 200) / 100; /* ¨M©w¬O§_©R¤¤¡A¥þ¤O¤@À»ªº¶Ã¼Æ¼vÅT¤ñ¸û¤j */ + + if (who) /* ¤pÂû§ðÀ» */ + { + d_resistmore = 0; + d_nodone = 0; + d.hp -= 5; /* ¥þ¤O¤@À»n¦©¦å¥B¤ñ¸û®e©ö²Ö */ + d.tired += 1 + rand() % 3; + + if (hr > d.level * 10) + { + /* ¦b¹ï¤è¨S¦³¨¾¿m¤U¡A¥þ¤O§ðÀ»ªº´Á±æ¶Ë®`¬° 120% * dr */ + injure = dr * (130 - rand() % 20) * (100 - m_resistmore) / 10000; + + if (injure > 0) + { + m.hp -= injure; + d.hexp += rand() % 3 + 2; + d.hskill += rand() % 3 + 1; + sprintf(buf, "±z¥þ¤O¤@À»¡A%s¥Í©R¤O´î§C %d", m.name, injure); + } + else + { + sprintf(buf, "±zªº§ðÀ»Â²ª½¬O´À%s§ìÄo", m.name); + } + } + else + { + strcpy(buf, "³ºµM¨S¥´¤¤"); + } + } + else /* ©Çª«§ðÀ» */ + { + m_resistmore = 0; + + if (injure > d.level * 10) + { + injure = dr * (130 - rand() % 20) * (100 - d_resistmore) / 10000; + + if (injure > 0) + { + d.hp -= injure; + sprintf(buf, "%s¥þ¤O¤@À»¡A±z¥Í©R¤O´î§C %d", m.name, injure); + } + else + { + strcpy(buf, "±z§¹¥þ¬Ý¤£°_¹ï¤èªº§ðÀ»"); + } + } + else + { + strcpy(buf, "±z°{¸ú¹L¹ï¤èªº§ðÀ»"); + } + } + + vmsg(buf); +} + + + +/*-------------------------------------------------------*/ +/* ¹ï¾Ô¥D¨ç¦¡ */ +/*-------------------------------------------------------*/ + + +static void +pip_vs_showing() +{ + int color; + char inbuf1[20], inbuf2[20]; + + clear(); + move(0, 0); + + prints("\033[1;41m " BBSNAME PIPNAME " ¡ã\033[32m%s\033[37m%-13s \033[m\n", + d.sex == 1 ? "¡ñ" : (d.sex == 2 ? "¡ð" : "¡H"), d.name); + + /* itoc.010801: ¿Ã¹õ¤W¤è¨q¥X¤pÂûªº¸ê®Æ */ + + if (d.tired >= 80) + color = 31; + else if (d.tired >= 60 && d.tired < 80) + color = 33; + else + color = 37; + + sprintf(inbuf1, "%d%s/%d%s", d.hp > 1000 ? d.hp / 1000 : d.hp, + d.hp > 1000 ? "K" : "", d.maxhp > 1000 ? d.maxhp / 1000 : d.maxhp, + d.maxhp > 1000 ? "K" : ""); + sprintf(inbuf2, "%d%s/%d%s", d.mp > 1000 ? d.mp / 1000 : d.mp, + d.mp > 1000 ? "K" : "", d.maxmp > 1000 ? d.maxmp / 1000 : d.maxmp, + d.maxmp > 1000 ? "K" : ""); + + outs("\033[1;31m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m\n"); + prints("\033[1;31m¢x\033[33m¥Í ©R:\033[37m%-12s\033[33mªk ¤O:\033[37m%-12s\033[33m¯h ³Ò:\033[%dm%-12d\033[33mª÷ ¿ú:\033[37m%-12d\033[31m¢x\033[m\n", inbuf1, inbuf2, color, d.tired, d.money); + prints("\033[1;31m¢x\033[33m§ð À»:\033[37m%-12d\033[33m¨¾ ¿m:\033[37m%-12d\033[33m³t «×:\033[37m%-12d\033[33m¸g Åç:\033[37m%-12d\033[31m¢x\033[m\n", d.attack, d.resist, d.speed, d.exp); + prints("\033[1;31m¢x\033[33m¹ ª«:\033[37m%-12d\033[33m¤j¸É¤Y:\033[37m%-12d\033[33m¹s ¹:\033[37m%-12d\033[33mÆF ªÛ:\033[37m%-12d\033[31m¢x\033[m\n", d.food, d.burger, d.cookie, d.medicine); + outs("\033[1;31m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m"); + + /* itoc.010801: ¿Ã¹õ¤¤¶¡ 7~16 ¦C ¨q¥X©Çª«ªº¹ÏÀÉ */ + show_badman_pic(m.pic); + + /* itoc.010801: ¿Ã¹õ¤U¤è¨q¥X©Çª«ªº¸ê®Æ */ + + sprintf(inbuf1, "%d%s/%d%s", m.hp > 1000 ? m.hp / 1000 : m.hp, + m.hp > 1000 ? "K" : "", m.maxhp > 1000 ? m.maxhp / 1000 : m.maxhp, + m.maxhp > 1000 ? "K" : ""); + + move(18, 0); + outs("\033[1;34m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m\n"); + prints("\033[1;34m¢x\033[32m©m ¦W:\033[37m%-12s\033[32m¥Í ©R:\033[37m%-12s\033[32m¨¾ Å@:\033[37m%-12d\033[32m°{ Á×:\033[37m%-12d\033[34m¢x\033[m\n", m.name, inbuf1, m.armor, m.dodge); + prints("\033[1;34m¢x\033[32m§ð À»:\033[37m%-12d\033[32m¤º ¤O:\033[37m%-12d\033[32mÅ] ªk:\033[37m%-12d\033[32mª÷ ¿ú:\033[37m%-12d\033[34m¢x\033[m\n", m.attack, m.spirit, m.magic, m.money); + outs("\033[1;34m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m\n"); + + out_cmd("", COLOR1 " ¾Ô°«©R¥O " COLOR2 " [1]´¶³q [2]¥þ¤O [3]§Þ¯à [4]¨¾¿m [5]¸É¥R [6]·Ò§¯ [A]¦Û°Ê [Q]°k©R \033[m"); +} + + +static void +pip_vs_ending(winorlost, area) + int winorlost; /* 2:K¦º©Çª« 1:©Çª«°k¶] -1:¤pÂû°k¶] -2:¤pÂû³QK¦º */ + char area; /* !=0: K©Çª« 0:¦¬Ã¬©u¤ñÁÉ */ +{ + int mode; + + mode = winorlost; + if (!area) + mode += 8; + + clrfromto(7, 16); + move(8, 0); + + /* itoc.010731: ¦¬Ã¬©u¤ñÁÉY¬O¿é¤F¡A«h«ì´_¤@¨Ç¦å¡FY¬OŤF¡A«ì´_¥þ³¡¦å */ + /* itoc.010731: ¾Ô³Ó¥[¸gÅçÈ/¿ú¡A¾Ô±Ñ¦©¿ú/ÄݩʡF¦ý¦¬Ã¬©u¾Ô±Ñ¤£¦©¿ú/ÄÝ©Ê */ + + switch (mode) + { + case 10: /* ¦¬Ã¬©u KO */ + d.tired = 0; + d.hp = d.maxhp; + d.hexp += rand() % 3 + 2; + d.mexp += rand() % 3 + 2; + d.exp += m.exp; + outs(" \033[1;31m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m\n"); + prints(" \033[1;31m¢x \033[37mªZ³N¤j·|ªº¤pÂû\033[33m%-13s \033[31m¢x\033[m\n", d.name); + prints(" \033[1;31m¢x \033[37m¥´±Ñ¤F±j«lªº¹ï¤â\033[32m%-13s \033[31m¢x\033[m\n", m.name); + outs(" \033[1;31m¢x \033[37m«i´±©M¸gÅç³£¤W¤É¤F¤£¤Ö \033[31m¢x\033[m\n"); + outs(" \033[1;31m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m"); + vmsg("±z¥´±Ñ¤F¤@Ó±jµwªº³Ã¥ë"); + break; + + case 9: /* ¦¬Ã¬©u win */ + d.tired = 0; + d.hp = d.maxhp; + d.hexp += rand() % 2 + 1; + d.mexp += rand() % 2 + 1; + d.exp += m.exp * (50 + rand() % 20) / 100; /* ±o 60% ªº¸gÅçÈ */ + outs(" \033[1;31m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m\n"); + prints(" \033[1;31m¢x \033[37mªZ³N¤j·|ªº¤pÂû\033[33m%-13s \033[31m¢x\033[m\n", d.name); + prints(" \033[1;31m¢x \033[37m¥´±Ñ¤F±j«lªº¹ï¤â\033[32m%-13s \033[31m¢x\033[m\n", m.name); + outs(" \033[1;31m¢x \033[37m«i´±©M¸gÅç³£¤W¤É¤F¤@¨Ç \033[31m¢x\033[m\n"); + outs(" \033[1;31m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m"); + vmsg("¤£t²³±æ¦a¡A±z¸Ñ¨M¤F³oÓÃøÄñªº¼Ä¤â"); + break; + + case 7: /* ¦¬Ã¬©u lose */ + d.tired = 50; + d.hp = d.maxhp / 3; + d.hexp -= rand() % 2 + 1; + d.mexp -= rand() % 2 + 1; + if (d.hexp < 0) + d.hexp = 0; + if (d.mexp < 0) + d.mexp = 0; + outs(" \033[1;31m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m\n"); + prints(" \033[1;31m¢x \033[37mªZ³N¤j·|ªº¤pÂû\033[33m%-13s \033[31m¢x\033[m\n", d.name); + prints(" \033[1;31m¢x \033[37m³Q\033[32m%-13s\033[37m¹ï¤â¥´±o¸¨ªá¬y¤ô \033[31m¢x\033[m\n", m.name); + outs(" \033[1;31m¢x \033[37m¨M©w¦^®a¦n¦n¦AÁë½m \033[31m¢x\033[m\n"); + outs(" \033[1;31m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m"); + vmsg("¸¨¶]ªº±z¤ß¤¤¬Û·í¤£¬O¨ý¹D"); + break; + + case 6: /* ¦¬Ã¬©u KO-ed */ + d.tired = 50; + d.hp = d.maxhp / 3; + d.hexp -= rand() % 3 + 2; + d.mexp -= rand() % 3 + 2; + if (d.hexp < 0) + d.hexp = 0; + if (d.mexp < 0) + d.mexp = 0; + outs(" \033[1;31m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m\n"); + prints(" \033[1;31m¢x \033[37mªZ³N¤j·|ªº¤pÂû\033[33m%-13s \033[31m¢x\033[m\n", d.name); + prints(" \033[1;31m¢x \033[37m§¹¥þ¤£¬O\033[32m%-13s\033[37mªº¹ï¤â \033[31m¢x\033[m\n", m.name); + outs(" \033[1;31m¢x \033[37mµo»}©ú¦~ÁÙn±²¤g«¨Ó \033[31m¢x\033[m\n"); + outs(" \033[1;31m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m"); + vmsg("±z½ö¦b¦a¤W©a©a¤@®§"); + break; + + case 2: /* KO ©Çª« */ + d.money += m.money; + d.exp += m.exp; + d.exp += m.exp; + d.brave += rand() % 4 + 3; + outs(" \033[1;31m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m\n"); + prints(" \033[1;31m¢x \033[37m^«iªº¤pÂû\033[33m%-13s \033[31m¢x\033[m\n", d.name); + prints(" \033[1;31m¢x \033[37m¥´±Ñ¤F¨¸´cªº©Çª«\033[32m%-13s \033[31m¢x\033[m\n", m.name); + outs(" \033[1;31m¢x \033[37m«i´±©M¸gÅç³£¤W¤É¤F¤£¤Ö \033[31m¢x\033[m\n"); + outs(" \033[1;31m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m"); + vmsg("¹ï¤è¦º±¼¤F°Ú¡A©Ò¥H±zÀò³Ó¤F³á"); + break; + + case 1: /* ©Çª«°k¶] */ + d.money += m.money * (30 + rand() % 20) / 100; /* ±o 40% ªº¿ú */ + d.exp += m.exp * (50 + rand() % 20) / 100; /* ±o 60% ªº¸gÅçÈ */ + d.brave += rand() % 3 + 2; + outs(" \033[1;31m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m\n"); + prints(" \033[1;31m¢x \033[37m^«iªº¤pÂû\033[33m%-13s \033[31m¢x\033[m\n", d.name); + prints(" \033[1;31m¢x \033[37m¥´±Ñ¤F¨¸´cªº©Çª«\033[32m%-13s \033[31m¢x\033[m\n", m.name); + outs(" \033[1;31m¢x \033[37m«i´±©M¸gÅç³£¤W¤É¤F¤@¨Ç \033[31m¢x\033[m\n"); + outs(" \033[1;31m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m"); + vmsg("¹ï¤è¥ý°{¤F..¦ý±¼¤F¤@¨Ç¿úµ¹±z..."); + break; + + case -1: /* ¤pÂû°k¶] */ + d.money -= d.level * 5 + rand() % 100; + d.brave -= rand() % 3 + 2; + if (d.money < 0) + d.money = 0; + if (d.brave < 0) + d.brave = 0; + outs(" \033[1;31m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m\n"); + prints(" \033[1;31m¢x \033[37m¥i¼¦ªº¤pÂû\033[33m%-13s \033[31m¢x\033[m\n", d.name); + prints(" \033[1;31m¢x \033[37m¦b»P\033[32m%-13s\033[37mªº¾Ô°«¤¤ \033[31m¢x\033[m\n", m.name); + outs(" \033[1;31m¢x \033[37m¤£©¯¦a¥´¿é¤F¡A¦b¦¹¯S§OÃø¹L.......... \033[31m¢x\033[m\n"); + outs(" \033[1;31m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m"); + vmsg("¤pÂû¥´¿é¤F...."); + break; + + case -2: /* ¤pÂû KO-ed */ + outs(" \033[1;31m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m\n"); + prints(" \033[1;31m¢x \033[37m¥i¼¦ªº¤pÂû\033[33m%-13s \033[31m¢x\033[m\n", d.name); + prints(" \033[1;31m¢x \033[37m¦b»P\033[32m%-13s\033[37mªº¾Ô°«¤¤ \033[31m¢x\033[m\n", m.name); + outs(" \033[1;31m¢x \033[37m¤£©¯¦a°}¤`¤F¡A¦b¦¹¯S§OÀq«s.......... \033[31m¢x\033[m\n"); + outs(" \033[1;31m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m"); + vmsg("¤pÂû°}¤`¤F...."); + pipdie("\033[1;31m¾Ô°«¤¤³Q¥´¦º¤F...\033[m ", 1); + break; + } +} + + +/* static */ /* itoc.010731: µ¹¦¬Ã¬©u¹ï¾Ô¥Î */ +int /* 1: ¤pÂû win 0: ¤pÂû lose */ +pip_vs_man(p, area) + struct playrule p; /* ¶Ç¤J©Çª«¸ê®Æ */ + int area; /* !=0: K©Çª«®Éªº°Ï°ì 0: ¦¬Ã¬©u¤ñÁÉ */ +{ + int d_dr; /* ¤pÂû¥´©Çª« ª«²z§ðÀ»«ü¼Æ damage rate */ + int d_sr; /* ¤pÂû¥´©Çª« ªZ¥\§ðÀ»«ü¼Æ spirit rate */ + int d_mr; /* ¤pÂû¥´©Çª« Å]ªk§ðÀ»«ü¼Æ magic rate */ + int d_hr; /* ¤pÂû¥´©Çª« ª«²z/ªZ¥\/Å]ªk§ðÀ»©R¤¤²v hit rate */ + + int m_dr; /* ©Çª«¥´¤pÂû ª«²z§ðÀ»«ü¼Æ damage rate */ + int m_sr; /* ©Çª«¥´¤pÂû ªZ¥\§ðÀ»«ü¼Æ spirit rate */ + int m_mr; /* ©Çª«¥´¤pÂû Å]ªk§ðÀ»«ü¼Æ magic rate */ + int m_hr; /* ©Çª«¥´¤pÂû ª«²z/ªZ¥\/Å]ªk§ðÀ»©R¤¤²v hit rate */ + + int randnum; /* random number */ + int pipkey; /* ¤pÂû¤Uªº«ü¥O */ + int mankey; /* ©Çª«¤Uªº«ü¥O */ + char buf[80]; + + /* ²£¥Í©Çª«¸ê®Æ */ + if (area) /* K©Çª« */ + { + badman_generate(area); + } + else /* ¦¬Ã¬©u¤ñÁÉ */ + { + strcpy(m.name, p.name); + m.attribute = p.attribute; + m.hp = p.hp; + m.maxhp = p.maxhp; + m.attack = p.attack; + m.spirit = p.spirit; + m.magic = p.magic; + m.armor = p.armor; + m.dodge = p.dodge; + m.money = p.money; + m.pic = p.pic; + } + + /* itoc.010731: ¤@¶}©l´Nºâ¦n¤@¨Ç°Ñ¼Æ¡AµM«áµ¥¤@¤Uª½±µ¶Ç¤J¨ç¼Æ¨D¶Ë®`È */ + d_dr = d.attack + (d.hskill + d.hexp) / 10 - m.armor; + d_sr = (d.attack + d.brave) / 2 + (d.hskill + d.hexp) / 10 - m.armor; + d_mr = d.mskill + (d.immune + d.mexp) / 10 - m.armor; + d_hr = d.speed + (d.hskill + d.hexp) / 10 - m.dodge; + m_dr = m.attack - d.resist; + m_sr = m.spirit - (d.speed + d.resist) / 2; + m_mr = m.magic - d.immune; + m_hr = m.attack - d.speed; + + /* itoc.020718: nÀˬd³o¨Ç°Ñ¼Æ¡A½T©w¬O¥¿ªº */ + if (d_dr <= 0) + d_dr = 1; + if (d_sr <= 0) + d_sr = 1; + if (d_mr <= 0) + d_mr = 1; + if (d_hr <= 0) + d_hr = 1; + if (m_dr <= 0) + m_dr = 1; + if (m_sr <= 0) + m_sr = 1; + if (m_mr <= 0) + m_mr = 1; + if (m_hr <= 0) + m_hr = 1; + + /* itoc.010820: ¦pªG¦³¯S®í§Þ¯à¡A¥i¥H¦A¥[¦¨ */ + if (d.skillXYZ & 0x0001) /* ¥ª¥k¤¬·i */ + d_dr += d.level << 3; + else if (d.skillXYZ & 0x0002) /* ¤O©Þ¤sªe */ + d_sr += d.level << 3; + else if (d.skillXYZ & 0x0004) /* Å]³êºëÆF */ + d_mr += d.level << 3; + else if (d.skillXYZ & 0x0008) /* §Ö°¨¥[Ã@ */ + d_hr += d.level << 3; + + /* itoc.010730: ¨M©w½Ö¥ý§ðÀ» */ + if (d.skillXYZ & 0x0040) /* Àu¥ý§ðÀ» */ + { + d_nodone = 1; + } + else + { + d_nodone = rand() % 10 > 2; /* 30% ¥Ñ©Çª«¥ý§ðÀ» */ + if (!d_nodone) + { + sprintf(buf, "±z³Q%s°½Å§¤F", m.name); + vmsg(buf); + } + } + + d_resistmore = 0; + m_resistmore = 0; + pipkey = 0; + + for (;;) /* µL½a°j°é */ + { + /* ¨q¥X¾Ô°«¥Dµe± */ + pip_vs_showing(); + + while (d_nodone) + { + if (pipkey != 'a') /* itoc.010820: ¦Û°Ê§ðÀ» */ + pipkey = vkey(); + + switch (pipkey) /* ¤pÂû¤U«ü¥O */ + { + case 'a': /* ¦Û°Ê§ðÀ»¥u°õ¦æ´¶³q§ðÀ» */ + case '1': /* ´¶³q§ðÀ» */ + show_fight_pic(1); + pip_attack_normal(1, d_dr, d_hr); + break; + + case '2': /* ¥þ¤O¤@À» */ + if (d.hp > 5) + { + show_fight_pic(2); + pip_attack_aggressive(1, d_dr, d_hr); + } + else + { + vmsg("±zÅé¤O³o»ò®t¤FÁÙ·Q¥þ¤O¤@À»"); + } + break; + + case '3': /* §Þ¯à: ªZ¥\/Å]ªk */ + pip_skill_menu(d_dr, d_sr, d_mr, d_hr); + if (d_nodone) /* ¶i¤J skill_menu ¥X¨ÓYÁÙ¬O d_nodone¡Aªí¥Ü©ñ±ó¨Ï¥Î§Þ¯à¡An«Ã¸«ü¥O */ + out_cmd("", COLOR1 " ¾Ô°«©R¥O " COLOR2 " [1]´¶³q [2]¥þ¤O [3]§Þ¯à [4]¨¾¿m [5]¸É¥R [6]·Ò§¯ [A]¦Û°Ê [Q]°k©R \033[m"); + break; + + case '4': /* ¨¾¿m */ + d_resistmore = 40; /* ©Çª«§ðÀ»´î¤Ö 40% */ + d.tired += rand() % 2 + 1; + d_nodone = 0; + show_fight_pic(3); + vmsg("¤pÂû¥[±j¨¾¿m°Õ...."); + break; + + case '5': /* ¦Y¸É«~ */ + d_nodone = pip_basic_feed(); /* feed §¹¶Ç¦^ 0 ªí¥Ü¦Y§¹¤F¡A¶Ç¦^ 1 ªí¥Ü©ñ±ó¨S¦Y */ + pip_vs_showing(); /* itoc.010801: »Ýn§¹¾ã«Ã¸ */ + + if (d.skillXYZ & 0x0020) /* ±o¨Ó³t */ + d_nodone = 1; + break; + + case '6': /* ·Ò§¯ */ + if (m.hp < m.maxhp * (d.level - rand() % 150) / 100) + { + d.mexp += 8; + m.hp = 0; + vmsg("®·®»¦¨¥\\¡A¦WÁn¼W¥["); + } + else + { + vmsg("®·®»¥¢±Ñ"); + } + d_nodone = 0; + break; + + case 'q': /* °k¶] */ + pip_vs_ending(-1, area); + return 0; + } + } + + /* ¤pÂû§ðÀ»«á¡A»ÝnÀˬd¤pÂû/©Çª«ª¬ºA */ + if (m.hp <= 0) /* ©Çª«¦º±¼¤F */ + { + pip_vs_ending(2, area); + return 1; + } + else if (d.tired >= 100) + { + /* ¤pÂû²Ö¦º¤F¡A¨¾¿m¤O¤j° */ + vmsg("±z¤w¸g¤Ó¯h²Ö¤F¡A¨¾¿m¤O¤j´T°§C"); + d_resistmore = -100; /* ©Çª«§ðÀ»¥[ 100% */ + } + + + /* ¨ì¦¹¤pÂû¤w¤U§¹«ü¥O¡A¸Ó©Çª«¤U«ü¥O */ + + /* ¨M©w©Çª«¤Uªº«ü¥O */ + randnum = rand() % 100; + if (m.attribute) /* ¦³¯S®íªº§Þ¯à */ + { + if (randnum < 40) + mankey = 1; /* 40% ´¶³q§ðÀ» */ + else if (randnum < 50) + mankey = 2; /* 10% ¥þ¤O§ðÀ» */ + else if (randnum < 90) + mankey = 3; /* 40% §Þ¯à§ðÀ» */ + else if (randnum < 98) + mankey = 4; /* 8% ¥[±j¨¾¿m */ + else + mankey = 5; /* 2% °k¤§¤Ô¤Ô */ + } + else + { + if (randnum < 40) + mankey = 1; /* 40% ´¶³q§ðÀ» */ + else if (randnum < 65) + mankey = 2; /* 25% ¥þ¤O§ðÀ» */ + else if (randnum < 90) + mankey = 3; /* 25% §Þ¯à§ðÀ» */ + else if (randnum < 98) + mankey = 4; /* 8% ¥[±j¨¾¿m */ + else + mankey = 5; /* 2% °k¤§¤Ô¤Ô */ + } + + switch (mankey) + { + case 2: /* ©Çª«¥þ¤O§ðÀ» */ + if (m.hp > 5) /* Y©Çª«¦å¤£¨ì¤ÂI¡AÅÜ´¶³q§ðÀ» */ + { + show_fight_pic(52); + pip_attack_aggressive(0, m_dr, m_hr); + break; + } + + case 1: /* ©Çª«´¶³q§ðÀ» */ + show_fight_pic(51); + pip_attack_normal(0, m_dr, m_hr); + break; + + case 3: /* ©Çª«§Þ¯à§ðÀ» */ + pip_attack_skill(m_dr, m_sr, m_mr, m_hr); + break; + + case 4: /* ©Çª«¨¾¿m */ + m_resistmore = 40; /* ¤pÂû§ðÀ»´î¤Ö 40% */ + break; + + case 5: /* ©Çª«°k¶] */ + pip_vs_ending(1, area); + return 1; + } + + /* ©Çª«§ðÀ»«á¡A¥u»ÝnÀˬd¤pÂûª¬ºA */ + + if (d.hp <= 0) /* ¤pÂû¦º±¼¤F */ + { + pip_vs_ending(-2, area); + return 0; + } + + d_nodone = 1; /* ¤S¸Ó¤pÂû¤F */ + + } /* µ²§ô for °j°é¡A¾Ô°«µ²§ô */ +} + + +/*-------------------------------------------------------*/ +/* ¦a¹Ï²£¥Í¾¹ */ +/*-------------------------------------------------------*/ + + +/* itoc.041017: ¬°¤F¦h¼Ë©Ê¡A¼g¤@Ó¦a¹Ï²£¥Í¾¹ */ + +/* ¦b³o¶¡©Ð¶¡¸Ì¦³þ¨Ç¤è¦V¥i¥H«e¶i */ +#define MAP_EAST 0x01 +#define MAP_WEST 0x02 +#define MAP_SOUTH 0x04 +#define MAP_NORTH 0x08 + + +static int /* ¶Ç¦^¥»©Ð¶¡¦³þ¨Ç¤è¦V¥i¥H¨« */ +map_generate() +{ + int direction; + int map[16] = + { + MAP_EAST | MAP_WEST | MAP_SOUTH | MAP_NORTH, + MAP_EAST, MAP_WEST, MAP_SOUTH, MAP_NORTH, + MAP_EAST | MAP_WEST, MAP_EAST | MAP_SOUTH, MAP_EAST | MAP_NORTH, MAP_WEST | MAP_SOUTH, MAP_WEST | MAP_NORTH, MAP_SOUTH | MAP_NORTH, + MAP_EAST | MAP_WEST | MAP_SOUTH, MAP_EAST | MAP_WEST | MAP_NORTH, MAP_EAST | MAP_SOUTH | MAP_NORTH, MAP_WEST | MAP_SOUTH | MAP_NORTH, + MAP_EAST | MAP_WEST | MAP_SOUTH | MAP_NORTH + }; + + /* ¨M©w³o¶¡©Ð¶¡¦³þ¨Ç¥X¤f */ + + direction = map[rand() & 15]; /* ¨M©w³o¶¡©Ð¶¡¦³þ¨Ç¥X¤f */ + move(16, 0); + prints(" ¥X¤f¡G\033[1m%s%s%s%s\033[m", + direction & MAP_EAST ? "\033[31mªF " : "", + direction & MAP_WEST ? "\033[32m¦è " : "", + direction & MAP_SOUTH ? "\033[33m«n " : "", + direction & MAP_NORTH ? "\033[34m¥_" : ""); + + return direction; +} + + +/*-------------------------------------------------------*/ +/* ¾Ô°«¥D¿ï³æ */ +/*-------------------------------------------------------*/ + + +int +pip_fight_menu() +{ + int ch, area, direction; + + show_badman_pic(0); + out_cmd(COLOR1 " ¥Ò°Ï " COLOR2 " [1]ª¢¤§¬}¸] [2]¥_¤è¦Bì [3]¥j¥N¿ò¸ñ [Q]Â÷¶} \033[m", + COLOR1 " ¤A°Ï " COLOR2 " [4]¤H¤u®qÀ¬ [5]¦aº»¤§ªù [6]ª÷±e¸s«L [Q]Â÷¶} \033[m"); + + while (1) + { + area = vkey(); + if (area == 'q') + return 0; + if (area >= '1' && area <= '6') + break; + } + + clrfromto(7, 17); + + while (d.hp > 0) + { + direction = map_generate(); + out_cmd("", COLOR1 " °Ï°ì " COLOR2 " [F]Áý¹ [E/W/S/N]ªF/¦è/«n/¥_ [Q]¦^®a \033[m"); + +re_key: + ch = vkey(); + + if (ch == 'q') + break; + + if (ch == 'f') /* Áý¹ */ + { + pip_basic_feed(); + continue; + } + + + /* ¨ä¥L«öÁä³£¬O¤è¦V */ + + ch = ch == 'e' ? MAP_EAST : ch == 'w' ? MAP_WEST : ch == 's' ? MAP_SOUTH : ch == 'n' ? MAP_NORTH : 0; + if (!(ch & direction)) /* ³oÓ¤è¦V¤£¯à«e¶i */ + goto re_key; /* ¤£»Ýn«·s²£¥Í¦a¹Ï */ + + if ((ch == 'e' && !(direction & MAP_EAST)) || (ch == 'e' && !(direction & MAP_EAST)) || + (ch == 'e' && !(direction & MAP_EAST)) || (ch == 'e' && !(direction & MAP_EAST))) + + if (d.vp < 10) /* ¾Ô°«¦a¹Ï¤¤²¾°Ê¦©²¾°Ê¤O¡A¦Ü¤Ö 10 ¤~¯à²¾°Ê */ + { + vmsg("±z¤w²Ö±oµLªk¦A¦æ°Ê"); + continue; /* ¥i¥H¥ÎÁý¹Ä~Äò */ + } + + d.vp -= 2; + + if (rand() % 3) /* ¤T¤À¤§¤Gªº¾÷·|¹J¨ì¼Ä¤H */ + { + pip_vs_man(m, area); /* ¶i¤J¾Ô°« */ + } + else + { + if (d.skillXYZ & 0x0010) /* ´MÀs³Z */ + { + d.hp += (d.maxhp >> 2); + if (d.hp > d.maxhp) + d.hp = d.maxhp; + vmsg("±zªu¸ô¬°¤H§®ºt¤Ñ¾÷"); + } + else + { + vmsg("¨Sµo¥Í¥ô¦ó¨Æ¡I"); + } + } + } + + /* itoc.010730: ¦bÂ÷¶}¾Ô°«¿ï³æ®É¤~¤@¨ÖÀˬd¬O§_¤É¯Å */ + pip_check_levelup(); + + return 0; +} +#endif /* HAVE_GAME */ diff --git a/pip/pip_item.c b/pip/pip_item.c new file mode 100644 index 0000000..0f00d01 --- /dev/null +++ b/pip/pip_item.c @@ -0,0 +1,256 @@ +/* ----------------------------------------------------- */ +/* pip_item.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/* ----------------------------------------------------- */ +/* target : ¤pÂû item */ +/* create : / / */ +/* update : 01/08/14 */ +/* author : dsyan.bbs@forever.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/* ----------------------------------------------------- */ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#include "pip.h" + + +struct itemset pipfoodlist[] = +{ + /* name msgbuy msgfeed price */ + 0, "ª««~¦W", "ÁʶR¶·ª¾", "¨Ï¥Î¶·ª¾", 0, + 1, "¦n¦Yªº¹ª«", "Åé¤O«ì´_ 50", "¨C¦Y¤@¦¸¹ª«·|«ì´_Åé¤O 50 ³á", 50, + 2, "¬ü¨ýªº¹s¹", "Åé¤O«ì´_ 100", "°£¤F«ì´_Åé¤O¡A¤pÂû¤]·|§ó§Ö¼Ö", 120, + 0, NULL, NULL, NULL, 0 +}; + + +struct itemset pipmedicinelist[] = +{ + /* name msgbuy msgfeed price */ + 0, "ª««~¦W", "ÁʶR¶·ª¾", "¨Ï¥Î¶·ª¾", 0, + 1, "¸É¦å¤jÁÙ¤¦", "Åé¤O«ì´_ 1000", "«ì´_¤j¶q¬y¥¢Åé¤Oªº¨}¤è", 1000, + 2, "¬Ã¶QªºÆFªÛ", "ªk¤O«ì´_ 1000", "«ì´_¤j¶q¬y¥¢ªk¤Oªº¨}¤è", 1000, + 3, "¦n¥Î¤j¸É¤Y", "²¾°Ê«ì´_ 1000", "«ì´_¤j¶q¬y¥¢²¾°Êªº¨}¤è", 1000, + 4, "¤d¦~¤H°Ñ¤ý", "¤º¤O«ì´_ 1000", "«ì´_¤j¶q¬y¥¢¤º¤Oªº¨}¤è", 1000, + 5, "¶Â¥ÉÂ_Äò»I", "Åé¤O§¹¥þ«ì´_", "¶Ç»¡¤¤¯à±N©Ò¦³¨ü¶Ë«ì´_ªºÃħ÷", 5000, + 6, "¤Ñ¤s³·½¬", "ª¬ºA§¹¥þ«ì´_", "ªF¥_¤Ñ¤s¤~¦³³·½¬¤l", 10000, + 0, NULL, NULL, NULL, 0 +}; + + +struct itemset pipotherlist[] = +{ + /* name msgbuy msgfeed price */ + 0, "ª««~¦W", "ÁʶR¶·ª¾", "¨Ï¥Î¶·ª¾", 0, + 1, "¦Ê¬ì¥þ®Ñ", "ª¾ÃѪº¨Ó·½", "®Ñ¥»Åý¤pÂû§óÁo©ú§ó¦³®ð½è°Õ", 3000, + 2, "¼Ö°ªª±¨ã²Õ", "§Ö¼Öº¡·N«×", "ª±¨ãÅý¤pÂû§ó§Ö¼Ö°Õ", 300, + 3, "»Õ¼ÓÂø»x", "º¡¨¬ªº§Ö·P", "®Ñ¤¤¦Û¦³ÃC¦p¥É°Õ", 500, + 0, NULL, NULL, NULL, 0 +}; + + +/* ------------------------------------------------------- */ +/* ª««~ÁʶR¨ç¦¡ */ +/* ------------------------------------------------------- */ + + +int +pip_buy_item(mode, p, oldnum) + int mode; + int oldnum[]; + struct itemset *p; +{ + char *shopname[4] = {"©±¦W", "«K§Q°Ó©±", "ªø¬KÃľQ", "©]¸Ì®Ñ§½"}; + char buf[128], genbuf[20]; + int oldmoney; /* ¶i°Ó©±«e즳¿ú */ + int total; /* ÁʶR/³c½æÓ¼Æ */ + int ch, choice; + + oldmoney = d.money; + + /* ¨q¥X²£«~¦Cªí */ + clrfromto(6, 18); + outs("\033[1;31m ¢w\033[41;37m ½s¸¹\033[0;1;31m¢w\033[41;37m °Ó «~\033[0;1;31m¢w¢w\033[41;37m ®Ä ¯à\033[0;1;31m¢w¢w\033[41;37m »ù ®æ\033[0;1;31m¢w\033[37;41m ¾Ö¦³¼Æ¶q\033[0;1;31m¢w\033[m\n\n"); + for (ch = 1; ch <= oldnum[0]; ch++) + { + prints(" \033[1;35m[\033[37m%2d\033[35m] \033[36m%-10s \033[37m%-14s \033[1;33m%-10d \033[1;32m%-9d \033[m\n", + p[ch].num, p[ch].name, p[ch].msgbuy, p[ch].price, oldnum[ch]); + } + + do + { + sprintf(buf, COLOR1 " ±Ä¶R " COLOR2 " (%8s) [B]¶R¤Jª««~ [S]½æ¥Xª««~ [Q]¸õ¥X \033[m", shopname[mode]); + out_cmd("", buf); + + switch (ch = vkey()) + { + case 'b': + sprintf(buf, "·Qn¶R¤JÔ£©O¡H[0]©ñ±ó¶R¤J [1¡ã%d]ª««~°Ó¸¹¡G", oldnum[0]); + choice = ians(b_lines - 2, 0, buf) - '0'; + if (choice >= 1 && choice <= oldnum[0]) + { + sprintf(buf, "±zn¶R¤Jª««~ [%s] ¦h¤ÖÓ©O(1-%d)¡H[Q] ", p[choice].name, d.money / p[choice].price); + vget(b_lines - 2, 0, buf, genbuf, 6, DOECHO); + total = atoi(genbuf); + + if (total <= 0) + { + vmsg("©ñ±ó¶R¤J..."); + } + else if (d.money < total * p[choice].price) + { + vmsg("±zªº¿ú¨S¦³¨º»ò¦h³á.."); + } + else + { + sprintf(buf, "½T©w¶R¤JÁ`»ù¬° %d ªºª««~ [%s] ¼Æ¶q %d Ó¶Ü(Y/N)¡H[N] ", total * p[choice].price, p[choice].name, total); + if (ians(b_lines - 2, 0, buf) == 'y') + { + oldnum[choice] += total; + d.money -= total * p[choice].price; + + /* itoc.010816: §ó·s¾Ö¦³¼Æ¶q */ + move(7 + choice, 0); + prints(" \033[1;35m[\033[37m%2d\033[35m] \033[36m%-10s \033[37m%-14s \033[1;33m%-10d \033[1;32m%-9d \033[m", + p[choice].num, p[choice].name, p[choice].msgbuy, p[choice].price, oldnum[choice]); + + vmsg(p[choice].msguse); + } + else + { + vmsg("©ñ±ó¶R¤J..."); + } + } + } + else + { + sprintf(buf, "©ñ±ó¶R¤J....."); + vmsg(buf); + } + break; + + case 's': + sprintf(buf, "·Qn½æ¥XÔ£©O¡H[0]©ñ±ó½æ¥X [1¡ã%d]ª««~°Ó¸¹: ", oldnum[0]); + choice = ians(b_lines - 2, 0, buf) - '0'; + if (choice >= 1 && choice <= oldnum[0]) + { + sprintf(buf, "±zn½æ¥Xª««~ [%s] ¦h¤ÖÓ©O(1-%d)¡H[Q] ", p[choice].name, oldnum[choice]); + vget(b_lines - 2, 0, buf, genbuf, 6, DOECHO); + total = atoi(genbuf); + + if (total <= 0) + { + vmsg("©ñ±ó½æ¥X..."); + } + else if (total > oldnum[choice]) + { + sprintf(buf, "±zªº [%s] ¨S¦³¨º»ò¦hÓ³á", p[choice].name); + vmsg(buf); + } + else + { + sprintf(buf, "½T©w½æ¥XÁ`»ù¬° %d ªºª««~ [%s] ¼Æ¶q %d Ó¶Ü(Y/N)¡H[N] ", total * p[choice].price * 4 / 5, p[choice].name, total); + if (ians(b_lines - 2, 0, buf) == 'y') + { + oldnum[choice] -= total; + d.money += total * p[choice].price * 8 / 10; + + /* itoc.010816: §ó·s¾Ö¦³¼Æ¶q */ + move(7 + choice, 0); + prints(" \033[1;35m[\033[37m%2d\033[35m] \033[36m%-10s \033[37m%-14s \033[1;33m%-10d \033[1;32m%-9d \033[m", + p[choice].num, p[choice].name, p[choice].msgbuy, p[choice].price, oldnum[choice]); + + sprintf(buf, "¦ÑÁ󮳨«¤F±zªº %d Ó%s", total, p[choice].name); + vmsg(buf); + } + else + { + vmsg("©ñ±ó½æ¥X..."); + } + } + } + else + { + sprintf(buf, "©ñ±ó½æ¥X....."); + vmsg(buf); + } + break; + + case 'q': + case KEY_LEFT: + sprintf(buf, "ª÷¿ú¥æ©ö¦@ %d ¤¸,Â÷¶} %s ", oldmoney - d.money, shopname[mode]); + vmsg(buf); + break; + } + + /* itoc.010816: ®ø±¼ ians() vget() ¯d¤Uªº´ÝÀe */ + move (b_lines - 2, 0); + clrtoeol(); + + } while (ch != 'q' && ch != KEY_LEFT); + + return 0; +} + + +/*-------------------------------------------------------*/ +/* °Ó©±¿ï³æ:¹ª« ¹s¹ ¤j¸É¤Y ª±¨ã ®Ñ¥» */ +/*-------------------------------------------------------*/ + +/*-------------------------------------------------------*/ +/* ¨ç¦¡®w */ +/*-------------------------------------------------------*/ + +int +pip_store_food() +{ + int num[3]; + num[0] = 2; + num[1] = d.food; + num[2] = d.cookie; + pip_buy_item(1, pipfoodlist, num); + d.food = num[1]; + d.cookie = num[2]; + return 0; +} + + +int +pip_store_medicine() +{ + int num[7]; + num[0] = 6; + num[1] = d.pill; + num[2] = d.medicine; + num[3] = d.burger; + num[4] = d.ginseng; + num[5] = d.paste; + num[6] = d.snowgrass; + pip_buy_item(2, pipmedicinelist, num); + d.pill = num[1]; + d.medicine = num[2]; + d.burger = num[3]; + d.ginseng = num[4]; + d.paste = num[5]; + d.snowgrass = num[6]; + return 0; +} + + +int +pip_store_other() +{ + int num[4]; + num[0] = 3; + num[1] = d.book; + num[2] = d.toy; + num[3] = d.playboy; + pip_buy_item(3, pipotherlist, num); + d.book = num[1]; + d.toy = num[2]; + d.playboy = num[3]; + return 0; +} +#endif /* HAVE_GAME */ diff --git a/pip/pip_job.c b/pip/pip_job.c new file mode 100644 index 0000000..f4575e6 --- /dev/null +++ b/pip/pip_job.c @@ -0,0 +1,910 @@ +/*-------------------------------------------------------*/ +/* pip_job.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¥´¤u */ +/* create : / / */ +/* update : 01/08/15 */ +/* author : dsyan.bbs@forever.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#include "pip.h" + + +/*-------------------------------------------------------*/ +/* ¨ç¦¡®w */ +/*-------------------------------------------------------*/ + + +/* itoc.010815: ¼g¤@°¦¤½¥Îªº function */ + +static int /* ¶Ç¦^: -1:©ñ±ó 0~100:¦¨¥\ª¬ªp */ +pip_job_function(classgrade, tired_prob, tired_base, pic) + int classgrade; /* ¨¤ßª¬ªp: 0% ~ 100 % */ + int tired_prob; /* pºâ¯h³Òªº¾÷²v */ + int tired_base; /* pºâ¯h³Òªº©³¼Æ */ + int pic; /* n¨qªº¹Ï */ +{ + int grade; + + /* ¦]¬°ÁÙ¨S update¡Alearn_skill ¥i¯à < 0 */ + if (LEARN_LEVEL < 0) + { + vmsg("±z¤w¸g²Ö¨ìÃz¤F"); + return -1; + } + + grade = classgrade * LEARN_LEVEL; + + /* grade À³¸Ó¥u±q 0~100% */ + if (grade < 0) + grade = 0; + else if (grade > 100) + grade = 100; + + /* ©Ò¦³¤u§@³£·|§ïÅܪºÄÝ©Ê */ + count_tired(tired_prob, tired_base, 1, 100, 1); /* ¼W¥[¯h³Ò»P¦~ÄÖ¦³Ãö */ + d.shit += rand() % 3 + 5; + d.hp -= rand() % 2 + 4; + d.happy -= rand() % 3 + 4; + d.satisfy -= rand() % 3 + 4; + + show_job_pic(pic); + return grade; /* ¦^¶Ç¤u§@µ²ªG: 0:¥¢±Ñ³z¤F ~ 100:§¹¥þ¦¨¥\ */ +} + + +/*-------------------------------------------------------*/ +/* ¥´¤u¿ï³æ:®a¨Æ W¤u ®a±Ð ¦aÅu */ +/*-------------------------------------------------------*/ + + +int +pip_job_workA() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x®a®xºÞ²z¢x+ «Ý¤H±µª« ±½¦a¬~¦ç ²i¶¹ ¿Ë¤lÃö«Y ®a¨Æµû»ù ¢x */ + /* ¢x ¢x- ·P¨ü ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + class = d.hp * 100 / d.maxhp - d.tired; + if ((class = pip_job_function(class, 2, 5, 11)) < 0) + return 0; + + if (class >= 75) + { + class = 4; + d.money += 80 + (d.homework + d.cook) / 50; + vmsg("®a¨Æ«Ü¦¨¥\\³á..¦h¤@ÂI¿úµ¹±z.."); + } + else if (class >= 50) + { + class = 3; + d.money += 60 + (d.homework + d.cook) / 55; + vmsg("®a¨ÆÁÙÆZ¶¶§Qªºò..¶â¶â.."); + } + else if (class >= 25) + { + class = 2; + d.money += 40 + (d.homework + d.cook) / 60; + vmsg("®a¨Æ´¶´¶³q³q°Õ..¥i¥H§ó¦nªº..¥[ªo.."); + } + else + { + class = 1; + d.money += 20 + (d.homework + d.cook) / 65; + vmsg("®a¨Æ«ÜÁV¿|³á..³o¼Ë¤£¦æ°Õ.."); + } + + d.toman += rand() % 2; + d.homework += rand() % 2 + class; + d.cook += rand() % 2 + class; + d.relation += rand() % 2; + d.family += class; + + d.affect -= rand() % 5; + if (d.affect < 0) + d.affect = 0; + + d.workA++; + return 0; +} + + +int +pip_job_workB() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x¨|¥®°| ¢x+ «Ý¤H±µª« ·R¤ß ·P¨ü ¢x */ + /* ¢x ¢x- ¾y¤O ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + class = d.hp * 100 / d.maxhp - d.tired; + if ((class = pip_job_function(class, 3, 7, 21)) < 0) + return 0; + + if (class >= 75) + { + class = 4; + d.money += 150 + (d.toman + d.love) / 50; + vmsg("·í«O©i«Ü¦¨¥\\³á..¤U¦¸¦A¨Ó³á.."); + } + else if (class >= 50) + { + class = 3; + d.money += 120 + (d.toman + d.love) / 55; + vmsg("«O©iÁÙ·íªº¤£¿ùò..¶â¶â.."); + } + else if (class >= 25) + { + class = 2; + d.money += 100 + (d.toman + d.love) / 60; + vmsg("¤pªB¤Í«Ü¥Ö³á..¥[ªo.."); + } + else + { + class = 1; + d.money += 80 + (d.toman + d.love) / 65; + vmsg("«ÜÁV¿|³á..³s¤pªB¤Í³£¸n¤£¦í.."); + } + + d.toman += rand() % 3; + d.love += rand() % 3 + class; + d.affect += class; + + d.charm -= rand() % 5; + if (d.charm < 0) + d.charm = 0; + + /* itoc.010824: ¶Ã¼Æ¾Ç·|·t¾¹ */ + if (rand() % 30 == 0) + pip_learn_skill(7); + + d.workB++; + return 0; +} + + +int +pip_job_workC() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x®ÈÀ] ¢x+ ±½¦a¬~¦ç ²i¶¹ ®a¨Æµû»ù ¢x */ + /* ¢x ¢x- µL ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + class = d.hp * 100 / d.maxhp - d.tired; + if ((class = pip_job_function(class, 4, 8, 31)) < 0) + return 0; + + if (class >= 75) + { + class = 4; + d.money += 250 + (d.homework + d.cook) / 50; + vmsg("®ÈÀ]¨Æ·~»]»]¤é¤W..§Æ±æ±z¦A¹L¨ÓÀ°¦£.."); + } + else if (class >= 50) + { + class = 3; + d.money += 200 + (d.homework + d.cook) / 55; + vmsg("®ÈÀ]ÁÙÆZ¶¶§Qªºò..¶â¶â.."); + } + else if (class >= 25) + { + class = 2; + d.money += 150 + (d.homework + d.cook) / 60; + vmsg("´¶´¶³q³q°Õ..¥i¥H§ó¦nªº..¥[ªo.."); + } + else + { + class = 1; + d.money += 100 + (d.homework + d.cook) / 65; + vmsg("³oÓ«ÜÁV¿|³á..³o¼Ë¤£¦æ°Õ.."); + } + + d.homework += rand() % 2 + class; + d.cook += rand() % 2 + class; + d.family += class; + + d.workC++; + return 0; +} + + +int +pip_job_workD() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x¹A³õ ¢x+ µL ¢x */ + /* ¢x ¢x- ®ð½è ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + class = d.hp * 100 / d.maxhp - d.tired; + if ((class = pip_job_function(class, 6, 12, 41)) < 0) + return 0; + + if (class >= 75) + { + d.money += 250 + (d.attack + d.resist) / 50; + vmsg("¤û¦Ïªøªº¦n¦n³á..§Æ±æ±z¦A¨ÓÀ°¦£.."); + } + else if (class >= 50) + { + d.money += 210 + (d.attack + d.resist) / 55; + vmsg("¨þ¨þ..ÁÙ¤£¿ù³á.."); + } + else if (class >= 25) + { + d.money += 160 + (d.attack + d.resist) / 60; + vmsg("´¶´¶³q³q°Õ..¥i¥H§ó¦nªº.."); + } + else + { + d.money += 120 + (d.attack + d.resist) / 65; + vmsg("±z¤£¤Ó¾A¦X¹A³õªº¤u§@.."); + } + + d.character -= rand() % 5; + if (d.character < 0) + d.character = 0; + + d.workD++; + return 0; +} + + +int +pip_job_workE() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢xÀ\ÆU ¢x+ ±½¦a¬~¦ç ²i¶¹ ¢x */ + /* ¢x ¢x- µL ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + class = d.cook / 6 - d.tired; + if ((class = pip_job_function(class, 4, 9, 51)) < 0) + return 0; + + if (class >= 75) + { + class = 4; + d.money += 250 + (d.homework + d.cook) / 50; + vmsg("«È¤H³£»¡¤Ó¦n¦Y¤F..¦A¨Ó¤@½L§a.."); + } + else if (class >= 50) + { + class = 3; + d.money += 200 + (d.homework + d.cook) / 55; + vmsg("µNªºÁÙ¤£¿ù¦Yò.."); + } + else if (class >= 25) + { + class = 2; + d.money += 150 + (d.homework + d.cook) / 60; + vmsg("´¶´¶³q³q°Õ..¥i¥H§ó¦nªº.."); + } + else + { + class = 1; + d.money += 100 + (d.homework + d.cook) / 65; + vmsg("¼pÃÀ«Ý¥[±j³á.."); + } + + d.homework += rand() % 2 + class; + d.cook += rand() % 5 + class; + + d.workE++; + return 0; +} + + +int +pip_job_workF() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x±Ð°ó ¢x+ ·R¤ß ¹D¼w «H¥õ ¢x */ + /* ¢x ¢x- ¸oÄ^ ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + class = d.hp * 100 / d.maxhp - d.tired; + if ((class = pip_job_function(class, 3, 6, 61)) < 0) + return 0; + + if (class >= 75) + { + class = 4; + d.money += 100 + (d.etchics + d.belief) / 50; + vmsg("«D±`ÁÂÁ±z³á..¯u¬O±o¤Oªº§U¤â"); + } + else if (class >= 50) + { + class = 3; + d.money += 75 + (d.etchics + d.belief) / 55; + vmsg("ÁÂÁ±zªº¼ö¤ßÀ°¦£.."); + } + else if (class >= 25) + { + class = 2; + d.money += 50 + (d.etchics + d.belief) / 60; + vmsg("¯uªº«Ü¦³·R¤ß°Õ..¤£¹L¦³ÂI¤p²Öªº¼Ë¤l.."); + } + else + { + class = 1; + d.money += 25 + (d.etchics + d.belief) / 65; + vmsg("¨Ó©^Äm¤£¿ù..¦ý¤]¤£¯à¥´²V£«.."); + } + + d.love += rand() % 2 + class; + d.etchics += rand() % 4 + class; + d.belief += rand() % 4 + class; + + d.sin -= rand() % 9; + if (d.sin < 0) + d.sin = 0; + + d.workF++; + return 0; +} + + +int +pip_job_workG() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x¦aÅu ¢x+ «Ý¤H±µª« ¾y¤O ½Í¦R ³t«× ¢x */ + /* ¢x ¢x- µL ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + class = d.hp * 100 / d.maxhp - d.tired; + if ((class = pip_job_function(class, 5, 10, 71)) < 0) + return 0; + + d.money += 200 + (d.charm + d.speech) * class / 5000; + vmsg("Â\\¦aÅun¸úĵ¹î°Õ..:p"); + + d.toman += rand() % 2; + d.charm += rand() % 2; + d.speed += rand() % 2 + 1; + d.speech += rand() % 2 + 1; + + d.workG++; + return 0; +} + + +int +pip_job_workH() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x¥ï¤ì³õ ¢x+ §ðÀ»¤O ¢x */ + /* ¢x ¢x- ®ð½è ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + if (d.bbtime < 1800 * 1) + { + vmsg("¤pÂû¤Ó¤p¤F¡A¤@·³¥H«á¦A¨Ó§a.."); + return 0; + } + + class = d.hp * 100 / d.maxhp - d.tired; + if ((class = pip_job_function(class, 7, 14, 81)) < 0) + return 0; + + if (class >= 75) + { + class = 4; + d.money += 350 + (d.maxhp + d.attack) / 50; + vmsg("±zµÃ¤O«Ü¦nò.."); + } + else if (class >= 50) + { + class = 3; + d.money += 300 + (d.maxhp + d.attack) / 55; + vmsg("¬å¤F¤£¤Ö¾ð³á.."); + } + else if (class >= 25) + { + class = 2; + d.money += 250 + (d.maxhp + d.attack) / 60; + vmsg("´¶´¶³q³q°Õ..¥i¥H§ó¦nªº.."); + } + else + { + class = 1; + d.money += 200 + (d.maxhp + d.attack) / 65; + vmsg("«Ý¥[±j³á..ÁëÁå¦A¨Ó§a.."); + } + + d.attack += rand() % 2 + class; + + d.character -= rand() % 5; + if (d.character < 0) + d.character = 0; + + d.workH++; + return 0; +} + + +int +pip_job_workI() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x¬ü®e°| ¢x+ ÃÀ³N ·P¨ü ¢x */ + /* ¢x ¢x- µL ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + if (d.bbtime < 1800 * 1) + { + vmsg("¤pÂû¤Ó¤p¤F¡A¤@·³¥H«á¦A¨Ó§a.."); + return 0; + } + + class = d.art / 6 - d.tired; + if ((class = pip_job_function(class, 5, 10, 91)) < 0) + return 0; + + if (class >= 75) + { + class = 4; + d.money += 400 + (d.art + d.affect) / 50; + vmsg("«È¤H³£«Ü³ßÅwÅý±z°µ³y«¬ò.."); + } + else if (class >= 50) + { + class = 3; + d.money += 360 + (d.art + d.affect) / 55; + vmsg("°µªº¤£¿ù³á..»á¦³¤Ñ¥÷.."); + } + else if (class >= 25) + { + class = 2; + d.money += 320 + (d.art + d.affect) / 60; + vmsg("°¨°¨ªêªê°Õ..¦A¥[ªo¤@ÂI.."); + } + else + { + class = 1; + d.money += 250 + (d.art + d.affect) / 65; + vmsg("«Ý¥[±j³á..¥H«á¦A¨Ó§a.."); + } + + d.art += rand() % 3 + class; + d.affect += rand() % 2 + class; + + d.workI++; + return 0; +} + + +int +pip_job_workJ() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x¬¼Ây°Ï ¢x+ §ðÀ»¤O ³t«× ¢x */ + /* ¢x ¢x- ®ð½è ·R¤ß ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + if (d.bbtime < 1800 * 2) + { + vmsg("¤pÂû¤Ó¤p¤F¡A¤G·³¥H«á¦A¨Ó§a.."); + return 0; + } + + class = d.hp * 100 / d.maxhp - d.tired; + if ((class = pip_job_function(class, 6, 13, 101)) < 0) + return 0; + + if (class >= 75) + { + class = 4; + d.money += 300 + (d.attack + d.speed) / 50; + vmsg("±z¬O§¹¬üªºÂy¤H.."); + } + else if (class >= 50) + { + class = 3; + d.money += 270 + (d.attack + d.speed) / 55; + vmsg("¦¬ÀòÁÙ¤£¿ù³á..¥i¥H¹¡À\\¤@¹y¤F.."); + } + else if (class >= 25) + { + class = 2; + d.money += 240 + (d.attack + d.speed) / 60; + vmsg("¬¼Ây¬OÅé¤O»P´¼¤Oªºµ²¦X.."); + } + else + { + class = 1; + d.money += 210 + (d.attack + d.speed) / 65; + vmsg("§Þ³N®t±j¤H·N..¦A¥[ªo³á.."); + } + + d.attack += rand() % 2 + class; + d.speed += rand() % 2 + class; + + d.character -= rand() % 5; + if (d.character < 0) + d.character = 0; + d.love -= rand() % 5; + if (d.love < 0) + d.love = 0; + + d.workJ++; + return 0; +} + + +int +pip_job_workK() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x¤u¦a ¢x+ ¨¾¿m¤O ¢x */ + /* ¢x ¢x- ¾y¤O ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + if (d.bbtime < 1800 * 2) + { + vmsg("¤pÂû¤Ó¤p¤F¡A¤G·³¥H«á¦A¨Ó§a.."); + return 0; + } + + class = d.hp * 100 / d.maxhp - d.tired; + if ((class = pip_job_function(class, 7, 15, 111)) < 0) + return 0; + + if (class >= 75) + { + class = 4; + d.money += 250 + (d.maxhp + d.resist) / 50; + vmsg("¤uµ{«Ü§¹¬ü..ÁÂÁ¤F.."); + } + else if (class >= 50) + { + class = 3; + d.money += 220 + (d.maxhp + d.resist) / 55; + vmsg("¤uµ{©|ºÙ¶¶§Q..¨¯W¤F.."); + } + else if (class >= 25) + { + class = 2; + d.money += 200 + (d.maxhp + d.resist) / 60; + vmsg("¤uµ{®t±j¤H·N..¦A¥[ªo³á.."); + } + else + { + class = 1; + d.money += 160 + (d.maxhp + d.resist) / 65; + vmsg("£..«Ý¥[±j«Ý¥[±j.."); + } + + d.resist += rand() % 2 + class; + + d.charm -= rand() % 5; + if (d.charm < 0) + d.charm = 0; + + d.workK++; + return 0; +} + + +int +pip_job_workL() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x¹Ó¶é ¢x+ «i´± §ÜÅ]¯à¤O ·P¨ü ¢x */ + /* ¢x ¢x- ¾y¤O ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + if (d.bbtime < 1800 * 3) + { + vmsg("¤pÂû¤Ó¤p¤F¡A¤T·³¥H«á¦A¨Ó§a.."); + return 0; + } + + class = d.hp * 100 / d.maxhp - d.tired; + if ((class = pip_job_function(class, 4, 8, 121)) < 0) + return 0; + + if (class >= 75) + { + class = 4; + d.money += 200 + (d.brave + d.affect) / 50; + vmsg("¦u¹Ó¦¨¥\\³á..¦hÁ¤F"); + } + else if (class >= 50) + { + class = 3; + d.money += 150 + (d.brave + d.affect) / 55; + vmsg("¦u¹ÓÁٺ⦨¥\\³á..Á°Õ.."); + } + else if (class >= 25) + { + class = 2; + d.money += 120 + (d.brave + d.affect) / 60; + vmsg("¦u¹ÓÁÙºâ®t±j¤H·N³á..¥[ªo.."); + } + else + { + class = 1; + d.money += 80 + (d.brave + d.affect) / 65; + vmsg("§Ú¤]¤£¤è«K»¡Ô£¤F..½Ð¦A¥[ªo.."); + } + + d.brave += rand() % 4 + class; + d.immune += rand() % 3 + class; + d.affect += class; + + d.charm -= rand() % 5; + if (d.charm < 0) + d.charm = 0; + + d.workL++; + return 0; +} + + +int +pip_job_workM() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x®a®x±Ð®v¢x+ ´¼¤O ½Í¦R ¢x */ + /* ¢x ¢x- µL ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + if (d.bbtime < 1800 * 4) + { + vmsg("¤pÂû¤Ó¤p¤F¡A¥|·³¥H«á¦A¨Ó§a.."); + return 0; + } + + class = d.hp * 100 / d.maxhp - d.tired; + if ((class = pip_job_function(class, 3, 7, 131)) < 0) + return 0; + + d.money += 50 + (d.wisdom + d.character) * class / 5000; + vmsg("®a±Ð»´ÃP..·íµM¿ú´N¤Ö¤@ÂIÅo"); + + d.wisdom += rand() % 2 + 3; + d.speech += rand() % 2 + 1; + + d.workM++; + return 0; +} + + +int +pip_job_workN() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x°s©± ¢x+ ¾y¤O ½Í¦R ²i¶¹ ¢x */ + /* ¢x ¢x- ´¼¤O ªÀ¥æµû»ù ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + if (d.bbtime < 1800 * 5) + { + vmsg("¤pÂû¤Ó¤p¤F¡A¤·³¥H«á¦A¨Ó§a.."); + return 0; + } + + class = d.charm / 6 - d.tired; + if ((class = pip_job_function(class, 5, 11, 141)) < 0) + return 0; + + if (class >= 75) + { + class = 4; + d.money += 500 + (d.charm + d.speech) / 50; + vmsg("«Ü¬õò.."); + } + else if (class >= 50) + { + class = 3; + d.money += 400 + (d.charm + d.speech) / 55; + vmsg("ÆZ¨üÅwªïªºC.."); + } + else if (class >= 25) + { + class = 2; + d.money += 300 + (d.charm + d.speech) / 60; + vmsg("«Ü¥¤Z°Õ..¦ý°¨°¨ªêªê.."); + } + else + { + class = 1; + d.money += 200 + (d.charm + d.speech) / 65; + vmsg("´A¤O¤£°÷°Õ..½Ð¥[ªo.."); + } + + d.charm += rand() % 3 + class; + d.speech += rand() % 2 + class; + d.cook += class; + + d.wisdom -= rand() % 5; + if (d.wisdom < 0) + d.wisdom = 0; + d.social -= rand() % 5; + if (d.social < 0) + d.social = 0; + + d.workN++; + return 0; +} + + +int +pip_job_workO() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x°s®a ¢x+ ¾y¤O ¸oÄ^ ¢x */ + /* ¢x ¢x- «Ý¤H±µª« ¹D¼w ¿Ë¤lÃö«Y «H¥õ ªÀ¥æµû»ù ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + if (d.bbtime < 1800 * 5) + { + vmsg("¤pÂû¤Ó¤p¤F¡A¤·³¥H«á¦A¨Ó§a.."); + return 0; + } + + class = d.charm / 6 - d.tired; + if ((class = pip_job_function(class, 6, 12, 151)) < 0) + return 0; + + if (class >= 75) + { + class = 4; + d.money += 600 + (d.charm + d.speech) / 50; + vmsg("±z¬O¥»©±ªº¬õµPò.."); + } + else if (class >= 50) + { + class = 3; + d.money += 500 + (d.charm + d.speech) / 55; + vmsg("±zÆZ¨üÅwªïªºC.."); + } + else if (class >= 25) + { + class = 2; + d.money += 400 + (d.charm + d.speech) / 60; + vmsg("«Ü¥¤Z..¦ý°¨°¨ªêªê°Õ.."); + } + else + { + class = 1; + d.money += 300 + (d.charm + d.speech) / 65; + vmsg("ü..´A¤O¤£°÷°Õ.."); + } + + d.charm += rand() % 4 + class; + d.sin += rand() % 4 + class; + + d.toman -= rand() % 5; + if (d.toman < 0) + d.toman = 0; + d.etchics -= rand() % 5; + if (d.etchics < 0) + d.etchics = 0; + d.relation -= rand() % 5; + if (d.relation < 0) + d.relation = 0; + d.belief -= rand() % 5; + if (d.belief < 0) + d.belief = 0; + d.social -= rand() % 5; + if (d.social < 0) + d.social = 0; + + d.workO++; + return 0; +} + + +int +pip_job_workP() +{ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x©]Á`·| ¢x+ ¾y¤O ½Í¦R ¸oÄ^ ¢x */ + /* ¢x ¢x- «Ý¤H±µª« ®ð½è ¹D¼w ¿Ë¤lÃö«Y «H¥õ ªÀ¥æµû»ù ¢x */ + /* ¢u¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + + int class; + + if (d.bbtime < 1800 * 6) + { + vmsg("¤pÂû¤Ó¤p¤F¡A¤»·³¥H«á¦A¨Ó§a.."); + return 0; + } + + class = (d.charm + d.art - d.belief) / 6 - d.tired; + if ((class = pip_job_function(class, 6, 12, 161)) < 0) + return 0; + + if (class >= 75) + { + class = 4; + d.money += 1000 + (d.charm + d.speech) / 50; + vmsg("±z¬O¥»©]Á`·|³Ì°{«Gªº¬P¬Pò.."); + } + else if (class >= 50) + { + class = 3; + d.money += 800 + (d.charm + d.speech) / 55; + vmsg("¶â¶â..±zÆZ¨üÅwªïªºC.."); + } + else if (class >= 25) + { + class = 2; + d.money += 600 + (d.charm + d.speech) / 60; + vmsg("n¥[ªo¤F°Õ..¦ý´¶´¶°Õ.."); + } + else + { + class = 1; + d.money += 400 + (d.charm + d.speech) / 65; + vmsg("ü..¤£¦æ°Õ.."); + } + + d.charm += rand() % 5 + class; + d.speech += rand() % 2 + class; + d.sin += rand() % 6 + class; + + d.toman -= rand() % 5; + if (d.toman < 0) + d.toman = 0; + d.character -= rand() % 5; + if (d.character < 0) + d.character = 0; + d.etchics -= rand() % 5; + if (d.etchics < 0) + d.etchics = 0; + d.relation -= rand() % 5; + if (d.relation < 0) + d.relation = 0; + d.belief -= rand() % 5; + if (d.belief < 0) + d.belief = 0; + d.social -= rand() % 5; + if (d.social < 0) + d.social = 0; + + d.workP++; + return 0; +} +#endif /* HAVE_GAME */ diff --git a/pip/pip_menu.c b/pip/pip_menu.c new file mode 100644 index 0000000..c4df517 --- /dev/null +++ b/pip/pip_menu.c @@ -0,0 +1,809 @@ +/*-------------------------------------------------------*/ +/* pip_menu.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¿ï³æ¨ç¦¡ */ +/* create : / / */ +/* update : 01/08/15 */ +/* author : dsyan.bbs@forever.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#include "pip.h" + + +/*-------------------------------------------------------*/ +/* ¿ï³æ */ +/*-------------------------------------------------------*/ + + +/* ¥D¿ï³æ [1]°ò¥» [2]³}µó [3]צæ [4]ª±¼Ö [5]¥´¤u [6]¯S®í [7]¨t²Î */ + +int pip_basic_menu(), pip_store_menu(), pip_practice_menu(), pip_play_menu(); +int pip_job_menu(), pip_special_menu(), pip_system_menu(); + +static struct pipcommands pipmainlist[] = +{ + pip_basic_menu, '1', + pip_store_menu, '2', + pip_practice_menu, '3', + pip_play_menu, '4', + pip_job_menu, '5', + pip_special_menu, '6', + pip_system_menu, '7', + NULL, '\0' +}; + + +/* °ò¥»¿ï³æ [1]Áý¹ [2]²M¼ä [3]¥ð®§ [4]¿Ë¿Ë [5]´«¿ú */ + +int pip_basic_feed(), pip_basic_takeshower(), pip_basic_takerest(), pip_basic_kiss(), pip_money(); + +static struct pipcommands pipbasiclist[] = +{ + pip_basic_feed, '1', + pip_basic_takeshower, '2', + pip_basic_takerest, '3', + pip_basic_kiss, '4', + pip_money, '5', + NULL, '\0' +}; + + +/* ³}µó ¡i¤é±`¥Î«~¡j[1]«K§Q°Ó©± [2]¦Ê¯óÃľQ [3]©]¸Ì®Ñ§½ */ +/* ¿ï³æ ¡iªZ¾¹¦Ê³f¡j[A]ÀY³¡¸Ë³Æ [B]¤â³¡¸Ë³Æ [C]¬ÞµP¸Ë³Æ [D]¨Åé¸Ë³Æ [E]¸}³¡¸Ë³Æ */ + +int pip_store_food(), pip_store_medicine(), pip_store_other(); +int pip_store_weapon_head(), pip_store_weapon_hand(), pip_store_weapon_shield(); +int pip_store_weapon_body(), pip_store_weapon_foot(); + +static struct pipcommands pipstorelist[] = +{ + pip_store_food, '1', + pip_store_medicine, '2', + pip_store_other, '3', + pip_store_weapon_head, 'a', + pip_store_weapon_hand, 'b', + pip_store_weapon_shield,'c', + pip_store_weapon_body, 'd', + pip_store_weapon_foot, 'e', + NULL, '\0' +}; + + +/* צæ [A]¬ì¾Ç(1) [B]¸Öµü(1) [C]¯«¾Ç(1) [D]x¾Ç(1) [E]¼C³N(1) */ +/* ¿ï³æ [F]®æ°«(1) [G]Å]ªk(1) [H]§»ö(1) [I]øµe(1) [J]»RÁÐ(1) */ + +int pip_practice_classA(), pip_practice_classB(), pip_practice_classC(), pip_practice_classD(), pip_practice_classE(); +int pip_practice_classF(), pip_practice_classG(), pip_practice_classH(), pip_practice_classI(), pip_practice_classJ(); + +static struct pipcommands pippracticelist[] = +{ + pip_practice_classA, 'a', + pip_practice_classB, 'b', + pip_practice_classC, 'c', + pip_practice_classD, 'd', + pip_practice_classE, 'e', + pip_practice_classF, 'f', + pip_practice_classG, 'g', + pip_practice_classH, 'h', + pip_practice_classI, 'i', + pip_practice_classJ, 'j', + NULL, '\0' +}; + + +/* ª±¼Ö¿ï³æ [1]´²¨B [2]¹B°Ê [3]¬ù·| [4]²q®± [5]®È¹C [6]¥¥~ [7]°Ûºq */ + +int pip_play_stroll(), pip_play_sport(), pip_play_date(), pip_play_guess(); +int pip_play_outing(), pip_play_kite(), pip_play_KTV(); + +static struct pipcommands pipplaylist[] = +{ + pip_play_stroll, '1', + pip_play_sport, '2', + pip_play_date, '3', + pip_play_guess, '4', + pip_play_outing, '5', + pip_play_kite, '6', + pip_play_KTV, '7', + NULL, '\0' +}; + + +/* ¥´¤u [A]®a¨Æ [B]«O©i [C]®ÈÀ] [D]¹A³õ [E]À\ÆU [F]±Ð°ó [G]¦aÅu [H]¥ï¤ì */ +/* ¿ï³æ [I]¬ü¾v [J]Ây¤H [K]¤u¦a [L]¦u¹Ó [M]®a±Ð [N]°s®a [O]°s©± [P]©]Á`·| */ + +int pip_job_workA(), pip_job_workB(), pip_job_workC(), pip_job_workD(); +int pip_job_workE(), pip_job_workF(), pip_job_workG(), pip_job_workH(); +int pip_job_workI(), pip_job_workJ(), pip_job_workK(), pip_job_workL(); +int pip_job_workM(), pip_job_workN(), pip_job_workO(), pip_job_workP(); + +static struct pipcommands pipjoblist[] = +{ + pip_job_workA, 'a', + pip_job_workB, 'b', + pip_job_workC, 'c', + pip_job_workD, 'd', + pip_job_workE, 'e', + pip_job_workF, 'f', + pip_job_workG, 'g', + pip_job_workH, 'h', + pip_job_workI, 'i', + pip_job_workJ, 'j', + pip_job_workK, 'k', + pip_job_workL, 'l', + pip_job_workM, 'm', + pip_job_workN, 'n', + pip_job_workO, 'o', + pip_job_workP, 'p', + NULL, '\0' +}; + + +/* ¯S®í¿ï³æ [1]Âå°| [2]¾ã®e [3]¾Ô°« [4]¬Ó®c [5]¥ô°È [6]¹ï¾Ô */ + +int pip_see_doctor(), pip_change_weight(), pip_fight_menu(), pip_go_palace(), pip_quest_menu(), pip_pk_menu(); + +static struct pipcommands pipspeciallist[] = +{ + pip_see_doctor, '1', + pip_change_weight, '2', + pip_fight_menu, '3', + pip_go_palace, '4', + pip_quest_menu, '5', + pip_pk_menu, '6', + NULL, '\0' +}; + + +/* ¨t²Î¿ï³æ [1]¸Ô²Ó¸ê®Æ [2]«ô³X¥L¤H [3]¤pÂû©ñ¥Í [4]¯S§OªA°È [S]Àx¦s¶i«× [L]Ū¨ú¶i«× */ + +int pip_query_self(), pip_query(), pip_system_freepip(), pip_system_service(); +int pip_write_backup(), pip_read_backup(); + +static struct pipcommands pipsystemlist[] = +{ + pip_query_self, '1', + pip_query, '2', + pip_system_freepip, '3', + pip_system_service, '4', + pip_write_backup, 's', + pip_read_backup, 'l', + NULL, '\0' +}; + + +/*-------------------------------------------------------*/ +/* «ü¥O¿ï³æ */ +/*-------------------------------------------------------*/ + + +/* ¦b b_lines ©M b_lines - 1 ³o¤G¦æ³£¬O«ü¥O¿ï³æ */ +/* Y«ü¥O²Ä¤G¦æ¡A«h²Ä¤@Äæ¦Û¥Õ */ +/* °Ñ¦Ò global.h FEETER */ + +/* ¶È¨Ñ pip_do_menu() ¨Ï¥Î */ + +static char *menuname[8][2] = +{ + {"", + COLOR1 " ¿ï³æ " COLOR2 " [1]°ò¥» [2]³}µó [3]צæ [4]ª±¼Ö [5]¥´¤u [6]¯S®í [7]¨t²Î [Q]Â÷¶} \033[m"}, + + {"", + COLOR1 " °ò¥» " COLOR2 " [1]Áý¹ [2]²M¼ä [3]¥ð®§ [4]¿Ë¿Ë [5]´«¿ú [Q]¸õ¥X \033[m"}, + + {COLOR1 " ³}µó " COLOR2 " ¤é±`¥Î«~ [1]«K§Q°Ó©± [2]¦Ê¯óÃľQ [3]©]¸Ì®Ñ§½ [Q]¸õ¥X \033[m", + COLOR1 " ±ÄÁÊ " COLOR2 " ªZ¾¹¦Ê³f [A]ÀY³¡¸Ë³Æ [B]¤â³¡¸Ë³Æ [C]¬ÞµP¸Ë³Æ [D]¨Åé¸Ë³Æ [E]¸}³¡¸Ë³Æ \033[m"}, + + {COLOR1 " צæ " COLOR2 " [A]¬ì¾Ç [B]¸Öµü [C]¯«¾Ç [D]x¾Ç [E]¼C³N \033[m", + COLOR1 " W½m " COLOR2 " [F]®æ°« [G]Å]ªk [H]§»ö [I]øµe [J]»RÁÐ [Q]¸õ¥X \033[m"}, + + {"", + COLOR1 " ª±¼Ö " COLOR2 " [1]´²¨B [2]¹B°Ê [3]¬ù·| [4]²q®± [5]®È¹C [6]¥¥~ [7]°Ûºq [Q]¸õ¥X \033[m"}, + + {COLOR1 " ¥´¤u " COLOR2 " [A]®a¨Æ [B]«O©i [C]®ÈÀ] [D]¹A³õ [E]À\\ÆU [F]±Ð°ó [G]¦aÅu [H]¥ï¤ì [Q]¸õ¥X\033[m", + COLOR1 " ÁÈ¿ú " COLOR2 " [I]¬ü¾v [J]Ây¤H [K]¤u¦a [L]¦u¹Ó [M]®a±Ð [N]°s®a [O]°s©± [P]©]Á`·| \033[m"}, + + {"", + COLOR1 " ¯S®í " COLOR2 " [1]Âå°| [2]¾ã®e [3]¾Ô°« [4]¬Ó®c [5]¥ô°È [6]¹ï¾Ô [Q]¸õ¥X \033[m"}, + + {COLOR1 " ªA°È " COLOR2 " [1]¸Ô²Ó¸ê®Æ [2]«ô³X¥L¤H [3]¤pÂû©ñ¥Í [4]¯S§OªA°È \033[m", + COLOR1 " ¨t²Î " COLOR2 " [S]Àx¦s¶i«× [L]Ū¨ú¶i«× [Q]¸õ¥X \033[m"} +}; + + +/*-------------------------------------------------------*/ +/* ¿ï³æ¨ç¦¡ */ +/*-------------------------------------------------------*/ + + + /*-----------------------------------------------------*/ + /* ±`¾n¨ç¦¡ */ + /*-----------------------------------------------------*/ + + +#define PIP_CHECK_PERIOD 60 /* ¨C 60 ¬íÀˬd¤@¦¸ */ + +static int /* ¦^¶Ç ·³¼Æ */ +pip_time_update() +{ + int oldtm, tm; + + /* ©T©w®É¶¡°µªº¨Æ */ + + if ((time(0) - last_time) >= PIP_CHECK_PERIOD) + { + do + { + d.shit += rand() % 3 + 3; /* ¤£°µ¨Æ¡AÁÙ¬O·|ÅÜżªº */ + d.tired -= 2; /* ¤£°µ¨Æ¡A¯h³Ò·íµM´î§C°Õ */ + d.sick += rand() % 4 - 2; /* ¤£°µ¨Æ¡A¯f®ð·|ÀH¾÷²v¼W¥[´î¤Ö©Î¼W¥[¤Ö³\ */ + d.happy += rand() % 4 - 2; /* ¤£°µ¨Æ¡A§Ö¼Ö·|ÀH¾÷²v¼W¥[´î¤Ö©Î¼W¥[¤Ö³\ */ + d.satisfy += rand() % 4 - 2; /* ¤£°µ¨Æ¡Aº¡¨¬·|ÀH¾÷²v¼W¥[´î¤Ö©Î¼W¥[¤Ö³\ */ + d.hp -= rand() % 3 + d.sick / 10; /* ¤£°µ¨Æ¡A¨{¤l¤]·|¾j«§¡A¤]·|¦]¥Í¯f°§C¤@ÂI */ + + last_time += PIP_CHECK_PERIOD; /* ¤U¦¸§ó·s®É¶¡ */ + } while ((time(0) - last_time) >= PIP_CHECK_PERIOD); + + /* Àˬd¦~ÄÖ */ + + oldtm = d.bbtime / 60 / 30; /* §ó·s«e´X·³¤F */ + d.bbtime += time(0) - start_time; /* §ó·s¤pÂûªº®É¶¡(¦~ÄÖ) */ + start_time = time(0); + tm = d.bbtime / 60 / 30; /* §ó·s«á´X·³¤F */ + + /* itoc.010815.µù¸Ñ: ¦pªG¤pÂû¤@ª½¦b¦¸¿ï³æ¤¤(¨Ò¦p¾Ô°«×¦æ)¡A + ¨º»ò·|¦]¬°«Ü¤[(¶W¹L30¤ÀÄÁ§Y¤@·³)¨S¦³°õ¦æ pip_time_update() ¦Ó¤@¦¸¥[¦n¦h·³ */ + + /* itoc.010815: ¤@¦¸¹L¦n¦h·³·|¤Ö¥[¦n¦h¦¸¹L¥Í¤éªº¦n³B¡A¤£¤©×¥¿¡A§@¬°h«Ý¤pÂûªº³B»@ :p */ + + if (tm != oldtm) /* ·³¼Æ§ó·s«e«á¦pªG¤£¦P¡Aªí¥Üªø¤j¤F */ + { + /* ªø¤j®Éªº¼W¥[§ïÅÜÈ */ + count_tired(1, 7, 0, 100, 0); /* «ì´_¯h³Ò */ + d.happy += rand() % 5 + 5; + d.satisfy += rand() % 5; + d.wisdom += 10; + d.character += rand() % 5; + d.money += 500; + d.seeroyalJ = 1; /* ¤@¦~¥i¥H¨£¤ý¤l¤@¦¸ */ + pip_write_file(); /* ¦Û°ÊÀx¦s */ + + vs_head("¹q¤l¾i¤pÂû", str_site); + show_basic_pic(20); /* ¥Í¤é§Ö¼Ö */ + vmsg("¤pÂû¹L¥Í¤é¤F"); + + /* ¦¬Ã¬©u */ + if (tm % 2 == 0) /* ¤G¦~¤@¦¸¦¬Ã¬©u */ + pip_race_main(); + + /* µ²§½ */ + if (tm >= 21 && (d.wantend == 4 || d.wantend == 5 || d.wantend == 6)) /* ª±¨ì 20 ·³ */ + pip_ending_screen(); + } + } + else + { + tm = d.bbtime / 60 / 30; /* ¦pªG¨S¦³ update¡A¤]n¦^¶Ç tm(·³¼Æ) */ + } + + /* °¸µo¨Æ¥ó */ + + oldtm = rand() % 2000; /* ɥΠoldtm °µ¶Ã¼Æ */ + if (oldtm == 0 && tm >= 15 && d.charm >= 300 && d.character >= 300) + pip_marriage_offer(); /* °Ó¤H¨Ó¨D±B */ + else if (oldtm > 1998) + pip_meet_divine(); /* ÀH¾÷¹J¨ì¥e¤R®v */ + else if (oldtm > 1996) + pip_meet_sysop(); /* ÀH¾÷¹J¨ì SYSOP */ + else if (oldtm > 1994) + pip_meet_smith(); /* ÀH¾÷¹J¨ìÅK¦K */ + + /* Àˬd¤@¨Ç±`ÅܰʪºÈ¬O§_Ãz±¼ */ + /* itoc.010815: ¦b pip_time_update() ¤¤¤£¥²Àˬd shit/tired/sick >100 ©Î happy/satisfy/hp < 0 + ¦Ó¦b pip_refresh_screen() Àˬd¨Ã¶¶¹D«Å§i¦º¤` */ + + if (d.shit < 0) + d.shit = 0; + if (d.tired < 0) + d.tired = 0; + if (d.sick < 0) + d.sick = 0; + + if (d.happy > 100) + d.happy = 100; + if (d.satisfy > 100) + d.satisfy = 100; + if (d.hp > d.maxhp) + d.hp = d.maxhp; + + return tm; +} + + +static int /* -1:¦º¤` 0:¨S¨Æ */ +pip_refresh_screen(menunum, mode) /* «Ã¸¾ãÓµe± */ + int menunum; /* ¿ï³æ½s¸¹ */ + int mode; /* µe±ºØÃþ 0:¤@¯ë 1:Áý¹ 2:¥´¤u 3:צæ */ +{ + int tm, age, pic; + char inbuf2[20], inbuf3[20], inbuf4[20], inbuf5[20], inbuf6[20], inbuf7[20]; + + char yo[12][5] = + { + "½Ï¥Í", "À¦¨à", "¥®¨à", "¨àµ£", "¤Ö¦~", "«C¦~", + "¦¨¦~", "§§¦~", "§ó¦~", "¦Ñ¦~", "¥jµ}", "¯«¥P" + }; + + tm = pip_time_update(); /* ©T©w®É¶¡n°µªº¨Æ */ + + if (tm == 0) /* ½Ï¥Í */ + age = 0; + else if (tm == 1) /* À¦¨à */ + age = 1; + else if (tm <= 5) /* ¥®¨à */ + age = 2; + else if (tm <= 12) /* ¨àµ£ */ + age = 3; + else if (tm <= 15) /* ¤Ö¦~ */ + age = 4; + else if (tm <= 18) /* «C¦~ */ + age = 5; + else if (tm <= 35) /* ¦¨¦~ */ + age = 6; + else if (tm <= 45) /* §§¦~ */ + age = 7; + else if (tm <= 60) /* §ó¦~ */ + age = 8; + else if (tm <= 70) /* ¦Ñ¦~ */ + age = 9; + else if (tm <= 100) /* ¥jµ} */ + age = 10; + else /* ¯«¥P */ + age = 11; + + sprintf(inbuf2, "%-4d/%4d", d.hp, d.maxhp); + sprintf(inbuf3, "%-4d/%4d", d.mp, d.maxmp); + sprintf(inbuf4, "%-4d/%4d", d.vp, d.maxvp); + sprintf(inbuf5, "%-4d/%4d", d.sp, d.maxsp); + sprintf(inbuf6, "%-4d/%4d", d.shit, d.sick); + sprintf(inbuf7, "%-4d/%4d", d.happy, d.satisfy); + + if (menunum) + { + clear(); + } + else /* itoc.010816: ¦pªG¬O¶i¤J¥D¿ï³æ¡A¤£n²M¤¤¶¡ 5~18 ¦C */ + { + clrfromto(0, 4); + clrfromto(19, b_lines); + } + + /* ¿Ã¹õ¤W± (0~4¦C) Åã¥ÜÂI¼Æ */ + + move(0, 0); + prints(COLOR1 " ¸ê®Æ " COLOR2 " %s %-15s \033[m\n", d.sex == 1 ? "¡ñ" : "¡ð", d.name); + + /* itoc,010802: ¬°¤F¬Ý²M·¡¤@ÂI¡A©Ò¥H prints() ¸Ì±ªº¤Þ¼Æ´N¤£Â_¦æ¼g¦b¸Ó¦C³Ì«á */ + prints("\033[1;32m[ª¬ ºA] \033[37m%-9s\033[32m [¥Í ¤é] \033[37m%-9s\033[32m [¦~ ÄÖ] \033[37m%-9d\033[32m [ª÷ ¿ú] \033[37m%-9d\033[m\n", yo[age], d.birth, tm, d.money); + prints("\033[1;32m[¥Í ©R] \033[35m%-9s\033[32m [ªk ¤O] \033[34m%-9s\033[32m [²¾°Ê¤O] \033[36m%-9s\033[32m [¤º ¤O] \033[31m%-9s\033[m\n", inbuf2, inbuf3, inbuf4, inbuf5); + prints("\033[1;32m[Åé «] \033[37m%-9d\033[32m [¯h ³Ò] \033[37m%-9d\033[32m [ż¡þ¯f] \033[37m%-9s\033[32m [§Ö¡þº¡] \033[37m%-9s\033[m\n", d.weight, d.tired, inbuf6, inbuf7); + + if (mode == 0) /* ¤@¯ëµe± */ + { + char *hint[3] = + { + "\033[1;35m[¯¸ªø¤ê]:\033[37mn¦h¦hª`·N¤pÂûªº¯h³Ò«×©M¯f®ð¡A¥H§K²Ö¦º¯f¦º\033[m\n", + "\033[1;35m[¯¸ªø¤ê]:\033[37mÀH®Éª`·N¤pÂûªº¥Í©R¼ÆÈò¡I\033[m\n", + "\033[1;35m[¯¸ªø¤ê]:\033[37m§Ö§Ö¼Ö¼Öªº¤pÂû¤~¬O©¯ºÖªº¤pÂû.....\033[m\n" + }; + outs(hint[rand() % 3]); + } + else if (mode == 1) /* Áý¹ */ + { + sprintf(inbuf2, "%-4d/%4d", d.food, d.cookie); + sprintf(inbuf3, "%-4d/%4d", d.pill, d.medicine); + sprintf(inbuf4, "%-4d/%4d", d.burger, d.ginseng); + sprintf(inbuf5, "%-4d/%4d", d.paste, d.snowgrass); + prints("\033[1;32m[¹¡þ¹s] \033[37m%-9s\033[32m [ÁÙ¡þÆF] \033[37m%-9s\033[32m [¸É¡þçx] \033[37m%-9s\033[32m [»I¡þ½¬] \033[37m%-9s\033[m\n", inbuf2, inbuf3, inbuf4, inbuf5); + } + else if (mode == 2) /* ¥´¤u */ + { + prints("\033[1;36m[·R¤ß]\033[37m%-5d\033[36m[´¼¼z]\033[37m%-5d\033[36m[®ð½è]\033[37m%-5d\033[36m[ÃÀ³N]\033[37m%-5d\033[36m[¹D¼w]\033[37m%-5d\033[36m[«i´±]\033[37m%-5d\033[36m[®a¨Æ]\033[37m%-5d\n\033[m", + d.love, d.wisdom, d.character, d.art, d.etchics, d.brave, d.homework); + } + else if (mode == 3) /* צæ */ + { + prints("\033[1;36m[´¼¼z]\033[37m%-5d\033[36m[®ð½è]\033[37m%-5d\033[36m[ÃÀ³N]\033[37m%-5d\033[36m[«i´±]\033[37m%-5d\033[36m[§ðÀ»]\033[37m%-5d\033[36m[¨¾¿m]\033[37m%-5d\033[36m[³t«×]\033[37m%-5d\n\033[m", + d.wisdom, d.character, d.art, d.brave, d.attack, d.resist, d.speed); + } + + /* ¿Ã¹õ¤¤¶¡ (5~18¦C) Åã¥Ü¹Ï */ + + tm *= 10; + + if (menunum) /* itoc.010816: ¦pªG¬O¶i¥X¥D¿ï³æ¡A¤£»Ýn«Ã¸¤¤¶¡ªº¹Ï */ + { + /* ¶i¥X¥D¿ï³æ¤£«Ã¸¤¤¶¡ªº¹Ï·|¦³¤@Ó¤p bug¡A´N¬O²Ä¤@¦¸¶i¨Ó¥D¿ï³æ¨S¦³¹Ï¡A¤£¹L¥i¥H¬Ù¤U¤j¶q«Ã¸ */ + + move(5, 0); + outs("\033[34m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m"); + + /* ¥Ñ¦~ÄÖ¤ÎÅ髨ӨM©w¤pÂû¤é±`¥Í¬¡°_©~ªº¹Ï */ + + /* Å髪º¨M©w¥i¥H°Ñ¦Ò¤U±¤@ÂIªºµ{¦¡»¡©ú */ + if (d.weight < tm + 30) + pic = 1; /* ½G */ + else if (d.weight < tm + 90) + pic = 2; /* ¤¤µ¥ */ + else + pic = 3; /* D */ + + switch (age) + { + case 0: + case 1: + case 2: + show_basic_pic(pic); /* pic1~3 */ + break; + + case 3: + case 4: + show_basic_pic(pic + 3); /* pic4~6 */ + break; + + case 5: + case 6: + show_basic_pic(pic + 6); /* pic7~9 */ + break; + + case 7: + case 8: + show_basic_pic(pic + 9); /* pic10~12 */ + break; + + case 9: + case 10: + show_basic_pic(pic + 12); /* pic13~15 */ + break; + + case 11: + show_basic_pic(pic + 15); /* pic16~18 */ + break; + } + + move(18, 0); + outs("\033[34m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m"); + } + + /* ¿Ã¹õ¤U¤è (19~b_lines¦C) Åã¥Ü¥Ø«eª¬ºA¡A¨Ã¶¶«KÀˬd¬O§_¦º¤` */ + + move(19, 0); + outs("\033[1;34m¢w\033[37;44m ª¬ ºA \033[0;1;34m¢w\033[m\n"); + + /* itoc.010801: ɥΠage Àˬdª¬ºA¡A¥Ñ°ª¤@¸ôÀˬd¨ì¤¤¡B¥Ñ§C¤@¸ôÀˬd¨ì¤¤ */ + + age = d.shit; /* ÁT«K¶V¤Ö¶V¦n¡A²z·Q age = 0 */ + if (age >= 100) + { + pipdie("\033[1;31m«z¡ã¯ä¦º¤F\033[m ", 1); + return -1; + } + else if (age >= 80) + { + outs("\033[1;35m§Ö¯ä¦º¤F\033[m "); + d.sick += 4; + } + else if (age >= 60) + { + outs("\033[1;33m«Ü¯ä¤F»¡\033[m "); + } + else if (age >= 40) + { + outs("¦³ÂI¯ä¯ä "); + } + else if (age == 0) + { + outs("°®²b¤pÂû "); + } + + age = d.hp * 100 / d.maxhp; /* age = ¦åº¡ªº¤ñ¨Ò % */ + if (age >= 90) + { + outs("\033[1;33m¼µ¼µªº»¡\033[m "); + } + else if (age >= 80) + { + outs("¨{¤l¹¡¹¡ "); + } + else if (age <= 40) + { + outs("\033[1;33m·Q¦YªF¦è\033[m "); + } + else if (age <= 0) + { + pipdie("\033[1;31m¶ã¡ã¾j¦º¤F\033[m ", 1); + return -1; + } + else if (age <= 20) + { + outs("\033[1;35m§Ö¾j©ü¤F\033[m "); + d.sick += 3; + d.happy -= 5; + d.satisfy -= 3; + } + + age = d.tired; /* ¯h³Ò¶V§C¶V¦n¡A²z·Q age = 0 */ + if (age >= 100) + { + pipdie("\033[1;31m£«¡ã²Ö¦º¤F\033[m ", 1); + return -1; + } + else if (age >= 80) + { + outs("\033[1;35m¯uªº«Ü²Ö\033[m "); + d.sick += 5; + } + else if (age >= 60) + { + outs("\033[1;33m¦³ÂI¤p²Ö\033[m "); + } + else if (age <= 10) + { + outs("ºë¯«¬Û·í´Î "); + } + else if (age <= 20) + { + outs("ºë¯««Ü¦n "); + } + + age = d.weight - tm; /* ²z·QÅé« age = 60 §Y d.wight = 60 + 10 * tm */ + /* ª`·N¦¹®É tm ¤w¸g * 10 ¹L¤F */ + if (age >= 130) + { + pipdie("\033[1;31m¶ã¡ãªÎ¦º¤F\033[m ", 1); + return -1; + } + else if (age >= 110) + { + outs("\033[1;35m¤ÓD¤F°Õ\033[m "); + d.sick += 3; + if (d.speed > 2) + d.speed -= 2; + else + d.speed = 0; + } + else if (age >= 90) + { + outs("\033[1;33m¦³ÂI¤pD\033[m "); + } + else if (age <= -10) + { + pipdie("\033[1;31m:~~ ½G¦º¤F\033[m ", 1); + return -1; + } + else if (age <= 10) + { + outs("\033[1;33m¦³ÂI¤p½G\033[m "); + } + else if (age <= 30) + { + outs("\033[1;35m¤Ó½G¤F³á\033[m "); + } + + age = d.sick; /* ¯e¯f¶V§C¶V¦n¡A²z·Q age = 0 */ + if (age >= 100) + { + pipdie("\033[1;31m¯f¦º¤F°Õ :~~\033[m ", 1); + return -1; + } + else if (age >= 75) + { + outs("\033[1;35m¥¿¯f«¤¤\033[m "); + d.sick += 5; + count_tired(1, 15, 1, 100, 1); + } + else if (age >= 50) + { + outs("\033[1;33m¥Í¯f¤F°Õ\033[m "); + count_tired(1, 8, 1, 100, 1); + } + + age = d.happy; /* §Ö¼Ö¶V°ª¶V¦n¡A²z·Q age = 100 */ + if (age >= 90) + { + outs("§Ö¼Ö°Õ.. "); + } + else if (age >= 80) + { + outs("§Ö¼Ö°Õ.. "); + } + else if (age <= 10) + { + outs("\033[1;35m«Ü¤£§Ö¼Ö\033[m "); + } + else if (age <= 20) + { + outs("\033[1;33m¤£¤Ó§Ö¼Ö\033[m "); + } + + age = d.satisfy; /* º¡¨¬¶V°ª¶V¦n¡A²z·Q age = 100 */ + if (age >= 90) + { + outs("º¡¨¬°Õ.. "); + } + else if (age >= 80) + { + outs("º¡¨¬°Õ.. "); + } + else if (age <= 10) + { + outs("\033[1;35m«Ü¤£º¡¨¬\033[m "); + } + else if (age <= 20) + { + outs("\033[1;33m¤£¤Óº¡¨¬\033[m "); + } + + return 0; +} + + + /*-----------------------------------------------------*/ + /* ¿ï³æ¥D¨ç¦¡ */ + /*-----------------------------------------------------*/ + +/* Ãþ¦ü menu.c ªº¥\¯à */ + +static int +pip_do_menu(menunum, menumode, cmdtable) + int menunum; /* þ¤@¶¿ï³æ */ + int menumode; /* þ¤@Ãþµe± */ + struct pipcommands cmdtable[]; /* «ü¥O¶° */ +{ + int ch, key; + struct pipcommands *cmd; + + while (1) + { + /* §PÂ_¬O§_¦º¤`¡A¦º±¼§Y¸õ¦^¤W¤@¼h */ + if (d.death) + return 0; + + /* µe±«Ã¸¡A¨Ã§P©w«á¬O§_¦º¤`¡A¦º±¼§Y¸õ¦^¤W¤@¼h */ + if (pip_refresh_screen(menunum, menumode)) + return 0; + + /* ¦L¥X³Ì«á¤G¦C«ü¥O¦C */ + out_cmd(menuname[menunum][0], menuname[menunum][1]); + + switch (ch = vkey()) + { + case KEY_LEFT: + case 'q': + return 0; + + default: +#if 0 + /* itoc.010815: ´«¤p¼g */ + if (ch >= 'A' && ch <= 'Z') + ch |= 0x20; +#endif + + cmd = cmdtable; + for (; key = cmd->key; cmd++) + { + if (ch == key) + { + cmd->fptr(); + break; /* itoc.010815: °õ¦æ§¹µ{¦¡n«·s«öÁä */ + } + } + break; + } + } + + return 0; +} + + + /*-----------------------------------------------------*/ + /* ¥D¿ï³æ: °ò¥» ³}µó ×¦æ ª±¼Ö ¥´¤u ¯S®í */ + /*-----------------------------------------------------*/ + +int +pip_main_menu() +{ + pip_do_menu(0, 0, pipmainlist); + return 0; +} + + + /*-----------------------------------------------------*/ + /* °ò¥»¿ï³æ: Áý¹ ²M¼ä ¿Ë¿Ë ¥ð®§ */ + /*-----------------------------------------------------*/ + +int +pip_basic_menu() +{ + pip_do_menu(1, 0, pipbasiclist); + return 0; +} + + + /*-----------------------------------------------------*/ + /* °Ó©±¿ï³æ: ¹ª« ¹s¹ ¤j¸É¤Y ª±¨ã ®Ñ¥» */ + /*-----------------------------------------------------*/ + +int +pip_store_menu() +{ + pip_do_menu(2, 1, pipstorelist); + return 0; +} + + + /*-----------------------------------------------------*/ + /* צæ¿ï³æ: ©À®Ñ ½mªZ צæ */ + /*-----------------------------------------------------*/ + +int +pip_practice_menu() +{ + pip_do_menu(3, 3, pippracticelist); + return 0; +} + + + /*-----------------------------------------------------*/ + /* ª±¼Ö¿ï³æ: ´²¨B ®È¹C ¹B°Ê ¬ù·| ²q®± */ + /*-----------------------------------------------------*/ + +int +pip_play_menu() +{ + pip_do_menu(4, 0, pipplaylist); + return 0; +} + + + /*-----------------------------------------------------*/ + /* ¥´¤u¿ï³æ: ®a¨Æ W¤u ®a±Ð ¦aÅu */ + /*-----------------------------------------------------*/ + +int +pip_job_menu() +{ + pip_do_menu(5, 2, pipjoblist); + return 0; +} + + + /*-----------------------------------------------------*/ + /* ¯S®í¿ï³æ: ¬Ý¯f ´îªÎ ¾Ô°« «ô³X ´Â¨£ */ + /*-----------------------------------------------------*/ + +int +pip_special_menu() +{ + pip_do_menu(6, 0, pipspeciallist); + return 0; +} + + + /*-----------------------------------------------------*/ + /* ¨t²Î¿ï³æ: Ó¤H¸ê®Æ ¤pÂû©ñ¥Í ¯S§OªA°È */ + /*-----------------------------------------------------*/ + +int +pip_system_menu() +{ + pip_do_menu(7, 0, pipsystemlist); + return; +} +#endif /* HAVE_GAME */ diff --git a/pip/pip_pk.c b/pip/pip_pk.c new file mode 100644 index 0000000..f177899 --- /dev/null +++ b/pip/pip_pk.c @@ -0,0 +1,801 @@ +/* ----------------------------------------------------- */ +/* pip_pk.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/* ----------------------------------------------------- */ +/* target : PK ¹ï¾Ô¿ï³æ */ +/* create : 02/02/17 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/* ----------------------------------------------------- */ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#include "pip.h" + + +#if 0 + + 0. ª±ªk¬O¶i¤J¹q¤lÂû¹CÀ¸¥H«á¿ï PK¡AµM«á¤@¤H¿ï 1)»W¶Õ«Ýµo¡A + ¥t¤@¤H¿ï 2)¤U¬D¾Ô®Ñ¿é¤J«eªÌªº ID §Y¥i¶}©l¹ï¾Ô¡C + + 1. PK ªº®ÉԥΪºÈ¬O ptmp-> ¸Ì±ªº¡A©Ò¥H¹ï¾Ô§¹ d. ¨Ã¤£·|§ïÅÜ¡C + 2. ¬°¼W¥[½ì¨ý¡A¹ï¾Ôªº§ðÀ»¤è¦¡¸û pip_fight.c ¬°¦h¼Ë¡C + 3. ¹ï¾Ô®É¤£¥i¦Y¸É«~¡C (¥i§ï) + 4. ¹ï¾Ô®É skillXYZ ¨S¦³¯S§O®Ä¥Î¡C (¥i§ï) + + 5. pip_pk_skill() ¤]¬O°½Ãi°µªk¡A·Q§ïªº¤H¦A¦Û¤v±q pip_fight.c §Û¹L¨Ó¡C + +#endif + +/*-------------------------------------------------------*/ +/* pip PK cache */ +/*-------------------------------------------------------*/ + + +static PCACHE *pshm; +static PTMP *cp; /* §Úªº¤pÂû */ +static PTMP *ep; /* ¹ï¤âªº¤pÂû */ + + +static void +pip_pkshm_init() +{ + pshm = shm_new(PIPSHM_KEY, sizeof(PCACHE)); +} + + +static int +pip_ptmp_new(pp) + PTMP *pp; +{ + PTMP *pentp, *ptail; + + /* --------------------------------------------------- */ + /* semaphore : critical section */ + /* --------------------------------------------------- */ + +#ifdef HAVE_SEM + sem_lock(BSEM_ENTER); +#endif + + pentp = pshm->pslot; + ptail = pentp + MAX_PIPPK_USER; + + do + { + if (!pentp->inuse) /* §ä¨ì¤@ӪŦì¤l¡Acp-> «ü¦V */ + { + memcpy(pentp, pp, sizeof(PTMP)); + cp = pentp; + +#ifdef HAVE_SEM + sem_lock(BSEM_LEAVE); +#endif + + return 1; + } + } while (++pentp < ptail); + + /* Thor:§i¶Duser¦³¤Hµn¥ý¤@¨B¤F */ + +#ifdef HAVE_SEM + sem_lock(BSEM_LEAVE); +#endif + + return 0; +} + + +static int +pip_ptmp_setup() +{ + PTMP ptmp; + + memset(&ptmp, 0, sizeof(PTMP)); + + /* °ò¥»ÄÝ©Ê */ + strcpy(ptmp.name, d.name); + strcpy(ptmp.userid, cuser.userid); + + ptmp.sex = d.sex; + ptmp.level = d.level; + + /* ¦å¸Éº¡ */ + ptmp.hp = d.maxhp; + ptmp.mp = d.maxmp; + ptmp.vp = d.maxvp; + ptmp.sp = d.maxsp; + ptmp.maxhp = d.maxhp; + ptmp.maxmp = d.maxmp; + ptmp.maxvp = d.maxvp; + ptmp.maxsp = d.maxsp; + + /* ¦UºØ§ðÀ»¯à¤O */ + ptmp.combat = d.attack + (d.resist >> 2); /* ª«²z¨¬q: ¨M©w¡u¦×·i¡B¨¾¿m¡vªº±j«× */ + ptmp.magic = d.immune + (d.mskill >> 2); /* Å]ªk³y¸Ú: ¨M©w¡uªk³N-¦U¨t¡vªº±j«× */ + ptmp.speed = d.speed + (d.hskill >> 2); /* ±Ó±¶§Þ¥©: ¨M©w¡u§Þ¯à-Å@¨¡B§Þ¯à-»´¥\¡B§Þ¯à-¼Cªk¡vªº±j«× */ + ptmp.spirit = d.brave + (d.etchics >> 2); /* ¤º¤O±j«×: ¨M©w¡u§Þ¯à-¤ßªk¡B§Þ¯à-®±ªk¡B§Þ¯à-¤Mªk¡vªº±j«× */ + ptmp.charm = d.charm + (d.art >> 2); /* °Ê·P¾y¤O: ¨M©w¡u¾y´b¡B¥l³ê¡vªº±j«× */ + ptmp.oral = d.speech + (d.manners >> 2); /* ¤fYÄaªe: ¨M©w¡u»¡ªA¡Bº´°Ê¡vªº±j«× */ + ptmp.cook = d.cook + (d.homework >> 2); /* ¬ü¨ý²i½Õ: ¨M©w¡u§Þ¯à-·t¾¹¡Bªk³N-ªvÀø¡v */ + + if (!pip_ptmp_new(&ptmp)) + { + vmsg("©êºp¡APK ³õ«Èº¡¤F³á"); + return 0; + } + + return 1; +} + + +static void +pip_ptmp_free() +{ + if (!cp || !cp->inuse) + return; + +#ifdef HAVE_SEM + sem_lock(BSEM_ENTER); +#endif + + cp->inuse = 0; + +#ifdef HAVE_SEM + sem_lock(BSEM_LEAVE); +#endif +} + + +static PTMP * +pip_ptmp_get(userid, inuse) + char *userid; + int inuse; /* 1:§ä¡u»W¶Õ«Ýµo¡vªº¤H¨Ó¬D¾Ô 2:§ä¡u¤U¬D¾Ô®Ñ¡vªº¬D¾ÔªÌ¦^À³ */ +{ + PTMP *pentp, *ptail; + + pentp = pshm->pslot; + ptail = pentp + MAX_PIPPK_USER; + do + { + if (pentp->inuse == inuse && !str_cmp(pentp->userid, userid)) + return pentp; + } while (++pentp < ptail); + + return NULL; +} + + +static void +pip_ptmp_show() +{ + int max; + PTMP *pentp, *ptail; + + clrfromto(7, 16); + move(10, 5); + + max = 0; + pentp = pshm->pslot; + ptail = pentp + MAX_PIPPK_USER; + do + { + if (pentp->inuse) + { + max++; + prints("\033[1;3%dm%-20s\033[m", 2 + pentp->inuse, pentp->userid); + + if (max % 4 == 0) + move(10 + max % 4, 5); + } + } while (++pentp < ptail); + + move(8, 5); + prints("\033[1;31m¾Ô°«¤¤ \033[33m»W¶Õ«Ýµo \033[34m¬D¾ÔªÌµ¥«Ý¦^À³\033[m" + " ¥Ø«e³õ¤l¸Ì¦³ \033[1;36m%d/%d\033[m °¦Âû", max, MAX_PIPPK_USER); +} + + +/*-------------------------------------------------------*/ +/* ¹ï¾Ô¥D¨ç¦¡ */ +/*-------------------------------------------------------*/ + + + /*-----------------------------------------------------*/ + /* ½ü¬y±±¨î */ + /*-----------------------------------------------------*/ + + +static void +pip_pk_turn() /* ´«¹ï¤è */ +{ + cp->done = 1; + ep->done = 0; +} + + + /*-----------------------------------------------------*/ + /* µe±Åã¥Ü */ + /*-----------------------------------------------------*/ + + +static void +pip_pk_showfoot() +{ + out_cmd("", COLOR1 " ¾Ô°«©R¥O " COLOR2 " [1]¦×·i [2]§Þ¯à [3]¾y´b [4]¥l³ê [5]»¡ªA [6]º´°Ê [Q]»{¿é \033[m"); +} + + +static void +pip_pk_showing() +{ + int pic; + char inbuf1[20], inbuf2[20], inbuf3[20], inbuf4[20]; + + clear(); + move(0, 0); + + prints("\033[1;41m " BBSNAME PIPNAME " ¡ã\033[32m%s\033[37m%-13s \033[m\n", + cp->sex == 1 ? "¡ñ" : (cp->sex == 2 ? "¡ð" : "¡H"), cp->name); + + /* ¿Ã¹õ¤W¤è¨q¥X§Úªº¤pÂû¸ê®Æ */ + + sprintf(inbuf1, "%d%s/%d%s", cp->hp > 1000 ? cp->hp / 1000 : cp->hp, + cp->hp > 1000 ? "K" : "", cp->maxhp > 1000 ? cp->maxhp / 1000 : cp->maxhp, + cp->maxhp > 1000 ? "K" : ""); + sprintf(inbuf2, "%d%s/%d%s", cp->mp > 1000 ? cp->mp / 1000 : cp->mp, + cp->mp > 1000 ? "K" : "", cp->maxmp > 1000 ? cp->maxmp / 1000 : cp->maxmp, + cp->maxmp > 1000 ? "K" : ""); + sprintf(inbuf3, "%d%s/%d%s", cp->vp > 1000 ? cp->vp / 1000 : cp->vp, + cp->vp > 1000 ? "K" : "", cp->maxvp > 1000 ? cp->maxvp / 1000 : cp->maxvp, + cp->maxvp > 1000 ? "K" : ""); + sprintf(inbuf4, "%d%s/%d%s", cp->sp > 1000 ? cp->sp / 1000 : cp->sp, + cp->sp > 1000 ? "K" : "", cp->maxsp > 1000 ? cp->maxsp / 1000 : cp->maxsp, + cp->maxsp > 1000 ? "K" : ""); + + outs("\033[1;31m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m\n"); + prints("\033[1;31m¢x\033[33m¥Í ©R:\033[37m%-12s\033[33mªk ¤O:\033[37m%-12s\033[33m²¾°Ê¤O:\033[37m%-12s\033[33m¤º ¤O:\033[37m%-12s\033[31m¢x\033[m\n", inbuf1, inbuf2, inbuf3, inbuf4); + prints("\033[1;31m¢x\033[33m§ð À»:\033[37m%-12d\033[33mÅ] ªk:\033[37m%-12d\033[33m±Ó ±¶:\033[37m%-12d\033[33mªZ ³N:\033[37m%-12d\033[31m¢x\033[m\n", cp->combat, cp->magic, cp->speed, cp->spirit); + prints("\033[1;31m¢x\033[33m¾y ¤O:\033[37m%-12d\033[33m¤f ¤~:\033[37m%-12d\033[33m²i ½Õ:\033[37m%-12d\033[33mµ¥ ¯Å:\033[37m%-12d\033[31m¢x\033[m\n", cp->charm, cp->oral, cp->cook, cp->level); + outs("\033[1;31m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m"); + + /* ¿Ã¹õ¤¤¶¡ 7~16 ¦C ¨q¥X©Çª«ªº¹ÏÀÉ */ + pic = 101 + 100 * (rand() % 5) + rand() % 3; /* 101~501 102~502 103~503 ¤Q¤¿ï¤@ */ + show_badman_pic(pic); + + /* ¿Ã¹õ¤U¤è¨q¥X¹ï¤èªº¤pÂû¸ê®Æ */ + + sprintf(inbuf1, "%d%s/%d%s", ep->hp > 1000 ? ep->hp / 1000 : ep->hp, + ep->hp > 1000 ? "K" : "", ep->maxhp > 1000 ? ep->maxhp / 1000 : ep->maxhp, + ep->maxhp > 1000 ? "K" : ""); + sprintf(inbuf2, "%d%s/%d%s", ep->mp > 1000 ? ep->mp / 1000 : ep->mp, + ep->mp > 1000 ? "K" : "", ep->maxmp > 1000 ? ep->maxmp / 1000 : ep->maxmp, + ep->maxmp > 1000 ? "K" : ""); + sprintf(inbuf3, "%d%s/%d%s", ep->vp > 1000 ? ep->vp / 1000 : ep->vp, + ep->vp > 1000 ? "K" : "", ep->maxvp > 1000 ? ep->maxvp / 1000 : ep->maxvp, + ep->maxvp > 1000 ? "K" : ""); + sprintf(inbuf4, "%d%s/%d%s", ep->sp > 1000 ? ep->sp / 1000 : ep->sp, + ep->sp > 1000 ? "K" : "", ep->maxsp > 1000 ? ep->maxsp / 1000 : ep->maxsp, + ep->maxsp > 1000 ? "K" : ""); + + move(18, 0); + outs("\033[1;34m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m\n"); + prints("\033[1;34m¢x\033[32m©m ¦W:\033[37m%-12s\033[32m¢× ¢Ò:\033[37m%-12s\033[32m©Ê §O:\033[37m%-12s\033[32mµ¥ ¯Å:\033[37m%-12d\033[34m¢x\033[m\n", ep->name, ep->userid, ep->sex == 1 ? "¡ñ" : (ep->sex == 2 ? "¡ð" : "¡H"), ep->level); + prints("\033[1;34m¢x\033[32m¥Í ©R:\033[37m%-12s\033[32mªk ¤O:\033[37m%-12s\033[32m²¾°Ê¤O:\033[37m%-12s\033[32m¤º ¤O:\033[37m%-12s\033[34m¢x\033[m\n", inbuf1, inbuf2, inbuf3, inbuf4); + outs("\033[1;34m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m\n"); + + pip_pk_showfoot(); +} + + +static void +pip_pk_ending() +{ + clrfromto(7, 16); + move(8, 0); + + if (cp->hp > 0) + { + outs(" \033[1;31m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m\n"); + prints(" \033[1;31m¢x \033[37mªZ³N¤j·|ªº¤pÂû\033[33m%-13s \033[31m¢x\033[m\n", cp->name); + prints(" \033[1;31m¢x \033[37m¥´±Ñ¤F±j«lªº¹ï¤â\033[32m%-13s \033[31m¢x\033[m\n", ep->name); + outs(" \033[1;31m¢x \033[37m«i´±©M¸gÅç³£¤W¤É¤F¤£¤Ö \033[31m¢x\033[m\n"); + outs(" \033[1;31m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m"); + vmsg("±z¥´±Ñ¤F¤@Ó±jµwªº³Ã¥ë"); + d.exp += ep->level; + } + else + { + outs(" \033[1;31m¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{\033[m\n"); + prints(" \033[1;31m¢x \033[37mªZ³N¤j·|ªº¤pÂû\033[33m%-13s \033[31m¢x\033[m\n", cp->name); + prints(" \033[1;31m¢x \033[37m³Q\033[32m%-13s\033[37m¹ï¤â¥´±o¸¨ªá¬y¤ô \033[31m¢x\033[m\n", ep->name); + outs(" \033[1;31m¢x \033[37m¨M©w¦^®a¦n¦n¦AÁë½m \033[31m¢x\033[m\n"); + outs(" \033[1;31m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m"); + vmsg("³Q¥´±Ñªº±z¤ß¤¤¬Û·í¤£¬O¨ý¹D"); + d.exp -= cp->level; + } +} + + + /*-----------------------------------------------------*/ + /* ¦æ°Ê¨ç¦¡ */ + /*-----------------------------------------------------*/ + + +static void +pip_pk_combat() /* ¦×·i */ +{ + int injure; + + injure = cp->combat - (ep->combat >> 2); + if (injure > 0) + { + ep->hp -= injure; + show_fight_pic(1); + vmsg("±z³y¦¨¤F¹ï¤èªº¶Ë®`"); + } + else + { + show_fight_pic(2); + vmsg("±zªº§ðÀ»¦b¹ï¤è²´¸Ì²ª½¬O·kÄo"); + } + pip_pk_turn(); +} + + +static void +pip_pk_skill() /* §Þ¯à: ªZ¥\/Å]ªk */ +{ + /* itoc.020217: Ãi±o¼g¹³ pip_fight.c ¸Ì±¨ººØªº¤F¡A¦³¿³½ìªº¤H¦Û¤v§ÛµÛ§ï :p */ + + /* §Þ¯à¤£¦©ÂI¡A¦ý®ÄªG¤ñ¸û®t(¥u¦³¨ä¥Lªº¹ï¥b) */ + + int ch, class; + int injure[5] = {125, 200, 300, 450, 750}; + + out_cmd(COLOR1 " ªZ¥\\¿ï³æ " COLOR2 " [1]Å@¨ [2]»´¥\\ [3]¤ßªk [4]®±ªk [5]¼Cªk [6]¤Mªk [7]·t¾¹ [Q]©ñ±ó \033[m", + COLOR1 " ªk³N¿ï³æ " COLOR2 " [A]ªvÀø [B]¹p¨t [C]¦B¨t [D]ª¢¨t [E]¤g¨t [F]·¨t [G]¯S®í [Q]©ñ±ó \033[m"); + + for (;;) + { + ch = vkey(); + + if (ch == 'q') + { + pip_pk_showfoot(); + return; + } + + else if (ch == '1') /* Å@¨ */ + { + class = rand() % 10; + if (class == 0) /* 10% ªº¾÷²v¤Ï¼u§ðÀ»¡A¥i¦A«×§ðÀ» */ + { + ep->hp -= cp->speed >> 3; + vmsg("¹ï¤âªº§ðÀ»¤Ï¼u¦^¥Lªº¨¤W"); + } + else if (class <= 2) /* 20% ªº¾÷²v¨Ï¹ï¤èª«²z§ðÀ»¥Ã»·°§C¡A¥i¦A«×§ðÀ» */ + { + ep->combat = ep->combat * 4 / 5; + vmsg("¹ï¤èªº¤â§á¨ì¤F¡A¬Ý¨Óµu®É¶¡¤º¤£·|«ì´_"); + } + else /* 70% ªº¾÷²v¤°»ò³£¨S°µ */ + { + vmsg("±z±Ä¨ú¨¾¿m±¹¬I"); + break; + } + pip_pk_showfoot(); + return; + } + + else if (ch == '2') /* »´¥\ */ + { + class = cp->speed >> 9; + if (class > 4) + class = 4; + + cp->vp += injure[class]; /* ¸É vp ¤]ɥΠinjure[] */ + if (cp->vp > cp->maxvp) + cp->vp = cp->maxvp; + + vmsg("ºë¯«¹¡º¡¡A·Ç³Æ¦A¾Ô"); + break; + } + + else if (ch == '3') /* ¤ßªk */ + { + class = cp->spirit >> 9; + if (class > 4) + class = 4; + + cp->sp += injure[class]; /* ¸É sp ¤]ɥΠinjure[] */ + if (cp->sp > cp->maxsp) + cp->sp = cp->maxsp; + + vmsg("¬¡¤O¥R¨K¡A·Ç³Æ¦A¾Ô"); + break; + } + + else if (ch == '4') /* ®±ªk */ + { + class = cp->spirit >> 9; + if (class > 4) + class = 4; + + ep->hp -= injure[class] * (75 + rand() % 50) / 100; + vmsg("¥þ¨ºë¤O¶°¤¤©ó´x¤W¡A¾Ä¤O¤@À»"); + break; + } + + else if (ch == '5') /* ¼Cªk */ + { + class = cp->speed >> 9; + if (class > 4) + class = 4; + + ep->hp -= injure[class] * (50 + rand() % 100) / 100; + vmsg("§Ö¼C±Ù¶Ã³Â¡A¯«¼CÂô¦¿´ò"); + break; + } + + else if (ch == '6') /* ¤Mªk */ + { + class = cp->spirit >> 9; + if (class > 4) + class = 4; + + ep->hp -= injure[class] * (30 + rand() % 140) / 100; + vmsg("¥þ¨ºë¤O¶°¤¤©ó´x¤W¡A¾Ä¤O¤@À»"); + break; + } + + else if (ch == '7') /* ·t¾¹ */ + { + class = cp->cook >> 9; + if (class > 4) + class = 4; + + ep->hp -= injure[class] * (80 + rand() % 40) / 100; + vmsg("±zªºµæÀa¤¤¤U¤F¬rÃÄ¡A¹ï¤â¤£ª`·N´N¦Y¤F¤U¥h"); + break; + } + + else if (ch == 'a') /* ªvÀø */ + { + class = cp->cook >> 10; /* ¸É hp ªºªùÂe¤ñ¸û°ª */ + if (class > 4) + class = 4; + + cp->hp += injure[class]; /* ¸É hp ¤]ɥΠinjure[] */ + if (cp->hp > cp->maxhp) + cp->hp = cp->maxhp; + + vmsg("¥R¹q¥H«á¡A¦A«×¥Xµo"); + break; + } + + else if (ch >= 'b' && ch <= 'f') /* ¦U¨tªk³N */ + { + char buf[64]; + char name[5][3] = {"¹p", "¦B", "ª¢", "¤g", "·"}; + + class = cp->magic >> 9; + if (class > 4) + class = 4; + + ep->hp -= injure[class] * (50 + rand() % 100) / 100; + sprintf(buf, "±z¬I®i¤F%s¨tªk³N¡A«Â¤O¤Q¨¬", name[ch - 'b']); + vmsg(buf); + break; + } + + else if (ch == 'g') /* ¯S®í */ + { + class = cp->magic >> 9; + if (class > 4) + class = 4; + + cp->mp += injure[class]; /* ¸É mp ¤]ɥΠinjure[] */ + if (cp->mp > cp->maxmp) + cp->mp = cp->maxmp; + + vmsg("¯à¶q¥R¶ñ¡AÅ]¤O¦A²{"); + break; + } + } + + pip_pk_turn(); +} + + +static void +pip_pk_charm() /* ¾y´b: ¯Ó hp */ +{ + int class; + char buf[80]; + char name[5][9] = {"¤Z¤Ò«U¤l", "¦â±¡¨g", "¤p°", "Às¯«", "¯¸ªø"}; + int injure[5] = {250, 400, 600, 900, 1500}; + int needhp[5] = {350, 600, 900, 1500, 3200}; + + class = cp->charm >> 8; /* ¬Û¹ï©ó¥H¤U¤TªÌ¡A¨ä©Ò»ÝªùÂe¤ñ¸û§C´N¥i¥H¬I®i±j¤j¾y´b³N¡A¦ý¯Óªº¬O hp */ + if (class > 4) + class = 4; + + if (cp->hp >= needhp[class]) + { + cp->hp -= needhp[class]; + ep->hp -= injure[class] * (75 + rand() % 50) / 100; + sprintf(buf, "¤@¸s%s¦b±zªº«ü¨Ï¤§¤U¡A«÷©R§ðÀ»¹ï¤è", name[class]); + vmsg(buf); + pip_pk_turn(); + } + else + { + vmsg("±z¥þ¨³£¬O¶Ë¤f¡AÁÙ·Q¾y´b½Ö"); + pip_pk_showfoot(); + } +} + + +static void +pip_pk_summon() /* ¥l³ê: ¯Ó mp */ +{ + int class; + char buf[80]; + char name[5][9] = {"¥vµÜ©i", "ªêÀY¸Á", "²rªê", "»·¥j¥¨Às", "¦º¯«¼»¥¹"}; + int injure[5] = {250, 400, 600, 900, 1500}; + int needmp[5] = {350, 600, 900, 1500, 3200}; + + class = cp->charm >> 9; + if (class > 4) + class = 4; + + if (cp->mp >= needmp[class]) + { + cp->mp -= needmp[class]; + ep->hp -= injure[class] * (75 + rand() % 50) / 100; + sprintf(buf, "±z¥l³ê¥X%s¡A««¦aµ¹¤F¹ï¤è¤@À»", name[class]); + vmsg(buf); + pip_pk_turn(); + } + else + { + vmsg("±z·P¨ì¥þ¨¯h¾Î¡A¤°»ò¤]¥l³ê¤£¥X¨Ó"); + pip_pk_showfoot(); + } +} + + +static void +pip_pk_convince() /* »¡ªA: ¯Ó vp */ +{ + int class; + char buf[80]; + char name[5][9] = {"±¨ã©Ç¤H", "¾uÅ\\ÀY©Ç", "¬µ³J¶W¤H", "ªF®üÀs¤ý", "»ô¤Ñ¤j¸t"}; + int injure[5] = {250, 400, 600, 900, 1500}; + int needvp[5] = {350, 600, 900, 1500, 3200}; + + class = cp->oral >> 9; + if (class > 4) + class = 4; + + if (cp->vp >= needvp[class]) + { + cp->vp -= needvp[class]; + ep->hp -= injure[class] * (75 + rand() % 50) / 100; + sprintf(buf, "±z¦¨¥\\¦a»¡ªA%s¨Ó§U±z¤@Áu¤§¤O", name[class]); + vmsg(buf); + pip_pk_turn(); + } + else + { + vmsg("»·¤è¶Ç¨Ó¤@°}Ánµ¡G·Q»¡ªA§Ú¡A¦Aµ¥¤@¦Ê¦~§a"); + pip_pk_showfoot(); + } +} + + +static void +pip_pk_incite() /* º´°Ê: ¯Ó sp */ +{ + int class; + char buf[80]; + char name[5][9] = {"¥¨ÃÇ©Ç", "¥¬C¾|", "¦aº»¤ü", "¼Q¤õÀs", "¿K¤Ñ¨Ï"}; + int injure[5] = {250, 400, 600, 900, 1500}; + int needsp[5] = {350, 600, 900, 1500, 3200}; + + class = cp->oral >> 9; + if (class > 4) + class = 4; + + if (cp->sp >= needsp[class]) + { + cp->sp -= needsp[class]; + ep->hp -= injure[class] * (40 + rand() % 120) / 100; /* Åܲ§©Ê¸û«e±¤TªÌ¬°°ª */ + sprintf(buf, "±z«i´±¦aº´°Ê%s¾ãÓ±Ú¸s¨Ó¹ï¥I¼Ä¤H", name[class]); + vmsg(buf); + pip_pk_turn(); + } + else + { + vmsg("²³¤H¤£¬°©Ò°Ê¡A±zªºpµe¥¢±Ñ¤F"); + pip_pk_showfoot(); + } +} + + +static void +pip_pk_man() /* ½ü¨ì§Ú¤U«ü¥O */ +{ + /* ¨q¥X¾Ô°«¥Dµe± */ + pip_pk_showing(); + + while (!cp->done) + { + switch (vkey()) + { + case '1': /* ¦×·i */ + pip_pk_combat(); + break; + + case '2': /* §Þ¯à: ªZ¥\/Å]ªk */ + pip_pk_skill(); + break; + + case '3': /* ¾y´b */ + pip_pk_charm(); + break; + + case '4': /* ¥l³ê */ + pip_pk_summon(); + break; + + case '5': /* »¡ªA */ + pip_pk_convince(); + break; + + case '6': /* º´°Ê */ + pip_pk_incite(); + break; + + case 'q': /* »{¿é */ + cp->hp = 0; + pip_pk_turn(); + break; + } + } +} + + +static void +pip_pk_wait() /* µ¥«Ý¹ï¤è¤U«ü¥O */ +{ + int fd; + struct timeval tv = {1, 100}; + + /* ¨q¥X¾Ô°«¥Dµe± */ + pip_pk_showing(); + + outz("µ¥«Ý¹ï¤èªº§ðÀ» Q)»{¿é"); + refresh(); + + while (!ep->done) + { + fd = 1; + if (select(1, (fd_set *) &fd, NULL, NULL, &tv) > 0) + { + if (vkey() == 'q') + { + cp->done = 1; /* ¤G¤H³£±j¢µ²§ô¦æ°Ê */ + ep->done = 1; + cp->hp = 0; /* ¦³¨ÆÂ÷¶}ºâ¿é */ + break; + } + } + } +} + + +/*-------------------------------------------------------*/ +/* ¹ï¾Ô¥D¿ï³æ */ +/*-------------------------------------------------------*/ + + +int +pip_pk_menu() +{ + int ch; + char userid[IDLEN + 1]; + struct timeval tv = {1, 100}; + + /* itoc.020327: ¦³ÓÆZ¤jªº°ÝÃD¬O¡A¦pªG¹ï¾Ô¨ì¤@¥b¡A¨ä¤¤¤@¤HÂ_½u¤F¡A + ¥t¥~¤@¤H·|¶i¤J°j°é¡A¥u¯à«ö Q Â÷¶} */ + + if (d.hp <= 0) + return XEASY; + + pip_pkshm_init(); + + pip_ptmp_show(); + + ch = ians(b_lines, 0, "¡· ¤pÂû¹ï¾Ô 1)»W¶Õ«Ýµo 2)¤U¬D¾Ô®Ñ [Q]Â÷¶} "); + if (ch == '1') + { + /* ³]©w cp-> */ + if (!pip_ptmp_setup()) + return XEASY; + + cp->inuse = 1; + + outz("µ¥Ô¬D¾Ô¤¤ Q)Â÷¶}"); + refresh(); + do + { + ch = 1; + if (select(1, (fd_set *) &ch, NULL, NULL, &tv) > 0) + { + if (vkey() == 'q') + { + pip_ptmp_free(); + return XEASY; + } + } + } while (!*cp->mateid); + + if (!(ep = pip_ptmp_get(cp->mateid, 2))) + { + pip_ptmp_free(); + return XEASY; + } + cp->done = 0; /* ³Q¬D¾ÔªÌ¥ý¦æ°Ê¡A¬D¾ÔªÌ´N·|³qª¾¥L */ + cp->inuse = -1; /* ¨â¤è³£¶i¤J¾Ô°« */ + ep->inuse = -1; + } + else if (ch == '2') + { + /* ¨M©w PK ¹ï¾Ô¹ï¶H ep-> */ + if (!vget(b_lines, 0, msg_uid, userid, IDLEN + 1, DOECHO) || + !str_cmp(cuser.userid, userid) || + !(ep = pip_ptmp_get(userid, 1))) + { + return XEASY; + } + + /* ³]©w cp-> */ + if (!pip_ptmp_setup()) + return XEASY; + + strcpy(cp->mateid, userid); + strcpy(ep->mateid, cuser.userid); + cp->done = 1; /* ¬D¾ÔªÌ«á¦æ°Ê¡A´N·|¥D°Ê³qª¾³Q¬D¾ÔªÌ */ + cp->inuse = 2; + } + else + { + return XEASY; + } + + ch = d.tired; + + for (;;) /* Âù¤è§ð¨¾ */ + { + pip_pk_man(); + if (ep->hp <= 0 || cp->hp <= 0) + break; + + pip_pk_wait(); + if (cp->hp <= 0 || ep->hp <= 0) + break; + } + + /* µ²ªG§PÂ_ */ + pip_pk_ending(); + + pip_ptmp_free(); + + d.tired = ch; /* ¥H§K PK ¥´¤Ó¤[¡APK µ²§ô«á¨Ó¦] tired ¹L°ª¦º±¼¤F */ + return 0; +} +#endif /* HAVE_GAME */ diff --git a/pip/pip_play.c b/pip/pip_play.c new file mode 100644 index 0000000..4d73d59 --- /dev/null +++ b/pip/pip_play.c @@ -0,0 +1,352 @@ +/*-------------------------------------------------------*/ +/* pip_play.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ª±¼Ö¿ï³æ */ +/* create : / / */ +/* update : 01/08/15 */ +/* author : dsyan.bbs@forever.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#include "pip.h" + + +/*-------------------------------------------------------*/ +/* ª±¼Ö¿ï³æ:´²¨B ®È¹C ¹B°Ê ¬ù·| ²q®± */ +/*-------------------------------------------------------*/ + + +int +pip_play_stroll() /* ´²¨B */ +{ + /* ¹w³]§ïÅÜÈ¡AY¦³°¸µo¨Æ¥ó¡A¥t¥~¥[¦¨©ó¤U */ + count_tired(3, 3, 1, 100, 0); /* ¼W¥[¯h³Ò */ + d.happy += rand() % 3 + 3; + d.satisfy += rand() % 2 + 1; + d.shit += rand() % 3 + 2; + d.hp -= rand() % 3 + 2; + + switch (rand() % 10) + { + case 0: + d.happy += 6; + d.satisfy += 6; + show_play_pic(1); + vmsg("¹J¨ìªB¤ÍÅo ¯u¦n.... ^_^"); + break; + + case 1: + d.happy += 4; + d.satisfy += 8; + show_play_pic(2); + vmsg(d.sex == 1 ? "¬Ý¨ìº}«Gªº¤k¥ÍÅo ¯u¦n.... ^_^" : "¬Ý¨ì^«Tªº¨k¥ÍÅo ¯u¦n.... ^_^"); + break; + + case 2: + d.money += 100; + d.happy += 4; + show_play_pic(3); + vmsg("¾ß¨ì¤F100¤¸¤F..CCC...."); + break; + + case 3: + d.happy -= 10; + d.satisfy -= 3; + show_play_pic(4); + if (d.money > 50) + { + d.money -= 50; + vmsg("±¼¤F50¤¸¤F..¶ã¶ã¶ã...."); + } + else + { + d.money = 0; + vmsg("¿ú±¼¥ú¥ú¤F..¶ã¶ã¶ã...."); + } + break; + + case 4: + d.happy += 3; + show_play_pic(5); + if (d.money > 50) + { + d.money -= 50; + vmsg("¥Î¤F50¤¸¤F..¤£¥i¥H½|§Ú³á...."); + } + else + { + d.money = 0; + vmsg("¿ú³Q§Ú°½¥Î¥ú¥ú¤F..:p"); + } + break; + + case 5: + d.toy++; + show_play_pic(6); + vmsg("¦n´Î³á¡A¾ß¨ìª±¨ã¤F»¡....."); + break; + + case 6: + d.cookie++; + show_play_pic(7); + vmsg("¦n´Î³á¡A¾ß¨ì»æ°®¤F»¡....."); + break; + + case 7: + d.satisfy -= 5; + d.shit += 5; + show_play_pic(9); + vmsg("¯u¬OË·° ¥i¥H¥h¶R·R°ê¼ú¨é"); + break; + + default: + show_play_pic(8); + vmsg("¨S¦³¯S§Oªº¨Æµo¥Í°Õ....."); + break; + } + + if (d.happy > 100) + d.happy = 100; + if (d.satisfy > 100) + d.satisfy = 100; + + return 0; +} + + +int +pip_play_sport() /* ¹B°Ê */ +{ + count_tired(3, 8, 1, 100, 1); + d.speed += 2 + rand() % 3; + d.weight -= rand() % 3 + 2; + d.shit += rand() % 5 + 10; + d.hp -= rand() % 2 + 8; + d.satisfy += rand() % 2 + 3; + if (d.satisfy > 100) + d.satisfy = 100; + + show_play_pic(10); + vmsg("¹B°Ê¦n³B¦h¦h°Õ..."); + + return 0; +} + + +int +pip_play_date() /* ¬ù·| */ +{ + if (d.money < 150) + { + vmsg("¿ú¤£°÷¦h°Õ¡I¬ù·|Á`±oªáÂI¿ú¿ú"); + } + else + { + count_tired(3, 6, 1, 100, 1); + d.money -= 150; + d.shit += rand() % 3 + 5; + d.hp -= rand() % 4 + 8; + d.character += rand() % 3 + 1; + d.happy += rand() % 5 + 12; + d.satisfy += rand() % 5 + 7; + + if (d.happy > 100) + d.happy = 100; + if (d.satisfy > 100) + d.satisfy = 100; + + show_play_pic(11); + vmsg("¬ù·|¥h ©I©I"); + } + return 0; +} + + +int +pip_play_outing() /* ¥¹C */ +{ + if (d.money < 250) + { + vmsg("¿ú¤£°÷¦h°Õ¡I®È¹CÁ`±oªáÂI¿ú¿ú"); + } + else + { + count_tired(10, 45, 0, 100, 0); + d.money -= 250; + d.weight += rand() % 2 + 1; + d.hp -= rand() % 7 + 15; + d.character += rand() % 5 + 5; + d.happy += rand() % 10 + 12; + d.satisfy += rand() % 10 + 10; + + if (d.happy > 100) + d.happy = 100; + if (d.satisfy > 100) + d.satisfy = 100; + + switch (rand() % 4) + { + case 0: + d.art += rand() % 2; + show_play_pic(12); + vmsg(rand() % 2 ? "¤ß¤¤¦³¤@ªÑ²H²Hªº·Pı ¦nµÎªA³á...." : "¶³¤ô ¶~±¡ ¤ß±¡¦n¦h¤F....."); + break; + + case 1: + d.art += rand() % 3; + show_play_pic(13); + vmsg(rand() % 2 ? "¦³¤s¦³¤ô¦³¸¨¤é §Î¦¨¤@´T¬üÄRªºµe.." : "¬ÝµÛ¬ÝµÛ ¥þ¨¯h¾Î³£¤£¨£Åo.."); + break; + + case 2: + d.love += rand() % 3; + show_play_pic(14); + vmsg(rand() % 2 ? "¬Ý ¤Ó¶§§Ö¨S¤J¤ô¤¤Åo..." : "¯u¬O¤@´T¬ü´º"); + break; + + case 3: + d.hp += d.maxhp; + show_play_pic(15); + vmsg(rand() % 2 ? "Åý§Ú̺ƨg¦b©]¸Ìªº®üÅy§a....©I©I.." : "²D²nªº®ü·ªï±Å§¨Ó ³Ì³ßÅw³oºØ·Pı¤F...."); + } + + /* ÀH¾÷¹J¨ì¤Ñ¨Ï */ + if (rand() % 301 == 0) + pip_meet_angel(); + } + + return 0; +} + + +int +pip_play_kite() /* ·ºå */ +{ + count_tired(4, 4, 1, 100, 0); + d.weight += (rand() % 2 + 2); + d.shit += rand() % 5 + 6; + d.hp -= rand() % 2 + 7; + d.affect += rand() % 4 + 6; + d.happy += rand() % 5 + 10; + d.satisfy += rand() % 3 + 12; + + if (d.happy > 100) + d.happy = 100; + if (d.satisfy > 100) + d.satisfy = 100; + + show_play_pic(16); + vmsg("©ñ·ºå¯u¦nª±°Õ..."); + return 0; +} + + +int +pip_play_KTV() /* KTV */ +{ + if (d.money < 250) + { + vmsg("¿ú¤£°÷¦h°Õ¡I°ÛºqÁ`±oªáÂI¿ú¿ú"); + } + else + { + count_tired(10, 10, 1, 100, 0); + d.money -= 250; + d.shit += rand() % 5 + 6; + d.hp += rand() % 2 + 6; + d.art += rand() % 4 + 3; + d.happy += rand() % 3 + 20; + d.satisfy += rand() % 2 + 20; + + if (d.happy > 100) + d.happy = 100; + if (d.satisfy > 100) + d.satisfy = 100; + + show_play_pic(17); + vmsg("¤G°¦¦Ñªê..¤G°¦¦Ñªê..¶]±o§Ö..¶]±o§Ö.."); + } + return 0; +} + + +static void +guess_pip_lose() +{ + d.winn++; + d.shit += rand() % 3 + 2; + d.hp -= rand() % 2 + 3; + d.satisfy--; + d.happy -= 2; + outs("¤pÂû¿é¤F....~>_<~"); + show_guess_pic(2); +} + + +static void +guess_pip_tie() +{ + d.tiee++; + count_tired(2, 2, 1, 100, 1); + d.shit += rand() % 3 + 2; + d.hp -= rand() % 2 + 3; + d.satisfy++; + d.happy++; + outs("¥¤â........-_-"); + show_guess_pic(3); +} + + +static void +guess_pip_win() +{ + d.losee++; + count_tired(2, 2, 1, 100, 1); + d.shit += rand() % 3 + 2; + d.hp -= rand() % 2 + 3; + d.satisfy += rand() % 3 + 2; + d.happy += rand() % 3 + 5; + outs("¤pÂûĹÅo....*^_^*"); + show_guess_pic(1); +} + + +int +pip_play_guess() /* ²q®±µ{¦¡ */ +{ + int mankey; /* §Ú¥Xªº¤â */ + int pipkey; /* ¤pÂû¥Xªº¤â */ + char msg[3][5] = {"°Å¤M", "¥ÛÀY", "¥¬ "}; + + out_cmd("", COLOR1 " ²q®± " COLOR2 " [1]§Ú¥X°Å¤M [2]§Ú¥X¥ÛÀY [3]§Ú¥X¥¬°Õ [Q]¸õ¥X \033[m"); + + /* itoc.010814: ¥i¥H¤@ª½²q®± */ + while (1) + { + /* §Ú¥ý¥X */ + mankey = vkey() - '1'; + if (mankey < 0 || mankey > 2) + return 0; + + /* ¤pÂû¦A¥X */ + pipkey = rand() % 3; + + /* ¦b b_lines - 2 ¨q¥þ³¡ªº³Ót°T®§ */ + move(b_lines - 2, 0); + prints("±z¡G%s ¤pÂû¡G%s ", msg[mankey], msg[pipkey]); + + /* §P©w³Ót */ + if (mankey == pipkey) /* ¥¤â */ + guess_pip_tie(); + else if (pipkey == mankey + 1 || pipkey == mankey - 2) /* ¤pÂû³Ó */ + guess_pip_win(); + else /* ¤pÂû±Ñ */ + guess_pip_lose(); + } +} +#endif /* HAVE_GAME */ diff --git a/pip/pip_prac.c b/pip/pip_prac.c new file mode 100644 index 0000000..c1937f4 --- /dev/null +++ b/pip/pip_prac.c @@ -0,0 +1,522 @@ +/*-------------------------------------------------------*/ +/* pip_prac.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : צæ¿ï³æ */ +/* create : / / */ +/* update : 01/08/14 */ +/* author : dsyan.bbs@forever.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#include "pip.h" + + +/*-------------------------------------------------------*/ +/* צæ¿ï³æ:©À®Ñ ½mªZ צæ */ +/*-------------------------------------------------------*/ + +/*-------------------------------------------------------*/ +/* ¸ê®Æ®w */ +/*-------------------------------------------------------*/ + +static char *classrank[6] = {"¨S¦³", "ªì¯Å", "¤¤¯Å", "°ª¯Å", "¶i¶¥", "±M·~"}; + +static int classmoney[11][2] = +{ + {0, 0}, {60, 110}, {70, 120}, {70, 120}, {80, 130}, {70, 120}, + {60, 110}, {90, 140}, {70, 120}, {70, 120}, {80, 130} +}; + +static int classvariable[11][4] = +{ + {0, 0, 0, 0}, + {5, 5, 4, 4}, {5, 7, 6, 4}, {5, 7, 6, 4}, {5, 6, 5, 4}, {7, 5, 4, 6}, + {7, 5, 4, 6}, {6, 5, 4, 6}, {6, 6, 5, 4}, {5, 5, 4, 7}, {7, 5, 4, 7} +}; + +static char classword[11][5][41] = /* ¤G¤QÓ¤¤¤å¦r */ +{ + {"½Ò¦W", "¦¨¥\\¤@", "¦¨¥\\¤G", "¥¢±Ñ¤@", "¥¢±Ñ¤G"}, + + {"¦ÛµM¬ì¾Ç", "¥¿¦b¥Î¥\\Ū®Ñ¤¤..", "§Ú¬OÁo©úº¡¤ÀÂû", + "³oÃD«ç»ò¬Ý¤£À´«¨..©Ç¤F", "°á¤£§¹¤F :~~~~~~"}, + + {"ð¸Ö§ºµü", "§É«e©ú¤ë¥ú..ºÃ¬O¦a¤WÁ÷..", "¬õ¨§¥Í«n°ê..¬K¨Óµo´XªK..", + "£°..¤W½Ò¤£n¬y¤f¤ô", "ÁÙ²V³á..§ÖIð¸Ö¤T¦Êº"}, + + {"¯«¾Ç±Ð¨|", "«¢¹p¸ô¨È «¢¹p¸ô¨È", "Åý§Ú̪ﱵ¤Ñ°ó¤§ªù", + "£°..¦b·F¹À£«¡HÁÙ¤£¦n¦n°á", "¯«¾Ç«ÜÄYµÂªº..½Ð¦n¦n¾Ç..:("}, + + {"x¾Ç±Ð¨|", "®]¤l§Lªk¬O¤¤°ê§Lªk®Ñ..", "±qx³ø°ê¡A§Ún±a§L¥h¥´¥M", + "¤°»ò°}§Î£«¡H²V¶Ã°}§Î¡H @_@", "³s¤T°ê§Ó³£ª±¤£¦n¡AÁÙ·Q¥´¥M¡H"}, + + {"¼C¹D§Þ³N", "¬Ý§Úªº¼F®`..", "§Ú¨ë §Ú¨ë §Ú¨ë¨ë¨ë..", + "¼Cn®³Ã¤@ÂI°Õ..", "¦b¨ë¦a¹«£«¡H¼C®³°ª¤@ÂI"}, + + {"®æ°«¾Ô§Þ", "¦Ù¦×¬O¦Ù¦× ©I©I..", "¤Q¤K»É¤H¦æ®ð´²..", + "¸}¦A½ð°ª¤@ÂI°Õ..", "®±ÀY«ç»ò³o»ò¨S¤O£«.."}, + + {"Å]ªk±Ð¨|", "§ÚÅÜ §ÚÅÜ §ÚÅÜÅÜÅÜ..", "³DÁx¡ÏÁµ»i§À¡Ï¹«¤ú¡ÏÃÊßï¡×¡H¡H", + "¤p¤ß±½©ª¤£n¶Ã´§..", "£°¡ã¤f¤ô¤£n¬y¨ì¤ô´¹²y¤W.."}, + + {"§»ö±Ð¨|", "n·í°¦¦³Â§»ªªºÂû..", "¼Ú¶Ùò..£«ù£«¨§..", + "«ç»ò¾Ç¤£·|£«¡H¤Ñ§r..", "¨«°_¸ô¨Ó¨S¨«¼Ë..¤Ñ£«.."}, + + {"øµe§Þ¥©", "«Ü¤£¿ùò..¦³¬ü³N¤Ñ¥÷..", "³o´TµeªºÃC¦â·f°tªº«Ü¦n..", + "¤£n°µe²Å°Õ..n¥[ªo..", "¤£n«rµeµ§°Õ..ÃaÃa¤pÂû³á.."}, + + {"»RÁЧޥ©", "¬ü±o´N¹³¤@°¦¤ÑÃZ³á..", "»RÁвÓM«Ü¦n³á..", + "¨Åé¦A¬X³n¤@ÂI..", "«ô°U¤£n³o»ò²Ê¾|.."} +}; + + +/*-------------------------------------------------------*/ +/* ¨ç¦¡®w */ +/*-------------------------------------------------------*/ + + +static int +pip_practice_gradeup(classnum, classgrade, newgrade) /* צ浥¯Å´£¤É */ + int classnum; /* ½Ò¸¹ */ + int classgrade; /* ¦~¯Å */ + int newgrade; /* ·s¦~¯Å */ +{ + /* itoc.0108802: ¬°¬Ùpºâ¡Anewgrade ±q 0 ¶}©lºâ¡Aclassgrade ±q 1 ¶}©lºâ */ + if (newgrade >= classgrade && newgrade < 5) + { + char buf[80]; + sprintf(buf, "¤U¦¸´«¤W [%8s%4s½Òµ{]", classword[classnum][0], classrank[newgrade + 1]); + vmsg(buf); + } + return 0; +} + + +/* ¶Ç¤J:½Ò¸¹ µ¥¯Å ¥Í©R §Ö¼Ö º¡¨¬ żż ¶Ç¦^:ÅܼÆ12345 ¶Ç¦^: -1:©ñ±ó 0:¥¢±Ñ 1:¦¨¥\ */ +static int +pip_practice_function(classnum, classgrade, pic1, pic2, change1, change2, change3, change4, change5) + int classnum; /* ×¦æºØÃþ */ + int classgrade; /* צ浥¯Å */ + int pic1, pic2; /* ¹ÏÀÉ */ + int *change1; /* ¥DnÄݩʼW¥[ */ + int *change2; /* ¦¸nÄݩʼW¥[ */ + int *change3; /* ªþ¥[ÄݩʼW¥[ */ + int *change4; /* ¬Û«gÄݩʴî¤Ö */ + int *change5; /* ¬Û¥¸Äݩʴî¤Ö */ +{ + int grade, success; + char buf[80]; + + /* itoc.010803: Àˬd classgrade¡AÁ×§K·N¥~ */ + /* ¦]¬°ÁÙ¨S update¡Alearn_skill ¥i¯à < 0 */ + if (LEARN_LEVEL < 0) + { + vmsg("±z¤w¸g²Ö¨ìÃz¤F"); + return -1; + } + + /* itoc.010803: classgrade À³¸Ó¥u±q 1~5 ¯Å */ + if (classgrade < 0) + grade = 1; + else if (classgrade > 5) + grade = 5; + else + grade = classgrade; + + /* ¿úªººâªk */ + success = grade * classmoney[classnum][0] + classmoney[classnum][1]; /* ɥΠsuccess */ + sprintf(buf, " [%8s%4s½Òµ{]nªá %d¤¸¡A½T©wn¶Ü(Y/N)¡H[Y] ", classword[classnum][0], classrank[grade], success); + + if (ians(b_lines - 2, 0, buf) == 'n') + return -1; + if (d.money < success) + { + vmsg("«Ü©êºp¡A±zªº¿ú¤£°÷³á"); + return -1; + } + count_tired(4, 5, 1, 100, 1); + d.money -= success; + + /* ¦¨¥\»P§_ªº§PÂ_ */ + success = (d.hp / 2 + rand() % 20 > d.tired); /* 1: ¦¨¥\ 0: ¥¢±Ñ */ + + d.hp -= rand() % 5 + classvariable[classnum][0]; + d.happy -= rand() % 5 + classvariable[classnum][1]; + d.satisfy -= rand() % 5 + classvariable[classnum][2]; + d.shit += rand() % 5 + classvariable[classnum][3]; + + /* ¥[ªºÂI¼Æ¦¨¥\¬O¥¢±Ñªº 1.5 ¿¡A¦©ªºÂI¼Æ¥¢±Ñ¬O¦¨¥\ªº 1.5 ¿ */ + /* learn_skill ¥i±q 2%~100% */ + *change1 = (7 + 6 * (rand() % grade)) * 2 * LEARN_LEVEL / (3 - success); /* ¥DnÄݩʥ[´Á±æÈ 3*classgrade+4 (Yצ榨¥\¥B°²³] learn_level = 100%) */ + *change2 = (5 + 4 * (rand() % grade)) * 2 * LEARN_LEVEL / (3 - success); /* ¦¸nÄݩʥ[´Á±æÈ 2*classgrade+3 (Yצ榨¥\¥B°²³] learn_level = 100%) */ + *change3 = (3 + 2 * (rand() % grade)) * 2 * LEARN_LEVEL / (3 - success); /* ªþ¥[Äݩʥ[´Á±æÈ classgrade+2 (Yצ榨¥\¥B°²³] learn_level = 100%) */ + + *change4 = (5 + rand() % grade) * 2 / (1 + success); /* ¬Û«gÄݩʦ©´Á±æÈ classgrade/2+4.5 (Yצ榨¥\) */ + *change5 = (5 + rand() % grade) * 2 / (2 + success); /* ¬Û¥¸Äݩʦ©´Á±æÈ classgrade/3+3 (Yצ榨¥\) */ + + /* ¶Ã¼Æ¿ï¤@ӹϨӨq */ + if (rand() % 2) + show_practice_pic(pic1); + else + show_practice_pic(pic2); + + vmsg(classword[classnum][3 - 2 * success + rand() % 2]); /* ²Ä¤@¤GÓ¬O¦¨¥\°T®§¡A¤T¥|Ó¬O¥¢±Ñ°T®§ */ + return success; +} + + +/*-------------------------------------------------------*/ +/* צæ¿ï³æ:©À®Ñ ½mªZ צæ */ +/*-------------------------------------------------------*/ + + +/* itoc.010802: ¦UÃþ classgrage ªº¬É©w¬O¤pÂûªº¬Y¶µÄÝ©Ê / 200¡A·íµM¤]¥i¥H¥[Åv³B²z */ + +int +pip_practice_classA() +{ + /* ¢z¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ */ + /* ¢x¦ÛµM¬ì¾Ç¢x¥¿ÄݩʡG´¼¤O¡B§ÜÅ]¡B±q¯Ê ¢x */ + /* ¢x ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x ¢xtÄݩʡG«H¥õ¡B±q¯Ê ¢x */ + /* ¢|¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} */ + + int class; + int change1, change2, change3, change4, change5; + + class = (d.wisdom * 3 + d.immune * 2) / 1000 + 1; /* ¬ì¾Ç */ + + if (pip_practice_function(1, class, 11, 12, &change1, &change2, &change3, &change4, &change5) < 0) + return 0; + + d.wisdom += change1; + d.immune += change2; + d.belief -= change4; + d.classA++; + + if (d.belief < 0) + d.belief = 0; + + /* itoc.010802: ¶Ã¼Æ¾Ç·|¨s·¥ªk³N */ + if (rand() % 30 == 0) + pip_learn_skill(-7); + + pip_practice_gradeup(1, class, (d.wisdom * 3 + d.immune * 2) / 1000); + return 0; +} + + +int +pip_practice_classB() +{ + /* ¢z¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ */ + /* ¢x ¸Öµü ¢x¥¿ÄݩʡG·P¨ü¡B®ð½è¡BÃÀ³N ¢x */ + /* ¢x ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x ¢xtÄݩʡG±q¯Ê¡B§ÜÅ] ¢x */ + /* ¢|¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} */ + + int class; + int change1, change2, change3, change4, change5; + + class = (d.affect * 3 + d.character * 2 + d.art) / 1200 + 1; /* ¸Öµü */ + + if (pip_practice_function(2, class, 21, 22, &change1, &change2, &change3, &change4, &change5) < 0) + return 0; + + d.affect += change1; + d.character += change2; + d.art += change3; + d.immune -= change5; + d.classB++; + + if (d.immune < 0) + d.immune = 0; + + /* itoc.010814: ¶Ã¼Æ¾Ç·|¤ßªk */ + if (rand() % 10 == 0) + pip_learn_skill(3); + + pip_practice_gradeup(2, class, (d.affect * 3 + d.character * 2 + d.art) / 1200); + return 0; +} + + +int +pip_practice_classC() +{ + /* ¢z¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ */ + /* ¢x ¯«¾Ç ¢x¥¿ÄݩʡG«H¥õ¡B§ÜÅ]¡B´¼¤O ¢x */ + /* ¢x ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x ¢xtÄݩʡG§ðÀ»¡B±q¯Ê ¢x */ + /* ¢|¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} */ + + int class; + int change1, change2, change3, change4, change5; + + class = (d.belief * 3 + d.immune * 2 + d.wisdom) / 1200 + 1; /* ¯«¾Ç */ + + if (pip_practice_function(3, class, 31, 32, &change1, &change2, &change3, &change4, &change5) < 0) + return 0; + + d.belief += change1; + d.immune += change2; + d.wisdom += change3; + d.attack -= change4; + d.classC++; + + if (d.attack < 0) + d.attack = 0; + + /* itoc.010802: ¶Ã¼Æ¾Ç·|ªvÀøªk³N */ + if (rand() % 10 == 0) + pip_learn_skill(-1); + + pip_practice_gradeup(3, class, (d.belief * 3 + d.immune * 2 + d.wisdom) / 1200); + return 0; +} + + +int +pip_practice_classD() +{ + /* ¢z¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ */ + /* ¢x x¾Ç ¢x¥¿ÄݩʡG¾Ô°«§Þ³N¡B´¼¤O¡B±q¯Ê ¢x */ + /* ¢x ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x ¢xtÄݩʡG·P¨ü¡B±q¯Ê ¢x */ + /* ¢|¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} */ + + int class; + int change1, change2, change3, change4, change5; + + class = (d.hskill * 3 + d.wisdom * 2) / 1000 + 1; + + if (pip_practice_function(4, class, 41, 42, &change1, &change2, &change3, &change4, &change5) < 0) + return 0; + + d.hskill += change1; + d.wisdom += change2; + d.affect -= change4; + d.classD++; + + if (d.affect < 0) + d.affect = 0; + + /* itoc.010814: ¶Ã¼Æ¾Ç·|Å@¨ */ + if (rand() % 10 == 0) + pip_learn_skill(1); + + pip_practice_gradeup(4, class, (d.hskill * 3 + d.wisdom * 2) / 1000); + return 0; +} + + +int +pip_practice_classE() +{ + /* ¢z¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ */ + /* ¢x ¼C³N ¢x¥¿ÄݩʡG§ðÀ»¡B¾Ô°«§Þ³N¡B¨¾¿m ¢x */ + /* ¢x ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x ¢xtÄݩʡG·P¨ü¡B±q¯Ê ¢x */ + /* ¢|¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} */ + + int class; + int change1, change2, change3, change4, change5; + + class = (d.attack * 3 + d.hskill * 2 + d.resist) / 1200 + 1; + + if (pip_practice_function(5, class, 51, 52, &change1, &change2, &change3, &change4, &change5) < 0) + return 0; + + d.attack += change1; + d.hskill += change2; + d.resist += change3; + d.affect -= change4; + d.classE++; + + if (d.affect < 0) + d.affect = 0; + + /* itoc.010802: ¶Ã¼Æ¾Ç·|¼Cªk */ + if (rand() % 10 == 0) + pip_learn_skill(5); + + pip_practice_gradeup(5, class, (d.attack * 3 + d.hskill * 2 + d.resist) / 1200); + return 0; +} + + +int +pip_practice_classF() +{ + /* ¢z¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ */ + /* ¢x ®æ°« ¢x¥¿ÄݩʡG¨¾¿m¡B³t«×¡B§ðÀ» ¢x */ + /* ¢x ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x ¢xtÄݩʡG·P¨ü¡B±q¯Ê ¢x */ + /* ¢|¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} */ + + int class; + int change1, change2, change3, change4, change5; + + class = (d.resist * 3 + d.speed * 2 + d.attack) / 1200 + 1; + + if (pip_practice_function(6, class, 61, 62, &change1, &change2, &change3, &change4, &change5) < 0) + return 0; + + d.resist += change1; + d.speed += change2; + d.attack += change3; + d.affect -= change4; + d.classF++; + + if (d.affect < 0) + d.affect = 0; + + /* itoc.010802: ¶Ã¼Æ¾Ç·|®±ªk */ + if (rand() % 10 == 0) + pip_learn_skill(4); + + pip_practice_gradeup(6, class, (d.resist * 3 + d.speed * 2 + d.attack) / 1200); + return 0; +} + + +int +pip_practice_classG() +{ + /* ¢z¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ */ + /* ¢x Å]ªk ¢x¥¿ÄݩʡGÅ]ªk§Þ³N¡B§ÜÅ]¡B±q¯Ê ¢x */ + /* ¢x ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x ¢xtÄݩʡG§ðÀ»¡B³t«× ¢x */ + /* ¢|¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} */ + + int class; + int change1, change2, change3, change4, change5; + + class = (d.mskill * 3 + d.immune * 2) / 1000 + 1; + + if (pip_practice_function(7, class, 71, 72, &change1, &change2, &change3, &change4, &change5) < 0) + return 0; + + d.mskill += change1; + d.immune += change2; + d.attack -= change4; + d.speed -= change5; + d.classG++; + + if (d.attack < 0) + d.attack = 0; + if (d.speed < 0) + d.speed = 0; + + /* itoc.010802: ¶Ã¼Æ¾Ç·|¤¨tÅ]ªk¤§¤@ */ + if (rand() % 7 == 0) + pip_learn_skill(- 2 - rand() % 5); + + pip_practice_gradeup(7, class, (d.mskill * 3 + d.immune * 2) / 1000); + return 0; +} + + +int +pip_practice_classH() +{ + /* ¢z¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ */ + /* ¢x §»ö ¢x¥¿ÄݩʡG§»ö¡B®ð½è¡B½Í¦R ¢x */ + /* ¢x ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x ¢xtÄݩʡG³t«×¡B±q¯Ê ¢x */ + /* ¢|¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} */ + + int class; + int change1, change2, change3, change4, change5; + + class = (d.manners * 3 + d.character * 2 + d.speech) / 1200 + 1; + + if (pip_practice_function(8, class, 81, 82, &change1, &change2, &change3, &change4, &change5) < 0) + return 0; + + d.manners += change1; + d.character += change2; + d.speech += change3; + d.speed -= change4; + d.classH++; + + if (d.speed < 0) + d.speed = 0; + + pip_practice_gradeup(8, class, (d.manners * 3 + d.character * 2 + d.speech) / 1200); + return 0; +} + + +int +pip_practice_classI() +{ + /* ¢z¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ */ + /* ¢x øµe ¢x¥¿ÄݩʡGÃÀ³N¡B·P¨ü¡B±q¯Ê ¢x */ + /* ¢x ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x ¢xtÄݩʡG±q¯Ê¡B±q¯Ê ¢x */ + /* ¢|¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} */ + + int class; + int change1, change2, change3, change4, change5; + + class = (d.art * 3 + d.character * 2) / 1000 + 1; + + if (pip_practice_function(9, class, 91, 92, &change1, &change2, &change3, &change4, &change5) < 0) + return 0; + + d.art += change1; + d.character += change2; + d.classI++; + + /* itoc.010814: ¶Ã¼Æ¾Ç·|¤Mªk */ + if (rand() % 10 == 0) + pip_learn_skill(6); + + pip_practice_gradeup(9, class, (d.art * 3 + d.character * 2) / 1000); + return 0; +} + + +int +pip_practice_classJ() +{ + /* ¢z¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ */ + /* ¢x »RÁÐ ¢x¥¿ÄݩʡGÃÀ³N¡B¾y¤O¡B®ð½è ¢x */ + /* ¢x ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t */ + /* ¢x ¢xtÄݩʡG§ðÀ»¡BÅ]ªk§Þ³N ¢x */ + /* ¢|¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} */ + + int class; + int change1, change2, change3, change4, change5; + + class = (d.art * 3 + d.charm * 2 + d.character) / 1200 + 1; + + if (pip_practice_function(10, class, 101, 102, &change1, &change2, &change3, &change4, &change5) < 0) + return 0; + + d.art += change1; + d.charm += change2; + d.character += change3; + d.attack -= change4; + d.mskill -= change5; + d.classJ++; + + if (d.attack < 0) + d.attack = 0; + if (d.mskill < 0) + d.mskill = 0; + + /* itoc.010802: ¶Ã¼Æ¾Ç·|»´¥\ */ + if (rand() % 10 == 0) + pip_learn_skill(2); + + pip_practice_gradeup(10, class, (d.art * 3 + d.charm * 2 + d.character) / 1200); + return 0; +} +#endif /* HAVE_GAME */ diff --git a/pip/pip_quest.c b/pip/pip_quest.c new file mode 100644 index 0000000..50f3a82 --- /dev/null +++ b/pip/pip_quest.c @@ -0,0 +1,418 @@ +/* ----------------------------------------------------- */ +/* pip_quest.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/* ----------------------------------------------------- */ +/* target : ¾Ô°«¿ï³æ */ +/* create : 01/12/22 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/* ----------------------------------------------------- */ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#include "pip.h" + + +/*-------------------------------------------------------*/ +/* ©Ò¦³¥ô°È: ¦^¶Ç 1 ªí¥Ü§¹¦¨ ¦^¶Ç 0 ªí¥Ü¨S¦³§¹¦¨ */ +/*-------------------------------------------------------*/ + + +/* ¼g¥ô°È«D±`²³æ¡G¼g¤@Ө禡 pip_quest_??()¡A¨Ã¥[¤J quest_cb¡A + ¨Ã§ï PIPQUEST_NUM¡A³Ì«á½s¿è¤@Ó etc/game/pip/quest/pic?? §Y¥i */ + + + /*-----------------------------------------------------*/ + /* pip_quest_1~99 ¨ú±oª««~ªº¥ô°È */ + /*-----------------------------------------------------*/ + + +static int +pip_quest_1() /* ¨ú±o°ò¦¸Ë³Æ */ +{ + /* ¥þ¨¨CÓ³¡¦ì³£¬ïµÛ¸Ë³Æ´Nºâ¦X®æ */ + if (d.weaponhead && d.weaponhand && d.weaponshield && d.weaponbody && d.weaponfoot) + { + /* ì¸Ë³Æ²¾°£ */ + d.weaponhead = d.weaponhand = d.weaponshield = d.weaponbody = d.weaponfoot = 0; + d.equiphead[0] = d.equiphand[0] = d.equipshield[0] = d.equipbody[0] = d.equipfoot[0] = '\0'; + + d.tired = 0; + vmsg("±z¤£¦A·P¨ì¯h¾Î¤F"); + return 1; + } + + return 0; +} + + +static int +pip_quest_2() /* ¨ú±o¶Àª÷¸Ë³Æ */ +{ + /* ¥þ¨¨CÓ³¡¦ìªº¸Ë³Æ¦WºÙ³£¥]§t¡uª÷¡v³o¦r´Nºâ¦X®æ */ + if (strstr(d.equiphead, "ª÷") && strstr(d.equiphand, "ª÷") && + strstr(d.equipshield, "ª÷") && strstr(d.equipbody, "ª÷") && strstr(d.equipfoot, "ª÷")) + { + /* ì¸Ë³Æ²¾°£ */ + d.weaponhead = d.weaponhand = d.weaponshield = d.weaponbody = d.weaponfoot = 0; + d.equiphead[0] = d.equiphand[0] = d.equipshield[0] = d.equipbody[0] = d.equipfoot[0] = '\0'; + + d.happy = 100; + d.tired = 0; + vmsg("±zªººë¯«¦Ê¿"); + return 1; + } + + return 0; +} + + +static int +pip_quest_3() /* ¨ú±oÃħ÷ */ +{ + /* ¨ú±o¤jÁÙ¤¦¡BÆFªÛ¡B¤j¸É¤Y¡B¤d¦~¤Hçx¡B¶Â¥ÉÂ_Äò»I¡B¤Ñ¤s³·½¬¦U¤@ */ + if (d.pill && d.medicine && d.burger && d.ginseng && d.paste && d.snowgrass) + { + d.pill--; + d.medicine--; + d.burger--; + d.ginseng--; + d.paste--; + d.snowgrass--; + d.happy = 100; + vmsg("§U¤H¬°§Ö¼Ö¤§¥»"); + return 1; + } + + return 0; +} + + + /*-----------------------------------------------------*/ + /* pip_quest_101~199 ÄݩʹF¦¨ªº¥ô°È */ + /*-----------------------------------------------------*/ + + +static int +pip_quest_101() /* §¹¥þ°·±d */ +{ + /* ¹F¨ì¤£¯h²Ö¡B¤£¥Í¯f¡B¤£»êż */ + if (d.tired == 0 && d.sick == 0 && d.shit == 0) + { + d.food++; + d.cookie++; + vmsg("¯u´Î¡A¤k¯«½ç±z¤@¨Ç¹ª«"); + return 1; + } + + return 0; +} + + + /*-----------------------------------------------------*/ + /* pip_quest_201~299 ¥´±Ñ©Çª«ªº¥ô°È */ + /*-----------------------------------------------------*/ + + +static int +pip_quest_201() /* ¥´Ë¯f¬r */ +{ + /* ¥´Ë¤@°¦¯à¤O¤ñ¦Û¤v°ªªº©Çª« */ + + int level; + playrule m; + + strcpy(m.name, "Åܺدf¬r"); + level = d.level + 5; + m.hp = m.maxhp = 100 + level * level; + m.attack = m.spirit = m.magic = m.armor = m.dodge = level * 15; + m.money = 0; + m.exp = 0; + m.attribute = +7; /* ±Mªø: ¨s·¥ªk³N */ + m.pic = 004; + + if (pip_vs_man(m, 0)) /* ¤pÂû¹ï¾Ô¼Ä¤H (ɥΪZ³N¤j·|) */ + { + d.hexp += d.level; + d.mexp += d.level; + vmsg("±z¥´±Ñ¤F³o°¦Åܺدf¬r¡Aµû»ù´£¤É"); + return 1; + } + + return 0; +} + + +static int +pip_quest_202() /* ¤Q¤j´c¤H */ +{ + /* ¨Ì§Ç¥´Ë¼Æ°¦©Çª« */ + /* Y¥´±Ñ¤Q¤j´c¤H¡A¦WÁn´£°ª¡F¤Ï¤§¡A½m¦¨¶ù¦ç¯«¥\ */ + + int i; + struct playrule badmanlist[] = /* ¤Q¤j´c¤H¬Û·í©óµ¥¯Å 40 ~ 50 ªº©Çª« */ + { + /* name[13] attribute hp maxhp attack spirit magic armor dodge money exp pic */ + /* ·R¥Î§lºë */ "§õ¤j¼L", +3, 1875, 1875, 500, 460, 350, 500, 500, 0, 220, 001, + /* ·R¥Î blitz */ "³±¤E«Õ", +2, 1850, 1850, 520, 470, 320, 420, 630, 0, 220, 002, + /* ·R¥Î·t¾¹ */ "«¢«¢¨à", +7, 1750, 1750, 450, 450, 370, 400, 520, 0, 220, 003, + /* ·R¥Îª¢¨tÅ]ªk */ "±O¼b¼b", -4, 1635, 1635, 430, 340, 640, 360, 470, 0, 220, 004, + /* §ðÀ»¤O¯S±j */ "§ù ±þ", 0, 2400, 2400, 610, 570, 280, 550, 500, 0, 250, 005, + }; + + if (ians(b_lines - 1, 0, "¤Q¤j´c¤H¬Ý°_¨Ó¶W±j¡A±zn§äÀ°¤â¶Ü(Y/N)¡H[Y] ") != 'n') + { + if (ians(b_lines - 1, 0, "½Ð½Ö·íÀ°¤â¡H(1)¿PªF¤Ñ (2)¿P¦è¤Ñ (3)¿P«n¤Ñ (4)¿P¥_¤Ñ ") == '3') + { + /* itoc.050320: Yµ¥¯Å¤Ó§C®É±µ¨ì³oÓ¥ô°È·|¥´¤£Ä¹¡A©Ò¥Hn´£¨Ñ½â©Û :p */ + vmsg("¦b¤j«L¿P«n¤ÑªºÀ°§U¤§¤U¡A±z¦¨¥\\¦a°£¥h¤Q¤j´c¤H"); + return 1; + } + else + { + vmsg("¥L©Úµ´¤F±zªº½Ð¨D¡A¬Ý¨Ó±z¥u¦n¦Û¤v¤W¤F"); + } + } + + for (i = 0; i< 5; i++) + { + if (!pip_vs_man(badmanlist[i], 0)) /* ¤pÂû¹ï¾Ô¼Ä¤H (ɥΪZ³N¤j·|) */ + { + vmsg("±z³Q¤Q¤j´c¤H³ò§ð¡A¥þ¨ºë¯ßÑÂ_"); + d.hp = 1; + d.mp = 0; + d.vp = 0; + d.sp = 0; + + /* ¶ù¦ç¯«¥\: ®³ maxmp ¥h´« maxsp */ + i = rand() % 10; + if (d.maxmp > i) + { + d.maxmp -= i; + d.maxsp += i; + vmsg("¦b¯«Âå¸U¬K¬yªºªvÀø¤§¤U¡A±z¤Ï½m¦¨¶ù¦ç¯«¥\\"); + } + + return 0; + } + } + + d.hexp += 100; + d.mexp += 100; + vmsg("±z¦¨¥\\¦a°£¥h´c¤H¨¦ªº©Ò¦³Ãa³J¡A¦WÁn¤j´T´£¤É"); + return 1; +} + + + /*-----------------------------------------------------*/ + /* pip_quest_301~399 ¼Æ¾Çpºâªº¥ô°È */ + /*-----------------------------------------------------*/ + + +static int +pip_quest_301() /* ¤À°t¯]Ä_ */ +{ + char ans[3]; + + vget(b_lines, 0, "§ÚÀ³¸Ó¥i¥H¤À¨ì´XÓ¯]Ä_©O¡H", ans, 3, DOECHO); + if (atoi(ans) == 2) + { + d.social += 10; + vmsg("Åý§Ú·Q·Q¬Ý°Ú¡I¾³¡A¨S¿ù¡A±z¹ê¦b¤ÓÁo©ú¤F"); + return 1; + } + + return 0; +} + + +static int +pip_quest_302() /* 0.9999... ´`Àô¤p¼Æ */ +{ + int num; + char ans1[4], ans2[4]; + + if (vget(b_lines, 0, "´`Àô¤p¼Æ 0.9999... ¤Æ¬°¤À¼Æ¡A¤À¥À¬O ", ans1, 4, DOECHO) && + vget(b_lines, 0, "´`Àô¤p¼Æ 0.9999... ¤Æ¬°¤À¼Æ¡A¤À¤l¬O ", ans2, 4, DOECHO)) + { + if ((num = atoi(ans1)) && (num == atoi(ans2))) /* ¤À¥À¤£¯à¬° 0 */ + { + d.wisdom += 10; + vmsg("¨S¿ù¡A0.9999... ´N¬O 1"); + return 1; + } + } + + return 0; +} + + + /*-----------------------------------------------------*/ + /* pip_quest_401~499 ®æ¨¥ªY½àªº¥ô°È */ + /*-----------------------------------------------------*/ + + +static int +pip_quest_401() /* ºA«×¦Ê¤À¦Ê */ +{ + if (ians(b_lines - 1, 0, "1)ª¾ÃÑ 2)§V¤O 3)ºA«× ") == '3') + { + d.affect += 5; + d.toman += 5; + vmsg("¬Oªº¡A°ß¦³¦Ê¤À¦ÊªººA«×¤~¯àÀò±o²³¤Hªº´L·q"); + return 1; + } + + return 0; +} + + + /*-----------------------------------------------------*/ + /* quest_cb[] ¥ô°È¦Cªí */ + /*-----------------------------------------------------*/ + + +#define PIPQUEST_NUM 9 + + +/* static KeyFunc quest_cb[] = */ +static KeyFunc quest_cb[PIPQUEST_NUM + 1] = /* §â PIPQUEST_NUM «ü©w¶i¥h¡A¦pªG¦³¿ù¡A¥i¥H¦b compile ¤¤¬Ý¥X */ +{ + /* ´M§äª««~ */ + 1, pip_quest_1, + 2, pip_quest_2, + 3, pip_quest_3, + + /* ÄݩʹF¦¨ */ + 101, pip_quest_101, + + /* ¥´±Ñ©Çª« */ + 201, pip_quest_201, + 202, pip_quest_202, + + /* ¼Æ¾Ç°ÝÃD */ + 301, pip_quest_301, + 302, pip_quest_302, + + /* ®æ¨¥ªY½à */ + 401, pip_quest_401, + + 0, NULL /* µ²§ô¥ô°È¦Cªí */ +}; + + +/*-------------------------------------------------------*/ +/* ¥ô°È¨ç¦¡ */ +/*-------------------------------------------------------*/ + + +static int /* 1:¬d¸ß¥ô°È 0:¨S¦³¥ô°È */ +pip_quest_query(quest) /* ¬d¸ßÂÂ¥ô°È */ + int quest; /* ¥ô°È½s¸¹ */ +{ + if (!quest && !(quest = d.quest)) + { + vmsg("±z¥Ø«e¨S¦³¥ô°È¦b¨"); + return 0; + } + show_quest_pic(quest); + return 1; +} + + +int /* 1:¨ú±o·s¥ô°È 0:¨ú®ø¨ú±o©Î¤w¦³¥ô°È */ +pip_quest_new() /* ¨ú±o·s¥ô°È */ +{ + if (ians(b_lines - 1, 0, "±z¤w¹F¤É¯Å¼Ð·Ç¡AÄ@·N±µ¨üªø¦Ñ«ü¬£¥ô°È¶Ü(Y/N)¡H[N] ") == 'y') + { + d.quest = quest_cb[rand() % PIPQUEST_NUM].key; + pip_quest_query(d.quest); + vmsg("¥h§a¡A°õ¦æ³oÓ¥ô°Èµ²§ô«á§Ú´N½á¤©±z§ó°ªªº¯à¤O"); + return 1; + } + return 0; +} + + +static int /* 1:¥ô°È§¹¦¨ 0:¥ô°È¥¢±Ñ */ +pip_quest_done() /* §¹¦¨¥ô°È */ +{ + KeyFunc *cb; + int key; + + if (!d.quest) + { + vmsg("±z¥Ø«e¨S¦³¥ô°È¦b¨"); + return 0; + } + + /* itoc.µù¸Ñ: ¬O¤£¬O¦Ò¼{´« binary search? */ + for (cb = quest_cb; (key = cb->key); cb++) + { + if (key == d.quest) + { + key = (*(cb->func)) (); /* 1:§¹¦¨ 0:¥¢±Ñ */ + pip_levelup(key); + return key; + } + } + + vmsg("½Ð§i¶D¯¸ªø¡A§ä¤£¨ì¦¹¥ô°Èªºµ{¦¡"); /* À³¸Ó¤£¥i¯à¥X²{ */ + return 0; +} + + +static int /* 1:©ñ±óÂÂ¥ô°È 0:¨ú®ø©ñ±ó©Î¨S¦³¥ô°È */ +pip_quest_abort() /* ©ñ±óÂÂ¥ô°È */ +{ + if (!d.quest) + { + vmsg("±z¥Ø«e¨S¦³¥ô°È¦b¨"); + } + else if (ians(b_lines - 1, 0, "±z½T©wn©ñ±ó²{¦³ªº¥ô°È¶Ü(Y/N)¡H[N] ") == 'y') + { + pip_levelup(0); + return 1; + } + else + { + vmsg("ÁÙ¬O¤£n©ñ±ó¦n¤F"); + } + return 0; +} + + +/*-------------------------------------------------------*/ +/* ¥ô°È¥D¿ï³æ */ +/*-------------------------------------------------------*/ + + +int +pip_quest_menu() +{ + while (1) + { + out_cmd("", COLOR1 " ¥ô°È " COLOR2 " [1]§¹¦¨ [2]¬d¸ß [3]©ñ±ó [Q]¸õ¥X \033[m"); + + switch (vkey()) + { + case 'q': + return 0; + + case '1': + pip_quest_done(); + break; + + case '2': + pip_quest_query(0); + break; + + case '3': + pip_quest_abort(); + break; + } + } +} +#endif /* HAVE_GAME */ diff --git a/pip/pip_race.c b/pip/pip_race.c new file mode 100644 index 0000000..e12dc6f --- /dev/null +++ b/pip/pip_race.c @@ -0,0 +1,287 @@ +/*-------------------------------------------------------*/ +/* pip_race.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¦¬Ã¬©u¤ñÁÉ */ +/* create : / / */ +/* update : 03/03/31 */ +/* author : dsyan.bbs@forever.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#include "pip.h" + + +/*-------------------------------------------------------*/ +/* ³Áɪ̦W³æ */ +/*-------------------------------------------------------*/ + + +static char racename[4][9] = {"ªZ°«¤j·|", "ÃÀ³N¤j®i", "¬Ó®a»R·|", "²i¶¹¤jÁÉ"}; + + +/* name[13] attribute hp maxhp attack spirit magic armor dodge money exp pic */ +/* °Ñ¦Ò badman_generate() ¤¤ªºµù¸Ñ¡A¦³©Çª«µ¥¯Åªº´Á±æÈ */ +struct playrule racemanlist[] = +{ + /* ¬Û·í©óµ¥¯Å 05 ªº©Çª« */ "¯üÄR¸¶ð", 0, 30, 30, 50, 50, 50, 50, 50, 50, 25, 001, + /* ¬Û·í©óµ¥¯Å 10 ªº©Çª« */ "µá¼Ú§Q®R", 0, 95, 95, 99, 99, 99, 99, 99, 99, 50, 002, + /* ¬Û·í©óµ¥¯Å 20 ªº©Çª« */ "ªü©g´µ¥Õ", 0, 300, 300, 350, 40, 40, 200, 200, 200, 100, 003, + /* ¬Û·í©óµ¥¯Å 40 ªº©Çª« */ "©¬¦h¹p¦è", 0, 1200, 1200, 350, 600, 200, 600, 100, 400, 200, 004, + /* ¬Û·í©óµ¥¯Å 60 ªº©Çª« */ "¥d¬ü©Ô¬ü", 0, 2700, 2700, 600, 600, 600, 600, 600, 600, 300, 005, + /* ¬Û·í©óµ¥¯Å 90 ªº©Çª« */ "¥§¥j©Ô´µ", 0, 6100, 6100, 900, 799, 999, 799, 999, 900, 450, 006, +}; + +static int player[3]; /* ¤T¦ì³ÁÉ¿ï¤âªº¸¹½X¡A±j«×¬O player[2] > player[1] > player[0] */ + + +/*-------------------------------------------------------*/ +/* ªZ°«¤j·| */ +/*-------------------------------------------------------*/ + + +/* itoc.030331.¹CÀ¸³]p: ©I¥s pip_vs_man() ³o¨ç¦¡¶i¤J¾Ô°«µe±¡A¥´Ä¹¦h¤Ö¤H¨Óºâ¦¨ÁZ */ + +static int /* ¦^¶Ç: ŤF´XÓ¤H >=3:«ax 2:¨Èx 1:©ux <=0:³Ì«á¤@¦W */ +pip_race_eventA() +{ + int i, winorlost; + char buf[80]; + + /* ±q racemanlist ¤»¦ì¤¤¬D¥X¤TÓ³ÁÉªÌ */ + player[0] = rand() % 2; + player[1] = rand() % 2 + 2; + player[2] = rand() % 2 + 4; + + winorlost = 0; + for (i = 0; i < 3; i++) + { + sprintf(buf, "±zªº²Ä %d Ó¹ï¤â¬O%s", i + 1, racemanlist[player[i]].name); + vmsg(buf); + + if (pip_vs_man(racemanlist[player[i]], 0)) /* ¤pÂû¹ï¾Ô¼Ä¤H */ + winorlost++; /* Àò³Ó */ + } + + return winorlost; +} + + +/*-------------------------------------------------------*/ +/* ÃÀ³N¤j®i */ +/*-------------------------------------------------------*/ + + +/* itoc.030331.¹CÀ¸³]p: §¹¥þ¥Ñ d.art ©M d.charm ¨Ó¨M©wÃÀ³N¤j®iªº¦¨ÁZ */ + +static int /* ¦^¶Ç: ŤF´XÓ¤H >=3:«ax 2:¨Èx 1:©ux <=0:³Ì«á¤@¦W */ +pip_race_eventB() +{ + /* ±q racemanlist ¤»¦ì¤¤¬D¥X¤TÓ³ÁÉªÌ */ + player[0] = rand() % 2 + 4; + player[1] = rand() % 2; + player[2] = rand() % 2 + 2; + + /* ª½±µ¬Ý¯à¤O¡A¨S¦³¤ñÁɹLµ{ */ + return ((d.art * 2 + d.character) / 600); +} + + +/*-------------------------------------------------------*/ +/* ¬Ó®a»R·| */ +/*-------------------------------------------------------*/ + + +/* itoc.030331.¹CÀ¸³]p: §¹¥þ¥Ñ d.art ©M d.charm ¨Ó¨M©w¬Ó®a»R·|ªº¦¨ÁZ */ + +static int /* ¦^¶Ç: ŤF´XÓ¤H >=3:«ax 2:¨Èx 1:©ux <=0:³Ì«á¤@¦W */ +pip_race_eventC() +{ + /* ±q racemanlist ¤»¦ì¤¤¬D¥X¤TÓ³ÁÉªÌ */ + player[0] = rand() % 2 + 2; + player[1] = rand() % 2 + 4; + player[2] = rand() % 2; + + /* ª½±µ¬Ý¯à¤O¡A¨S¦³¤ñÁɹLµ{ */ + return ((d.art * 2 + d.charm) / 600); +} + + +/*-------------------------------------------------------*/ +/* ²i¶¹¤jÁÉ */ +/*-------------------------------------------------------*/ + + +/* itoc.030331.¹CÀ¸³]p: ì«h¤W¬O¥Ñ d.cook ©M d.affect ¨Ó¨M©w²i¶¹¤jÁɪº¦¨ÁZ¡A + ¦ý¬O¦pªGµæ¦â©M¥Ø«eªºª¬ºA§k¦Xªº¸Ü¦³¥[¤À®ÄªG¡A¤Ï¤§«h¦³¦©¤À®ÄªG */ + +static int /* ¦^¶Ç: ŤF´XÓ¤H >=3:«ax 2:¨Èx 1:©ux <=0:³Ì«á¤@¦W */ +pip_race_eventD() +{ + int winorlost; + + /* ±q racemanlist ¤»¦ì¤¤¬D¥X¤TÓ³ÁÉªÌ */ + player[0] = rand() % 2 + 4; + player[1] = rand() % 2 + 2; + player[2] = rand() % 2; + + winorlost = ians(b_lines - 1, 0, "±z·QµNþºØ¤f¨ýªºµæ¦â¡H0)®a±` 1)»Ä 2)²¢ 3)W 4)»¶ [0] "); + if (winorlost == '1') + winorlost = 70 - d.satisfy * 2; /* ¶V¤£º¡¨¬µN¥X¨Óªºµæ¤~¶V±a¦³¾L¨ý (¤£º¡¨¬·|¦Y¾L) */ + else if (winorlost == '2') + winorlost = d.happy * 2 - 130; /* ¶V¬O§Ö¼ÖµN¥X¨Óªºµæ¤~¶V±a¦³²¢«× («Ü§Ö¼Ö·|²¢»e) */ + else if (winorlost == '3') + winorlost = d.shit * 2 - 130; /* ¶V¬O»êżµN¥X¨Óªºµæ¤~¶V±a¦³W³B (¤j«K¬OWªº:p) */ + else if (winorlost == '4') + winorlost = d.sick * 2 - 130; /* ¶V¬O¥Í¯fµN¥X¨Óªºµæ¤~¶V±a¦³»¶» (¥Í¯f¨ýı¤£ÆF) */ + else + winorlost = 0; /* ®a±`µæ»Pª¬ºAµLÃö */ + + winorlost += d.cook * 2 + d.affect; + + return (winorlost / 600); +} + + +/*-------------------------------------------------------*/ +/* ¤ñÁɵ²ªG */ +/*-------------------------------------------------------*/ + + +static void +pip_race_ending(winorlost, mode) + int winorlost; /* ŤF´XÓ¤H >=3:«ax 2:¨Èx 1:©ux <=0:³Ì«á¤@¦W */ + int mode; /* °Ñ¥[þ¤@ºØ¤ñÁÉ */ +{ + char *name1, *name2, *name3, *name4; + char buf[80]; + + if (winorlost <= 0) /* ³Ì«á¤@¦W */ + { + name1 = racemanlist[player[2]].name; + name2 = racemanlist[player[1]].name; + name3 = racemanlist[player[0]].name; + name4 = d.name; + } + else if (winorlost == 1) /* ©ux¼úª÷ 2000 */ + { + name1 = racemanlist[player[2]].name; + name2 = racemanlist[player[1]].name; + name3 = d.name; + name4 = racemanlist[player[0]].name; + d.money += 2000; + } + else if (winorlost == 2) /* ¨Èx¼úª÷ 5000 */ + { + name1 = racemanlist[player[2]].name; + name2 = d.name; + name3 = racemanlist[player[1]].name; + name4 = racemanlist[player[0]].name; + d.money += 5000; + } + else /* «ax¼úª÷ 10000 */ + { + name1 = d.name; + name2 = racemanlist[player[2]].name; + name3 = racemanlist[player[1]].name; + name4 = racemanlist[player[0]].name; + d.money += 10000; + } + + clear(); + move(6, 13); + prints("\033[1;37m¡ã¡ã¡ã\033[32m¥»©¡ %s µ²ªG´¦¾å\033[37m¡ã¡ã¡ã\033[m", racename[mode - 1]); + move(8, 15); + prints("\033[1;41m «ax \033[0;1m¡ã\033[1;33m%-10s\033[36m ¼úª÷ %d\033[m", name1, 10000); + move(10, 15); + prints("\033[1;41m ¨Èx \033[0;1m¡ã\033[1;33m%-10s\033[36m ¼úª÷ %d\033[m", name2, 5000); + move(12, 15); + prints("\033[1;41m ©ux \033[0;1m¡ã\033[1;33m%-10s\033[36m ¼úª÷ %d\033[m", name3, 2000); + move(14, 15); + prints("\033[1;41m ³Ì«á \033[0;1m¡ã\033[1;33m%-10s\033[36m\033[0m", name4); + sprintf(buf, "¤µ¦~ªº%sµ²§ôÅo «á¦~¦A¨Ó§a..", racename[mode - 1]); + vmsg(buf); +} + + +/*-------------------------------------------------------*/ +/* ¦¬Ã¬©u¤ñÁÉ */ +/*-------------------------------------------------------*/ + + +int /* !=0:°Ñ¥[ªº¶µ¥Ø 0:¤£°Ñ¥[ */ +pip_race_main() /* ¦¬Ã¬©u */ +{ + int ch; + int winorlost; /* ŤF´XÓ¤H >=3:«ax 2:¨Èx 1:©ux <=0:³Ì«á¤@¦W */ + + clear(); + move(10, 14); + outs("\033[1;33m¥m©N¥m©N¡ã ¨¯Wªº¶l®tÀ°§Ṵ́e«H¨Ó¤F³á...\033[m"); + vmsg("¶â §â«H¥´¶}¬Ý¬Ý§a..."); + + show_resultshow_pic(0); + + move(b_lines - 2, 0); + prints("[A]%s [B]%s [C]%s [D]%s [Q]©ñ±ó¡G", racename[0], racename[1], racename[2], racename[3]); + do + { + ch = vkey(); + } while (ch != 'q' && (ch < 'a' || ch > 'd')); + + if (ch == 'q') + { + vmsg("¤µ¦~¤£°Ñ¥[°Õ.....:("); + d.happy -= rand() % 10 + 10; + d.satisfy -= rand() % 10 + 10; + d.relation -= rand() % 10; + return 0; + } + + ch -= 'a' - 1; + show_resultshow_pic(ch); + vmsg("¤µ¦~¦@¦³¥|¤H°ÑÁÉ¡ã²{¦b¤ñÁɶ}©l"); + + switch (ch) + { + case 1: /* ªZ°«¤j·| */ + winorlost = pip_race_eventA(); + d.hexp += rand() % 10 + 20 * winorlost; + d.exp += rand() % 10 + d.level * winorlost; + break; + + case 2: /* ÃÀ³N¤j®i */ + winorlost = pip_race_eventB(); + d.art += rand() % 10 + 20 * winorlost; + d.character += rand() % 10 + 20 * winorlost; + break; + + case 3: /* ¬Ó®a»R·| */ + winorlost = pip_race_eventC(); + d.art += rand() % 10 + 20 * winorlost; + d.charm += rand() % 10 + 20 * winorlost; + break; + + case 4: /* ²i¶¹¤jÁÉ */ + winorlost = pip_race_eventD(); + d.cook += rand() % 10 + 20 * winorlost; + d.family += rand() % 10 + 20 * winorlost; + break; + } + + pip_race_ending(winorlost, ch); + + /* ¦pªG°Ñ¥[ªº¸Ü¡A«ì´_©Ò¦³ÄÝ©Ê */ + d.tired = 0; + d.hp = d.maxhp; + d.happy += rand() % 20; + d.satisfy += rand() % 20; + d.relation += rand() % 10; + + return ch; +} +#endif /* HAVE_GAME */ diff --git a/pip/pip_royal.c b/pip/pip_royal.c new file mode 100644 index 0000000..4364419 --- /dev/null +++ b/pip/pip_royal.c @@ -0,0 +1,200 @@ +/* ----------------------------------------------------- */ +/* pip_royal.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/* ----------------------------------------------------- */ +/* target : ¤pÂû royal */ +/* create : / / */ +/* update : 01/08/14 */ +/* author : dsyan.bbs@forever.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/* ----------------------------------------------------- */ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#include "pip.h" + + +/* royalset: num name needmode needvalue addtoman maxtoman words1 words2 */ + +struct royalset royallist[] = +{ + "T", "«ô³X¹ï¶H", 0, 0, 0, 0, NULL, NULL, + "A", "¬Ó«°ÃM§L³s", 1, 10, 15, 100, "±z¯u¦n¡A¨Ó³§Ú²á¤Ñ..", "¦u½Ã¬PªÅªº¦w¥þ¬O«Ü¨¯Wªº..", + "B", "¢¯¢¯¢¶¯S°È", 1, 100, 25, 200, "¯u¬O§»ªªº¤pÂû..§Ú³ßÅw..", "¯S°È´N¬O¯µ±K«OÅ@¯¸ªø¦w¥þªº¤H..", + "C", "Âí°ê¤j±Nx", 1, 200, 30, 250, "·í¦~¨ºÓ¾Ô§Ð«Üºë±m³á..", "±z¯u¬O°ª¶QÀu¶®ªº¤pÂû..", + "D", "°Ñ¿ÑÁ`°Èªø", 1, 300, 35, 300, "§ÚÀ°¯¸ªøºÞ²z³oÓ°ê®aò..", "±zªºÁnµ«Ü¦nÅ¥C..§Ú«Ü³ßÅw³á..:)", + "E", "ºÞ²z°Æ¯¸ªø", 1, 400, 35, 300, "±z«Ü¦³±Ð¾iò¡I«Ü°ª¿³»{Ãѱz..", "Àu¶®ªº±z¡A½ÐÅý§ÚÀ°±z¬èºÖ..", + "F", "¨t²Î¯¸ªø", 1, 500, 40, 350, "±z¦n¥i·R³á..§Ú³ßÅw±zò..", "¹ï°Õ..¥H«án¦h¦h¨Ó©M§Úª±³á..", + "G", "µ{¦¡¯¸ªø", 1, 550, 40, 350, "§i¶D±zò¡A¸ò±zÁ¿¸Ü«Ü§Ö¼Ö³á..", "¨Ó¡A§¤§Ú½¥»\\¤W¡AÅ¥§ÚÁ¿¬G¨Æ..", + "H", SYSOPNICK, 1, 600, 50, 400, "¤@¯¸¤§ªø³d¥ô«¤j§r..:)..", "ÁÂÁ±zÅ¥§ÚÁ¿¸Ü..¥H«án¦h¨Ó³á..", + "I", "ºÆ¨gÄé¤ô¸s", 2, 60, 20, 150, "¤£¿ùò..ÆZ¾÷ÆFªº³á..«Ü¥i·R..", "¨Ó¡A§Ṳ́@°_¨ÓÄé¤ô§a..", + "J", "«C¦~«ÓªZ©x", 0, 0, 0, 0, "±z¦n¡A§Ú¬OªZ©x¡Aè±qÃä¹Ò¦^¨Ó", "§Æ±æ¤U¦¸Áٯਣ¨ì±z..:)", + NULL, NULL, 0, 0, 0, 0, NULL, NULL +}; + + +static int +pip_go_palace_screen(p) + struct royalset *p; +{ + char inbuf1[128], inbuf2[20]; + char *needmode[3] = {" ", "§»öªí²{¡Ö", "½Í¦R§Þ¥©¡Ö"}; + int n, a, b, choice, change; + int save[11]; + + /* ¨q¥X©Ò¦³¥i¥H«ô³Xªº¤H */ + clear(); + show_palace_pic(0); + move(13, 0); + outs(" \033[1;31m¢z¢w¢w¢w¢w¢w¢w¢t\033[37;41m ¨Ó¨ìÁ`¥q¥O³¡¤F ½Ð¿ï¾Ü±z±ý«ô³Xªº¹ï¶H\033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢{\033[m\n"); + outs(" \033[1;31m¢x ¢x\033[m\n"); + + for (n = 0; n < 5; n++) + { + a = 2 * n + 1; + b = 2 * n + 2; + sprintf(inbuf1, "%-10s%3d", needmode[p[a].needmode], p[a].needvalue); + + if (n == 4) /* ¤ý¤l */ + sprintf(inbuf2, "%-10s", needmode[p[b].needmode]); + else + sprintf(inbuf2, "%-10s%3d", needmode[p[b].needmode], p[b].needvalue); + + if ((d.seeroyalJ == 1 && n == 4) || (n != 4)) + { + prints(" \033[1;31m¢x\033[36m(\033[37m%s\033[36m)\033[33m%-10s \033[37m%-14s \033[36m(\033[37m%s\033[36m)\033[33m%-10s \033[37m%-14s \033[31m¢x\033[m\n", + p[a].num, p[a].name, inbuf1, p[b].num, p[b].name, inbuf2); + } + else + { + prints(" \033[1;31m¢x\033[36m(\033[37m%s\033[36m)\033[33m%-10s \033[37m%-14s \033[31m¢x\033[0m\n", + p[a].num, p[a].name, inbuf1); + } + } + outs(" \033[1;31m¢x ¢x\033[m\n"); + outs(" \033[1;31m¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}\033[m"); + + while (1) + { + sprintf(inbuf1, COLOR1 " [¥Í©R¤O] %6d/%6d [¯h³Ò«×] %6d \033[m", d.hp, d.maxhp, d.tired); + out_cmd(inbuf1, COLOR1 " °Ñ¨£¿ï³æ " COLOR2 " [¦r¥À]¿ï¾Ü±ý«ô³Xªº¤Hª« [Q]Â÷¶}Á`¥q¥O³¡ \033[m"); + + choice = vkey(); + if (choice == 'q' || choice == KEY_LEFT) + { + vmsg("Â÷¶}" BBSNAME "Á`¥q¥O³¡....."); + return 0; + } + + /* ±N¦U¤Hª«¤w¸gµ¹»Pªº¼ÆÈ¥ýÀx¦s°_¨Ó*/ + save[1] = d.royalA; /* from¦u½Ã */ + save[2] = d.royalB; /* fromªñ½Ã */ + save[3] = d.royalC; /* from±Nx */ + save[4] = d.royalD; /* from¤j¦Ú */ + save[5] = d.royalE; /* from²½¥q */ + save[6] = d.royalF; /* fromÃd¦m */ + save[7] = d.royalG; /* from¤ý¦m */ + save[8] = d.royalH; /* from°ê¤ý */ + save[9] = d.royalI; /* from¤p¤¡ */ + save[10] = d.royalJ; /* from¤ý¤l */ + + choice -= 'a' - 1; + + if ((choice >= 1 && choice <= 10 && d.seeroyalJ == 1) || (choice >= 1 && choice <= 9 && d.seeroyalJ == 0)) + { + d.social += rand() % 3 + 3; + d.hp -= rand() % 5 + 6; + d.tired += rand() % 5 + 8; + + if ((p[choice].needmode == 0) || (p[choice].needmode == 1 && d.manners >= p[choice].needvalue) || + (p[choice].needmode == 2 && d.speech >= p[choice].needvalue)) + { + if (choice >= 1 && choice <= 9 && save[choice] >= p[choice].maxtoman) + { + vmsg(rand() % 2 ? "¯à©M³o»ò°¶¤jªº±zÁ¿¸Ü¯u¬Oºa©¯£«..." : "«Ü°ª¿³±z¨Ó«ô³X§Ú¡A¦ý§Ú¤£¯àµ¹±z¤°»ò¤F.."); + } + else + { + if (choice >= 1 && choice <= 8) /* ®Ê¨£©xû¡A¼W¥[«Ý¤H±µª« */ + { + switch (choice) + { + case 1: + change = d.character / 5; + break; + case 2: + change = d.character / 8; + break; + case 3: + change = d.charm / 5; + break; + case 4: + change = d.wisdom / 10; + break; + case 5: + change = d.belief / 10; + break; + case 6: + change = d.speech / 10; + break; + case 7: + change = d.social / 10; + break; + case 8: + change = d.hexp / 10; + break; + } + + if (change > p[choice].addtoman) /* ¦pªG¤j©ó¨C¦¸ªº¼W¥[³Ì¤j¶q */ + change = p[choice].addtoman; + else if ((change + save[choice]) >= p[choice].maxtoman) /* ¦pªG¥[¤Wì¥ýªº¤§«á¤j©ó©Ò¯àµ¹ªº©Ò¦³È®É */ + change = p[choice].maxtoman - save[choice]; + + save[choice] += change; + d.toman += change; + } + else if (choice == 9) /* §ä¤p¤¡ */ + { + save[9] = 0; + d.social -= 13 + rand() % 4; + d.affect += 13 + rand() % 4; + } + else if (choice == 10 && d.seeroyalJ == 1) /* «ô³X¤ý¤l */ + { + save[10] += 15 + rand() % 4; + d.seeroyalJ = 0; + } + + vmsg(rand() % 2 ? p[choice].words1 : p[choice].words2); + } + } + else + { + vmsg(rand() % 2 ? "§Ú¤£©M³o¼ËªºÂû½Í¸Ü...." : "¨S±Ð¾iªºÂû¡A¦A¥h¾Ç¾Ç§»ö§a...."); + } + } + + d.royalA = save[1]; + d.royalB = save[2]; + d.royalC = save[3]; + d.royalD = save[4]; + d.royalE = save[5]; + d.royalF = save[6]; + d.royalG = save[7]; + d.royalH = save[8]; + d.royalI = save[9]; + d.royalJ = save[10]; + } +} + + +int +pip_go_palace() /* °Ñ¨£ */ +{ + pip_go_palace_screen(royallist); + return 0; +} +#endif /* HAVE_GAME */ + diff --git a/pip/pip_stuff.c b/pip/pip_stuff.c new file mode 100644 index 0000000..4ad3bbc --- /dev/null +++ b/pip/pip_stuff.c @@ -0,0 +1,670 @@ +/*-------------------------------------------------------*/ +/* pip_stuff.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¤É¯Å¡B¨t²Î¡B¯S®í¿ï³æµ¥Âø¤CÂø¤K¨ç¦¡ */ +/* create : / / */ +/* update : 01/08/14 */ +/* author : dsyan.bbs@forever.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#include "pip.h" + + +/*-------------------------------------------------------*/ +/* ¸ê®Æ¦s¨ú */ +/*-------------------------------------------------------*/ + + +void +pip_write_file() /* ¹CÀ¸¼g¸ê®Æ¤JÀÉ®× */ +{ + int fd; + char fpath[64]; + + usr_fpath(fpath, cuser.userid, fn_pip); + fd = open(fpath, O_WRONLY | O_CREAT, 0600); /* fpath ¤£¥²¤w¸g¦s¦b */ + write(fd, &d, sizeof(CHICKEN)); + close(fd); +} + + +int /* >=0:¦¨¥\ <0:¥¢±Ñ */ +pip_read_file(userid, p) /* ¹CÀ¸Åª¸ê®Æ¥XÀÉ®× */ + char *userid; + struct CHICKEN *p; +{ + int fd; + char fpath[64]; + + usr_fpath(fpath, userid, fn_pip); + fd = open(fpath, O_RDONLY); /* fpath ¥²¶·¤w¸g¦s¦b */ + if (fd >= 0) + { + read(fd, p, sizeof(CHICKEN)); + close(fd); + } + return fd; +} + + +int /* 1: ¦¨¥\¼g¤J 0: ©ñ±ó */ +pip_write_backup() /* ¤pÂû¶i«×³Æ¥÷ */ +{ + char *files[4] = {"¨S¦³", "¶i«×¤@", "¶i«×¤G", "¶i«×¤T"}; + char buf[80], fpath[64]; + int ch; + + show_basic_pic(101); + + ch = ians(b_lines - 2, 0, "Àx¦s [1] ¶i«×¤@ [2] ¶i«×¤G [3] ¶i«×¤T [Q] ©ñ±ó¡G[Q] ") - '0'; + + if (ch < 1 || ch > 3) + { + vmsg("©ñ±óÀx¦s¹CÀ¸³Æ¥÷"); + return 0; + } + + sprintf(buf, "½T©wnÀx¦s©ó [%s] ÀÉ®×¶Ü(Y/N)¡H[N] ", files[ch]); + if (ians(b_lines - 2, 0, buf) != 'y') + { + vmsg("©ñ±óÀx¦sÀÉ®×"); + return 0; + } + + sprintf(buf, "Àx¦s [%s] ÀÉ®×§¹¦¨¤F", files[ch]); + vmsg(buf); + + sprintf(buf, "%s.bak%d", fn_pip, ch); + usr_fpath(fpath, cuser.userid, buf); + ch = open(fpath, O_WRONLY | O_CREAT, 0600); /* fpath ¤£¥²¤w¸g¦s¦b */ + write(ch, &d, sizeof(CHICKEN)); + close(ch); + + return 1; +} + + +int /* 1: ¦¨¥\Ū¥X 0: ©ñ±ó */ +pip_read_backup() /* ¤pÂû³Æ¥÷Ū¨ú */ +{ + char *files[4] = {"¨S¦³", "¶i«×¤@", "¶i«×¤G", "¶i«×¤T"}; + char buf[80], fpath[64]; + int ch, fd; + + show_basic_pic(102); + + ch = ians(b_lines - 2, 0, "Ū¨ú [1] ¶i«×¤@ [2] ¶i«×¤G [3] ¶i«×¤T [Q] ©ñ±ó¡G[Q] ") - '0'; + + if (ch < 1 || ch > 3) + { + vmsg("©ñ±óŪ¨ú¹CÀ¸³Æ¥÷"); + return 0; + } + + sprintf(buf, "%s.bak%d", fn_pip, ch); + usr_fpath(fpath, cuser.userid, buf); + + fd = open(fpath, O_RDONLY); /* fpath ¥²¶·¤w¸g¦s¦b */ + if (fd >= 0) + { + sprintf(buf, "½T©wnŪ¨ú©ó [%s] ÀÉ®×¶Ü(Y/N)¡H[N] ", files[ch]); + if (ians(b_lines - 2, 0, buf) == 'y') + { + read(fd, &d, sizeof(CHICKEN)); + close(fd); + sprintf(buf, "Ū¨ú [%s] ÀÉ®×§¹¦¨¤F", files[ch]); + vmsg(buf); + return 1; + } + vmsg("©ñ±óŪ¨úÀÉ®×"); + close(fd); + return 0; + } + else + { + sprintf(buf, "ÀÉ®× [%s] ¤£¦s¦b", files[ch]); + vmsg(buf); + return 0; + } +} + + +/*-------------------------------------------------------*/ +/* ¤pÂûª¬ºA¨ç¦¡ */ +/*-------------------------------------------------------*/ + + +void +pipdie(msg, diemode) /* ¤pÂû¦º¤` */ + char *msg; + int diemode; +{ + vs_head("¹q¤l¾i¤pÂû", str_site); + + if (diemode == 1) + { + show_die_pic(1); + vmsg("¦º¯«¨Ó±a¨«¤pÂû¤F"); + vs_head("¹q¤l¾i¤pÂû", str_site); + show_die_pic(2); + move(14, 20); + prints("¥i¼¦ªº¤pÂû\033[1;31m%s\033[m", msg); + vmsg(BBSNAME "«s±¥¤¤...."); + } + else if (diemode == 2) + { + show_die_pic(3); + vmsg("¶ã¶ã¶ã..§Ú³Q¥á±ó¤F....."); + } + else if (diemode == 3) + { + show_die_pic(0); + vmsg("¹CÀ¸µ²§ôÅo.."); + } + + d.death = diemode; + pip_write_file(); +} + + +int +count_tired(prob, base, mode, mul, cal) /* itoc.010803: ¨Ì·Ó¶Ç¤Jªº¤Þ¼Æ¨Ó¼W´î¯h³Ò«× */ + int prob; /* ¾÷²v */ + int base; /* ©³¼Æ */ + int mode; /* Ãþ«¬ 1:©M¦~ÄÖ¦³Ãö 0:©M¦~ÄÖµLÃö */ + int mul; /* ¥[Åv (¥H % ¨Óp 100->1) */ + int cal; /* 1:¥[¯h³Ò 0:´î¯h³Ò */ +{ + int tiredvary; /* §ïÅÜÈ */ + + /* ¥ýºâ§ïÅܶq */ + tiredvary = rand() % prob + base; + + if (mode) /* ©M¦~ÄÖ¦³Ãö */ + { + int tm; /* ¦~ÄÖ */ + tm = d.bbtime / 60 / 30; + + /* itoc.010803: ¦~¬ö¶V¤p¡A¥[¯h³Ò¤ñ¸û¤Ö¡A«ì´_¯h³Ò¤]¤ñ¸û§Ö */ + /* ª`·N¤£¯à¼g¦¨ tiredvary *= 6 / 5; ³á :p */ + + if (tm <= 3) /* 0~3 ·³ */ + { + tiredvary = cal ? tiredvary * 16 / 15 : tiredvary * 6 / 5; + } + else if (tm <= 7) /* 4~7 ·³ */ + { + tiredvary = cal ? tiredvary * 11 / 10 : tiredvary * 8 / 7; + } + else if (tm <= 10) /* 8~10 ·³ */ + { + tiredvary = cal ? tiredvary * 8 / 7 : tiredvary * 11 / 10; + } + else /* 11 ·³¥H¤W */ + { + tiredvary = cal ? tiredvary * 6 / 5 : tiredvary * 16 / 15; + } + } + + /* ¦Aºâ¥[Åv */ + if (cal) + { + d.tired += tiredvary * mul / 100; + if (d.tired > 100) + d.tired = 100; + } + else + { + d.tired -= tiredvary; /* ¦©È¤£¦A¥[Åv¤F */ + if (d.tired < 0) + d.tired = 0; + } +} + + +/*-------------------------------------------------------*/ +/* ¯S®í¿ï³æ:¬Ý¯f ´îªÎ */ +/*-------------------------------------------------------*/ + + +int /* 1:¬Ý§¹Âå¥Í 0:¨S¯f¨ÓÂå°|´c·d */ +pip_see_doctor() /* ¬ÝÂå¥Í */ +{ + char buf[256]; + long savemoney; + savemoney = d.sick * 25; + if (d.sick <= 0) + { + vmsg("«zù..¨S¯f¨ÓÂå°|·F¹À..³Q½|¤F..¶ã~~"); + d.character -= rand() % 3 + 1; + if (d.character < 0) + d.character = 0; + d.happy -= (rand() % 3 + 3); + d.satisfy -= rand() % 3 + 2; + } + else if (d.money < savemoney) + { + sprintf(buf, "±zªº¯fnªá %d ¤¸³á....±z¤£°÷¿ú°Õ...", savemoney); + vmsg(buf); + } + else + { + d.tired -= rand() % 10 + 20; + if (d.tired < 0) + d.tired = 0; + d.sick = 0; + d.money = d.money - savemoney; + move(4, 0); + show_special_pic(1); + vmsg("ÃĨì¯f°£..¨S¦³°Æ§@¥Î!!"); + return 1; + } + return 0; +} + + +int /* 1:¾ã®e 0:¨S¦³¾ã®e */ +pip_change_weight() /* ¼WD/´îªÎ */ +{ + char buf[80]; + int weightmp; + + show_special_pic(2); + + out_cmd("", COLOR1 " ¬ü®e " COLOR2 " [1]¶Ç²Î¼WD [2]§Ö³t¼WD [3]¶Ç²Î´îªÎ [4]§Ö³t´îªÎ [Q]¸õ¥X \033[m"); + + switch (vkey()) + { + case '1': + if (d.money < 80) + { + vmsg("¶Ç²Î¼WDn80¤¸³á....±z¤£°÷¿ú°Õ..."); + } + else + { + if (ians(b_lines - 1, 0, " »Ýªá¶O 80 ¤¸¡]3¡ã5¤½¤ç¡^¡A½T©w¶Ü(Y/N)¡H[N] ") == 'Y') + { + weightmp = 3 + rand() % 3; + d.weight += weightmp; + d.money -= 80; + d.hp -= rand() % 2 + 3; + show_special_pic(3); + sprintf(buf, "Á`¦@¼W¥[¤F %d ¤½¤ç", weightmp); + vmsg(buf); + return 1; + } + else + { + vmsg("¦^¤ßÂà·NÅo....."); + } + } + break; + + case '2': + vget(b_lines - 1, 0, " ¼W¤@¤½¤çn 30 ¤¸¡A±zn¼W¦h¤Ö¤½¤ç©O¡H[½Ð¶ñ¼Æ¦r]¡G", buf, 4, DOECHO); + weightmp = atoi(buf); + if (weightmp <= 0) + { + vmsg("¿é¤J¦³»~..©ñ±óÅo..."); + } + else if (d.money > (weightmp * 30)) + { + sprintf(buf, " ¼W¥[ %d ¤½¤ç¡AÁ`¦@»Ýªá¶O¤F %d ¤¸¡A½T©w¶Ü(Y/N)¡H[N] ", weightmp, weightmp * 30); + if (ians(b_lines - 1, 0, buf) == 'y') + { + d.money -= weightmp * 30; + d.weight += weightmp; + count_tired(5, 8, 0, 100, 1); + d.hp -= (rand() % 2 + 3); + d.sick += rand() % 10 + 5; + show_special_pic(3); + sprintf(buf, "Á`¦@¼W¥[¤F %d ¤½¤ç", weightmp); + vmsg(buf); + return 1; + } + else + { + vmsg("¦^¤ßÂà·NÅo....."); + } + } + else + { + vmsg("±z¿ú¨S¨º»ò¦h°Õ......."); + } + break; + + case '3': + if (d.money < 80) + { + vmsg("¶Ç²Î´îªÎn80¤¸³á....±z¤£°÷¿ú°Õ..."); + } + else + { + if (ians(b_lines - 1, 0, "»Ýªá¶O 80¤¸(3¡ã5¤½¤ç)¡A½T©w¶Ü(Y/N)¡H[N] ") == 'y') + { + weightmp = 3 + rand() % 3; + d.weight -= weightmp; + if (d.weight <= 0) + d.weight = 1; + d.money -= 100; + d.hp -= rand() % 2 + 3; + show_special_pic(4); + sprintf(buf, "Á`¦@´î¤Ö¤F %d ¤½¤ç", weightmp); + vmsg(buf); + return 1; + } + else + { + vmsg("¦^¤ßÂà·NÅo....."); + } + } + break; + + case '4': + vget(b_lines - 1, 0, " ´î¤@¤½¤çn 30 ¤¸¡A±zn´î¦h¤Ö¤½¤ç©O¡H[½Ð¶ñ¼Æ¦r]¡G", buf, 4, DOECHO); + weightmp = atoi(buf); + if (weightmp <= 0) + { + vmsg("¿é¤J¦³»~..©ñ±óÅo..."); + } + else if (d.weight <= weightmp) + { + vmsg("±z¨S¨º»ò«³á....."); + } + else if (d.money > (weightmp * 30)) + { + sprintf(buf, " ´î¤Ö %d ¤½¤ç¡AÁ`¦@»Ýªá¶O¤F %d ¤¸¡A½T©w¶Ü(Y/N)¡H[N] ", weightmp, weightmp * 30); + if (ians(b_lines - 1, 0, buf) == 'y') + { + d.money -= weightmp * 30; + d.weight -= weightmp; + count_tired(5, 8, 0, 100, 1); + d.hp -= (rand() % 2 + 3); + d.sick += rand() % 10 + 5; + show_special_pic(4); + sprintf(buf, "Á`¦@´î¤Ö¤F %d ¤½¤ç", weightmp); + vmsg(buf); + return 1; + } + else + { + vmsg("¦^¤ßÂà·NÅo....."); + } + } + else + { + vmsg("±z¿ú¨S¨º»ò¦h°Õ......."); + } + break; + } + return 0; +} + + +/*-------------------------------------------------------*/ +/* ¨t²Î¿ï³æ: Ó¤H¸ê®Æ «ô³X ¤pÂû©ñ¥Í ¯S§OªA°È */ +/*-------------------------------------------------------*/ + + +static int /* 0: ¨S¦³¾i¤pÂû 1: ¦³¾i¤pÂû */ +pip_data_list(userid) /* ¬Ý¬Y¤H¤pÂû¸Ô²Ó¸ê®Æ */ + char *userid; +{ + char buf1[20], buf2[20], buf3[20], buf4[20]; + int ch, page; + struct CHICKEN chicken; + + if (!strcmp(cuser.userid, userid)) /* itoc.021031: ¦pªG¬d¸ß¦Û¤v¡A±q°O¾ÐÅé¥s²{¦bÈ */ + { + memcpy(&chicken, &d, sizeof(CHICKEN)); + } + else if (pip_read_file(userid, &chicken) < 0) + { + vmsg("¥L¨S¦³¾i¤pÂû³á"); + return 0; + } + + page = 1; + + do + { + clear(); + move(1, 0); + + /* itoc,010802: ¬°¤F¬Ý²M·¡¤@ÂI¡A©Ò¥H prints() ¸Ì±ªº¤Þ¼Æ´N¤£Â_¦æ¼g¦b¸Ó¦C³Ì«á */ + + if (page == 1) + { + outs("\033[1;31m ¢~¢t\033[41;37m °ò¥»¸ê®Æ \033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢¡\033[m\n"); + prints("\033[1;31m ¢x\033[33m¡Ì©m ¦W : \033[37m%-10s\033[33m¡Ì¥Í ¤é : \033[37m%-10s\033[33m¡Ì©Ê §O : \033[37m%-10s\033[31m ¢x\033[m\n", chicken.name, chicken.birth, chicken.sex == 1 ? "¡ñ" : "¡ð"); + prints("\033[1;31m ¢x\033[33m¡Ìª¬ ºA : \033[37m%-10s\033[33m¡Ì´_¬¡¦¸¼Æ : \033[37m%-10d\033[33m¡Ì¦~ ÄÖ : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.death == 1 ? "¦º¤`" : chicken.death == 2 ? "©ß±ó" : chicken.death == 3 ? "µ²§ô" : "¥¿±`", chicken.liveagain, chicken.bbtime / 60 / 30); + + outs("\033[1;31m ¢u¢t\033[41;37m ª¬ºA«ü¼Æ \033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t\033[m\n"); + prints("\033[1;31m ¢x\033[33m¡Ì¿Ë¤lÃö«Y : \033[37m%-10d\033[33m¡Ì§Ö ¼Ö «× : \033[37m%-10d\033[33m¡Ìº¡ ·N «× : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.relation, chicken.happy, chicken.satisfy); + prints("\033[1;31m ¢x\033[33m¡ÌÅÊ·R«ü¼Æ : \033[37m%-10d\033[33m¡Ì«H ¥õ : \033[37m%-10d\033[33m¡Ì¸o Ä^ : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.fallinlove, chicken.belief, chicken.sin); + prints("\033[1;31m ¢x\033[33m¡Ì·P ¨ü : \033[37m%-10d\033[33m¡Ì : \033[37m%-10s\033[33m¡Ì : \033[37m%-10s\033[31m ¢x\033[m\n", chicken.affect, "", ""); + + outs("\033[1;31m ¢u¢t\033[41;37m °·±d«ü¼Æ \033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t\033[m\n"); + prints("\033[1;31m ¢x\033[33m¡ÌÅé « : \033[37m%-10d\033[33m¡Ì¯h ³Ò «× : \033[37m%-10d\033[33m¡Ì¯f ®ð : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.weight, chicken.tired, chicken.sick); + prints("\033[1;31m ¢x\033[33m¡Ì²M ¼ä «× : \033[37m%-10d\033[33m¡Ì : \033[37m%-10s\033[33m¡Ì : \033[37m%-10s\033[31m ¢x\033[m\n", chicken.shit, "", ""); + + outs("\033[1;31m ¢u¢t\033[41;37m ¹CÀ¸I´º \033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t\033[m\n"); + prints("\033[1;31m ¢x\033[33m¡Ì²q ®± Ĺ : \033[37m%-10d\033[33m¡Ì²q ®± ¿é : \033[37m%-10d\033[33m¡Ì²q®±¥¤â : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.winn, chicken.losee, chicken.tiee); + + outs("\033[1;31m ¢u¢t\033[41;37m µû»ù°Ñ¼Æ \033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t\033[m\n"); + prints("\033[1;31m ¢x\033[33m¡ÌªÀ¥æµû»ù : \033[37m%-10d\033[33m¡Ì®a¨Æµû»ù : \033[37m%-10d\033[33m¡Ì¾Ô°«µû»ù : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.social, chicken.family, chicken.hexp); + prints("\033[1;31m ¢x\033[33m¡ÌÅ]ªkµû»ù : \033[37m%-10d\033[33m¡Ì : \033[37m%-10s\033[33m¡Ì : \033[37m%-10s\033[31m ¢x\033[m\n", chicken.hexp, "", ""); + + outs("\033[1;31m ¢u¢t\033[41;37m µû»ù°Ñ¼Æ \033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t\033[m\n"); + prints("\033[1;31m ¢x\033[33m¡ÌªÀ¥æµû»ù : \033[37m%-10d\033[33m¡Ì®a¨Æµû»ù : \033[37m%-10d\033[33m¡Ì¾Ô°«µû»ù : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.social, chicken.family, chicken.hexp); + prints("\033[1;31m ¢x\033[33m¡ÌÅ]ªkµû»ù : \033[37m%-10d\033[33m¡Ì : \033[37m%-10s\033[33m¡Ì : \033[37m%-10s\033[31m ¢x\033[m\n", chicken.hexp, "", ""); + + outs("\033[1;31m ¢¢¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢£\033[m\n"); + move(b_lines - 2, 0); + outs(" \033[1;36m²Ä¤@¶\033[37m/\033[36m¦@¤T¶\033[m\n"); + } + else if (page == 2) + { + outs("\033[1;31m ¢~¢t\033[41;37m ¯à¤O°Ñ¼Æ \033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢¡\033[m\n"); + prints("\033[1;31m ¢x\033[33m¡Ì«Ý¤H±µª« : \033[37m%-10d\033[33m¡Ì®ð ½è «× : \033[37m%-10d\033[33m¡Ì·R ¤ß : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.toman, chicken.character, chicken.love); + prints("\033[1;31m ¢x\033[33m¡Ì´¼ ¤O : \033[37m%-10d\033[33m¡ÌÃÀ³N¯à¤O : \033[37m%-10d\033[33m¡Ì¹D ¼w : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.wisdom, chicken.art, chicken.etchics); + prints("\033[1;31m ¢x\033[33m¡Ì«i ´± : \033[37m%-10d\033[33m¡Ì±½¦a¬~¦ç : \033[37m%-10d\033[33m¡Ì¾y ¤O : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.brave, chicken.homework, chicken.charm); + prints("\033[1;31m ¢x\033[33m¡Ì§ »ö : \033[37m%-10d\033[33m¡Ì½Í ¦R : \033[37m%-10d\033[33m¡Ì²i ¶¹ : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.manners, chicken.speech, chicken.cook); + prints("\033[1;31m ¢x\033[33m¡Ì§ð À» ¤O : \033[37m%-10d\033[33m¡Ì¨¾ ¿m ¤O : \033[37m%-10d\033[33m¡Ì³t «× : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.attack, chicken.resist, chicken.speed); + prints("\033[1;31m ¢x\033[33m¡Ì¾Ô°«§Þ³N : \033[37m%-10d\033[33m¡ÌÅ]ªk§Þ³N : \033[37m%-10d\033[33m¡Ì§ÜÅ]¯à¤O : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.hskill, chicken.mskill, chicken.immune); + + sprintf(buf1, "%d%s/%d%s", chicken.hp > 1000 ? chicken.hp / 1000 : chicken.hp, chicken.hp > 1000 ? "K" : "", /* HP */ + chicken.maxhp > 1000 ? chicken.maxhp / 1000 : chicken.maxhp, chicken.maxhp > 1000 ? "K" : ""); + sprintf(buf2, "%d%s/%d%s", chicken.mp > 1000 ? chicken.mp / 1000 : chicken.mp, chicken.mp > 1000 ? "K" : "", /* MP */ + chicken.maxmp > 1000 ? chicken.maxmp / 1000 : chicken.maxmp, chicken.maxmp > 1000 ? "K" : ""); + sprintf(buf3, "%d%s/%d%s", chicken.vp > 1000 ? chicken.vp / 1000 : chicken.vp, chicken.vp > 1000 ? "K" : "", /* VP */ + chicken.maxvp > 1000 ? chicken.maxvp / 1000 : chicken.maxvp, chicken.maxvp > 1000 ? "K" : ""); + sprintf(buf4, "%d%s/%d%s", chicken.sp > 1000 ? chicken.sp / 1000 : chicken.sp, chicken.sp > 1000 ? "K" : "", /* SP */ + chicken.maxsp > 1000 ? chicken.maxsp / 1000 : chicken.maxsp, chicken.maxsp > 1000 ? "K" : ""); + + outs("\033[1;31m ¢u¢t\033[41;37m ¾Ô°««ü¼Ð \033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t\033[m\n"); + prints("\033[1;31m ¢x\033[33m¡Ìµ¥ ¯Å : \033[37m%-10d\033[33m¡Ì¸g Åç È : \033[37m%-10d\033[33m¡Ì ¦å : \033[37m%-10s\033[31m ¢x\033[m\n", chicken.level, chicken.exp, buf1); + prints("\033[1;31m ¢x\033[33m¡Ìªk ¤O : \033[37m%-10s\033[33m¡Ì²¾ °Ê ¤O : \033[37m%-10s\033[33m¡Ì¤º ¤O : \033[37m%-10s\033[31m ¢x\033[m\n", buf2, buf3, buf4); + + outs("\033[1;31m ¢u¢t\033[41;37m ¹ª«®w¦s \033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t\033[m\n"); + prints("\033[1;31m ¢x\033[33m¡Ì¹ ª« : \033[37m%-10d\033[33m¡Ì¹s ¹ : \033[37m%-10d\033[33m¡Ì : \033[37m%-10s\033[31m ¢x\033[m\n", chicken.food, chicken.cookie, ""); + prints("\033[1;31m ¢x\033[33m¡Ì¤j ÁÙ ¤¦ : \033[37m%-10d\033[33m¡ÌÆF ªÛ : \033[37m%-10d\033[33m¡Ì¤j ¸É ¤Y : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.pill, chicken.medicine, chicken.burger); + prints("\033[1;31m ¢x\033[33m¡Ì¤H çx : \033[37m%-10d\033[33m¡ÌÂ_ Äò »I : \033[37m%-10d\033[33m¡Ì³· ½¬ : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.ginseng, chicken.paste, chicken.snowgrass); + + outs("\033[1;31m ¢u¢t\033[41;37m ª««~®w¦s \033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t\033[m\n"); + prints("\033[1;31m ¢x\033[33m¡Ìª÷ ¿ú : \033[37m%-10d\033[33m¡Ì : \033[37m%-10s\033[33m¡Ì : \033[37m%-10s\033[31m ¢x\033[m\n", chicken.money, "", ""); + prints("\033[1;31m ¢x\033[33m¡Ì®Ñ ¥» : \033[37m%-10d\033[33m¡Ìª± ¨ã : \033[37m%-10d\033[33m¡Ì½Ò¥~Ūª« : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.book, chicken.toy, chicken.playboy); + + + outs("\033[1;31m ¢¢¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢£\033[m\n"); + move(b_lines - 2, 0); + outs(" \033[1;36m²Ä¤G¶\033[37m/\033[36m¦@¤T¶\033[m\n"); + } + else /* if (page == 3) */ + { + outs("\033[1;31m ¢~¢t\033[41;37m °Ñ¨£¤ý¦Ú \033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢¡\033[m\n"); + prints("\033[1;31m ¢x\033[33m¡Ì¦u½Ã¦n·P : \033[37m%-10d\033[33m¡Ìªñ½Ã¦n·P : \033[37m%-10d\033[33m¡Ì±Nx¦n·P : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.royalA, chicken.royalB, chicken.royalC); + prints("\033[1;31m ¢x\033[33m¡Ì¤j¦Ú¦n·P : \033[37m%-10d\033[33m¡Ì²½¥q¦n·P : \033[37m%-10d\033[33m¡ÌÃd¦m¦n·P : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.royalD, chicken.royalE, chicken.royalF); + prints("\033[1;31m ¢x\033[33m¡Ì¤ý¦m¦n·P : \033[37m%-10d\033[33m¡Ì°ê¤ý¦n·P : \033[37m%-10d\033[33m¡Ì¤p¤¡¦n·P : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.royalG, chicken.royalH, chicken.royalI); + + outs("\033[1;31m ¢u¢t\033[41;37m ¤u§@¦¸¼Æ \033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t\033[m\n"); + prints("\033[1;31m ¢x\033[33m¡Ì®a¨Æ¦¸¼Æ : \033[37m%-10d\033[33m¡Ì«O©i¦¸¼Æ : \033[37m%-10d\033[33m¡Ì®È©±¦¸¼Æ : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.workA, chicken.workB, chicken.workC); + prints("\033[1;31m ¢x\033[33m¡Ì¹A³õ¦¸¼Æ : \033[37m%-10d\033[33m¡ÌÀ\\ÆU¦¸¼Æ : \033[37m%-10d\033[33m¡Ì±Ð°ó¦¸¼Æ : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.workD, chicken.workE, chicken.workF); + prints("\033[1;31m ¢x\033[33m¡Ì¦aÅu¦¸¼Æ : \033[37m%-10d\033[33m¡Ì¥ï¤ì¦¸¼Æ : \033[37m%-10d\033[33m¡Ì¬ü¾v¦¸¼Æ : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.workG, chicken.workH, chicken.workI); + prints("\033[1;31m ¢x\033[33m¡ÌÂy¤H¦¸¼Æ : \033[37m%-10d\033[33m¡Ì¤u¦a¦¸¼Æ : \033[37m%-10d\033[33m¡Ì¦u¹Ó¦¸¼Æ : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.workJ, chicken.workK, chicken.workL); + prints("\033[1;31m ¢x\033[33m¡Ì®a±Ð¦¸¼Æ : \033[37m%-10d\033[33m¡Ì°s®a¦¸¼Æ : \033[37m%-10d\033[33m¡Ì°s©±¦¸¼Æ : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.workM, chicken.workN, chicken.workO); + prints("\033[1;31m ¢x\033[33m¡Ì©] Á` ·| : \033[37m%-10d\033[33m¡Ì : \033[37m%-10s\033[33m¡Ì : \033[37m%-10s\033[31m ¢x\033[m\n", chicken.workP, "", ""); + + outs("\033[1;31m ¢u¢t\033[41;37m ¤W½Ò¦¸¼Æ \033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t\033[m\n"); + prints("\033[1;31m ¢x\033[33m¡Ì¦ÛµM¬ì¾Ç : \033[37m%-10d\033[33m¡Ìð¸Ö§ºµü : \033[37m%-10d\033[33m¡Ì¯«¾Ç±Ð¨| : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.classA, chicken.classB, chicken.classC); + prints("\033[1;31m ¢x\033[33m¡Ìx¾Ç±Ð¨| : \033[37m%-10d\033[33m¡Ì¼C¹D§Þ³N : \033[37m%-10d\033[33m¡Ì®æ°«¾Ô§Þ : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.classD, chicken.classE, chicken.classF); + prints("\033[1;31m ¢x\033[33m¡ÌÅ]ªk±Ð¨| : \033[37m%-10d\033[33m¡Ì§»ö±Ð¨| : \033[37m%-10d\033[33m¡Ìøµe§Þ¥© : \033[37m%-10d\033[31m ¢x\033[m\n", chicken.classG, chicken.classH, chicken.classI); + prints("\033[1;31m ¢x\033[33m¡Ì»RÁЧޥ© : \033[37m%-10d\033[33m¡Ì : \033[37m%-10s\033[33m¡Ì : \033[37m%-10s\033[31m ¢x\033[m\n", chicken.classJ, "", ""); + + outs("\033[1;31m ¢u¢t\033[41;37m ¸Ë³Æ¦Cªí \033[0;1;31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t\033[m\n"); + prints("\033[1;31m ¢x\033[33m¡ÌÀY³¡¸Ë³Æ : \033[37m%-10s\033[33m¡Ì¤â³¡¸Ë³Æ : \033[37m%-10s\033[33m¡Ì¬ÞµP¸Ë³Æ : \033[37m%-10s\033[31m ¢x\033[m\n", chicken.equiphead, chicken.equiphand, chicken.equipshield); + prints("\033[1;31m ¢x\033[33m¡Ì¨Åé¸Ë³Æ : \033[37m%-10s\033[33m¡Ì¸}³¡¸Ë³Æ : \033[37m%-10s\033[33m¡Ì \033[37m%-10s\033[31m ¢x\033[m\n", chicken.equipbody, chicken.equipfoot, ""); + + outs("\033[1;31m ¢¢¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢£\033[m\n"); + move(b_lines - 2, 0); + outs(" \033[1;36m²Ä¤T¶\033[37m/\033[36m¦@¤T¶\033[m\n"); + } + + out_cmd("", COLOR1 " ¬d¸ß " COLOR2 " [¡ô/PgUP]©¹¤W¤@¶ [¡õ/PgDN]©¹¤U¤@¶ [Q]Â÷¶} \033[m"); + + switch (ch = vkey()) + { + case KEY_UP: + case KEY_PGUP: + if (page > 1) + page--; + break; + + default: + if (page < 3) + page++; + break; + } + } while (ch != 'q' && ch != KEY_LEFT); + + return 1; +} + + +int +pip_query_self() /* ¬d¸ß¦Û¤v */ +{ + pip_data_list(cuser.userid); + return 0; +} + + +int /* 1:«ô³X¦¨¥\ 0:¨S³o°¦Âû */ +pip_query() /* «ô³X¤pÂû */ +{ + int uno; + char uid[IDLEN + 1]; + + vs_bar("«ô³X¦P¦ñ"); + if (vget(1, 0, msg_uid, uid, IDLEN + 1, GET_USER)) + { + move(2, 0); + if (uno = acct_userno(uid)) + { + pip_data_list(uid); + return 1; + } + else + { + outs(err_uid); + clrtoeol(); + } + } + return 0; +} + + +int /* 1:©ñ¥Í 0:Äò¾i */ +pip_system_freepip() +{ + char buf[80]; + + if (ians(b_lines - 2, 0, "¯uªºn©ñ¥Í¶Ü(Y/N)¡H[N] ") == 'y') + { + sprintf(buf, "\033[1;31m%s ³Q¬½¤ßªº %s ¥á±¼¤F~\033[m", d.name, cuser.userid); + pipdie(buf, 2); + return 1; + } + return 0; +} + + +int +pip_system_service() +{ + int choice; + char buf[128]; + + out_cmd("", COLOR1 " ªA°È " COLOR2 " [1]©R¦W¤j®v [2]Åܩʤâ³N [3]µ²§½³]§½ [Q]Â÷¶} \033[m"); + + switch (vkey()) + { + case '1': + vget(b_lines - 2, 0, "À°¤pÂû«·s¨úÓ¦n¦W¦r¡G", buf, 11, DOECHO); + if (!buf[0]) + { + vmsg("µ¥¤@¤U·Q¦n¦A¨Ó¦n¤F :)"); + } + else + { + strcpy(d.name, buf); + vmsg("¶â¶â ´«¤@Ó·sªº¦W¦r³á..."); + } + break; + + case '2': /* ÅÜ©Ê */ + if (d.sex == 1) /* 1:¤½ 2:¥À */ + { + choice = 2; /* ¤½-->¥À */ + sprintf(buf, "±N¤pÂû¥Ñ¡ñÅܩʦ¨¡ðªº¶Ü(Y/N)¡H[N] "); + } + else + { + choice = 1; /* ¥À-->¤½ */ + sprintf(buf, "±N¤pÂû¥Ñ¡ðÅܩʦ¨¡ñªº¶Ü(Y/N)¡H[N] "); + } + if (ians(b_lines - 2, 0, buf) == 'y') + { + d.sex = choice; + vmsg("Åܩʤâ³N§¹²¦..."); + } + break; + + case '3': + /* 1:¤£n¥B¥¼±B 4:n¥B¥¼±B */ + if (d.wantend == 1 || d.wantend == 2 || d.wantend == 3) + { + choice = 3; /* ¨S¦³-->¦³ */ + sprintf(buf, "±N¤pÂû¹CÀ¸§ï¦¨¡i¦³20·³µ²§½¡j(Y/N)¡H[N] "); + } + else + { + choice = -3; /* ¦³-->¨S¦³ */ + sprintf(buf, "±N¤pÂû¹CÀ¸§ï¦¨¡i¨S¦³20·³µ²§½¡j(Y/N)¡H[N] "); + } + if (ians(b_lines - 2, 0, buf) == 'y') + { + d.wantend += choice; + vmsg("¹CÀ¸µ²§½³]©w§¹²¦..."); + } + break; + } + return 0; +} +#endif /* HAVE_GAME */ diff --git a/pip/pip_visio.c b/pip/pip_visio.c new file mode 100644 index 0000000..b063775 --- /dev/null +++ b/pip/pip_visio.c @@ -0,0 +1,299 @@ +/*-------------------------------------------------------*/ +/* pipvisio.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¾i¤pÂû¹CÀ¸ */ +/* create : / / */ +/* update : 01/08/03 */ +/* author : dsyan.bbs@forever.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/* picture: tiball.bbs@bbs.nhctc.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#include "pip.h" + + +#if 0 /* itoc.010803.µù¸Ñ:¿Ã¹õ°t¸m */ + +³Ì«e± ¤@¨Ç¸ê®ÆÅã¥Ü + +¤¤¶¡ ¹Ï + +b_lines - 2 ¸ß°Ý¦C +b_lines - 1 «ü¥O¦C +b_lines «ü¥O¦C + +#endif + + + +/*-------------------------------------------------------*/ +/* «ü¥O¨ú±o */ +/*-------------------------------------------------------*/ + + +int /* itoc.010802: ¨ú¥N vans("Y/N¡H[Y] ") ³oÃþ°ÝÃD¥Îªº¨ç¦¡ */ +ians(x, y, msg) + int x, y; /* itoc.010803: ¤@¯ë®³ (b_lines - 2, 0) ¨Ó·í¸ß°Ý¦C */ + char *msg; +{ + move(x, 0); /* ²M±¼¾ã¦C */ + clrtoeol(); + move(x, y); + outs(msg); + outs("\033[47m \033[m"); + move(x, y + strlen(msg)); /* ²¾¼Ð²¾°Ê®Ø®Ø¤º */ + return vkey(); /* ¥u«öÁä¡A¤£»Ýn«ö ENTER */ + +#if 0 + if (ch >= 'A' && ch <= 'Z') + ch |= 0x20; /* ´«¤p¼g */ +#endif +} + + +/*-------------------------------------------------------*/ +/* ¿Ã¹õ±±¨î */ +/*-------------------------------------------------------*/ + + +void +clrfromto(from, to) /* ²M°£ from~to ¦C¡A³Ì«á´å¼Ð°±¯d¦b (from, 0) */ + int from, to; +{ + while (to >= from) + { + move(to, 0); + clrtoeol(); + to--; + } +} + + +static int /* 1: Àɮצb 0: Àɮפ£¦b */ +show_file(fpath, ln, lines) /* ±q²Ä ln ¦C¶}©l¦LÀÉ®× lines ¦C */ + char *fpath; + int ln, lines; +{ + FILE *fp; + char buf[ANSILINELEN]; + int i; + + if ((fp = fopen(fpath, "r"))) + { + clrfromto(ln, ln + lines); + i = lines; + while (fgets(buf, ANSILINELEN, fp) && i--) + outs(buf); + fclose(fp); + return 1; + } + + /* itoc.010802: ¦^³øÀɮ׿ò¥¢ */ + sprintf(buf, "%s ¿ò¥¢¡A½Ð§iª¾¯¸ªø", fpath); + zmsg(buf); + return 0; +} + + +/*-------------------------------------------------------*/ +/* ¤pÂû¹Ï§Î°Ï */ +/*-------------------------------------------------------*/ + + +/* itoc.010801: ½Ð¨Ì·Ó¦U show_xxx_pic() ¤¤ show_file(buf, ln, lines) ªº lines ¨Ó±±¨î¹Ï®×¦C¼Æ */ +/* itoc.010801: ¥¿±`ª¬ªp¤U³£¬O 10 ¦C (è¦n¤]¬O°ÊºA¬ÝªOªº¦C¼Æ)¡CY ln=0 ¥B lines=b_lines+1 ªí¥Ü¾ãӿùõ¥þ²M */ + + +/* -------------------- */ +/* ¤@¯ëªº¹Ï¡A¦b 7~16 ¦C */ +/* -------------------- */ + +int +show_basic_pic(i) + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "basic/pic%d", i); + return show_file(buf, 7, 10); +} + + +int +show_feed_pic(i) /* ¦YªF¦è */ + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "feed/pic%d", i); + return show_file(buf, 7, 10); +} + + +int +show_usual_pic(i) /* ¥±`ª¬ºA */ + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "usual/pic%d", i); + return show_file(buf, 7, 10); +} + + +int +show_special_pic(i) /* ¯S®í¿ï³æ */ + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "special/pic%d", i); + return show_file(buf, 7, 10); +} + +int +show_practice_pic(i) /* צæ¥Îªº¹Ï */ + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "practice/pic%d", i); + return show_file(buf, 7, 10); +} + + +int +show_job_pic(i) /* ¥´¤uªºshow¹Ï */ + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "job/pic%d", i); + return show_file(buf, 7, 10); +} + + +int +show_play_pic(i) /* ¥ð¶¢ªº¹Ï */ + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "play/pic%d", i); + return show_file(buf, 7, 10); +} + + +int +show_guess_pic(i) /* ²q®±¥Î */ + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "guess/pic%d", i); + return show_file(buf, 7, 10); +} + + +int +show_badman_pic(i) /* ©Çª« */ + int i; +{ + char buf[64]; + +/* itoc.010731: picabc abc ¬O½s¸¹ + ¦Ê¦ì¼Æ a ¬O¤ÀÃþ¡A¤Q¦ì¼ÆÓ¦ì¼Æ bc ¬O¸ÓÃþ¹Ïªº½s¸¹ */ + + sprintf(buf, PIP_PICHOME "badman/pic%03d", i); + return show_file(buf, 7, 10); +} + + +int +show_fight_pic(i) /* ¥´¬[ */ + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "fight/pic%d", i); + return show_file(buf, 7, 10); +} + + +int +show_resultshow_pic(i) /* ¦¬Ã¬©u */ + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "resultshow/pic%d", i); + return show_file(buf, 7, 10); +} + + +int +show_quest_pic(i) /* ¥ô°È */ + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "quest/pic%d", i); + return show_file(buf, 7, 10); +} + + +/* -------------------------- */ +/* ¤@¨Ç¯S®íªº¹Ï¡A¨q¦b 1~10 ¦C */ +/* -------------------------- */ + +int +show_weapon_pic(i) /* ªZ¾¹¥Î */ + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "weapon/pic%d", i); + return show_file(buf, 1, 10); +} + + +int +show_palace_pic(i) /* °Ñ¨£¤ý¦Ú¥Î */ + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "palace/pic%d", i); + return show_file(buf, 1, 10); +} + + +/* ------------------------------------- */ +/* ¤@¨Ç¯S®íªº¹Ï¡A¨q¦b 4~19(b_lines-4) ¦C */ +/* ------------------------------------- */ + +int +show_system_pic(i) /* ¨t²Î */ + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "system/pic%d", i); + return show_file(buf, 4, 16); +} + + +int +show_ending_pic(i) /* µ²§ô */ + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "ending/pic%d", i); + return show_file(buf, 4, 16); +} + + +/* -------------------------- */ +/* ¤@¨Ç¯S®íªº¹Ï¡A¨q¦b¾ãӿùõ */ +/* -------------------------- */ + +int +show_die_pic(i) /* ¦º¤` */ + int i; +{ + char buf[64]; + sprintf(buf, PIP_PICHOME "die/pic%d", i); + return show_file(buf, 0, b_lines + 1); +} +#endif /* HAVE_GAME */ diff --git a/pip/pip_weapon.c b/pip/pip_weapon.c new file mode 100644 index 0000000..532abe4 --- /dev/null +++ b/pip/pip_weapon.c @@ -0,0 +1,241 @@ +/* ----------------------------------------------------- */ +/* pip_weapon.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/* ----------------------------------------------------- */ +/* target : ¤pÂû weapon structure */ +/* create : / / */ +/* update : 01/08/15 */ +/* author : dsyan.bbs@forever.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/* ----------------------------------------------------- */ + + +#include "bbs.h" + +#ifdef HAVE_GAME + +#include "pip.h" + + +/* ------------------------------------------------------- */ +/* ªZ¾¹ÁʶR¨ç¦¡ */ +/* ------------------------------------------------------- */ + + +/* name[11] quality cost */ +static weapon p[9]; /* °O¿ýªZ¾¹ */ + + +/* itoc.021031: ¬°¤F¼W¥[¹CÀ¸ªº¦h¼Ë©Ê¡A¼g¤@¤äªZ¾¹²£¥Í¾¹ */ +static void +weapon_generate(type) + int type; /* þ¤@³¡¤À¸Ë³Æ */ +{ + int i, num; + + char adje[14][5] = {"·lÃa", "¦A¥Í", "¤G¤â", "µ´ª©", "¶ì½¦", "¤û¥Ö", "¿ûÅK", "¶Àª÷", "¯S¯Å", "±OÀs", "§Ñ±¡", "±OÀs", "¸¤Ñ", "¶Ç©_"}; + char prep[13][3] = {"¯}", "Äê", "³¾", "¤§", "¨g", "¯P", "¬¯", "¸t", "Å]", "Ä_", "¥ú", "¯«", ""}; + char noun[5][9][5] = + { + /* ÀY³¡ªZ¾¹ */ "´U", "ÀY²¯", "ÀY¸n", "ÀY¤y", "ÀY¹¢", "¦Õ¾÷", "²´Ãè", "¾vãT", "¶µÁå", + /* ¤â³¡ªZ¾¹ */ "¼C", "¤M", "§ú", "´Î", "ºj", "¥Ù", "¤}", "Âñ", "§æ¤â", + /* ¬ÞµPªZ¾¹ */ "¿ö", "¬Þ", "§Ù«ü", "¤â®M", "¤âÀô", "Áu³¹", "¬ÞµP", "½Ò¥»", "Á¿¸q", + /* ¨ÅéªZ¾¹ */ "²¯¥Ò", "«`¥Ò", "¥Ö¥Ò", "©Ü·", "®M¸Ë", "¬v¸Ë", "¦çªA", "¢â«ò", "¤ò¦ç", + /* ¸}³¡ªZ¾¹ */ "¾c", "¹u", "®j", "¼i", "¶³", "½ü", "Äû", "´à", "½ñ" + }; + + for (i = 0; i < 9; i++) + { + /* ¨Ì¯à¤O¤Î¤âÀYªº¿ú¨Ó¨M©wªZ¾¹ªº¦nÃa */ + + if (d.money < 12) + { + p[i].quality = 1; + p[i].cost = d.money; + } + else + { + num = d.money / 1000 + 1; + if (num > 300) + num = 300; + num = rand() % num + 1; + p[i].quality = num; + p[i].cost = 3 * num * num; + } + + num = rand(); /* ¥Î¦P¤@¶Ã¼Æ¨Ó¨M©w adj+prep+noun¡A©Ò¥H mod ªº¼Æ¤£n¤@¼Ë */ + /* ¨Ìþ¤@³¡¤À¸Ë³Æ¨Ó¨M©wªZ¾¹¦WºÙ¡Aª`·N¦r¦êªø«× */ + sprintf(p[i].name, "%s%s%s", adje[num % 14], prep[num % 13], noun[type][num % 9]); + } +} + + +void +pip_weapon_wear(type, variance) /* ¸Ë³ÆªZ¾¹¡Apºâ¯à¤Oªº§ïÅÜ */ + int type; /* þ¤@³¡¤À¸Ë³Æ */ + int variance; /* ·sªZ¾¹ªº«~½è®t²§ */ +{ + /* ¨Ì¸Ë³Æ³¡¦ì¤£¦P¨Ó§ïÅÜ«ü¼Æ */ + if (type == 0) /* ÀY³¡ªZ¾¹ */ + { + d.speed += variance; + d.immune += variance; + } + else if (type == 1) /* ¤â³¡ªZ¾¹ */ + { + d.attack += variance; + d.immune += variance; + } + else if (type == 2) /* ¬ÞµPªZ¾¹ */ + { + d.attack += variance; + d.resist += variance; + } + else if (type == 3) /* ¨ÅéªZ¾¹ */ + { + d.resist += variance; + d.immune += variance; + } + else if (type == 4) /* ¸}³¡ªZ¾¹ */ + { + d.attack += variance; + d.speed += variance; + } +} + + +static int +pip_weapon_doing_menu(quality, type, name) /* ªZ¾¹ÁʶRµe± */ + int quality; /* ¶Ç¤J¥Ø«e°tÀ¹ */ + int type; /* þ¤@³¡¤À¸Ë³Æ */ + char *name; +{ + char menutitle[5][11] = {"ÀY³¡¸Ë³Æ°Ï", "¤â³¡¸Ë³Æ°Ï", "¬ÞµP¸Ë³Æ°Ï", "¨Åé¸Ë³Æ°Ï", "¸}³¡¸Ë³Æ°Ï"}; + char buf[80]; + int n; + + /* ¶Ã¼Æ²£¥ÍªZ¾¹ */ + weapon_generate(type); + + /* ¦L¥XªZ¾¹¦Cªí */ + vs_head(menutitle[type], str_site); + show_weapon_pic(0); + move(11, 0); + outs(" \033[1;37;41m [NO] [ªZ¾¹¦WºÙ] [«~½è] [°â»ù] \033[m\n"); + + /* ¦L¥XªZ¾¹³æ¶µ */ + for (n = 0; n < 9; n++) + prints(" %d %-10s %6d %6d\n", n, p[n].name, p[n].quality, p[n].cost); + + /* ¿ï³æ³B²z */ + while (1) + { + out_cmd("", COLOR1 " ±Ä¶R " COLOR2 " (x¤õ³c¤l) [B]ÁʶRªZ¾¹ [E]±j¤ÆªZ¾¹ [D]©ß±óªZ¾¹ [Q]¸õ¥X \033[m"); + + switch (vkey()) + { + case 'b': + sprintf(buf, "±z¦³ %d ¤¸¡A·QnÁʶRÔ£©O¡H[Q] ", d.money); + n = ians(b_lines - 2, 1, buf) - '0'; + + if (n >= 0 && n < 9) + { + sprintf(buf, "½T©wnÁʶR»ùÈ %d ¤¸ ªº%s¶Ü(Y/N)¡H[N] ", p[n].cost, p[n].name); + if (ians(b_lines - 2, 1, buf) == 'y') + { + /* ´«ªZ¾¹ */ + d.money -= p[n].cost; + strcpy(name, p[n].name); + pip_weapon_wear(type, p[n].quality - quality); + quality = p[n].quality; + + sprintf(buf, "¤pÂû¤w¸g¸Ë°t¤W%s¤F", name); + vmsg(buf); + } + else + { + vmsg("©ñ±óÁʶR"); + } + } + break; + + case 'e': + n = quality * 100; + if (quality && d.money >= n) + { + sprintf(buf, "½T©wnªá %d ¤¸¨Ó´£¤É%sªº¼ç¯à¶Ü(Y/N)¡H[N] ", n, name); + if (ians(b_lines - 2, 1, buf) == 'y') + { + /* «~½è¶V¦nªºªZ¾¹±j¤Æ¦¬¶O¶V°ª */ + d.money -= n; + quality++; + pip_weapon_wear(type, 1); + } + } + break; + + case 'd': + sprintf(buf, "½T©wn©ß±ó%s¶Ü(Y/N)¡H[N] ", name); + if (ians(b_lines - 2, 1, buf) == 'y') + { + pip_weapon_wear(type, -quality); + name[0] = '\0'; + quality = 0; + } + break; + + case 'q': + case KEY_LEFT: + return quality; + } + + /* itoc.010816: ®ø±¼ ians() ¯d¤Uªº´ÝÀe */ + move (b_lines - 2, 0); + clrtoeol(); + } +} + + +/*-------------------------------------------------------*/ +/* ªZ¾¹°Ó©±¿ï³æ: ¦U³¡¦ì */ +/*-------------------------------------------------------*/ + + +int +pip_store_weapon_head() /* ÀY³¡ªZ¾¹ */ +{ + d.weaponhead = pip_weapon_doing_menu(d.weaponhead, 0, d.equiphead); + return 0; +} + + +int +pip_store_weapon_hand() /* ¤â³¡ªZ¾¹ */ +{ + d.weaponhand = pip_weapon_doing_menu(d.weaponhand, 1, d.equiphand); + return 0; +} + + +int +pip_store_weapon_shield() /* ¬ÞµPªZ¾¹ */ +{ + d.weaponshield = pip_weapon_doing_menu(d.weaponshield, 2, d.equipshield); + return 0; +} + + +int +pip_store_weapon_body() /* ¨ÅéªZ¾¹ */ +{ + d.weaponbody = pip_weapon_doing_menu(d.weaponbody, 3, d.equipbody); + return 0; +} + + +int +pip_store_weapon_foot() /* ¸}³¡ªZ¾¹ */ +{ + d.weaponfoot = pip_weapon_doing_menu(d.weaponfoot, 4, d.equipfoot); + return 0; +} +#endif /* HAVE_GAME */ diff --git a/pip/pipglobal.h b/pip/pipglobal.h new file mode 100644 index 0000000..fc9ad18 --- /dev/null +++ b/pip/pipglobal.h @@ -0,0 +1,59 @@ +/*-------------------------------------------------------*/ +/* pip_global.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : global definitions & variables */ +/* create : 01/07/25 */ +/* update : 01/08/02 */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#ifndef _PIP_GLOBAL_H_ +#define _PIP_GLOBAL_H_ + + +#ifdef _PIPMAIN_C_ +# define VAR +# define INI(x) = x +#else +# define VAR extern +# define INI(x) +#endif + + +/* ----------------------------------------------------- */ +/* GLOBAL DEFINITION */ +/* ----------------------------------------------------- */ + + + /* --------------------------------------------------- */ + /* ¹CÀ¸¦WºÙ³]©w */ + /* --------------------------------------------------- */ + + +#define PIPNAME "Ãdª«Âû" + + + /* --------------------------------------------------- */ + /* Ó¤H¥Ø¿ýÀɦW³]©w */ + /* --------------------------------------------------- */ + + +#define FN_PIP "chicken" + +VAR char *fn_pip INI(FN_PIP); + + +/* ----------------------------------------------------- */ +/* GLOBAL VARIABLE */ +/* ----------------------------------------------------- */ + + +VAR struct CHICKEN d; /* ¤pÂûªº¸ê®Æ */ + +VAR time_t start_time; /* ¥»¦¸¹CÀ¸¶}©l®É¶¡ */ +VAR time_t last_time; /* ¤W¦¸§ó·s®É¶¡ */ + +#undef VAR + +#endif /* _PIP_GLOBAL_H_ */ diff --git a/pip/pipstruct.h b/pip/pipstruct.h new file mode 100644 index 0000000..818bf3d --- /dev/null +++ b/pip/pipstruct.h @@ -0,0 +1,430 @@ +/* ----------------------------------------------------- */ +/* pip_struct.h ( NTHU CS MapleBBS Ver 3.10 ) */ +/* ----------------------------------------------------- */ +/* target : ¤pÂû data structure */ +/* create : / / */ +/* update : 01/08/14 */ +/* author : dsyan.bbs@@forever.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/* ----------------------------------------------------- */ + + +#ifndef _PIP_STRUCT_H_ +#define _PIP_STRUCT_H_ + + +/* ------------------------------------------------------- */ +/* ¤pÂû°Ñ¼Æ³]©w */ +/* ------------------------------------------------------- */ + + +struct CHICKEN +{ + /* ---©m¦W¤Î¥Í¤é--- */ + char name[IDLEN + 1]; /* ©m ¦W */ + char birth[9]; /* ¥Í ¤é */ + + /* ---¤pÂûªº®É¶¡--- */ + time_t bbtime; /* ª±¤pÂûªºÁ`®É¶¡(¬í) */ + /* itoc.010804: ¥Ø«eªº³]©w¬O 30 ¤À(§Y30*60¬í) ¬°¤@·³ */ + + /* ¥H¤U¥þ¬O integer */ + /* ¨C¤@ºØÃþ«¬³£«O¯d¦Ü¤QÄæ¥H·Ç³ÆÂX¥R */ + /* ¨S¦³µù¸Ñªº³o¨Ç³£¬O«O¯d¡A¨S¦³¨Ï¥ÎªºÄæ¦ì */ + + /* ---°ò¥»¸ê®Æ--- */ + int year; /* ¥Í¤é ¦~ */ + int month; /* ¥Í¤é ¤ë */ + int day; /* ¥Í¤é ¤é */ + int sex; /* ©Ê §O 1:¡ñ 2:¡ð */ + int death; /* ª¬ ºA 1:¦º¤` 2:©ß±ó 3:µ²§ô */ + int liveagain; /* ´_¬¡¦¸¼Æ */ + int wantend; /* 20·³µ²§½ 1:¤£n¥B¥¼±B 2:¤£n¥B¤w±B 3:¤£n¥B·í²Ä¤TªÌ 4:n¥B¥¼±B 5:n¥B¤w±B 6:n¥B·í²Ä¤TªÌ */ + int lover; /* ·R¤H 0:¨S¦³ 1:Å]¤ý 2:Às±Ú 3:A 4:B 5:C 6:D 7:E */ + int seeroyalJ; /* ¬O§_¥i¥H¹J¤W¤ý¤l/¤½¥D 1:¥i¥H(¤ý¤l¤w¸g¦^°ê¤F) 0:¤£¯à(¤ý¤lÁÙ¦bÃäæ) */ + int quest; /* ¥ô °È 0:µL¥ô°È !=0:¥ô°È½s¸¹ */ + + /* ---ª¬ºA«ü¼Æ--- */ + /* itoc.010730: ³o¨Ç«ü¼Æ¦b¤u§@/¾Ç²ß/¹Cª±¤¤§ïÅÜ */ + int relation; /* ¿Ë¤lÃö«Y (¤H©MÃdª«ªº¤¬°ÊÃö«Y) */ + int happy; /* §Ö ¼Ö «× */ + int satisfy; /* º¡ ·N «× */ + int fallinlove; /* ÅÊ·R«ü¼Æ */ + int belief; /* «H ¥õ */ + int sin; /* ¸o Ä^ */ + int affect; /* ·P ¨ü */ + int state7; + int state8; + int state9; + + /* ---°·±d«ü¼Æ--- */ + /* itoc.010730: ³o¨Ç«ü¼Æ¦b¤u§@/¾Ç²ß/¹Cª±¤¤§ïÅÜ */ + int weight; /* Åé « */ + int tired; /* ¯h ³Ò «× */ + int sick; /* ¯f ®ð */ + int shit; /* ²M ¼ä «× */ + int body4; + int body5; + int body6; + int winn; /* ²q®±Ä¹ªº¦¸¼Æ */ + int losee; /* ²q®±¿éªº¦¸¼Æ */ + int tiee; /* ²q®±¥¤âªº¦¸¼Æ */ + + /* ---µû»ù°Ñ¼Æ--- */ + int social; /* ªÀ¥æµû»ù */ + int family; /* ®a¨Æµû»ù */ + int hexp; /* ¾Ô°«µû»ù */ + int mexp; /* Å]ªkµû»ù */ + int value4; + int value5; + int value6; + int value7; + int value8; + int value9; + + /* ---¯à¤O°Ñ¼Æ--- */ + /* itoc.010730: ³o¨Ç«ü¼Æ¦b¾Ç²ß¤¤¤j¶q§ïÅÜ¡A¦b¤u§@¤¤·L¶q½Õ¾ã */ + int toman; /* «Ý¤H±µª« */ + int character; /* ®ð ½è «× */ + int love; /* ·R ¤ß */ + int wisdom; /* ´¼ ¤O */ + int art; /* ÃÀ³N¯à¤O */ + int etchics; /* ¹D ¼w */ + int brave; /* «i ´± */ + int homework; /* ±½¦a¬~¦ç */ + int charm; /* ¾y ¤O */ + int manners; /* § »ö */ + int speech; /* ½Í ¦R */ + int cook; /* ²i ¶¹ */ + int attack; /* §ð À» ¤O */ + int resist; /* ¨¾ ¿m ¤O */ + int speed; /* ³t «× */ + int hskill; /* ¾Ô°«§Þ³N */ + int mskill; /* Å]ªk§Þ³N */ + int immune; /* §ÜÅ]¯à¤O */ + int learn18; + int learn19; + + /* ---¾Ô°««ü¼Ð--- (ÀH¤É¯Å¦Ó¼W¥[) */ + /* itoc.010730: ¬°¤F¼W¥[¾Ô°«ªº¥²n©Ê¡Amaxhp maxmp maxvp maxsp + ³o¨ÇÄÝ©ÊÀ³¸Ó¥u¦b exp ¼W¥[¤É¯Å«á¡A¤~¯à¤j¶q¼W¥[ */ + /* itoc.010804: ¥Ø«e®e³\¦b¬Y¨Çª¬ªp¤U maxhp ¥H 0~3 ÂIªº³t«×¼W¥[ */ + + int level; /* µ¥ ¯Å */ + int exp; /* ¸g Åç È */ + int hp; /* Health Point ¦å */ + int maxhp; /* ³Ì¤j¦å */ + int mp; /* Mana Point ªk¤O */ + int maxmp; /* ³Ì¤jªk¤O */ + int vp; /* moVe Point ²¾°Ê¤O */ + int maxvp; /* ³Ì¤j²¾°Ê¤O */ + int sp; /* Spirit Point ¤º¤O */ + int maxsp; /* ³Ì¤j¤º¤O */ + + /* ---©Ò¾Ç·|§Þ¯à--- */ /* bitwise operation */ + usint skillA; /* §Þ¯à: Å@¨ */ + usint skillB; /* §Þ¯à: »´¥\ */ + usint skillC; /* §Þ¯à: ¤ßªk */ + usint skillD; /* §Þ¯à: ®±ªk */ + usint skillE; /* §Þ¯à: ¼Cªk */ + usint skillF; /* §Þ¯à: ¤Mªk */ + usint skillG; /* §Þ¯à: ·t¾¹¡B¬r */ + usint skill7; + usint skill8; + usint skillXYZ; /* ¯S®í§Þ¯à */ + usint spellA; /* ªvÀøªk³N */ + usint spellB; /* ¹p¨tªk³N */ + usint spellC; /* ¦B¨tªk³N */ + usint spellD; /* ª¢¨tªk³N */ + usint spellE; /* ¤g¨tªk³N */ + usint spellF; /* ·¨tªk³N */ + usint spellG; /* ¨s·¥ªk³N */ + usint spell7; + usint spell8; + usint spell9; + + /* ---ªZ¾¹ªº°Ñ¼Æ--- */ + int weaponhead; /* ÀY³¡ªZ¾¹ */ + int weaponhand; /* ¤â³¡ªZ¾¹ */ + int weaponshield; /* ¬ÞµPªZ¾¹ */ + int weaponbody; /* ¨ÅéªZ¾¹ */ + int weaponfoot; /* ¸}³¡ªZ¾¹ */ + int weapon5; + int weapon6; + int weapon7; + int weapon8; + int weapon9; + + /* ---¦YªºªF¦è--- */ + int food; /* ¹ ª« */ + int cookie; /* ¹s ¹ */ + int eat2; + int pill; /* ¤j ÁÙ ¤¦ : ¸É¦å */ + int medicine; /* ÆF ªÛ : ¸Éªk¤O */ + int burger; /* ¤j ¸É ¤Y : ¸É²¾°Ê¤O */ + int ginseng; /* ¤d¦~¤Hçx : ¸É¤º¤O */ + int paste; /* ¶Â¥ÉÂ_Äò»I : ¦å¥þº¡ */ + int snowgrass; /* ¤Ñ¤s³·½¬ : ³q³q¥þº¡ */ + int eat9; + + /* ---¾Ö¦³ªºªF¦è--- */ + int money; /* ª÷ ¿ú */ + int book; /* ®Ñ ¥» */ + int toy; /* ª± ¨ã */ + int playboy; /* ½Ò¥~Ūª« */ + int thing4; + int thing5; + int thing6; + int thing7; + int thing8; + int thing9; + + /* ---°Ñ¨£¤ý¦Ú-- */ + int royalA; /* ©M ¦u½Ã ªº¦n·P */ + int royalB; /* ©M ªñ½Ã ªº¦n·P */ + int royalC; /* ©M ±Nx ªº¦n·P */ + int royalD; /* ©M ¤j¦Ú ªº¦n·P */ + int royalE; /* ©M ²½¥q ªº¦n·P */ + int royalF; /* ©M Ãd¦m ªº¦n·P */ + int royalG; /* ©M ¤ý¦m ªº¦n·P */ + int royalH; /* ©M °ê¤ý ªº¦n·P */ + int royalI; /* ©M ¤p¤¡ ªº¦n·P */ + int royalJ; /* ©M ¤ý¤l/¤½¥D ªº¦n·P */ + + /* -------¤u§@¦¸¼Æ-------- */ + int workA; /* ®a¨Æ */ + int workB; /* «O©i */ + int workC; /* ®È©± */ + int workD; /* ¹A³õ */ + int workE; /* À\ÆU */ + int workF; /* ±Ð°ó */ + int workG; /* ¦aÅu */ + int workH; /* ¥ï¤ì */ + int workI; /* ¬ü¾v */ + int workJ; /* Ây¤H */ + int workK; /* ¤u¦a */ + int workL; /* ¦u¹Ó */ + int workM; /* ®a±Ð */ + int workN; /* °s®a */ + int workO; /* °s©± */ + int workP; /* ©]Á`·| */ + int work16; + int work17; + int work18; + int work19; + + /* -------¤W½Ò¦¸¼Æ-------- */ + int classA; /* ¦ÛµM¬ì¾Ç */ + int classB; /* ð¸Ö§ºµü */ + int classC; /* ¯«¾Ç±Ð¨| */ + int classD; /* x¾Ç±Ð¨| */ + int classE; /* ¼C¹D§Þ³N */ + int classF; /* ®æ°«¾Ô§Þ */ + int classG; /* Å]ªk±Ð¨| */ + int classH; /* §»ö±Ð¨| */ + int classI; /* øµe§Þ¥© */ + int classJ; /* »RÁЧޥ© */ + int class10; + int class11; + int class12; + int class13; + int class14; + int class15; + int class16; + int class17; + int class18; + int class19; + + /* ---ªZ¾¹ªº¦WºÙ--- */ + char equiphead[11]; /* ÀY³¡ªZ¾¹¦WºÙ */ + char equiphand[11]; /* ¤â³¡ªZ¾¹¦WºÙ */ + char equipshield[11]; /* ¬ÞµPªZ¾¹¦WºÙ */ + char equipbody[11]; /* ¨ÅéªZ¾¹¦WºÙ */ + char equipfoot[11]; /* ¸}³¡ªZ¾¹¦WºÙ */ + char equip5[11]; + char equip6[11]; + char equip7[11]; + char equip8[11]; + char equip9[11]; +}; +typedef struct CHICKEN CHICKEN; + + +/* ------------------------------------------------------- */ +/* ª««~°Ñ¼Æ³]©w */ +/* ------------------------------------------------------- */ + +struct itemset +{ + int num; /* ½s¸¹ */ + char *name; /* ¦W¦r */ + char *msgbuy; /* ¥\¥Î */ + char *msguse; /* »¡©ú */ + int price; /* »ù®æ */ +}; +typedef struct itemset itemset; + + +/* ------------------------------------------------------- */ +/* °Ñ¨£¤ý¦Ú°Ñ¼Æ³]©w */ +/* ------------------------------------------------------- */ + +struct royalset +{ + char *num; /* ¥N½X */ + char *name; /* ¤ý¦Úªº¦W¦r */ + int needmode; /* »Ýnªºmode *//* 0:¤£»Ýn 1:§»ö 2:½Í¦R */ + int needvalue; /* »Ýnªºvalue */ + int addtoman; /* ³Ì¤jªº¼W¥[¶q */ + int maxtoman; /* ®w¦s¶q */ + char *words1; + char *words2; +}; +typedef struct royalset royalset; + + +/* ------------------------------------------------------- */ +/* §Þ¯à°Ñ¼Æ³]©w */ +/* ------------------------------------------------------- */ + + +#if 0 /* itoc.010729.»¡©ú */ + + smode n¹ïÀ³ struce CHICKEN ªºªº skill/spell + smode = +1 ¬° skillA¡Asmode = +2 ¬° skillB + smode = -1 ¬° spellA¡Asmode = -2 ¬° spellB + + sno ¬O¦¹§Þ¯àªº½s¸¹¡A¨Ò¦p 0x01 ¬O¼Cªk¥Ò¡A0x02 ¬O¼Cªk¤A¡A0x04 ¬O¼Cªk¤þ (ª`·N¬O bit operation) + sbasic «h¬O¦¹§Þ¯àªº°ò¥»§Þ¯à¡AYn¥ý¾Ç²ß¼Cªk¥Ò¤þ¥H«á¤~¯à¾Ç²ß¼Cªk¤B¡A¨º»ò¼Cªk¤Bªº sbasic = 0x01 | 0x04 = 0x05 + + needhp/nedmp/addtired Y¬O¥¿ªº¡A´N¬O¦©¦å/¦©ªk¤O/¥[¯h³Ò + +#endif + + +struct skillset +{ + int smode; /* skill mode 0:¯S®í >0:ªZ¥\ <0:Å]ªk */ + usint sno; /* skill number */ + usint sbasic; /* basic skill */ + char name[13]; /* §Þ¯àªº¦W¦r¡A¨î¤»Ó¤¤¤å¦r */ + int needhp; /* ¥Í©R¤Oªº§ïÅÜ */ + int needmp; /* ªk¤Oªº§ïÅÜ */ + int needvp; /* ²¾°Ê¤Oªº§ïÅÜ */ + int needsp; /* ¤º¤Oªº§ïÅÜ */ + int addtired; /* ¯h³ÒȪº§ïÅÜ */ + int effect; /* ®ÄªG/±j®z */ + int pic; /* ¹ÏÀÉ */ + char msg[41]; /* ¨Ï¥Î§Þ¯àªº»¡©ú¡A¨î20Ó¤¤¤å¦r */ +}; +typedef struct skillset skillset; + + +/* ------------------------------------------------------- */ +/* ¿ï³æªº³]©w */ +/* ------------------------------------------------------- */ + +struct pipcommands +{ + int (*fptr) (); + int key; +}; +typedef struct pipcommands pipcommands; + + +/* ------------------------------------------------------- */ +/* ©Çª«°Ñ¼Æ³]©w */ +/* ------------------------------------------------------- */ + +struct playrule +{ + /* itoc.010731: ©Çª«¥u¦³ hp ³oºØ¦å¡A¤£»Ýn mp/vp/sp/tired¡A + ¥¦ªº§Þ¯à§ðÀ»µL¡A¦ý¬O©Çª«ªº§ðÀ»¼Ò¦¡¬O¥Ñ¶Ã¼Æ¨M©w¡A¦p¦¹¥i²³æ¤Æ */ + + /* itoc.010731: µ¥¯Å¬° n ¯Åªº©Çª«¡A¨ä´Á±æ + maxhp = 0.75*(n^2) (©Mª±®a¤@¼Ë) + attack/spirit/magic/armor/dodge = 10*n + money = 10*n + exp = 5*n (ì«h¤W¥´20°¦©Çª«¤É¤@¯Å) */ + + char name[13]; /* ¦W¦r¡A¨î¤»Ó¤¤¤å¦r */ + int attribute; /* ·R¥Îªº§ðÀ»§Þ¯à 0:µL >0:ªZ¥\ <0:Å]ªk */ + int hp; /* ¦å */ + int maxhp; /* ³Ì¤j¦å */ + + /* ¤À§O»P©Çª« ª«²z/ªZ¥\/Å]ªk §ðÀ»¤pÂû¥¿¬ÛÃö */ + int attack; /* ª«²z§ðÀ»¯à¤O */ + int spirit; /* ¤º¤O«ü¼Æ¡A§Þ¯à§ðÀ»¯à¤O */ + int magic; /* Å]ªk«ü¼Æ¡Aªk³N§ðÀ»¯à¤O */ + + /* ¤À§O»P¤pÂû¥´©Çª«ªº ¶Ë®`/©R¤¤²v t¬ÛÃö */ + int armor; /* ¨¾Å@«ü¼Æ¡A©Ó¨ü§ðÀ»ªº¯à¤O */ + int dodge; /* °{Á׫ü¼Æ¡A°{Á×§ðÀ»ªº¯à¤O */ + + /* ¥´¦º©Çª«ªº¼úÀy */ + int money; /* ¥´¦º©Çª«±o¨ìªº°]Ä_ */ + int exp; /* ¥´¦º©Çª«±o¨ìªº¸gÅçÈ */ + + int pic; /* ¹ÏÀÉ */ +}; +typedef struct playrule playrule; + + +/* ------------------------------------------------------- */ +/* ªZ¾¹°Ñ¼Æ³]©w */ +/* ------------------------------------------------------- */ + +struct weapon +{ + char name[11]; /* ¦WºÙ¡A¨î¤Ó¤¤¤å¦r */ + int quality; /* «~½è */ + int cost; /* »ù®æ */ +}; +typedef struct weapon weapon; + + +/* ------------------------------------------------------- */ +/* PK ¹ï¾Ô°Ñ¼Æ³]©w */ +/* ------------------------------------------------------- */ + + +#define MAX_PIPPK_USER 10 /* ³Ì¦h¦P®É¦³ 10 ¤H¦b PK ³õ¤¤ */ + +struct PTMP +{ + char inuse; /* 0:¥¼¨Ï¥Î 1:»W¶Õ«Ýµo 2:¤U¬D¾Ô®Ñ -1:¾Ô°«¤¤ */ + char done; /* 0:¥¼¦æ°Ê 1:¤w¦æ°Ê */ + char name[IDLEN + 1]; /* ©m¦W */ + char userid[IDLEN + 1]; /* ¦Û¤vªº ID */ + char mateid[IDLEN + 1]; /* ¹ï¤âªº ID */ + + int sex; /* ©Ê§O */ + int level; /* µ¥¯Å */ + + int hp; /* Health Point ¦å */ + int maxhp; /* ³Ì¤j¦å */ + int mp; /* Mana Point ªk¤O */ + int maxmp; /* ³Ì¤jªk¤O */ + int vp; /* moVe Point ²¾°Ê¤O */ + int maxvp; /* ³Ì¤j²¾°Ê¤O */ + int sp; /* Spirit Point ¤º¤O */ + int maxsp; /* ³Ì¤j¤º¤O */ + + int combat; /* ª«²z¨¬q: ¨M©w¡u¦×·i¡B¨¾¿m¡vªº±j«× */ + int magic; /* Å]ªk³y¸Ú: ¨M©w¡uªk³N-¦U¨t¡vªº±j«× */ + int speed; /* ±Ó±¶§Þ¥©: ¨M©w¡u§Þ¯à-Å@¨¡B§Þ¯à-»´¥\¡B§Þ¯à-¼Cªk¡vªº±j«× */ + int spirit; /* ¤º¤O±j«×: ¨M©w¡u§Þ¯à-¤ßªk¡B§Þ¯à-®±ªk¡B§Þ¯à-¤Mªk¡vªº±j«× */ + int charm; /* °Ê·P¾y¤O: ¨M©w¡u¾y´b¡B¥l³ê¡vªº±j«× */ + int oral; /* ¤fYÄaªe: ¨M©w¡u»¡ªA¡Bº´°Ê¡vªº±j«× */ + int cook; /* ¬ü¨ý²i½Õ: ¨M©w¡u§Þ¯à-·t¾¹¡Bªk³N-ªvÀø¡v */ +}; +typedef struct PTMP PTMP; + + +struct PCACHE +{ + PTMP pslot[MAX_PIPPK_USER]; /* PTMP slots */ +}; +typedef struct PCACHE PCACHE; + +#endif /* _PIP_STRUCT_H_ */ diff --git a/sh/bmta.sh b/sh/bmta.sh new file mode 100755 index 0000000..fb667ab --- /dev/null +++ b/sh/bmta.sh @@ -0,0 +1,8 @@ +#!/bin/sh +#¥»µ{¦¡¥Î¨Ó¤ÀªR³s±µ bbs ªº smtp ³s±µ¨Ó·½¼Æ¶q +cat /dev/null | awk 'BEGIN {printf("%10s %-20s\n", "³s½u¦¸¼Æ", "³s½u¨Ó·½")} {} END{}' + +cat /home/bbs/run/bmta.log.* | grep CONN | sort -k 3 -r | awk '{print $3}'| awk 'BEGIN {} {Number[$1]++} END { + for(course in Number) + printf("%10d %-20s\n", Number[course], course) +}' | sort -n -r diff --git a/sh/killbbs.sh b/sh/killbbs.sh new file mode 100755 index 0000000..71b1517 --- /dev/null +++ b/sh/killbbs.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# ²M°£¯¸¤W¨Ï¥ÎªÌ»Pshared memory +kill `ps -auxwww | grep bbsd | awk '{print $2}'` + +# for freebsd only +for i in `ipcs | grep bbs | awk '{print $3}'` +do + if [ $OSTYPE = "FreeBSD" ]; then + ipcrm -M $i + fi +done + +# Linux ½Ð¥Î ipcs ¤Î ipcrm shm diff --git a/sh/killhigh.sh b/sh/killhigh.sh new file mode 100755 index 0000000..3e37cb8 --- /dev/null +++ b/sh/killhigh.sh @@ -0,0 +1,3 @@ +#!/bin/sh +ps aux | awk '$3 > 30 {print $2}' | xargs kill -9 +# ¬å±¼¦Y¸ê·½ > 30 ªº process diff --git a/sh/killtop.sh b/sh/killtop.sh new file mode 100755 index 0000000..970147c --- /dev/null +++ b/sh/killtop.sh @@ -0,0 +1,2 @@ +#!/bin/sh +kill -9 `top | grep -w bbsd | grep RUN | awk '{print $1}'` diff --git a/sh/routin.sh b/sh/routin.sh new file mode 100755 index 0000000..57f6985 --- /dev/null +++ b/sh/routin.sh @@ -0,0 +1,45 @@ +#!/bin/bash +#################################################################### +#¬ÝªO±Æ¦æº]²Îp +basedir=/home/bbs/manage +logfile=/home/bbs/gem/@/@hotboard +hotweek=/home/bbs/gem/@/@hotweek +hotmonth=/home/bbs/gem/@/@hotmonth +yestarday=`date --date='1 day ago' +%y%m%d` +if [ ! -d "$basedir/brd" ]; then + mkdir -p $basedir/brd +fi +cp /home/bbs/run/brd_usies.log $basedir/brd/$yestarday.log +cat /home/bbs/run/brd_usies.log|awk '{print $1}'|uniq -c|awk '{printf "%-15s%s\n" ,$2,$1}'|sort -rn -k 2 > $basedir/board.log +echo "¬ÝªO¦WºÙ °ÑÆ[¤H¦¸"|awk '{printf("%-15s%s\n",$1,$2)}' > $logfile +echo "¦W¦¸ ¬ÝªO¦WºÙ °ÑÆ[¤H¦¸"|awk '{printf("%-8s%-15s%s\n",$1,$2,$3)}' > $hotweek +echo "¦W¦¸ ¬ÝªO¦WºÙ °ÑÆ[¤H¦¸"|awk '{printf("%-8s%-15s%s\n",$1,$2,$3)}' > $hotmonth +echo "-----------------------------" >> $logfile +echo "-----------------------------" >> $hotweek +echo "-----------------------------" >> $hotmonth +ls -l /home/bbs/brd|awk '$1 !~ /total/ {print $9}'|sed 's/\///' > $basedir/boardlist +echo "¥Ø«e¬ÝªOÓ¼Æ:`cat $basedir/boardlist|wc -l`" >> $logfile +cat $basedir/board.log >> $logfile +today=`date +%y%m%d` +find $basedir/brd -mtime -7 -type f -exec cat '{}' \;|awk '{print $1}'|sort|uniq -c|awk '{printf "%-15s%s\n" ,$2,$1}'|sort -rn -k 2 > $basedir/week +cat -b $basedir/week >> $hotweek +find $basedir/brd -mtime -30 -type f -exec cat '{}' \;|awk '{print $1}'|sort|uniq -c|awk '{printf "%-15s%s\n" ,$2,$1}'|sort -rn -k 2 > $basedir/month +cat -b $basedir/month >> $hotmonth +boards=`cat $basedir/boardlist` +for board in $boards +do + judge=`cat $basedir/board.log|grep "^$board"` + if [ "$judge" == "" ]; then + echo "$board 0"|awk '{printf("%-15s%s\n",$1,$2)}' >> $logfile + fi + judge=`cat $basedir/week|grep "^$board"` + if [ "$judge" == "" ]; then + echo "$board 0"|awk '{printf("%-15s%s\n",$1,$2)}' >> $hotweek + fi + judge=`cat $basedir/month|grep "^$board"` + if [ "$judge" == "" ]; then + echo "$board 0"|awk '{printf("%-15s%s\n",$1,$2)}' >> $hotmonth + fi +done +} +##################################################################### diff --git a/so/Makefile b/so/Makefile new file mode 100644 index 0000000..8422e52 --- /dev/null +++ b/so/Makefile @@ -0,0 +1,64 @@ +# ------------------------------------------------------ # +# Makefile ( NTHU CS MapleBBS Ver 2.36 ) # +# ------------------------------------------------------ # +# author : opus.bbs@bbs.cs.nthu.edu.tw # +# target : Makefile for MapleBBS main programs # +# create : 95/03/29 # +# update : 95/12/15 # +# ------------------------------------------------------ # + + +# ------------------------------------------------------ # +# ¤U¦Cªº make rules ¤£»Ý×§ï # +# ------------------------------------------------------ # + + +SO = admutil.so aloha.so bank.so chat.so help.so innbbs.so manage.so newbrd.so \ + song.so vote.so xyz.so \ + calendar.so classtable.so credit.so todo.so + + +.SUFFIXES: +.SUFFIXES: .c .o .so + +.c.o: ; $(CC) $(CFLAGS) -c $*.c +.o.so: ; ld -s -G $*.o -o $*.so -L../lib -ldao + + +all: + @echo "Please enter 'make sys-type', " + @echo " make sun : for Sun-OS 4.x and maybe some BSD systems, cc or gcc" + @echo " make linux : for Linux" + @echo " make solaris : for Sun-OS 5.x gcc" + @echo " make sol-x86 : for Solaris 7 x86" + @echo " make freebsd : for BSD 4.4 systems" + @echo " make bsd : for BSD systems, cc or gcc, if not in the above lists" + @echo " make cygwin : for Microsoft Windows and Cygwin gcc" + +sun: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -fomit-frame-pointer -Wunused -I../include" $(SO) + +linux: + @$(MAKE) CC=gcc CFLAGS="-DLINUX -O2 -pipe -fomit-frame-pointer -Wunused -I../include" $(SO) + +solaris: + @$(MAKE) CC=gcc CFLAGS="-DSOLARIS -DSYSV -O2 -pipe -fomit-frame-pointer -Wunused -I../include" $(SO) + +sol-x86: + @$(MAKE) CC=gcc CFLAGS="-DSOLARIS -DSYSV -O2 -fomit-frame-pointer -Wunused -I../include" $(SO) + +freebsd: + @$(MAKE) CC=gcc CFLAGS="-DBSD44 -O2 -pipe -fomit-frame-pointer -Wunused -I../include" $(SO) + +bsd: + @$(MAKE) CC=gcc CFLAGS="-DBSD44 -O2 -pipe -fomit-frame-pointer -Wunused -I../include" $(SO) + +cygwin: + @cd ../maple; make cygwin + + +install: $(SO) + install -m 0700 $? $(HOME)/bin + +clean: + rm -f *.so *.o *~ diff --git a/so/admutil.c b/so/admutil.c new file mode 100644 index 0000000..9034f6b --- /dev/null +++ b/so/admutil.c @@ -0,0 +1,883 @@ +/*-------------------------------------------------------*/ +/* admutil.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¯¸ªø«ü¥O */ +/* create : 95/03/29 */ +/* update : 01/03/01 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +extern BCACHE *bshm; +extern UCACHE *ushm; + + +/* ----------------------------------------------------- */ +/* ¯¸°È«ü¥O */ +/* ----------------------------------------------------- */ + + +int +a_user() +{ + int ans; + ACCT acct; + + move(1, 0); + clrtobot(); + + while (ans = acct_get(msg_uid, &acct)) + { + if (ans > 0) + acct_setup(&acct, 1); + } + return 0; +} + + +int +a_search() /* itoc.010902: ¼É¤O·j´M¨Ï¥ÎªÌ */ +{ + ACCT acct; + char c; + char key[30]; + + if (!vget(b_lines, 0, "½Ð¿é¤JÃöÁä¦r(©m¦W/¼ÊºÙ/¨Ó·½/«H½c)¡G", key, 30, DOECHO)) + return XEASY; + + /* itoc.010929.µù¸Ñ: ¯u¬O¦³°÷¼É¤O :p ¦Ò¼{¥ý¥Ñ reaper °µ¥X¤@Ó .PASSWDS ¦A¥h§ä */ + + for (c = 'a'; c <= 'z'; c++) + { + char buf[64]; + struct dirent *de; + DIR *dirp; + + sprintf(buf, "usr/%c", c); + if (!(dirp = opendir(buf))) + continue; + + while (de = readdir(dirp)) + { + if (acct_load(&acct, de->d_name) < 0) + continue; + + if (strstr(acct.realname, key) || strstr(acct.username, key) || + strstr(acct.lasthost, key) || strstr(acct.email, key)) + { + move(1, 0); + acct_setup(&acct, 1); + + if (vans("¬O§_Ä~Äò·j´M¤U¤@µ§¡H[N] ") != 'y') + { + closedir(dirp); + goto end_search; + } + } + } + closedir(dirp); + } +end_search: + vmsg("·j´M§¹²¦"); + return 0; +} + + +int +a_editbrd() /* itoc.010929: ×§ï¬ÝªO¿ï¶µ */ +{ + int bno; + BRD *brd; + char bname[BNLEN + 1]; + + if (brd = ask_board(bname, BRD_L_BIT, NULL)) + { + bno = brd - bshm->bcache; + brd_edit(bno); + } + else + { + vmsg(err_bid); + } + + return 0; +} + + +int +a_xfile() /* ³]©w¨t²ÎÀÉ®× */ +{ + static char *desc[] = + { + "¬ÝªO¤å³¹´Á", + + "¨¤À»{ÃÒ«H¨ç", + "»{ÃÒ³q¹L³qª¾", + "«·s»{ÃÒ³qª¾", + +#ifdef HAVE_DETECT_CROSSPOST + "¸ó¶K°±Åv³qª¾", +#endif + + "¤£¶®¦W³æ", + "¯¸°È¦W³æ", + + "¸`¤é", + +#ifdef HAVE_WHERE + "¬G¶m ID", + "¬G¶m IP", + "¬G¶m FQDN", +#endif + +#ifdef HAVE_TIP + "¨C¤é¤p¯µ³Z", +#endif + +#ifdef HAVE_LOVELETTER + "±¡®Ñ²£¥Í¾¹¤å®w", +#endif + + "»{ÃÒ¥Õ¦W³æ", + "»{ÃҶ¦W³æ", + + "¦¬«H¥Õ¦W³æ", + "¦¬«H¶Â¦W³æ", + +#ifdef HAVE_LOGIN_DENIED + "©Úµ´³s½u¦W³æ", +#endif + + NULL + }; + + static char *path[] = + { + FN_ETC_EXPIRE, + + FN_ETC_VALID, + FN_ETC_JUSTIFIED, + FN_ETC_REREG, + +#ifdef HAVE_DETECT_CROSSPOST + FN_ETC_CROSSPOST, +#endif + + FN_ETC_BADID, + FN_ETC_SYSOP, + + FN_ETC_FEAST, + +#ifdef HAVE_WHERE + FN_ETC_IDHOME, + FN_ETC_HOST, + FN_ETC_FQDN, +#endif + +#ifdef HAVE_TIP + FN_ETC_TIP, +#endif + +#ifdef HAVE_LOVELETTER + FN_ETC_LOVELETTER, +#endif + + TRUST_ACLFILE, + UNTRUST_ACLFILE, + + MAIL_ACLFILE, + UNMAIL_ACLFILE, + +#ifdef HAVE_LOGIN_DENIED + BBS_ACLFILE, +#endif + }; + + x_file(M_XFILES, desc, path); + return 0; +} + +int +a_sysload() +{ + char buf[80]; + + double load[3]; + getloadavg(load, 3); + + /* ³o¤TÓ¼ÆÈ¤À§Oªí¥Ü¹L¥h 1, 5, 15 ¤ÀÄÁªºt¸ü */ + sprintf(buf, "¨t²Ît¸ü %.2f %.2f %.2f", load[0], load[1], load[2]); + vmsg(buf); + return XEASY; +} + + +int +a_resetsys() /* «¸m */ +{ + switch (vans("¡· ¨t²Î«³] 1)°ÊºA¬ÝªO 2)¤ÀÃþ¸s²Õ 3)«ü¦W¤Î¾×«H 4)¥þ³¡ S)ync¡G[Q] ")) + { + case '1': + system("bin/camera"); + break; + + case '2': + system("bin/account -nokeeplog"); + brh_save(); + board_main(); + break; + + case '3': + system("kill -1 `cat run/bmta.pid`; kill -1 `cat run/bguard.pid`"); + break; + + case '4': + system("kill -1 `cat run/bmta.pid`; kill -1 `cat run/bguard.pid`; bin/account -nokeeplog; bin/camera"); + brh_save(); + board_main(); + break; + + case 's': + /* + move(1,0), clrtobot(); + outs("³o¶µ¥\\¯à·|n¨D§@·~¨t²Î±N«O¯d¦b°O¾ÐÅ餤ªºÀɮץߧY¼g¤JÀÉ®×\n" + "¦pªG¦¹®É¦³¤j¶q¸ê®Æ¼g¤J¡A¥i¯à»Ýn¸ûªøªº®É¶¡\n"); + vmsg(NULL); + */ + vmsg("³o¶µ¥\\¯à·|n¨D§@·~¨t²Î±N«O¯d¦b°O¾ÐÅ餤ªºÀɮץߧY¼g¤JÀÉ®×"); + if(fork()==0){ + sync(); + exit(0); + }else{ + vmsg("³oÓ¨t²Î©I¥s¤w¦bI´º°õ¦æ"); + } + return XO_HEAD; + } + + return XEASY; +} + + +/* ----------------------------------------------------- */ +/* ÁÙì³Æ¥÷ÀÉ */ +/* ----------------------------------------------------- */ + + +static void +show_availability(type) /* ±N BAKPATH ¸Ì±©Ò¦³¥i¨ú¦^³Æ¥÷ªº¥Ø¿ý¦L¥X¨Ó */ + char *type; +{ + int tlen, len, col; + char *fname, fpath[64]; + struct dirent *de; + DIR *dirp; + FILE *fp; + + if (dirp = opendir(BAKPATH)) + { + col = 0; + tlen = strlen(type); + + sprintf(fpath, "tmp/restore.%s", cuser.userid); + fp = fopen(fpath, "w"); + fputs("¡° ¥i¨Ñ¨ú¦^ªº³Æ¥÷¦³¡G\n\n", fp); + + while (de = readdir(dirp)) + { + fname = de->d_name; + if (!strncmp(fname, type, tlen)) + { + len = strlen(fname) + 2; + if (SCR_WIDTH - col < len) + { + fputc('\n', fp); + col = 0; + } + else + { + col += len; + } + fprintf(fp, "%s ", fname); + } + } + + fputc('\n', fp); + fclose(fp); + closedir(dirp); + + more(fpath, (char *) -1); + unlink(fpath); + } +} + + +int +a_restore() +{ + int ch; + char *type, *ptr; + char *tpool[3] = {"brd", "gem", "usr"}; + char date[20], brdname[BNLEN + 1], src[64], cmd[256]; + ACCT acct; + BPAL *bpal; + + ch = vans("¡· ÁÙì³Æ¥÷ 1)¬ÝªO 2)ºëµØ°Ï 3)¨Ï¥ÎªÌ¡G[Q] ") - '1'; + if (ch < 0 || ch >= 3) + return XEASY; + + type = tpool[ch]; + show_availability(type); + + if (vget(b_lines, 0, "n¨ú¦^ªº³Æ¥÷¥Ø¿ý¡G", date, 20, DOECHO)) + { + /* Á×§K¯¸ªø¥´¤F¤@Ó¦s¦bªº¥Ø¿ý¡A¦ý¬O©M type ¤£¦X */ + if (strncmp(date, type, strlen(type))) + return 0; + + sprintf(src, BAKPATH"/%s", date); + if (!dashd(src)) + return 0; + ptr = strchr(src, '\0'); + + clear(); + move(3, 0); + outs("±ýÁÙì³Æ¥÷ªº¬ÝªO/¨Ï¥ÎªÌ¥²¶·¤w¦s¦b¡C\n" + "Y¸Ó¬ÝªO/¨Ï¥ÎªÌ¤w§R°£¡A½Ð¥ý«·s¶}³]/µù¥U¤@Ó¦P¦Wªº¬ÝªO/¨Ï¥ÎªÌ¡C\n" + "ÁÙì³Æ¥÷®É½Ð½T»{¸Ó¬ÝªOµL¤H¨Ï¥Î/¨Ï¥ÎªÌ¤£¦b½u¤W"); + + if (ch == 0 || ch == 1) + { + if (!ask_board(brdname, BRD_L_BIT, NULL)) + return 0; + sprintf(ptr, "/%s%s.tgz", ch == 0 ? "" : "brd/", brdname); + } + else /* if (ch == 2) */ + { + if (acct_get(msg_uid, &acct) <= 0) + return 0; + type = acct.userid; + str_lower(type, type); + sprintf(ptr, "/%c/%s.tgz", *type, type); + } + + if (!dashf(src)) + { + /* Àɮפ£¦s¦b¡A³q±`¬O¦]¬°³Æ¥÷ÂI®É¸Ó¬ÝªO/¨Ï¥ÎªÌ¤w³Q§R°£¡A©Î¬O·í®É®Ú¥»´NÁÙ¨S¦³¸Ó¬ÝªO/¨Ï¥ÎªÌ */ + vmsg("³Æ¥÷Àɮפ£¦s¦b¡A½Ð¸Õ¸Õ¨ä¥L®É¶¡ÂIªº³Æ¥÷"); + return 0; + } + + if (vans("ÁÙì³Æ¥÷«á¡A¥Ø«e©Ò¦³¸ê®Æ³£·|¬y¥¢¡A½Ð°È¥²½T©w(Y/N)¡H[N] ") != 'y') + return 0; + + alog("ÁÙì³Æ¥÷", src); + + /* ¸ÑÀ£ÁY */ + if (ch == 0) + ptr = "brd"; + else if (ch == 1) + ptr = "gem/brd"; + else /* if (ch == 2) */ + sprintf(ptr = date, "usr/%c", *type); + sprintf(cmd, "tar xfz %s -C %s/", src, ptr); + /* system(cmd); */ + +#if 1 /* Åý¯¸ªø¤â°Ê°õ¦æ */ + move(7, 0); + outs("\n½Ð¥H bbs ¨¤Àµn¤J¤u§@¯¸¡A¨Ã©ó\033[1;36m®a¥Ø¿ý\033[m°õ¦æ\n\n\033[1;33m"); + outs(cmd); + outs("\033[m\n\n"); +#endif + + /* tar §¹¥H«á¡AÁÙn°µªº¨Æ */ + if (vans("¡· «ü¥O Y)¤w¦¨¥\\°õ¦æ¥H¤W«ü¥O Q)©ñ±ó°õ¦æ¡G[Q] ") == 'y') + { + if (ch == 0) /* ÁÙì¬ÝªO®É¡An§ó·sªO¤Í */ + { + if ((ch = brd_bno(brdname)) >= 0) + { + brd_fpath(src, brdname, fn_pal); + bpal = bshm->pcache + ch; + bpal->pal_max = image_pal(src, bpal->pal_spool); + } + } + else if (ch == 2) /* ÁÙì¨Ï¥ÎªÌ®É¡A¤£ÁÙì userno */ + { + ch = acct.userno; + if (acct_load(&acct, type) >= 0) + { + acct.userno = ch; + acct_save(&acct); + } + } + vmsg("ÁÙì³Æ¥÷¦¨¥\\"); + return 0; + } + } + + vmsg(msg_cancel); + return 0; +} + + +#ifdef HAVE_REGISTER_FORM + +/* ----------------------------------------------------- */ +/* ³B²z Register Form */ +/* ----------------------------------------------------- */ + + +static int +scan_register_form(fd) + int fd; +{ + static char logfile[] = FN_RUN_RFORM_LOG; + static char *reason[] = + { + "¿é¤J¯u¹ê©m¦W", "¸Ô¹ê¶ñ¼g¥Ó½Ðªí", "¸Ô¶ñ¦í§}¸ê®Æ", "¸Ô¶ñ³sµ¸¹q¸Ü", + "¸Ô¶ñªA°È³æ¦ì¡B©Î¾Ç®Õ¨t¯Å", "¥Î¤¤¤å¶ñ¼g¥Ó½Ð³æ", +#ifdef EMAIL_JUSTIFY /* waynesan.040327: ¦³ E-mail »{ÃÒ¤~¦³¦¹¶µ */ + "±Ä¥Î E-mail »{ÃÒ", +#endif + NULL + }; + + ACCT acct; + RFORM rform; + HDR hdr; + FILE *fout; + + int op, n; + char buf[256], *agent, *userid, *str; + char folder[64], fpath[64]; + + vs_bar("¼f®Ö¨Ï¥ÎªÌµù¥U¸ê®Æ"); + agent = cuser.userid; + + while (read(fd, &rform, sizeof(RFORM)) == sizeof(RFORM)) + { + userid = rform.userid; + move(2, 0); + prints("¥Ó½Ð¥N¸¹: %s (¥Ó½Ð®É¶¡¡G%s)\n", userid, Btime(&rform.rtime)); + prints("ªA°È³æ¦ì: %s\n", rform.career); + prints("¥Ø«e¦í§}: %s\n", rform.address); + prints("³sµ¸¹q¸Ü: %s\n%s\n", rform.phone, msg_seperator); + clrtobot(); + + if ((acct_load(&acct, userid) < 0) || (acct.userno != rform.userno)) + { + vmsg("¬dµL¦¹¤H"); + op = 'd'; + } + else + { + acct_show(&acct, 2); + +#ifdef JUSTIFY_PERIODICAL + if (acct.userlevel & PERM_VALID && acct.tvalid + VALID_PERIOD - INVALID_NOTICE_PERIOD >= acct.lastlogin) +#else + if (acct.userlevel & PERM_VALID) +#endif + { + vmsg("¦¹±b¸¹¤w¸g§¹¦¨µù¥U"); + op = 'd'; + } + else if (acct.userlevel & PERM_ALLDENY) + { + /* itoc.050405: ¤£¯àÅý°±ÅvªÌ«·s»{ÃÒ¡A¦]¬°·|§ï±¼¥Lªº tvalid (°±Åv¨ì´Á®É¶¡) */ + vmsg("¦¹±b¸¹¥Ø«e³Q°±Åv¤¤"); + op = 'd'; + } + else + { + op = vans("¬O§_±µ¨ü(Y/N/Q/Del/Skip)¡H[S] "); + } + } + + switch (op) + { + case 'y': + + /* ´£¤ÉÅv */ + sprintf(buf, "REG: %s:%s:%s:by %s", rform.phone, rform.career, rform.address, agent); + justify_log(acct.userid, buf); + time(&acct.tvalid); + /* itoc.041025: ³oÓ acct_setperm() ¨Ã¨S¦³ºò¸ò¦b acct_load() «á±¡A¤¤¶¡¹j¤F¤@Ó vans()¡A + ³o¥i¯à³y¦¨®³Â acct ¥hÂл\·s .ACCT ªº°ÝÃD¡C¤£¹L¦]¬°¬O¯¸ªø¤~¦³ªºÅv¡A©Ò¥H´N¤£§ï¤F */ + acct_setperm(&acct, PERM_VALID, 0); + + /* ±H«H³qª¾¨Ï¥ÎªÌ */ + usr_fpath(folder, userid, fn_dir); + hdr_stamp(folder, HDR_LINK, &hdr, FN_ETC_JUSTIFIED); + strcpy(hdr.title, msg_reg_valid); + strcpy(hdr.owner, str_sysop); + rec_add(folder, &hdr, sizeof(HDR)); + + strcpy(rform.agent, agent); + rec_add(logfile, &rform, sizeof(RFORM)); + + m_biff(rform.userno); + alog("µù¥U¦¨¥\\",userid); + + break; + + case 'q': /* ¤Ó²Ö¤F¡Aµ²§ô¥ð®§ */ + + do + { + rec_add(FN_RUN_RFORM, &rform, sizeof(RFORM)); + } while (read(fd, &rform, sizeof(RFORM)) == sizeof(RFORM)); + + case 'd': + break; + + case 'n': + + move(9, 0); + prints("½Ð´£¥X°h¦^¥Ó½Ðªíì¦]¡A©Î±q¥H¤U²M³æ¿ï¨ú¤@¶µ¡A¥¼¿é¤Jª½±µ«ö <enter> «h·|¨ú®ø\n\n"); + for (n = 0; str = reason[n]; n++) + prints("%d) ½Ð%s\n", n, str); + clrtobot(); + + if (op = vget(b_lines, 0, "°h¦^ì¦]¡G", buf, 60, DOECHO)) + { + int i; + + i = op - '0'; + if (i >= 0 && i < n) + strcpy(buf, reason[i]); + + usr_fpath(folder, acct.userid, fn_dir); + if (fout = fdopen(hdr_stamp(folder, 0, &hdr, fpath), "w")) + { + fprintf(fout, "\t¥Ñ©ó±z´£¨Ñªº¸ê®Æ¤£°÷¸Ô¹ê¡AµLªk½T»{¨¤À¡A" + "\n\n\t½Ð«·s¶ñ¼gµù¥Uªí³æ¡G%s¡C\n", buf); + fclose(fout); + + strcpy(hdr.owner, agent); + strcpy(hdr.title, "[°h¥ó] ½Ð±z«·s¶ñ¼gµù¥Uªí³æ"); + rec_add(folder, &hdr, sizeof(HDR)); + } + + strcpy(rform.reply, buf); /* ²z¥Ñ */ + strcpy(rform.agent, agent); + rec_add(logfile, &rform, sizeof(RFORM)); + + char buf2[256]; + sprintf(buf2,"%-13s%s",userid,buf); + alog("µù¥U°h¥ó",buf2); + + break; + } + + default: /* put back to regfile */ + + rec_add(FN_RUN_RFORM, &rform, sizeof(RFORM)); + } + } +} + + +int +a_register() +{ + int num; + char buf[80]; + + num = rec_num(FN_RUN_RFORM, sizeof(RFORM)); + if (num <= 0) + { + zmsg("¥Ø«e¨ÃµL·sµù¥U¸ê®Æ"); + return XEASY; + } + + sprintf(buf, "¦@¦³ %d µ§¸ê®Æ¡A¶}©l¼f®Ö¶Ü(Y/N)¡H[N] ", num); + num = XEASY; + + if (vans(buf) == 'y') + { + sprintf(buf, "%s.tmp", FN_RUN_RFORM); + if (dashf(buf)) + { + vmsg("¨ä¥L SYSOP ¤]¦b¼f®Öµù¥U¥Ó½Ð³æ"); + } + else + { + int fd; + + rename(FN_RUN_RFORM, buf); + fd = open(buf, O_RDONLY); + if (fd >= 0) + { + scan_register_form(fd); + close(fd); + unlink(buf); + num = 0; + } + else + { + vmsg("µLªk¶}±Òµù¥U¸ê®Æ¤u§@ÀÉ"); + } + } + } + return num; +} + + +int +a_regmerge() /* itoc.000516: Â_½u®Éµù¥U³æ×´_ */ +{ + char fpath[64]; + FILE *fp; + + sprintf(fpath, "%s.tmp", FN_RUN_RFORM); + if (dashf(fpath)) + { + vmsg("½Ð¥ý½T©w¤wµL¨ä¥L¯¸ªø¦b¼f®Öµù¥U³æ¡A¥H§Kµo¥ÍÄY«·N¥~¡I"); + + if (vans("½T©wn±Ò°Êµù¥U³æ×´_¥\\¯à(Y/N)¡H[N] ") == 'y') + { + if (fp = fopen(FN_RUN_RFORM, "a")) + { + f_suck(fp, fpath); + fclose(fp); + unlink(fpath); + } + vmsg("³B²z§¹²¦¡A¥H«á½Ð¤p¤ß¡I"); + alog("´_ì¼f®Ö",""); + } + } + else + { + zmsg("¥Ø«e¨ÃµL×´_µù¥U³æ¤§¥²n"); + } + return XEASY; +} +#endif /* HAVE_REGISTER_FORM */ + + +/* ----------------------------------------------------- */ +/* ±H«Hµ¹¥þ¯¸¨Ï¥ÎªÌ/ªO¥D */ +/* ----------------------------------------------------- */ + + +static void +add_to_list(list, id) + char *list; + char *id; /* ¥¼¥² end with '\0' */ +{ + char *i; + + /* ¥ýÀˬd¥ý«eªº list ¸Ì±¬O§_¤w¸g¦³¤F¡A¥H§K«ÂÐ¥[¤J */ + for (i = list; *i; i += IDLEN + 1) + { + if (!strncmp(i, id, IDLEN)) + return; + } + + /* Y¤§«eªº list ¨S¦³¡A¨º»òª½±µªþ¥[¦b list ³Ì«á */ + str_ncpy(i, id, IDLEN + 1); +} + + +static void +make_bm_list(list) + char *list; +{ + BRD *head, *tail; + char *ptr, *str, buf[BMLEN + 1]; + + /* ¥h bshm ¤¤§ì¥X©Ò¦³ brd->BM */ + + head = bshm->bcache; + tail = head + bshm->number; + do /* ¦Ü¤Ö¦³ note ¤@ªO¡A¤£¥²¹ï¬ÝªO°µÀˬd */ + { + ptr = buf; + strcpy(ptr, head->BM); + + while (*ptr) /* §â brd->BM ¤¤ bm1/bm2/bm3/... ¦UÓ bm §ì¥X¨Ó */ + { + if (str = strchr(ptr, '/')) + *str = '\0'; + add_to_list(list, ptr); + if (!str) + break; + ptr = str + 1; + } + } while (++head < tail); +} + + +static void +make_all_list(list) + char *list; +{ + int fd; + SCHEMA schema; + + if ((fd = open(FN_SCHEMA, O_RDONLY)) < 0) + return; + + while (read(fd, &schema, sizeof(SCHEMA)) == sizeof(SCHEMA)) + add_to_list(list, schema.userid); + + close(fd); +} + + +static void +send_list(title, fpath, list) + char *title; /* «H¥óªº¼ÐÃD */ + char *fpath; /* «H¥óªºÀÉ®× */ + char *list; /* ±H«Hªº¦W³æ */ +{ + char folder[64], *ptr; + HDR mhdr; + + for (ptr = list; *ptr; ptr += IDLEN + 1) + { + usr_fpath(folder, ptr, fn_dir); + if (hdr_stamp(folder, HDR_LINK, &mhdr, fpath) >= 0) + { + strcpy(mhdr.owner, str_sysop); + strcpy(mhdr.title, title); + mhdr.xmode = 0; + rec_add(folder, &mhdr, sizeof(HDR)); + } + } +} + + +static void +biff_bm() +{ + UTMP *utmp, *uceil; + + utmp = ushm->uslot; + uceil = (void *) utmp + ushm->offset; + do + { + if (utmp->pid && (utmp->userlevel & PERM_BM)) + utmp->status |= STATUS_BIFF; + } while (++utmp <= uceil); +} + + +static void +biff_all() +{ + UTMP *utmp, *uceil; + + utmp = ushm->uslot; + uceil = (void *) utmp + ushm->offset; + do + { + if (utmp->pid) + utmp->status |= STATUS_BIFF; + } while (++utmp <= uceil); +} + + +int +m_bm() +{ + char *list, fpath[64]; + FILE *fp; + int size; + + if (vans("n±H«Hµ¹¥þ¯¸©Ò¦³ªO¥D(Y/N)¡H[N] ") != 'y') + return XEASY; + + strcpy(ve_title, "[ªO¥D³q§i] "); + if (!vget(1, 0, "¼ÐÃD¡G", ve_title, TTLEN + 1, GCARRY)) + return 0; + + usr_fpath(fpath, cuser.userid, "sysmail"); + if (fp = fopen(fpath, "w")) + { + fprintf(fp, "¡° [ªO¥D³q§i] ¯¸ªø³q§i¡A¦¬«H¤H¡G¦UªO¥D\n"); + fprintf(fp, "-------------------------------------------------------------------------\n"); + fclose(fp); + } + + curredit = EDIT_MAIL; + *quote_file = '\0'; + if (vedit(fpath, 1) >= 0) + { + vmsg("»Ýn¤@¬qÆZªøªº®É¶¡¡A½Ð@¤ßµ¥«Ý"); + + size = (IDLEN + 1) * MAXBOARD * 4; /* °²³]¨CªO¥|ÓªO¥D¤w¨¬°÷ */ + if (list = (char *) malloc(size)) + { + memset(list, 0, size); + + make_bm_list(list); + send_list(ve_title, fpath, list); + + free(list); + biff_bm(); + } + } + else + { + vmsg(msg_cancel); + } + + unlink(fpath); + + return 0; +} + + +int +m_all() +{ + char *list, fpath[64]; + FILE *fp; + int size; + + if (vans("n±H«Hµ¹¥þ¯¸¨Ï¥ÎªÌ(Y/N)¡H[N] ") != 'y') + return XEASY; + + strcpy(ve_title, "[¨t²Î³q§i] "); + if (!vget(1, 0, "¼ÐÃD¡G", ve_title, TTLEN + 1, GCARRY)) + return 0; + + usr_fpath(fpath, cuser.userid, "sysmail"); + if (fp = fopen(fpath, "w")) + { + fprintf(fp, "¡° [¨t²Î³q§i] ¯¸ªø³q§i¡A¦¬«H¤H¡G¥þ¯¸¨Ï¥ÎªÌ\n"); + fprintf(fp, "-------------------------------------------------------------------------\n"); + fclose(fp); + } + + curredit = EDIT_MAIL; + *quote_file = '\0'; + if (vedit(fpath, 1) >= 0) + { + vmsg("»Ýn¤@¬qÆZªøªº®É¶¡¡A½Ð@¤ßµ¥«Ý"); + + size = (IDLEN + 1) * rec_num(FN_SCHEMA, sizeof(SCHEMA)); + if (list = (char *) malloc(size)) + { + memset(list, 0, size); + + make_all_list(list); + send_list(ve_title, fpath, list); + + free(list); + biff_all(); + } + } + else + { + vmsg(msg_cancel); + } + + unlink(fpath); + + return 0; +} diff --git a/so/aloha.c b/so/aloha.c new file mode 100644 index 0000000..fad0d6b --- /dev/null +++ b/so/aloha.c @@ -0,0 +1,445 @@ +/*-------------------------------------------------------*/ +/* aloha.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : aloha routines */ +/* create : 95/03/29 */ +/* update : 00/01/02 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_ALOHA + +extern XZ xz[]; +extern char xo_pool[]; + + +/* ----------------------------------------------------- */ +/* ¤W¯¸³qª¾¦W³æ */ +/* ----------------------------------------------------- */ + + +static int +cmpfrienz(frienz) + FRIENZ *frienz; +{ + return frienz->userno == cuser.userno; +} + + +static void +delbenz(xo, aloha) + XO *xo; + ALOHA *aloha; +{ + char fpath[64]; + + usr_fpath(fpath, aloha->userid, FN_FRIENZ); + while (!rec_del(fpath, sizeof(FRIENZ), 0, cmpfrienz)) + ; +} + + +static int +aloha_find(fpath, userno) + char *fpath; + int userno; +{ + ALOHA old; + int fd; + int rc = 0; + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + while (read(fd, &old, sizeof(ALOHA)) == sizeof(ALOHA)) + { + if (userno == old.userno) + { + rc = 1; + break; + } + } + close(fd); + } + return rc; +} + + +static int +chkaloha(aloha) + ALOHA *aloha; +{ + int userno; + + userno = aloha->userno; + return (userno > 0 && userno == acct_userno(aloha->userid)); +} + + +static void +aloha_sync(fpath) + char *fpath; +{ + int fsize; + + outz(MSG_CHKDATA); + refresh(); + + fsize = rec_sync(fpath, sizeof(ALOHA), str_cmp, chkaloha); + + if (fsize > ALOHA_MAX * sizeof(ALOHA)) + vmsg(msg_list_over); +} + + +/* ----------------------------------------------------- */ +/* ¤W¯¸³qª¾¦W³æ¡G¿ï³æ¦¡¾Þ§@¬É±´yz */ +/* ----------------------------------------------------- */ + + +static int aloha_add(); + + +static void +aloha_item(num, aloha) + int num; + ALOHA *aloha; +{ +#ifdef CHECK_ONLINE + UTMP *online = utmp_get(aloha->userno, NULL); + + prints("%6d%c %s%-14s%s\n", num, tag_char(aloha->userno), + online ? COLOR7 : "", aloha->userid, online ? str_ransi : ""); +#else + prints("%6d%c %-14s\n", num, tag_char(aloha->userno), aloha->userid); +#endif +} + + +static int +aloha_body(xo) + XO *xo; +{ + ALOHA *aloha; + int num, max, tail; + + max = xo->max; + if (max <= 0) + { + if (vans("n·s¼W¦W³æ¶Ü(Y/N)¡H[N] ") == 'y') + return aloha_add(xo); + return XO_QUIT; + } + + aloha = (ALOHA *) xo_pool; + num = xo->top; + tail = num + XO_TALL; + if (max > tail) + max = tail; + + move(3, 0); + do + { + aloha_item(++num, aloha++); + } while (num < max); + clrtobot(); + + /* return XO_NONE; */ + return XO_FOOT; /* itoc.010403: §â b_lines ¶ñ¤W feeter */ +} + + +static int +aloha_head(xo) + XO *xo; +{ + vs_head("¤W¯¸³qª¾", str_site); + prints(NECKER_ALOHA, d_cols, ""); + return aloha_body(xo); +} + + +static int +aloha_load(xo) + XO *xo; +{ + xo_load(xo, sizeof(ALOHA)); + return aloha_body(xo); +} + + +static int +aloha_init(xo) + XO *xo; +{ + xo_load(xo, sizeof(ALOHA)); + return aloha_head(xo); +} + + +static int +aloha_loadpal(xo) + XO *xo; +{ + int fd, quota; + char fpath[64]; + FRIENZ frienz; + PAL pal; + ALOHA aloha; + + if (vans("n¤Þ¤J¦n¤Í¦W³æ¶Ü(Y/N)¡H[N] ") == 'y') + { + usr_fpath(fpath, cuser.userid, FN_PAL); + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + /* itoc.001224: ¤Þ¤J¦W³æ¥u¥[¨ì ALOHA_MAX */ + quota = ALOHA_MAX - xo->max; + + memset(&frienz, 0, sizeof(FRIENZ)); + frienz.userno = cuser.userno; + strcpy(frienz.userid, cuser.userid); + + while (read(fd, &pal, sizeof(PAL)) == sizeof(PAL)) + { + if (!aloha_find(xo->dir, pal.userno)) + { + memset(&aloha, 0, sizeof(ALOHA)); + aloha.userno = pal.userno; + strcpy(aloha.userid, pal.userid); + rec_add(xo->dir, &aloha, sizeof(ALOHA)); + + usr_fpath(fpath, aloha.userid, FN_FRIENZ); + rec_add(fpath, &frienz, sizeof(FRIENZ)); + + /* ¥un¦³¤Þ¤J¥ô¦ó¤@¤H¡A´N§â´å¼Ð©ñ¦b³Ì«á */ + xo->pos = XO_TAIL; + + if (quota < 0) + break; + } + } + close(fd); + return aloha_load(xo); + } + } + return XO_FOOT; +} + + +static int +aloha_add(xo) + XO *xo; +{ + int userno; + char fpath[64]; + FRIENZ frienz; + ACCT acct; + ALOHA aloha; + + if (xo->max >= ALOHA_MAX) + { + vmsg(msg_list_over); + return XO_FOOT; + } + + if ((userno = acct_get(msg_uid, &acct)) <= 0) + return aloha_head(xo); + + if (userno == cuser.userno) + { + vmsg("¦Û¤v¤£¶·¥[¤J¤W¯¸³qª¾¦W³æ¤¤"); + return aloha_head(xo); + } + + if (!aloha_find(xo->dir, userno)) + { + memset(&aloha, 0, sizeof(ALOHA)); + aloha.userno = userno; + strcpy(aloha.userid, acct.userid); + rec_add(xo->dir, &aloha, sizeof(ALOHA)); + + memset(&frienz, 0, sizeof(FRIENZ)); + frienz.userno = cuser.userno; + strcpy(frienz.userid, cuser.userid); + usr_fpath(fpath, aloha.userid, FN_FRIENZ); + rec_add(fpath, &frienz, sizeof(FRIENZ)); + } + xo->pos = XO_TAIL; + xo_load(xo, sizeof(ALOHA)); + + return aloha_head(xo); +} + + +static int +aloha_delete(xo) + XO *xo; +{ + if (vans(msg_del_ny) == 'y') + { + char fpath[64]; + ALOHA *aloha; + + aloha = (ALOHA *) xo_pool + (xo->pos - xo->top); + + usr_fpath(fpath, aloha->userid, FN_FRIENZ); + /* itoc.030310: µù¸Ñ: ©È frienz ¸Ì±¦³«ÂЪº */ + while (!rec_del(fpath, sizeof(FRIENZ), 0, cmpfrienz)) + ; + + rec_del(xo->dir, sizeof(ALOHA), xo->pos, NULL); + return aloha_init(xo); + } + return XO_FOOT; +} + + +static int +aloha_rangedel(xo) + XO *xo; +{ + return xo_rangedel(xo, sizeof(ALOHA), NULL, delbenz); +} + + +static int +vfyaloha(aloha, pos) + ALOHA *aloha; + int pos; +{ + return Tagger(aloha->userno, pos, TAG_NIN); +} + + +static int +aloha_prune(xo) + XO *xo; +{ + return xo_prune(xo, sizeof(ALOHA), vfyaloha, delbenz); +} + + +static int +aloha_mail(xo) + XO *xo; +{ + ALOHA *aloha; + + aloha = (ALOHA *) xo_pool + (xo->pos - xo->top); + return my_send(aloha->userid); +} + + +static int +aloha_write(xo) + XO *xo; +{ + if (HAS_PERM(PERM_PAGE)) + { + ALOHA *aloha; + UTMP *up; + + aloha = (ALOHA *) xo_pool + (xo->pos - xo->top); + + if (up = utmp_find(aloha->userno)) + do_write(up); + } + return XO_NONE; +} + + +static int +aloha_query(xo) + XO *xo; +{ + ALOHA *aloha; + + aloha = (ALOHA *) xo_pool + (xo->pos - xo->top); + move(1, 0); + clrtobot(); + + my_query(aloha->userid); + return aloha_head(xo); +} + + +static int +aloha_sort(xo) + XO *xo; +{ + aloha_sync(xo->dir); + return aloha_init(xo); +} + + +static int +aloha_tag(xo) + XO *xo; +{ + ALOHA *aloha; + int tag, pos, cur; + + pos = xo->pos; + cur = pos - xo->top; + aloha = (ALOHA *) xo_pool + cur; + + if (tag = Tagger(aloha->userno, pos, TAG_TOGGLE)) + { + move(3 + cur, 6); + outc(tag > 0 ? '*' : ' '); + } + + /* return XO_NONE; */ + return xo->pos + 1 + XO_MOVE; /* lkchu.981201: ¸õ¦Ü¤U¤@¶µ */ +} + + +static int +aloha_help(xo) + XO *xo; +{ + xo_help("aloha"); + return aloha_head(xo); +} + + +static KeyFunc aloha_cb[] = +{ + XO_INIT, aloha_init, + XO_LOAD, aloha_load, + XO_HEAD, aloha_head, + XO_BODY, aloha_body, + + 'a', aloha_add, + 'd', aloha_delete, + 'm', aloha_mail, + 'w', aloha_write, + 'D', aloha_rangedel, + 'f', aloha_loadpal, + + 'r', aloha_query, + Ctrl('Q'), aloha_query, + + 's', aloha_sort, + 't', aloha_tag, + Ctrl('D'), aloha_prune, + + 'h', aloha_help +}; + + +int +t_aloha() +{ + XO *xo; + char fpath[64]; + + usr_fpath(fpath, cuser.userid, FN_ALOHA); + xz[XZ_ALOHA - XO_ZONE].xo = xo = xo_new(fpath); + xz[XZ_ALOHA - XO_ZONE].cb = aloha_cb; + xover(XZ_ALOHA); + free(xo); + return 0; +} +#endif /* HAVE_ALOHA */ diff --git a/so/bank.c b/so/bank.c new file mode 100644 index 0000000..0b4a472 --- /dev/null +++ b/so/bank.c @@ -0,0 +1,521 @@ +/*-------------------------------------------------------*/ +/* bank.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : »È¦æ¡BÁʶRÅv¥\¯à */ +/* create : 01/07/16 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_BUY + +static void +x_give() +{ + int way, dollar; + char userid[IDLEN + 1], buf[80]; + char folder[64], fpath[64], reason[40]; + HDR hdr; + FILE *fp; + time_t now; + PAYCHECK paycheck; + + if (!vget(13, 0, "±zn§â¿úÂ൹½Ö©O¡H", userid, IDLEN + 1, DOECHO)) + if (!vget(13, 0, "±zn§â¿úÂ൹½Ö©O¡H", userid, IDLEN + 1, DOECHO) || + !str_cmp(userid, STR_GUEST)) + return; + + if (acct_userno(userid) <= 0) + { + vmsg(err_uid); + return; + } + + way = vget(15, 0, "Âà±b 1)Âà»È¹ô 2)Âàª÷¹ô¡G", buf, 3, DOECHO) - '1'; + if (way < 0 || way > 1) + return; + + do + { + if (!vget(17, 0, "nÂà¦h¤Ö¿ú¹L¥h¡H", buf, 9, DOECHO)) /* ³Ì¦hÂà 99999999 Á×§K·¸¦ì */ + return; + + dollar = atoi(buf); + + if (!way) + { + if (dollar > cuser.money) + dollar = cuser.money; /* ¥þÂà¹L¥h */ + } + else + { + if (dollar > cuser.gold) + dollar = cuser.gold; /* ¥þÂà¹L¥h */ + } + } while (dollar <= 1); /* ¤£¯à¥uÂà 1¡A·|¥þÅܤâÄò¶O */ + + if (!vget(19, 0, "½Ð¿é¤J²z¥Ñ¡G", reason, 40, DOECHO)) + strcpy(reason, "¿ú¤Ó¦h"); + + sprintf(buf, "¬O§_nÂà±bµ¹ %s %s¹ô %d (Y/N)¡H[N] ", userid, !way ? "»È" : "ª÷", dollar); + if (vget(21, 0, buf, fpath, 3, LCECHO) == 'y') + { + if (!way) + cuser.money -= dollar; + else + cuser.gold -= dollar; + + dollar -= dollar / 10 + ((dollar % 10) ? 1 : 0); /* 10% ¤âÄò¶O */ + + /* itoc.020831: ¥[¤J¶×¿ú°O¿ý */ + time(&now); + sprintf(buf, "%-13sÂ൹ %-13sp %d %s (%s)\n", + cuser.userid, userid, dollar, !way ? "»È" : "ª÷", Btime(&now)); + f_cat(FN_RUN_BANK_LOG, buf); + + usr_fpath(folder, userid, fn_dir); + if (fp = fdopen(hdr_stamp(folder, 0, &hdr, fpath), "w")) + { + fprintf(fp, "%s %s (%s)\n¼ÐÃD: Âà±b³qª¾\n®É¶¡: %s\n\n", + str_author1, cuser.userid, cuser.username, Btime(&now)); + fprintf(fp, "%s\n¥Lªº²z¥Ñ¬O¡G%s\n\n½Ð±z¦Üª÷¿Ä¤¤¤ß±N¤ä²¼§I²{", buf, reason); + fclose(fp); + + strcpy(hdr.title, "Âà±b³qª¾"); + strcpy(hdr.owner, cuser.userid); + rec_add(folder, &hdr, sizeof(HDR)); + } + + memset(&paycheck, 0, sizeof(PAYCHECK)); + time(&paycheck.tissue); + if (!way) + paycheck.money = dollar; + else + paycheck.gold = dollar; + sprintf(paycheck.reason, "[Âà±b] %s", cuser.userid); + usr_fpath(fpath, userid, FN_PAYCHECK); + rec_add(fpath, &paycheck, sizeof(PAYCHECK)); + + sprintf(buf, "±z¨¤W¦³»È¹ô %d ¤¸¡Aª÷¹ô %d ¤¸", cuser.money, cuser.gold); + vmsg(buf); + } + else + { + vmsg("¨ú®ø¥æ©ö"); + } +} + + +#define GOLD2MONEY 900000 /* ª÷¹ô¡÷»È¹ô ¶×²v */ +#define MONEY2GOLD 1100000 /* »È¹ô¡÷ª÷¹ô ¶×²v */ + +static void +x_exchange() +{ + int way, gold, money; + char buf[80], ans[8]; + + move(13, 0); + prints("»È¹ô¡÷ª÷¹ô = %d¡G1 ª÷¹ô¡÷»È¹ô = 1¡G%d", MONEY2GOLD, GOLD2MONEY); + + way = vget(15, 0, "¶×§I 1)»È¹ô¡÷ª÷¹ô 2)ª÷¹ô¡÷»È¹ô¡G", ans, 3, DOECHO) - '1'; + + if (!way) + money = cuser.money / MONEY2GOLD; + else if (way == 1) + money = cuser.gold; + else + return; + + if (!way) + sprintf(buf, "±zn±N»È¹ô§I´«¦¨¦h¤ÖÓª÷¹ô©O¡H[1 - %d] ", money); + else + sprintf(buf, "±zn§I´«¦h¤ÖÓª÷¹ô¦¨¬°»È¹ô©O¡H[1 - %d] ", money); + + if (!vget(17, 0, buf, ans, 4, DOECHO)) /* ªø«×¤ñ¸ûµu¡AÁ×§K·¸¦ì */ + return; + + gold = atoi(ans); + if (gold <= 0 || gold > money) + return; + + if (!way) + { + if (gold > (INT_MAX - cuser.gold)) + { + vmsg("±z´«¤Ó¦h¿úÅo¡ã·|·¸¦ìªº¡I"); + return; + } + money = gold * MONEY2GOLD; + sprintf(buf, "¬O§_n§I´«»È¹ô %d ¤¸ ¬°ª÷¹ô %d (Y/N)¡H[N] ", money, gold); + } + else + { + money = gold * GOLD2MONEY; + if (money > (INT_MAX - cuser.money)) + { + vmsg("±z´«¤Ó¦h¿úÅo¡ã·|·¸¦ìªº¡I"); + return; + } + sprintf(buf, "¬O§_n§I´«ª÷¹ô %d ¤¸ ¬°»È¹ô %d (Y/N)¡H[N] ", gold, money); + } + + if (vget(19, 0, buf, ans, 3, LCECHO) == 'y') + { + if (!way) + { + cuser.money -= money; + addgold(gold); + } + else + { + cuser.gold -= gold; + addmoney(money); + } + sprintf(buf, "±z¨¤W¦³»È¹ô %d ¤¸¡Aª÷¹ô %d ¤¸", cuser.money, cuser.gold); + vmsg(buf); + } + else + { + vmsg("¨ú®ø¥æ©ö"); + } +} + + +static void +x_cash() +{ + int fd, money, gold; + char fpath[64], buf[64]; + FILE *fp; + PAYCHECK paycheck; + + usr_fpath(fpath, cuser.userid, FN_PAYCHECK); + if ((fd = open(fpath, O_RDONLY)) < 0) + { + vmsg("±z¥Ø«e¨S¦³¤ä²¼¥¼§I²{"); + return; + } + + usr_fpath(buf, cuser.userid, "cashed"); + fp = fopen(buf, "w"); + fputs("¥H¤U¬O±zªº¤ä²¼§I´«²M³æ¡G\n\n", fp); + + money = gold = 0; + while (read(fd, &paycheck, sizeof(PAYCHECK)) == sizeof(PAYCHECK)) + { + if (paycheck.money < (INT_MAX - money)) /* Á×§K·¸¦ì */ + money += paycheck.money; + else + money = INT_MAX; + if (paycheck.gold < (INT_MAX - gold)) /* Á×§K·¸¦ì */ + gold += paycheck.gold; + else + gold = INT_MAX; + + fprintf(fp, "%s %s %d »È %d ª÷\n", + Btime(&paycheck.tissue), paycheck.reason, paycheck.money, paycheck.gold); + } + close(fd); + unlink(fpath); + + fprintf(fp, "\n±z¦@§I²{ %d »È %d ª÷\n", money, gold); + fclose(fp); + + addmoney(money); + addgold(gold); + + more(buf, NULL); + unlink(buf); +} + + +int +x_bank() +{ + char ans[3]; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + vs_bar("«H°U»È¦æ"); + move(2, 0); + + /* itoc.011208: ¥H¨¾¸U¤@ */ + if (cuser.money < 0) + cuser.money = 0; + if (cuser.gold < 0) + cuser.gold = 0; + + outs("\033[1;36m ùúùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùû\n"); + prints(" ùø\033[32m±z²{¦b¦³»È¹ô \033[33m%12d\033[32m ¤¸¡Aª÷¹ô \033[33m%12d\033[32m ¤¸\033[36m ùø\n", + cuser.money, cuser.gold); + outs(" ùàùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùâ\n" + " ùø ¥Ø«e»È¦æ´£¨Ñ¤U¦C´X¶µªA°È¡G ùø\n" + " ùø\033[33m1.\033[37m Âà±b -- Âà±bµ¹¨ä¥L¤H (©â¨ú 10% ¤âÄò¶O) \033[36m ùø\n" + " ùø\033[33m2.\033[37m ¶×§I -- »È¹ô/ª÷¹ô §I´« (©â¨ú 10% ¤âÄò¶O) \033[36m ùø\n" + " ùø\033[33m3.\033[37m §I²{ -- ¤ä²¼§I²{ \033[36m ùø\n" + " ùüùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùý\033[m"); + + vget(11, 0, "½Ð¿é¤J±z»ÝnªºªA°È¡G", ans, 3, DOECHO); + if (ans[0] == '1') + x_give(); + else if (ans[0] == '2') + x_exchange(); + else if (ans[0] == '3') + x_cash(); + + return 0; +} + + +int +b_invis() +{ + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + if (cuser.ufo & UFO_CLOAK) + { + if (vans("¬O§_²{¨(Y/N)¡H[N] ") != 'y') + return XEASY; + /* ²{¨§K¶O */ + } + else + { + if (HAS_PERM(PERM_CLOAK)) + { + if (vans("¬O§_Áô§Î(Y/N)¡H[N] ") != 'y') + return XEASY; + /* ¦³µLÁô§ÎÅvªÌ§K¶O */ + } + else + { + if (cuser.gold < 10) + { + vmsg("n 10 ª÷¹ô¤~¯àÁô§Î³á"); + return XEASY; + } + if (vans("¬O§_ªá 10 ª÷¹ôÁô§Î(Y/N)¡H[N] ") != 'y') + return XEASY; + cuser.gold -= 10; + } + } + + cuser.ufo ^= UFO_CLOAK; + cutmp->ufo ^= UFO_CLOAK; /* ufo n¦P¨B */ + + return XEASY; +} + + +static void +buy_level(userlevel) /* itoc.010830: ¥u¦s level Äæ¦ì¡A¥H§KÅܰʨì¦b½u¤W§ó°Êªº»{ÃÒÄæ¦ì */ + usint userlevel; +{ + if (!HAS_STATUS(STATUS_DATALOCK)) /* itoc.010811: n¨S¦³³Q¯¸ªøÂê©w¡A¤~¯à¼g¤J */ + { + int fd; + char fpath[80]; + ACCT tuser; + + usr_fpath(fpath, cuser.userid, fn_acct); + fd = open(fpath, O_RDWR); + if (fd >= 0) + { + if (read(fd, &tuser, sizeof(ACCT)) == sizeof(ACCT)) + { + tuser.userlevel |= userlevel; + lseek(fd, (off_t) 0, SEEK_SET); + write(fd, &tuser, sizeof(ACCT)); + vmsg("±z¤w¸gÀò±oÅv¡A½Ð«·s¤W¯¸"); + } + close(fd); + } + } +} + + +int +b_cloak() +{ + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + if (HAS_PERM(PERM_CLOAK)) + { + vmsg("±z¤w¸g¯àµLÁô§Î¤F"); + } + else + { + if (cuser.gold < 1000) + { + vmsg("n 1000 ª÷¹ô¤~¯àÁʶRµLÁô§ÎÅv³á"); + } + else if (vans("¬O§_ªá 1000 ª÷¹ôÁʶRµLÁô§ÎÅv(Y/N)¡H[N] ") == 'y') + { + cuser.gold -= 1000; + buy_level(PERM_CLOAK); + } + } + + return XEASY; +} + +int +b_changeid() +{ + char ans[3]; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + if (HAS_PERM(PERM_CHANGEID)) + { + vmsg("±z¤w¸g¯à§ïID¤F"); + return XEASY; + } + + vs_bar("ÁʶR§ó§ïIDÅv"); + move(2, 0); + + /* itoc.011208: ¥H¨¾¸U¤@ */ + if (cuser.money < 0) + cuser.money = 0; + if (cuser.gold < 0) + cuser.gold = 0; + + outs("ÁʶR¦¹ÅvªÌ¡A½Ð¦P·N¿í¦u¥H¤U³W«h¡G\n\n" + " 1.±ý§ó§ïID½Ð©ó¨Ï¥ÎªÌ¦W³æ«ö¤U ^D\n" + " 2.§ó§ï«áªºID ³Ì«á¤è·|¥X²{','¦r¤¸ ¥H¥Ü°Ï§O ¨Ò¦p \"chensc,\"\n" + " 3.¥Ñ©ó§ó§ïID«á ¨Ï¥ÎªÌ¸ê®Æ¤£·|Åã¥Ü ½Ð¤Å¥H¦¹À¸§Ë¥L¤H\n" + " 4.½Ð¤Å±NID§ï¬°¤£¶®¦r²´\n" + " 5.¦p¹H¤Ï¤Wz³W«h ¯¸°È±o¥H±j¢Â÷½u³B¤§ ¸g¥Ó¶D±¡¸`«¤jªÌ¨ú®øÅv\n\n" + "³Ì«áÁÙ¬O§Æ±æ¤j®a¯à°÷ª±ªº´r§Ö^^"); + + vget(11, 0, "Ū§¹¥H¤W³W«h¡A±znªá 6 ª÷¹ôÁʶR§ó§ïIDªºÅv¶Ü¡Hy/n [n]¡G", ans, 3, DOECHO); + if (ans[0] == 'y') + { + if (cuser.gold < 6) + { + vmsg("n 6 ª÷¹ô¤~¯àÁʶR§ó§ïIDªºÅv³á"); + } + else + { + cuser.gold -= 6; + cclog("BUY_CHANGEID",cuser.userid); + buy_level(PERM_CHANGEID); + } + } + return 0; +} + + + + +int +b_mbox() +{ + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + if (HAS_PERM(PERM_MBOX)) + { + vmsg("±zªº«H½c¤w¸g¨S¦³¤W¤F"); + } + else + { + if (cuser.gold < 1000) + { + vmsg("n 1000 ª÷¹ô¤~¯àÁʶR«H½cµLÅv³á"); + } + else if (vans("¬O§_ªá 1000 ª÷¹ôÁʶR«H½cµLÅv(Y/N)¡H[N] ") == 'y') + { + cuser.gold -= 1000; + buy_level(PERM_MBOX); + } + } + + return XEASY; +} + + +int +b_xempt() +{ + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + if (HAS_PERM(PERM_XEMPT)) + { + vmsg("±zªº±b¸¹¤w¸g¥Ã¤[«O¯d¤F"); + } + else + { + if (cuser.gold < 1000) + { + vmsg("n 1000 ª÷¹ô¤~¯àÁʶR±b¸¹¥Ã¤[«O¯dÅv³á"); + } + else if (vans("¬O§_ªá 1000 ª÷¹ôÁʶR±b¸¹¥Ã¤[«O¯dÅv(Y/N)¡H[N] ") == 'y') + { + cuser.gold -= 1000; + buy_level(PERM_XEMPT); + } + } + + return XEASY; +} + + +#if 0 /* ¤£´£¨ÑÁʶR¦Û±þ¥\¯à */ +int +b_purge() +{ + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XEASY; + } + + if (HAS_PERM(PERM_PURGE)) + { + vmsg("¨t²Î¦b¤U¦¸©w´Á²M±b¸¹®É¡A±N²M°£¦¹ ID"); + } + else + { + if (cuser.gold < 1000) + { + vmsg("n 1000 ª÷¹ô¤~¯à¦Û±þ³á"); + } + else if (vans("¬O§_ªá 1000 ª÷¹ô¦Û±þ(Y/N)¡H[N] ") == 'y') + { + cuser.gold -= 1000; + buy_level(PERM_PURGE); + } + } + + return XEASY; +} +#endif +#endif /* HAVE_BUY */ diff --git a/so/calendar.c b/so/calendar.c new file mode 100644 index 0000000..d9fd66e --- /dev/null +++ b/so/calendar.c @@ -0,0 +1,359 @@ +/*-------------------------------------------------------*/ +/* calendar.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¸U¦~¾ä */ +/* create : 02/08/31 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_CALENDAR + +/* $NetBSD: cal.c,v 1.10 1998/07/28 19:26:09 mycroft Exp $ */ + +/* + * Copyright (c) 1989, 1993, 1994 The Regents of the University of + * California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by Kim Letkeman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 3. All advertising + * materials mentioning features or use of this software must display the + * following acknowledgement: This product includes software developed by the + * University of California, Berkeley and its contributors. 4. Neither the + * name of the University nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#define TM_YEAR_BASE 1900 + +#define THURSDAY 4 /* for reformation */ +#define SATURDAY 6 /* 1 Jan 1 was a Saturday */ + +#define FIRST_MISSING_DAY 639799 /* 3 Sep 1752 */ +#define NUMBER_MISSING_DAYS 11 /* 11 day correction */ + +#define MAXDAYS 42 /* max slots in a month array */ +#define SPACE -1 /* used in day array */ + + +static int days_in_month[2][13] = +{ + {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, +}; + +static int sep1752[MAXDAYS] = +{ + SPACE, SPACE, 1, 2, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, +}; + +static int empty[MAXDAYS] = +{ + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, +}; + +static char *month_names[12] = +{ + "¤@¤ë", "¤G¤ë", "¤T¤ë", "¥|¤ë", "¤¤ë", "¤»¤ë", + "¤C¤ë", "¤K¤ë", "¤E¤ë", "¤Q¤ë", "¤Q¤@¤ë", "¤Q¤G¤ë" +}; + +static char *day_headings = "¤é ¤@ ¤G ¤T ¥| ¤ ¤»"; + +/* leap year -- account for gregorian reformation in 1752 */ +#define leap_year(yr) ((yr) <= 1752 ? !((yr) % 4) : (!((yr) % 4) && ((yr) % 100)) || !((yr) % 400)) + +/* number of centuries since 1700, not inclusive */ +#define centuries_since_1700(yr) ((yr) > 1700 ? (yr) / 100 - 17 : 0) + +/* number of centuries since 1700 whose modulo of 400 is 0 */ +#define quad_centuries_since_1700(yr) ((yr) > 1600 ? ((yr) - 1600) / 400 : 0) + +/* number of leap years between year 1 and this year, not inclusive */ +#define leap_years_since_year_1(yr) ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr)) + +#define DAY_LEN 3 /* 3 spaces per day */ +#define WEEK_LEN 20 /* 7 * 3 - one space at the end */ +#define HEAD_SEP 2 /* spaces between day headings */ + + +/* + * day_in_year -- return the 1 based day number within the year + */ +static int +day_in_year(day, month, year) + int day, month, year; +{ + int i, leap; + + leap = leap_year(year); + for (i = 1; i < month; i++) + day += days_in_month[leap][i]; + return (day); +} + + +/* + * day_in_week return the 0 based day number for any date from 1 Jan. 1 to 31 + * Dec. 9999. Assumes the Gregorian reformation eliminates 3 Sep. 1752 + * through 13 Sep. 1752. Returns Thursday for all missing days. + */ +static int +day_in_week(day, month, year) + int day, month, year; +{ + int temp; + + temp = (year - 1) * 365 + leap_years_since_year_1(year - 1) + day_in_year(day, month, year); + if (temp < FIRST_MISSING_DAY) + return ((temp - 1 + SATURDAY) % 7); + if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS)) + return (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7); + return (THURSDAY); +} + + +/* + * day_array -- Fill in an array of 42 integers with a calendar. Assume for + * a moment that you took the (maximum) 6 rows in a calendar and stretched + * them out end to end. You would have 42 numbers or spaces. This routine + * builds that array for any month from Jan. 1 through Dec. 9999. + */ +static void +day_array(month, year, days) + int month, year; + int *days; +{ + int day, dw, dm; + + if (month == 9 && year == 1752) + { + memmove(days, sep1752, MAXDAYS * sizeof(int)); + return; + } + memmove(days, empty, MAXDAYS * sizeof(int)); + dm = days_in_month[leap_year(year)][month]; + dw = day_in_week(1, month, year); + day = 1; + while (dm--) + days[dw++] = day++; +} + + +static char * +ascii_day(p, day) + char *p; + int day; +{ + static char *aday[] = + { + "", + " 1", " 2", " 3", " 4", " 5", " 6", " 7", + " 8", " 9", "10", "11", "12", "13", "14", + "15", "16", "17", "18", "19", "20", "21", + "22", "23", "24", "25", "26", "27", "28", + "29", "30", "31", + }; + + if (day == SPACE) + { + memset(p, ' ', DAY_LEN); + p += DAY_LEN; + } + else + { + *p++ = aday[day][0]; + *p++ = aday[day][1]; + *p++ = ' '; + } + + return p; +} + + +static void +monthly(year, month) + int year, month; +{ + int col, row, len, days[MAXDAYS]; + char *p, buf[80]; + + day_array(month, year, days); + len = snprintf(buf, sizeof(buf), "%s %d", month_names[month - 1], year); + + vs_bar("¸U¦~¤ë¾ä"); + move(2, 5); + outs("Y¥¼¿é¤J¤ë¥÷¥i¬d¸ß¦~¾ä"); + move(4, 6); + prints("\033[1;35m%*s%s", (WEEK_LEN - len) / 2, "", buf); + move(6, 6); + prints("\033[1;36m%s\033[m", day_headings); + + for (row = 0; row < 6; row++) + { + for (col = 0, p = buf; col < 7; col++) + { + if (col == 0) /* ¬P´Á¤é */ + { + move(7 + row, 6); + strcpy(p, "\033[1;31m"); + p += 7; + } + else if (col == 1) /* ¬P´Á¤@¡ã¤ */ + { + strcpy(p, "\033[37m"); + p += 5; + } + else if (col == 6) /* ¬P´Á¤» */ + { + strcpy(p, "\033[32m"); + p += 5; + } + p = ascii_day(p, days[row * 7 + col]); + } + strcpy(p, "\033[m\n"); + outs(buf); + } + + vmsg(NULL); +} + + +static void +center(fp, str, len, separate) + FILE *fp; + char *str; + int len; + int separate; +{ + len -= strlen(str); + fprintf(fp, "%*s%s%*s", len / 2, "", str, len / 2 + len % 2, ""); + if (separate) + fprintf(fp, "%*s", separate, ""); +} + + +static void +yearly(fpath, year) + char *fpath; + int year; +{ + int col, *dp, i, month, row, which_cal; + int days[12][MAXDAYS]; + char *p, buf[80]; + FILE *fp; + + /* ¦~¾ä·|¶W¹L¤@¶¡A¥Î more() ªº */ + + if (fp = fopen(fpath, "w")) + { + sprintf(buf, "%d", year); + center(fp, buf, WEEK_LEN * 3 + HEAD_SEP * 2, 0); + fprintf(fp, "\n"); + for (i = 0; i < 12; i++) + day_array(i + 1, year, days[i]); + memset(buf, ' ', sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + for (month = 0; month < 12; month += 3) + { + center(fp, month_names[month], WEEK_LEN, HEAD_SEP); + center(fp, month_names[month + 1], WEEK_LEN, HEAD_SEP); + center(fp, month_names[month + 2], WEEK_LEN, 0); + fprintf(fp, "\n%s%*s%s%*s%s\n", + day_headings, HEAD_SEP, "", day_headings, HEAD_SEP, "", day_headings); + for (row = 0; row < 6; row++) + { + for (which_cal = 0; which_cal < 3; which_cal++) + { + p = buf + which_cal * (WEEK_LEN + 2); + dp = &days[month + which_cal][row * 7]; + for (col = 0; col < 7; col++) + p = ascii_day(p, *dp++); + } + *p = '\0'; + fprintf(fp, "%s\n", buf); + } + } + fprintf(fp, "\n"); + fclose(fp); + + more(fpath, NULL); + unlink(fpath); + } +} + + +int +main_calendar() +{ + int year, month; + time_t now; + struct tm *ptime; + char fpath[64], ans[5]; + + time(&now); + ptime = localtime(&now); + year = ptime->tm_year + 1900; + month = ptime->tm_mon + 1; + sprintf(fpath, "tmp/%s.calendar", cuser.userid); + + for (;;) + { + if (month) /* ¤ë¾ä */ + monthly(year, month); + else /* ¦~¾ä */ + yearly(fpath, year); + + if (!vget(b_lines, 0, "½Ð¿é¤Jn¬d¸ßªº¦~¥÷¡G", ans, 5, DOECHO)) + return 0; + year = atoi(ans); + if (year < 1 || year > 9999) + return 0; + + if (!vget(b_lines, 0, "½Ð¿é¤Jn¬d¸ßªº¤ë¥÷¡G", ans, 3, DOECHO)) + { + month = 0; + } + else + { + month = atoi(ans); + if (month < 1 || month > 12) + return 0; + } + } +} +#endif /* HAVE_CALENDAR */ diff --git a/so/chat.c b/so/chat.c new file mode 100644 index 0000000..db833e2 --- /dev/null +++ b/so/chat.c @@ -0,0 +1,827 @@ +/*-------------------------------------------------------*/ +/* chat.c ( NTHU CS MapleBBS Ver 2.36 ) */ +/*-------------------------------------------------------*/ +/* target : chat client for xchatd */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> + + +static char chatroom[IDLEN]; /* Chat-Room Name */ +static int chatline; /* Where to display message now */ +static char chatopic[48]; +static FILE *frec; + + +#define stop_line (b_lines - 2) + + +extern char *bmode(); + + +static void +chat_topic() +{ + move(0, 0); + prints("[1;37;46m %s«Ç¡G%-14s[45m ¸ÜÃD¡G%-48s[m", + (frec ? "¿ýµ" : "½Í¤Ñ"), chatroom, chatopic); +} + + +static void +printchatline(msg) + char *msg; +{ + int line; + + line = chatline; + move(line, 0); + outs(msg); + outc('\n'); + + if (frec) + fprintf(frec, "%s\n", msg); + + if (++line == stop_line) + line = 2; + move(line, 0); + outs("¡÷"); + clrtoeol(); + chatline = line; +} + + +static void +chat_record() +{ + FILE *fp; + time_t now; + char buf[80]; + + time(&now); + + if (fp = frec) + { + fprintf(fp, "%s\nµ²§ô¡G%s\n", msg_seperator, Btime(&now)); + fclose(fp); + frec = NULL; + printchatline("¡» ¿ýµ§¹²¦¡I"); + } + else + { +#ifdef EVERY_Z + /* Thor.980602: ¥Ñ©ó tbf_ask() »Ý°ÝÀɦW¡A¦¹®É·|¥Î¨ì igetch()¡A + ¬°¤F¨¾¤î I_OTHERDATA ³y¦¨·í¦í¡A¦b¦¹¥Î every_Z() ªº¤è¦¡¡A + ¥ý«O¦s vio_fd¡A«Ý°Ý§¹«á¦AÁÙì */ + + vio_save(); /* Thor.980602: ¼È¦s vio_fd */ +#endif + + usr_fpath(buf, cuser.userid, tbf_ask()); + +#ifdef EVERY_Z + vio_restore(); /* Thor.980602: ÁÙì vio_fd */ +#endif + + move(b_lines, 0); + clrtoeol(); + + fp = fopen(buf, "a"); + if (fp) + { + fprintf(fp, "¥DÃD: %s\n¥]´[: %s\n¿ýµ: %s (%s)\n¶}©l: %s\n%s\n", + chatopic, chatroom, cuser.userid, cuser.username, + Btime(&now), msg_seperator); + printchatline("¡» ¶}©l¿ýµÅo¡I"); + frec = fp; + } + else + { + printchatline("¡» ¿ýµ¾÷¬G»Ù¤F¡A½Ð³qª¾¯¸ªøºû×"); + } + } + bell(); + chat_topic(); +} + + +static void +chat_clear() +{ + int line; + + for (line = 2; line < stop_line; line++) + { + move(line, 0); + clrtoeol(); + } + chatline = stop_line - 1; + printchatline(""); +} + + +static void +print_chatid(chatid) + char *chatid; +{ + move(b_lines - 1, 0); + outs(chatid); + outc(':'); +} + + +static inline int +chat_send(fd, buf) + int fd; + char *buf; +{ + int len; + + len = strlen(buf); + return (send(fd, buf, len, 0) == len); +} + + +static inline int +chat_recv(fd, chatid) + int fd; + char *chatid; +{ + static char buf[512]; + static int bufstart = 0; + int cc, len; + char *bptr, *str; + + bptr = buf; + cc = bufstart; + len = sizeof(buf) - cc - 1; + if ((len = recv(fd, bptr + cc, len, 0)) <= 0) + return -1; + cc += len; + + for (;;) + { + len = strlen(bptr); + + if (len >= cc) + { /* wait for trailing data */ + memcpy(buf, bptr, len); + bufstart = len; + break; + } + if (*bptr == '/') + { + str = bptr + 1; + fd = *str++; + + if (fd == 'c') + { + chat_clear(); + } + else if (fd == 'n') + { + str_ncpy(chatid, str, 9); + + /* Thor.980819: ¶¶«K´«¤@¤U mateid ¦n¤F... */ + str_ncpy(cutmp->mateid, str, sizeof(cutmp->mateid)); + + print_chatid(chatid); + clrtoeol(); + } + else if (fd == 'r') + { + str_ncpy(chatroom, str, sizeof(chatroom)); + chat_topic(); + } + else if (fd == 't') + { + str_ncpy(chatopic, str, sizeof(chatopic)); + chat_topic(); + } + } + else + { + printchatline(bptr); + } + + cc -= ++len; + if (cc <= 0) + { + bufstart = 0; + break; + } + bptr += len; + } + + return 0; +} + + +static void +chat_pager(arg) + char *arg; +{ + cuser.ufo ^= UFO_PAGER; + cutmp->ufo ^= UFO_PAGER; + /* Thor.980805: ¸Ñ¨Mufo ¦P¨B°ÝÃD */ + + sprintf(arg, "¡» ±zªº©I¥s¾¹¤w¸g%s¤F!", + cuser.ufo & UFO_PAGER ? "Ãö³¬" : "¥´¶}"); + printchatline(arg); +} + + +#if 0 +/* Thor.980727: ©M /flag ½Äkey */ +static void +chat_write(arg) + char *arg; +{ + int uno; + UTMP *up; + char *str; + CallMsg cmsg; + + strtok(arg, STR_SPACE); + if ((str = strtok(NULL, STR_SPACE)) && (uno = acct_userno(str)) > 0) + { + cmsg.recver = uno; /* ¥ý°O¤U userno §@¬° check */ + if (up = utmp_find(uno)) + { + if (can_override(up)) + { + if (str = strtok(NULL, "\n")) /* Thor.980725:§ì¾ã¥y¸Ü */ + { /* Thor.980724: ±q my_write §ï¹L¨Ó */ + int len; + char buf[80]; + extern char fpmsg[]; + /* Thor.980722: msg file¥[¤W¦Û¤v»¡ªº¸Ü */ + + sprintf(fpmsg + 4, "%s-", cuser.userid); + /* Thor.980722: ɥΠlen·í¤@¤Ufd :p */ + len = open(fpmsg, O_WRONLY | O_CREAT | O_APPEND, 0600); + sprintf(buf, "µ¹%s¡G%s\n", up->userid, str); + write(len, buf, strlen(buf)); + close(len); + + sprintf(buf, "%s(%s", cuser.userid, cuser.username); + len = strlen(str); + buf[71 - len] = '\0'; + sprintf(cmsg.msg, "\033[1;33;46m¡¹ %s) \033[37;45m %s \033[m", buf, str); + + cmsg.caller = cutmp; + cmsg.sender = cuser.userno; + + if (do_write(up, &cmsg)) + printchatline("¡» ¹ï¤è¤w¸gÂ÷¥h"); + } + else + { + printchatline("¡» §O¥u¯w²´¡A»¡¨Ç¸Ü§a¡I"); + } + } + else + { + printchatline("¡» ¹ï¤è§â¦Õ¦·Ý³¦í»¡¡G¡y§Ú¨SÅ¥¨ì¡K¡K§Ú¨SÅ¥¨ì¡K¡K¡z"); + } + } + else + { + printchatline("¡» ¹ï¤è¤£¦b¯¸¤W"); + } + } + else + { + printchatline(err_uid); + } +} + + +static int +printuserent(uentp) + user_info *uentp; +{ + static char uline[80]; + static int cnt; + char pline[30]; + int cloak; + + if (!uentp) + { + if (cnt) + printchatline(uline); + memset(uline, 0, 80); + return cnt = 0; + } + cloak = uentp->ufo & UFO_CLOAK; + if (cloak && !HAS_PERM(PERM_SEECLOAK)) + return 0; + + sprintf(pline, " %-13s%c%-10s", uentp->userid, + cloak ? '#' : ' ', bmode(uentp, 1)); + if (cnt < 2) + strcat(pline, "¢x"); + strcat(uline, pline); + if (++cnt == 3) + { + printchatline(uline); + memset(uline, 0, 80); + cnt = 0; + } + return 0; +} + + +static void +chat_users() +{ /* ¦]¬°¤H¼Æ°Ê»³¤W¦Ê¡A·N¸q¤£¤j */ + printchatline(""); + printchatline("¡i " BBSNAME "¹C«È¦Cªí ¡j"); + printchatline(MSG_CHAT_ULIST); + + if (apply_ulist(printuserent) == -1) + printchatline("ªÅµL¤@¤H"); + + printuserent(NULL); +} +#endif + + +struct chat_command +{ + char *cmdname; /* Char-room command length */ + void (*cmdfunc) (); /* Pointer to function */ +}; + + +struct chat_command chat_cmdtbl[] = +{ + {"pager", chat_pager}, + {"tape", chat_record}, + +#if 0 + /* Thor.980727: ©M /flag ½Äkey */ + {"fire", chat_write}, + + {"users", chat_users}, +#endif + + {NULL, NULL} +}; + + +static inline int +chat_cmd_match(buf, str) + char *buf; + char *str; +{ + int c1, c2; + + for (;;) + { + c1 = *str++; + if (!c1) + break; + + c2 = *buf++; + if (!c2 || c2 == ' ' || c2 == '\n') + break; + + if (c2 >= 'A' && c2 <= 'Z') + c2 |= 0x20; + + if (c1 != c2) + return 0; + } + + return 1; +} + + +static inline int +chat_cmd(fd, buf) + int fd; + char *buf; +{ + struct chat_command *cmd; + char *key; + + buf++; + for (cmd = chat_cmdtbl; key = cmd->cmdname; cmd++) + { + if (chat_cmd_match(buf, key)) + { + cmd->cmdfunc(buf); + return '/'; + } + } + + return 0; +} + + +extern char lastcmd[MAXLASTCMD][80]; + +#define CHAT_YPOS 10 + + +int +t_chat() +{ + ACCT acct; + int ch, cfd, cmdpos, cmdcol; + char *ptr, buf[80], chatid[9]; + struct sockaddr_in sin; +#if defined(__OpenBSD__) + struct hostent *h; +#endif + +#ifdef CHAT_SECURE + extern char passbuf[]; +#endif + +#ifdef EVERY_Z + /* Thor.980725: ¬° talk & chat ¥i¥Î ^z §@·Ç³Æ */ + if (vio_holdon()) + { + vmsg("±zÁ¿¸ÜÁ¿¤@¥bÁÙ¨SÁ¿§¹C"); + return -1; + } +#endif + +#if defined(__OpenBSD__) + + if (!(h = gethostbyname(str_host))) + return -1; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(CHAT_PORT); + memcpy(&sin.sin_addr, h->h_addr, h->h_length); + +#else + + sin.sin_family = AF_INET; + sin.sin_port = htons(CHAT_PORT); + /* sin.sin_addr.s_addr = INADDR_LOOPBACK; */ + /* sin.sin_addr.s_addr = INADDR_ANY; */ + /* for FreeBSD 4.x */ + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); + +#endif + + cfd = socket(AF_INET, SOCK_STREAM, 0); + if (cfd < 0) + return -1; + + if (connect(cfd, (struct sockaddr *) & sin, sizeof sin)) + { + close(cfd); + blog("CHAT ", "connect"); + return -1; + } + + for (;;) + { + ch = vget(b_lines, 0, "½Ð¿é¤J²á¤Ñ¥N¸¹¡G", chatid, 9, DOECHO); + if (ch == '/') + { + continue; + } + else if (!ch) + { + /* str_ncpy(chatid, cuser.userid, sizeof(chatid)); */ + close(cfd); /* itoc.010322: ¤j³¡¤À³£¬O»~«ö¨ì Talk->Chat §ï¦¨¹w³]¬°Â÷¶} */ + return 0; + } + else + { + /* itoc.010528: ¤£¥i¥H¥Î§O¤Hªº id °µ¬°²á¤Ñ¥N¸¹ */ + if (acct_load(&acct, chatid) >= 0 && acct.userno != cuser.userno) + { + vmsg("©êºp³oÓ¥N¸¹¦³¤Hµù¥U¬° id¡A©Ò¥H±z¤£¯à·í¦¨²á¤Ñ¥N¸¹"); + continue; + } + /* Thor.980911: chatid¤¤¤£¥i¥HªÅ¥Õ, ¨¾¤î parse¿ù»~ */ + for(ch = 0; ch < 8; ch++) + { + if (chatid[ch] == ' ') + break; + else if (!chatid[ch]) /* Thor.980921: ¦pªG0ªº¸Ü´Nµ²§ô */ + ch = 8; + } + if (ch < 8) + continue; + } + +#ifdef CHAT_SECURE /* Thor.980729: secured chat room */ + +#if 0 + §@ªÌ opus (¤H¥Í¦³¨ý¬O²MÅw) ¯¸¤º sysopplan + ¼ÐÃD Re: Ãö©ó chatroom + ®É¶¡ Wed Jul 30 03:14:56 1997 + ¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w + + > passwd ¬O³sÄòªº«DªÅ¥Õ¦r¤¸¶Ü?? + + ¤TÓ°Ñ¼Æ userid + chatid + passwd ¤¤, userid/chatid ¬Ò¤£§t space, + ¦Ó passwd ¥i¥]§t space, ©Ò¥H¥²¶·±N¥¦Â\¦b²Ä¤TÓ¦ì¸m¥H«K token-parsing¡C + + > ¥t¥~, ACCT ¤¤ªº passwd ¬OPASSLEN¦Û°Ê¸ÉªÅ¥ÕÁÙ¬On¤â°Ê¥[? + > ·|¦Û°Ê¸Éº¡¶Ü? + + Unix ªº crypt ³Ì¦h¥u¨ú«e 14 Ó¦r, ©Ò¥H¤£¥[¥ç¥i¡C + ³oÓ¦a¤è °Ñ·Ó user login ªº¦a¤è¼g´N¦n¤F¡C + + -- + ¡° Origin: ·¬¾ôÅæ¯¸(bbs.cs.nthu.edu.tw) From: thcs-8.cs.nthu.edu.tw +#endif + + /* Thor.980819: ®³±¼userno */ + /* Thor.980730: passwd §ï¬°³Ì«áªº°Ñ¼Æ */ + /* Thor.980813: passwd §ï¬°¯u¥¿ªº password */ + /* Thor.980813: xchatd¤¤, chatid ¦Û°Ê¸õ¹LªÅ¥Õ, ©Ò¥H¦³ªÅ¥Õ·| invalid login */ +#if 0 + sprintf(buf, "/! %d %s %s %s\n", + cuser.userno, cuser.userid, chatid, cuser.passwd); + cuser.userno, cuser.userid, chatid, passbuf); +#endif + sprintf(buf, "/! %s %s %s\n", + cuser.userid, chatid, passbuf); + +#else + sprintf(buf, "/! %d %d %s %s\n", + cuser.userno, cuser.userlevel, cuser.userid, chatid); +#endif + + chat_send(cfd, buf); + if (recv(cfd, buf, 3, 0) != 3) + return 0; + + if (!strcmp(buf, CHAT_LOGIN_OK)) + break; + else if (!strcmp(buf, CHAT_LOGIN_EXISTS)) + ptr = "³oÓ¥N¸¹¤w¸g¦³¤H¥Î¤F"; + else if (!strcmp(buf, CHAT_LOGIN_INVALID)) + ptr = "³oÓ¥N¸¹¬O¿ù»~ªº"; + else if (!strcmp(buf, CHAT_LOGIN_BOGUS)) + { /* Thor: ¸T¤î¬Û¦P¤G¤H¶i¤J */ + close(cfd); + vmsg("½Ð¤Å¬£»º¡u¤À¨¡v¶i¤J½Í¤Ñ«Ç"); + return 0; + } + move(b_lines - 1, 0); + outs(ptr); + clrtoeol(); + bell(); + } + + clear(); + move(1, 0); + outs(msg_seperator); + move(stop_line, 0); + outs(msg_seperator); + print_chatid(chatid); + memset(ptr = buf, 0, sizeof(buf)); + chatline = 2; + cmdcol = 0; + cmdpos = -1; + + add_io(cfd, 60); + + strcpy(cutmp->mateid, chatid); + + for (;;) + { + move(b_lines - 1, cmdcol + CHAT_YPOS); + ch = vkey(); + + if (ch == I_OTHERDATA) + { /* incoming */ + if (chat_recv(cfd, chatid) == -1) + break; + continue; + } + + if (isprint2(ch)) + { + if (cmdcol < 68) + { + if (ptr[cmdcol]) + { /* insert */ + int i; + + for (i = cmdcol; ptr[i] && i < 68; i++); + ptr[i + 1] = '\0'; + for (; i > cmdcol; i--) + ptr[i] = ptr[i - 1]; + } + else + { /* append */ + ptr[cmdcol + 1] = '\0'; + } + ptr[cmdcol] = ch; + move(b_lines - 1, cmdcol + CHAT_YPOS); + outs(&ptr[cmdcol++]); + } + continue; + } + + if (ch == '\n') + { +#ifdef EVERY_BIFF + /* Thor.980805: ¦³¤H¦b®ÇÃä«öenter¤~»Ýncheck biff */ + static int old_biff; + int biff = HAS_STATUS(STATUS_BIFF); + if (biff && !old_biff) + printchatline("¡» ¾´! ¶l®t¨Ó«ö¹a¤F!"); + old_biff = biff; +#endif + if (ch = *ptr) + { + if (ch == '/') + ch = chat_cmd(cfd, ptr); + + /* Thor.980602: ¦³Ónª`·Nªº¤p¦a¤è, 쥻¦pªG¬O¡y/¡z, + ·|¨q¥X /helpªºµe±, + ²{¦b¥´ /, ·|Åܦ¨ /p ¤Á´« pager */ + + /* Thor.980925: «O¯d ptr ³Ìì©l¼Ë, ¤£¥[ /n */ + for (cmdpos = MAXLASTCMD - 1; cmdpos; cmdpos--) + strcpy(lastcmd[cmdpos], lastcmd[cmdpos - 1]); + strcpy(lastcmd[0], ptr); + + if (ch != '/') + { + strcat(ptr, "\n"); + if (!chat_send(cfd, ptr)) + break; + } + if (*ptr == '/' && ptr[1] == 'b') + break; + +#if 0 + for (cmdpos = MAXLASTCMD - 1; cmdpos; cmdpos--) + strcpy(lastcmd[cmdpos], lastcmd[cmdpos - 1]); + strcpy(lastcmd[0], ptr); +#endif + + *ptr = '\0'; + cmdcol = 0; + cmdpos = -1; + move(b_lines - 1, CHAT_YPOS); + clrtoeol(); + } + continue; + } + + if (ch == KEY_BKSP) + { + if (cmdcol) + { + ch = cmdcol; + cmdcol--; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: §PÂ_²{¦b§R°£ªº¦ì¸m¬O§_¬°º~¦rªº«á¥b¬q¡AY¬O§R¤G¦r¤¸ */ + if ((cuser.ufo & UFO_ZHC) && cmdcol && IS_ZHC_LO(ptr, cmdcol)) + cmdcol--; +#endif + strcpy(ptr + cmdcol, ptr + ch); + move(b_lines - 1, cmdcol + CHAT_YPOS); + outs(ptr + cmdcol); + clrtoeol(); + } + continue; + } + + if (ch == KEY_DEL) + { + if (ptr[cmdcol]) + { +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: §PÂ_²{¦b§R°£ªº¦ì¸m¬O§_¬°º~¦rªº«e¥b¬q¡AY¬O§R¤G¦r¤¸ */ + if ((cuser.ufo & UFO_ZHC) && ptr[cmdcol + 1] && IS_ZHC_HI(ptr[cmdcol])) + ch = 2; + else +#endif + ch = 1; + strcpy(ptr + cmdcol, ptr + cmdcol + ch); + move(b_lines - 1, cmdcol + CHAT_YPOS); + outs(ptr + cmdcol); + clrtoeol(); + } + continue; + } + + if (ch == Ctrl('D')) + { + chat_send(cfd, "/b\n"); /* /bye Â÷¶} */ + break; + } + + if (ch == Ctrl('C')) /* itoc.µù¸Ñ: ²M°£ input ¾ã¦æ */ + { + *ptr = '\0'; + cmdcol = 0; + move(b_lines - 1, CHAT_YPOS); + clrtoeol(); + continue; + } + + if (ch == KEY_HOME || ch == Ctrl('A')) + { + cmdcol = 0; + continue; + } + + if (ch == KEY_END || ch == Ctrl('E')) + { + cmdcol = strlen(ptr); + continue; + } + + if (ch == KEY_LEFT) + { + if (cmdcol) + { + cmdcol--; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: ¥ª²¾®É¸I¨ìº~¦r²¾Âù®æ */ + if ((cuser.ufo & UFO_ZHC) && cmdcol && IS_ZHC_LO(ptr, cmdcol)) + cmdcol--; +#endif + } + continue; + } + + if (ch == KEY_RIGHT) + { + if (ptr[cmdcol]) + { + cmdcol++; +#ifdef HAVE_MULTI_BYTE + /* hightman.060504: ¥k²¾®É¸I¨ìº~¦r²¾Âù®æ */ + if ((cuser.ufo & UFO_ZHC) && ptr[cmdcol] && IS_ZHC_HI(ptr[cmdcol - 1])) + cmdcol++; +#endif + } + continue; + } + +#ifdef EVERY_Z + /* Thor: Chat ¤¤«ö ctrl-z */ + if (ch == Ctrl('Z')) + { + char buf[IDLEN + 1]; + screenline slt[T_LINES]; + + /* Thor.980731: ¼È¦s mateid, ¦]¬°¥X¥h®É¥i¯à·|¥Î±¼ mateid */ + strcpy(buf, cutmp->mateid); + + vio_save(); /* Thor.980727: ¼È¦s vio_fd */ + vs_save(slt); + every_Z(0); + vs_restore(slt); + vio_restore(); /* Thor.980727: ÁÙì vio_fd */ + + /* Thor.980731: ÁÙì mateid, ¦]¬°¥X¥h®É¥i¯à·|¥Î±¼ mateid */ + strcpy(cutmp->mateid, buf); + continue; + } +#endif + + if (ch == KEY_DOWN) + { + cmdpos += MAXLASTCMD - 2; + ch = KEY_UP; + } + + if (ch == KEY_UP) + { + cmdpos++; + cmdpos %= MAXLASTCMD; + strcpy(ptr, lastcmd[cmdpos]); + move(b_lines - 1, CHAT_YPOS); + outs(ptr); + clrtoeol(); + cmdcol = strlen(ptr); + } + } + + if (frec) + chat_record(); + + close(cfd); + add_io(0, 60); + cutmp->mateid[0] = '\0'; + return 0; +} diff --git a/so/classtable.c b/so/classtable.c new file mode 100644 index 0000000..4f6ef16 --- /dev/null +++ b/so/classtable.c @@ -0,0 +1,311 @@ +/*-------------------------------------------------------*/ +/* classtable.c ( YZU WindTopBBS Ver 3.02 ) */ +/*-------------------------------------------------------*/ +/* target : ¥\½Òªí */ +/* create : / / */ +/* update : 02/07/12 */ +/* author : */ +/* modify : itoc.bbs@bbs.ee.nctu.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_CLASSTABLE + +/* ----------------------------------------------------- */ +/* classtable.c ¤¤¹B¥Îªº¸ê®Æµ²ºc */ +/* ----------------------------------------------------- */ + + +#define MAX_WEEKDAY 6 /* ¤@¬P´Á¦³ 6 ¤Ñ */ +#define MAX_DAYCLASS 16 /* ¤@¤Ñ¦³ 16 ¸` */ + + +typedef struct +{ + char name[9]; /* ½Ò¦W */ + char teacher[9]; /* ±Ð®v */ + char class[5]; /* ±Ð«Ç */ + char objid[7]; /* ½Ò¸¹ */ +} CLASS; + + +typedef struct +{ + CLASS table[MAX_WEEKDAY][MAX_DAYCLASS]; /* ¤@¬P´Á MAX_WEEKDAY * MAX_DAYCLASS °ó½Ò */ +} CLASS_TABLE; + + +typedef struct +{ + char c_class[5]; /* ²Ä´X¸` */ + char c_start[6]; /* ¤W½Ò®É¶¡ */ + char c_break[6]; /* ¤U½Ò®É¶¡ */ +} CLOCK; + + +static CLOCK class_time[MAX_DAYCLASS] = /* ½Ò°ó®É¶¡ */ +{ + {" ¤@ ", "06:00", "06:50"}, + {" ¤G ", "07:00", "07:50"}, + {" ¤T ", "08:00", "08:50"}, + {" ¥| ", "09:00", "09:50"}, + {" ¤ ", "10:10", "11:00"}, + {" ¤» ", "11:10", "12:00"}, + {" ¤C ", "12:30", "13:20"}, + {" ¤K ", "13:30", "14:20"}, + {" ¤E ", "14:30", "15:20"}, + {" ¤Q ", "15:40", "16:30"}, + {"¤Q¤@", "16:40", "17:30"}, + {"¤Q¤G", "17:40", "18:30"}, + {"¤Q¤T", "18:30", "19:20"}, + {"¤Q¥|", "19:30", "20:20"}, + {"¤Q¤", "20:30", "21:20"}, + {"¤Q¤»", "21:30", "22:20"} +}; + + +/* ----------------------------------------------------- */ +/* CLASS ³B²z¨ç¼Æ */ +/* ----------------------------------------------------- */ + + +static void +class_show(x, y, class) + int x, y; + CLASS *class; +{ + move(x, y); + prints("½Ò¦W¡G%s", class->name); + move(x + 1, y); + prints("±Ð®v¡G%s", class->teacher); + move(x + 2, y); + prints("±Ð«Ç¡G%s", class->class); + move(x + 3, y); + prints("½Ò¸¹¡G%s", class->objid); +} + + +static void +class_edit(class) + CLASS *class; +{ + int echo; + + echo = *(class->name) ? GCARRY : DOECHO; + vget(4, 0, "½Ò¦W¡G", class->name, sizeof(class->name), echo); + vget(5, 0, "±Ð®v¡G", class->teacher, sizeof(class->teacher), echo); + vget(6, 0, "±Ð«Ç¡G", class->class, sizeof(class->class), echo); + vget(7, 0, "½Ò¸¹¡G", class->objid, sizeof(class->objid), echo); +} + + +static int /* 1:¥¿½T 0:¿ù»~ */ +class_number(day, class) /* ¶Ç¦^¬P´Á´X²Ä´X¸` */ + int *day; + int *class; +{ + char ans[5]; + + move(2, 0); + outs("503 ªí¥Ü¬P´Á¤²Ä¤T¸`"); + *day = vget(3, 0, "¤W½Ò®É¶¡¡G", ans, 4, DOECHO) - '1'; /* 503 ªí¥Ü¬P´Á¤²Ä¤T¸` */ + *class = atoi(ans + 1) - 1; + if (*day > MAX_WEEKDAY - 1 || *day < 0 || *class > MAX_DAYCLASS - 1 || *class < 0) + return 0; + + return 1; +} + + +/* ----------------------------------------------------- */ +/* CLASS_TABLE ³B²z¨ç¼Æ */ +/* ----------------------------------------------------- */ + + +static void +table_file(fpath, table) /* §â table ¼g¤J FN_CLASSTBL_LOG */ + char *fpath; + CLASS_TABLE *table; +{ + int i, j; + FILE *fp; + + fp = fopen(fpath, "w"); + + fprintf(fp, " ¬P´Á¤@ ¬P´Á¤G ¬P´Á¤T ¬P´Á¥| ¬P´Á¤ ¬P´Á¤»\n"); + for (i = 0; i < MAX_DAYCLASS; i++) + { + fprintf(fp, "²Ä%s¸` ", class_time[i].c_class); + for (j = 0; j < MAX_WEEKDAY; j++) + fprintf(fp, "%-8.8s ", table->table[j][i].name); + + fprintf(fp, "\n %s ", class_time[i].c_start); + for (j = 0; j < MAX_WEEKDAY; j++) + fprintf(fp, "%-8.8s ", table->table[j][i].teacher); + + fprintf(fp, "\n ¡õ "); + for (j = 0; j < MAX_WEEKDAY; j++) + fprintf(fp, "%-8.8s ", table->table[j][i].class); + + fprintf(fp, "\n %s ", class_time[i].c_break); + for (j = 0; j < MAX_WEEKDAY; j++) + fprintf(fp, "%-8.8s ", table->table[j][i].objid); + + fprintf(fp, "\n\n"); + } + fclose(fp); +} + + +static void +table_show(table) + CLASS_TABLE *table; +{ + char fpath[64]; + + usr_fpath(fpath, cuser.userid, FN_CLASSTBL_LOG); + table_file(fpath, table); + more(fpath, NULL); +} + + +static void +table_mail(table) + CLASS_TABLE *table; +{ + char fpath[64]; + + usr_fpath(fpath, cuser.userid, FN_CLASSTBL_LOG); + table_file(fpath, table); + mail_self(fpath, cuser.userid, "Ó¤H¥\\½Òªí", MAIL_READ); +} + + +static void +table_edit(table) + CLASS_TABLE *table; +{ + int i, j; + + vs_bar("½s¿èÓ¤H¥\\½Òªí"); + + if (class_number(&i, &j)) + { + class_edit(&(table->table[i][j])); + class_show(10, 0, &(table->table[i][j])); + } +} + + +static void +table_del(table) + CLASS_TABLE *table; +{ + int i, j; + + vs_bar("§R°£Ó¤H¥\\½Òªí"); + + if (!class_number(&i, &j)) + return; + + class_show(10, 0, &(table->table[i][j])); + + if (vans(msg_sure_ny) == 'y') + memset(&(table->table[i][j]), 0, sizeof(CLASS)); +} + + +static void +table_copy(table) + CLASS_TABLE *table; +{ + int i, j, x, y; + + vs_bar("Ó¤H¥\\½Òªí"); + + move(9, 0); + outs("¨Ó·½¡G"); + if (!class_number(&i, &j)) + return; + + class_show(10, 0, &(table->table[i][j])); + + move(9, 39); + outs("¥Øªº¡G"); + if (!class_number(&x, &y)) + return; + + class_show(10, 39, &(table->table[x][y])); + + if (vans(msg_sure_ny) == 'y') + memcpy(&(table->table[x][y]), &(table->table[i][j]), sizeof(CLASS)); +} + + +int +main_classtable() +{ + char fpath[64]; + CLASS_TABLE newtable, oldtable, *ptr; + + usr_fpath(fpath, cuser.userid, FN_CLASSTBL); + ptr = &newtable; + + if (rec_get(fpath, ptr, sizeof(CLASS_TABLE), 0)) + memset(ptr, 0, sizeof(CLASS_TABLE)); + memcpy(&oldtable, ptr, sizeof(CLASS_TABLE)); + + for (;;) + { + switch (vans("½Òªí¨t²Î (E/C/D)½s¿è/½Æ»s/§R°£ P)¦L¥X K)¥þ¬å S)¦sÀÉ M)«H½c Q)Â÷¶} [Q] ")) + { + case 'e': + table_edit(ptr); + break; + case 'd': + table_del(ptr); + break; + case 'c': + table_copy(ptr); + break; + + case 'p': + table_show(ptr); + break; + case 'm': + table_mail(ptr); + break; + + case 's': + rec_put(fpath, ptr, sizeof(CLASS_TABLE), 0, NULL); + memcpy(&oldtable, ptr, sizeof(CLASS_TABLE)); + vmsg("Àx¦s§¹¦¨"); + break; + case 'k': + if (vans(msg_sure_ny) == 'y') + { + unlink(fpath); + memset(ptr, 0, sizeof(CLASS_TABLE)); + memset(&oldtable, 0, sizeof(CLASS_TABLE)); + } + break; + + default: + goto end_loop; + } + } + +end_loop: + + /* Àˬd·s¬O§_¤@¼Ë¡AY¤£¤@¼Ën°Ý¬O§_¦sÀÉ */ + if (memcmp(&oldtable, ptr, sizeof(CLASS_TABLE))) + { + if (vans("¬O§_Àx¦s(Y/N)¡H[Y] ") != 'n') + rec_put(fpath, ptr, sizeof(CLASS_TABLE), 0, NULL); + } + + return 0; +} +#endif /* HAVE_CLASSTABLE */ diff --git a/so/credit.c b/so/credit.c new file mode 100644 index 0000000..933a5e8 --- /dev/null +++ b/so/credit.c @@ -0,0 +1,274 @@ +/*-------------------------------------------------------*/ +/* credit.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : °O±b¥»¡A°O¿ý¥Í¬¡¤¤ªº¦¬¤J¤ä¥X */ +/* create : 99/12/18 */ +/* update : 02/01/26 */ +/* author : wildcat@wd.twbbs.org */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_CREDIT + +/* ----------------------------------------------------- */ +/* credit.c ¤¤¹B¥Îªº¸ê®Æµ²ºc */ +/* ----------------------------------------------------- */ + +typedef struct +{ + int year; /* ¦~ */ + char month; /* ¤ë */ + char day; /* ¤é */ + + char flag; /* ¤ä¥X/¦¬¤J */ + int money; /* ª÷ÃB */ + char useway; /* Ãþ§O(¹¦ç¦í¦æ¨|¼Ö) */ + char desc[112]; /* »¡©ú */ /* ³o¤Óªø¤F¡A«O¯dµ¹¨ä¥LÄæ¦ì¨Ï¥Î */ +} CREDIT; + + +#define CREDIT_OUT 0x1 /* ¤ä¥X */ +#define CREDIT_IN 0x2 /* ¦¬¤J */ + +#define CREDIT_OTHER 0 /* ¨ä¥L */ +#define CREDIT_EAT 1 /* ¹ */ +#define CREDIT_WEAR 2 /* ¦ç */ +#define CREDIT_LIVE 3 /* ¦í */ +#define CREDIT_MOVE 4 /* ¦æ */ +#define CREDIT_EDU 5 /* ¨| */ +#define CREDIT_PLAY 6 /* ¼Ö */ + +static char fpath[64]; /* FN_CREDIT Àɮ׸ô®| */ + + +static void +credit_head() +{ + vs_head("°O±b¤â¥¾", str_site); + prints(NECKER_CREDIT, d_cols, ""); +} + + +static void +credit_body(page) + int page; +{ + CREDIT credit; + char *way[] = {"¨ä¥L", "[¹]", "[¦ç]", "[¦í]", "[¦æ]", "[¨|]", "[¼Ö]"}; + int fd; + + move(1, 65); + prints("²Ä %2d ¶", page + 1); + + move(3, 0); + clrtobot(); + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + int pos, n; + + pos = page * XO_TALL; /* ¤@¶¦³ XO_TALL µ§ */ + n = XO_TALL; + + while (n) + { + lseek(fd, (off_t) (sizeof(CREDIT) * pos), SEEK_SET); + if (read(fd, &credit, sizeof(CREDIT)) == sizeof(CREDIT)) + { + n--; + pos++; + prints("%6d %04d/%02d/%02d %s %8d %4s %.*s\n", + pos, credit.year, credit.month, credit.day, + credit.flag == CREDIT_OUT ? "\033[1;32m¤ä¥X\033[m" : "\033[1;31m¦¬¤J\033[m", + credit.money, + credit.flag == CREDIT_OUT ? way[credit.useway] : " ", + d_cols + 46, credit.desc); + } + else + { + break; + } + } + + close(fd); + } +} + + +static int +credit_add() +{ + CREDIT credit; + char buf[80]; + + move(3, 0); + clrtobot(); + + memset(&credit, 0, sizeof(CREDIT)); + + if (vget(5, 0, "¦¬¤ä (1)¦¬¤J (2)¤ä¥X [2] ", buf, 3, DOECHO) == '1') + credit.flag = CREDIT_IN; + else + credit.flag = CREDIT_OUT; + + vget(6, 0, "®É¶¡ (¦~¥÷) ", buf, 5, DOECHO); + credit.year = atoi(buf); + + vget(7, 0, "®É¶¡ (¤ë¥÷) ", buf, 3, DOECHO); + credit.month = atoi(buf); + + vget(8, 0, "®É¶¡ (¤é´Á) ", buf, 3, DOECHO); + credit.day = atoi(buf); + + vget(9, 0, "ª÷¿ú (¤¸) ", buf, 9, DOECHO); + credit.money = atoi(buf); + + if (credit.flag == CREDIT_OUT) /* ¤ä¥X¤~¦³°O¿ý¥Î³~ */ + { + int useway; + + useway = vget(10, 0, "¥Î³~ 0)¨ä¥L 1)¹ 2)¦ç 3)¦í 4)¦æ 5)¨| 6)¼Ö [0] ", buf, 3, DOECHO) - '0'; + if (useway > 6 || useway < 0) + useway = 0; + credit.useway = useway; + } + + vget(11, 0, "»¡©ú¡G", credit.desc, 51, DOECHO); + + rec_add(fpath, &credit, sizeof(CREDIT)); + return 1; +} + + +static int +credit_delete() +{ + int pos; + char buf[4]; + + vget(b_lines, 0, "n§R°£²Ä´Xµ§¸ê®Æ¡G", buf, 4, DOECHO); + pos = atoi(buf); + + if (rec_num(fpath, sizeof(CREDIT)) < pos) + { + vmsg("±z·d¿ùÅo¡A¨S¦³³oµ§¸ê®Æ"); + return 0; + } + + rec_del(fpath, sizeof(CREDIT), pos - 1, NULL); + return 1; +} + + +static int +credit_count() +{ + CREDIT *credit; + struct stat st; + int fd; + int way[7], moneyin, moneyout; + + if ((fd = open(fpath, O_RDONLY)) >= 0 && !fstat(fd, &st) && st.st_size > 0) + { + memset(way, 0, sizeof(way)); + moneyin = 0; + + mgets(-1); + while (credit = mread(fd, sizeof(CREDIT))) + { + if (credit->flag == CREDIT_OUT) /* ¤ä¥X¤~¦³°O¿ý¥Î³~ */ + way[credit->useway] += credit->money; + else + moneyin += credit->money; + } + close(fd); + + for (fd = 0; fd <= 6; fd++) + moneyout += way[fd]; + + move(3, 0); + clrtobot(); + + move(7, 0); + prints(" \033[1;31mÁ`¦¬¤J %12d ¤¸\033[m\n", moneyin); + prints(" \033[1;32mÁ`¤ä¥X %12d ¤¸\033[m\n\n", moneyout); + + prints("ªá¦b \033[1;36m [¹] %12d ¤¸ \033[32m [¦ç] %12d ¤¸\033[m\n", way[CREDIT_EAT], way[CREDIT_WEAR]); + prints(" \033[1;31m [¦í] %12d ¤¸ \033[33m [¦æ] %12d ¤¸\033[m\n", way[CREDIT_LIVE], way[CREDIT_MOVE]); + prints(" \033[1;35m [¨|] %12d ¤¸ \033[37m [¼Ö] %12d ¤¸\033[m\n", way[CREDIT_EDU], way[CREDIT_PLAY]); + prints(" \033[1;34m ¨ä¥L %12d ¤¸\033[m", way[CREDIT_OTHER]); + + vmsg(NULL); + return 1; + } + + vmsg("±z¨S¦³°O±b°O¿ý"); + return 0; +} + + + +int +main_credit() +{ + int page, redraw; + char buf[3]; + + credit_head(); + + usr_fpath(fpath, cuser.userid, FN_CREDIT); + page = 0; + redraw = 1; + + for (;;) + { + if (redraw) + credit_body(page); + + switch (vans("°O±b¤â¥¾ C)´«¶ 1)·s¼W 2)§R°£ 3)¥þ§R 4)Á`p Q)Â÷¶} [Q] ")) + { + case 'c': + vget(b_lines, 0, "¸õ¨ì²Ä´X¶¡G", buf, 3, DOECHO); + redraw = atoi(buf) - 1; + + if (page != redraw && redraw >= 0 && + redraw <= (rec_num(fpath, sizeof(CREDIT)) - 1) / XO_TALL) + { + page = redraw; + redraw = 1; + } + else + { + redraw = 0; + } + break; + + case '1': + redraw = credit_add(); + break; + + case '2': + redraw = credit_delete(); + break; + + case '3': + if (vans(MSG_SURE_NY) == 'y') + { + unlink(fpath); + return 0; + } + break; + + case '4': + redraw = credit_count(); + break; + + default: + return 0; + } + } +} +#endif /* HAVE_CREDIT */ diff --git a/so/help.c b/so/help.c new file mode 100644 index 0000000..b64f778 --- /dev/null +++ b/so/help.c @@ -0,0 +1,207 @@ +/*-------------------------------------------------------*/ +/* help.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : help »¡©ú¤å¥ó */ +/* create : 03/05/10 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +static void +do_help(path) /* itoc.021122: »¡©ú¤å¥ó */ + char *path; +{ + char *str; + char fpath[64]; + int num, pageno, pagemax, redraw, reload; + int ch, cur, i; + struct stat st; + PAL *pal; + + /* »¡©ú¤å¥ó³£©ñ¦b etc/help/ ¤U */ + sprintf(fpath, "etc/help/%s/%s", path, fn_dir); + str = strchr(fpath, '.'); + + reload = 1; + pageno = 0; + cur = 0; + pal = NULL; + + do + { + if (reload) + { + if (stat(fpath, &st) == -1) + return; + + i = st.st_size; + num = (i / sizeof(PAL)) - 1; + if (num < 0) + return; + + if ((ch = open(fpath, O_RDONLY)) >= 0) + { + pal = pal ? (PAL *) realloc(pal, i) : (PAL *) malloc(i); + read(ch, pal, i); + close(ch); + } + + pagemax = num / XO_TALL; + reload = 0; + redraw = 1; + } + + if (redraw) + { + /* itoc.µù¸Ñ: ºÉ¶q°µ±o¹³ xover ®æ¦¡ */ + vs_head("»¡©ú¤å¥ó", str_site); + prints(NECKER_HELP, d_cols, ""); + + i = pageno * XO_TALL; + ch = BMIN(num, i + b_lines - 4); + move(3, 0); + do + { + prints("%6d %-14s%s\n", i + 1, pal[i].userid, pal[i].ship); + i++; + } while (i <= ch); + + outf(FEETER_HELP); + move(3 + cur, 0); + outc('>'); + redraw = 0; + } + + ch = vkey(); + switch (ch) + { + case KEY_RIGHT: + case '\n': + case ' ': + case 'r': + i = cur + pageno * XO_TALL; + strcpy(str, pal[i].userid); + more(fpath, NULL); + strcpy(str, fn_dir); + redraw = 1; + break; + + case Ctrl('P'): + if (HAS_PERM(PERM_ALLADMIN)) + { + PAL new; + + memset(&new, 0, sizeof(PAL)); + + if (vget(b_lines, 0, "¼ÐÃD¡G", new.ship, sizeof(new.ship), DOECHO) && + vget(b_lines, 0, "ÀɮסG", new.userid, IDLEN + 1, DOECHO)) + { + strcpy(str, new.userid); + i = vedit(fpath, 0); + strcpy(str, fn_dir); + if (!i) + { + rec_add(fpath, &new, sizeof(PAL)); + num++; + cur = num % XO_TALL; /* ´å¼Ð©ñ¦b·s¥[¤Jªº³o½g */ + pageno = num / XO_TALL; + reload = 1; + } + } + redraw = 1; + } + break; + + case 'd': + if (HAS_PERM(PERM_ALLADMIN)) + { + if (vans(msg_del_ny) == 'y') + { + i = cur + pageno * XO_TALL; + strcpy(str, pal[i].userid); + unlink(fpath); + strcpy(str, fn_dir); + rec_del(fpath, sizeof(PAL), i, NULL); + cur = i ? ((i - 1) % XO_TALL) : 0; /* ´å¼Ð©ñ¦b¬å±¼ªº«e¤@½g */ + reload = 1; + } + redraw = 1; + } + break; + + case 'T': + if (HAS_PERM(PERM_ALLADMIN)) + { + i = cur + pageno * XO_TALL; + if (vget(b_lines, 0, "¼ÐÃD¡G", pal[i].ship, sizeof(pal[0].ship), GCARRY)) + rec_put(fpath, &pal[i], sizeof(PAL), i, NULL); + redraw = 1; + } + break; + + case 'E': + if (!HAS_STATUS(STATUS_EDITHELP)) /* Y¬O±q vedit ®É¶i¨Ó help «h¤£¯à¦A vedit */ + { + i = cur + pageno * XO_TALL; + strcpy(str, pal[i].userid); + vedit(fpath, HAS_PERM(PERM_ALLADMIN) ? 0 : -1); + strcpy(str, fn_dir); + redraw = 1; + } + break; + + case 'm': + if (HAS_PERM(PERM_ALLADMIN)) + { + char buf[40], ans[5]; + + i = cur + pageno * XO_TALL; + sprintf(buf, "½Ð¿é¤J²Ä %d ¿ï¶µªº·s¦ì¸m¡G", i + 1); + if (vget(b_lines, 0, buf, ans, 5, DOECHO)) + { + redraw = atoi(ans) - 1; /* ɥΠredraw */ + if (redraw < 0) + redraw = 0; + else if (redraw > num) + redraw = num; + + if (redraw != i) + { + if (!rec_del(fpath, sizeof(PAL), i, NULL)) + { + rec_ins(fpath, &pal[i], sizeof(PAL), redraw, 1); + cur = redraw % XO_TALL; + pageno = redraw / XO_TALL; + } + reload = 1; + } + } + redraw = 1; + } + break; + + default: + ch = xo_cursor(ch, pagemax, num, &pageno, &cur, &redraw); + break; + } + } while (ch != 'q'); + + free(pal); +} + + +#include <stdarg.h> + +int +vaHelp(pvar) + va_list pvar; +{ + char *path; + path = va_arg(pvar, char *); + do_help(path); + return 0; +} diff --git a/so/innbbs.c b/so/innbbs.c new file mode 100644 index 0000000..089430c --- /dev/null +++ b/so/innbbs.c @@ -0,0 +1,701 @@ +/*-------------------------------------------------------*/ +/* innbbs.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : Âà«H³]©w */ +/* create : 04/04/25 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +extern BCACHE *bshm; + + +/* ----------------------------------------------------- */ +/* nodelist.bbs ¤l¨ç¦¡ */ +/* ----------------------------------------------------- */ + + +static void +nl_item(num, nl) + int num; + nodelist_t *nl; +{ + prints("%6d %-13s%-*.*s %s(%d)\n", num, + nl->name, d_cols + 45, d_cols + 45, nl->host, nl->xmode & INN_USEIHAVE ? "IHAVE" : "POST", nl->port); +} + + +static void +nl_query(nl) + nodelist_t *nl; +{ + move(3, 0); + clrtobot(); + prints("\n\nÂà«H¯¸¥x¡G%s\n¯¸¥x¦ì§}¡G%s\n¯¸¥x¨ó©w¡G%s(%d)\n³Q Áý «H¡G%s", + nl->name, nl->host, nl->xmode & INN_USEIHAVE ? "IHAVE" : "POST", nl->port, nl->xmode & INN_FEEDED ? "¬O" : "§_"); + vmsg(NULL); +} + + +static int /* 1:¦¨¥\ 0:¥¢±Ñ */ +nl_add(fpath, old, pos) + char *fpath; + nodelist_t *old; + int pos; +{ + nodelist_t nl; + int ch, port; + char ans[8]; + char msg1[] = "¨ó©w¡G(1)IHAVE (2)POST [1] "; + char msg2[] = "¦¹¯¸¥x·|¥D°ÊÁý«Hµ¹¥»¯¸¶Ü(Y/N)¡H[N] "; + + if (old) + memcpy(&nl, old, sizeof(nodelist_t)); + else + memset(&nl, 0, sizeof(nodelist_t)); + + if (vget(b_lines, 0, "^¤å¯¸¦W¡G", nl.name, sizeof(nl.name), GCARRY) && + vget(b_lines, 0, "¯¸§}¡G", nl.host, /* sizeof(nl.host) */ 70, GCARRY)) + { + msg1[24] = (nl.xmode & INN_USEPOST) ? '2' : '1'; /* ·s¼W¸ê®Æ¹w³] INN_HAVE */ + ch = vans(msg1); + if (ch != '1' && ch != '2') + ch = msg1[24]; + + if (ch == '1') + { + nl.xmode = INN_USEIHAVE | INN_FEEDED; /* IHAVE ¤@©w¬O³QÁý«H */ + vget(b_lines, 0, "Port¡G[7777] ", ans, 6, DOECHO); + if ((port = atoi(ans)) <= 0) + port = 7777; + } + else /* if (ch == '2') */ + { + nl.xmode = INN_USEPOST; + vget(b_lines, 0, "Port¡G[119] ", ans, 6, DOECHO); + if ((port = atoi(ans)) <= 0) + port = 119; + + msg2[32] = (old && old->xmode & INN_FEEDED) ? 'Y' : 'N'; /* ·s¼W¸ê®Æ¹w³]¤£Áý«H */ + ch = vans(msg2); + if (ch != 'y' && ch != 'n') + ch = msg2[32] | 0x20; + + if (ch == 'y') + nl.xmode |= INN_FEEDED; + } + nl.port = port; + + if (old) + rec_put(fpath, &nl, sizeof(nodelist_t), pos, NULL); + else + rec_add(fpath, &nl, sizeof(nodelist_t)); + return 1; + } + return 0; +} + + +static int +nl_cmp(a, b) + nodelist_t *a, *b; +{ + /* ¨Ì name ±Æ§Ç */ + return str_cmp(a->name, b->name); +} + + +static int +nl_search(nl, key) + nodelist_t *nl; + char *key; +{ + return (int) (str_str(nl->name, key) || str_str(nl->host, key)); +} + + +/* ----------------------------------------------------- */ +/* newsfeeds.bbs ¤l¨ç¦¡ */ +/* ----------------------------------------------------- */ + + +static void +nf_item(num, nf) + int num; + newsfeeds_t *nf; +{ + int bno; + BRD *brd; + char outgo, income; + + if ((bno = brd_bno(nf->board)) >= 0) + { + if (nf->xmode & INN_ERROR) + { + outgo = income = '?'; + } + else + { + brd = bshm->bcache + bno; + outgo = brd->battr & BRD_NOTRAN ? ' ' : '<'; + income = nf->xmode & INN_NOINCOME ? ' ': '>'; + } + } + else + { + outgo = income = 'X'; + } + + prints("%6d %-13s%-*.*s %c-%c %-13s %.7s\n", num, + nf->path, d_cols + 32, d_cols + 32, nf->newsgroup, outgo, income, nf->board, nf->charset); +} + + +static void +nf_query(nf) + newsfeeds_t *nf; +{ + nodelist_t nl; + int fd; + int rc = 0; + BRD *brd; + char *outgo, *income; + + /* §ä¥X¸Ó¯¸¥x¦b nodelist.bbs ¤¤ªº¸ê°T */ + if ((fd = open("innd/nodelist.bbs", O_RDONLY)) >= 0) + { + while (read(fd, &nl, sizeof(nodelist_t)) == sizeof(nodelist_t)) + { + if (!strcmp(nl.name, nf->path)) + { + rc = 1; + break; + } + } + close(fd); + } + if (!rc) + { + memset(&nl, 0, sizeof(nodelist_t)); + strcpy(nl.host, "\033[1;33m¦¹¯¸¥x¤£¦b nodelist.bbs ¤¤\033[m"); + } + + /* ¬ÝªOª¬ºA */ + if ((rc = brd_bno(nf->board)) >= 0) + { + brd = bshm->bcache + rc; + outgo = brd->battr & BRD_NOTRAN ? "\033[1;33m¤£Âà¥X\033[m" : "Âà¥X"; + income = nf->xmode & INN_NOINCOME ? "¥B\033[1;33m¤£Âà¶i\033[m" : "¥BÂà¶i"; + } + else + { + outgo = "\033[1;33m¦¹¬ÝªO¤£¦s¦b\033[m"; + income = ""; + } + + move(3, 0); + clrtobot(); + prints("\n\nÂà«H¯¸¥x¡G%s\n¯¸¥x¦ì§}¡G%s\n¯¸¥x¨ó©w¡G%s(%d)\n" + "Âà«H¸s²Õ¡G%s%s\n¥»¯¸¬ÝªO¡G%s (%s%s)\n¨Ï¥Î¦r¶°¡G%s", + nf->path, nl.host, nl.xmode & INN_USEIHAVE ? "IHAVE" : "POST", nl.port, + nf->newsgroup, nf->xmode & INN_ERROR ? " (\033[1;33m¦¹¸s²Õ¤£¦s¦b\033[m)" : "", + nf->board, outgo, income, nf->charset); + if (rc && !(nl.xmode & INN_FEEDED)) + prints("\n¥Ø«e½g¼Æ¡G%d", nf->high); + vmsg(NULL); +} + + +static int /* 1:¦¨¥\ 0:¥¢±Ñ */ +nf_add(fpath, old, pos) + char *fpath; + newsfeeds_t *old; + int pos; +{ + newsfeeds_t nf; + int high; + char ans[12]; + BRD *brd; + + if (old) + memcpy(&nf, old, sizeof(newsfeeds_t)); + else + { + memset(&nf, 0, sizeof(newsfeeds_t)); + nf.high = INT_MAX; /* ²Ä¤@¦¸¨ú«H±j¢ reload */ + } + + if ((brd = ask_board(nf.board, BRD_L_BIT, NULL)) && + vget(b_lines, 0, "^¤å¯¸¦W¡G", nf.path, sizeof(nf.path), GCARRY) && + vget(b_lines, 0, "¸s²Õ¡G", nf.newsgroup, /* sizeof(nf.newsgroup) */ 70, GCARRY)) + { + if (!vget(b_lines, 0, "¦r¶° [" MYCHARSET "]¡G", nf.charset, sizeof(nf.charset), GCARRY)) + str_ncpy(nf.charset, MYCHARSET, sizeof(nf.charset)); + nf.xmode = (vans("¬O§_Âà¶i(Y/N)¡H[Y] ") == 'n') ? INN_NOINCOME : 0; + + if (vans("¬O§_§ó§ïÂà«Hªº high-number ³]©w¡A³o³]©w¹ï³QÁý«Hªº¸s²ÕµL®Ä(Y/N)¡H[N] ") == 'y') + { + sprintf(ans, "%d", nf.high); + vget(b_lines, 0, "¥Ø«e½g¼Æ¡G", ans, 11, GCARRY); + if ((high = atoi(ans)) >= 0) + nf.high = high; + } + + if (old) + rec_put(fpath, &nf, sizeof(newsfeeds_t), pos, NULL); + else + rec_add(fpath, &nf, sizeof(newsfeeds_t)); + + if ((brd->battr & BRD_NOTRAN) && vans("¥»ªOÄݩʥثe¬°¤£Âà¥X¡A¬O§_§ï¬°Âà¥X(Y/N)¡H[Y] ") != 'n') + { + high = brd - bshm->bcache; + brd->battr &= ~BRD_NOTRAN; + rec_put(FN_BRD, brd, sizeof(BRD), high, NULL); + } + + return 1; + } + return 0; +} + + +static int +nf_cmp(a, b) + newsfeeds_t *a, *b; +{ + /* path/newsgroup ¥æ¤e¤ñ¹ï */ + int k = str_cmp(a->path, b->path); + return k ? k : str_cmp(a->newsgroup, b->newsgroup); +} + + +static int +nf_search(nf, key) + newsfeeds_t *nf; + char *key; +{ + return (int) (str_str(nf->newsgroup, key) || str_str(nf->board, key)); +} + + +/* ----------------------------------------------------- */ +/* ncmperm.bbs ¤l¨ç¦¡ */ +/* ----------------------------------------------------- */ + + +static void +ncm_item(num, ncm) + int num; + ncmperm_t *ncm; +{ + prints("%6d %-*.*s%-23.23s %s\n", num, + d_cols + 44, d_cols + 44, ncm->issuer, ncm->type, ncm->perm ? "¡³" : "¢®"); +} + + +static void +ncm_query(ncm) + ncmperm_t *ncm; +{ + move(3, 0); + clrtobot(); + prints("\n\nµo¦æ¯¸¥x¡G%s\n¬å«HºØÃþ¡G%s\n¤¹³\\¬å«H¡G%s", + ncm->issuer, ncm->type, ncm->perm ? "¡³" : "¢®"); + vmsg(NULL); +} + + +static int /* 1:¦¨¥\ 0:¥¢±Ñ */ +ncm_add(fpath, old, pos) + char *fpath; + ncmperm_t *old; + int pos; +{ + ncmperm_t ncm; + + if (old) + memcpy(&ncm, old, sizeof(ncmperm_t)); + else + memset(&ncm, 0, sizeof(ncmperm_t)); + + if (vget(b_lines, 0, "µo¦æ¡G", ncm.issuer, /* sizeof(ncm.issuer) */ 70, GCARRY) && + vget(b_lines, 0, "ºØÃþ¡G", ncm.type, sizeof(ncm.type), GCARRY)) + { + ncm.perm = (vans("¤¹³\\¦¹ NCM message ¬å«H(Y/N)¡H[N] ") == 'y'); + + if (old) + rec_put(fpath, &ncm, sizeof(ncmperm_t), pos, NULL); + else + rec_add(fpath, &ncm, sizeof(ncmperm_t)); + return 1; + } + return 0; +} + + +static int +ncm_cmp(a, b) + ncmperm_t *a, *b; +{ + /* issuer/type ¥æ¤e¤ñ¹ï */ + int k = str_cmp(a->issuer, b->issuer); + return k ? k : str_cmp(a->type, b->type); +} + + +static int +ncm_search(ncm, key) + ncmperm_t *ncm; + char *key; +{ + return (int) (str_str(ncm->issuer, key) || str_str(ncm->type, key)); +} + + +/* ----------------------------------------------------- */ +/* spamrule.bbs ¤l¨ç¦¡ */ +/* ----------------------------------------------------- */ + + +static char * +spam_compare(xmode) + int xmode; +{ + if (xmode & INN_SPAMADDR) + return "§@ªÌ"; + if (xmode & INN_SPAMNICK) + return "¼ÊºÙ"; + if (xmode & INN_SPAMSUBJECT) + return "¼ÐÃD"; + if (xmode & INN_SPAMPATH) + return "¸ô®|"; + if (xmode & INN_SPAMMSGID) + return "MSID"; + if (xmode & INN_SPAMBODY) + return "¥»¤å"; + if (xmode & INN_SPAMSITE) + return "²Õ´"; + if (xmode & INN_SPAMPOSTHOST) + return "¨Ó·½"; + return "¡H¡H"; +} + + +static void +spam_item(num, spam) + int num; + spamrule_t *spam; +{ + char *path, *board; + + path = spam->path; + board = spam->board; + prints("%6d %-13s%-13s[%s] ¥]§t %.*s\n", + num, *path ? path : "©Ò¦³¯¸¥x", *board ? board : "©Ò¦³¬ÝªO", + spam_compare(spam->xmode), d_cols + 30, spam->detail); +} + + +static void +spam_query(spam) + spamrule_t *spam; +{ + char *path, *board; + + path = spam->path; + board = spam->board; + + move(3, 0); + clrtobot(); + prints("\n\n¾A¥Î¯¸¥x¡G%s\n¾A¥Î¬ÝªO¡G%s\n¤ñ¸û¶µ¥Ø¡G%s\n¤ñ¸û¤º®e¡G%s", + *path ? path : "©Ò¦³¯¸¥x", *board ? board : "©Ò¦³¬ÝªO", spam_compare(spam->xmode), spam->detail); + vmsg("Yº¡¨¬¦¹³W«h¡A·|³Qµø¬°¼s§i¦ÓµLªkÂà«H¶i¨Ó"); +} + + +static int /* 1:¦¨¥\ 0:¥¢±Ñ */ +spam_add(fpath, old, pos) + char *fpath; + spamrule_t *old; + int pos; +{ + spamrule_t spam; + + if (old) + memcpy(&spam, old, sizeof(spamrule_t)); + else + memset(&spam, 0, sizeof(spamrule_t)); + + vget(b_lines, 0, "^¤å¯¸¦W¡G", spam.path, sizeof(spam.path), GCARRY); + ask_board(spam.board, BRD_L_BIT, NULL); + + switch (vans("¾×«H³W«h 1)§@ªÌ 2)¼ÊºÙ 3)¼ÐÃD 4)¸ô®| 5)MSGID 6)¥»¤å 7)²Õ´ 8)¨Ó·½ [Q] ")) + { + case '1': + spam.xmode = INN_SPAMADDR; + break; + case '2': + spam.xmode = INN_SPAMNICK; + break; + case '3': + spam.xmode = INN_SPAMSUBJECT; + break; + case '4': + spam.xmode = INN_SPAMPATH; + break; + case '5': + spam.xmode = INN_SPAMMSGID; + break; + case '6': + spam.xmode = INN_SPAMBODY; + break; + case '7': + spam.xmode = INN_SPAMSITE; + break; + case '8': + spam.xmode = INN_SPAMPOSTHOST; + break; + default: + return 0; + } + + if (vget(b_lines, 0, "¥]§t¡G", spam.detail, /* sizeof(spam.detail) */ 70, GCARRY)) + { + if (old) + rec_put(fpath, &spam, sizeof(spamrule_t), pos, NULL); + else + rec_add(fpath, &spam, sizeof(spamrule_t)); + return 1; + } + return 0; +} + + +static int +spam_cmp(a, b) + spamrule_t *a, *b; +{ + /* path/board/xmode/detail ¥æ¤e¤ñ¹ï */ + int i = strcmp(a->path, b->path); + int j = strcmp(a->board, b->board); + int k = a->xmode - b->xmode; + return i ? i : j ? j : k ? k : str_cmp(a->detail, b->detail); +} + + +static int +spam_search(spam, key) + spamrule_t *spam; + char *key; +{ + return (int) (str_str(spam->detail, key)); +} + + +/* ----------------------------------------------------- */ +/* Âà«H³]©w¥D¨ç¦¡ */ +/* ----------------------------------------------------- */ + + +int +a_innbbs() +{ + int num, pageno, pagemax, redraw, reload; + int ch, cur, i, dirty; + struct stat st; + char *data; + int recsiz; + char *fpath; + char buf[40]; + void (*item_func)(), (*query_func)(); + int (*add_func)(), (*sync_func)(), (*search_func)(); + + vs_bar("Âà«H³]©w"); + more("etc/innbbs.hlp", (char *) -1); + + switch (vans("½Ð¿ï¾Ü 1)Âà¤å¯¸¥x¦Cªí 2)Âà¤å¬ÝªO¦Cªí 3)NoCeM¾×¤å³W«h 4)¼s§i¤å¦W³æ¡G[Q] ")) + { + case '1': + fpath = "innd/nodelist.bbs"; + recsiz = sizeof(nodelist_t); + item_func = nl_item; + query_func = nl_query; + add_func = nl_add; + sync_func = nl_cmp; + search_func = nl_search; + break; + + case '2': + fpath = "innd/newsfeeds.bbs"; + recsiz = sizeof(newsfeeds_t); + item_func = nf_item; + query_func = nf_query; + add_func = nf_add; + sync_func = nf_cmp; + search_func = nf_search; + break; + + case '3': + fpath = "innd/ncmperm.bbs"; + recsiz = sizeof(ncmperm_t); + item_func = ncm_item; + query_func = ncm_query; + add_func = ncm_add; + sync_func = ncm_cmp; + search_func = ncm_search; + break; + + case '4': + fpath = "innd/spamrule.bbs"; + recsiz = sizeof(spamrule_t); + item_func = spam_item; + query_func = spam_query; + add_func = spam_add; + sync_func = spam_cmp; + search_func = spam_search; + break; + + default: + return 0; + } + + dirty = 0; /* 1:¦³·s¼W/§R°£¸ê®Æ */ + reload = 1; + pageno = 0; + cur = 0; + data = NULL; + + do + { + if (reload) + { + if (stat(fpath, &st) == -1) + { + if (!add_func(fpath, NULL, -1)) + return 0; + dirty = 1; + continue; + } + + i = st.st_size; + num = (i / recsiz) - 1; + if (num < 0) + { + if (!add_func(fpath, NULL, -1)) + return 0; + dirty = 1; + continue; + } + + if ((ch = open(fpath, O_RDONLY)) >= 0) + { + data = data ? (char *) realloc(data, i) : (char *) malloc(i); + read(ch, data, i); + close(ch); + } + + pagemax = num / XO_TALL; + reload = 0; + redraw = 1; + } + + if (redraw) + { + /* itoc.µù¸Ñ: ºÉ¶q°µ±o¹³ xover ®æ¦¡ */ + vs_head("Âà«H³]©w", str_site); + prints(NECKER_INNBBS, d_cols, ""); + + i = pageno * XO_TALL; + ch = BMIN(num, i + XO_TALL - 1); + move(3, 0); + do + { + item_func(i + 1, data + i * recsiz); + i++; + } while (i <= ch); + + outf(FEETER_INNBBS); + move(3 + cur, 0); + outc('>'); + redraw = 0; + } + + ch = vkey(); + switch (ch) + { + case KEY_RIGHT: + case '\n': + case ' ': + case 'r': + i = cur + pageno * XO_TALL; + query_func(data + i * recsiz); + redraw = 1; + break; + + case Ctrl('P'): + if (add_func(fpath, NULL, -1)) + { + dirty = 1; + num++; + cur = num % XO_TALL; /* ´å¼Ð©ñ¦b·s¥[¤Jªº³o½g */ + pageno = num / XO_TALL; + reload = 1; + } + redraw = 1; + break; + + case 'd': + if (vans(msg_del_ny) == 'y') + { + dirty = 1; + i = cur + pageno * XO_TALL; + rec_del(fpath, recsiz, i, NULL); + cur = i ? ((i - 1) % XO_TALL) : 0; /* ´å¼Ð©ñ¦b¬å±¼ªº«e¤@½g */ + reload = 1; + } + redraw = 1; + break; + + case 'E': + i = cur + pageno * XO_TALL; + if (add_func(fpath, data + i * recsiz, i)) + { + dirty = 1; + reload = 1; + } + redraw = 1; + break; + + case '/': + if (vget(b_lines, 0, "ÃöÁä¦r¡G", buf, sizeof(buf), DOECHO)) + { + str_lower(buf, buf); + for (i = pageno * XO_TALL + cur + 1; i <= num; i++) /* ±q´å¼Ð¤U¤@Ó¶}©l§ä */ + { + if (search_func(data + i * recsiz, buf)) + { + pageno = i / XO_TALL; + cur = i % XO_TALL; + break; + } + } + } + redraw = 1; + break; + + default: + ch = xo_cursor(ch, pagemax, num, &pageno, &cur, &redraw); + break; + } + } while (ch != 'q'); + + free(data); + + if (dirty) + rec_sync(fpath, recsiz, sync_func, NULL); + return 0; +} diff --git a/so/manage.c b/so/manage.c new file mode 100644 index 0000000..44c1e93 --- /dev/null +++ b/so/manage.c @@ -0,0 +1,762 @@ +/*-------------------------------------------------------*/ +/* manage.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¬ÝªOºÞ²z */ +/* create : 95/03/29 */ +/* update : 96/04/05 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +extern BCACHE *bshm; + + +#ifdef HAVE_TERMINATOR +/* ----------------------------------------------------- */ +/* ¯¸ªø¥\¯à : ©Ø·¬¸¨¸±Ù */ +/* ----------------------------------------------------- */ + + +extern char xo_pool[]; + + +#define MSG_TERMINATOR "¡m©Ø·¬¸¨¸±Ù¡n" + +int +post_terminator(xo) /* Thor.980521: ²×·¥¤å³¹§R°£¤jªk */ + XO *xo; +{ + int mode, type; + HDR *hdr; + char keyOwner[80], keyTitle[TTLEN + 1], buf[80]; + + if (!HAS_PERM(PERM_ALLBOARD)) + return XO_FOOT; + + mode = vans(MSG_TERMINATOR "§R°£ (1)¥»¤å§@ªÌ (2)¥»¤å¼ÐÃD (3)¦Û©w¡H[Q] ") - '0'; + + if (mode == 1) + { + hdr = (HDR *) xo_pool + (xo->pos - xo->top); + strcpy(keyOwner, hdr->owner); + } + else if (mode == 2) + { + hdr = (HDR *) xo_pool + (xo->pos - xo->top); + strcpy(keyTitle, str_ttl(hdr->title)); /* ®³±¼ Re: */ + } + else if (mode == 3) + { + if (!vget(b_lines, 0, "§@ªÌ¡G", keyOwner, 73, DOECHO)) + mode ^= 1; + if (!vget(b_lines, 0, "¼ÐÃD¡G", keyTitle, TTLEN + 1, DOECHO)) + mode ^= 2; + } + else + { + return XO_FOOT; + } + + type = vans(MSG_TERMINATOR "§R°£ (1)Âà«HªO (2)«DÂà«HªO (3)©Ò¦³¬ÝªO¡H[Q] "); + if (type < '1' || type > '3') + return XO_FOOT; + + sprintf(buf, "§R°£%s¡G%.35s ©ó%sªO¡A½T©w¶Ü(Y/N)¡H[N] ", + mode == 1 ? "§@ªÌ" : mode == 2 ? "¼ÐÃD" : "±ø¥ó", + mode == 1 ? keyOwner : mode == 2 ? keyTitle : "¦Û©w", + type == '1' ? "Âà«H" : type == '2' ? "«DÂà«H" : "©Ò¦³¬Ý"); + + if (vans(buf) == 'y') + { + BRD *bhdr, *head, *tail; + char tmpboard[BNLEN + 1]; + + /* Thor.980616: °O¤U currboard¡A¥H«K´_ì */ + strcpy(tmpboard, currboard); + + head = bhdr = bshm->bcache; + tail = bhdr + bshm->number; + do /* ¦Ü¤Ö¦³ note ¤@ªO */ + { + int fdr, fsize, xmode; + FILE *fpw; + char fpath[64], fnew[64], fold[64]; + HDR *hdr; + + xmode = head->battr; + if ((type == '1' && (xmode & BRD_NOTRAN)) || (type == '2' && !(xmode & BRD_NOTRAN))) + continue; + + /* Thor.980616: §ó§ï currboard¡A¥H cancel post */ + strcpy(currboard, head->brdname); + + sprintf(buf, MSG_TERMINATOR "¬ÝªO¡G%s \033[5m...\033[m", currboard); + outz(buf); + refresh(); + + brd_fpath(fpath, currboard, fn_dir); + + if ((fdr = open(fpath, O_RDONLY)) < 0) + continue; + + if (!(fpw = f_new(fpath, fnew))) + { + close(fdr); + continue; + } + + fsize = 0; + mgets(-1); + while (hdr = mread(fdr, sizeof(HDR))) + { + xmode = hdr->xmode; + + if ((xmode & POST_MARKED) || + ((mode & 1) && strcmp(keyOwner, hdr->owner)) || + ((mode & 2) && strcmp(keyTitle, str_ttl(hdr->title)))) + { + if ((fwrite(hdr, sizeof(HDR), 1, fpw) != 1)) + { + fclose(fpw); + close(fdr); + goto contWhileOuter; + } + fsize++; + } + else + { + /* Y¬°¬ÝªO´N³s½u¬å«H */ + + cancel_post(hdr); + hdr_fpath(fold, fpath, hdr); + unlink(fold); + } + } + close(fdr); + fclose(fpw); + + sprintf(fold, "%s.o", fpath); + rename(fpath, fold); + if (fsize) + rename(fnew, fpath); + else + contWhileOuter: + unlink(fnew); + } while (++head < tail); + + /* ÁÙì currboard */ + strcpy(currboard, tmpboard); + return XO_LOAD; + } + + return XO_FOOT; +} +#endif /* HAVE_TERMINATOR */ + + +/* ----------------------------------------------------- */ +/* ªO¥D¥\¯à : ×§ïªO¦W */ +/* ----------------------------------------------------- */ + + +static int +post_brdtitle(xo) + XO *xo; +{ + BRD *oldbrd, newbrd; + + oldbrd = bshm->bcache + currbno; + memcpy(&newbrd, oldbrd, sizeof(BRD)); + + /* itoc.µù¸Ñ: ¨ä¹ê©I¥s brd_title(bno) ´N¥i¥H¤F¡A¨S®t¡AÆZ·F¤@¤U¦n¤F :p */ + if (vans("¬O§_ק襤¤åªO¦W±Ôz(Y/N)¡H[N] ") == 'y') + { + vget(b_lines, 0, "¬ÝªO¥DÃD¡G", newbrd.title, BTLEN + 1, GCARRY); + + if (memcmp(&newbrd, oldbrd, sizeof(BRD)) && vans(msg_sure_ny) == 'y') + { + memcpy(oldbrd, &newbrd, sizeof(BRD)); + rec_put(FN_BRD, &newbrd, sizeof(BRD), currbno, NULL); + return XO_HEAD; /* itoc.011125: n«Ã¸¤¤¤åªO¦W */ + } + } + + return XO_FOOT; +} + + +/* ----------------------------------------------------- */ +/* ªO¥D¥\¯à : ×§ï¶iªOµe± */ +/* ----------------------------------------------------- */ + + +static int +post_memo_edit(xo) + XO *xo; +{ + int mode; + char fpath[64]; + + mode = vans("¶iªOµe± (D)§R°£ (E)×§ï (Q)¨ú®ø¡H[E] "); + + if (mode != 'q') + { + brd_fpath(fpath, currboard, fn_note); + + if (mode == 'd') + { + unlink(fpath); + return XO_FOOT; + } + + if (vedit(fpath, 0)) /* Thor.981020: ª`·N³Qtalkªº°ÝÃD */ + vmsg(msg_cancel); + return XO_HEAD; + } + return XO_FOOT; +} + +#ifdef POST_PREFIX +/* ----------------------------------------------------- */ +/* ªO¥D¥\¯à : ×§ïµo¤åÃþ§O */ +/* ----------------------------------------------------- */ + + +static int +post_prefix_edit(xo) + XO *xo; +{ +#define NUM_PREFIX 9 + int i; + FILE *fp; + char fpath[64], buf[20], prefix[NUM_PREFIX][20], *menu[NUM_PREFIX + 3]; + char *prefix_def[NUM_PREFIX] = /* ¹w³]ªºÃþ§O */ + { + "[¤½§i]", "[´ú¸Õ]", "[¶¢²á]", "[Äé¤ô]", "[µL²á]", + "[¥´²V]", "[¬ö©À]", "[³Ð§@]", "[¤å¥ó]" + }; + char modified=0; /* lantw44: §PÂ_¦³µL×§ï¹L */ + + if (!(bbstate & STAT_BOARD)) + return XO_NONE; + + i = vans("Ãþ§O (D)§R°£ (E)×§ï (Q)¨ú®ø¡H [E] "); + + if (i == 'q') + return XO_FOOT; + + brd_fpath(fpath, currboard, "prefix"); + + if (i == 'd') + { + unlink(fpath); + return XO_FOOT; + } + + i = 0; + + if (fp = fopen(fpath, "r")) + { + for (; i < NUM_PREFIX; i++) + { + //if (fscanf(fp, "%10s", buf) != 1) + if (fgets(buf, 11, fp) == NULL) + break; + buf[strlen(buf)-1]='\0'; /* lantw44:¦Y±¼³Ì«á¤@Ó\n */ + sprintf(prefix[i], "%d.%s", i + 1, buf); + } + fclose(fp); + } + + /* ¶ñº¡¦Ü NUM_PREFIX Ó */ + for (; i < NUM_PREFIX; i++) + sprintf(prefix[i], "%d.%s", i + 1, prefix_def[i]); + + menu[0] = "10"; + for (i = 1; i <= NUM_PREFIX; i++) + menu[i] = prefix[i - 1]; + menu[NUM_PREFIX + 1] = "0.Â÷¶}"; + menu[NUM_PREFIX + 2] = NULL; + + do + { + /* ¦b popupmenu ¸Ì±«ö ¥ªÁä Â÷¶} */ + i = pans(3, 20, "¤å³¹Ãþ§O", menu) - '0'; + if (i >= 1 && i <= NUM_PREFIX) + { + strcpy(buf, prefix[i - 1] + 2); + if (vget(b_lines, 0, "Ãþ§O¡G", buf, 10, GCARRY)){ + if(strcmp(prefix[i - 1] + 2,buf)){ + modified=1; + } + strcpy(prefix[i - 1] + 2, buf); + } + } + } while (i); + + if(!modified || vans("½T©wnÀx¦sÀÉ®×¶Ü(Y/N)¡H[Y] ") == 'n'){ + vmsg("ì«Ê¤£°Ê"); + return XO_FOOT; + } + + if (fp = fopen(fpath, "w")) + { + for (i = 0; i < NUM_PREFIX; i++) + fprintf(fp, "%s\n", prefix[i] + 2); + fclose(fp); + vmsg("§ó·s§¹²¦"); + }else{ + vmsg("ÀÉ®×¼g¤J¥¢±Ñ"); + } + + return XO_FOOT; +} +#endif /* POST_PREFIX */ +/* ----------------------------------------------------- */ +/* ªO¥D¥\¯à : ×§ïµo¤åºõ»â */ +/* ----------------------------------------------------- */ + + +static int +post_postlaw_edit(xo) /* ªO¥D¦Û©w¤å³¹µoªíºõ»â */ + XO *xo; +{ + int mode; + char fpath[64]; + + mode = vans("¤å³¹µoªíºõ»â (D)§R°£ (E)×§ï (Q)¨ú®ø¡H[E] "); + + if (mode != 'q') + { + brd_fpath(fpath, currboard, FN_POSTLAW); + + if (mode == 'd') + { + unlink(fpath); + return XO_FOOT; + } + if (vedit(fpath, 0)) /* Thor.981020: ª`·N³Qtalkªº°ÝÃD */ + vmsg(msg_cancel); + return XO_HEAD; + } + return XO_FOOT; +} + + +/* ----------------------------------------------------- */ +/* ªO¥D¥\¯à : ¬ÝªOÄÝ©Ê */ +/* ----------------------------------------------------- */ + + +#ifdef HAVE_SCORE +static int +post_battr_noscore(xo) + XO *xo; +{ + BRD *oldbrd, newbrd; + + oldbrd = bshm->bcache + currbno; + memcpy(&newbrd, oldbrd, sizeof(BRD)); + + switch (vans("¶}©ñµû¤À (1)¤¹³\\ (2)¤£³\\ (Q)¨ú®ø¡H[Q] ")) + { + case '1': + newbrd.battr &= ~BRD_NOSCORE; + break; + case '2': + newbrd.battr |= BRD_NOSCORE; + break; + default: + return XO_FOOT; + } + + if (memcmp(&newbrd, oldbrd, sizeof(BRD)) && vans(msg_sure_ny) == 'y') + { + memcpy(oldbrd, &newbrd, sizeof(BRD)); + rec_put(FN_BRD, &newbrd, sizeof(BRD), currbno, NULL); + } + + return XO_FOOT; +} +#endif /* HAVE_SCORE */ + + +#ifdef ANTI_PHONETIC +static int +post_battr_nophonetic(xo) + XO *xo; +{ + BRD *oldbrd, newbrd; + + oldbrd = bshm->bcache + currbno; + memcpy(&newbrd, oldbrd, sizeof(BRD)); + + switch (vans("1)¥i¥H¥Îª`µ¤å 2)¤£¥i¥Îª`µ¤å [Q] ")) + { + case '1': + newbrd.battr &= ~BRD_NOPHONETIC; + break; + case '2': + newbrd.battr |= BRD_NOPHONETIC; + break; + default: + return XO_FOOT; + } + + if (memcmp(&newbrd, oldbrd, sizeof(BRD)) && vans(msg_sure_ny) == 'y') + { + memcpy(oldbrd, &newbrd, sizeof(BRD)); + rec_put(FN_BRD, &newbrd, sizeof(BRD), currbno, NULL); + } + + return XO_FOOT; +} +#endif /* ANTI_PHONETIC */ +/* ----------------------------------------------------- */ +/* ªO¥D¥\¯à : ×§ïªO¥D¦W³æ */ +/* ----------------------------------------------------- */ + + +static int +post_changeBM(xo) + XO *xo; +{ + char buf[80], userid[IDLEN + 2], *blist; + BRD *oldbrd, newbrd; + ACCT acct; + int BMlen, len; + + oldbrd = bshm->bcache + currbno; + + if (strcmp(oldbrd->class, "Ó¤H") && + strcmp(oldbrd->class, "ªÀ¹Î") && + strcmp(oldbrd->class, "¹ÎÅé")) + { + vmsg ("¤½¶}ªO¤£µ¹§ï³é"); + return XO_FOOT; + } + + blist = oldbrd->BM; + if (is_bm(blist, cuser.userid) != 1) /* ¥u¦³¥¿ªO¥D¥i¥H³]©wªO¥D¦W³æ */ + return XO_FOOT; + + memcpy(&newbrd, oldbrd, sizeof(BRD)); + + move(3, 0); + clrtobot(); + + move(8, 0); + prints("¥Ø«eªO¥D¬° %s\n½Ð¿é¤J·sªºªO¥D¦W³æ¡A©Î«ö [Return] ¤£§ï", oldbrd->BM); + + strcpy(buf, oldbrd->BM); + BMlen = strlen(buf); + + while (vget(10, 0, "½Ð¿é¤J°ÆªO¥D¡Aµ²§ô½Ð«ö Enter¡A²M±¼©Ò¦³°ÆªO¥D½Ð¥´¡uµL¡v¡G", userid, IDLEN + 1, DOECHO)) + { + if (!strcmp(userid, "µL")) + { + strcpy(buf, cuser.userid); + BMlen = strlen(buf); + } + else if (is_bm(buf, userid)) /* §R°£Â¦³ªºªO¥D */ + { + len = strlen(userid); + if (!str_cmp(cuser.userid, userid)) + { + vmsg("¤£¥i¥H±N¦Û¤v²¾¥XªO¥D¦W³æ"); + continue; + } + else if (!str_cmp(buf + BMlen - len, userid)) /* ¦W³æ¤W³Ì«á¤@¦ì¡AID «á±¤£±µ '/' */ + { + buf[BMlen - len - 1] = '\0'; /* §R°£ ID ¤Î«e±ªº '/' */ + len++; + } + else /* ID «á±·|±µ '/' */ + { + str_lower(userid, userid); + strcat(userid, "/"); + len++; + blist = str_str(buf, userid); + strcpy(blist, blist + len); + } + BMlen -= len; + } + else if (acct_load(&acct, userid) >= 0 && !is_bm(buf, userid)) /* ¿é¤J·sªO¥D */ + { + len = strlen(userid) + 1; /* '/' + userid */ + if (BMlen + len > BMLEN) + { + vmsg("ªO¥D¦W³æ¹Lªø¡AµLªk±N³o ID ³]¬°ªO¥D"); + continue; + } + sprintf(buf + BMlen, "/%s", acct.userid); + BMlen += len; + + acct_setperm(&acct, PERM_BM, 0); + } + move(8, 0); + prints("¥Ø«eªO¥D¬° %s", buf); + clrtoeol(); + } + strcpy(newbrd.BM, buf); + + if (memcmp(&newbrd, oldbrd, sizeof(BRD)) && vans(msg_sure_ny) == 'y') + { + memcpy(oldbrd, &newbrd, sizeof(BRD)); + rec_put(FN_BRD, &newbrd, sizeof(BRD), currbno, NULL); + + sprintf(currBM, "ªO¥D¡G%s", newbrd.BM); + return XO_HEAD; /* n«Ã¸ÀÉÀYªºªO¥D */ + } + + return XO_BODY; +} + + +#ifdef HAVE_MODERATED_BOARD +/* ----------------------------------------------------- */ +/* ªO¥D¥\¯à : ¬ÝªOÅv */ +/* ----------------------------------------------------- */ + + +static int +post_brdlevel(xo) + XO *xo; +{ + BRD *oldbrd, newbrd; + + oldbrd = bshm->bcache + currbno; + memcpy(&newbrd, oldbrd, sizeof(BRD)); + + switch (vans("1)¤½¶}¬ÝªO 2)¯µ±K¬ÝªO 3)¦n¤Í¬ÝªO¡H[Q] ")) + { + case '1': /* ¤½¶}¬ÝªO */ + newbrd.readlevel = 0; + newbrd.postlevel = PERM_POST; + newbrd.battr &= ~(BRD_NOSTAT | BRD_NOVOTE); + break; + + case '2': /* ¯µ±K¬ÝªO */ + newbrd.readlevel = PERM_SYSOP; + newbrd.postlevel = 0; + newbrd.battr |= (BRD_NOSTAT | BRD_NOVOTE); + break; + + case '3': /* ¦n¤Í¬ÝªO */ + newbrd.readlevel = PERM_BOARD; + newbrd.postlevel = 0; + newbrd.battr |= (BRD_NOSTAT | BRD_NOVOTE); + break; + + default: + return XO_FOOT; + } + + if (memcmp(&newbrd, oldbrd, sizeof(BRD)) && vans(msg_sure_ny) == 'y') + { + memcpy(oldbrd, &newbrd, sizeof(BRD)); + rec_put(FN_BRD, &newbrd, sizeof(BRD), currbno, NULL); + } + + return XO_FOOT; +} +#endif /* HAVE_MODERATED_BOARD */ + + +#ifdef HAVE_MODERATED_BOARD +/* ----------------------------------------------------- */ +/* ªO¤Í¦W³æ¡Gmoderated board */ +/* ----------------------------------------------------- */ + + +static void +bpal_cache(fpath) + char *fpath; +{ + BPAL *bpal; + + bpal = bshm->pcache + currbno; + bpal->pal_max = image_pal(fpath, bpal->pal_spool); +} + + +extern XZ xz[]; + + +static int +XoBM(xo) + XO *xo; +{ + XO *xt; + char fpath[64]; + + brd_fpath(fpath, currboard, fn_pal); + xz[XZ_PAL - XO_ZONE].xo = xt = xo_new(fpath); + xt->key = PALTYPE_BPAL; + xover(XZ_PAL); /* Thor: ¶ixover«e, pal_xo ¤@©wn ready */ + + /* build userno image to speed up, maybe upgreade to shm */ + + bpal_cache(fpath); + + free(xt); + + return XO_INIT; +} +#endif /* HAVE_MODERATED_BOARD */ + +static int +post_usies(xo) + XO *xo; +{ + char fpath[64]; + + brd_fpath(fpath, currboard, "usies"); + if (more(fpath, (char *) -1) >= 0 && + vans("½Ð°Ý¬O§_§R°£³o¨Ç¬ÝªO¾\\Ū°O¿ý(Y/N)¡H[N] ") == 'y') + unlink(fpath); + + return XO_HEAD; +} + +static int post_extern(xo) + XO* xo; +{ + char buf[80]; + BRD *oldbrd, newbrd; + oldbrd = bshm->bcache + currbno; + memcpy(&newbrd, oldbrd, sizeof(BRD)); + sprintf(buf,"¬O§_±N¶Ç°e¨ì %s.brd@%s ªº¤å³¹±i¶K©ó¥»¬ÝªO(Y/N)¡H[Q] ",oldbrd->brdname,MYHOSTNAME); + switch(vans(buf)){ + case 'n': + newbrd.battr |= BRD_LOCAL; + break; + case 'y': + newbrd.battr &= ~(BRD_LOCAL); + break; + default: + return XO_FOOT; + } + if (memcmp(&newbrd, oldbrd, sizeof(BRD)) && vans(msg_sure_ny) == 'y') + { + memcpy(oldbrd, &newbrd, sizeof(BRD)); + rec_put(FN_BRD, &newbrd, sizeof(BRD), currbno, NULL); + } + return XO_FOOT; +} + +static int post_lock(xo) + XO* xo; +{ + BRD *brd; + brd = bshm->bcache + currbno; + char fpath[64]; + brd_fpath(fpath, brd->brdname, fn_lock); + brd_editlock(fpath); + return XO_FOOT; +} + +/* ----------------------------------------------------- */ +/* ªO¥D¿ï³æ */ +/* ----------------------------------------------------- */ + + +int +post_manage(xo) + XO *xo; +{ +#ifdef POPUP_ANSWER + char *menu[] = + { + "BQ", + "BTitle ×§ï¬ÝªO¥DÃD", + "WMemo ½s¿è¶iªOµe±", +#ifdef POST_PREFIX + "RPrefix ½s¿è¤å³¹Ãþ§O", +#endif + "PostLaw ½s¿èµo¤åºõ»â", + "Manager ¼W´î°ÆªO¥D", + "ExtPost ³]©w¯¸¥~±H«Hµo¤å", + "ZLock ºÞ²z¬ÝªOÂê©wª¬ºA", + "Usies Æ[¹î¬ÝªO¾\\Ū°O¿ý", +# ifdef HAVE_SCORE + "Score ³]©w¥i§_µû¤À", +# endif +# ifdef ANTI_PHONETIC + "Juyinwenª`µ¤å³]©w", +# endif +# ifdef HAVE_MODERATED_BOARD + "Level ¤½¶}/¦n¤Í/¯µ±K", + "OPal ªO¤Í¦W³æ", +# endif + NULL + }; +#else + char *menu = "¡· ªO¥D¿ï³æ (B)¥DÃD (W)¶iªO (R)Ãþ§O (P)ºõ»â (M)°ÆªO (E)¦¬«H (Z)Âê©w (U)°O¿ý" +# ifdef HAVE_SCORE + " (S)µû¤À" +# endif +# ifdef ANTI_PHONETIC + " (P)ª`µ" +# endif +# ifdef HAVE_MODERATED_BOARD + " (L)Åv (O)ªO¤Í" +# endif + "¡H[Q] "; +#endif + + if (!(bbstate & STAT_BOARD)) + return XO_NONE; + +#ifdef POPUP_ANSWER + switch (pans(3, 20, "ªO¥D¿ï³æ", menu)) +#else + switch (vans(menu)) +#endif + { + case 'b': + return post_brdtitle(xo); + + case 'w': + return post_memo_edit(xo); +#ifdef POST_PREFIX + case 'r': + return post_prefix_edit(xo); +#endif + case 'p': + return post_postlaw_edit(xo); + + case 'm': + return post_changeBM(xo); + + case 'e': + return post_extern(xo); + + case 'z': + return post_lock(xo); + + case 'u': + return post_usies(xo); + +#ifdef HAVE_SCORE + case 's': + return post_battr_noscore(xo); +#endif +#ifdef ANTI_PHONETIC + case 'j': + return post_battr_nophonetic(xo); +#endif +#ifdef HAVE_MODERATED_BOARD + case 'l': + return post_brdlevel(xo); + + case 'o': + return XoBM(xo); +#endif + } + + return XO_FOOT; +} + diff --git a/so/newbrd.c b/so/newbrd.c new file mode 100644 index 0000000..d5e0abf --- /dev/null +++ b/so/newbrd.c @@ -0,0 +1,906 @@ +/*-------------------------------------------------------*/ +/* newbrd.c ( YZU_CSE WindTop BBS ) */ +/*-------------------------------------------------------*/ +/* target : ³s¸p¥\¯à */ +/* create : 00/01/02 */ +/* update : 02/04/29 */ +/*-------------------------------------------------------*/ +/* run/newbrd/_/.DIR - newbrd control header */ +/* run/newbrd/_/@/@_ - newbrd description file */ +/* run/newbrd/_/@/G_ - newbrd voted id loG file */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#ifdef HAVE_COSIGN + +extern XZ xz[]; +extern char xo_pool[]; +extern BCACHE *bshm; /* itoc.010805: ¶}·sªO¥Î */ + +static int nbrd_add(); +static int nbrd_body(); +static int nbrd_head(); + +static char *split_line = "\033[33m¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\033[m\n"; + + +typedef struct +{ + char userid[IDLEN + 1]; + char email[60]; +} LOG; + + +static int +cmpbtime(nbrd) + NBRD *nbrd; +{ + return nbrd->btime == currchrono; +} + + +static char +nbrd_attr(nbrd) + NBRD *nbrd; +{ + int xmode = nbrd->mode; + + /* µ§¹º¶V¤Öªº¡A¶V¶É¦Vµ²®× */ + if (xmode & NBRD_FINISH) + return ' '; + if (xmode & NBRD_END) + return '-'; +#ifdef SYSOP_START_COSIGN + if (xmode & NBRD_START) + return '+'; + else + return 'x'; +#else + return '+'; +#endif +} + + +static int +nbrd_stamp(folder, nbrd, fpath) + char *folder; + NBRD *nbrd; + char *fpath; +{ + char *fname; + char *family = NULL; + int rc; + int token; + + fname = fpath; + while (rc = *folder++) + { + *fname++ = rc; + if (rc == '/') + family = fname; + } + + fname = family; + *family++ = '@'; + + token = time(0); + + archiv32(token, family); + + rc = open(fpath, O_WRONLY | O_CREAT | O_EXCL, 0600); + nbrd->btime = token; + str_stamp(nbrd->date, &nbrd->btime); + strcpy(nbrd->xname, fname); + + return rc; +} + + +static void +nbrd_fpath(fpath, folder, nbrd) + char *fpath; + char *folder; + NBRD *nbrd; +{ + char *str; + int cc; + + while (cc = *folder++) + { + *fpath++ = cc; + if (cc == '/') + str = fpath; + } + strcpy(str, nbrd->xname); +} + + +static int +nbrd_init(xo) + XO *xo; +{ + xo_load(xo, sizeof(NBRD)); + return nbrd_head(xo); +} + + +static int +nbrd_load(xo) + XO *xo; +{ + xo_load(xo, sizeof(NBRD)); + return nbrd_body(xo); +} + + +static void +nbrd_item(num, nbrd) + int num; + NBRD *nbrd; +{ + prints("%6d %c %-5s %-13s [%s] %.*s\n", + num, nbrd_attr(nbrd), nbrd->date + 3, nbrd->owner, + (nbrd->mode & NBRD_NEWBOARD) ? nbrd->brdname : "\033[1;33m¥»¯¸¤½§ë\033[m", d_cols + 20, nbrd->title); +} + + +static int +nbrd_body(xo) + XO *xo; +{ + NBRD *nbrd; + int num, max, tail; + + max = xo->max; + if (max <= 0) + { + if (vans("n·s¼W³s¸p¶µ¥Ø¶Ü(Y/N)¡H[N] ") == 'y') + return nbrd_add(xo); + return XO_QUIT; + } + + nbrd = (NBRD *) xo_pool; + num = xo->top; + tail = num + XO_TALL; + + if (max > tail) + max = tail; + + move(3, 0); + do + { + nbrd_item(++num, nbrd++); + } while (num < max); + clrtobot(); + + return XO_FOOT; +} + + +static int +nbrd_head(xo) + XO *xo; +{ + vs_head("³s¸p¨t²Î", str_site); + prints(NECKER_COSIGN, d_cols, ""); + return nbrd_body(xo); +} + + +static int +nbrd_find(fpath, brdname) + char *fpath, *brdname; +{ + NBRD old; + int fd; + int rc = 0; + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + while (read(fd, &old, sizeof(NBRD)) == sizeof(NBRD)) + { + if (!str_cmp(old.brdname, brdname) && !(old.mode & NBRD_FINISH)) + { + rc = 1; + break; + } + } + close(fd); + } + return rc; +} + + +static int +nbrd_add(xo) + XO *xo; +{ + int fd, ans, days, numbers; + char *dir, fpath[64], path[64]; + char *brdname, *class, *title; + FILE *fp; + NBRD nbrd; + + if (HAS_PERM(PERM_ALLADMIN)) + { + ans = vans("³s¸p¼Ò¦¡ 1)¶}·sªO 2)°O¦W 3)µL°O¦W¡G[Q] "); + if (ans < '1' || ans > '3') + return xo->max ? XO_FOOT : nbrd_body(xo); /* itoc.020122: ¦pªG¨S¦³¥ô¦ó³s¸p¡An¦^¨ì nbrd_body() */ + /* itoc.030613: ¨ä¹ê¤U±ªº return XO_FOOT; ¤]À³¸Ó³o¼Ë§ï */ + } + else if (HAS_PERM(PERM_POST)) + { + /* ¤@¬q¨Ï¥ÎªÌ¥u¯à¶}·sªO³s¸p */ + ans = '1'; + } + else + { + vmsg("¹ï¤£°_¡A¥»¬ÝªO¬O°ßŪªº"); + return XO_FOOT; + } + + memset(&nbrd, 0, sizeof(NBRD)); + + brdname = nbrd.brdname; + class = nbrd.class; + title = nbrd.title; + + if (ans == '1') /* ·sªO³s¸p */ + { + if (!vget(b_lines, 0, "^¤åªO¦W¡G", brdname, sizeof(nbrd.brdname), DOECHO)) + return XO_FOOT; + + if (brd_bno(brdname) >= 0 || !valid_brdname(brdname)) + { + vmsg("¤w¦³¦¹ªO©ÎªO¦W¤£¦Xªk"); + return XO_FOOT; + } + if (nbrd_find(xo->dir, brdname)) + { + vmsg("¥¿¦b³s¸p¤¤"); + return XO_FOOT; + } + + if (!vget(b_lines, 0, "¬ÝªO¤ÀÃþ¡G", class, sizeof(nbrd.class), DOECHO) || + !vget(b_lines, 0, "¬ÝªO¥DÃD¡G", title, sizeof(nbrd.title), DOECHO)) + return XO_FOOT; + + days = NBRD_DAY_BRD; + numbers = NBRD_NUM_BRD; + +#ifdef SYSOP_START_COSIGN + nbrd.mode = NBRD_NEWBOARD; +#else + nbrd.mode = NBRD_NEWBOARD | NBRD_START; +#endif + } + else /* ¨ä¥L³s¸p */ + { + char tmp[8]; + + if (!vget(b_lines, 0, "³s¸p¥DÃD¡G", title, sizeof(nbrd.title), DOECHO)) + return XO_FOOT; + + /* ³s¸p¤é´Á³Ì¦h 30 ¤Ñ¡A³s¸p¤H¼Æ³Ì¦h 500 ¤H */ + if (!vget(b_lines, 0, "³s¸p¤Ñ¼Æ¡G", tmp, 5, DOECHO)) + return XO_FOOT; + days = atoi(tmp); + if (days > 30 || days < 1) + return XO_FOOT; + if (!vget(b_lines, 0, "³s¸p¤H¼Æ¡G", tmp, 6, DOECHO)) + return XO_FOOT; + numbers = atoi(tmp); + if (numbers > 500 || numbers < 1) + return XO_FOOT; + + nbrd.mode = (ans == '2') ? (NBRD_OTHER | NBRD_START) : (NBRD_OTHER | NBRD_START | NBRD_ANONYMOUS); + } + + vmsg("¶}©l½s¿è [¬ÝªO»¡©ú»PªO¥D©êt©Î³s¸pì¦]]"); + sprintf(path, "tmp/%s.nbrd", cuser.userid); /* ³s¸pì¦]ªº¼È¦sÀÉ®× */ + if (fd = vedit(path, 0)) + { + unlink(path); + vmsg(msg_cancel); + return nbrd_head(xo); + } + + dir = xo->dir; + if ((fd = nbrd_stamp(dir, &nbrd, fpath)) < 0) + return nbrd_head(xo); + close(fd); + + nbrd.etime = nbrd.btime + days * 86400; + nbrd.total = numbers; + strcpy(nbrd.owner, cuser.userid); + + fp = fopen(fpath, "a"); + fprintf(fp, "§@ªÌ: %s (%s) ¯¸¤º: ³s¸p¨t²Î\n", cuser.userid, cuser.username); + fprintf(fp, "¼ÐÃD: %s\n", title); + fprintf(fp, "®É¶¡: %s\n\n", Now()); + + if (ans == '1') + { + fprintf(fp, "^¤åªO¦W¡G%s\n", brdname); + fprintf(fp, "¬ÝªO¤ÀÃþ¡G%s\n", class); + fprintf(fp, "¬ÝªO¥DÃD¡G%s\n", title); + fprintf(fp, "ªO¥D¦WºÙ¡G%s\n", cuser.userid); + fprintf(fp, "¹q¤l«H½c¡G%s\n", cuser.email); + } + else + { + fprintf(fp, "³s¸p¥DÃD¡G%s\n", title); + } + fprintf(fp, "Á|¿ì¤é´Á¡G%s\n", nbrd.date); + fprintf(fp, "¨ì´Á¤Ñ¼Æ¡G%d\n", days); + fprintf(fp, "»Ý³s¸p¤H¡G%d\n", numbers); + fprintf(fp, split_line); + fprintf(fp, "³s¸p»¡©ú¡G\n"); + f_suck(fp, path); + unlink(path); + fprintf(fp, split_line); + fclose(fp); + + rec_add(dir, &nbrd, sizeof(NBRD)); + +#ifdef SYSOP_START_COSIGN + vmsg(ans == '1' ? "°e¥æ¥Ó½Ð¤F¡A½Ðµ¥Ô®Öã§a" : "³s¸p¶}©l¤F¡I"); +#else + vmsg("³s¸p¶}©l¤F¡I"); +#endif + + char buf[80]; + sprintf (buf, "[¶}©l³s¸p] %s ¬ÝªO", brdname); + add_post("newboard", fpath, buf); + + return nbrd_init(xo); +} + + +static int +nbrd_seek(fpath) + char *fpath; +{ + LOG old; + int fd; + int rc = 0; + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + while (read(fd, &old, sizeof(LOG)) == sizeof(LOG)) + { + if (!strcmp(old.userid, cuser.userid) || !str_cmp(old.email, cuser.email)) + { + rc = 1; + break; + } + } + close(fd); + } + return rc; +} + + +static void +addreply(hdd, ram) + NBRD *hdd, *ram; +{ + if (--hdd->total <= 0) + { + if (hdd->mode & NBRD_NEWBOARD) /* ·sªO³s¸p±¾ END */ + hdd->mode |= NBRD_END; + else /* ¨ä¥L³s¸p±¾ FINISH */ + hdd->mode |= NBRD_FINISH; + } +} + + +static int +nbrd_reply(xo) + XO *xo; +{ + NBRD *nbrd; + char *fname, fpath[64], reason[80]; + LOG mail; + + nbrd = (NBRD *) xo_pool + (xo->pos - xo->top); + fname = NULL; + + if (nbrd->mode & (NBRD_FINISH | NBRD_END)) + return XO_NONE; + +#ifdef SYSOP_START_COSIGN + if (!(nbrd->mode & NBRD_START)) + { + vmsg("©|¥¼¶}©l³s¸p"); + return XO_FOOT; + } +#endif + + if (time(0) >= nbrd->etime) + { + currchrono = nbrd->btime; + if (nbrd->mode & NBRD_NEWBOARD) /* ·sªO³s¸p±¾ END */ + { + if (!(nbrd->mode & NBRD_END)) + { + nbrd->mode ^= NBRD_END; + currchrono = nbrd->btime; + rec_put(xo->dir, nbrd, sizeof(NBRD), xo->pos, cmpbtime); + } + } + else /* ¨ä¥L³s¸p±¾ FINISH */ + { + if (!(nbrd->mode & NBRD_FINISH)) + { + nbrd->mode ^= NBRD_FINISH; + currchrono = nbrd->btime; + rec_put(xo->dir, nbrd, sizeof(NBRD), xo->pos, cmpbtime); + } + } + vmsg("³s¸p¤w¸gºI¤î¤F"); + return XO_FOOT; + } + + + /* --------------------------------------------------- */ + /* Àˬd¬O§_¤w¸g³s¸p¹L */ + /* --------------------------------------------------- */ + + nbrd_fpath(fpath, xo->dir, nbrd); + fname = strrchr(fpath, '@'); + *fname = 'G'; + + if (nbrd_seek(fpath)) + { + vmsg("±z¤w¸g³s¸p¹L¤F¡I"); + return XO_FOOT; + } + + /* --------------------------------------------------- */ + /* ¶}©l³s¸p */ + /* --------------------------------------------------- */ + + *fname = '@'; + + if (vans("n¥[¤J³s¸p¶Ü(Y/N)¡H[N] ") == 'y' && + vget(b_lines, 0, "§Ú¦³¸Ün»¡¡G", reason, 65, DOECHO)) + { + FILE *fp; + + if (fp = fopen(fpath, "a")) + { + if (nbrd->mode & NBRD_ANONYMOUS) + fprintf(fp, "%3d -> " STR_ANONYMOUS "\n %s\n", nbrd->total, reason); + else + fprintf(fp, "%3d -> %s (%s)\n %s\n", nbrd->total, cuser.userid, cuser.email, reason); + fclose(fp); + } + + currchrono = nbrd->btime; + rec_ref(xo->dir, nbrd, sizeof(NBRD), xo->pos, cmpbtime, addreply); + + memset(&mail, 0, sizeof(LOG)); + strcpy(mail.userid, cuser.userid); + strcpy(mail.email, cuser.email); + *fname = 'G'; + rec_add(fpath, &mail, sizeof(LOG)); + + vmsg("¥[¤J³s¸p§¹¦¨"); + + if (nbrd->mode & NBRD_END) + { + char buf[80]; + sprintf (buf, "[³s¸p¦¨¥\\] ¯¸°È½Ð¨ì³s¸p¾÷¶}±Ò %s ¬ÝªO", nbrd->brdname); + add_post("newboard", fpath, buf); + } + return nbrd_init(xo); + } + + return XO_FOOT; +} + + +#ifdef SYSOP_START_COSIGN +static int +nbrd_start(xo) + XO *xo; +{ + NBRD *nbrd; + char fpath[64], buf[80], tmp[10]; + time_t etime; + + if (!HAS_PERM(PERM_ALLBOARD)) + return XO_NONE; + + nbrd = (NBRD *) xo_pool + (xo->pos - xo->top); + + if (nbrd->mode & (NBRD_FINISH | NBRD_END | NBRD_START)) + return XO_NONE; + + if (vans("½Ð½T©w¶}©l³s¸p(Y/N)¡H[N] ") != 'y') + return XO_FOOT; + + nbrd_fpath(fpath, xo->dir, nbrd); + etime = time(0) + NBRD_DAY_BRD * 86400; + + str_stamp(tmp, &etime); + sprintf(buf, "¶}©l³s¸p¡G ¨ì´Á¤é´Á¡G%s\n", tmp); + f_cat(fpath, buf); + f_cat(fpath, split_line); + + nbrd->etime = etime; + nbrd->mode ^= NBRD_START; + currchrono = nbrd->btime; + rec_put(xo->dir, nbrd, sizeof(NBRD), xo->pos, cmpbtime); + + return nbrd_head(xo); +} +#endif + + +static int +nbrd_finish(xo) + XO *xo; +{ + NBRD *nbrd; + char fpath[64], path[64]; + int fd; + FILE *fp; + + if (!HAS_PERM(PERM_ALLBOARD)) + return XO_NONE; + + nbrd = (NBRD *) xo_pool + (xo->pos - xo->top); + + if (nbrd->mode & NBRD_FINISH) + return XO_NONE; + + if (vans("½Ð½T©wµ²§ô³s¸p(Y/N)¡H[N] ") != 'y') + return XO_FOOT; + + vmsg("½Ð½s¿èµ²§ô³s¸pì¦]"); + sprintf(path, "tmp/%s", cuser.userid); /* ³s¸pì¦]ªº¼È¦sÀÉ®× */ + if (fd = vedit(path, 0)) + { + unlink(path); + vmsg(msg_cancel); + return nbrd_head(xo); + } + + nbrd_fpath(fpath, xo->dir, nbrd); + + f_cat(fpath, "µ²§ô³s¸pì¦]¡G\n\n"); + fp = fopen(fpath, "a"); + f_suck(fp, path); + fclose(fp); + f_cat(fpath, split_line); + unlink(path); + + nbrd->mode ^= NBRD_FINISH; + currchrono = nbrd->btime; + rec_put(xo->dir, nbrd, sizeof(NBRD), xo->pos, cmpbtime); + + return nbrd_head(xo); +} + + +static int /* 1:¶}ªO¦¨¥\ */ +nbrd_newbrd(nbrd) /* ¶}·sªO */ + NBRD *nbrd; +{ + BRD newboard; + ACCT acct; + + /* itoc.030519: Á×§K«Âж}ªO */ + if (brd_bno(nbrd->brdname) >= 0) + { + vmsg("¤w¦³¦¹ªO"); + return 1; + } + + memset(&newboard, 0, sizeof(BRD)); + + /* itoc.010805: ·s¬ÝªO¹w³] battr = ¤£Âà«H; postlevel = PERM_POST; ¬ÝªOªO¥D¬°´£°_³s¸pªÌ */ + newboard.battr = BRD_NOTRAN; + newboard.postlevel = PERM_POST; + strcpy(newboard.brdname, nbrd->brdname); + strcpy(newboard.class, nbrd->class); + strcpy(newboard.title, nbrd->title); + strcpy(newboard.BM, nbrd->owner); + + if (acct_load(&acct, nbrd->owner) >= 0) + acct_setperm(&acct, PERM_BM, 0); + + if (brd_new(&newboard) < 0) + return 0; + + vmsg("·sªO¦¨¥ß¡A°OµÛ¥[¤J¤ÀÃþ¸s²Õ"); + return 1; +} + + +static int +nbrd_open(xo) /* itoc.010805: ¶}·sªO³s¸p¡A³s¸p§¹²¦¶}·s¬ÝªO */ + XO *xo; +{ + NBRD *nbrd; + + if (!HAS_PERM(PERM_ALLBOARD)) + return XO_NONE; + + nbrd = (NBRD *) xo_pool + (xo->pos - xo->top); + + if (nbrd->mode & NBRD_FINISH || !(nbrd->mode & NBRD_NEWBOARD)) + return XO_NONE; + + if (vans("½Ð½T©w¶}±Ò¬ÝªO(Y/N)¡H[N] ") == 'y') + { + if (nbrd_newbrd(nbrd)) + { + nbrd->mode ^= NBRD_FINISH; + currchrono = nbrd->btime; + rec_put(xo->dir, nbrd, sizeof(NBRD), xo->pos, cmpbtime); + } + return nbrd_head(xo); + } + + return XO_FOOT; +} + + +static int +nbrd_browse(xo) + XO *xo; +{ + int key; + NBRD *nbrd; + char fpath[80]; + + /* itoc.010304: ¬°¤FÅý¾\Ū¨ì¤@¥b¤]¥i¥H¥[¤J³s¸p¡A¦Ò¼{ more ¶Ç¦^È */ + for (;;) + { + nbrd = (NBRD *) xo_pool + (xo->pos - xo->top); + nbrd_fpath(fpath, xo->dir, nbrd); + + if ((key = more(fpath, FOOTER_COSIGN)) < 0) + break; + + if (!key) + key = vkey(); + + switch (key) + { + case KEY_UP: + case KEY_PGUP: + case '[': + case 'k': + key = xo->pos - 1; + + if (key < 0) + break; + + xo->pos = key; + + if (key <= xo->top) + { + xo->top = (key / XO_TALL) * XO_TALL; + nbrd_load(xo); + } + continue; + + case KEY_DOWN: + case KEY_PGDN: + case ']': + case 'j': + case ' ': + key = xo->pos + 1; + + if (key >= xo->max) + break; + + xo->pos = key; + + if (key >= xo->top + XO_TALL) + { + xo->top = (key / XO_TALL) * XO_TALL; + nbrd_load(xo); + } + continue; + + case 'y': + case 'r': + nbrd_reply(xo); + break; + + case 'h': + xo_help("cosign"); + break; + } + break; + } + + return nbrd_head(xo); +} + + +static int +nbrd_delete(xo) + XO *xo; +{ + NBRD *nbrd; + char *fname, fpath[80]; + char *list = "@G"; /* itoc.µù¸Ñ: ²M newbrd file */ + + nbrd = (NBRD *) xo_pool + (xo->pos - xo->top); + if (strcmp(cuser.userid, nbrd->owner) && !HAS_PERM(PERM_ALLBOARD)) + return XO_NONE; + + if (vans(msg_del_ny) != 'y') + return XO_FOOT; + + nbrd_fpath(fpath, xo->dir, nbrd); + fname = strrchr(fpath, '@'); + while (*fname = *list++) + { + unlink(fpath); /* Thor: ½T©w¦W¦r´N¬å */ + } + + currchrono = nbrd->btime; + rec_del(xo->dir, sizeof(NBRD), xo->pos, cmpbtime); + return nbrd_init(xo); +} + + +static int +nbrd_edit(xo) + XO *xo; +{ + if (HAS_PERM(PERM_ALLBOARD)) + { + char fpath[64]; + NBRD *nbrd; + + nbrd = (NBRD *) xo_pool + (xo->pos - xo->top); + nbrd_fpath(fpath, xo->dir, nbrd); + vedit(fpath, 0); + return nbrd_head(xo); + } + + return XO_NONE; +} + + +static int +nbrd_setup(xo) + XO *xo; +{ + int numbers; + char ans[6]; + NBRD *nbrd, newnh; + + if (!HAS_PERM(PERM_ALLBOARD)) + return XO_NONE; + + vs_bar("³s¸p³]©w"); + nbrd = (NBRD *) xo_pool + (xo->pos - xo->top); + memcpy(&newnh, nbrd, sizeof(NBRD)); + + prints("¬ÝªO¦WºÙ¡G%s\n¬ÝªO»¡©ú¡G%4.4s %s\n³s¸pµo°_¡G%s\n", + newnh.brdname, newnh.class, newnh.title, newnh.owner); + prints("¶}©l®É¶¡¡G%s\n", Btime(&newnh.btime)); + prints("µ²§ô®É¶¡¡G%s\n", Btime(&newnh.etime)); + prints("ÁٻݤH¼Æ¡G%d\n", newnh.total); + + if (vget(8, 0, "(E)³]©w (Q)¨ú®ø¡H[Q] ", ans, 3, LCECHO) == 'e') + { + vget(11, 0, MSG_BID, newnh.brdname, BNLEN + 1, GCARRY); + vget(12, 0, "¬ÝªO¤ÀÃþ¡G", newnh.class, sizeof(newnh.class), GCARRY); + vget(13, 0, "¬ÝªO¥DÃD¡G", newnh.title, sizeof(newnh.title), GCARRY); + sprintf(ans, "%d", newnh.total); + vget(14, 0, "³s¸p¤H¼Æ¡G", ans, 6, GCARRY); + numbers = atoi(ans); + if (numbers <= 500 && numbers >= 1) + newnh.total = numbers; + + if (memcmp(&newnh, nbrd, sizeof(newnh)) && vans(msg_sure_ny) == 'y') + { + memcpy(nbrd, &newnh, sizeof(NBRD)); + currchrono = nbrd->btime; + rec_put(xo->dir, nbrd, sizeof(NBRD), xo->pos, cmpbtime); + } + } + + return nbrd_head(xo); +} + + +static int +nbrd_uquery(xo) + XO *xo; +{ + NBRD *nbrd; + + nbrd = (NBRD *) xo_pool + (xo->pos - xo->top); + + move(1, 0); + clrtobot(); + my_query(nbrd->owner); + return nbrd_head(xo); +} + + +static int +nbrd_usetup(xo) + XO *xo; +{ + NBRD *nbrd; + ACCT acct; + + if (!HAS_PERM(PERM_ALLACCT)) + return XO_NONE; + + nbrd = (NBRD *) xo_pool + (xo->pos - xo->top); + if (acct_load(&acct, nbrd->owner) < 0) + return XO_NONE; + + move(3, 0); + acct_setup(&acct, 1); + return nbrd_head(xo); +} + + +static int +nbrd_help(xo) + XO *xo; +{ + xo_help("cosign"); + return nbrd_head(xo); +} + + +static KeyFunc nbrd_cb[] = +{ + XO_INIT, nbrd_init, + XO_LOAD, nbrd_load, + XO_HEAD, nbrd_head, + XO_BODY, nbrd_body, + + 'y', nbrd_reply, + 'r', nbrd_browse, + 'o', nbrd_open, +#ifdef SYSOP_START_COSIGN + 's', nbrd_start, +#endif + 'c', nbrd_finish, + 'd', nbrd_delete, + 'E', nbrd_edit, + 'B', nbrd_setup, + + Ctrl('P'), nbrd_add, + Ctrl('Q'), nbrd_uquery, + Ctrl('O'), nbrd_usetup, + + 'h', nbrd_help +}; + + +int +XoNewBoard() +{ + XO *xo; + char fpath[64]; + + sprintf(fpath, "run/newbrd/%s", fn_dir); + xz[XZ_COSIGN - XO_ZONE].xo = xo = xo_new(fpath); + xz[XZ_COSIGN - XO_ZONE].cb = nbrd_cb; + xo->key = XZ_COSIGN; + xover(XZ_COSIGN); + free(xo); + + return 0; +} +#endif /* HAVE_COSIGN */ diff --git a/so/song.c b/so/song.c new file mode 100644 index 0000000..13b9cea --- /dev/null +++ b/so/song.c @@ -0,0 +1,752 @@ +/*-------------------------------------------------------*/ +/* song.c ( YZU_CSE WindTop BBS ) */ +/*-------------------------------------------------------*/ +/* target : song ordering routines */ +/* create : / / */ +/* update : 01/12/18 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#ifdef HAVE_SONG + +extern BCACHE *bshm; +extern XZ xz[]; +extern char xo_pool[]; +extern char brd_bits[]; + + +static void XoSong(); + + +#define SONG_SRC "<~Src~>" +#define SONG_DES "<~Des~>" +#define SONG_SAY "<~Say~>" +#define SONG_END "<~End~>" + + +#ifdef LOG_SONG_USIES +static int /* -1:¨S§ä¨ì >=0:pos */ +song_usies_find(fpath, chrono, songdata) + char *fpath; + time_t chrono; + SONGDATA *songdata; +{ + int fd, pos; + int rc = -1; + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + pos = 0; + while (read(fd, songdata, sizeof(SONGDATA)) == sizeof(SONGDATA)) + { + if (songdata->chrono == chrono) + { + rc = pos; + break; + } + pos++; + } + close(fd); + } + return rc; +} + + +static void +song_usies_log(chrono, title) + time_t chrono; + char *title; +{ + SONGDATA songdata; + int pos; + char *dir; + + dir = FN_RUN_SONGUSIES; + + if ((pos = song_usies_find(dir, chrono, &songdata)) >= 0) + { + songdata.count++; + rec_put(dir, &songdata, sizeof(SONGDATA), pos, NULL); + } + else + { + songdata.chrono = chrono; + songdata.count = 1; + strcpy(songdata.title, title); + rec_add(dir, &songdata, sizeof(SONGDATA)); + } +} +#endif + + +static int swaped; /* ¥»¤å¬O§_¦³ <~Src~> µ¥ */ + +static int +song_swap(str, src, des) + char *str; + char *src; + char *des; +{ + char *ptr; + char buf[ANSILINELEN]; + + if (ptr = strstr(str, src)) + { + *ptr = '\0'; + ptr += strlen(src); + /* sprintf(buf, "%s%s%s", str, des, ptr); */ + snprintf(buf, ANSILINELEN, "%s%s%s", str, des, ptr); /* swap ¥i¯à·|¶W¹L ANSILINELEN */ + strcpy(str, buf); + + /* return 1; */ + return ++swaped; + } + + return 0; +} + + +static void +song_quote(fpr, fpw, src, des, say) /* ±q fpr Ū¥X¤º¤å¡A§â <~Src~> µ¥´À´«±¼¡A¼g¤J fpw */ + FILE *fpr, *fpw; + char *src, *des, *say; +{ + char buf[ANSILINELEN]; + + swaped = 0; + while (fgets(buf, sizeof(buf), fpr)) + { + if (strstr(buf, SONG_END)) + break; + + while (song_swap(buf, SONG_SRC, src)); + while (song_swap(buf, SONG_DES, des)); + while (song_swap(buf, SONG_SAY, say)); + fputs(buf, fpw); + } + + if (!swaped) /* itoc.011115: ¦pªG¥»¤å¨S¦³ <~Src~>¡A«h¦b³Ì«á¥[¤W */ + { + /* ¦b³Ì«á¤@¦æ¥[¤W <~Src~> ·Q¹ï <~Des~> »¡ <~Say~> */ + strcpy(buf, "\033[1;33m" SONG_SRC " ·Q¹ï " SONG_DES " »¡ " SONG_SAY "\033[m\n"); + song_swap(buf, SONG_SRC, src); + song_swap(buf, SONG_DES, des); + song_swap(buf, SONG_SAY, say); + fputs(buf, fpw); + } + + /* ¦bÀɮ׳̫á¥[¤WÂIºq®É¶¡ */ + fprintf(fpw, "\n--\n%s\n", Now()); +} + + +#define GEM_FILE 0x01 /* ¹w´Á¬OÀÉ®× */ + + +static HDR * /* NULL:µLÅvŪ¨ú */ +song_check(xo, fpath, op) + XO *xo; + char *fpath; + int op; +{ + HDR *hdr; + int gtype; + + hdr = (HDR *) xo_pool + (xo->pos - xo->top); + gtype = hdr->xmode; + + if ((gtype & GEM_RESTRICT) && !(xo->key & GEM_M_BIT)) + return NULL; + + if ((op & GEM_FILE) && (gtype & GEM_FOLDER)) + return NULL; + + if (fpath) + { + if (gtype & GEM_BOARD) + gem_fpath(fpath, hdr->xname, fn_dir); + else + hdr_fpath(fpath, xo->dir, hdr); + } + return hdr; +} + + +static void +song_item(num, hdr, level) + int num; + HDR *hdr; + int level; +{ + int xmode, gtype; + + xmode = hdr->xmode; + gtype = (char) 0xba; + + /* ¥Ø¿ý¥Î¹ê¤ß¡A¤£¬O¥Ø¿ý¥ÎªÅ¤ß */ + if (xmode & GEM_FOLDER) /* ¤å³¹:¡º ¨÷©v:¡» */ + gtype += 1; + + if (hdr->xname[0] == '@') /* ¸ê®Æ:¡¸ ¤ÀÃþ:¡¹ */ + gtype -= 2; + else if (xmode & GEM_BOARD) /* ¬ÝªO:¡½ */ + gtype += 2; + + prints("%6d%c \241%c ", num, xmode & GEM_RESTRICT ? ')' : ' ', gtype); + + if ((xmode & GEM_RESTRICT) && !(level & GEM_M_BIT)) + outs(MSG_DATA_CLOAK); + else + prints("%.*s\n", d_cols + 64, hdr->title); +} + + +static int +song_body(xo) + XO *xo; +{ + HDR *hdr; + int num, max, tail; + + max = xo->max; + if (max <= 0) + { + outs("\n\n¡mºq¥»¡n©|¦b§l¨ú¤Ñ¦a¶¡ªº¤éºë¤ëµØ :)"); + vmsg(NULL); + return XO_QUIT; + } + + hdr = (HDR *) xo_pool; + num = xo->top; + tail = num + XO_TALL; + if (max > tail) + max = tail; + + move(3, 0); + tail = xo->key; /* ɥΠtail */ + do + { + song_item(++num, hdr++, tail); + } while (num < max); + clrtobot(); + + /* return XO_NONE; */ + return XO_FOOT; /* itoc.010403: §â b_lines ¶ñ¤W feeter */ +} + + +static int +song_head(xo) + XO *xo; +{ + vs_head("ºëµØ¤å³¹", xo->xyz); + prints(NECKER_SONG, d_cols, ""); + return song_body(xo); +} + + +static int +song_init(xo) + XO *xo; +{ + xo_load(xo, sizeof(HDR)); + return song_head(xo); +} + + +static int +song_load(xo) + XO *xo; +{ + xo_load(xo, sizeof(HDR)); + return song_body(xo); +} + + +/* ----------------------------------------------------- */ +/* ¸ê®Æ¤§·s¼W¡Gappend / insert */ +/* ----------------------------------------------------- */ + + +static int +song_browse(xo) + XO *xo; +{ + HDR *hdr; + int op, xmode; + char fpath[64], title[TTLEN + 1]; + + op = 0; + + for (;;) + { + if (!(hdr = song_check(xo, fpath, op))) + break; + + xmode = hdr->xmode; + + /* browse folder */ + + if (xmode & GEM_FOLDER) + { + if (xmode & GEM_BOARD) + { + if ((op = gem_link(hdr->xname)) < 0) + { + vmsg("¹ï¤£°_¡A¦¹ªOºëµØ°Ï¥uãªO¤Í¶i¤J¡A½Ð¦VªO¥D¥Ó½Ð¤J¹Ò³\\¥i"); + return XO_FOOT; + } + } + else /* ¤@¯ë¨÷©v */ + { + op = xo->key; /* Ä~©Ó¥À¨÷©vªºÅv */ + } + + strcpy(title, hdr->title); + XoSong(fpath, title, op); + return song_init(xo); + } + + /* browse article */ + + /* Thor.990204: ¬°¦Ò¼{more ¶Ç¦^È */ + if ((xmode = more(fpath, FOOTER_GEM)) < 0) + break; + + op = GEM_FILE; + +re_key: + switch (xo_getch(xo, xmode)) + { + case XO_BODY: + continue; + + case '/': + if (vget(b_lines, 0, "·j´M¡G", hunt, sizeof(hunt), DOECHO)) + { + more(fpath, FOOTER_GEM); + goto re_key; + } + continue; + + case 'C': + { + FILE *fp; + if (fp = tbf_open()) + { + f_suck(fp, fpath); + fclose(fp); + } + } + break; + + case 'h': + xo_help("song"); + break; + } + break; + } + + return song_head(xo); +} + + +static int +count_ktv() /* itoc.021102: ktv ªO¸Ì±¤w¦³´X½gªºÂIºq°O¿ý */ +{ + int count, fd; + time_t yesterday; + char folder[64]; + HDR *hdr; + + brd_fpath(folder, BN_KTV, fn_dir); + if ((fd = open(folder, O_RDONLY)) < 0) + return 0; + + mgets(-1); + count = 0; + yesterday = time(0) - 86400; + while (hdr = mread(fd, sizeof(HDR))) + { + /* §Y¨Ï¬O°Î¦WÂIºq¡Auserid ¤´°O¿ý¦b hdr.owner + IDLEN + 1 */ + if (!strcmp(hdr->owner + IDLEN + 1, cuser.userid) && + hdr->chrono > yesterday) + { + if (++count >= 3) /* ¨îÂI¤Tº */ + break; + } + } + close(fd); + + return count; +} + + +static int +song_order(xo) + XO *xo; +{ +#ifdef HAVE_ANONYMOUS + int annoy; +#endif + char fpath[64], des[20], say[57], buf[64]; + HDR *hdr, xpost; + FILE *fpr, *fpw; + + /* itoc.µù¸Ñ: song_order µø¦P post */ + if (!HAS_PERM(PERM_POST)) + return XO_NONE; + + /* itoc.010831: ÂIºqn¿ú¡A©Ò¥Hn¸T¤î multi-login */ + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XO_FOOT; + } + + if (count_ktv() >= 3) /* ¨îÂI¤Tº */ + { + vmsg("¹L¥h¤G¤Q¥|¤p®É¤º±z¤wÂI¿ï¹L¦hºq¦±"); + return XO_FOOT; + } + + if (cuser.money < 1000) + { + vmsg("n 1000 »È¹ô¤~¯àÂIºq¨ì¬ÝªO³á"); + return XO_FOOT; + } + + if (!(hdr = song_check(xo, fpath, GEM_FILE))) + return XO_NONE; + + if (!vget(b_lines, 0, "ÂIºqµ¹½Ö¡G", des, sizeof(des), DOECHO)) + return XO_FOOT; + if (!vget(b_lines, 0, "·Q»¡ªº¸Ü¡G", say, sizeof(say), DOECHO)) + return XO_FOOT; + +#ifdef HAVE_ANONYMOUS + annoy = vans("·Qn°Î¦W¶Ü(Y/N)¡H[N] ") == 'y'; +#endif + + if (vans("½T©wÂIºq¶Ü(Y/N)¡H[Y] ") == 'n') + return XO_FOOT; + + if (!(fpr = fopen(fpath, "r"))) + return XO_FOOT; + + cuser.money -= 1000; + +#ifdef LOG_SONG_USIES + song_usies_log(hdr->chrono, hdr->title); +#endif + + /* ¥[¤J¤å³¹ÀÉ®× */ + + brd_fpath(fpath, BN_KTV, fn_dir); + + if (fpw = fdopen(hdr_stamp(fpath, 'A', &xpost, buf), "w")) + { +#ifdef HAVE_ANONYMOUS + song_quote(fpr, fpw, annoy ? STR_ANONYMOUS : cuser.userid, des, say); +#else + song_quote(fpr, fpw, cuser.userid, des, say); +#endif + fclose(fpw); + } + + fclose(fpr); + + /* ¥[¤J .DIR record */ + +#ifdef HAVE_ANONYMOUS + strcpy(xpost.owner, annoy ? STR_ANONYMOUS : cuser.userid); + /* §Y¨Ï¬O°Î¦WÂIºq¡Auserid ¤´°O¿ý¦b hdr.owner + IDLEN + 1 */ + strcpy(xpost.owner + IDLEN + 1, cuser.userid); +#else + strcpy(xpost.owner, cuser.userid); +#endif + strcpy(xpost.nick, xpost.owner); + sprintf(xpost.title, "%s ÂIµ¹ %s", xpost.owner, des); + rec_bot(fpath, &xpost, sizeof(HDR)); + + btime_update(brd_bno(BN_KTV)); + + return XO_FOOT; +} + + +static int +song_send(xo) + XO *xo; +{ + char fpath[64], say[57], buf[64]; + HDR *hdr, xpost; + FILE *fpr, *fpw; + ACCT acct; + + /* itoc.µù¸Ñ: song_send µø¦P mail */ + if (!HAS_PERM(PERM_LOCAL)) + return XO_NONE; + + if (!(hdr = song_check(xo, fpath, GEM_FILE))) + return XO_NONE; + + if (acct_get("ÂIºqµ¹½Ö¡G", &acct) < 1) /* acct_get ¥i¯à·| clear¡A©Ò¥Hn«Ã¸ */ + return song_head(xo); + + if (!vget(b_lines, 0, "·Q»¡ªº¸Ü¡G", say, sizeof(say), DOECHO)) + strcpy(say, "........."); + + if (vans("½T©wÂIºq¶Ü(Y/N)¡H[Y] ") == 'n') + return song_head(xo); /* acct_get ¥i¯à·| clear¡A©Ò¥Hn«Ã¸ */ + +#ifdef LOG_SONG_USIES + song_usies_log(hdr->chrono, hdr->title); +#endif + + /* ¥[¤J¤å³¹ÀÉ®× */ + + if (!(fpr = fopen(fpath, "r"))) + return song_head(xo); /* acct_get ¥i¯à·| clear¡A©Ò¥Hn«Ã¸ */ + + usr_fpath(fpath, acct.userid, fn_dir); + + if (fpw = fdopen(hdr_stamp(fpath, 0, &xpost, buf), "w")) + { + song_quote(fpr, fpw, cuser.userid, acct.userid, say); + fclose(fpw); + } + + fclose(fpr); + + /* ¥[¤J .DIR record */ + + strcpy(xpost.owner, cuser.userid); + strcpy(xpost.nick, cuser.username); + sprintf(xpost.title, "%s ÂIºqµ¹±z", cuser.userid); + rec_add(fpath, &xpost, sizeof(HDR)); + + mail_hold(buf, acct.userid, xpost.title, 0); + m_biff(acct.userno); /* Y¹ï¤è¦b½u¤W¡A«hn³qª¾¦³·s«H */ + + return song_head(xo); /* acct_get ¥i¯à·| clear¡A©Ò¥Hn«Ã¸ */ +} + + +static int +song_internet(xo) + XO *xo; +{ + int rc; + char fpath[64], rcpt[64], des[20], say[57]; + HDR *hdr; + FILE *fpr, *fpw; + + /* itoc.µù¸Ñ: song_internet µø¦P internet_mail */ + if (!HAS_PERM(PERM_INTERNET)) + return XO_NONE; + + if (!(hdr = song_check(xo, fpath, GEM_FILE))) + return XO_NONE; + + if (!vget(b_lines, 0, "¥Øªº¦a¡G", rcpt, sizeof(rcpt), DOECHO)) + return XO_FOOT; + if (!strchr(rcpt, '@')) + return XO_FOOT; + + if (!vget(b_lines, 0, "ÂIºqµ¹½Ö¡G", des, sizeof(des), DOECHO)) + return XO_FOOT; + if (!vget(b_lines, 0, "·Q»¡ªº¸Ü¡G", say, sizeof(say), DOECHO)) + strcpy(say, "........."); + + if (vans("½T©wÂIºq¶Ü(Y/N)¡H[Y] ") == 'n') + return XO_FOOT; + +#ifdef LOG_SONG_USIES + song_usies_log(hdr->chrono, hdr->title); +#endif + + /* ¥[¤J¤å³¹ÀÉ®× */ + + if (!(fpr = fopen(fpath, "r"))) + return XO_FOOT; + + sprintf(fpath, "tmp/song_internet.%s", cuser.userid); + fpw = fopen(fpath, "w"); + + song_quote(fpr, fpw, cuser.userid, des, say); + + fclose(fpr); + fclose(fpw); + + /* ±Hµ¹¹ï¤è */ + + rc = bsmtp(fpath, "ÂIºqµ¹±z", rcpt, 0); + vmsg(rc >= 0 ? msg_sent_ok : "«H¥óµLªk±H¹F¡A©³½Z³Æ¥÷¦b«H½c"); + + mail_hold(fpath, rcpt, hdr->title, rc); + unlink(fpath); + + return XO_FOOT; +} + + +static int +song_edit(xo) + XO *xo; +{ + char fpath[64]; + + if (!song_check(xo, fpath, GEM_FILE)) + return XO_NONE; + + if (xo->key & GEM_W_BIT) + vedit(fpath, 0); + else + vedit(fpath, -1); /* itoc.010403: Åý¤@¯ë¨Ï¥ÎªÌ¤]¥i¥H edit ¬Ý±±¨î½X */ + return song_head(xo); +} + + +static int +song_title(xo) + XO *xo; +{ + HDR *fhdr, mhdr; + int pos, cur; + + if (!(xo->key & GEM_W_BIT) || !(fhdr = song_check(xo, NULL, 0))) + return XO_NONE; + + memcpy(&mhdr, fhdr, sizeof(HDR)); + + vget(b_lines, 0, "¼ÐÃD¡G", mhdr.title, TTLEN + 1, GCARRY); + + if (xo->key & GEM_X_BIT) + { + vget(b_lines, 0, "½sªÌ¡G", mhdr.owner, IDLEN + 1, GCARRY); + /* vget(b_lines, 0, "¼ÊºÙ¡G", mhdr.nick, sizeof(mhdr.nick), GCARRY); */ /* ºëµØ°Ï¦¹Äæ¦ì¬°ªÅ */ + vget(b_lines, 0, "¤é´Á¡G", mhdr.date, sizeof(mhdr.date), GCARRY); + } + + if (memcmp(fhdr, &mhdr, sizeof(HDR)) && vans(msg_sure_ny) == 'y') + { + pos = xo->pos; + cur = pos - xo->top; + + memcpy(fhdr, &mhdr, sizeof(HDR)); + rec_put(xo->dir, fhdr, sizeof(HDR), pos, NULL); + + move(3 + cur, 0); + song_item(++pos, fhdr, xo->key); + + } + return XO_FOOT; +} + + +static int +song_help(xo) + XO *xo; +{ + xo_help("song"); + return song_head(xo); +} + + +static KeyFunc song_cb[] = +{ + XO_INIT, song_init, + XO_LOAD, song_load, + XO_HEAD, song_head, + XO_BODY, song_body, + + 'r', song_browse, + 'o', song_order, + 'm', song_send, + 'M', song_internet, + + 'E', song_edit, + 'T', song_title, + + 'h', song_help +}; + + +static void +XoSong(folder, title, level) + char *folder; + char *title; + int level; +{ + XO *xo, *last; + + last = xz[XZ_SONG - XO_ZONE].xo; /* record */ + + xz[XZ_SONG - XO_ZONE].xo = xo = xo_new(folder); + xz[XZ_SONG - XO_ZONE].cb = song_cb; + xo->pos = 0; + xo->key = level; + xo->xyz = title; + strcpy(currBM, "ªO¥D¡G¨t²ÎºÞ²zªÌ"); + + xover(XZ_SONG); + + free(xo); + + xz[XZ_SONG - XO_ZONE].xo = last; /* restore */ +} + + +int +XoSongMain() +{ + int level; + char fpath[64]; + + gem_fpath(fpath, BN_KTV, fn_dir); + + if (HAS_PERM(PERM_SYSOP)) + level = GEM_W_BIT | GEM_X_BIT | GEM_M_BIT; + else if (HAS_PERM(PERM_ALLBOARD)) + level = GEM_W_BIT | GEM_M_BIT; + else + level = 0; + + XoSong(fpath, "ÂIºq¨t²Î", level); + return 0; +} + + +int +XoSongSub() +{ + int bno; + + if ((bno = brd_bno(BN_REQUEST)) >= 0) + { + XoPost(bno); + xover(XZ_POST); + return 0; + } + return XEASY; +} + + +int +XoSongLog() +{ + int bno; + + if ((bno = brd_bno(BN_KTV)) >= 0) + { + XoPost(bno); + xover(XZ_POST); + return 0; + } + return XEASY; +} +#endif /* HAVE_SONG */ diff --git a/so/todo.c b/so/todo.c new file mode 100644 index 0000000..b99e589 --- /dev/null +++ b/so/todo.c @@ -0,0 +1,365 @@ +/*-------------------------------------------------------*/ +/* todo.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¦æ¨Æ¾ä */ +/* create : 00/09/13 */ +/* update : 03/08/24 */ +/* author : DavidYu.bbs@ptt2.twbbs.org */ +/* recast : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef HAVE_CALENDAR + +#define HEADER_COLOR "\033[1;44m" +#define CALENDAR_COLOR "\033[30;47m" +#define CALENDAR_TODAY "\033[30;42m" + + +/*-------------------------------------------------------*/ +/* ¤é´Á³B²z¨ç¦¡ */ +/*-------------------------------------------------------*/ + + +static int /* ³oӤ릳´X¤Ñ */ +month_day(y, m) + int y, m; +{ + static int day[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + return ((m == 2) && ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0))) ? 29 : day[m - 1]; +} + + +static time_t +make_time(year, month, day) + int year, month, day; +{ + struct tm ptime; + + ptime.tm_sec = 0; + ptime.tm_min = 0; + ptime.tm_hour = 0; + ptime.tm_mday = day; + ptime.tm_mon = month - 1; + ptime.tm_year = year - 1900; + ptime.tm_isdst = 0; +#ifndef CYGWIN + ptime.tm_zone = "GMT"; + ptime.tm_gmtoff = 0; +#endif + + return mktime(&ptime); +} + + +static time_t +parse_date(date, year, month, day) + char *date; /* ¶Ç¤J date ®æ¦¡¬° 2003/08/25 */ + int *year, *month, *day; /* ¶Ç¥X time_t year month day */ +{ + char *yy, *mm, *dd; + + yy = strtok(date, "/"); + mm = strtok(NULL, "/"); + dd = strtok(NULL, ""); + if (!yy || !mm || !dd) + return 0; + + *year = atoi(yy); + *month = atoi(mm); + *day = atoi(dd); + if (*year < 1 || *month < 1 || *month > 12 || *day < 1 || *day > 31) + return 0; + + return make_time(*year, *month, *day); +} + + +/*-------------------------------------------------------*/ +/* ¨Æ¥ó³B²z¨ç¦¡ */ +/*-------------------------------------------------------*/ + + +typedef struct EVENT +{ + time_t chrono; /* µ´¹ï®É¶¡ */ + int year, month, day; /* ¤é´Á: ¦~/¤ë/¤é */ + char content[40]; /* ±Ôz */ + struct EVENT *next; +} EVENT; + + +static void +event_insert(head, insert) + EVENT *head, *insert; +{ + EVENT *p, *next; + + for (p = head; (next = p->next) && (next->chrono < insert->chrono); p = next) + ; + insert->next = p->next; + p->next = insert; +} + + +static void +event_free(head) + EVENT *head; +{ + EVENT *n; + + while (head) + { + n = head->next; + free(head); + head = n; + } +} + + +static EVENT * +event_read(today) + time_t today; +{ + FILE *fp; + char buf[80]; + EVENT head; + + head.next = NULL; + + usr_fpath(buf, cuser.userid, FN_TODO); + if (fp = fopen(buf, "r")) + { + while (fgets(buf, sizeof(buf), fp)) + { + time_t chrono; + int year, month, day; + char *date, *content; + EVENT *t; + + if (buf[0] == '#') + continue; + + date = strtok(buf, " \n"); + content = strtok(NULL, "\n"); + if (!date || !content) + continue; + + if ((chrono = parse_date(date, &year, &month, &day)) && (chrono >= today)) + { + t = (EVENT *) malloc(sizeof(EVENT)); + + t->chrono = chrono; + t->year = year; + t->month = month; + t->day = day; + for (; *content == ' '; content++) + ; + str_ncpy(t->content, content, sizeof(t->content)); + + event_insert(&head, t); + } + } + fclose(fp); + } + + return head.next; +} + + +/*-------------------------------------------------------*/ +/* ¤ë¾ä²£¥Í¾¹ */ +/*-------------------------------------------------------*/ + + +static char ** +AllocCalBuffer(line, len) + int line, len; +{ + int i; + char **p; + + p = malloc(sizeof(char *) * line); + p[0] = malloc(sizeof(char) * line * len); + p[0][0] = '\0'; + for (i = 1; i < line; i++) + { + p[i] = p[i - 1] + len; + p[i][0] = '\0'; + } + return p; +} + + +static int +GenerateCalendar(calendar, y, m, tm_mon, tm_mday) /* ²£¥Í¤ë¾ä */ + char **calendar; + int y, m; /* n²£¥Í´X¦~´X¤ëªº¤ë¾ä */ + int tm_mon, tm_mday; /* ¤µ¤Ñ¬O´X¤ë´X¤é */ +{ + static char week_str[7][3] = {"¤é", "¤@", "¤G", "¤T", "¥|", "¤", "¤»"}; + static char month_color[12][8] = + { + "\033[1;32m", "\033[1;33m", "\033[1;35m", "\033[1;36m", + "\033[1;32m", "\033[1;33m", "\033[1;35m", "\033[1;36m", + "\033[1;32m", "\033[1;33m", "\033[1;35m", "\033[1;36m" + }; + static char *month_str[12] = + { + "¤@¤ë ", "¤G¤ë ", "¤T¤ë ", "¥|¤ë ", "¤¤ë ", "¤»¤ë ", + "¤C¤ë ", "¤K¤ë ", "¤E¤ë ", "¤Q¤ë ", "¤Q¤@¤ë", "¤Q¤G¤ë" + }; + + char *p; + int monthday, wday; + int i, line; + time_t first_day; + struct tm *ptime; + + line = 0; + first_day = make_time(y, m, 1); + ptime = localtime(&first_day); + + /* week day banner */ + p = calendar[line]; + p += sprintf(p, " %s ", HEADER_COLOR); + for (i = 0; i < 7; i++) + p += sprintf(p, "%s ", week_str[i]); + p += sprintf(p, "\033[m"); + + /* indent for first line */ + p = calendar[++line]; + p += sprintf(p, " %s ", CALENDAR_COLOR); + for (i = 0, wday = ptime->tm_wday; i < wday; i++) + p += sprintf(p, " "); + + monthday = month_day(y, m); + for (i = 1; i <= monthday; i++, wday = (wday + 1) % 7) + { + if (m == tm_mon && i == tm_mday) + p += sprintf(p, "%s%2d%s", CALENDAR_TODAY, i, CALENDAR_COLOR); + else + p += sprintf(p, "%2d", i); + + if (wday == 6) + { + p += sprintf(p, " \033[m"); + p = calendar[++line]; + + if (line >= 2 && line <= 4) /* show month */ + p += sprintf(p, "%s%2.2s\033[m %s ", month_color[m - 1], month_str[m - 1] + (line - 2) * 2, CALENDAR_COLOR); + else if (i < monthday) + p += sprintf(p, " %s ", CALENDAR_COLOR); + } + else + { + *p++ = ' '; + } + } + + /* fill up the last line */ + if (wday) + { + for (wday = 7 - wday; wday; wday--) + p += sprintf(p, " "); + p += sprintf(p, "\033[m"); + } + + return line + 1; +} + + +/*-------------------------------------------------------*/ +/* ¥Dµ{¦¡ */ +/*-------------------------------------------------------*/ + + +int +main_todo() +{ + char **calendar, fpath[64]; + time_t now, today; + struct tm *ptime, ntime; + int i, y, m; + int lines; /* ¥Ø«e¦³´X¦æ¨Æ¥ó */ + EVENT *head, *e; + + /* initialize date */ + time(&now); + ptime = localtime(&now); + ntime = *ptime; + y = ntime.tm_year + 1900; + m = ntime.tm_mon + 1; + today = now - (now % 86400); + + /* read event */ + head = e = event_read(today); + + /* generate calendar */ + lines = 0; + + calendar = AllocCalBuffer(21, 128); /* ¤TÓ¤ë³Ì¦hn 21 ¦C */ + for (i = 0; i < 3; i++) /* ¨C¦¸¨q¥X¤TӤ몺¦æ¨Æ¾ä */ + { + lines += GenerateCalendar(calendar + lines, y, m, ntime.tm_mon + 1, ntime.tm_mday) + 1; + if (m == 12) + { + y++; + m = 1; + } + else + { + m++; + } + } + + /* output */ + vs_bar("¦æ¨Æ¾ä"); + + today /= 86400; + + for (i = 0; i < 21; i++) + { + outs(calendar[i]); + if (i >= 2) + { + if (e) + { + prints("%*s\033[1;37m(%3d)\033[m %02d/%02d %s", + (i % 7) ? 5 : 31, "", e->chrono / 86400 - today, e->month, e->day, e->content); + e = e->next; + } + } + else if (i == 0) + { + prints(" \033[1;37m²{¦b¬O %d/%02d/%02d %2d:%02d:%02d%cm\033[m", + ntime.tm_year + 1900, ntime.tm_mon + 1, ntime.tm_mday, + (ntime.tm_hour == 0 || ntime.tm_hour == 12) ? 12 : ntime.tm_hour % 12, + ntime.tm_min, ntime.tm_sec, + ntime.tm_hour >= 12 ? 'p' : 'a'); + } + outc('\n'); + } + event_free(head); + + /* edit */ + switch (vans("¦æ¨Æ¾ä (D)§R°£ (E)×§ï (Q)¨ú®ø¡H[Q] ")) + { + case 'e': + more("etc/todo.welcome", NULL); + usr_fpath(fpath, cuser.userid, FN_TODO); + vedit(fpath, 0); + break; + + case 'd': + usr_fpath(fpath, cuser.userid, FN_TODO); + unlink(fpath); + break; + } + + return 0; +} +#endif /* HAVE_CALENDAR */ diff --git a/so/vote.c b/so/vote.c new file mode 100644 index 0000000..7ea7318 --- /dev/null +++ b/so/vote.c @@ -0,0 +1,1336 @@ +/*-------------------------------------------------------*/ +/* vote.c ( NTHU CS MapleBBS Ver 2.36 ) */ +/*-------------------------------------------------------*/ +/* target : boards' vote routines */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ +/* brd/_/.VCH : Vote Control Header ¥Ø«e©Ò¦³§ë²¼¯Á¤Þ */ +/* brd/_/@vote : vote history ¹L¥hªº§ë²¼¾ú¥v */ +/* brd/_/@/@_ : vote description §ë²¼»¡©ú */ +/* brd/_/@/I_ : vote selection Items §ë²¼¿ï¶µ */ +/* brd/_/@/O_ : users' Opinions ¨Ï¥ÎªÌ¦³¸Ün»¡ */ +/* brd/_/@/L_ : can vote List ¥i§ë²¼¦W³æ */ +/* brd/_/@/G_ : voted id loG file ¤w»â²¼¦W³æ */ +/* brd/_/@/Z_ : final/temporary result §ë²¼µ²ªG */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +extern BCACHE *bshm; +extern XZ xz[]; +extern char xo_pool[]; + + +static char * +vch_fpath(fpath, folder, vch) + char *fpath, *folder; + VCH *vch; +{ + /* VCH ©M HDR ªº xname Äæ¦ì¤Ç°t¡A©Ò¥Hª½±µÉ¥Î hdr_fpath() */ + hdr_fpath(fpath, folder, (HDR *) vch); + return strrchr(fpath, '@'); +} + + +static int vote_add(); + + +int +vote_result(xo) + XO *xo; +{ + char fpath[64]; + + setdirpath(fpath, xo->dir, "@/@vote"); + /* Thor.990204: ¬°¦Ò¼{more ¶Ç¦^È */ + if (more(fpath, NULL) >= 0) + return XO_HEAD; /* XZ_POST ©M XZ_VOTE ¦@¥Î vote_result() */ + + vmsg("¥Ø«e¨S¦³¥ô¦ó¶}²¼ªºµ²ªG"); + return XO_FOOT; +} + + +static void +vote_item(num, vch) + int num; + VCH *vch; +{ + prints("%6d%c%c%c%c%c %-9.8s%-12s %.44s\n", + num, tag_char(vch->chrono), vch->vgamble, vch->vsort, vch->vpercent, vch->vprivate, + vch->cdate, vch->owner, vch->title); +} + + +static int +vote_body(xo) + XO *xo; +{ + VCH *vch; + int num, max, tail; + + max = xo->max; + if (max <= 0) + { + if (bbstate & STAT_BOARD) + { + if (vans("nÁ|¿ì§ë²¼¶Ü(Y/N)¡H[N] ") == 'y') + return vote_add(xo); + } + else + { + vmsg("¥Ø«e¨ÃµL§ë²¼Á|¦æ"); + } + return XO_QUIT; + } + + vch = (VCH *) xo_pool; + num = xo->top; + tail = num + XO_TALL; + if (max > tail) + max = tail; + + move(3, 0); + do + { + vote_item(++num, vch++); + } while (num < max); + clrtobot(); + + /* return XO_NONE; */ + return XO_FOOT; /* itoc.010403: §â b_lines ¶ñ¤W feeter */ +} + + +static int +vote_head(xo) + XO *xo; +{ + vs_head(currBM, "§ë²¼©Ò"); + prints(NECKER_VOTE, d_cols, ""); + return vote_body(xo); +} + + +static int +vote_init(xo) + XO *xo; +{ + xo_load(xo, sizeof(VCH)); + return vote_head(xo); +} + + +static int +vote_load(xo) + XO *xo; +{ + xo_load(xo, sizeof(VCH)); + return vote_body(xo); +} + + +static void +vch_edit(vch, item, echo) + VCH *vch; + int item; /* vlist ¦³´X¶µ */ + int echo; +{ + int num; + char ans[8], buf[80]; + + if (echo == DOECHO) /* ¥u¦³·s¼W®É¤~¯à¨M©w¬O§_¬°½ä½L */ + vch->vgamble = (vget(b_lines - 6, 0, "¬O§_¬°½ä½L(Y/N)¡H[N] ", ans, 3, LCECHO) == 'y') ? '$' : ' '; + + if (vch->vgamble == ' ') + { + sprintf(buf, "½Ð°Ý¨C¤H³Ì¦h¥i§ë´X²¼¡H([1]¡ã%d)¡G", item); + vget(b_lines - 5, 0, buf, ans, 3, DOECHO); + num = atoi(ans); + if (num < 1) + num = 1; + else if (num > item) + num = item; + vch->maxblt = num; + } + else if (echo == DOECHO) /* ¥u¦³·s¼W®É¤~¯à§ïÅܽä½Lªº²¼»ù */ + { + /* ½ä½L´N¥u¯à¿ï¤@¶µ */ + vch->maxblt = 1; + + vget(b_lines - 5, 0, "½Ð°Ý¨C²¼°â»ù¦h¤Ö»È¹ô¡H(100¡ã100000)¡G", ans, 7, DOECHO); + num = atoi(ans); + if (num < 100) + num = 100; + else if (num > 100000) + num = 100000; + vch->price = num; + } + + vget(b_lines - 4, 0, "¥»¶µ§ë²¼¶i¦æ´X¤p®É (¦Ü¤Ö¤@¤p®É)¡H[1] ", ans, 5, DOECHO); + num = atoi(ans); + if (num < 1) + num = 1; + vch->vclose = vch->chrono + num * 3600; + str_stamp(vch->cdate, &vch->vclose); + + if (vch->vgamble == ' ') /* ½ä½L¤@©w±Æ§Ç¡B¤ÎÅã¥Ü¦Ê¤À¤ñ */ + { + vch->vsort = (vget(b_lines - 3, 0, "¶}²¼µ²ªG¬O§_±Æ§Ç(Y/N)¡H[N] ", ans, 3, LCECHO) == 'y') ? 's' : ' '; + vch->vpercent = (vget(b_lines - 2, 0, "¶}²¼µ²ªG¬O§_Åã¥Ü¦Ê¤À¤ñ¨Ò(Y/N)¡H[N] ", ans, 3, LCECHO) == 'y') ? '%' : ' '; + } + else + { + vch->vsort = 's'; + vch->vpercent = '%'; + } + + vch->vprivate = (vget(b_lines - 1, 0, "¬O§_¨î§ë²¼¦W³æ(Y/N)¡H[N] ", ans, 3, LCECHO) == 'y') ? ')' : ' '; +} + + +static int +vlist_edit(vlist) + vitem_t vlist[]; +{ + int item; + char buf[80]; + + clear(); + + outs("½Ð¨Ì§Ç¿é¤J¿ï¶µ (³Ì¦h 32 ¶µ)¡A«ö ENTER µ²§ô¡G"); + + strcpy(buf, " ) "); + for (;;) + { + item = 0; + for (;;) + { + buf[0] = radix32[item]; + if (!vget((item & 15) + 3, (item / 16) * 40, buf, vlist[item], sizeof(vitem_t), GCARRY) || + (++item >= MAX_CHOICES)) + break; + } + if (item && vans("¬O§_«·s¿é¤J¿ï¶µ(Y/N)¡H[N] ") != 'y') + break; + } + return item; +} + + +static int +vlog_seek(fpath) + char *fpath; +{ + VLOG old; + int fd; + int rc = 0; + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + while (read(fd, &old, sizeof(VLOG)) == sizeof(VLOG)) + { + if (!strcmp(old.userid, cuser.userid)) + { + rc = 1; + break; + } + } + close(fd); + } + return rc; +} + + +static int +vote_add(xo) + XO *xo; +{ + VCH vch; + int fd, item; + char *dir, *str, fpath[64], title[TTLEN + 1]; + vitem_t vlist[MAX_CHOICES]; + BRD *brd; + + if (!(bbstate & STAT_BOARD)) + return XO_NONE; + + if (!vget(b_lines, 0, "¼ÐÃD¡G", title, TTLEN + 1, DOECHO)) + return xo->max ? XO_FOOT : vote_body(xo); /* itoc.011125: ¦pªG¨S¦³¥ô¦ó§ë²¼¡An¦^¨ì vote_body() */ + /* return XO_FOOT; */ + + dir = xo->dir; + if ((fd = hdr_stamp(dir, 0, (HDR *) &vch, fpath)) < 0) + { + vmsg("µLªk«Ø¥ß§ë²¼»¡©úÀÉ"); + return XO_FOOT; + } + + close(fd); + vmsg("¶}©l½s¿è [§ë²¼»¡©ú]"); + fd = vedit(fpath, 0); /* Thor.981020: ª`·N³Qtalkªº°ÝÃD */ + if (fd) + { + unlink(fpath); + vmsg("¨ú®ø§ë²¼"); + return vote_head(xo); + } + + strcpy(vch.title, title); + str = strrchr(fpath, '@'); + + /* --------------------------------------------------- */ + /* §ë²¼¿ï¶µÀÉ : Item */ + /* --------------------------------------------------- */ + + memset(vlist, 0, sizeof(vlist)); + item = vlist_edit(vlist); + + *str = 'I'; + if ((fd = open(fpath, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) + { + vmsg("µLªk«Ø¥ß§ë²¼¿ï¶µÀÉ"); + return vote_head(xo); + } + write(fd, vlist, item * sizeof(vitem_t)); + close(fd); + + vch_edit(&vch, item, DOECHO); + + strcpy(vch.owner, cuser.userid); + + brd = bshm->bcache + currbno; + + brd->bvote++; + if (brd->bvote >= 0) + brd->bvote = (vch.vgamble == '$') ? -1 : 1; + vch.bstamp = brd->bstamp; + + rec_add(dir, &vch, sizeof(vch)); + + vmsg("¶}©l§ë²¼¤F¡I"); + return vote_init(xo); +} + + +static int +vote_edit(xo) + XO *xo; +{ + int pos; + VCH *vch, vxx; + char *dir, fpath[64]; + + /* Thor: for ×§ï§ë²¼¿ï¶µ */ + int fd, item; + vitem_t vlist[MAX_CHOICES]; + char *fname; + + if (!(bbstate & STAT_BOARD)) + return XO_NONE; + + pos = xo->pos; + dir = xo->dir; + vch = (VCH *) xo_pool + (pos - xo->top); + + /* Thor: ×§ï§ë²¼¥DÃD */ + + vxx = *vch; + + if (!vget(b_lines, 0, "¼ÐÃD¡G", vxx.title, TTLEN + 1, GCARRY)) + return XO_FOOT; + + fname = vch_fpath(fpath, dir, vch); + vedit(fpath, 0); /* Thor.981020: ª`·N³Qtalkªº°ÝÃD */ + + /* Thor: ×§ï§ë²¼¿ï¶µ */ + + memset(vlist, 0, sizeof(vlist)); + *fname = 'I'; + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + read(fd, vlist, sizeof(vlist)); + close(fd); + } + + item = vlist_edit(vlist); + + if ((fd = open(fpath, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) + { + vmsg("µLªk«Ø¥ß§ë²¼¿ï¶µÀÉ"); + return vote_head(xo); + } + write(fd, vlist, item * sizeof(vitem_t)); + close(fd); + + vch_edit(&vxx, item, GCARRY); + + if (memcmp(&vxx, vch, sizeof(VCH))) + { + if (vans("½T©wn×§ï³o¶µ§ë²¼¶Ü(Y/N)¡H[N] ") == 'y') + { + *vch = vxx; + currchrono = vch->chrono; + rec_put(dir, vch, sizeof(VCH), pos, cmpchrono); + } + } + + return vote_head(xo); +} + + +static int +vote_query(xo) + XO *xo; +{ + char *dir, *fname, fpath[64], buf[80]; + VCH *vch; + int cc, pos; + + if (!(bbstate & STAT_BOARD)) + return XO_NONE; + + pos = xo->pos; + dir = xo->dir; + vch = (VCH *) xo_pool + (pos - xo->top); + + fname = vch_fpath(fpath, dir, vch); + more(fpath, (char *) -1); + + *fname = 'G'; + sprintf(buf, "¦@¦³ %d ¤H°Ñ¥[§ë²¼¡A½T©wn±N¶}²¼®É¶¡§ï´Á(Y/N)¡H[N] ", rec_num(fpath, sizeof(VLOG))); + if (vans(buf) == 'y') + { + vget(b_lines, 0, "½Ð§ó§ï¶}²¼®É¶¡(-n´£«en¤p®É/+m©µ«ám¤p®É/0¤£§ï)¡G", buf, 5, DOECHO); + if (cc = atoi(buf)) + { + vch->vclose = vch->vclose + cc * 3600; + str_stamp(vch->cdate, &vch->vclose); + currchrono = vch->chrono; + rec_put(dir, vch, sizeof(VCH), pos, cmpchrono); + } + } + + return vote_head(xo); +} + + +static int +vfyvch(vch, pos) + VCH *vch; + int pos; +{ + return Tagger(vch->chrono, pos, TAG_NIN); +} + + +static void +delvch(xo, vch) + XO *xo; + VCH *vch; +{ + int fd; + char fpath[64], buf[64], *fname; + char *list = "@IOLGZ"; /* itoc.µù¸Ñ: ²M vote file */ + VLOG vlog; + PAYCHECK paycheck; + + fname = vch_fpath(fpath, xo->dir, vch); + + if (vch->vgamble == '$') /* itoc.050313: ¦pªG¬O½ä½L³Q§R°£¡A¨º»òn°h½äª÷ */ + { + *fname = 'G'; + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + memset(&paycheck, 0, sizeof(PAYCHECK)); + time(&paycheck.tissue); + sprintf(paycheck.reason, "[°h´Ú] %s", currboard); + + while (read(fd, &vlog, sizeof(VLOG)) == sizeof(VLOG)) + { + paycheck.money = vlog.numvotes * vch->price; + usr_fpath(buf, vlog.userid, FN_PAYCHECK); + rec_add(buf, &paycheck, sizeof(PAYCHECK)); + } + } + close(fd); + } + + while (*fname = *list++) + unlink(fpath); /* Thor: ½T©w¦W¦r´N¬å */ +} + + + +static int +vote_delete(xo) + XO *xo; +{ + int pos; + VCH *vch; + + if (!(bbstate & STAT_BOARD)) + return XO_NONE; + + pos = xo->pos; + vch = (VCH *) xo_pool + (pos - xo->top); + + if (vans(msg_del_ny) == 'y') + { + delvch(xo, vch); + + currchrono = vch->chrono; + rec_del(xo->dir, sizeof(VCH), pos, cmpchrono); + return vote_load(xo); + } + + return XO_FOOT; +} + + +static int +vote_rangedel(xo) + XO *xo; +{ + if (!(bbstate & STAT_BOARD)) + return XO_NONE; + + return xo_rangedel(xo, sizeof(VCH), NULL, delvch); +} + + +static int +vote_prune(xo) + XO *xo; +{ + if (!(bbstate & STAT_BOARD)) + return XO_NONE; + + return xo_prune(xo, sizeof(VCH), vfyvch, delvch); +} + + +static int +vote_pal(xo) /* itoc.020117: ½s¿è¨î§ë²¼¦W³æ */ + XO *xo; +{ + char *fname, fpath[64]; + VCH *vch; + XO *xt; + + if (!(bbstate & STAT_BOARD)) + return XO_NONE; + + vch = (VCH *) xo_pool + (xo->pos - xo->top); + + if (vch->vprivate != ')') + return XO_NONE; + + fname = vch_fpath(fpath, xo->dir, vch); + *fname = 'L'; + + xz[XZ_PAL - XO_ZONE].xo = xt = xo_new(fpath); + xt->key = PALTYPE_VOTE; + xover(XZ_PAL); /* Thor: ¶ixover«e, pal_xo ¤@©wn ready */ + + free(xt); + return vote_init(xo); +} + + +static int +vote_join(xo) + XO *xo; +{ + VCH *vch, vbuf; + VLOG vlog; + int count, fd; + usint choice; + char *dir, *fname, fpath[64], buf[80], ans[4], *slist[MAX_CHOICES]; + vitem_t vlist[MAX_CHOICES]; + + if (HAS_STATUS(STATUS_COINLOCK)) + { + vmsg(msg_coinlock); + return XO_FOOT; + } + + vch = (VCH *) xo_pool + (xo->pos - xo->top); + + /* --------------------------------------------------- */ + /* Àˬd¬O§_¤w¸gµ²§ô§ë²¼ */ + /* --------------------------------------------------- */ + + if (time(0) > vch->vclose) + { + vmsg("§ë²¼¤w¸gºI¤î¤F¡A½ÐÀRÔ¶}²¼"); + return XO_FOOT; + } + + /* --------------------------------------------------- */ + /* Àˬd¬O§_¦³¨¬°÷¿ú */ + /* --------------------------------------------------- */ + + if (vch->vgamble == '$') + { + if (cuser.money < vch->price) + { + vmsg("±zªº¿ú¤£°÷°Ñ¥[½ä½L"); + return XO_FOOT; + } + if (vans("¬O§_°Ñ¥[½ä½L(Y/N)¡H[N] ") != 'y') + return XO_FOOT; + } + + /* --------------------------------------------------- */ + /* §ë²¼ÀÉ®× */ + /* --------------------------------------------------- */ + + dir = xo->dir; + fname = vch_fpath(fpath, dir, vch); + + /* --------------------------------------------------- */ + /* Àˬd¬O§_¤w¸g§ë¹L²¼ */ + /* --------------------------------------------------- */ + + if (vch->vgamble == ' ') /* itoc.031101: ½ä½L¥i¥H¤@ª½¤Uª` */ + { + *fname = 'G'; + if (vlog_seek(fpath)) + { + vmsg("±z¤w¸g§ë¹L²¼¤F¡I"); + return XO_FOOT; + } + if (vans("¬O§_°Ñ¥[§ë²¼(Y/N)¡H[N] ") != 'y') + return XO_FOOT; + } + + /* --------------------------------------------------- */ + /* Àˬd¬O§_¦b§ë²¼¦W³æ¤¤ */ + /* --------------------------------------------------- */ + + if (vch->vprivate == ')') /* itoc.020117: ¨p¤H§ë²¼ */ + { + *fname = 'L'; + + if (!pal_find(fpath, cuser.userno) && + !(bbstate & STAT_BOARD)) /* ¥Ñ©ó¨Ã¤£¯à§â¦Û¤v¥[¤JªB¤Í¦W³æ¡A©Ò¥Hn¦hÀˬd¬O§_¬°ªO¥D */ + { + vmsg("±z¨S¦³¨üÁÜ¥»¦¸¨p¤H§ë²¼¡I"); + return XO_FOOT; + } + } + + /* --------------------------------------------------- */ + /* ¶}©l§ë²¼¡AÅã¥Ü§ë²¼»¡©ú */ + /* --------------------------------------------------- */ + + *fname = '@'; + more(fpath, NULL); + + /* --------------------------------------------------- */ + /* ¸ü¤J§ë²¼¿ï¶µÀÉ */ + /* --------------------------------------------------- */ + + *fname = 'I'; + if ((fd = open(fpath, O_RDONLY)) < 0) + { + vmsg("µLªkŪ¨ú§ë²¼¿ï¶µÀÉ"); + return vote_head(xo); + } + count = read(fd, vlist, sizeof(vlist)) / sizeof(vitem_t); + close(fd); + + for (fd = 0; fd < count; fd++) + slist[fd] = (char *) &vlist[fd]; + + /* --------------------------------------------------- */ + /* ¶i¦æ§ë²¼ */ + /* --------------------------------------------------- */ + + choice = 0; + sprintf(buf, "§ë¤U¯«¸tªº %d ²¼", vch->maxblt); /* Thor: Åã¥Ü³Ì¦h´X²¼ */ + vs_bar(buf); + outs("§ë²¼¥DÃD¡G"); + for (;;) + { + choice = bitset(choice, count, vch->maxblt, vch->title, slist); + + if (vch->vgamble == ' ') /* ¤@¯ë§ë²¼¤~¯à¼g·N¨£ */ + vget(b_lines - 1, 0, "§Ú¦³¸Ün»¡¡G", buf, 60, DOECHO); + + fd = vans("§ë²¼ (Y)½T©w (N)«¨Ó (Q)¨ú®ø¡H[N] "); + + if (fd == 'q') + return vote_head(xo); + + if ((fd == 'y') && (vch->vgamble == ' ' || choice)) /* Y¬O½ä½L«h¤@©wn¿ï */ + break; + } + + /* --------------------------------------------------- */ + /* °O¿ýµ²ªG¡G¤@²¼¤]¥¼§ëªº±¡ªp ==> ¬Û·í©ó§ë¼o²¼ */ + /* --------------------------------------------------- */ + + if (vch->vgamble == '$') + { + /* ½ä½L¥i¥H¶R¤J¦h±i */ + for (;;) + { + sprintf(buf, "¨C±i½ä²¼ %d »È¹ô¡A½Ð°Ýn¶R´X±i¡H[1] ", vch->price); + vget(b_lines, 0, buf, ans, 3, DOECHO); /* ³Ì¦h¶R 99 ±i¡AÁ×§K·¸¦ì */ + + if (time(0) > vch->vclose) /* ¦]¬°¦³Ó vget¡A©Ò¥HÁÙn¦AÀˬd¤@¦¸ */ + { + vmsg("§ë²¼¤w¸gºI¤î¤F¡A½ÐÀRÔ¶}²¼"); + return vote_head(xo); + } + + if ((count = atoi(ans)) < 1) + count = 1; + fd = count * vch->price; + if (cuser.money >= fd) + break; + } + } + else + { + /* ¤@¯ë§ë²¼´N¬O¤@±i²¼ */ + count = 1; + } + + /* ½T©w§ë²¼©|¥¼ºI¤î */ + /* itoc.050514: ¦]¬°ªO¥D¥i¥H§ïÅܶ}²¼®É¶¡¡A¬°¤FÁ×§K¨Ï¥ÎªÌ·|Àt¦b vget() ©Î¬O + §Q¥Î xo_pool[] ¥¼¦P¨B¨Ó³WÁ× time(0) > vclose ªºÀˬd¡A©Ò¥H´N±o«·s¸ü¤J VCH */ + if (rec_get(dir, &vbuf, sizeof(VCH), xo->pos) || vch->chrono != vch->chrono || time(0) > vbuf.vclose) + { + vmsg("§ë²¼¤w¸gºI¤î¤F¡A½ÐÀRÔ¶}²¼"); + return vote_init(xo); + } + + if (vch->vgamble == '$') + { + cuser.money -= fd; /* fd ¬On¥Iªº½äª÷ */ + } + else if (*buf) /* ¤@¯ë§ë²¼¤~¯à¼g¤J¨Ï¥ÎªÌ·N¨£ */ + { + FILE *fp; + + *fname = 'O'; + if (fp = fopen(fpath, "a")) + { + fprintf(fp, "¡E%-12s¡G%s\n", cuser.userid, buf); + fclose(fp); + } + } + + /* ¥[¤J°O¿ýÀÉ */ + memset(&vlog, 0, sizeof(VLOG)); + strcpy(vlog.userid, cuser.userid); + vlog.numvotes = count; + vlog.choice = choice; + *fname = 'G'; + rec_add(fpath, &vlog, sizeof(VLOG)); + + vmsg("§ë²¼§¹¦¨¡I"); + return vote_head(xo); +} + + +struct Tchoice +{ + int count; + vitem_t vitem; +}; + + +static int +TchoiceCompare(i, j) + struct Tchoice *i, *j; +{ + return j->count - i->count; +} + + +static char * /* NULL:¥¢±Ñ(ÁÙ¨S¦³¤H§ë²¼) */ +draw_vote(fpath, folder, vch, preview) /* itoc.030906: §ë²¼µ²ªG (»P account.c:draw_vote() ®æ¦¡¬Û¦P) */ + char *fpath; + char *folder; + VCH *vch; + int preview; /* 1:¹wÄý 0:¶}²¼ */ +{ + struct Tchoice choice[MAX_CHOICES]; + FILE *fp; + char *fname; + int total, items, num, fd, ticket, bollt; + VLOG vlog; + + fname = vch_fpath(fpath, folder, vch); + + /* vote item */ + + *fname = 'I'; + + items = 0; + if (fp = fopen(fpath, "r")) + { + while (fread(&choice[items].vitem, sizeof(vitem_t), 1, fp) == 1) + { + choice[items].count = 0; + items++; + } + fclose(fp); + } + + if (items == 0) + return NULL; + + /* ²Öp§ë²¼µ²ªG */ + + *fname = 'G'; + bollt = 0; /* Thor: Á`²¼¼ÆÂk¹s */ + total = 0; + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + while (read(fd, &vlog, sizeof(VLOG)) == sizeof(VLOG)) + { + for (ticket = vlog.choice, num = 0; ticket && num < items; ticket >>= 1, num++) + { + if (ticket & 1) + { + choice[num].count += vlog.numvotes; + bollt += vlog.numvotes; + } + } + total++; + } + close(fd); + } + + /* ²£¥Í¶}²¼µ²ªG */ + + *fname = 'Z'; + if (!(fp = fopen(fpath, "w"))) + return NULL; + + fprintf(fp, "\n\033[1;34m%s\033[m\n\n" + "\033[1;32m¡» [%s] ¬ÝªO§ë²¼¡G%s\033[m\n\nÁ|¿ìªO¥D¡G%s\n\nÁ|¿ì¤é´Á¡G%s\n\n", + msg_seperator, currboard, vch->title, vch->owner, Btime(&vch->chrono)); + fprintf(fp, "¶}²¼¤é´Á¡G%s\n\n\033[1;32m¡» §ë²¼¥DÃD¡G\033[m\n\n", Btime(&vch->vclose)); + + *fname = '@'; + f_suck(fp, fpath); + + fprintf(fp, "\n\033[1;32m¡» §ë²¼µ²ªG¡G¨C¤H¥i§ë %d ²¼¡A¦@ %d ¤H°Ñ¥[¡A§ë¥X %d ²¼\033[m\n\n", + vch->maxblt, total, bollt); + + if (vch->vsort == 's') + qsort(choice, items, sizeof(struct Tchoice), TchoiceCompare); + + if (vch->vpercent == '%') + fd = BMAX(1, bollt); + else + fd = 0; + + if (preview && vch->vgamble == ' ') /* ¥u¦³¹wÄý½ä½L¤~»ÝnÅã¥Ü½ß²v */ + preview = 0; + + for (num = 0; num < items; num++) + { + ticket = choice[num].count; + if (preview) /* Åã¥Ü¥[¶R¤@±i®Éªº½ß²v */ + fprintf(fp, " %-36s%5d ²¼ (%4.1f%%) ½ß²v 1:%.3f\n", &choice[num].vitem, ticket, 100.0 * ticket / fd, 0.9 * (bollt + 1) / (ticket + 1)); + else if (fd) + fprintf(fp, " %-36s%5d ²¼ (%4.1f%%)\n", &choice[num].vitem, ticket, 100.0 * ticket / fd); + else + fprintf(fp, " %-36s%5d ²¼\n", &choice[num].vitem, ticket); + } + + /* other opinions */ + + *fname = 'O'; + fputs("\n\033[1;32m¡» §Ú¦³¸Ün»¡¡G\033[m\n\n", fp); + f_suck(fp, fpath); + fputs("\n", fp); + fclose(fp); + + /* ³Ì«á¶Ç¦^ªº fpath §Y¬°§ë²¼µ²ªGÀÉ */ + *fname = 'Z'; + return fname; +} + + +static int +vote_view(xo) + XO *xo; +{ + char fpath[64]; + VCH *vch; + + vch = (VCH *) xo_pool + (xo->pos - xo->top); + + if (bbstate & STAT_BOARD || vch->vgamble == '$') + { + if (draw_vote(fpath, xo->dir, vch, 1)) + { + more(fpath, NULL); + unlink(fpath); + return vote_head(xo); + } + + vmsg("¥Ø«e©|¥¼¦³¤H§ë²¼"); + return XO_FOOT; + } + + return XO_NONE; +} + + +static void +keeplog(fnlog, board, title) + char *fnlog; + char *board; + char *title; +{ + HDR hdr; + char folder[64], fpath[64]; + FILE *fp; + + if (!dashf(fnlog)) /* Kudo.010804: Àɮ׬OªÅªº´N¤£ keeplog */ + return; + + brd_fpath(folder, board, fn_dir); + + if (fp = fdopen(hdr_stamp(folder, 'A', &hdr, fpath), "w")) + { + fprintf(fp, "§@ªÌ: %s (%s)\n¼ÐÃD: %s\n®É¶¡: %s\n\n", + str_sysop, SYSOPNICK, title, Btime(&hdr.chrono)); + f_suck(fp, fnlog); + fclose(fp); + + strcpy(hdr.title, title); + strcpy(hdr.owner, str_sysop); + rec_bot(folder, &hdr, sizeof(HDR)); + + btime_update(brd_bno(board)); + } +} + + +static void +vlog_pay(fpath, choice, fp, vch)/* ½ß¿úµ¹©ã¹ïªº¨Ï¥ÎªÌ */ + char *fpath; /* °O¿ýÀɸô®| */ + usint choice; /* ¥¿½Tªºµª®× */ + FILE *fp; /* ¼g¤JªºÀÉ®× */ + VCH *vch; +{ + int fd; + int correct, bollt; /* ©ã¹ï/¥þ³¡ ªº²¼¼Æ */ + int single, money; + char buf[64]; + VLOG vlog; + PAYCHECK paycheck; + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + /* ²Ä¤@°éºâ¥X½ß²v */ + correct = bollt = 0; + while (read(fd, &vlog, sizeof(VLOG)) == sizeof(VLOG)) + { + bollt += vlog.numvotes; + if (vlog.choice == choice) + correct += vlog.numvotes; + } + + /* µ¹ªO¥D©âÀY 1% */ + money = (INT_MAX / vch->price) * 100; /* BioStar.050626: Á×§K·¸¦ì */ + money = (bollt > money) ? INT_MAX : vch->price / 100 * bollt; + fprintf(fp, "ªO¥D %s ©âÀY¡A¥iÀò±o %d »È¹ô\n", vch->owner, money); + + memset(&paycheck, 0, sizeof(PAYCHECK)); + time(&paycheck.tissue); + paycheck.money = money; + sprintf(paycheck.reason, "[©âÀY] %s", currboard); + usr_fpath(buf, vch->owner, FN_PAYCHECK); + rec_add(buf, &paycheck, sizeof(PAYCHECK)); + + if (correct) /* ¦pªG¨S¤H©ã¤¤¡A´N¤£»Ýnµo¿ú */ + { + /* µo¼úª÷¡A¨t²Î©â 10% ªºµ| */ + single = (float) vch->price * 0.9 * bollt / correct; + fprintf(fp, "¨C±i¥iÀò %d »È¹ô¡A©ã¹ïªº¨Ï¥ÎªÌ¦³¡G\n", single); + + /* ²Ä¤G°é¶}©lµo¿ú */ + lseek(fd, (off_t) 0, SEEK_SET); + while (read(fd, &vlog, sizeof(VLOG)) == sizeof(VLOG)) + { + if (vlog.choice == choice) + { + money = INT_MAX / single; /* BioStar.050626: Á×§K·¸¦ì */ + money = (vlog.numvotes > money) ? INT_MAX : single * vlog.numvotes; + fprintf(fp, "%s ¶R¤F %d ±i¡A¦@¥iÀò±o %d »È¹ô\n", vlog.userid, vlog.numvotes, money); + + paycheck.money = money; + sprintf(paycheck.reason, "[½ä½L] %s", currboard); + usr_fpath(buf, vlog.userid, FN_PAYCHECK); + rec_add(buf, &paycheck, sizeof(PAYCHECK)); + } + } + } + + close(fd); + } +} + + +static int +vote_open(xo) + XO *xo; +{ + int pos, fd, count; + char *dir, *fname, fpath[64], buf[80]; + usint choice; + char *slist[MAX_CHOICES]; + vitem_t vlist[MAX_CHOICES]; + VCH *vch; + FILE *fp; + + if (!(bbstate & STAT_BOARD)) + return XO_NONE; + + pos = xo->pos; + vch = (VCH *) xo_pool + (pos - xo->top); + + if (time(NULL) < vch->vclose) + { + if (vans("©|¥¼¨ìì©w¶}²¼®É¶¡¡A½T©wn´£¦¶}²¼(Y/N)¡H[N] ") != 'y') + return XO_FOOT; + } + + dir = xo->dir; + + /* §ë²¼µ²ªG */ + + if (!(fname = draw_vote(fpath, dir, vch, 0))) + { + vmsg("¥Ø«e©|¥¼¦³¤H§ë²¼"); + return XO_FOOT; + } + + if (vch->vgamble == '$') /* ½ä½L */ + { + /* ªO¥D¿é¤Jµ²ªG¡A¨Ã¼g¤J§ë²¼µ²ªG */ + while (!vget(b_lines, 0, "½Ð¿é¤J¥¿½Tµª®×¡G", buf, 60, DOECHO)) + ; + + /* ¸ü¤J§ë²¼¿ï¶µÀÉ */ + *fname = 'I'; + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + count = read(fd, vlist, sizeof(vlist)) / sizeof(vitem_t); + close(fd); + + for (fd = 0; fd < count; fd++) + slist[fd] = (char *) &vlist[fd]; + + /* ªO¥D¿ï¥X¥¿½Tµª®× */ + choice = 0; + vs_bar("¿ï¾Ü¥¿½Tµª®×"); + outs("§ë²¼¥DÃD¡G"); + for (;;) + { + choice = bitset(choice, count, vch->maxblt, vch->title, slist); + + fd = vans("¶}²¼ (Y)½T©w (N)«¨Ó (Q)¨ú®ø¡H[N] "); + + if (fd == 'q') + { + *fname = 'Z'; + unlink(fpath); + return vote_head(xo); + } + + if (fd == 'y' && choice) /* Y¬O½ä½L«h¤@©wn¿ï */ + break; + } + + /* ¶}©lµo¿ú */ + *fname = 'Z'; + if (fp = fopen(fpath, "a")) + { + fprintf(fp, "ªO¥D¤½§Gµª®×¡G%s\n\n", buf); + + *fname = 'G'; + vlog_pay(fpath, choice, fp, vch); + + fputs("\n", fp); + fclose(fp); + } + + /* ¶}²¼µ²ªG */ + *fname = 'Z'; + } + } + + /* ±N¶}²¼µ²ªG post ¨ì [BN_RECORD] »P ¥»¬ÝªO */ + + if (!(currbattr & BRD_NOVOTE)) + { + sprintf(buf, "[°O¿ý] %s <<¬ÝªO¿ï±¡³ø¾É>>", currboard); + keeplog(fpath, BN_RECORD, buf); + } + + keeplog(fpath, currboard, "[°O¿ý] ¿ï±¡³ø¾É"); + + /* §ë²¼µ²ªGªþ¥[¨ì @vote */ + + setdirpath(buf, dir, "@/@vote"); + if (fp = fopen(fpath, "a")) + { + f_suck(fp, buf); + fclose(fp); + rename(fpath, buf); + } + + /* ¶}§¹²¼´N§R°£ */ + vch->vgamble = ' '; /* ¥O¬°«D½ä½L¡A¦p¦¹¦b delvch ¸Ì±´N¤£·|°h½äª÷ */ + delvch(xo, vch); + + currchrono = vch->chrono; + rec_del(dir, sizeof(VCH), pos, cmpchrono); + + vmsg("¶}²¼§¹²¦"); + return vote_init(xo); +} + + +static int +vote_tag(xo) + XO *xo; +{ + VCH *vch; + int tag, pos, cur; + + pos = xo->pos; + cur = pos - xo->top; + vch = (VCH *) xo_pool + cur; + + if (tag = Tagger(vch->chrono, pos, TAG_TOGGLE)) + { + move(3 + cur, 6); + outc(tag > 0 ? '*' : ' '); + } + + /* return XO_NONE; */ + return xo->pos + 1 + XO_MOVE; /* lkchu.981201: ¸õ¦Ü¤U¤@¶µ */ +} + + +static int +vote_help(xo) + XO *xo; +{ + xo_help("vote"); + return vote_head(xo); +} + + +static KeyFunc vote_cb[] = +{ + XO_INIT, vote_init, + XO_LOAD, vote_load, + XO_HEAD, vote_head, + XO_BODY, vote_body, + + 'r', vote_join, /* itoc.010901: «ö¥kÁä¤ñ¸û¤è«K */ + 'v', vote_join, + 'R', vote_result, + + 'V', vote_view, + 'E', vote_edit, + 'o', vote_pal, + 'd', vote_delete, + 'D', vote_rangedel, + 't', vote_tag, + 'b', vote_open, + + Ctrl('D'), vote_prune, + Ctrl('G'), vote_pal, + Ctrl('P'), vote_add, + Ctrl('Q'), vote_query, + + 'h', vote_help +}; + + +int +XoVote(xo) + XO *xo; +{ + char fpath[64]; + + /* ¦³ post Åv§Qªº¤~¯à°Ñ¥[§ë²¼ */ + /* ¦Ó¥BnÁ×§K guest ¦b sysop ªO§ë²¼ */ + + if (!(bbstate & STAT_POST) || !cuser.userlevel) + return XO_NONE; + + setdirpath(fpath, xo->dir, FN_VCH); + if (!(bbstate & STAT_BOARD) && !rec_num(fpath, sizeof(VCH))) + { + vmsg("¥Ø«e¨S¦³§ë²¼Á|¦æ"); + return XO_FOOT; + } + + xz[XZ_VOTE - XO_ZONE].xo = xo = xo_new(fpath); + xz[XZ_VOTE - XO_ZONE].cb = vote_cb; + xover(XZ_VOTE); + free(xo); + + return XO_INIT; +} + + +int +vote_all() /* itoc.010414: §ë²¼¤¤¤ß */ +{ + typedef struct + { + char brdname[BNLEN + 1]; + char class[BCLEN + 1]; + char title[BTLEN + 1]; + char BM[BMLEN + 1]; + char bvote; + } vbrd_t; + + extern char brd_bits[]; + char *str; + char fpath[64]; + int num, pageno, pagemax, redraw; + int ch, cur; + BRD *bhead, *btail; + XO *xo; + vbrd_t vbrd[MAXBOARD], *vb; + + bhead = bshm->bcache; + btail = bhead + bshm->number; + cur = 0; + num = 0; + + do + { + str = &brd_bits[cur]; + ch = *str; + if (bhead->bvote && (ch & BRD_W_BIT)) + { + vb = vbrd + num; + strcpy(vb->brdname, bhead->brdname); + strcpy(vb->class, bhead->class); + strcpy(vb->title, bhead->title); + strcpy(vb->BM, bhead->BM); + vb->bvote = bhead->bvote; + num++; + } + cur++; + } while (++bhead < btail); + + if (!num) + { + vmsg("¥Ø«e¯¸¤º¨Ã¨S¦³¥ô¦ó§ë²¼"); + return XEASY; + } + + num--; + pagemax = num / XO_TALL; + pageno = 0; + cur = 0; + redraw = 1; + + do + { + if (redraw) + { + /* itoc.µù¸Ñ: ºÉ¶q°µ±o¹³ xover ®æ¦¡ */ + vs_head("§ë²¼¤¤¤ß", str_site); + prints(NECKER_VOTEALL, d_cols >> 1, "", d_cols - (d_cols >> 1), ""); + + redraw = pageno * XO_TALL; /* ɥΠredraw */ + ch = BMIN(num, redraw + XO_TALL - 1); + move(3, 0); + do + { + vb = vbrd + redraw; + /* itoc.010909: ªO¦W¤Óªøªº§R±¼¡B¥[¤ÀÃþÃC¦â¡C°²³] BCLEN = 4 */ + prints("%6d %-13s\033[1;3%dm%-5s\033[m%s %-*.*s %.*s\n", + redraw + 1, vb->brdname, + vb->class[3] & 7, vb->class, + vb->bvote > 0 ? ICON_VOTED_BRD : ICON_GAMBLED_BRD, + (d_cols >> 1) + 34, (d_cols >> 1) + 33, vb->title, d_cols - (d_cols >> 1) + 13, vb->BM); + + redraw++; + } while (redraw <= ch); + + outf(FEETER_VOTEALL); + move(3 + cur, 0); + outc('>'); + redraw = 0; + } + + switch (ch = vkey()) + { + case KEY_RIGHT: + case '\n': + case ' ': + case 'r': + vb = vbrd + (cur + pageno * XO_TALL); + + /* itoc.060324: µ¥¦P¶i¤J·sªº¬ÝªO¡AXoPost() ¦³°µªº¨Æ¡A³o¸Ì´X¥G³£n°µ */ + if (!vb->brdname[0]) /* ¤w§R°£ªº¬ÝªO */ + break; + + redraw = brd_bno(vb->brdname); /* ɥΠredraw */ + ch = brd_bits[redraw]; + + /* ³B²zÅv */ + if (ch & BRD_X_BIT) + bbstate |= STAT_BOARD; + else + bbstate &= ~STAT_BOARD; + + /* itoc.050613.µù¸Ñ: ¤H®ðªº´î¤Ö¤£¬O¦bÂ÷¶}¬ÝªO®É¡A¦Ó¬O¦b¶i¤J·sªº¬ÝªO©Î¬OÂ÷¯¸®É¡A + ³o¬O¬°¤FÁ×§K switch ¸õ¬ÝªO·|ºâ¿ù¤H®ð */ + if (currbno >= 0) + bshm->mantime[currbno]--; /* °h¥X¤W¤@ÓªO */ + bshm->mantime[redraw]++; /* ¶i¤J·sªºªO */ + + currbno = redraw; + bhead = bshm->bcache + currbno; + currbattr = bhead->battr; + strcpy(currboard, bhead->brdname); + str = bhead->BM; + sprintf(currBM, "ªO¥D¡G%s", *str <= ' ' ? "¼x¨D¤¤" : str); +#ifdef HAVE_BRDMATE + strcpy(cutmp->reading, currboard); +#endif + + sprintf(fpath, "brd/%s/%s", currboard, FN_VCH); + xz[XZ_VOTE - XO_ZONE].xo = xo = xo_new(fpath); + xz[XZ_VOTE - XO_ZONE].cb = vote_cb; + xover(XZ_VOTE); + free(xo); + redraw = 1; + break; + + default: + ch = xo_cursor(ch, pagemax, num, &pageno, &cur, &redraw); + break; + } + } while (ch != 'q'); + + return 0; +} diff --git a/so/xyz.c b/so/xyz.c new file mode 100644 index 0000000..23fdd29 --- /dev/null +++ b/so/xyz.c @@ -0,0 +1,213 @@ +/*-------------------------------------------------------*/ +/* xyz.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : Âø¤CÂø¤Kªº¥~±¾ */ +/* create : 01/03/01 */ +/* update : / / */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#ifdef HAVE_TIP + +/* ----------------------------------------------------- */ +/* ¨C¤é¤p¯µ³Z */ +/* ----------------------------------------------------- */ + +int +x_tip() +{ + int i, j; + char msg[128]; + FILE *fp; + + if (!(fp = fopen(FN_ETC_TIP, "r"))) + return XEASY; + + fgets(msg, 128, fp); + j = atoi(msg); /* ²Ä¤@¦æ°O¿ýÁ`½g¼Æ */ + i = time(0) % j + 1; + j = 0; + + while (j < i) /* ¨ú²Ä i Ó tip */ + { + fgets(msg, 128, fp); + if (msg[0] == '#') + j++; + } + + move(12, 0); + clrtobot(); + fgets(msg, 128, fp); + prints("\033[1;36m¨C¤é¤p¯¦³Z¡G\033[m\n"); + prints(" %s", msg); + fgets(msg, 128, fp); + prints(" %s", msg); + vmsg(NULL); + fclose(fp); + return 0; +} +#endif /* HAVE_TIP */ + + +#ifdef HAVE_LOVELETTER + +/* ----------------------------------------------------- */ +/* ±¡®Ñ²£¥Í¾¹ */ +/* ----------------------------------------------------- */ + +int +x_loveletter() +{ + FILE *fp; + int start_show; /* 1:¶}©l¨q */ + int style; /* 0:¶}ÀY 1:¥¿¤å 2:µ²§À */ + int line; + char buf[128]; + char header[3][5] = {"head", "body", "foot"}; /* ¶}ÀY¡B¥¿¤å¡Bµ²§À */ + int num[3]; + + /* etc/loveletter «e¬q¬O#head ¤¤¬q¬O#body «á¬q¬O#foot */ + /* ¦æ¼Æ¤W¡G#head¤¦æ #body¤K¦æ #foot¤¦æ */ + + if (!(fp = fopen(FN_ETC_LOVELETTER, "r"))) + return XEASY; + + /* «e¤T¦æ°O¿ý½g¼Æ */ + fgets(buf, 128, fp); + num[0] = atoi(buf + 5); + num[1] = atoi(buf + 5); + num[2] = atoi(buf + 5); + + /* ¨M©wn¿ï²Ä´X½g */ + line = time(0); + num[0] = line % num[0]; + num[1] = (line >> 1) % num[1]; + num[2] = (line >> 2) % num[2]; + + vs_bar("±¡®Ñ²£¥Í¾¹"); + + start_show = style = line = 0; + + while (fgets(buf, 128, fp)) + { + if (*buf == '#') + { + if (!strncmp(buf + 1, header[style], 4)) /* header[] ªø«×³£¬O 5 bytes */ + num[style]--; + + if (num[style] < 0) /* ¤w¸g fget ¨ìn¿ïªº³o½g¤F */ + { + outc('\n'); + start_show = 1; + style++; + } + else + { + start_show = 0; + } + continue; + } + + if (start_show) + { + if (line >= (b_lines - 5)) /* ¶W¹L¿Ã¹õ¤j¤p¤F */ + break; + + outs(buf); + line++; + } + } + + fclose(fp); + vmsg(NULL); + + return 0; +} +#endif /* HAVE_LOVELETTER */ + + +/* ----------------------------------------------------- */ +/* ±K½X§Ñ°O¡A«³]±K½X */ +/* ----------------------------------------------------- */ + + +int +x_password() +{ + int i; + ACCT acct; + FILE *fp; + char fpath[80], email[60], passwd[PSWDLEN + 1]; + time_t now; + + vmsg("·í¨ä¥L¨Ï¥ÎªÌ§Ñ°O±K½X®É¡A«°e·s±K½X¦Ü¸Ó¨Ï¥ÎªÌªº«H½c"); + + if (acct_get(msg_uid, &acct) > 0) + { + time(&now); + + if (acct.lastlogin > now - 86400 * 10) + { + vmsg("¸Ó¨Ï¥ÎªÌ¥²¶·¤Q¤Ñ¥H¤W¥¼¤W¯¸¤è¥i«°e±K½X"); + return 0; + } + + vget(b_lines - 2, 0, "½Ð¿é¤J»{ÃҮɪº Email¡G", email, 40, DOECHO); + + if (str_cmp(acct.email, email)) + { + vmsg("³o¤£¬O¸Ó¨Ï¥ÎªÌ»{ÃҮɥΪº Email"); + return 0; + } + + if (not_addr(email) || !mail_external(email)) + { + vmsg(err_email); + return 0; + } + + vget(b_lines - 1, 0, "½Ð¿é¤J¯u¹ê©m¦W¡G", fpath, RNLEN + 1, DOECHO); + if (strcmp(acct.realname, fpath)) + { + vmsg("³o¤£¬O¸Ó¨Ï¥ÎªÌªº¯u¹ê©m¦W"); + return 0; + } + + if (vans("¸ê®Æ¥¿½T¡A½Ð½T»{¬O§_²£¥Í·s±K½X(Y/N)¡H[N] ") != 'y') + return 0; + + sprintf(fpath, "%s §ï¤F %s ªº±K½X", cuser.userid, acct.userid); + blog("PASSWD", fpath); + + /* ¶Ã¼Æ²£¥Í A~Z ²Õ¦Xªº±K½X¤K½X */ + for (i = 0; i < PSWDLEN; i++) + passwd[i] = rnd(26) + 'A'; + passwd[PSWDLEN] = '\0'; + + /* «·s acct_load ¸ü¤J¤@¦¸¡AÁ×§K¹ï¤è¦b vans() ®Éµn¤J·|¦³¬~¿úªº®ÄªG */ + if (acct_load(&acct, acct.userid) >= 0) + { + str_ncpy(acct.passwd, genpasswd(passwd), PASSLEN + 1); + acct_save(&acct); + } + + sprintf(fpath, "tmp/sendpass.%s", cuser.userid); + if (fp = fopen(fpath, "w")) + { + fprintf(fp, "%s ¬°±z¥Ó½Ð¤F·s±K½X\n\n", cuser.userid); + fprintf(fp, BBSNAME "ID : %s\n\n", acct.userid); + fprintf(fp, BBSNAME "·s±K½X : %s\n", passwd); + fclose(fp); + + bsmtp(fpath, BBSNAME "·s±K½X", email, 0); + unlink(fpath); + + vmsg("·s±K½X¤w±H¨ì¸Ó»{ÃÒ«H½c"); + } + } + + return 0; +} diff --git a/util/Makefile b/util/Makefile new file mode 100644 index 0000000..f191168 --- /dev/null +++ b/util/Makefile @@ -0,0 +1,59 @@ +# ------------------------------------------------------- # +# util/Makefile ( NTHU CS MapleBBS Ver 3.10 ) # +# ------------------------------------------------------- # +# target : Makefile for ±H«H¡B²Îp¡B³Æ¥÷¡B¨t²ÎºûÅ@¤u¨ã # +# create : 95/03/29 # +# update : 95/12/15 # +# ------------------------------------------------------- # + + +# ------------------------------------------------------ # +# ¤U¦Cªº make rules ¤£»Ý×§ï # +# ------------------------------------------------------ # + + +EXE = account acl-sort bbsmail bquota brdmail camera counter changeperm \ + gem-index give_paycheck hdr-dump mailpost outgo poststat reaper redir setperm setusr \ + showACCT showBRD showDIR showperm showUSR topgem topsong topusr + + +all: + @echo "Please enter 'make sys-type', " + @echo " make sun : for Sun-OS 4.x and maybe some BSD systems, cc or gcc" + @echo " make linux : for Linux" + @echo " make solaris : for Sun-OS 5.x gcc" + @echo " make sol-x86 : for Solaris 7 x86" + @echo " make freebsd : for BSD 4.4 systems" + @echo " make bsd : for BSD systems, cc or gcc, if not in the above lists" + @echo " make cygwin : for Microsoft Windows and Cygwin gcc" + +sun: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -fomit-frame-pointer -Wunused -I../include" LDFLAGS="-s -L../lib -ldao" $(EXE) + +linux: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao -lcrypt -lresolv" $(EXE) + +solaris: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao -lsocket -lresolv -lnsl -L/usr/ucblib -lucb -R/usr/ucblib" $(EXE) + +sol-x86: + @$(MAKE) CC=gcc CFLAGS="-O2 -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao -lsocket -lresolv -lnsl" $(EXE) + +freebsd: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao -lcrypt" $(EXE) + +bsd: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao" $(EXE) + +cygwin: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../lib -ldao -lcrypt -lresolv -lcygipc" $(EXE) + + +.c: ; $(CC) -o $@ $@.c $(CFLAGS) $(LDFLAGS) + + +install: $(EXE) + install -m 0700 $? $(HOME)/bin + +clean: + rm -f $(EXE) *.exe *.o *~ diff --git a/util/account.c b/util/account.c new file mode 100644 index 0000000..f68eff6 --- /dev/null +++ b/util/account.c @@ -0,0 +1,1181 @@ +/*-------------------------------------------------------*/ +/* util/account.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : ¤W¯¸¤H¦¸²Îp¡B¨t²Î¸ê®Æ³Æ¥÷¡B¶}²¼ */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ +/* syntax : ¥»µ{¦¡©y¥H crontab °õ¦æ¡A³]©w®É¶¡¬°¨C¤p®É */ +/* 1-5 ¤À ¤§¶¡ */ +/*-------------------------------------------------------*/ +/* notice : brdshm (board shared memory) synchronize */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#include <sys/ipc.h> +#include <sys/shm.h> + + +#define MAX_LINE 16 +#define ADJUST_M 10 /* adjust back 10 minutes */ + + +/* itoc.011004.µù¸Ñ: ¥Î - ¥Nªí³o¦¸ªº¡A¥Î = ¥Nªí¤W¦¸ªº¡C¦b gem/@/ ¤U¦³«Ü¦h³o¼Ëªº½d¨Ò */ + +static char fn_today[] = "gem/@/@-act"; /* ¤µ¤é¤W¯¸¤H¦¸²Îp */ +static char fn_yesday[] = "gem/@/@=act"; /* ¬Q¤é¤W¯¸¤H¦¸²Îp */ +static char log_file[] = FN_RUN_USIES "="; + +static time_t now; /* °õ¦æµ{¦¡ªº®É¶¡ */ + + +/* ----------------------------------------------------- */ +/* ¶}²¼¡Gshm ³¡¥÷¶·»P cache.c ¬Û®e */ +/* ----------------------------------------------------- */ + + +static BCACHE *bshm; + + +static int +boardname_cmp(a, b) + BRD *a, *b; +{ + return str_cmp(a->brdname, b->brdname); +} + + +static void +fix_brd() +{ + BRD allbrd[MAXBOARD], brd; + FILE *fp; + int i, num; + + if (!(fp = fopen(FN_BRD, "r"))) + return; + + num = 0; + for (i = 0; i < MAXBOARD; i++) + { + if (fread(&brd, sizeof(BRD), 1, fp) != 1) + break; + + if (!*brd.brdname) /* ¦¹ªO¤w³Q§R°£ */ + continue; + + memcpy(&allbrd[num], &brd, sizeof(BRD)); + num++; + } + + fclose(fp); + + /* itoc.041110: ¦b²Ä¤@¦¸¸ü¤J bshm ®É¡A±N bno ¨ÌªO¦W±Æ§Ç */ + if (num > 1) + qsort(allbrd, num, sizeof(BRD), boardname_cmp); + + unlink(FN_BRD); + + if (num) + rec_add(FN_BRD, allbrd, sizeof(BRD) * num); +} + + +#ifdef HAVE_MODERATED_BOARD +static int +int_cmp(a, b) + int *a, *b; +{ + return *a - *b; +} +#endif + + +static void +init_allbrd() +{ + BRD *head, *tail; +#ifdef HAVE_MODERATED_BOARD + int fd; + char fpath[64]; + BPAL *bpal; +#endif + + head = bshm->bcache; + tail = head + bshm->number; +#ifdef HAVE_MODERATED_BOARD + bpal = bshm->pcache; +#endif + + do + { + /* itoc.040314: ªO¥D§ó§ï¬ÝªO±Ôz©Î¬O¯¸ªø§ó§ï¬ÝªO®É¤~·|§â bpost/blast ¼g¶i .BRD ¤¤ + ©Ò¥H .BRD ¸Ìªº bpost/blast ¥¼¥²¬O¹ïªº¡An«·s initial¡C + initial ªº¤èªk¬O±N btime ³]¦¨ -1¡AÅý class_item() ¥h§ó·s */ + head->btime = -1; + +#ifdef HAVE_MODERATED_BOARD + brd_fpath(fpath, head->brdname, FN_PAL); + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + struct stat st; + PAL *pal, *up; + int count; + + fstat(fd, &st); + if (pal = (PAL *) malloc(count = st.st_size)) + { + count = read(fd, pal, count) / sizeof(PAL); + if (count > 0 && count <= PAL_MAX) + { + int *userno; + int c = count; + + userno = bpal->pal_spool; + up = pal; + do + { + *userno++ = (up->ftype & PAL_BAD) ? -(up->userno) : up->userno; + up++; + } while (--c); + + if (count > 1) + qsort(bpal->pal_spool, count, sizeof(int), int_cmp); + bpal->pal_max = count; + } + free(pal); + } + close(fd); + } + + bpal++; +#endif + + } while (++head < tail); +} + + +static void +init_bshm() +{ + time_t *uptime; + int n, turn; + + bshm = shm_new(BRDSHM_KEY, sizeof(BCACHE)); + uptime = &(bshm->uptime); + + turn = 0; + for (;;) + { + n = *uptime; + if (n > 0) /* bshm ¤w initial §¹¦¨ */ + return; + + if (n < 0) + { + if (++turn < 30) + { + sleep(2); + continue; + } + } + + *uptime = -1; + + fix_brd(); /* itoc.030725: ¦b²Ä¤@¦¸¸ü¤J bshm «e¡A¥ý¾ã²z .BRD */ + + if ((n = open(FN_BRD, O_RDONLY)) >= 0) + { + turn = read(n, bshm->bcache, MAXBOARD * sizeof(BRD)) / sizeof(BRD); + close(n); + bshm->number = bshm->numberOld = turn; + + init_allbrd(); + } + + /* µ¥©Ò¦³ boards ¸ê®Æ§ó·s«á¦A³]©w uptime */ + + time(uptime); + fprintf(stderr, "[account]\tCACHE\treload bcache\n"); + return; + } +} + + +/* ----------------------------------------------------- */ +/* keep log in board */ +/* ----------------------------------------------------- */ + + +static void +update_btime(brdname) + char *brdname; +{ + BRD *brdp, *bend; + + brdp = bshm->bcache; + bend = brdp + bshm->number; + do + { + if (!strcmp(brdname, brdp->brdname)) + { + brdp->btime = -1; + break; + } + } while (++brdp < bend); +} + + +static void +keeplog(fnlog, board, title, mode) + char *fnlog; + char *board; + char *title; + int mode; /* 0:load 1:rename 2:unlink */ +{ + HDR hdr; + char folder[64], fpath[64]; + int fd; + FILE *fp; + + if (!dashf(fnlog)) /* Kudo.010804: Àɮ׬OªÅªº´N¤£ keeplog */ + return; + + if (!board) + board = BN_RECORD; + + brd_fpath(folder, board, FN_DIR); + fd = hdr_stamp(folder, 'A', &hdr, fpath); + if (fd < 0) + return; + + if (mode == 1) + { + close(fd); + /* rename(fnlog, fpath); */ + f_mv(fnlog, fpath); /* Thor.990409: ¥i¸ópartition */ + } + else + { + fp = fdopen(fd, "w"); + fprintf(fp, "§@ªÌ: %s (%s)\n¼ÐÃD: %s\n®É¶¡: %s\n\n", + STR_SYSOP, SYSOPNICK, title, Btime(&hdr.chrono)); + f_suck(fp, fnlog); + fclose(fp); + if (mode) + unlink(fnlog); + } + + strcpy(hdr.title, title); + strcpy(hdr.owner, STR_SYSOP); + rec_bot(folder, &hdr, sizeof(HDR)); + + update_btime(board); +} + + +/* ----------------------------------------------------- */ +/* build vote result */ +/* ----------------------------------------------------- */ + + +struct Tchoice +{ + int count; + vitem_t vitem; +}; + + +static int +TchoiceCompare(i, j) + struct Tchoice *i, *j; +{ + return j->count - i->count; +} + + +static int +draw_vote(brd, fpath, vch) + BRD *brd; /* Thor: ¶Ç¤J BRD, ¥i¬d battr */ + char *fpath; + VCH *vch; +{ + struct Tchoice choice[MAX_CHOICES]; + FILE *fp; + char *fname, *bid, buf[80]; + int total, items, num, fd, ticket, bollt; + VLOG vlog; + char *list = "@IOLGZ"; /* itoc.µù¸Ñ: ²M vote file */ + + bid = brd->brdname; + fname = strrchr(fpath, '@'); + + /* vote item */ + + *fname = 'I'; + + items = 0; + if (fp = fopen(fpath, "r")) + { + while (fread(&choice[items].vitem, sizeof(vitem_t), 1, fp) == 1) + { + choice[items].count = 0; + items++; + } + fclose(fp); + } + + if (items == 0) + return 0; + + /* ²Öp§ë²¼µ²ªG */ + + *fname = 'G'; + bollt = 0; /* Thor: Á`²¼¼ÆÂk¹s */ + total = 0; + + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + while (read(fd, &vlog, sizeof(VLOG)) == sizeof(VLOG)) + { + for (ticket = vlog.choice, num = 0; ticket && num < items; ticket >>= 1, num++) + { + if (ticket & 1) + { + choice[num].count += vlog.numvotes; + bollt += vlog.numvotes; + } + } + total++; + } + close(fd); + } + + /* ²£¥Í¶}²¼µ²ªG */ + + *fname = 'Z'; + if (!(fp = fopen(fpath, "w"))) + return 0; + + fprintf(fp, "\n\033[1;34m" MSG_SEPERATOR "\033[m\n\n" + "\033[1;32m¡» [%s] ¬ÝªO§ë²¼¡G%s\033[m\n\nÁ|¿ìªO¥D¡G%s\n\nÁ|¿ì¤é´Á¡G%s\n\n", + bid, vch->title, vch->owner, Btime(&vch->chrono)); + fprintf(fp, "¶}²¼¤é´Á¡G%s\n\n\033[1;32m¡» §ë²¼¥DÃD¡G\033[m\n\n", Btime(&vch->vclose)); + + *fname = '@'; + f_suck(fp, fpath); + + fprintf(fp, "\n\033[1;32m¡» §ë²¼µ²ªG¡G¨C¤H¥i§ë %d ²¼¡A¦@ %d ¤H°Ñ¥[¡A§ë¥X %d ²¼\033[m\n\n", + vch->maxblt, total, bollt); + + if (vch->vsort == 's') + qsort(choice, items, sizeof(struct Tchoice), TchoiceCompare); + + if (vch->vpercent == '%') + fd = BMAX(1, bollt); + else + fd = 0; + + for (num = 0; num < items; num++) + { + ticket = choice[num].count; + if (fd) + fprintf(fp, " %-36s%5d ²¼ (%4.1f%%)\n", &choice[num].vitem, ticket, 100.0 * ticket / fd); + else + fprintf(fp, " %-36s%5d ²¼\n", &choice[num].vitem, ticket); + } + + /* other opinions */ + + *fname = 'O'; + fputs("\n\033[1;32m¡» §Ú¦³¸Ün»¡¡G\033[m\n\n", fp); + f_suck(fp, fpath); + fputs("\n", fp); + fclose(fp); + + fp = fopen(fpath, "w"); /* Thor: ¥Î O_ ¼È¦s¤@¤U¤U... */ + *fname = 'Z'; + f_suck(fp, fpath); + sprintf(buf, "brd/%s/@/@vote", bid); + f_suck(fp, buf); + fclose(fp); + *fname = 'O'; + rename(fpath, buf); + + /* ±N¶}²¼µ²ªG post ¨ì [BN_RECORD] »P ¥»¬ÝªO */ + + *fname = 'Z'; + + /* Thor: Y¬ÝªOÄݩʬ° BRD_NOVOTE¡A«h¤£ post ¨ì [BN_RECORD] */ + + if (!(brd->battr & BRD_NOVOTE)) + { + sprintf(buf, "[°O¿ý] %s <<¬ÝªO¿ï±¡³ø¾É>>", bid); + keeplog(fpath, NULL, buf, 0); + } + + keeplog(fpath, bid, "[°O¿ý] ¿ï±¡³ø¾É", 2); + + while (*fname = *list++) + unlink(fpath); /* Thor: ½T©w¦W¦r´N¬å */ + + return 1; +} + + +static int /* 0:¤£»Ý¼g¦^.BRD !=0:»Ý¼g¦^.BRD */ +draw_board(brd) + BRD *brd; +{ + int fd, fsize, alive; + int oldbvote, newbvote; + VCH *vch, *head, *tail; + char *fname, fpath[64], buf[64]; + struct stat st; + + /* ¥Ñ account ¨Ó maintain brd->bvote */ + + oldbvote = brd->bvote; + + brd_fpath(fpath, brd->brdname, FN_VCH); + + if ((fd = open(fpath, O_RDWR | O_APPEND, 0600)) < 0 || fstat(fd, &st) || (fsize = st.st_size) <= 0) + { + if (fd >= 0) + { + close(fd); + unlink(fpath); + } + brd->bvote = 0; + return oldbvote; + } + + vch = (VCH *) malloc(fsize); + + /* flock(fd, LOCK_EX); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_exlock(fd); + + read(fd, vch, fsize); + + strcpy(buf, fpath); + fname = strrchr(buf, '.'); + *fname++ = '@'; + *fname++ = '/'; + + head = vch; + tail = (VCH *) ((char *)vch + fsize); + + alive = 0; + newbvote = 0; + + do + { + if (head->vclose < now && head->vgamble == ' ') /* ½ä½L¤£Åý account ¶} */ + { + strcpy(fname, head->xname); + draw_vote(brd, buf, head);/* Thor: ¶Ç¤J BRD, ¥i¬d battr */ + head->chrono = 0; + } + else + { + alive++; + + if (head->vgamble == '$') + newbvote = -1; + } + } while (++head < tail); + + + if (alive && alive != fsize / sizeof(VCH)) + { + ftruncate(fd, 0); + head = vch; + do + { + if (head->chrono) + { + write(fd, head, sizeof(VCH)); + } + } while (++head < tail); + } + + /* flock(fd, LOCK_UN); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_unlock(fd); + + close(fd); + + free(vch); + + if (!alive) + unlink(fpath); + else if (!newbvote) + newbvote = 1; /* ¥u¦³§ë²¼¡A¨S¦³½ä½L */ + + if (oldbvote != newbvote) + { + brd->bvote = newbvote; + return 1; + } + + return 0; +} + + +static void +closepolls() +{ + BRD *bcache, *head, *tail; + int dirty; + + dirty = 0; + + head = bcache = bshm->bcache; + tail = head + bshm->number; + do + { + dirty |= draw_board(head); + } while (++head < tail); + + if (!dirty) + return; + + /* write back the shm cache data */ + + if ((dirty = open(FN_BRD, O_WRONLY | O_CREAT, 0600)) < 0) + return; + + /* flock(dirty, LOCK_EX); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_exlock(dirty); + + write(dirty, bcache, (char *)tail - (char *)bcache); + + /* flock(dirty, LOCK_UN); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_unlock(dirty); + + close(dirty); + time(&bshm->uptime); +} + + +/* ----------------------------------------------------- */ +/* build Class image */ +/* ----------------------------------------------------- */ + + +#define CLASS_RUNFILE "run/class.run" + + +static ClassHeader *chx[CH_MAX]; +static int chn; +static BRD *bhead, *btail; + + +static int +class_parse(key) + char *key; +{ + char *str, *ptr, fpath[64]; + ClassHeader *chp; + HDR hdr; + int i, len, count; + FILE *fp; + + strcpy(fpath, "gem/@/@"); + str = fpath + sizeof("gem/@/@") - 1; + for (ptr = key;; ptr++) + { + i = *ptr; + if (i == '/') + i = 0; + *str = i; + if (!i) + break; + str++; + } + + len = ptr - key; + + /* search classes */ + + for (i = 1; i < chn; i++) + { + str = chx[i]->title; + if (str[len] == '/' && !memcmp(key, str, len)) + return CH_END - i; + } + + /* build classes */ + + if (fp = fopen(fpath, "r")) + { + int ans; + struct stat st; + + if (fstat(fileno(fp), &st) || (count = st.st_size / sizeof(HDR)) <= 0) + { + fclose(fp); + return CH_END; + } + + /* itoc.030723: Àˬd Class ¼Æ¶q¬O§_¶W¹L CH_MAX */ + if (chn >= CH_MAX - 1) + { + static int show_error = 0; + if (!show_error) /* ¿ù»~°T®§¥u¦L¤@¦¸ */ + { + fprintf(stderr, "[account]\t½Ð¥[¤j±zªº CH_MAX ©w¸q¡ACH_MAX ¥²¶·¶W¹L Class ªº¼Æ¶q\n"); + show_error = 1; + } + fclose(fp); + return CH_END; + } + + chx[chn++] = chp = (ClassHeader *) malloc(sizeof(ClassHeader) + count * sizeof(short)); + memset(chp->title, 0, CH_TTLEN); + strcpy(chp->title, key); + + ans = chn; + count = 0; + + while (fread(&hdr, sizeof(hdr), 1, fp) == 1) + { + if (hdr.xmode & GEM_BOARD) + { + BRD *bp; + + i = -1; + str = hdr.xname; + bp = bhead; + + for (;;) + { + i++; + if (!str_cmp(str, bp->brdname)) + break; + + if (++bp >= btail) + { + i = -1; + break; + } + } + + if (i < 0) + continue; + } + else + { + /* recursive ¦a¤@¼h¤@¼h¶i¥h«Ø Class */ + i = class_parse(hdr.title); + + if (i == CH_END) + continue; + } + + chp->chno[count++] = i; + } + + fclose(fp); + + chp->count = count; + return -ans; + } + + return CH_END; +} + + +static int +brdname_cmp(i, j) + short *i, *j; +{ + return str_cmp(bhead[*i].brdname, bhead[*j].brdname); +} + + +static int +brdtitle_cmp(i, j) /* itoc.010413: ¨Ì¬ÝªO¤¤¤å±Ôz±Æ§Ç */ + short *i, *j; +{ + /* return strcmp(bhead[*i].title, bhead[*j].title); */ + + /* itoc.010413: ¤ÀÃþ/ªO¦W¥æ¤e¤ñ¹ï */ + int k = strcmp(bhead[*i].class, bhead[*j].class); + return k ? k : str_cmp(bhead[*i].brdname, bhead[*j].brdname); +} + + +static void +class_sort(cmp) + int (*cmp) (); +{ + ClassHeader *chp; + int i, j, max; + BRD *bp; + + max = bshm->number; + bhead = bp = bshm->bcache; + btail = bp + max; + + chp = (ClassHeader *) malloc(sizeof(ClassHeader) + max * sizeof(short)); + + for (i = j = 0; i < max; i++, bp++) + { + if (bp->brdname) + chp->chno[j++] = i; + } + + chp->count = j; + + qsort(chp->chno, j, sizeof(short), cmp); + + memset(chp->title, 0, CH_TTLEN); + strcpy(chp->title, "Boards"); + chx[chn++] = chp; +} + + +static void +class_image() +{ + int i, times; + FILE *fp; + short len, pos[CH_MAX]; + ClassHeader *chp; + + for (times = 2; times > 0; times--) /* itoc.010413: ²£¥Í¤G¥÷ class image */ + { + chn = 0; + class_sort(times == 1 ? brdname_cmp : brdtitle_cmp); + class_parse(CLASS_INIFILE); + + if (chn < 2) /* lkchu.990106: ©|¨S¦³¤ÀÃþ */ + return; + + len = sizeof(short) * (chn + 1); + + for (i = 0; i < chn; i++) + { + pos[i] = len; + len += CH_TTLEN + chx[i]->count * sizeof(short); + } + + pos[i++] = len; + + if (fp = fopen(CLASS_RUNFILE, "w")) + { + fwrite(pos, sizeof(short), i, fp); + for (i = 0; i < chn; i++) + { + chp = chx[i]; + fwrite(chp->title, 1, CH_TTLEN + chp->count * sizeof(short), fp); + free(chp); + } + fclose(fp); + + rename(CLASS_RUNFILE, times == 1 ? CLASS_IMGFILE_NAME : CLASS_IMGFILE_TITLE); + } + } + + bshm->min_chn = -chn; +} + + +/* ----------------------------------------------------- */ +/* ¤W¯¸¤H¼Æ²Îp */ +/* ----------------------------------------------------- */ + + +static void +error(fpath) + char *fpath; +{ + printf("can not open [%s]\n", fpath); + /* exit(1); */ /* itoc.011004: ¤W¯¸¤H¦¸²Îp¥¢±Ñ¡AµL»Ý¤¤Â_ account °õ¦æ */ +} + + +static void +ansi_puts(fp, buf, mode) + FILE *fp; + char *buf, mode; +{ + static char state = '0'; + + if (state != mode) + fprintf(fp, "\033[3%cm", state = mode); + if (*buf) + { + fprintf(fp, buf); + *buf = '\0'; + } +} + + +static void +draw_usies(ptime) + struct tm *ptime; +{ + int fact, hour, max, item, total, i, j, over; + char buf[256]; + FILE *fp, *fpw; + int act[26]; /* act[0~23]:0~23®É¦U¤p®Éªº¤W¯¸¤H¦¸ act[24]:°±¯d²Öp®É¶¡ act[25]:²Ö¿n¤H¦¸ */ + + static char act_file[] = "run/var/act"; + static char run_file[] = FN_RUN_USIES; + static char tmp_file[] = FN_RUN_USIES ".tmp"; + + rename(run_file, tmp_file); + if (!(fp = fopen(tmp_file, "r"))) + { + /* error(tmp_file); */ /* itoc.011004.µù¸Ñ: ¨S¦³ tmp_file ªí¥Ü¨S¦³ run_file¡Aªí¥Ü±q¤W¦¸¶] account ¨ì²{¦b¡A */ + return; /* ¨S¦³¤H login ¹L bbs¡C³q±`µo¥Í¦b¤â°Ê¶] account ÀWÁc®É¡C */ + } + + if (!(fpw = fopen(log_file, "a"))) + { + fclose(fp); + error(log_file); /* itoc.011004.µù¸Ñ: log_file ¬O¬Q¤Ñ run_file¡C¦pªG¬Q¤Ñ¾ã¤Ñ³£¨S¦³¤H login ¹L bbs¡A */ + return; /* ´N·|µo¥Í¨S¦³ log_file ªºª¬ªp */ + } + + if ((fact = open(act_file, O_RDWR | O_CREAT, 0600)) < 0) + { + fclose(fp); + fclose(fpw); + error(act_file); /* itoc.011004.µù¸Ñ: ³£¤w¸g¦³ O_CREAT ¦pªGÁÙ¨S¦³ act_file ªº¸Ü..¦n¦Û¬°¤§§a :P */ + return; + } + + memset(act, 0, sizeof(act)); + + if (ptime->tm_hour != 0) + { + read(fact, act, sizeof(act)); + lseek(fact, 0, SEEK_SET); + } + + while (fgets(buf, sizeof(buf), fp)) + { + fputs(buf, fpw); + + if (!memcmp(buf + 24, "ENTER", 5)) + { + hour = atoi(buf + 15); + if (hour >= 0 && hour <= 23) + act[hour]++; + continue; + } + + if (!memcmp(buf + 43, "Stay:", 5)) + { + if (hour = atoi(buf + 49)) + { + act[24] += hour; + act[25]++; + } + continue; + } + } + fclose(fp); + fclose(fpw); + unlink(tmp_file); + + write(fact, act, sizeof(act)); + close(fact); + + for (i = max = total = 0; i < 24; i++) + { + total += act[i]; /* itoc.030415.µù¸Ñ: act[25] ¥¼¥²µ¥©ó total¡A¦³¤H¤]³\¤£¥¿±`Â÷¯¸ */ + if (act[i] > max) + max = act[i]; + } + + item = max / MAX_LINE + 1; + over = max > 1000; + + if (!(fp = fopen(fn_today, "w"))) + { + error(fn_today); + return; + } + + /* Thor.990329: y2k */ + fprintf(fp, "\t\t\t \033[1;33;46m [%02d/%02d/%02d] ¤W¯¸¤H¦¸²Îp \033[40m\n", + ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday); + + for (i = MAX_LINE + 1; i > 0; i--) + { + strcpy(buf, " "); + for (j = 0; j < 24; j++) + { + max = item * i; + hour = act[j]; + if (hour && (max > hour) && (max - item <= hour)) + { + ansi_puts(fp, buf, '3'); + if (over) + hour = (hour + 5) / 10; + fprintf(fp, "%-3d", hour); + } + else if (max <= hour) + { + ansi_puts(fp, buf, '1'); + fprintf(fp, "¢i "); + } + else + strcat(buf, " "); + } + fprintf(fp, "\n"); + } + + if (act[25] == 0) + act[25] = 1; /* Thor.980928: lkchu patch: ¨¾¤î°£¼Æ¬°0 */ + + fprintf(fp, "\033[34m" + " ùæùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùè\n \033[32m" + "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23\n\n" + "\t%s\t\033[35mÁ`¦@¤W¯¸¤H¦¸¡G\033[37m%-9d\033[35m¥§¡¨Ï¥Î®É¶¡¡G\033[37m%d\033[m\n", + over ? "\033[35m³æ¦ì¡G\033[37m10 ¤H" : "", total, act[24] / act[25] + 1); + fclose(fp); +} + + +/* ----------------------------------------------------- */ +/* À£ÁYµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +gzip(source, target, stamp) + char *source, *target, *stamp; +{ + char buf[128]; + + if (dashf(source)) + { + sprintf(buf, "/usr/bin/gzip -n log/%s%s", target, stamp); + /* rename(source, buf + 17); */ + f_mv(source, buf + 17); /* Thor.990409: ¥i¸ó partition */ + system(buf); + } +} + + +/* ----------------------------------------------------- */ +/* ²£¥ÍÅçÃÒ«Hªº private key */ +/* ----------------------------------------------------- */ + + +#ifdef HAVE_SIGNED_MAIL +static void +private_key(ymd) + char *ymd; +{ + srandom(time(NULL)); + +#if (PRIVATE_KEY_PERIOD == 0) + if (!dashf(FN_RUN_PRIVATE)) +#else + if (!dashf(FN_RUN_PRIVATE) || (random() % PRIVATE_KEY_PERIOD) == 0) +#endif + { + int i, j; + char buf[80]; + + sprintf(buf, "log/prikey%s", ymd); + f_mv(FN_RUN_PRIVATE, buf); + i = 8; + for (;;) + { + j = random() & 0xff; + if (!j) + continue; + buf[--i] = j; + if (i == 0) + break; + } + rec_add(FN_RUN_PRIVATE, buf, 8); + } +} +#endif + + +/* ----------------------------------------------------- */ +/* ¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct tm ntime, *ptime; + FILE *fp; + + now = time(NULL); /* ¤@¶}©l´Nn°¨¤W°O¿ý®É¶¡ */ + + setgid(BBSGID); + setuid(BBSUID); + chdir(BBSHOME); + umask(077); + + /* --------------------------------------------------- */ + /* ªì©l¤Æ board shm ¥Î¨Ó«Ø Class ¤Î¶}²¼ */ + /* --------------------------------------------------- */ + + init_bshm(); + + /* --------------------------------------------------- */ + /* build Class image */ + /* --------------------------------------------------- */ + + class_image(); + + /* --------------------------------------------------- */ + /* ¨t²Î¶}²¼ */ + /* --------------------------------------------------- */ + + closepolls(); + + /* --------------------------------------------------- */ + /* ¸ê®Æ²Îp®É¶¡ */ + /* --------------------------------------------------- */ + + /* itoc.030911: Y¥[¤F°Ñ¼Æ¡Aªí¥Ü¤£¬O¦b crontab ¸Ì¶]ªº¡A¨º»ò¤£°µ¸ê®Æ²Îp */ + if (argc != 1) + exit(0); + + /* ntime ¬O¤µ¤Ñ */ + ptime = localtime(&now); + memcpy(&ntime, ptime, sizeof(ntime)); /* ¥ý¦s°_¨Ó¡A¦]¬°ÁÙn°µ¤@¦¸ localtime() */ + + /* ptime ¬O¬Q¤Ñ */ + /* itoc.011004.µù¸Ñ: ¥Ñ©ó account ¬Oºâ«e¤@¤p®É²Îp¡A©Ò¥H¦b¹s®É®Én§â®ÉÄÁÂà¦^ 10 ¤ÀÄÁ¡A¨ì¬Q¤Ñ¥h */ + /* itoc.030911.µù¸Ñ: ©Ò¥H account ¥²¶·¦b¨C¤p®Éªº 1-10 ¤À¤º°õ¦æ */ + now -= ADJUST_M * 60; /* back to ancent */ + ptime = localtime(&now); + + /* --------------------------------------------------- */ + /* ¤W¯¸¤H¦¸²Îp */ + /* --------------------------------------------------- */ + + draw_usies(ptime); + + /* --------------------------------------------------- */ + /* ¸ê®ÆÀ£ÁY³Æ¥÷¡B¼öªù¸ÜÃD²Îp */ + /* --------------------------------------------------- */ + + if (ntime.tm_hour == 0) + { + char date[16], ymd[16]; + char title[80]; + + sprintf(ymd, "-%02d%02d%02d", + ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday); /* Thor.990329: y2k */ + + sprintf(date, "[%d ¤ë %d ¤é] ", ptime->tm_mon + 1, ptime->tm_mday); + + + /* ------------------------------------------------- */ + /* ¨C¤éâ±á¹s®É°µªº¨Æ */ + /* ------------------------------------------------- */ + + gzip(log_file, "usies", ymd); /* ³Æ¥÷©Ò¦³ [¤W¯¸] °O¿ý */ + +#ifdef HAVE_SIGNED_MAIL + private_key(ymd); +#endif + + sprintf(title, "%s¤å³¹½g¼Æ²Îp", date); + keeplog(FN_RUN_POST_LOG, BN_SECURITY, title, 2); + + sprintf(title, "%s¯¸°È¦æ¬°°O¿ý", date); + keeplog(FN_RUN_ADMIN, BN_SECURITY, title, 2); + +#if 0 + sprintf(title, "%s±H«H°O¿ý", date); + keeplog(FN_RUN_MAIL_LOG, BN_SECURITY, title, 2); +#endif +#if 0 +#ifdef HAVE_ANONYMOUS + sprintf(title, "%s°Î¦W¤å³¹µoªí", date); + keeplog(FN_RUN_ANONYMOUS, BN_SECURITY, title, 2); +#endif +#endif + +#ifdef HAVE_BUY + sprintf(title, "%s¶×¿ú°O¿ý", date); + keeplog(FN_RUN_BANK_LOG, BN_SECURITY, title, 2); +#endif + + system("grep OVER " BMTA_LOGFILE " | cut -f2 | cut -d' ' -f2- | sort | uniq -c > run/over.log"); + sprintf(title, "%sE-Mail over max connection ²Îp", date); + keeplog("run/over.log", BN_SECURITY, title, 2); + + sprintf(title, "%s»Ä²¢W»¶¯d¨¥ªO", date); + keeplog(FN_RUN_NOTE_ALL, NULL, title, 2); + + if (fp = fopen(fn_yesday, "w")) + { + f_suck(fp, fn_today); + fclose(fp); + } + sprintf(title, "%s¤W¯¸¤H¦¸²Îp", date); + keeplog(fn_today, NULL, title, 1); + + + /* ------------------------------------------------- */ + /* ¨C¶g¤@â±á¹s®É°µªº¨Æ */ + /* ------------------------------------------------- */ + + if (ntime.tm_wday == 0) + { + sprintf(title, "%s¥»¶g¼öªù¸ÜÃD", date); + keeplog("gem/@/@-week", NULL, title, 0); + + sprintf(title, "%s°½ÃiªO¥D²Îp", date); + keeplog(FN_RUN_LAZYBM, BN_SECURITY, title, 2); + + sprintf(title, "%s¯S®íÅv¨Ï¥ÎªÌ¦Cªí", date); + keeplog(FN_RUN_MANAGER, BN_SECURITY, title, 2); + + sprintf(title, "%sªø´Á¥¼¤W¯¸³Q²M°£ªº¨Ï¥ÎªÌ¦Cªí", date); + keeplog(FN_RUN_REAPER, BN_SECURITY, title, 2); + + sprintf(title, "%s¦P¤@ email »{ÃÒ¦h¦¸", date); + keeplog(FN_RUN_EMAILADDR, BN_SECURITY, title, 2); + } + + + /* ------------------------------------------------- */ + /* ¨C¤ë¤@¤éâ±á¹s®É°µªº¨Æ */ + /* ------------------------------------------------- */ + + if (ntime.tm_mday == 1) + { + sprintf(title, "%s¥»¤ë¼öªù¸ÜÃD", date); + keeplog("gem/@/@-month", NULL, title, 0); + } + + + /* ------------------------------------------------- */ + /* ¨C¦~¤@¤ë¤@¤éâ±á¹s®É°µªº¨Æ */ + /* ------------------------------------------------- */ + + if (ntime.tm_yday == 1) + { + sprintf(title, "%s¦~«×¼öªù¸ÜÃD", date); + keeplog("gem/@/@-year", NULL, title, 0); + } + } + + exit(0); +} diff --git a/util/acl-sort.c b/util/acl-sort.c new file mode 100644 index 0000000..f230a96 --- /dev/null +++ b/util/acl-sort.c @@ -0,0 +1,130 @@ +/*-------------------------------------------------------*/ +/* util/acl-sort.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : sort [Access Control List] */ +/* create : 98/03/29 */ +/* update : 98/03/29 */ +/*-------------------------------------------------------*/ +/* syntax : acl-sort <file> */ +/*-------------------------------------------------------*/ + + +#include <stdio.h> +#include "splay.h" + + +typedef struct +{ + int domain; + char text[0]; +} AclText; + + +static int +at_cmp(x, y) + AclText *x; + AclText *y; +{ + char *tail1, *tail2; + int c1, c2, diff; + + tail1 = x->text + x->domain; + tail2 = y->text + y->domain; + + for (;;) + { + c1 = *tail1--; + if (c1 == '@') + c1 = 0; + else if (c1 >= 'A' && c1 <= 'Z') + c1 |= 32; + + c2 = *tail2--; + if (c2 == '@') + c2 = 0; + else if (c2 >= 'A' && c2 <= 'Z') + c2 |= 32; + + if (diff = c1 - c2) + return (diff); + } +} + + +static void +at_out(top) + SplayNode *top; +{ + AclText *at; + + if (top == NULL) + return; + + at_out(top->left); + + at = (AclText *) top->data; + fputs(at->text + 1, stdout); + + at_out(top->right); +} + + +static void +acl_sort(fpath) + char *fpath; +{ + FILE *fp; + int len, domain; + AclText *at; + SplayNode *top; + char *str, buf[256]; + + if (!(fp = fopen(fpath, "r"))) + return; + + top = NULL; + + while (fgets(buf, sizeof(buf) - 2, fp)) + { + str = buf; + if (*str <= '#') + continue; + + while (*++str > ' ') + ; + + domain = str - buf; + + + while (*str) + str++; + + len = str - buf; + + at = (AclText *) malloc(sizeof(AclText) + len + 2); + at->domain = domain; + at->text[0] = '\0'; + strcpy(at->text + 1, buf); + + top = splay_in(top, at, at_cmp); + } + + at_out(top); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + if (argc != 2) + { + printf("Usage:\t%s file\n", argv[0]); + } + else + { + acl_sort(argv[1]); + } + exit(0); +} diff --git a/util/backup/Makefile b/util/backup/Makefile new file mode 100644 index 0000000..5bc70a4 --- /dev/null +++ b/util/backup/Makefile @@ -0,0 +1,57 @@ +# ------------------------------------------------------- # +# util/Makefile ( NTHU CS MapleBBS Ver 3.10 ) # +# ------------------------------------------------------- # +# target : Makefile for ±H«H¡B²Îp¡B³Æ¥÷¡B¨t²ÎºûÅ@¤u¨ã # +# create : 95/03/29 # +# update : 95/12/15 # +# ------------------------------------------------------- # + + +# ------------------------------------------------------ # +# ¤U¦Cªº make rules ¤£»Ý×§ï # +# ------------------------------------------------------ # + + +EXE = backupacct backupbrd backupgem backupoth backupusr restoreacct restorebrd restoregem restoreusr + + +all: + @echo "Please enter 'make sys-type', " + @echo " make sun : for Sun-OS 4.x and maybe some BSD systems, cc or gcc" + @echo " make linux : for Linux" + @echo " make solaris : for Sun-OS 5.x gcc" + @echo " make sol-x86 : for Solaris 7 x86" + @echo " make freebsd : for BSD 4.4 systems" + @echo " make bsd : for BSD systems, cc or gcc, if not in the above lists" + @echo " make cygwin : for Microsoft Windows and Cygwin gcc" + +sun: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -fomit-frame-pointer -Wunused -I../../include" LDFLAGS="-s -L../../lib -ldao" $(EXE) + +linux: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao" $(EXE) + +solaris: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao -lsocket -lnsl -L/usr/ucblib -lucb" $(EXE) + +sol-x86: + @$(MAKE) CC=gcc CFLAGS="-O2 -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao -lsocket -lnsl" $(EXE) + +freebsd: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao" $(EXE) + +bsd: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao" $(EXE) + +cygwin: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao" $(EXE) + + +.c: ; $(CC) -o $@ $@.c $(CFLAGS) $(LDFLAGS) + + +install: $(EXE) + install -m 0700 $? $(HOME)/bin + +clean: + rm -f $(EXE) *.exe *.o *~ diff --git a/util/backup/backupacct.c b/util/backup/backupacct.c new file mode 100644 index 0000000..f503767 --- /dev/null +++ b/util/backup/backupacct.c @@ -0,0 +1,58 @@ +/*-------------------------------------------------------*/ +/* util/backupacct.c ( NTHU MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ³Æ¥÷©Ò¦³¨Ï¥ÎªÌ .ACCT */ +/* create : 01/10/19 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +int +main() +{ + struct dirent *de; + DIR *dirp; + char *ptr, ch; + char fpath[128], bakpath[128], cmd[256]; + time_t now; + struct tm *ptime; + + time(&now); + ptime = localtime(&now); + /* «Ø¥ß³Æ¥÷¸ô®|¥Ø¿ý */ + sprintf(fpath, "%s/acct%02d%02d%02d", BAKPATH, ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday); + mkdir(fpath, 0755); + + /* §ïÅÜÅv¨Ï ftp ¶ÇÀɤ£·|º|¶Ç */ + sprintf(cmd, "cp %s/%s %s/; chmod 644 %s/%s", BBSHOME, FN_SCHEMA, fpath, fpath, FN_SCHEMA); + system(cmd); + + for (ch = 'a'; ch <= 'z'; ch++) + { + sprintf(cmd, "%s/usr/%c", BBSHOME, ch); + if (chdir(cmd) || !(dirp = opendir("."))) + exit(-1); + + sprintf(bakpath, "%s/%c", fpath, ch); + mkdir(bakpath, 0755); + + /* §â¦U¨Ï¥ÎªÌªº .ACCT ³£«þ¨©¨ì acct/*userid/ */ + while (de = readdir(dirp)) + { + ptr = de->d_name; + + if (ptr[0] > ' ' && ptr[0] != '.') + { + sprintf(cmd, "cp %s/%s %s/%s.ACCT", ptr, FN_ACCT, bakpath, ptr); + system(cmd); + } + } + closedir(dirp); + } + + exit(0); +} diff --git a/util/backup/backupbrd.c b/util/backup/backupbrd.c new file mode 100644 index 0000000..22518c4 --- /dev/null +++ b/util/backup/backupbrd.c @@ -0,0 +1,51 @@ +/*-------------------------------------------------------*/ +/* util/backupbrd.c ( NTHU MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ³Æ¥÷©Ò¦³¬ÝªO¸ê®Æ */ +/* create : 01/10/19 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +int +main() +{ + struct dirent *de; + DIR *dirp; + char *ptr; + char bakpath[128], cmd[256]; + time_t now; + struct tm *ptime; + + if (chdir(BBSHOME "/brd") || !(dirp = opendir("."))) + exit(-1); + + /* «Ø¥ß³Æ¥÷¸ô®|¥Ø¿ý */ + time(&now); + ptime = localtime(&now); + sprintf(bakpath, "%s/brd%02d%02d%02d", BAKPATH, ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday); + mkdir(bakpath, 0755); + + /* §ïÅÜÅv¨Ï ftp ¶ÇÀɤ£·|º|¶Ç */ + sprintf(cmd, "cp %s/%s %s/; chmod 644 %s/%s", BBSHOME, FN_BRD, bakpath, bakpath, FN_BRD); + system(cmd); + + /* §â¦U¬ÝªO¤À§OÀ£ÁY¦¨¤@ÓÀ£ÁYÀÉ */ + while (de = readdir(dirp)) + { + ptr = de->d_name; + + if (ptr[0] > ' ' && ptr[0] != '.') + { + sprintf(cmd, "tar cfz %s/%s.tgz %s", bakpath, ptr, ptr); + system(cmd); + } + } + closedir(dirp); + + exit(0); +} diff --git a/util/backup/backupgem.c b/util/backup/backupgem.c new file mode 100644 index 0000000..bcf49ec --- /dev/null +++ b/util/backup/backupgem.c @@ -0,0 +1,77 @@ +/*-------------------------------------------------------*/ +/* util/backupgem.c ( NTHU MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ³Æ¥÷©Ò¦³ºëµØ°Ï¸ê®Æ */ +/* create : 01/10/19 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +int +main() +{ + struct dirent *de; + DIR *dirp; + char *ptr; + char bakpath[128], cmd[256]; + time_t now; + struct tm *ptime; + + if (chdir(BBSHOME "/gem") || !(dirp = opendir("."))) + exit(-1); + + /* «Ø¥ß³Æ¥÷¸ô®|¥Ø¿ý */ + time(&now); + ptime = localtime(&now); + sprintf(bakpath, "%s/gem%02d%02d%02d", BAKPATH, ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday); + mkdir(bakpath, 0755); + + sprintf(cmd, "cp %s %s/", FN_DIR, bakpath); + system(cmd); + + /* §â 0~9 @ A~V ¤À§OÀ£ÁY¦¨¤@ÓÀ£ÁYÀÉ */ + while (de = readdir(dirp)) + { + ptr = de->d_name; + + /* ¬ÝªOªººëµØ°Ï¥t¥~³Æ¥÷ */ + if (!strcmp(ptr, "brd")) + continue; + + if (ptr[0] > ' ' && ptr[0] != '.') + { + sprintf(cmd, "tar cfz %s/%s.tgz %s", bakpath, ptr, ptr); + system(cmd); + } + } + closedir(dirp); + + + /* ³Æ¥÷¬ÝªO */ + + if (chdir(BBSHOME "/gem/brd") || !(dirp = opendir("."))) + exit(-1); + + /* «Ø¥ß³Æ¥÷¸ô®|¥Ø¿ý */ + sprintf(bakpath, "%s/brd", bakpath); + mkdir(bakpath, 0755); + + /* §â¦U¬ÝªO¤À§OÀ£ÁY¦¨¤@ÓÀ£ÁYÀÉ */ + while (de = readdir(dirp)) + { + ptr = de->d_name; + + if (ptr[0] > ' ' && ptr[0] != '.') + { + sprintf(cmd, "tar cfz %s/%s.tgz %s", bakpath, ptr, ptr); + system(cmd); + } + } + closedir(dirp); + + exit(0); +} diff --git a/util/backup/backupoth.c b/util/backup/backupoth.c new file mode 100644 index 0000000..cfe3eb3 --- /dev/null +++ b/util/backup/backupoth.c @@ -0,0 +1,40 @@ +/*-------------------------------------------------------*/ +/* util/backupoth.c ( YZU WindTopBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : ³Æ¥÷©Ò¦³¨Ï¥ÎªÌ¸ê®Æ */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +int +main() +{ + int i; + char *str; + char bakpath[128], cmd[256]; + time_t now; + struct tm *ptime; + char *folders[] = {"bin", "etc", "innd", "run", "src", NULL}; + + time(&now); + ptime = localtime(&now); + + sprintf(bakpath, "%s/oth%02d%02d%02d", BAKPATH, ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday); + mkdir(bakpath, 0755); + + for (i = 0; str = folders[i]; i++) + { + if (*str) + { + sprintf(cmd, "tar cfz %s/%s.tgz %s/%s", bakpath, str, BBSHOME, str); + system(cmd); + } + } + + exit(0); +} diff --git a/util/backup/backupusr.c b/util/backup/backupusr.c new file mode 100644 index 0000000..4b488c3 --- /dev/null +++ b/util/backup/backupusr.c @@ -0,0 +1,58 @@ +/*-------------------------------------------------------*/ +/* util/backupusr.c ( NTHU MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ³Æ¥÷©Ò¦³¨Ï¥ÎªÌ¸ê®Æ */ +/* create : 01/10/19 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +int +main() +{ + struct dirent *de; + DIR *dirp; + char *ptr, ch; + char fpath[128], bakpath[128], cmd[256]; + time_t now; + struct tm *ptime; + + time(&now); + ptime = localtime(&now); + /* «Ø¥ß³Æ¥÷¸ô®|¥Ø¿ý */ + sprintf(fpath, "%s/usr%02d%02d%02d", BAKPATH, ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday); + mkdir(fpath, 0755); + + /* §ïÅÜÅv¨Ï ftp ¶ÇÀɤ£·|º|¶Ç */ + sprintf(cmd, "cp %s/%s %s/; chmod 644 %s/%s", BBSHOME, FN_SCHEMA, fpath, fpath, FN_SCHEMA); + system(cmd); + + for (ch = 'a'; ch <= 'z'; ch++) + { + sprintf(cmd, "%s/usr/%c", BBSHOME, ch); + if (chdir(cmd) || !(dirp = opendir("."))) + exit(-1); + + sprintf(bakpath, "%s/%c", fpath, ch); + mkdir(bakpath, 0755); + + /* §â¦U¨Ï¥ÎªÌ¤À§OÀ£ÁY¦¨¤@ÓÀ£ÁYÀÉ */ + while (de = readdir(dirp)) + { + ptr = de->d_name; + + if (ptr[0] > ' ' && ptr[0] != '.') + { + sprintf(cmd, "tar cfz %s/%s.tgz %s", bakpath, ptr, ptr); + system(cmd); + } + } + closedir(dirp); + } + + exit(0); +} diff --git a/util/backup/restoreacct.c b/util/backup/restoreacct.c new file mode 100644 index 0000000..ee3a952 --- /dev/null +++ b/util/backup/restoreacct.c @@ -0,0 +1,58 @@ +/*-------------------------------------------------------*/ +/* util/restoreacct.c ( NTHU MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ÁÙì©Ò¦³¨Ï¥ÎªÌ .ACCT */ +/* create : 02/03/26 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + BAKPATH ¤U·|¦³«Ü¦h¤£¦P¤é´Á³Æ¥÷ªº .ACCT ¸ê®Æ¡A¨Ò¦p acct010101 acct010102 + §ân´_쪺¨º¥÷§ó¦W¬° acct (mv acct010101 acct) + °õ¦æ¥»µ{¦¡§Y¥i¥þ³¡´_ì + +#endif + + +#include "bbs.h" + + +int +main() +{ + struct dirent *de; + DIR *dirp; + char *ptr, ch; + char bakpath[128], cmd[256]; + + strcpy(bakpath, BAKPATH "/acct"); + if (chdir(bakpath)) + exit(-1); + + sprintf(cmd, "cp %s %s/%s; chmod 600 %s/%s", FN_SCHEMA, BBSHOME, FN_SCHEMA, BBSHOME, FN_SCHEMA); + system(cmd); + + for (ch = 'a'; ch <= 'z'; ch++) + { + sprintf(cmd, "%s/usr/%c", BBSHOME, ch); + if (chdir(cmd) || !(dirp = opendir("."))) + exit(-1); + + while (de = readdir(dirp)) + { + ptr = de->d_name; + + if (ptr[0] > ' ' && ptr[0] != '.') + { + sprintf(cmd, "cp %s/%c/%s.ACCT %s/%s", bakpath, ch, ptr, ptr, FN_ACCT); + system(cmd); + } + } + closedir(dirp); + } + + exit(0); +} diff --git a/util/backup/restorebrd.c b/util/backup/restorebrd.c new file mode 100644 index 0000000..a3914c9 --- /dev/null +++ b/util/backup/restorebrd.c @@ -0,0 +1,56 @@ +/*-------------------------------------------------------*/ +/* util/restorebrd.c ( NTHU MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ÁÙì©Ò¦³¬ÝªO¸ê®Æ */ +/* create : 01/10/26 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + BAKPATH ¤U·|¦³«Ü¦h¤£¦P¤é´Á³Æ¥÷ªº¬ÝªO¸ê®Æ¡A¨Ò¦p brd010101 brd010102 + §ân´_쪺¨º¥÷§ó¦W¬° brd (mv brd010101 brd) + °õ¦æ¥»µ{¦¡§Y¥i¥þ³¡´_ì + +#endif + + +#include "bbs.h" + + +int +main() +{ + struct dirent *de; + DIR *dirp; + char *ptr; + char brdpath[128], cmd[256]; + + if (chdir(BAKPATH "/brd") || !(dirp = opendir("."))) + exit(-1); + + sprintf(cmd, "cp %s %s/%s; chmod 600 %s/%s", FN_BRD, BBSHOME, FN_BRD, BBSHOME, FN_BRD); + system(cmd); + + strcpy(brdpath, BBSHOME "/brd"); + mkdir(brdpath, 0700); + + while (de = readdir(dirp)) + { + ptr = de->d_name; + + if (!strcmp(ptr, "BRD")) + continue; + + if (ptr[0] > ' ' && ptr[0] != '.') + { + sprintf(cmd, "tar xfz %s -C %s/", ptr, brdpath); + system(cmd); + } + } + closedir(dirp); + + exit(0); +} diff --git a/util/backup/restoregem.c b/util/backup/restoregem.c new file mode 100644 index 0000000..93cf871 --- /dev/null +++ b/util/backup/restoregem.c @@ -0,0 +1,80 @@ +/*-------------------------------------------------------*/ +/* util/restoregem.c ( NTHU MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ÁÙì©Ò¦³ºëµØ°Ï¸ê®Æ */ +/* create : 01/10/26 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + BAKPATH ¤U·|¦³«Ü¦h¤£¦P¤é´Á³Æ¥÷ªººëµØ°Ï¸ê®Æ¡A¨Ò¦p gem010101 gem010102 + §ân´_쪺¨º¥÷§ó¦W¬° gem (mv gem010101 gem) + °õ¦æ¥»µ{¦¡§Y¥i¥þ³¡´_ì + +#endif + + +#include "bbs.h" + + +int +main() +{ + struct dirent *de; + DIR *dirp; + char *ptr; + char gempath[128], cmd[256]; + + if (chdir(BAKPATH "/gem") || !(dirp = opendir("."))) + exit(-1); + + strcpy(gempath, BBSHOME "/gem"); + mkdir(gempath, 0700); + + sprintf(cmd, "cp %s %s/", FN_DIR, gempath); + system(cmd); + + /* §â 0~9 @ A~V ¤À§O¸ÑÀ£ÁY¦^¨Ó */ + while (de = readdir(dirp)) + { + ptr = de->d_name; + + /* ¬ÝªOªººëµØ°Ï¥t¥~¸ÑÀ£ÁY */ + if (!strcmp(ptr, "brd")) + continue; + + if (ptr[0] > ' ' && ptr[0] != '.') + { + sprintf(cmd, "tar xfz %s -C %s/", ptr, gempath); + system(cmd); + } + } + closedir(dirp); + + + /* ¦^´_¬ÝªO */ + + if (chdir(BAKPATH "/gem/brd") || !(dirp = opendir("."))) + exit(-1); + + strcat(gempath, "/brd"); + mkdir(gempath, 0700); + + /* §â¦U¬ÝªO¤À§O¸ÑÀ£ÁY¦^¨Ó */ + while (de = readdir(dirp)) + { + ptr = de->d_name; + + if (ptr[0] > ' ' && ptr[0] != '.') + { + sprintf(cmd, "tar xfz %s -C %s/", ptr, gempath); + system(cmd); + } + } + closedir(dirp); + + exit(0); +} diff --git a/util/backup/restoreusr.c b/util/backup/restoreusr.c new file mode 100644 index 0000000..d87ffe5 --- /dev/null +++ b/util/backup/restoreusr.c @@ -0,0 +1,64 @@ +/*-------------------------------------------------------*/ +/* util/restoreusr.c ( NTHU MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ÁÙì©Ò¦³¨Ï¥ÎªÌ¸ê®Æ */ +/* create : 01/10/26 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + BAKPATH ¤U·|¦³«Ü¦h¤£¦P¤é´Á³Æ¥÷ªº¨Ï¥ÎªÌ¸ê®Æ¡A¨Ò¦p usr010101 usr010102 + §ân´_쪺¨º¥÷§ó¦W¬° usr (mv usr010101 usr) + °õ¦æ¥»µ{¦¡§Y¥i¥þ³¡´_ì + +#endif + + +#include "bbs.h" + + +int +main() +{ + struct dirent *de; + DIR *dirp; + char *ptr, ch; + char usrpath[128], cmd[256]; + + if (chdir(BAKPATH "/usr")) + exit(-1); + + sprintf(cmd, "cp %s %s/%s; chmod 600 %s/%s", FN_SCHEMA, BBSHOME, FN_SCHEMA, BBSHOME, FN_SCHEMA); + system(cmd); + + strcpy(usrpath, BBSHOME "/usr"); + mkdir(usrpath, 0700); + + for (ch = 'a'; ch <= 'z'; ch++) + { + sprintf(cmd, "%s/usr/%c", BAKPATH, ch); + if (chdir(cmd) || !(dirp = opendir("."))) + exit(-1); + + sprintf(cmd, "%s/%c", usrpath, ch); + mkdir(cmd, 0700); + + /* §â¦U¨Ï¥ÎªÌ¤À§O¸ÑÀ£ÁY¦^¨Ó */ + while (de = readdir(dirp)) + { + ptr = de->d_name; + + if (ptr[0] > ' ' && ptr[0] != '.') + { + sprintf(cmd, "tar xfz %s -C %s/%c/", ptr, usrpath, ch); + system(cmd); + } + } + closedir(dirp); + } + + exit(0); +} diff --git a/util/bbsmail.c b/util/bbsmail.c new file mode 100644 index 0000000..55a9c05 --- /dev/null +++ b/util/bbsmail.c @@ -0,0 +1,330 @@ +/*-------------------------------------------------------*/ +/* util/bbsmail.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : ¥Ñ Internet ±H«Hµ¹ BBS ¯¸¤º¨Ï¥ÎªÌ */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#include <sysexits.h> + +#define ANTI_HTMLMAIL /* itoc.021014: ¾× html_mail */ +#define ANTI_NOTMYCHARSETMAIL /* itoc.030513: ¾× not-mycharset mail */ + + +static void +mailog(msg) + char *msg; +{ + FILE *fp; + + if (fp = fopen(BMTA_LOGFILE, "a")) + { + time_t now; + struct tm *p; + + time(&now); + p = localtime(&now); + fprintf(fp, "%02d/%02d %02d:%02d:%02d <bbsmail> %s\n", + p->tm_mon + 1, p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec, + msg); + fclose(fp); + } +} + + +/* ----------------------------------------------------- */ +/* user¡Gshm ³¡¥÷¶·»P cache.c ¬Û®e */ +/* ----------------------------------------------------- */ + + +static UCACHE *ushm; + + +static inline void +init_ushm() +{ + ushm = shm_new(UTMPSHM_KEY, sizeof(UCACHE)); +} + + +static inline void +bbs_biff(userid) + char *userid; +{ + UTMP *utmp, *uceil; + usint offset; + + offset = ushm->offset; + if (offset > (MAXACTIVE - 1) * sizeof(UTMP)) /* Thor.980805: ¤£µMcall¤£¨ì */ + offset = (MAXACTIVE - 1) * sizeof(UTMP); + + utmp = ushm->uslot; + uceil = (void *) utmp + offset; + + do + { + if (!str_cmp(utmp->userid, userid)) + utmp->status |= STATUS_BIFF; + } while (++utmp <= uceil); +} + + +/* ----------------------------------------------------- */ +/* ¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static int +mail2bbs(userid) + char *userid; +{ + HDR hdr; + char buf[512], title[256], sender[256], owner[256], nick[256], folder[64]; + char *str, *ptr, decode; + int fd; + FILE *fp; + + /* check if the userid is in our bbs now */ + + usr_fpath(folder, userid, NULL); + if (!dashd(folder)) + { + sprintf(buf, "BBS user <%s> not existed", userid); + mailog(buf); + return EX_NOUSER; + } + strcat(folder, "/" FN_DIR); + + if (rec_num(folder, sizeof(HDR)) >= MAX_BBSMAIL) + { + sprintf(buf, "BBS user <%s> over-spammed", userid); + mailog(buf); + return EX_NOUSER; + } + + /* parse header */ + + title[0] = sender[0] = owner[0] = nick[0] = '\0'; + decode = 0; + + while (fgets(buf, sizeof(buf), stdin)) + { +start: + if (!memcmp(buf, "From", 4)) + { + if ((str = strchr(buf, '<')) && (ptr = strrchr(str, '>'))) + { + if (str[-1] == ' ') + str[-1] = '\0'; + + if (strchr(++str, '@')) + *ptr = '\0'; + else /* ¥Ñ local host ±H«H */ + strcpy(ptr, "@" MYHOSTNAME); + + if (ptr = (char *) strchr(buf, ' ')) + { + while (*++ptr == ' ') + ; + } + + if (ptr && *ptr == '"') + { + char *right; + + if (right = strrchr(++ptr, '"')) + *right = '\0'; + + str_decode(ptr); + sprintf(sender, "%s (%s)", str, ptr); + strcpy(nick, ptr); + strcpy(owner, str); + } + else /* Thor.980907: ¨S¦³ finger name, ¯S§O³B²z */ + { + strcpy(sender, str); + strcpy(owner, str); + } + } + else + { + strtok(buf, " \t\n\r"); + strcpy(sender, (char *) strtok(NULL, " \t\n\r")); + + if (!strchr(sender, '@')) /* ¥Ñ local host ±H«H */ + strcat(sender, "@" MYHOSTNAME); + strcpy(owner, sender); + } + + /* itoc.040804: ¾×«H¶Â¥Õ¦W³æ */ + str_lower(buf, owner); /* «O«ùì email ªº¤j¤p¼g */ + if (ptr = (char *) strchr(buf, '@')) + { + *ptr++ = '\0'; + + if (!acl_has(MAIL_ACLFILE, buf, ptr) || + acl_has(UNMAIL_ACLFILE, buf, ptr) > 0) + { + sprintf(buf, "SPAM %s", sender); + mailog(buf); + return EX_NOUSER; + } + } + } + + else if (!memcmp(buf, "Subject: ", 9)) + { + str_ansi(title, buf + 9, sizeof(title)); + /* str_decode(title); */ + /* LHD.051106: Y¥i¯à¸g RFC 2047 QP encode «h¦³¥i¯à¦h¦æ subject */ + if (strstr(buf + 9, "=?")) + { + while (fgets(buf, sizeof(buf), stdin)) + { + if (buf[0] == ' ' || buf[0] == '\t') /* ²Ä¤G¦æ¥H«á·|¥HªÅ¥Õ©Î TAB ¶}ÀY */ + str_ansi(title + strlen(title), strstr(buf, "=?"), sizeof(title)); + else + { + str_decode(title); + goto start; + } + } + } + } + + else if (!memcmp(buf, "Content-Type: ", 14)) + { + str = buf + 14; + +#ifdef ANTI_HTMLMAIL + /* ¤@¯ë BBS ¨Ï¥ÎªÌ³q±`¥u±H¤å¦r¶l¥ó©Î¬O±q¨ä¥L BBS ¯¸±H¤å³¹¨ì¦Û¤vªº«H½c + ¦Ó¼s§i«H¥ó³q±`¬O html ®æ¦¡©Î¬O¸Ì±¦³§¨±a¨ä¥LÀÉ®× + §Q¥Î¶l¥óªºÀÉÀY¦³ Content-Type: ªºÄݩʧⰣ¤F text/plain (¤å¦r¶l¥ó) ªº«H¥ó³£¾×¤U¨Ó */ + if (*str != '\0' && str_ncmp(str, "text/plain", 10)) + { + sprintf(buf, "ANTI-HTML [%d] %s => %s", getppid(), sender, userid); + mailog(buf); + return EX_NOUSER; + } +#endif + +#ifdef ANTI_NOTMYCHARSETMAIL + { + char charset[32]; + mm_getcharset(str, charset, sizeof(charset)); + if (str_cmp(charset, MYCHARSET) && str_cmp(charset, "us-ascii")) + { + sprintf(buf, "ANTI-NONMYCHARSET [%d] %s => %s", getppid(), sender, userid); + mailog(buf); + return EX_NOUSER; + } + } +#endif + } + + else if (!memcmp(buf, "Content-Transfer-Encoding: ", 27)) + { + mm_getencode(buf + 27, &decode); + } + + else if (buf[0] == '\n') + { + break; + } + } + + /* allocate a file for the new mail */ + + fd = hdr_stamp(folder, 0, &hdr, buf); + hdr.xmode = MAIL_INCOME; + + str_ncpy(hdr.owner, owner, sizeof(hdr.owner)); + str_ncpy(hdr.nick, nick, sizeof(hdr.nick)); + if (!title[0]) + sprintf(title, "¨Ó¦Û %.64s", sender); + str_ncpy(hdr.title, title, sizeof(hdr.title)); + + /* copy the stdin to the specified file */ + + fp = fdopen(fd, "w"); + + fprintf(fp, "§@ªÌ: %s\n¼ÐÃD: %s\n®É¶¡: %s\n\n", + sender, title, Btime(&hdr.chrono)); + + while (fgets(buf, sizeof(buf), stdin)) + { + if (decode && ((fd = mmdecode(buf, decode, buf)) > 0)) + buf[fd] = '\0'; + + fputs(buf, fp); + } + + fclose(fp); + + /* append the record to the .DIR */ + + rec_add(folder, &hdr, sizeof(HDR)); + + bbs_biff(userid); /* itoc.021113: ³qª¾ user ¦³·s«H¥ó */ + + /* Thor.980827: ¥[¤W parent process id¡A¥H«K§ì©U§£«H */ + sprintf(buf, "[%d] %s => %s", getppid(), sender, userid); + mailog(buf); + + return 0; +} + + +static void +sig_catch(sig) + int sig; +{ + char buf[512]; + + while (fgets(buf, sizeof(buf), stdin)) + ; + sprintf(buf, "signal [%d]", sig); + mailog(buf); + exit(0); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + char buf[512]; + + /* argv[1] is userid in bbs */ + + if (argc < 2) + { + printf("Usage:\t%s <bbs_userid>\n", argv[0]); + exit(-1); + } + + setgid(BBSGID); + setuid(BBSUID); + chdir(BBSHOME); + + signal(SIGBUS, sig_catch); + signal(SIGSEGV, sig_catch); + signal(SIGPIPE, sig_catch); + + init_ushm(); + str_lower(buf, argv[1]); /* §â userid ´«¦¨¤p¼g */ + + if (mail2bbs(buf)) + { + /* eat mail queue */ + while (fgets(buf, sizeof(buf), stdin)) + ; + } + exit(0); +} diff --git a/util/bquota.c b/util/bquota.c new file mode 100644 index 0000000..505bbc7 --- /dev/null +++ b/util/bquota.c @@ -0,0 +1,385 @@ +/*-------------------------------------------------------*/ +/* util/bquota.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : BBS user quota maintain & mail expire */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ +/* syntax : bquota */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#ifdef OVERDUE_MAILDEL + +#include <sys/resource.h> + +#undef VERBOSE +#define LOG_FILE "run/bquota.log" + + +#define MAX_SIZE 20000 /* ¶W¹L 20k bytes ´N§R°£ */ + + +/* itoc.011002.µù¸Ñ: XXXX_DUE ¦b config.h ¤¤©w¸q */ +/* itoc.011002: ¦³¥²n§â´»°²ªº bquota ©µªø®É¶¡¶Ü¡H */ + +static time_t file_due; +static time_t mail_due; +static time_t mark_due; + + +static FILE *flog; + + +/* ----------------------------------------------------- */ +/* synchronize folder & files */ +/* ----------------------------------------------------- */ + + +#define SYNC_DB_SIZE 1024 + + +typedef struct +{ + time_t chrono; + char exotic; +} SyncMail; + + +static SyncMail *xlist; +static int xsize; + + +static int +sync_cmp(s1, s2) + SyncMail *s1, *s2; +{ + return s1->chrono - s2->chrono; +} + + +static int +bquota(userid) + char *userid; +{ + HDR hdr; + char *fname, *str, fpath[80], fnew[80], fold[80]; + int bonus, cc, count, xmode; + time_t due, chrono; + FILE *fpr, *fpw; + struct stat st; + DIR *dirp; + struct dirent *de; + + SyncMail *tlist, *tsync; + int tsize; + + bonus = 0; + sprintf(fpath, "%s/@", userid); + + if (!(dirp = opendir(fpath))) + { + fprintf(flog, "dir: %s\n", fpath); + rmdir(userid); + return bonus; + } + + fname = strchr(fpath, '@') + 1; + *fname++ = '/'; + count = 0; + + tlist = xlist; + tsize = xsize; + + while (de = readdir(dirp)) + { + str = de->d_name; + cc = *str; + if (cc == '.') + continue; + + strcpy(fname, str); + + if (cc != '@') + { + unlink(fpath); +#ifdef VERBOSE + fprintf(flog, "NAME: %s\n", fpath); +#endif + continue; + } + + chrono = chrono32(str); + + if (chrono < mark_due) + { +#ifdef VERBOSE + fprintf(flog, "OLD : %s\n", fpath); +#endif + unlink(fpath); + bonus++; + continue; + } + + if (chrono < file_due) + { + if (!stat(fpath, &st) && (st.st_size >= MAX_SIZE || st.st_size <= 0)) + { +#ifdef VERBOSE + fprintf(flog, "BIG : %s\n", fpath); +#endif + unlink(fpath); + bonus++; + continue; + } + } + + if (count >= tsize) + { + xsize = (tsize += count); + xlist = tlist = (SyncMail *) realloc(tlist, sizeof(SyncMail) * tsize); + } + tlist[count].chrono = chrono; + tlist[count].exotic = 1; + count++; + } + closedir(dirp); + + if (count > 1) + qsort(tlist, count, sizeof(SyncMail), sync_cmp); + + sprintf(fold, "%s/.DIR", userid); + + if (fpr = fopen(fold, "r")) + { + cc = 0; + if (fpw = (FILE *) f_new(fold, fnew)) + { + while (fread(&hdr, sizeof(HDR), 1, fpr) == 1) + { + tsync = (SyncMail *) bsearch(&hdr.chrono, + tlist, count, sizeof(SyncMail), sync_cmp); + + if (!tsync) + continue; + + tsync->exotic = 0; + + xmode = hdr.xmode; + + if (xmode & MAIL_MARKED) + due = mark_due; + else + due = mail_due; + + if (hdr.chrono < due) + { + strcpy(fname, hdr.xname); + unlink(fpath); + bonus++; +#ifdef VERBOSE + fprintf(flog, "DUE : %s\n", fpath); +#endif + } + else + { + if (fwrite(&hdr, sizeof(HDR), 1, fpw) != 1) + { + cc = count = -1; + break; + } + cc++; + } + } + + fclose(fpw); + if (count < 0) + unlink(fnew); + } + fclose(fpr); + + if (cc > 0) + rename(fnew, fold); + else + unlink(fold); + } + + *fname++ = '@'; + for (cc = 0; cc < count; cc++) + { + if (tlist[cc].exotic) + { + archiv32(tlist[cc].chrono, fname); + unlink(fpath); + bonus++; +#ifdef VERBOSE + fprintf(flog, "SYNC: %s\n", fpath); +#endif + } + } + + /* maintain userid/... */ + + fname -= 3; + *fname = '\0'; + if (dirp = opendir(fpath)) + { + due = file_due; + while (de = readdir(dirp)) + { + str = de->d_name; + + if (str[0] == 'b' && str[1] == 'u') /* buf.? */ + { + strcpy(fname, str); + + stat(fpath, &st); + if ((st.st_mtime < due) || (st.st_size > 3000) || (st.st_size <= 0)) + { +#ifdef VERBOSE + fprintf(flog, "FILE: %s\n", fpath); +#endif + unlink(fpath); + bonus++; + continue; + } + } + else if (!strcmp(str, "log")) + { + strcpy(fname, str); + stat(fpath, &st); + if ((st.st_mtime < due) || (st.st_size <= 0)) + { + unlink(fpath); + bonus++; + continue; + } + +#define ULOG_SIZE 3072 + + if ((st.st_size >= ULOG_SIZE) && (cc = open(fpath, O_RDWR)) >= 0) + { + char buf[ULOG_SIZE]; + + lseek(cc, st.st_size - ULOG_SIZE, 0); + count = read(cc, buf, sizeof(buf)); + if (str = strchr(buf, '\n')) + { + str++; + count -= str - buf; + lseek(cc, 0, 0); + write(cc, str, count); + ftruncate(cc, count); + bonus++; + } + close(cc); + } + +#undef ULOG_SIZE + + continue; + } + } + + closedir(dirp); + } + + return bonus; +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + DIR *dirp; + struct dirent *de; + char *fname, fpath[64]; + time_t start, end; + int bonus, visit; + struct rlimit rl; + + setuid(BBSUID); + setgid(BBSGID); + + chdir(BBSHOME); + + rl.rlim_cur = rl.rlim_max = 0; + setrlimit(RLIMIT_CORE, &rl); + time(&start); + + if (argc == 2 && (argc = argv[1][0]) >= 'a' && argc <= 'z') + { + flog = stderr; + } + else + { + flog = fopen(LOG_FILE, "w"); + argc = 'a' + (start / 86400) % 26; /* ¨C¹j 26 ¤Ñ bquota ¤@¦¸ */ + } + + /* visit the second hierarchy */ + + sprintf(fpath, "usr/%c", argc); + fprintf(flog, "# visit: %s\n\n", fpath); + + if (chdir(fpath) || (!(dirp = opendir(".")))) + { + fprintf(flog, "## unable to enter user home\n"); + fclose(flog); + exit(-1); + } + + /* traverse user home */ + + file_due = start - FILE_DUE * 86400; + mail_due = start - MAIL_DUE * 86400; + mark_due = start - MARK_DUE * 86400; + + xlist = (SyncMail *) malloc(SYNC_DB_SIZE * sizeof(SyncMail)); + xsize = SYNC_DB_SIZE; + + bonus = 0; + visit = 0; + + fprintf(flog, "\nbegin\n"); + + while (de = readdir(dirp)) + { + fname = de->d_name; + if (*fname != '.' && *fname > ' ') + { +#ifdef VERBOSE + fprintf(flog, "\n[%s]\n", fname); +#endif + bonus += bquota(fname); + visit++; + } + } + closedir(dirp); + + time(&end); + fprintf(flog, "# ¶}©l®É¶¡¡G%s\n", Btime(&start)); + fprintf(flog, "# µ²§ô®É¶¡¡G%s\n", Btime(&end)); + end -= start; + start = end % 60; + end /= 60; + fprintf(flog, "# Á`p¯Ó®É¡G%d:%d:%d\n", end / 60, end % 60, start); + fprintf(flog, "# µù¥U¤H¼Æ¡G%d\n", visit); + fprintf(flog, "# ²M°£ÀɮסG%d\n", bonus); + fclose(flog); + exit(0); +} + +#else +int +main() +{ + printf("You should define OVERDUE_MAILDEL first.\n"); + return -1; +} +#endif /* HAVE_NETTOOL */ diff --git a/util/brdmail.c b/util/brdmail.c new file mode 100644 index 0000000..1656431 --- /dev/null +++ b/util/brdmail.c @@ -0,0 +1,334 @@ +/*-------------------------------------------------------*/ +/* util/brdmail.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : ¥Ñ Internet ±H«Hµ¹ BBS ¯¸¤º¬ÝªO¡Aµø¬° post */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#include <sysexits.h> + +#define ANTI_HTMLMAIL /* itoc.021014: ¾× html_mail */ +#define ANTI_NOTMYCHARSETMAIL /* itoc.030513: ¾× not-mycharset mail */ + + +static void +mailog(msg) + char *msg; +{ + FILE *fp; + + if (fp = fopen(BMTA_LOGFILE, "a")) + { + time_t now; + struct tm *p; + + time(&now); + p = localtime(&now); + fprintf(fp, "%02d/%02d %02d:%02d:%02d <brdmail> %s\n", + p->tm_mon + 1, p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec, + msg); + fclose(fp); + } +} + + +/* ----------------------------------------------------- */ +/* board¡Gshm ³¡¥÷¶·»P cache.c ¬Û®e */ +/* ----------------------------------------------------- */ + + +static BCACHE *bshm; + + +static void +init_bshm() +{ + /* itoc.030727: ¦b¶}±Ò bbsd ¤§«e¡AÀ³¸Ó´Nn°õ¦æ¹L account¡A + ©Ò¥H bshm À³¸Ó¤w³]©w¦n */ + + bshm = shm_new(BRDSHM_KEY, sizeof(BCACHE)); + + if (bshm->uptime <= 0) /* bshm ¥¼³]©w§¹¦¨ */ + exit(0); +} + + +static BRD * +brd_get(bname) + char *bname; +{ + BRD *bhdr, *tail; + + bhdr = bshm->bcache; + tail = bhdr + bshm->number; + do + { + if (!str_cmp(bname, bhdr->brdname)) + return bhdr; + } while (++bhdr < tail); + return NULL; +} + + +/* ----------------------------------------------------- */ +/* ¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static int +mail2brd(brd) + BRD *brd; +{ + HDR hdr; + char buf[512], title[256], sender[256], owner[256], nick[256], folder[64]; + char *str, *ptr, decode, *brdname; + int fd; + FILE *fp; + + /* check if the brdname is in our bbs now */ + + brdname = brd->brdname; + + if (brd->battr & BRD_LOCAL){ + sprintf(buf, "BBS brd <%s> denied", brdname); + mailog(buf); + return EX_NOUSER; + } + + brd_fpath(folder, brdname, NULL); + if (!dashd(folder)) + { + sprintf(buf, "BBS brd <%s> not existed", brdname); + mailog(buf); + return EX_NOUSER; + } + strcat(folder, "/" FN_DIR); + + /* parse header */ + + title[0] = sender[0] = owner[0] = nick[0] = '\0'; + decode = 0; + + while (fgets(buf, sizeof(buf), stdin)) + { +start: + if (!memcmp(buf, "From", 4)) + { + if ((str = strchr(buf, '<')) && (ptr = strrchr(str, '>'))) + { + if (str[-1] == ' ') + str[-1] = '\0'; + + if (strchr(++str, '@')) + *ptr = '\0'; + else /* ¥Ñ local host ±H«H */ + strcpy(ptr, "@" MYHOSTNAME); + + if (ptr = (char *) strchr(buf, ' ')) + { + while (*++ptr == ' ') + ; + } + + if (ptr && *ptr == '"') + { + char *right; + + if (right = strrchr(++ptr, '"')) + *right = '\0'; + + str_decode(ptr); + sprintf(sender, "%s (%s)", str, ptr); + strcpy(nick, ptr); + strcpy(owner, str); + } + else /* Thor.980907: ¨S¦³ finger name, ¯S§O³B²z */ + { + strcpy(sender, str); + strcpy(owner, str); + } + } + else + { + strtok(buf, " \t\n\r"); + strcpy(sender, (char *) strtok(NULL, " \t\n\r")); + + if (!strchr(sender, '@')) /* ¥Ñ local host ±H«H */ + strcat(sender, "@" MYHOSTNAME); + strcpy(owner, sender); + } + + /* itoc.040804: ¾×«H¶Â¥Õ¦W³æ */ + str_lower(buf, owner); /* «O«ùì email ªº¤j¤p¼g */ + if (ptr = (char *) strchr(buf, '@')) + { + *ptr++ = '\0'; + + if (!acl_has(MAIL_ACLFILE, buf, ptr) || + acl_has(UNMAIL_ACLFILE, buf, ptr) > 0) + { + sprintf(buf, "SPAM %s", sender); + mailog(buf); + return EX_NOUSER; + } + } + } + + else if (!memcmp(buf, "Subject: ", 9)) + { + str_ansi(title, buf + 9, sizeof(title)); + /* str_decode(title); */ + /* LHD.051106: Y¥i¯à¸g RFC 2047 QP encode «h¦³¥i¯à¦h¦æ subject */ + if (strstr(buf + 9, "=?")) + { + while (fgets(buf, sizeof(buf), stdin)) + { + if (buf[0] == ' ' || buf[0] == '\t') /* ²Ä¤G¦æ¥H«á·|¥HªÅ¥Õ©Î TAB ¶}ÀY */ + str_ansi(title + strlen(title), strstr(buf, "=?"), sizeof(title)); + else + { + str_decode(title); + goto start; + } + } + } + } + + else if (!memcmp(buf, "Content-Type: ", 14)) + { + str = buf + 14; + +#ifdef ANTI_HTMLMAIL + /* ¤@¯ë BBS ¨Ï¥ÎªÌ³q±`¥u±H¤å¦r¶l¥ó©Î¬O±q¨ä¥L BBS ¯¸±H¤å³¹¨ì¦Û¤vªº«H½c + ¦Ó¼s§i«H¥ó³q±`¬O html ®æ¦¡©Î¬O¸Ì±¦³§¨±a¨ä¥LÀÉ®× + §Q¥Î¶l¥óªºÀÉÀY¦³ Content-Type: ªºÄݩʧⰣ¤F text/plain (¤å¦r¶l¥ó) ªº«H¥ó³£¾×¤U¨Ó */ + if (*str != '\0' && str_ncmp(str, "text/plain", 10)) + { + sprintf(buf, "ANTI-HTML [%d] %s => %s", getppid(), sender, brdname); + mailog(buf); + return EX_NOUSER; + } +#endif + +#ifdef ANTI_NOTMYCHARSETMAIL + { + char charset[32]; + mm_getcharset(str, charset, sizeof(charset)); + if (str_cmp(charset, MYCHARSET) && str_cmp(charset, "us-ascii")) + { + sprintf(buf, "ANTI-NONMYCHARSET [%d] %s => %s", getppid(), sender, brdname); + mailog(buf); + return EX_NOUSER; + } + } +#endif + } + + else if (!memcmp(buf, "Content-Transfer-Encoding: ", 27)) + { + mm_getencode(buf + 27, &decode); + } + + else if (buf[0] == '\n') + { + break; + } + } + + /* allocate a file for the new post */ + + fd = hdr_stamp(folder, 'A', &hdr, buf); + hdr.xmode = POST_INCOME; + + str_ncpy(hdr.owner, owner, sizeof(hdr.owner)); + str_ncpy(hdr.nick, nick, sizeof(hdr.nick)); + if (!title[0]) + sprintf(title, "¨Ó¦Û %.64s", sender); + str_ncpy(hdr.title, title, sizeof(hdr.title)); + + /* copy the stdin to the specified file */ + + fp = fdopen(fd, "w"); + + fprintf(fp, "µo«H¤H: %.50s ¬ÝªO: %s\n¼Ð ÃD: %.72s\nµo«H¯¸: %s\n\n", + sender, brdname, title, Btime(&hdr.chrono)); + + while (fgets(buf, sizeof(buf), stdin)) + { + if (decode && ((fd = mmdecode(buf, decode, buf)) > 0)) + buf[fd] = '\0'; + + fputs(buf, fp); + } + + fclose(fp); + + /* append the record to the .DIR */ + + rec_bot(folder, &hdr, sizeof(HDR)); + + /* amaki.040311: nÅýclass_item()§ó·s¥Î */ + brd->btime = -1; + + /* Thor.0827: ¥[¤W parent process id¡A¥H«K§ì©U§£«H */ + sprintf(buf, "[%d] %s => %s", getppid(), sender, brdname); + mailog(buf); + + return 0; +} + + +static void +sig_catch(sig) + int sig; +{ + char buf[512]; + + while (fgets(buf, sizeof(buf), stdin)) + ; + sprintf(buf, "signal [%d]", sig); + mailog(buf); + exit(0); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + char buf[512]; + BRD *brd; + + /* argv[1] is brdname in bbs */ + + if (argc < 2) + { + printf("Usage:\t%s <bbs_brdname>\n", argv[0]); + exit(-1); + } + + setgid(BBSGID); + setuid(BBSUID); + chdir(BBSHOME); + + signal(SIGBUS, sig_catch); + signal(SIGSEGV, sig_catch); + signal(SIGPIPE, sig_catch); + + init_bshm(); + brd = brd_get(argv[1]); + + if (!brd || mail2brd(brd)) + { + /* eat mail queue */ + while (fgets(buf, sizeof(buf), stdin)) + ; + } + exit(0); +} diff --git a/util/camera.c b/util/camera.c new file mode 100644 index 0000000..079b9e9 --- /dev/null +++ b/util/camera.c @@ -0,0 +1,395 @@ +/*-------------------------------------------------------*/ +/* util/camera.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : «Ø¥ß [°ÊºA¬ÝªO] cache */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +static char *list[] = /* src/include/struct.h */ +{ + "opening.0", /* FILM_OPENING0 */ + "opening.1", /* FILM_OPENING1 */ + "opening.2", /* FILM_OPENING2 */ + "goodbye", /* FILM_GOODBYE */ + "notify", /* FILM_NOTIFY */ + "mquota", /* FILM_MQUOTA */ + "mailover", /* FILM_MAILOVER */ + "mgemover", /* FILM_MGEMOVER */ + "birthday", /* FILM_BIRTHDAY */ + "apply", /* FILM_APPLY */ + "justify", /* FILM_JUSTIFY */ + "re-reg", /* FILM_REREG */ + "e-mail", /* FILM_EMAIL */ + "newuser", /* FILM_NEWUSER */ + "tryout", /* FILM_TRYOUT */ + "post", /* FILM_POST */ + NULL /* FILM_MOVIE */ +}; + + +static void +str_strip(str) /* itoc.060417: ±N°ÊºA¬ÝªO¨C¦Cªº¼e«×Õt¦b SCR_WIDTH */ + char *str; +{ + int ch, ansi, len; + + /* Y°ÊºA¬ÝªO¦³¤@¦Cªº¼e«×¶W¹L SCR_WIDTH¡A·|Åã¥Ü¤G¦C¡A³y¦¨±Æª©¿ù»~ (¥Dn¬OÂIºqªº³¡¤À) + ©Ò¥H´N°®¯Ü§â¶W¹L SCR_WIDTH ªº³¡¤À§R°£ (¦b¦¹¤£¦Ò¼{¼e¿Ã¹õ) */ + /* Y¥»¦C¤¤¦³ \033*s ©Î \033*n¡AÅã¥Ü¥X¨Ó·|§óªø¡A©Ò¥Hn¯S§O³B²z */ + + ansi = len = 0; + while (ch = *str++) + { + if (ch == '\n') + { + break; + } + else if (ch == '\033') + { + ansi = 1; + } + else if (ansi) + { + if (ch == '*') /* KEY_ESC + * + s/n ¨q¥X ID/username¡A¦Ò¼{³Ì¤jªø«× */ + { + ansi = 0; + len += BMAX(IDLEN, UNLEN) - 1; + if (len > SCR_WIDTH) + { + *str = '\0'; + break; + } + } + else if ((ch < '0' || ch > '9') && ch != ';' && ch != '[') + ansi = 0; + } + else + { + if (++len > SCR_WIDTH) + { + *str = '\0'; + break; + } + } + } +} + + +static FCACHE image; +static int number; /* ¥Ø«e¤w mirror ´X½g¤F */ +static int total; /* ¥Ø«e¤w mirror ´X byte ¤F */ + + +static int /* 1:¦¨¥\ 0:¤w¶W¹L½g¼Æ©Î®e¶q */ +mirror(fpath, line) + char *fpath; + int line; /* 0:¨t²Î¤å¥ó¡A¤£¨î¦C¼Æ !=0:°ÊºA¬ÝªO¡Aline ¦C */ +{ + int size, i; + char buf[FILM_SIZ]; + char tmp[ANSILINELEN]; + struct stat st; + FILE *fp; + + /* Y¤w¸g¶W¹L³Ì¤j½g¼Æ¡A«h¤£¦AÄ~Äò mirror */ + if (number >= MOVIE_MAX - 1) + return 0; + + if (stat(fpath, &st)) + size = -1; + else + size = st.st_size; + + if (size > 0 && size < FILM_SIZ && (fp = fopen(fpath, "r"))) + { + size = i = 0; + while (fgets(tmp, ANSILINELEN, fp)) + { + str_strip(tmp); + + strcpy(buf + size, tmp); + size += strlen(tmp); + + if (line) + { + /* °ÊºA¬ÝªO¡A³Ì¦h line ¦C */ + if (++i >= line) + break; + } + } + fclose(fp); + + if (i != line) + { + /* °ÊºA¬ÝªO¡AY¤£¨ì line ¦C¡An¶ñº¡ line ¦C */ + for (; i < line; i++) + { + buf[size] = '\n'; + size++; + } + buf[size] = '\0'; + } + } + + if (size <= 0 || size >= FILM_SIZ) + { + if (line) /* ¦pªG¬O °ÊºA¬ÝªO/ÂIºq ¯ÊÀɮסA´N¤£ mirror */ + return 1; + + /* ¦pªG¬O¨t²Î¤å¥ó¥X¿ùªº¸Ü¡An¸É¤W¥h */ + sprintf(buf, "½Ð§i¶D¯¸ªøÀÉ®× %s ¿ò¥¢©Î¬O¹L¤j", fpath); + size = strlen(buf); + } + + size++; /* Thor.980804: +1 ±Nµ²§Àªº '\0' ¤]ºâ¤J */ + + i = total + size; + if (i >= MOVIE_SIZE) /* Y¥[¤J³o½g·|¶W¹L¥þ³¡®e¶q¡A«h¤£ mirror */ + return 0; + + memcpy(image.film + total, buf, size); + image.shot[++number] = total = i; + + return 1; +} + + +static void +do_gem(folder) /* itoc.011105: §â¬ÝªO/ºëµØ°Ïªº¤å³¹¦¬¶i movie */ + char *folder; /* index ¸ô®| */ +{ + char fpath[64]; + FILE *fp; + HDR hdr; + + if (fp = fopen(folder, "r")) + { + while (fread(&hdr, sizeof(HDR), 1, fp) == 1) + { + if (hdr.xmode & (GEM_RESTRICT | GEM_RESERVED | GEM_BOARD)) /* ¨î¯Å¡B¬ÝªO ¤£©ñ¤J movie ¤¤ */ + continue; + + hdr_fpath(fpath, folder, &hdr); + + if (hdr.xmode & GEM_FOLDER) /* ¹J¨ì¨÷©v«h°j°é¶i¥h¦¬ movie */ + { + do_gem(fpath); + } + else /* plain text */ + { + if (!mirror(fpath, MOVIE_LINES)) + break; + } + } + fclose(fp); + } +} + + +static void +lunar_calendar(key, now, ptime) /* itoc.050528: ¥Ñ¶§¾äºâ¹A¾ä¤é´Á */ + char *key; + time_t *now; + struct tm *ptime; +{ +#if 0 /* Table ªº·N¸q */ + + (1) "," ¥u¬O¤À¹j¡A¤è«Kµ¹¤H¾\Ū¦Ó¤w + (2) «e 12 Ó byte ¤À§O¥Nªí¹A¾ä 1-12 ¤ë¬°¤j¤ë©Î¬O¤p¤ë¡C"L":¤j¤ë¤T¤Q¤Ñ¡A"-":¤p¤ë¤G¤Q¤E¤Ñ + (3) ²Ä 14 Ó byte ¥Nªí¤µ¦~¹A¾ä¶|¤ë¡C"X":µL¶|¤ë¡A"123456789:;<" ¤À§O¥Nªí¹A¾ä 1-12 ¬O¶|¤ë + (4) ²Ä 16-20 Ó bytes ¥Nªí¤µ¦~¹A¾ä·s¦~¬Oþ¤Ñ¡C¨Ò¦p "02:15" ªí¥Ü¶§¾ä¤G¤ë¤Q¤¤é¬O¹A¾ä·s¦~ + +#endif + + #define TABLE_INITAIL_YEAR 2005 + #define TABLE_FINAL_YEAR 2011 + + char Table[TABLE_FINAL_YEAR - TABLE_INITAIL_YEAR + 1][21] = + { + "-L-L-LL-L-L-,X,02:09", /* 2005 Âû¦~ */ + "L-L-L-L-LL-L,7,01:29", /* 2006 ª¯¦~ */ + "--L--L-LLL-L,X,02:18", /* 2007 ½Þ¦~ */ + "L--L--L-LL-L,X,02:07", /* 2008 ¹«¦~ */ + "LL--L--L-L-L,5,01:26", /* 2009 ¤û¦~ */ + "L-L-L--L-L-L,X,02:14", /* 2010 ªê¦~ */ + "L-LL-L--L-L-,X,02:03", /* 2011 ¨ß¦~ */ + }; + + char year[21]; + + time_t nyd; /* ¤µ¦~ªº¹A¾ä·s¦~ */ + struct tm ntime; + + int i; + int Mon, Day; + int leap; /* 0:¥»¦~µL¶|¤ë */ + + /* ¥ý§ä¥X¤µ¤Ñ¬O¹A¾äþ¤@¦~ */ + + memcpy(&ntime, ptime, sizeof(ntime)); + + for (i = TABLE_FINAL_YEAR - TABLE_INITAIL_YEAR; i >= 0; i--) + { + strcpy(year, Table[i]); + ntime.tm_year = TABLE_INITAIL_YEAR - 1900 + i; + ntime.tm_mday = atoi(year + 18); + ntime.tm_mon = atoi(year + 15) - 1; + nyd = mktime(&ntime); + + if (*now >= nyd) + break; + } + + /* ¦A±q¹A¾ä¥¿¤ëªì¤@¶}©l¼Æ¨ì¤µ¤Ñ */ + + leap = (year[13] == 'X') ? 0 : 1; + + Mon = Day = 1; + for (i = (*now - nyd) / 86400; i > 0; i--) + { + if (++Day > (year[Mon - 1] == 'L' ? 30: 29)) + { + Mon++; + Day = 1; + + if (leap == 2) + { + leap = 0; + Mon--; + year[Mon - 1] = '-'; /* ¶|¤ë¥²¤p¤ë */ + } + else if (year[13] == Mon + '0') + { + if (leap == 1) /* ¤U¤ë¬O¶|¤ë */ + leap++; + } + } + } + + sprintf(key, "%02d:%02d", Mon, Day); +} + + +static char * +do_today() +{ + FILE *fp; + char buf[80], *ptr1, *ptr2, *ptr3, *today; + char key1[6]; /* mm/dd: ¶§¾ä mm¤ëdd¤é */ + char key2[6]; /* mm/#A: ¶§¾ä mm¤ëªº²Ä#Ó¬P´ÁA */ + char key3[6]; /* MM\DD: ¹A¾ä MM¤ëDD¤é */ + time_t now; + struct tm *ptime; + static char feast[64]; + + time(&now); + ptime = localtime(&now); + sprintf(key1, "%02d/%02d", ptime->tm_mon + 1, ptime->tm_mday); + sprintf(key2, "%02d/%d%c", ptime->tm_mon + 1, (ptime->tm_mday - 1) / 7 + 1, ptime->tm_wday + 'A'); + lunar_calendar(key3, &now, ptime); + + today = image.today; + sprintf(today, "%s %.2s", key1, "¤é¤@¤G¤T¥|¤¤»" + (ptime->tm_wday << 1)); + + if (fp = fopen(FN_ETC_FEAST, "r")) + { + while (fgets(buf, 80, fp)) + { + if (buf[0] == '#') + continue; + + if ((ptr1 = strtok(buf, " \t\n")) && (ptr2 = strtok(NULL, " \t\n"))) + { + if (!strcmp(ptr1, key1) || !strcmp(ptr1, key2) || !strcmp(ptr1, key3)) + { + str_ncpy(today, ptr2, sizeof(image.today)); + + if (ptr3 = strtok(NULL, " \t\n")) + sprintf(feast, "etc/feasts/%s", ptr3); + if (!dashf(feast)) + feast[0] = '\0'; + + break; + } + } + } + fclose(fp); + } + + return feast; +} + + +int +main() +{ + int i; + char *fname, *str, *feast, fpath[64]; + FCACHE *fshm; + + setgid(BBSGID); + setuid(BBSUID); + chdir(BBSHOME); + + number = total = 0; + + /* --------------------------------------------------- */ + /* ¤µ¤Ñ¸`¤é */ + /* --------------------------------------------------- */ + + feast = do_today(); + + /* --------------------------------------------------- */ + /* ¸ü¤J±`¥Îªº¤å¥ó¤Î help */ + /* --------------------------------------------------- */ + + strcpy(fpath, "gem/@/@"); + fname = fpath + 7; + + for (i = 0; str = list[i]; i++) + { + if (i >= FILM_OPENING0 && i <= FILM_OPENING2 && feast[0]) /* Y¬O¸`¤é¡A¶}ÀYµe±¥Î¸Ó¸`¤éªºµe± */ + { + mirror(feast, 0); + } + else + { + strcpy(fname, str); + mirror(fpath, 0); + } + } + + /* itoc.µù¸Ñ: ¨ì³o¸Ì¥H«á¡AÀ³¸Ó¤w¦³ FILM_MOVIE ½g */ + + /* --------------------------------------------------- */ + /* ¸ü¤J°ÊºA¬ÝªO */ + /* --------------------------------------------------- */ + + /* itoc.µù¸Ñ: °ÊºA¬ÝªO¤ÎÂIºq¥»¦Xp¥u¦³ MOVIE_MAX - FILM_MOVIE - 1 ½g¤~·|³Q¦¬¶i movie */ + + sprintf(fpath, "gem/brd/%s/@/@note", BN_CAMERA); /* °ÊºA¬ÝªOªº¸s²ÕÀɮצWºÙÀ³©R¦W¬° @note */ + do_gem(fpath); /* §â [note] ºëµØ°Ï¦¬¶i movie */ + +#ifdef HAVE_SONG_CAMERA + brd_fpath(fpath, BN_KTV, FN_DIR); + do_gem(fpath); /* §â³QÂIªººq¦¬¶i movie */ +#endif + + /* --------------------------------------------------- */ + /* resolve shared memory */ + /* --------------------------------------------------- */ + + image.shot[0] = number; /* Á`¦@¦³´X¤ù */ + + fshm = (FCACHE *) shm_new(FILMSHM_KEY, sizeof(FCACHE)); + memcpy(fshm, &image, sizeof(FCACHE)); + + /* printf("%d/%d films, %d/%d bytes\n", number, MOVIE_MAX, total, MOVIE_SIZE); */ + + exit(0); +} diff --git a/util/changeperm.c b/util/changeperm.c new file mode 100644 index 0000000..f293c81 --- /dev/null +++ b/util/changeperm.c @@ -0,0 +1,58 @@ +/*-------------------------------------------------------*/ +/* util/changeperm.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : ¥h°£¨C¦ì¨Ï¥ÎªÌ§ó§ïIDªºÅv */ +/* author : chensc.bbs@sony.tfcis.org */ +/* create : 06/09/03 */ +/* update : */ +/*-------------------------------------------------------*/ + +#include "bbs.h" + +int +main() +{ + printf("Be SURE to change all user's perm, continue? y/n : "); + if(getchar() !='y') + exit(1); + + int i,fd; + SCHEMA *usr; + struct stat st; + + chdir(BBSHOME); + + if ((fd = open(FN_SCHEMA, O_RDONLY)) < 0) + { + printf("ERROR at open file\n"); + exit(1); + } + + fstat(fd, &st); + usr = (SCHEMA *) malloc(st.st_size); + read(fd, usr, st.st_size); + close(fd); + + fd = st.st_size / sizeof(SCHEMA); + + for (i = 0; i < fd; i++) + { + ACCT cuser; + char fpath[64]; + + usr_fpath(fpath, usr[i].userid, FN_ACCT); + if (rec_get(fpath, &cuser, sizeof(cuser), 0) < 0) + { + printf("%s: read error (maybe no such id?)\n", usr[i].userid); + continue; + } + + if (HAS_PERM(PERM_CHANGEID)) + cuser.userlevel ^= PERM_CHANGEID; + + if (rec_put(fpath, &cuser, sizeof(cuser), 0, NULL) < 0) + printf("%s: write error\n", usr[i].userid); + + printf("%s : done !\n",usr[i].userid); + } +} diff --git a/util/counter.c b/util/counter.c new file mode 100644 index 0000000..8620d15 --- /dev/null +++ b/util/counter.c @@ -0,0 +1,112 @@ +/*-------------------------------------------------------*/ +/* util/counter.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¾ú¥vy¸ñ */ +/* create : 03/03/03 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#define OUTFILE_COUNTER "gem/@/@-counter" +#define FN_RUN_COUNTER "run/var/counter" + + +typedef struct +{ + time_t uptime; /* §ó·s®É¶¡ */ + + int total_acct; /* ¯¸¤WÁ`¦@¦³¦h¤Ö¨Ï¥ÎªÌµù¥U */ + int online_usr; /* ½u¤W¦P®É¦³¦h¤Ö¨Ï¥ÎªÌ */ + int today_usr; /* ¤µ¤éÁ`¦@¦³´XÓ¤H¦¸¤W¯¸ */ + int online_usr_every_hour[24];/* ¤µ¤é¦U¾ãÂI½u¤W¦³¦h¤Ö¨Ï¥ÎªÌ */ + int total_brd; /* ¯¸¤WÁ`¦@¦³¦h¤Ö¬ÝªO */ + + char ident[12]; /* ¯d¥Õ¥HÂX¥R¥Î */ +} COUNTER; + + +#define break_record(new, old) (new > old + old / 20) /* ·í·s¬ö¿ý¶W¹L¬ö¿ý 5% ¥H¤W®É¡A´N§ï¼g¬ö¿ý */ + + +int +main() +{ + UCACHE *ushm; + COUNTER counter; + + int num; + char *fname, date[20]; + FILE *fp; + time_t now; + struct tm *ptime; + + chdir(BBSHOME); + + if (!(fp = fopen(OUTFILE_COUNTER, "a+"))) + return -1; + + fname = FN_RUN_COUNTER; + + memset(&counter, 0, sizeof(COUNTER)); + rec_get(fname, &counter, sizeof(COUNTER), 0); + + counter.uptime = time(&now); + ptime = localtime(&now); + sprintf(date, "¡i%02d/%02d/%02d %02d:%02d¡j", + ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday, ptime->tm_hour, ptime->tm_min); + + + /* µù¥U¤H¼Æ */ + num = rec_num(FN_SCHEMA, sizeof(SCHEMA)); + if (break_record(num, counter.total_acct)) + { + fprintf(fp, "¡¹ %s \033[31m¥»¯¸µù¥U¤H¼Æ\033[m¨g¶P¶W¹L \033[1;31m%d\033[m ¤H\n", date, num); + counter.total_acct = num; + } + + /* ½u¤W¤H¼Æ */ + ushm = shm_new(UTMPSHM_KEY, sizeof(UCACHE)); + num = ushm->count; + if (break_record(num, counter.online_usr)) + { + fprintf(fp, "¡· %s \033[32m¦P®É½u¤W¤H¼Æ\033[mº¦¸¹F¨ì \033[1;32m%d\033[m ¤H\n", date, num); + counter.online_usr = num; + } + counter.online_usr_every_hour[ptime->tm_hour] = num; /* ¥»¤p®Éªº½u¤W¤H¼Æ¡A´N®³³o¦¸ sample È */ + + /* ¥»¤é¤W¯¸¤H¦¸ */ + if (ptime->tm_hour == 23) /* ¨C¤Ñpºâ¤@¦¸¥»¤é¤W¯¸¤H¦¸ */ + { + int i; + + /* itoc.µù¸Ñ: ³oÓȬO¤£¥¿½Tªº¡A¦]¬°¥u¬O®³¨CÓ¤p®É sample ªº©M¡A + ¦Ó¥BÁÙ°²³]¨CÓ¤H¥§¡¦b¯¸¤W®É¶¡¬O 60 ¤ÀÄÁ */ + num = 0; + for (i = 0; i < 24; i++) + num += counter.online_usr_every_hour[i]; + + if (break_record(num, counter.today_usr)) + { + fprintf(fp, "¡» %s \033[33m³æ¤é¤W¯¸¤H¦¸\033[m¥¿¦¡¬ð¯} \033[1;33m%d\033[m ¤H\n", date, num); + counter.today_usr = num; + } + } + + /* ¬ÝªOÓ¼Æ */ + num = rec_num(FN_BRD, sizeof(BRD)); + if (break_record(num, counter.total_brd)) + { + fprintf(fp, "¡¸ %s \033[34m¥»¯¸¬ÝªOÓ¼Æ\033[m«Å§G°ª¹F \033[1;34m%d\033[m Ó\n", date, num); + counter.total_brd = num; + } + + + rec_put(fname, &counter, sizeof(COUNTER), 0, NULL); + + fclose(fp); + return 0; +} diff --git a/util/expire.c b/util/expire.c new file mode 100644 index 0000000..85ba130 --- /dev/null +++ b/util/expire.c @@ -0,0 +1,490 @@ +/*-------------------------------------------------------*/ +/* util/expire.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : ¦Û°Ê¬å«H¤u¨ãµ{¦¡ */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ +/* syntax : expire [day max min board] */ +/* notice : ¥[¤W board ®É¡A¥i expire+sync ¬Y¤@ board */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#if 0 /* itoc.030325: ²©ö»¡©ú */ + + expire.c ¥]§t¤GºØ°Ê§@¡Gexpire ©M sync + + 1) ©Ò¿×¡u¹L´Á¡v¡A´N¬O ¤å³¹¤é´Á¹L¤[/¬ÝªO½g¼Æ¹L¦h + + 2) ©Ò¿×¡uexpire¡v¡A´N¬O¦b .DIR ¯Á¤Þ¤¤§ä¥X¹L´Áªº¤å³¹¡A§â³o hdr ±q¯Á¤Þ¤¤²¾°£¡A + ¨Ã±N¸ÓÀÉ®×§R°£ + + 3) ©Ò¿×¡usync¡v¡A¬°¤FÁ×§KµwºÐ¦³¦h¾lªº©U§£¡A¨t²Î¨C 32 ¤Ñ·|¹ï¬ÝªO¤ºªºÀɮפ@¤@ + À˵ø¡AY¨ä¤£¦b .DIR ¤¤¡Aªí¥Ü³oÓÀɮפw¸g±q¯Á¤Þ¤¤¿ò¥¢¤F¡A¦¹®É¨t²Î·|ª½±µ±N + ³oÀÉ®×§R°£ + +#endif + + +#define DEF_DAYS 730 /* ¹w³]²M°£¶W¹L 730 ¤Ñªº¤å³¹ */ +#define DEF_MAXP 5000 /* ¹w³]²M°£¶W¹L 5000 ½gªº¤å³¹ */ +#define DEF_MINP 500 /* ¹w³]§C©ó 500 ½gªº¬ÝªO¤£¬å¤å³¹ */ + + +#define EXPIRE_LOG "run/expire.log" + + +typedef struct +{ + char bname[BNLEN + 1]; /* board ID */ + int days; /* expired days */ + int maxp; /* max post */ + int minp; /* min post */ +} Life; + + +static int +life_cmp(a, b) + Life *a, *b; +{ + return str_cmp(a->bname, b->bname); +} + + +/* ----------------------------------------------------- */ +/* board¡Gshm ³¡¥÷¶·»P cache.c ¬Û®e */ +/* ----------------------------------------------------- */ + + +static BCACHE *bshm; + + +static void +init_bshm() +{ + /* itoc.030727: ¦b¶}±Ò bbsd ¤§«e¡AÀ³¸Ó´Nn°õ¦æ¹L account¡A + ©Ò¥H bshm À³¸Ó¤w³]©w¦n */ + + bshm = shm_new(BRDSHM_KEY, sizeof(BCACHE)); + + if (bshm->uptime <= 0) /* bshm ¥¼³]©w§¹¦¨ */ + exit(0); +} + + +/* ----------------------------------------------------- */ +/* synchronize folder & files */ +/* ----------------------------------------------------- */ + + +static time_t synctime; + + +typedef struct +{ + time_t chrono; + char prefix; /* Àɮתº family */ + char exotic; /* 1:¤£¦b.DIR¤¤ 0:¦b.DIR¤¤ */ +} SyncData; + + +static SyncData *sync_pool; +static int sync_size, sync_head; + + +#define SYNC_DB_SIZE 2048 + + +static int +sync_cmp(a, b) + SyncData *a, *b; +{ + return a->chrono - b->chrono; +} + + +static void +sync_init(fname) + char *fname; +{ + int ch, prefix; + time_t chrono; + char *str, fpath[80]; + struct dirent *de; + DIR *dirp; + + SyncData *xpool; + int xsize, xhead; + + if (xpool = sync_pool) + { + xsize = sync_size; + } + else + { + xpool = (SyncData *) malloc(SYNC_DB_SIZE * sizeof(SyncData)); + xsize = SYNC_DB_SIZE; + } + + xhead = 0; + + ch = strlen(fname); + memcpy(fpath, fname, ch); + fname = fpath + ch; + *fname++ = '/'; + fname[1] = '\0'; + + /* itoc.030325.µù¸Ñ: ¥ý§â brd/brdname/?/* ªº©Ò¦³Àɮ׳£¥á¶i¥h xpool[] + ³o¥÷Æ[¹î¦W³æ¤¤¡AµM«á¦^¨ì expire() ¤¤Àˬd¸ÓÀɮ׬O§_¦b .DIR ¤¤ + Y¦b .DIR ¤¤¡A´N§â exotic ³]¦^ 0 + ³Ì«á¦b sync_check() ¤¤§âÆ[¹î¦W³æ¤¤ exotic ÁÙ¬O 1 ªºÀɮ׳£§R°£ */ + + ch = '0'; + for (;;) + { + *fname = ch++; + + if (dirp = opendir(fpath)) + { + while (de = readdir(dirp)) + { + str = de->d_name; + prefix = *str; + if (prefix == '.') + continue; + + chrono = chrono32(str); + + if (chrono > synctime) /* ³o¬O³Ìªñèµoªíªº¤å³¹¡A¤£»Ýn¥[¤J xpool[] ¥h sync */ + continue; + + if (xhead >= xsize) + { + xsize += (xsize >> 1); + xpool = (SyncData *) realloc(xpool, xsize * sizeof(SyncData)); + } + + xpool[xhead].chrono = chrono; + xpool[xhead].prefix = prefix; + xpool[xhead].exotic = 1; /* ¥ý¥þ³¡¥O¬° 1¡A©ó expire() ¤¤¦A§ï¦^ 0 */ + xhead++; + } + + closedir(dirp); + } + + if (ch == 'W') + break; + + if (ch == '9' + 1) + ch = 'A'; + } + + if (xhead > 1) + qsort(xpool, xhead, sizeof(SyncData), sync_cmp); + + sync_pool = xpool; + sync_size = xsize; + sync_head = xhead; +} + + +static void +sync_check(flog, fname) + FILE *flog; + char *fname; +{ + char *str, fpath[80]; + SyncData *xpool, *xtail; + time_t cc; + + if ((cc = sync_head) <= 0) + return; + + xpool = sync_pool; + xtail = xpool + cc; + + sprintf(fpath, "%s/ /", fname); + str = strchr(fpath, ' '); + fname = str + 3; + + do + { + if (xtail->exotic) + { + cc = xtail->chrono; + fname[-1] = xtail->prefix; + *str = radix32[cc & 31]; + archiv32(cc, fname); + unlink(fpath); + + fprintf(flog, "-\t%s\n", fpath); + } + } while (--xtail >= xpool); +} + + +static void +expire(flog, life, sync) + FILE *flog; + Life *life; + int sync; +{ + HDR hdr; + struct stat st; + char fpath[128], fnew[128], index[128], *fname, *bname, *str; + int done, keep, total; + FILE *fpr, *fpw; + + int days, maxp, minp; + int duetime; + + SyncData *xpool, *xsync; + int xhead; + + days = life->days; + maxp = life->maxp; + minp = life->minp; + bname = life->bname; + + fprintf(flog, "%s\n", bname); + + sprintf(index, "%s/.DIR", bname); + if (!(fpr = fopen(index, "r"))) + { + fprintf(flog, "\tError open file: %s\n", index); + return; + } + + fpw = f_new(index, fnew); + if (!fpw) + { + fprintf(flog, "\tExclusive lock: %s\n", fnew); + fclose(fpr); + return; + } + + if (sync) + { + sync_init(bname); + xpool = sync_pool; + xhead = sync_head; + if (xhead <= 0) + sync = 0; + else + fprintf(flog, "\t%d files to sync\n\n", xhead); + } + + strcpy(fpath, index); + str = (char *) strrchr(fpath, '.'); + fname = str + 1; + *fname++ = '/'; + + done = 1; + duetime = synctime - days * 86400; + + fstat(fileno(fpr), &st); + total = st.st_size / sizeof(hdr); + + while (fread(&hdr, sizeof(hdr), 1, fpr) == 1) + { + if (hdr.xmode & (POST_MARKED | POST_BOTTOM) || total <= minp) + keep = 1; + else if (hdr.chrono < duetime || total > maxp) + keep = 0; + else + keep = 1; + + if (sync && (hdr.chrono < synctime)) + { + if (xsync = (SyncData *) bsearch(&hdr.chrono, xpool, xhead, sizeof(SyncData), sync_cmp)) + { + xsync->exotic = 0; /* ³o½g¦b .DIR ¤¤¡A¤£ sync */ + } + else + { + keep = 0; /* ¤@«ß¤£«O¯d */ + } + } + + if (keep) + { + if (fwrite(&hdr, sizeof(hdr), 1, fpw) != 1) + { + fprintf(flog, "\tError in write DIR.n: %s\n", hdr.xname); + done = 0; + sync = 0; /* Thor.990127: ¨S§@¦¨, ´N§O¬å¤F§a */ + break; + } + } + else + { + *str = hdr.xname[7]; + strcpy(fname, hdr.xname); + unlink(fpath); + fprintf(flog, "\t%s\n", fname); + total--; + } + } + fclose(fpr); + fclose(fpw); + + if (done) + { + sprintf(fpath, "%s.o", index); + if (!rename(index, fpath)) + { + if (rename(fnew, index)) + rename(fpath, index); /* ´«¦^¨Ó */ + } + } + unlink(fnew); + + if (sync) + sync_check(flog, bname); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + FILE *fp; + int number, count; + Life db, table[MAXBOARD], *key; + char *ptr, *bname, buf[256]; + BRD *brdp, *bend; + + /* itoc.030325: n¹À¤£«ü©w°Ñ¼Æ¡An¹À«ü©w©Ò¦³°Ñ¼Æ */ + if (argc != 1 && argc != 5) + { + printf("%s [day max min board]\n", argv[0]); + exit(-1); + } + + /* YµL«ü©w°Ñ¼Æ¡A«h¥Î¹w³]È */ + db.days = ((argc == 5) && (number = atoi(argv[1])) > 0) ? number : DEF_DAYS; + db.maxp = ((argc == 5) && (number = atoi(argv[2])) > 0) ? number : DEF_MAXP; + db.minp = ((argc == 5) && (number = atoi(argv[3])) > 0) ? number : DEF_MINP; + + /* --------------------------------------------------- */ + /* load expire.conf */ + /* --------------------------------------------------- */ + + setgid(BBSGID); + setuid(BBSUID); + chdir(BBSHOME); + + init_bshm(); + + count = 0; + if (argc != 5) /* Y¨S¦³«ü©w°Ñ¼Æ¡A¤~»Ýn¥hŪ expire.conf */ + { + if (fp = fopen(FN_ETC_EXPIRE, "r")) + { + while (fgets(buf, sizeof(buf), fp)) + { + if (buf[0] == '#') + continue; + + bname = (char *) strtok(buf, " \t\r\n"); + if (bname && *bname) + { + ptr = (char *) strtok(NULL, " \t\r\n"); + if (ptr && (number = atoi(ptr)) > 0) + { + key = &(table[count]); + strcpy(key->bname, bname); + key->days = number; + key->maxp = db.maxp; + key->minp = db.minp; + + ptr = (char *) strtok(NULL, " \t\r\n"); + if (ptr && (number = atoi(ptr)) > 0) + { + key->maxp = number; + + ptr = (char *) strtok(NULL, " \t\r\n"); + if (ptr && (number = atoi(ptr)) > 0) + key->minp = number; + } + + /* expire.conf ¥i¯à¨S¦³ºûÅ@¦Ó¶W¹L MAXBOARD ÓªO */ + if (++count >= MAXBOARD) + break; + } + } + } + fclose(fp); + } + + if (count > 1) + qsort(table, count, sizeof(Life), life_cmp); + } + + /* --------------------------------------------------- */ + /* visit all boards */ + /* --------------------------------------------------- */ + + fp = fopen(EXPIRE_LOG, "w"); + + chdir("brd"); + + synctime = time(NULL) - 10 * 60; /* ¤Q¤ÀÄÁ¤ºªº·s¤å³¹¤£»Ýn sync */ + number = synctime / 86400; + + brdp = bshm->bcache; + bend = brdp + bshm->number; + do + { + bname = brdp->brdname; + if (!*bname) + continue; + + { + struct tm *ptime; + time_t now; + + time(&now); + ptime = localtime(&now); + + if (ptime->tm_wday == 0) /* ¨C¶g¤@¬å usies */ + { + sprintf(buf, "%s/%s", bname, "usies"); + unlink(buf); + } + } + + /* Thor.981027: ¥[¤W board ®É¡A¥i expire+sync ¬Y¤@ board */ + if (argc == 5) + { + if (str_cmp(argv[4], bname)) + continue; + + number = 0; /* ±j¢ sync ³oªO */ + } + + if (count) + { + key = (Life *) bsearch(bname, table, count, sizeof(Life), life_cmp); + if (!key) + key = &db; + } + else + { + key = &db; + } + + strcpy(key->bname, bname); /* ´«¦¨¥¿½Tªº¤j¤p¼g */ + expire(fp, key, !(number & 31)); /* ¨C¹j 32 ¤Ñ sync ¤@¦¸ */ + number++; + brdp->btime = -1; + } while (++brdp < bend); + + fclose(fp); + exit(0); +} diff --git a/util/gem-index.c b/util/gem-index.c new file mode 100644 index 0000000..d08f811 --- /dev/null +++ b/util/gem-index.c @@ -0,0 +1,245 @@ +/*-------------------------------------------------------*/ +/* util/gem-index.c ( NTHU CS MapleBBS Ver 2.39 ) */ +/*-------------------------------------------------------*/ +/* target : ºëµØ°Ï¯Á¤Þµ{¦¡ (man index) */ +/* create : 95/03/29 */ +/* update : 95/08/08 */ +/*-------------------------------------------------------*/ +/* syntax : gem-index [board] */ +/* [board] ¦³È ==> ¥u¶]¸Ó board */ +/* ªÅªº ==> ©Ò¦³ªº boards ³£¶] */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#define COLOR_INDEX /* Thor.980307: ¥[¤WÃC¦â¸Õ¸Õ¬O§_¤ñ¸û©ö§ä */ + + +#define GINDEX_LOG (BBSHOME "/run/gindex.log") + + +#define CHRONO_INDEX 1 +#define CHRONO_LOG 2 + + +static char fn_index[] = "@/@index"; +static char fn_log[] = "@/@log"; + + +static int gem_default; +static int ndir; +static int nfile; +static char pgem[128], pndx[128], pool[128]; +static FILE *flog; + + +/* visit the hierarchy recursively */ + + +static void +gindex(level, toc, fpath, fndx) + int level; + char *toc; + char *fpath; + FILE *fndx; +{ + int count, xmode; + char *fname, *ptr, buf[128]; + FILE *fgem; + HDR hdr; + + if (level > 7) /* endless loop ? */ + { + fprintf(flog, "level: %d [%s]\n", level, fpath); + return; + } + + if (!level) + { + fprintf(flog, "%-14s", fpath); /* report */ + sprintf(pool, "%s/.DIR", fpath); + fpath = pool; + strcpy(pgem, fpath); + } + + if (!(fgem = fopen(fpath, "r"))) + return; + + fname = fpath; + while (xmode = *fname++) + { + if (xmode == '/') + ptr = fname; + } + if (*ptr != '.') + ptr -= 2; + fname = ptr; + + if (!fndx) + { + strcpy(fname, "@/@ing--"); + fndx = fopen(fpath, "w"); + if (!fndx) + { + fclose(fgem); + return; + } + fprintf(fndx, "§Ç¸¹\t\t\tºëµØ°Ï¥DÃD\n" + "-------------------------------------------------------------\n"); + strcpy(pndx, fpath); + gem_default = ndir = nfile = 0; + } + + count = 0; + while (fread(&hdr, sizeof(hdr), 1, fgem) == 1) + { + count++; + xmode = hdr.xmode; + + /* Àˬd¬O§_¬°¯Á¤Þ¡B²§°Ê */ + if (!level && hdr.chrono <= CHRONO_LOG) + { + gem_default |= hdr.chrono; + continue; + } + + if (xmode & GEM_FOLDER) + ndir++; + else + nfile++; + + if (xmode & GEM_RESTRICT) + continue; + + sprintf(buf, "%.*s%3d. ", level * 4, toc, count); + +#ifdef COLOR_INDEX + /* Thor.980307: ¥[¤WÃC¦â¸Õ¸Õ¬O§_¤ñ¸û©ö§ä */ + if (xmode & GEM_FOLDER) + fprintf(fndx, "%s\033[1;37;%dm%s\033[m\n", buf, 41 + (level % 6) , hdr.title); + else + fprintf(fndx, "%s%s\n", buf, hdr.title); +#else + if (xmode & GEM_FOLDER) + fprintf(fndx, "*%s%s\n", buf + 1, hdr.title); + else + fprintf(fndx, "%*d. %s\n", 4 * level + 3, count, hdr.title); +#endif + + if ((xmode & (GEM_FOLDER | GEM_BOARD)) == GEM_FOLDER) /* ¤@¯ë¨÷©v */ + { + ptr = hdr.xname; /* F1234567 */ + sprintf(fname, "%c/%s", (*ptr == '@' ? '@' : ptr[7]), ptr); + gindex(level + 1, buf, fpath, fndx); + } + } + + if (!level) + { + fclose(fndx); + strcpy(fname, fn_index); + rename(pndx, fpath); + + /* report */ + + fprintf(flog, "==> d: %d\tf: %d\n", ndir, nfile); + + xmode = gem_default; + if (xmode != (CHRONO_INDEX | CHRONO_LOG)) /* ¤w¦³¯Á¤Þ¤Î²§°Ê */ + { + sprintf(pool, "%s.o", pgem); + sprintf(pndx, "%s.n", pgem); + if (fndx = fopen(pndx, "w")) + { + memset(&hdr, 0, sizeof(HDR)); + hdr.xmode = GEM_RESERVED; + strcpy(hdr.owner, SYSOPNICK); + + if (!(xmode & CHRONO_INDEX)) + { + hdr.chrono = CHRONO_INDEX; + strcpy(hdr.xname, fn_index + 2); + strcpy(hdr.title, "ºëµØ°Ï¯Á¤Þ"); + fwrite(&hdr, sizeof(hdr), 1, fndx); + } + + if (!(xmode & CHRONO_LOG)) + { + hdr.chrono = CHRONO_LOG; + strcpy(hdr.xname, fn_log + 2); + strcpy(hdr.title, "ºëµØ°Ï²§°Ê"); + fwrite(&hdr, sizeof(hdr), 1, fndx); + } + + fseek(fgem, (off_t) 0, SEEK_SET); + + while (fread(&hdr, sizeof(hdr), 1, fgem) == 1) + { + fwrite(&hdr, sizeof(hdr), 1, fndx); + } + + fclose(fndx); + fclose(fgem); + rename(pgem, pool); + rename(pndx, pgem); + return; + } + } + } + + fclose(fgem); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + DIR *dirp; + struct dirent *de; + char *fname, fpath[80]; + + umask(077); + chdir(BBSHOME "/gem"); + + if (argc > 1) + { + flog = stderr; + sprintf(fpath, "brd/%s", argv[1]); + gindex(0, "", fpath, NULL); + exit(0); + } + + if (!(flog = fopen(GINDEX_LOG, "w"))) + exit(-1); + + /* visit the top folder */ + + gindex(0, "", ".", NULL); + + /* visit the second hierarchy for all boards */ + + strcpy(fpath, "brd"); + if (!(dirp = opendir(fpath))) + { + fprintf(flog, "## unable to visit [gem/brd]\n"); + fclose(flog); + exit(-1); + } + + fpath[3] = '/'; + while (de = readdir(dirp)) + { + fname = de->d_name; + if (fname[1] && *fname != '.') + { + strcpy(fpath + 4, fname); + gindex(0, "", fpath, NULL); + } + } + closedir(dirp); + fclose(flog); + exit(0); +} diff --git a/util/give_paycheck.c b/util/give_paycheck.c new file mode 100644 index 0000000..2c1d906 --- /dev/null +++ b/util/give_paycheck.c @@ -0,0 +1,91 @@ +/*-------------------------------------------------------*/
+/* util/give_paycheck.c ( NTHU CS MapleBBS Ver 3.10 ) */
+/*-------------------------------------------------------*/
+/* target : µoµ¹¥þ¯¸¨Ï¥ÎªÌ¤ä²¼ */
+/* create : 05/04/18 */
+/* update : / / */
+/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */
+/*-------------------------------------------------------*/
+
+
+#if 0
+
+ µ¹ itoc ¤@±i 100 »È 200 ª÷ ªº¤ä²¼
+ % ~/bin/give_paycheck 100 200 itoc
+
+ µ¹ sysop ¤@±i 100 »È 0 ª÷ ªº¤ä²¼
+ % ~/bin/give_paycheck 100 0 sysop
+
+ µ¹¥þ¯¸¨Ï¥ÎªÌ¦U¤@±i 50 »È 30 ª÷ ªº¤ä²¼
+ % ~/bin/give_paycheck 50 30
+
+ µ¹¥þ¯¸¨Ï¥ÎªÌ¤ä²¼n°õ¦æ¤@¬q®É¶¡¡A½Ð@¤ßµ¥Ô
+
+#endif
+
+
+#include "bbs.h"
+
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int money, gold;
+ char c, *str, buf[64];
+ struct dirent *de;
+ DIR *dirp;
+ PAYCHECK paycheck;
+
+ if (argc == 3 || argc == 4)
+ {
+ money = atoi(argv[1]);
+ gold = atoi(argv[2]);
+ if (money < 0 || gold < 0)
+ printf("money and gold should not be negative.\n");
+ }
+ else
+ {
+ printf("Usage: %s money gold [userid]\n", argv[0]);
+ return -1;
+ }
+
+ memset(&paycheck, 0, sizeof(PAYCHECK));
+ time(&paycheck.tissue);
+ paycheck.money = money;
+ paycheck.gold = gold;
+ //strcpy(paycheck.reason, "[µo¿ú] ¯¸ªø");
+ strcpy(paycheck.reason, "¨Ä¨Ä¯¸¥Á¦³¬õ¥]");
+
+ if (argc == 4)
+ {
+ chdir(BBSHOME);
+ usr_fpath(buf, argv[3], FN_PAYCHECK);
+ rec_add(buf, &paycheck, sizeof(PAYCHECK));
+ return 0;
+ }
+
+ for (c = 'a'; c <= 'z'; c++)
+ {
+ sprintf(buf, BBSHOME "/usr/%c", c);
+ chdir(buf);
+
+ if (!(dirp = opendir(".")))
+ continue;
+
+ while (de = readdir(dirp))
+ {
+ str = de->d_name;
+ if (*str <= ' ' || *str == '.')
+ continue;
+
+ sprintf(buf, "%s/" FN_PAYCHECK, str);
+ rec_add(buf, &paycheck, sizeof(PAYCHECK));
+ }
+
+ closedir(dirp);
+ }
+
+ return 0;
+}
diff --git a/util/hdr-dump.c b/util/hdr-dump.c new file mode 100644 index 0000000..544acd8 --- /dev/null +++ b/util/hdr-dump.c @@ -0,0 +1,43 @@ +/*-------------------------------------------------------*/ +/* util/hdr-dump.c ( NTHU CS MapleBBS Ver 2.36 ) */ +/*-------------------------------------------------------*/ +/* target : ¬ÝªO¼ÐÃDªí */ +/* create : 95/03/29 */ +/* update : 95/12/15 */ +/*-------------------------------------------------------*/ +/* Usage: hdr-dump .DIR */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int fd, count; + HDR hdr; + + if (argc < 2) + { + printf("Usage:\t%s .DIR\n", argv[0]); + exit(1); + } + + if ((fd = open(argv[1], O_RDONLY)) < 0) + { + printf("error open file\n"); + exit(1); + } + + count = 0; + while (read(fd, &hdr, sizeof(HDR)) == sizeof(HDR)) + { + count++; + printf("%04d %c/%s %s (%s) %s %s\n", count, hdr.xname[7], hdr.xname, hdr.owner, hdr.nick, hdr.date, hdr.title); + } + close(fd); + + exit(0); +} diff --git a/util/mailpost.c b/util/mailpost.c new file mode 100644 index 0000000..5ee88a6 --- /dev/null +++ b/util/mailpost.c @@ -0,0 +1,202 @@ +/*-------------------------------------------------------*/ +/* util/mailpost.c ( NTHU CS MapleBBS Ver 2.36 ) */ +/*-------------------------------------------------------*/ +/* target : ¼f®Ö¨¤À»{ÃÒ«H¨ç¤§¦^«H */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ +/* notice : brdshm (board shared memory) synchronize */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +static void +mailog(msg) + char *msg; +{ + FILE *fp; + + if (fp = fopen(BMTA_LOGFILE, "a")) + { + time_t now; + struct tm *p; + + time(&now); + p = localtime(&now); + fprintf(fp, "%02d/%02d %02d:%02d:%02d <mailpost> %s\n", + p->tm_mon + 1, p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec, + msg); + fclose(fp); + } +} + + +/* ----------------------------------------------------- */ +/* °O¿ýÅçÃÒ¸ê®Æ¡Guser ¦³¥i¯à¥¿¦b½u¤W¡A¬G¼g¤JÀÉ®×¥H«O©P¥þ */ +/* ----------------------------------------------------- */ + + +static int +is_badid(userid) + char *userid; +{ + int ch; + char *str; + + ch = strlen(userid); + if (ch < 2 || ch > IDLEN) + return 1; + + if (!is_alpha(*userid)) + return 1; + + str = userid; + while (ch = *(++str)) + { + if (!is_alnum(ch)) + return 1; + } + return 0; +} + + +static void +justify_user(userid, email) + char *userid, *email; +{ + char fpath[64]; + HDR hdr; + FILE *fp; + + /* ±H»{ÃÒ³q¹L«Hµ¹¨Ï¥ÎªÌ */ + usr_fpath(fpath, userid, FN_DIR); + if (!hdr_stamp(fpath, HDR_LINK, &hdr, FN_ETC_JUSTIFIED)) + { + strcpy(hdr.title, "±z¤w¸g³q¹L¨¤À»{ÃÒ¤F¡I"); + strcpy(hdr.owner, STR_SYSOP); + hdr.xmode = MAIL_NOREPLY; + rec_add(fpath, &hdr, sizeof(HDR)); + } + + /* °O¿ý¦b FN_JUSTIFY */ + usr_fpath(fpath, userid, FN_JUSTIFY); + if (fp = fopen(fpath, "a")) + { + fprintf(fp, "RPY: %s\n", email); + fclose(fp); + } +} + + +static void +verify_user(str) + char *str; +{ + int fd; + char *ptr, *next, fpath[64]; + ACCT acct; + + /* itoc.µù¸Ñ: "userid(regkey) [VALID]" */ + + if ((ptr = strchr(str, '(')) && (next = strchr(ptr + 1, ')'))) + { + *ptr = '\0'; + *next = '\0'; + + if (!is_badid(str) && !str_ncmp(next + 1, " [VALID]", 8)) + { + /* ¨ì¦¹®æ¦¡³£¥¿½T */ + + usr_fpath(fpath, str, FN_ACCT); + if ((fd = open(fpath, O_RDWR, 0600)) >= 0) + { + if (read(fd, &acct, sizeof(ACCT)) == sizeof(ACCT)) + { + if (str_hash(acct.email, acct.tvalid) == chrono32(ptr)) /* regkey ¥¿½T */ + { + /* ´£¤ÉÅv */ + acct.userlevel |= PERM_VALID; + time(&acct.tvalid); + lseek(fd, (off_t) 0, SEEK_SET); + write(fd, &acct, sizeof(ACCT)); + + justify_user(str, acct.email); + } + } + close(fd); + } + } + } +} + + +/* ----------------------------------------------------- */ +/* ¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +mailpost() +{ + int count; + char *ptr, buf[512]; + + /* ¥u»Ýn§ä Subject: ªºÀÉÀY */ + + count = 0; + while ((++count < 20) && fgets(buf, sizeof(buf), stdin)) /* ³Ì¦h fgets 20 ¦¸¡AÁ×§K¨S¦³ subject */ + { + if (!str_ncmp(buf, "Subject: ", 9)) + { + str_decode(buf); + + /* itoc.µù¸Ñ: mail.c: TAG_VALID " userid(regkey) [VALID]" */ + if (ptr = strstr(buf, TAG_VALID " ")) + { + /* gslin.990101: TAG_VALID ªø«×¤£¤@©w */ + verify_user(ptr + sizeof(TAG_VALID)); + } + break; + } + } +} + + +static void +sig_catch(sig) + int sig; +{ + char buf[512]; + + while (fgets(buf, sizeof(buf), stdin)) + ; + sprintf(buf, "signal [%d]", sig); + mailog(buf); + exit(0); +} + + +int +main() +{ + char buf[512]; + + setgid(BBSGID); + setuid(BBSUID); + chdir(BBSHOME); + + signal(SIGBUS, sig_catch); + signal(SIGSEGV, sig_catch); + signal(SIGPIPE, sig_catch); + + mailpost(); + + /* eat mail queue */ + while (fgets(buf, sizeof(buf), stdin)) + ; + + exit(0); +} diff --git a/util/outgo.c b/util/outgo.c new file mode 100644 index 0000000..862d2db --- /dev/null +++ b/util/outgo.c @@ -0,0 +1,70 @@ +/*-------------------------------------------------------*/ +/* util/outgo.c ( YZU CSE WindTop BBS ) */ +/*-------------------------------------------------------*/ +/* target : ¦Û°Ê°e«Hµ{¦¡ */ +/* create : 00/06/22 */ +/* update : / / */ +/*-------------------------------------------------------*/ +/* syntax : outgo [board] [start] [end] */ +/* NOTICE : ±N¬ÝªO¤å³¹«·s°e¨ì news */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +static inline void +outgo_post(hdr, board) + HDR *hdr; + char *board; +{ + bntp_t bntp; + + memset(&bntp, 0, sizeof(bntp_t)); + bntp.chrono = hdr->chrono; + strcpy(bntp.board, board); + strcpy(bntp.xname, hdr->xname); + strcpy(bntp.owner, hdr->owner); + strcpy(bntp.nick, hdr->nick); + strcpy(bntp.title, hdr->title); + rec_add("innd/out.bntp", &bntp, sizeof(bntp_t)); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + char fpath[128]; + int start, end, fd; + char *board; + HDR hdr; + + if (argc > 3) + { + chdir(BBSHOME); + + board = argv[1]; + start = atoi(argv[2]); + end = atoi(argv[3]); + brd_fpath(fpath, board, FN_DIR); + if (fd = open(fpath, O_RDONLY)) + { + lseek(fd, (off_t) ((start - 1) * sizeof(HDR)), SEEK_SET); + while (read(fd, &hdr, sizeof(HDR)) == sizeof(HDR) && start <= end) + { + if (!(hdr.xmode & POST_INCOME)) + outgo_post(&hdr, board); + start++; + } + close(fd); + } + } + else + { + printf("usage: %s ¬ÝªO °_ÂI ²×ÂI\n", argv[0]); + } + + return 0; +} diff --git a/util/poststat.c b/util/poststat.c new file mode 100644 index 0000000..4fc1c2c --- /dev/null +++ b/util/poststat.c @@ -0,0 +1,471 @@ +/*-------------------------------------------------------*/ +/* util/poststat.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : ²Îp¤µ¤é¡B¶g¡B¤ë¡B¦~¼öªù¸ÜÃD */ +/* create : 95/03/29 */ +/* update : 97/08/29 */ +/*-------------------------------------------------------*/ +/* syntax : poststat [day] */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +static char *myfile[] = {"day", "week", "month", "year"}; +static int mycount[4] = {7, 4, 12}; +static int mytop[] = {10, 50, 100, 100}; +static char *mytitle[] = {"¤é¤Q", "¶g¤¤Q", "¤ë¦Ê", "¦~«×¦Ê"}; + + +#define FN_RUN_POST_AUTHOR "run/var/post.author" +#define FN_RUN_POST_OLD "run/var/post.old" +#define FN_RUN_DAY_0 "run/var/day.0" + + +#define HASHSIZE 1024 /* 2's power */ +#define TOPCOUNT 200 +#define LOWER_BOUND 4 + + +/* POSTLOG + next rec */ +static +struct postrec +{ + char author[IDLEN + 1]; /* author name */ + char board[BNLEN + 1]; /* board name */ + char title[66]; /* title name */ + time_t date; /* last post's date */ + int number; /* post number */ + struct postrec *next; /* next rec */ +} *bucket[HASHSIZE]; + + +static POSTLOG top[TOPCOUNT], *tp; + + +static int +hash(key) + char *key; +{ + int i, ch, value = 0; + + for (i = 0; (ch = key[i]) && i < 80; i++) + { + value = (value << 5) - value + ch; + } + + return value; +} + + +/* ---------------------------------- */ +/* hash structure : array + link list */ +/* ---------------------------------- */ + + +static void +search(t) + POSTLOG *t; +{ + struct postrec *p, *q, *s; + int i, found = 0; + + i = hash(t->title) & (HASHSIZE - 1); + q = NULL; + p = bucket[i]; + while (p && (!found)) + { + if (!strcmp(p->title, t->title) && !strcmp(p->board, t->board)) + found = 1; + else + { + q = p; + p = p->next; + } + } + if (found) + { + p->number += t->number; + if (p->date < t->date) /* ¨ú¸ûªñ¤é´Á */ + p->date = t->date; + } + else + { + s = (struct postrec *) malloc(sizeof(struct postrec)); + memcpy(s, t, sizeof(POSTLOG)); + s->next = NULL; + if (q == NULL) + bucket[i] = s; + else + q->next = s; + } +} + + +static int +sort(pp, count) + struct postrec *pp; +{ + int i, j; + + for (i = 0; i <= count; i++) + { + if (pp->number > top[i].number) + { + if (count < TOPCOUNT - 1) + count++; + for (j = count - 1; j >= i; j--) + memcpy(&top[j + 1], &top[j], sizeof(POSTLOG)); + + memcpy(&top[i], pp, sizeof(POSTLOG)); + break; + } + } + return count; +} + + +static void +load_stat(fname) + char *fname; +{ + FILE *fp; + + if (fp = fopen(fname, "r")) + { + int count = fread(top, sizeof(POSTLOG), TOPCOUNT, fp); + fclose(fp); + while (count) + search(&top[--count]); + } +} + + +static void +poststat(mytype) + int mytype; +{ + FILE *fp; + char buf[40], *p; + char curfile[80] = FN_RUN_DAY_0; + struct postrec *pp; + int i, j; + + if (mytype < 0) + { + FILE *fpw; + + /* --------------------------------------- */ + /* load .post and statictic processing */ + /* --------------------------------------- */ + + unlink(FN_RUN_POST_OLD); + rename(FN_RUN_POST, FN_RUN_POST_OLD); + if (!(fp = fopen(FN_RUN_POST_OLD, "r"))) + return; + + if (!(fpw = fopen(FN_RUN_POST_AUTHOR, "a"))) + { + fclose(fp); + return; + } + + mytype = 0; + load_stat(curfile); + + while (fread(top, sizeof(POSTLOG), 1, fp) == 1) + { + fwrite(top, sizeof(POSTLOG), 1, fpw); + search(top); + } + fclose(fp); + fclose(fpw); + } + else + { + /* ---------------------------------------------- */ + /* load previous results and statictic processing */ + /* ---------------------------------------------- */ + + i = mycount[mytype]; + p = myfile[mytype]; + while (i) + { + sprintf(buf, "run/var/%s.%d", p, i); + sprintf(curfile, "run/var/%s.%d", p, --i); + load_stat(curfile); + rename(curfile, buf); + } + mytype++; + } + + /* ---------------------------------------------- */ + /* sort top 100 issue and save results */ + /* ---------------------------------------------- */ + + memset(top, 0, sizeof(top)); + for (i = j = 0; i < HASHSIZE; i++) + { + for (pp = bucket[i]; pp; pp = pp->next) + { + +#ifdef DEBUG + printf("Title : %s, Board: %s\nPostNo : %d, Author: %s\n", + pp->title, pp->board, pp->number, pp->author); +#endif + + j = sort(pp, j); + } + } + + p = myfile[mytype]; + sprintf(curfile, "run/var/%s.0", p); + if (fp = fopen(curfile, "w")) + { + fwrite(top, sizeof(POSTLOG), j, fp); + fclose(fp); + } + + /* --------------------------------------------------- */ + /* report file : gem/@/@- */ + /* --------------------------------------------------- */ + + sprintf(curfile, BBSHOME "/gem/@/@-%s", p); + if (fp = fopen(curfile, "w")) + { + int max, cnt; + + fprintf(fp, "\t\t\033[1;34m-----\033[37m=====\033[41m ¥»%s¤j¼öªù¸ÜÃD \033[40m=====\033[34m-----\033[0m\n\n", + mytitle[mytype]); + + max = mytop[mytype]; + p = buf + 5; + for (i = cnt = 0; (cnt < max) && (i < j); i++) + { + tp = &top[i]; + strcpy(buf, Btime(&(tp->date))); + buf[23] = '\0'; + fprintf(fp, + "\033[1;31m%3d. \033[33m¬ÝªO : \033[32m%-16s\033[35m¡m%s¡n\033[36m%4d ½g\033[33m%+16s\n" + " \033[33m¼ÐÃD : \033[0;44;37m%-60.60s\033[40m\n", + ++cnt, tp->board, p, tp->number, tp->author, tp->title); + } + fclose(fp); + } + + /* free statistics */ + + for (i = 0; i < HASHSIZE; i++) + { + struct postrec *next; + + for (pp = bucket[i]; pp; pp = next) + { + next = pp->next; + free(pp); + } + bucket[i] = NULL; + } +} + + +#include "splay.h" + + +typedef struct PostText +{ + struct PostText *ptnext; + int count; + char title[0]; +} PostText; + + +typedef struct PostAuthor +{ + struct PostAuthor *panext; + PostText *text; + int count; + int hash; + char author[0]; +} PostAuthor; + + +static int +pa_cmp(x, y) + PostAuthor *x; + PostAuthor *y; +{ + int dif; + + dif = y->count - x->count; + if (dif) + return dif; + return strcmp(x->author, y->author); +} + + +static void +pa_out(top, fp) + SplayNode *top; + FILE *fp; +{ + PostAuthor *pa; + PostText *text; + + if (top == NULL) + return; + + pa_out(top->left, fp); + + pa = (PostAuthor *) top->data; + if (pa->count <= LOWER_BOUND) + return; + + fprintf(fp, "\n>%6d %s\n", pa->count, pa->author); + for (text = pa->text; text; text = text->ptnext) + { + fprintf(fp, "%7d %.70s\n", text->count, text->title); + } + + pa_out(top->right, fp); +} + + +static void +post_author() +{ + int cc, i, len; + char *str; + FILE *fp; + POSTLOG post; + PostAuthor **paht, *pahe; + PostText *text; + SplayNode *patop; + + unlink(FN_RUN_POST_OLD); + rename(FN_RUN_POST_AUTHOR, FN_RUN_POST_OLD); + if (!(fp = fopen(FN_RUN_POST_OLD, "r"))) + return; + + paht = (PostAuthor **) calloc(sizeof(PostAuthor *), HASHSIZE); + + while (fread(&post, sizeof(post), 1, fp) == 1) + { + cc = hash(str = post.author); + pahe = paht[i = cc & (HASHSIZE - 1)]; + + for (;;) + { + if (pahe == NULL) + { + len = strlen(str) + 1; + pahe = (PostAuthor *) malloc(sizeof(PostAuthor) + len); + pahe->panext = paht[i]; + pahe->text = NULL; + pahe->count = 1; + pahe->hash = cc; + memcpy(pahe->author, str, len); + paht[i] = pahe; + break; + } + + if ((cc == pahe->hash) && !strcmp(str, pahe->author)) + { + pahe->count++; + break; + } + + pahe = pahe->panext; + } + + text = pahe->text; + str = post.title; + for (;;) + { + if (text == NULL) + { + len = strlen(str) + 1; + text = (PostText *) malloc(sizeof(PostText) + len + BNLEN + 1); + text->ptnext = pahe->text; + text->count = 1; + sprintf(text->title, "%-13s%s", post.board, str); + /* memcpy(text->title, str, len); */ + pahe->text = text; + break; + } + + if (!strcmp(str, text->title + BNLEN + 1)) + { + text->count ++; + break; + } + + text = text->ptnext; + } + } + fclose(fp); + + /* splay sort */ + + patop = NULL; + + for (i = 0; i < HASHSIZE; i++) + { + for (pahe = paht[i]; pahe; pahe = pahe->panext) + { + patop = splay_in(patop, pahe, pa_cmp); + } + } + + /* report */ + + if (fp = fopen(FN_RUN_POST_LOG, "w")) + { + pa_out(patop, fp); + fclose(fp); + } +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + time_t now; + struct tm *ptime; + + chdir(BBSHOME); + umask(077); + + if (argc == 2) + { + argc = atoi(argv[1]); + if (argc == 100) + post_author(); + else + poststat(argc); + exit(0); + } + + time(&now); + ptime = localtime(&now); + argc = ptime->tm_hour; + + if (argc == 0) + { + if (ptime->tm_mday == 1) + poststat(2); + if (ptime->tm_wday == 0) + poststat(1); + poststat(0); + } + + poststat(-1); + + if (argc == 23) + post_author(); + + exit(0); +} diff --git a/util/reaper.c b/util/reaper.c new file mode 100644 index 0000000..f4bf4c9 --- /dev/null +++ b/util/reaper.c @@ -0,0 +1,647 @@ +/*-------------------------------------------------------*/ +/* util/reaper.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : ¨Ï¥ÎªÌ±b¸¹©w´Á²M²z */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ +/* syntax : reaper */ +/*-------------------------------------------------------*/ +/* notice : ~bbs/usr/@/ - expired users's data */ +/* run/reaper - list of expired users */ +/* run/manager - list of managers */ +/* run/lazybm - list of lazy bm */ +/* run/emailaddr - list of same email addr */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +/* Thor.980930: YnÃö³¬¥H¤U¥\¯à®É¥Î undef §Y¥i */ + +#define CHECK_LAZYBM /* Àˬd°½ÃiªO¥D */ +#define EADDR_GROUPING /* Àˬd¦@¥Î email */ + + +#ifdef CHECK_LAZYBM +#define DAY_LAZYBM 7 /* 7 ¤Ñ¥H¤W¥¼¤W¯¸ªºªO¥D§Y°O¿ý */ +#endif + +#ifdef EADDR_GROUPING +#define EMAIL_REG_LIMIT 3 /* 3 Ó¥H¤W¨Ï¥ÎªÌ¥Î¦P¤@ email §Y°O¿ý */ +#endif + + +/* «O¯d±b¸¹´Á -- ¾Ç´Á¤¤ */ +#define DAY_NEWUSR 7 /* µn¤J¤£¶W¹L¤T¦¸ªº¨Ï¥ÎªÌ«O¯d 7 ¤Ñ */ +#define DAY_FORFUN 120 /* ¥¼§¹¦¨¨¤À»{ÃÒªº¨Ï¥ÎªÌ«O¯d 120 ¤Ñ */ +#define DAY_OCCUPY 120 /* ¤w§¹¦¨¨¤À»{ÃÒªº¨Ï¥ÎªÌ«O¯d 120 ¤Ñ */ + +/* «O¯d±b¸¹´Á -- ´»°² */ +#define VAC_NEWUSR 7 /* µn¤J¤£¶W¹L¤T¦¸ªº¨Ï¥ÎªÌ«O¯d 7 ¤Ñ */ +#define VAC_FORFUN 180 /* ¥¼§¹¦¨¨¤À»{ÃÒªº¨Ï¥ÎªÌ«O¯d 180 ¤Ñ */ +#define VAC_OCCUPY 180 /* ¤w§¹¦¨¨¤À»{ÃÒªº¨Ï¥ÎªÌ«O¯d 180 ¤Ñ */ + + +static time_t due_newusr; +static time_t due_forfun; +static time_t due_occupy; + + +static int visit = 0; /* Á` ID ªº¼Æ¥Ø */ +static int prune = 0; /* ³Q²M°£IDªº¼Æ¥Ø */ +static int manager = 0; /* ºÞ²zªÌªº¼Æ¥Ø */ +static int invalid = 0; /* ¥¼»{ÃÒ³q¹LIDªº¼Æ¥Ø */ + + +static FILE *flog; +static FILE *flst; + +#ifdef CHECK_LAZYBM +static time_t due_lazybm; +static int lazybm = 0; /* °½ÃiªO¥Dªº¼Æ¥Ø */ +static FILE *fbm; +#endif + +#ifdef EADDR_GROUPING +static FILE *faddr; +#endif + + +/* ----------------------------------------------------- */ +/* ²MªÅ .USR ¸Ì±ªºÄæ¦ì */ +/* ----------------------------------------------------- */ + + +static int funo; +static int max_uno; + + +static void +userno_free(uno) + int uno; +{ + off_t off; + int fd; + static SCHEMA schema; /* itoc.031216.µù¸Ñ: ¥Î static ¬O¦]¬° schema.userid n¤@ª½³Q²M¦¨¥þ¹s */ + + fd = funo; + + /* flock(fd, LOCK_EX); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_exlock(fd); + + time(&schema.uptime); + off = (uno - 1) * sizeof(SCHEMA); + if (lseek(fd, off, SEEK_SET) < 0) + exit(2); + if (write(fd, &schema, sizeof(SCHEMA)) != sizeof(SCHEMA)) + exit(2); + + /* flock(fd, LOCK_UN); */ + /* Thor.981205: ¥Î fcntl ¨ú¥Nflock, POSIX¼Ð·Ç¥Îªk */ + f_unlock(fd); +} + + +/* ----------------------------------------------------- */ +/* Åã¥Ü¥Î¨ç¦¡ */ +/* ----------------------------------------------------- */ + + +static void +levelmsg(str, level) + char *str; + int level; +{ + static char perm[] = STR_PERM; + int len = 32; + char *p = perm; + + do + { + *str = (level & 1) ? *p : '-'; + p++; + str++; + level >>= 1; + } while (--len); + *str = '\0'; +} + + +static void +datemsg(str, chrono) + char *str; + time_t *chrono; +{ + struct tm *t; + + t = localtime(chrono); + /* Thor.990329: y2k */ + sprintf(str, "%02d/%02d/%02d%3d:%02d:%02d ", + t->tm_year % 100, t->tm_mon + 1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); +} + + +/*-------------------------------------------------------*/ +/* ¬ÝªOÅv³¡¤À¶·»P board.c ¬Û®e */ +/*-------------------------------------------------------*/ + + +static BCACHE *bshm; + + +static void +init_bshm() +{ + /* itoc.030727: ¦b¶}±Ò bbsd ¤§«e¡AÀ³¸Ó´Nn°õ¦æ¹L account¡A + ©Ò¥H bshm À³¸Ó¤w³]©w¦n */ + + bshm = shm_new(BRDSHM_KEY, sizeof(BCACHE)); + + if (bshm->uptime <= 0) /* bshm ¥¼³]©w§¹¦¨ */ + exit(0); +} + + +static int num_bm = 0; +static char all_bm[MAXBOARD * BMLEN / 3][IDLEN + 1]; /* ¨CªO¦Ü¦h¦³ (BMLEN / 3) ÓªO¥D */ + + +static int +bm_cmp(a, b) /* ¨ä¹ê´N¬O str_cmp */ + char *a, *b; +{ + return str_cmp(a, b); +} + + +static char * /* 1: ¦b¥þ¯¸ªO¥D¦W³æ¤º */ +check_allBM(userid) + char *userid; /* lower case userid */ +{ + return bsearch(userid, all_bm, num_bm, IDLEN + 1, bm_cmp); +} + + +static void +collect_allBM() +{ + BRD *head, *tail; + char *ptr, *str, buf[BMLEN + 1]; + + /* ¥h bshm ¤¤§ì¥X©Ò¦³ brd->BM */ + + head = bshm->bcache; + tail = head + bshm->number; + do /* ¦Ü¤Ö¦³ note ¤@ªO¡A¤£¥²¹ï¬ÝªO°µÀˬd */ + { + ptr = buf; + strcpy(ptr, head->BM); + + while (*ptr) /* §â brd->BM ¤¤ bm1/bm2/bm3/... ¦UÓ bm §ì¥X¨Ó */ + { + if (str = strchr(ptr, '/')) + *str = '\0'; + if (!check_allBM(ptr)) + { + strcpy(all_bm[num_bm], ptr); + num_bm++; + qsort(all_bm, num_bm, IDLEN + 1, bm_cmp); + } + if (!str) + break; + ptr = str + 1; + } + } while (++head < tail); +} + + +/* ----------------------------------------------------- */ +/* Àˬd¦@¥Î email */ +/* ----------------------------------------------------- */ + +#ifdef EADDR_GROUPING +/* + Thor.980930: ±N¦P¤@email addrªºaccount, ¦¬¶°°_¨Ó¨Ã¦Cªí ¤u§@ì²z: + 1. _hash() ±N email addr ¼ÆÈ¤Æ + 2.¥Îbinary search, §ä¨ì«happend userno, §ä¤£¨ì«h insert ·sentry + 3.±N userno list ¾ã²z¦C¥X + + ¸ê®Æµ²ºc: chain: int hash, int link_userno plist: int next_userno + + ¼È®É¹w¦ôemail addrÁ`¼Æ¤£¶W¹L100000, + ¼È®É¹w¦ôuserÁ`¼Æ¤£¶W¹L 100000 + */ + +typedef struct +{ + int hash; + int link; +} Chain; + +static Chain *chain; +static int *plist; +static int numC; + +static void +eaddr_group(userno, eaddr) + int userno; + char *eaddr; +{ + int left, right, mid, i; + int hash = str_hash(eaddr, 0); + + left = 0; + right = numC - 1; + for (;;) + { + int cmp; + Chain *cptr; + + if (left > right) /* Thor.980930: §ä¨S */ + { + for (i = numC; i > left; i--) + chain[i] = chain[i - 1]; + + cptr = &chain[left]; + cptr->hash = hash; + cptr->link = userno; + plist[userno] = 0; /* Thor: tail */ + numC++; + break; + } + + mid = (left + right) >> 1; + cptr = &chain[mid]; + cmp = hash - cptr->hash; + + if (!cmp) + { + plist[userno] = cptr->link; + cptr->link = userno; + break; + } + + if (cmp < 0) + right = mid - 1; + else + left = mid + 1; + } +} + + +static void +report_eaddr_group() +{ + int i, j, cnt; + off_t off; + int fd; + SCHEMA s; + + fprintf(faddr, "Email registration over %d times list\n\n", EMAIL_REG_LIMIT); + + for (i = 0; i < numC; i++) + { + for (cnt = 0, j = chain[i].link; j; cnt++, j = plist[j]) + ; + + if (cnt > EMAIL_REG_LIMIT) + { + fprintf(faddr, "\n> %d\n", chain[i].hash); + for (j = chain[i].link; j; j = plist[j]) + { + off = (j - 1) * sizeof(SCHEMA); + if (lseek(funo, off, SEEK_SET) < 0) + { + fprintf(faddr, "==> %d) can't lseek\n", j); + continue; + } + if (read(funo, &s, sizeof(SCHEMA)) != sizeof(SCHEMA)) + { + fprintf(faddr, "==> %d) can't read\n", j); + continue; + } + else + { + ACCT acct; + char buf[256]; + + if (s.userid[0] <= ' ') + { + fprintf(faddr, "==> %d) has been reapered\n", j); + continue; + } + usr_fpath(buf, s.userid, FN_ACCT); + fd = open(buf, O_RDONLY); + if (fd < 0) + { + fprintf(faddr, "==> %d)%-13s can't open\n", j, s.userid); + continue; + } + if (read(fd, &acct, sizeof(ACCT)) != sizeof(ACCT)) + { + fprintf(faddr, "==> %d)%-13s can't read\n", j, s.userid); + continue; + } + close(fd); + + datemsg(buf, &acct.lastlogin); + fprintf(faddr, "%5d) %-13s%s[%d]\t%s\n", acct.userno, acct.userid, buf, acct.numlogins, acct.email); + } + } + } + } +} +#endif + + +/* ----------------------------------------------------- */ +/* ¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +reaper(fpath, lowid) + char *fpath; + char *lowid; +{ + int fd, login, userno; + usint ulevel; + time_t life; + char buf[256], data[40]; + ACCT acct; + + sprintf(buf, "%s/" FN_ACCT, fpath); + fd = open(buf, O_RDWR); + if (fd < 0) + { /* Thor.981001: ¥[¨Ç log */ + fprintf(flog, "acct can't open %-13s ==> %s\n", lowid, buf); + return; + } + + if (read(fd, &acct, sizeof(ACCT)) != sizeof(ACCT)) + { + fprintf(flog, "acct can't read %-13s ==> %s\n", lowid, buf); + close(fd); + return; + } + + ulevel = acct.userlevel; + + /* ¦³ PERM_BM ¦ý¤£¦b¥þ¯¸ªO¥D¦W³æ¤º¡A²¾°£¨ä PERM_BM */ + if ((ulevel & PERM_BM) && !check_allBM(lowid)) + { + ulevel ^= PERM_BM; + acct.userlevel = ulevel; + lseek(fd, 0, SEEK_SET); + write(fd, &acct, sizeof(ACCT)); + } + + close(fd); + + userno = acct.userno; + + if ((userno <= 0) || (userno > max_uno)) + { + fprintf(flog, "%5d) %-13s ==> %s\n", userno, acct.userid, buf); + return; + } + + life = acct.lastlogin; /* ¥²¤£¬° 0 */ + login = acct.numlogins; + +#ifdef EADDR_GROUPING + if (ulevel & PERM_VALID) /* Thor.980930: ¥u¬Ý³q¹L»{ÃÒªº email, ¥þºâ */ + eaddr_group(userno, acct.email); +#endif + + if (ulevel & (PERM_XEMPT | PERM_BM | PERM_ALLADMIN)) /* ¦³³o¨ÇÅvªÌ¤£¬å */ + { + datemsg(buf, &acct.lastlogin); + levelmsg(data, ulevel); + fprintf(flst, "%5d) %-13s%s[%s] %d\n", userno, acct.userid, buf, data, login); + manager++; + +#ifdef CHECK_LAZYBM + if ((ulevel & PERM_BM) && life < due_lazybm) + { + fprintf(fbm, "%5d) %-13s%s %d\n", userno, acct.userid, buf, login); + lazybm++; + } +#endif + } + else if (ulevel) /* guest.ulevel == 0, ¥Ã»·«O¯d */ + { + if (ulevel & PERM_PURGE) /* lkchu.990221: ¡u²M°£±b¸¹¡v */ + { + life = 0; + } + else if (ulevel & PERM_DENYLOGIN) /* itoc.010927: ¦³¡u¸T¤î¤W¯¸¡vªº¤£¬å¡A¦ýY¦³¡u²M°£±b¸¹¡vÅv·Ó¬å */ + { + /* life = 1; */ /* ¤£»Ýn¡A«e±¦³¤F */ + } + else if (ulevel & PERM_VALID) + { + if (life < due_occupy) + life = 0; + } + else + { + if (login <= 3 && life < due_newusr) + life = 0; + else if (life < due_forfun) + life = 0; + else + invalid++; + } + + if (!life) + { + sprintf(buf, "usr/@/%s", lowid); + + while (rename(fpath, buf)) + { + extern int errno; + + fprintf(flog, "rename %s ==> %s : %d\n", fpath, buf, errno); + sprintf(buf, "usr/@/%s.%d", lowid, ++life); + } + + userno_free(userno); + datemsg(buf, &acct.lastlogin); + fprintf(flog, "%5d) %-13s%s%d\n", userno, acct.userid, buf, login); + prune++; + } + } + + visit++; +} + + +static void +traverse(fpath) + char *fpath; +{ + DIR *dirp; + struct dirent *de; + char *fname, *str; + + /* visit the second hierarchy */ + + if (!(dirp = opendir(fpath))) + { + fprintf(flog, "## unable to enter hierarchy [%s]\n", fpath); + return; + } + + for (str = fpath; *str; str++); + *str++ = '/'; + + while (de = readdir(dirp)) + { + fname = de->d_name; + if (fname[0] > ' ' && fname[0] != '.') + { + strcpy(str, fname); + reaper(fpath, fname); + } + } + closedir(dirp); +} + + +int +main() +{ + int ch; + time_t start, end; + struct tm *ptime; + struct stat st; + char *fname, fpath[256]; + + setuid(BBSUID); + setgid(BBSGID); + chdir(BBSHOME); + umask(077); + + flog = fopen(FN_RUN_REAPER, "w"); + if (flog == NULL) + exit(1); + + flst = fopen(FN_RUN_MANAGER, "w"); + if (flst == NULL) + exit(1); + +#ifdef CHECK_LAZYBM + fbm = fopen(FN_RUN_LAZYBM, "w"); + if (fbm == NULL) + exit(1); +#endif + +#ifdef EADDR_GROUPING + faddr = fopen(FN_RUN_EMAILADDR, "w"); + if (faddr == NULL) + exit(1); +#endif + +#ifdef EADDR_GROUPING + funo = open(FN_SCHEMA, O_RDWR | O_CREAT, 0600); /* Thor.980930: for read name */ +#else + funo = open(FN_SCHEMA, O_WRONLY | O_CREAT, 0600); +#endif + + if (funo < 0) + exit(1); + + /* °²³]²M°£±b¸¹´Á¶¡¡A·sµù¥U¤H¼Æ¤£·|¶W¹L 300 ¤H */ + + fstat(funo, &st); + max_uno = st.st_size / sizeof(SCHEMA) + 300; + + init_bshm(); + collect_allBM(); + + time(&start); + ptime = localtime(&start); + + /* itoc.011002.µù¸Ñ: ¤£¯à¦b¤@¶}¾Ç´N°¨¤W apply ÄY®æªº®É¶¡¨î¡A + §_«h«Ü¦h user ·|¦]¬°¾ãÓ´»°²¨S¦³¤W¯¸¡A¦b¤@¶}¾Ç´N³Q reaper ±¼ */ + + if ((ptime->tm_mon >= 6 && ptime->tm_mon <= 8) || /* 7 ¤ë¨ì 9 ¤ë¬O´»°² */ + (ptime->tm_mon >= 1 && ptime->tm_mon <= 2)) /* 2 ¤ë¨ì 3 ¤ë¬O´H°² */ + { + due_newusr = start - VAC_NEWUSR * 86400; + due_forfun = start - VAC_FORFUN * 86400; + due_occupy = start - VAC_OCCUPY * 86400; + } + else + { + due_newusr = start - DAY_NEWUSR * 86400; + due_forfun = start - DAY_FORFUN * 86400; + due_occupy = start - DAY_OCCUPY * 86400; + } + +#ifdef CHECK_LAZYBM + due_lazybm = start - DAY_LAZYBM * 86400; +#endif + +#ifdef EADDR_GROUPING + chain = (Chain *) malloc(max_uno * sizeof(Chain)); + plist = (int *)malloc((max_uno + 1) * sizeof(int)); + if (!chain || !plist) + { + fprintf(faddr, "out of memory....\n"); + exit(1); + } +#endif + + strcpy(fname = fpath, "usr/@"); + mkdir(fname, 0700); + fname = (char *)strchr(fname, '@'); + + /* visit the first hierarchy */ + + for (ch = 'a'; ch <= 'z'; ch++) + { + fname[0] = ch; + fname[1] = '\0'; + traverse(fpath); + } + +#ifdef EADDR_GROUPING + report_eaddr_group(); /* Thor.980930: before close funo */ +#endif + + close(funo); + + fprintf(flst, "\nManager: %d\n", manager); + fclose(flst); + + time(&end); + fprintf(flog, "# ¶}©l®É¶¡¡G%s\n", Btime(&start)); + fprintf(flog, "# µ²§ô®É¶¡¡G%s\n", Btime(&end)); + end -= start; + start = end % 60; + end /= 60; + fprintf(flog, "# Á`p¯Ó®É¡G%d:%d:%d\n", end / 60, end % 60, start); + fprintf(flog, "# µù¥U¤H¼Æ¡G%d\n", visit); /* ¥¼²M°£«eªºÁ`¼Æ */ + fprintf(flog, "# ²M°£¤H¼Æ¡G%d\n", prune); + fprintf(flog, "# ¥¼»{ÃҼơG%d\n", invalid); + fclose(flog); + +#ifdef CHECK_LAZYBM + fprintf(fbm, "\nLazy BM for %d days: %d\n", DAY_LAZYBM, lazybm); + fclose(fbm); +#endif + +#ifdef EADDR_GROUPING + free(chain); + free(plist); + fclose(faddr); +#endif + + exit(0); +} diff --git a/util/redir.c b/util/redir.c new file mode 100644 index 0000000..33f5de7 --- /dev/null +++ b/util/redir.c @@ -0,0 +1,358 @@ +/*-------------------------------------------------------*/ +/* util/redir.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¦Û°Ê««Ø.DIRµ{¦¡ */ +/* create : 99/10/07 */ +/* update : 04/11/29 */ +/* author : Thor.bbs@bbs.cs.nthu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ +/* input : scan current directory */ +/* output : generate .DIR.re */ +/*-------------------------------------------------------*/ + + +#if 0 + + ¦¹µ{¦¡¥i¥H««Ø¬ÝªO¡BºëµØ°Ï¡B«H½cªº .DIR + ·| scan current directory ¨Ó²£¥Í .DIR.re + ¥H chrono ¨Ó±Æ§Ç + +#endif + + +#include "bbs.h" + + +#define FNAME_DB_SIZE 2048 + + +typedef char FNAME[9]; +static FNAME *n_pool; +static int n_size, n_head; + + +static int +pool_add(fname) + FNAME fname; +{ + char *p; + + /* initial pool */ + if (!n_pool) + { + n_pool = (FNAME *) malloc(FNAME_DB_SIZE * sizeof(FNAME)); + n_size = FNAME_DB_SIZE; + n_head = 0; + } + + if (n_head >= n_size) + { + n_size += (n_size >> 1); + n_pool = (FNAME *) realloc(n_pool, n_size * sizeof(FNAME)); + } + + p = n_pool[n_head]; + + if (strlen(fname) != 8) + return -1; + + strcpy(p, fname); + + n_head++; + + return 0; +} + + +static int type; /* 'b':¬ÝªO 'g':ºëµØ°Ï 'm':«H½c */ + + +static HDR * +article_parse(fname) + char *fname; +{ + char buf[ANSILINELEN], *ptr1, *ptr2, *ptr3; + FILE *fp; + static HDR hdr; + + memset(&hdr, 0, sizeof(HDR)); + + /* fill in chrono/date/xmode/xid/xname */ + hdr.chrono = chrono32(fname); + str_stamp(hdr.date, &hdr.chrono); + strcpy(hdr.xname, fname); + if (type == 'm') + hdr.xmode = MAIL_READ; + + if (*fname == 'F') /* ¦pªG¬O¨÷©v¡A¥Ñ©ó¨S¦³¨ä¥L¸ê°T¤F¡A©Ò¥H¥u¯àÀH«Kµ¹ */ + { + hdr.xmode = GEM_FOLDER; + strcpy(hdr.owner, STR_SYSOP); + strcpy(hdr.nick, SYSOPNICK); + strcpy(hdr.title, "·É®ü¬B¿ò"); + return &hdr; + } + + sprintf(buf, "%c/%s", (type == 'm') ? '@' : fname[7], fname); + if (fp = fopen(buf, "r")) + { + if (fgets(buf, sizeof(buf), fp)) + { + if (ptr1 = strchr(buf, '\n')) + ptr1 = '\0'; + + if (!strncmp(buf, STR_AUTHOR1 " ", LEN_AUTHOR1 + 1)) + ptr1 = buf + LEN_AUTHOR1 + 1; + else if (!strncmp(buf, STR_AUTHOR2 " ", LEN_AUTHOR2 + 1)) + ptr1 = buf + LEN_AUTHOR2 + 1; + else + ptr1 = NULL; + + if (ptr1 && *ptr1) + { + ptr2 = strchr(ptr1 + 1, '@'); + ptr3 = strchr(ptr1 + 1, '('); + + if (ptr2 && (!ptr3 || ptr2 < ptr3)) /* ¦b¼ÊºÙ¸Ì±ªº @ ¤£ºâ¬O email */ + { + str_from(ptr1, hdr.owner, hdr.nick); + hdr.xmode |= POST_INCOME; /* also MAIL_INCOME */ + } + else if (ptr3) + { + ptr3[-1] = '\0'; + str_ncpy(hdr.owner, ptr1, sizeof(hdr.owner)); + if (ptr2 = strchr(ptr3 + 1, ')')) + { + *ptr2 = '\0'; + str_ncpy(hdr.nick, ptr3 + 1, sizeof(hdr.nick)); + } + } + } + + if (fgets(buf, sizeof(buf), fp)) + { + if (ptr1 = strchr(buf, '\n')) + *ptr1 = '\0'; + + if (!strncmp(buf, "¼ÐÃD: ", LEN_AUTHOR1 + 1)) + ptr1 = buf + LEN_AUTHOR1 + 1; + else if (!strncmp(buf, "¼Ð ÃD: ", LEN_AUTHOR2 + 1)) + ptr1 = buf + LEN_AUTHOR2 + 1; + else + ptr1 = NULL; + + if (ptr1 && *ptr1) /* ¦³¼ÐÃDÄæ¦ì */ + str_ncpy(hdr.title, ptr1, sizeof(hdr.title)); + } + } + + fclose(fp); + } + + return &hdr; +} + + +static char *allindex = ".DIR.tmp"; + + +static void +allindex_collect() +{ + int i; + char *fname, fpath[64]; + FILE *fp; + + /* ±N©Ò¦³ªº F* ³£¼g¤J¤@ӼȦsÀÉ */ + if (fp = fopen(allindex, "w")) + { + for (i = 0; i < n_head; i++) + { + fname = n_pool[i]; + + if (*fname != 'F') + continue; + + sprintf(fpath, "%c/%s", fname[7], fname); + f_suck(fp, fpath); + } + fclose(fp); + } +} + + +static int +allindex_search(fname) + char *fname; +{ + HDR old; + int fd; + int rc = 0; + + if ((fd = open(allindex, O_RDONLY)) >= 0) + { + while (read(fd, &old, sizeof(HDR)) == sizeof(HDR)) + { + if (!strcmp(fname, old.xname)) + { + rc = 1; + break; + } + } + close(fd); + } + return rc; +} + + +static int +fname_cmp(s1, s2) + char *s1, *s2; +{ + return strcmp(s1 + 1, s2 + 1); +} + + +static void +usage(argv) + char *argv[]; +{ + char *str = argv[0]; + + printf("Usage: ½Ð«ü©w°Ñ¼Æ\n"); + printf(" ««Ø ¬ÝªO¤å³¹ ¯Á¤Þ½Ð°õ¦æ %s -b\n", str); + printf(" ««ØºëµØ°Ï¤å³¹¯Á¤Þ½Ð°õ¦æ %s -g\n", str); + printf(" ««Ø «H½c«H¥ó ¯Á¤Þ½Ð°õ¦æ %s -m\n", str); + printf("°õ¦æµ²§ô¥H«á¡A¦A±N .DIR.re Âл\\ .DIR §Y¥i\n"); + + exit(0); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int i; + char *fname, buf[10]; + FILE *fp; + HDR *hdr; + struct dirent *de; + DIR *dirp; + + if (argc != 2) + usage(argv); + + type = argv[1][1]; + if (type != 'b' && type != 'g' && type != 'm') + usage(argv); + + /* readdir 0-9A-V(¬ÝªO¡BºëµØ°Ï) ©Î @(«H½c) */ + + buf[1] = '\0'; + + for (i = 0; i < 32; i++) + { + *buf = (type == 'm') ? '@' : radix32[i]; + + if (dirp = opendir(buf)) + { + while (de = readdir(dirp)) + { + fname = de->d_name; + if (type == 'b' && *fname != 'A') /* ¬ÝªO¥²¬O A1234567 */ + continue; + if (type == 'g' && *fname != 'A' && *fname != 'F') /* ºëµØ°Ï¥²¬O A1234567 ©Î F1234567 */ + continue; + if (type == 'm' && *fname != '@') /* «H½c¥²¬O @1234567 */ + continue; + + if (pool_add(fname) < 0) + printf("Bad article/folder name %c/%s\n", *buf, fname); + } + closedir(dirp); + } + + if (type == 'm') /* «H½c¥u»Ýn±½ @ ³oӥؿý */ + break; + } + + if (n_head) + { + /* ¬ÝªO/«H½c ´Nª½±µ§â n_pool ¸Ì±ªº©Ò¦³ÀÉ®×¥[¶i .DIR §Y¥i */ + /* ºëµØ°Ïªº¸Ü¡A«h¬O¥u»Ýn§â¨S¦³¦b¨ä¥L F* ¸Ì±ªº¥[¤J .DIR */ + + /* qsort chrono */ + if (n_head > 1) + qsort(n_pool, n_head, sizeof(FNAME), fname_cmp); + + if (type == 'g') + allindex_collect(); + + /* generate .DIR.re */ + if (fp = fopen(".DIR.re", "w")) + { + /* for each file/folder */ + for (i = 0; i < n_head; i++) + { + fname = n_pool[i]; + + if (type == 'g' && allindex_search(fname)) /* ¤w¸g¦b¨ä¥L¨÷©v¸Ì±¤F¡A¨º´N¤£·|¬O¦b .DIR ¸Ì± */ + continue; + + /* parse header */ + if (hdr = article_parse(fname)) + fwrite(hdr, sizeof(HDR), 1, fp); + } + fclose(fp); + + /* add */ + time_t now; + struct tm *ptime; + time(&now); + ptime = localtime(&now); + char cmd[100], oldfname[60]; + sprintf(oldfname, ".DIR.before.%02d%02d%02d-%02d%02d%02d", + ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday, + ptime->tm_hour, ptime->tm_min, ptime->tm_sec); + sprintf (cmd, "cp .DIR %s", oldfname); + system (cmd); + + FILE *fpold = fopen (oldfname, "r"); + + int posold = 0; + HDR hdrold, hdrnew; + + while (!rec_get(oldfname, &hdrold, sizeof(HDR), posold)) + { + fp = fopen (".DIR.re", "a+b"); + int posnew = 0; + while (!rec_get(".DIR.re", &hdrnew, sizeof(HDR), posnew)) + { + if (!strcmp(hdrnew.xname, hdrold.xname)) + { + hdrnew.xmode = hdrold.xmode; + hdrnew.score = hdrold.score; + rec_put(".DIR.re", &hdrnew, sizeof(HDR), posnew, NULL); + } + posnew ++; + } + fclose (fp); + posold++; + } + + fclose (fpold); + system ("cp .DIR.re .DIR"); + /* above */ + + } + + if (type == 'g') + unlink(allindex); + } + + return 0; +} diff --git a/util/rmbadmail.c b/util/rmbadmail.c new file mode 100644 index 0000000..6973e96 --- /dev/null +++ b/util/rmbadmail.c @@ -0,0 +1,318 @@ +/*-------------------------------------------------------*/ +/* util/rmbadmail.c ( YZU WindTop 2000) */ +/*-------------------------------------------------------*/ +/* author : visor.bbs@bbs.yzu.edu.tw */ +/* target : §R°£[«H½c|¬ÝªO]¥¼¦b .DIR ¸Ìªº«H¥ó */ +/* create : 00/08/30 */ +/* update : 01/02/16 */ +/*-------------------------------------------------------*/ +/* syntax : rmbadmail */ +/*-------------------------------------------------------*/ + + +#undef FAKE_IO +#include "bbs.h" + + +static int reserve, r_size, ulink, u_size; + + +static void +reaper(fpath, lowid) + char *fpath; + char *lowid; +{ + int fd, size, check; + char buf[256], *fname, folder[128], *ptr; + DIR *dirp; + struct dirent *de; + HDR *head, *tail, *base; + struct stat st; + time_t now; + + now = time(0) - 60; + + printf("> processing account %-20s ", lowid); + + sprintf(buf, "%s/.DIR", fpath); + + if ((fd = open(buf, O_RDONLY)) >= 0) + { + fstat(fd, &st); + size = st.st_size / sizeof(HDR); + + if (size <= 0) + { + base = NULL; + } + else + { + base = (HDR *) malloc(sizeof(HDR) * size); + tail = base + size; + read(fd, base, sizeof(HDR) * size); + } + + close(fd); + } + else + { + size = 0; + base = NULL; + } + + printf("total mail : %d\n", size); + sprintf(folder, "%s/@", fpath); + + if (!(dirp = opendir(folder))) + { + if (base) + free(base); + return; + } + + ptr = strchr(folder, '@') + 1; + *ptr++ = '/'; + + while (de = readdir(dirp)) + { + check = 0; + fname = de->d_name; + if (fname[0] > ' ' && fname[0] != '.') + { + if (base) + { + for (head = base; head < tail; head++) + { + if (!strcmp(head->xname, fname)) + { + check = 1; + break; + } + } + } + if (!check) + { + strcpy(ptr, fname); + if (!(!stat(folder, &st) && (st.st_atime > now))) + { + u_size += st.st_size; + ulink++; + printf("file is not in HDR : %s : unlink !\n", fname); + printf("--> unlinking %s\n", folder); + +#ifndef FAKE_IO + unlink(folder); +#endif + } + else + { + r_size += st.st_size; + reserve++; + printf("file is not in HDR : %s : reserve !\n", fname); + } + } + } + } + closedir(dirp); + free(base); +} + + +static void +expire(fpath, lowid) + char *fpath; + char *lowid; +{ + int fd, size, check; + char buf[256], *fname, folder[128], *ptr, *str; + DIR *dirp; + struct dirent *de; + HDR *head, *tail, *base; + struct stat st; + time_t now; + + now = time(0) - 60; + + printf("> processing board %-20s ", lowid); + + sprintf(buf, "%s/.DIR", fpath); + if ((fd = open(buf, O_RDONLY)) >= 0) + { + fstat(fd, &st); + size = st.st_size / sizeof(HDR); + if (size <= 0) + { + base = NULL; + } + else + { + base = (HDR *) malloc(sizeof(HDR) * size); + tail = base + size; + read(fd, base, sizeof(HDR) * size); + } + close(fd); + } + else + { + base = NULL; + size = 0; + } + printf("total article : %d\n", size); + sprintf(folder, "%s/@", fpath); + + str = strchr(folder, '@'); + ptr = str + 1; + *ptr++ = '/'; + *str = '0'; + + while (1) + { + if ((dirp = opendir(folder))) + { + while (de = readdir(dirp)) + { + check = 0; + fname = de->d_name; + if (fname[0] > ' ' && fname[0] != '.') + { + if (base) + { + for (head = base; head < tail; head++) + { + if (!strcmp(head->xname, fname)) + { + check = 1; + break; + } + } + } + if (!check) + { + strcpy(ptr, fname); + if (!(!stat(folder, &st) && (st.st_atime > now))) + { + u_size += st.st_size; + ulink++; + printf("file is not in HDR : %s : unlink !\n", fname); + printf("--> unlinking %s\n", folder); + +#ifndef FAKE_IO + unlink(folder); +#endif + } + else + { + r_size += st.st_size; + reserve++; + printf("file is not in HDR : %s : reserve !\n", fname); + } + } + } + } + closedir(dirp); + } + if (++(*str) == ('9' + 1)) + *str = 'A'; + if ((*str) == 'W') + break; + } + free(base); +} + + +static void +traverse(fpath, mode) + char *fpath; + int mode; +{ + DIR *dirp; + struct dirent *de; + char *fname, *str; + + if (!(dirp = opendir(fpath))) + { + return; + } + for (str = fpath; *str; str++); + *str++ = '/'; + + while (de = readdir(dirp)) + { + fname = de->d_name; + if (fname[0] > ' ' && fname[0] != '.') + { + strcpy(str, fname); + if (mode == 1) + reaper(fpath, fname); + else if (mode == 2) + expire(fpath, fname); + } + } + closedir(dirp); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int ch; + char *fname, fpath[256], buf[32]; + + chdir(BBSHOME); + + if (argc > 1 && !strncmp(argv[1], "-a", 2)) + { + if (argc > 2) + { + str_lower(buf, argv[2]); + sprintf(fpath, "usr/%c/%s", *buf, buf); + if (!access(fpath, 0)) + reaper(fpath, buf); + else + printf("error open account %s\n", buf); + } + else + { + strcpy(fname = fpath, "usr/@"); + fname = (char *) strchr(fname, '@'); + for (ch = 'a'; ch <= 'z'; ch++) + { + fname[0] = ch; + fname[1] = '\0'; + traverse(fpath, 1); + } + for (ch = '0'; ch <= '9'; ch++) + { + fname[0] = ch; + fname[1] = '\0'; + traverse(fpath, 1); + } + } + } + else if (argc > 1 && !strncmp(argv[1], "-b", 2)) + { + if (argc > 2) + { + strcpy(buf, argv[2]); + sprintf(fpath, "brd/%s", buf); + if (!access(fpath, 0)) + expire(fpath, buf); + else + printf("error open board %s\n", buf); + } + else + { + strcpy(fpath, "brd"); + traverse(fpath, 2); + } + } + else + { + printf("syntax : rmbadmail [-a|-b] [account|board]\n"); + } + printf("total unlink %10d unlink size : %10d\n", ulink, u_size); + printf("total reserve %10d reserve size : %10d\n", reserve, r_size); + return 0; +} diff --git a/util/setperm.c b/util/setperm.c new file mode 100644 index 0000000..281e06c --- /dev/null +++ b/util/setperm.c @@ -0,0 +1,88 @@ +/*-------------------------------------------------------*/ +/* util/setperm.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : ³]©w¨Ï¥ÎªÌÅv */ +/* author : gslin@abpe.org */ +/* create : 00/07/28 */ +/* update : */ +/*-------------------------------------------------------*/ + + +#if 0 + ±N itoc ¤Î sysop ³]¬°©Ò¦³Åv³£¦³: + setperm -1 itoc sysop + setperm 11111111111111111111111111111111 itoc sysop + + ±N itoc ³]¬°¥u¦³°ò¥»Åv: + setperm 1 itoc + setperm 00000000000000000000000000000001 itoc + + ±N guest ³]¬°¨S¦³Åv: + setperm 0 guest + setperm 00000000000000000000000000000000 guest +#endif + + +#include "bbs.h" + + +static void +usage(msg) + char *msg; +{ + printf("Usage: %s Perm32 UserID1 [UserID2] ...\n", msg); + exit(1); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int i; + usint userlevel; + + if (argc < 3) + usage(argv[0]); + + if (strlen(argv[1]) != 32) + { + userlevel = (usint) atoi(argv[1]); + } + else + { + userlevel = 0; + + for (i = 0; i < 32; i++) + { + char c = argv[1][i]; + + if (c != '0' && c != '1') + usage(argv[0]); + + userlevel <<= 1; + userlevel |= c - '0'; + } + } + + chdir(BBSHOME); + + for (i = 2; i < argc; i++) + { + ACCT cuser; + char fpath[64]; + + usr_fpath(fpath, argv[i], FN_ACCT); + if (rec_get(fpath, &cuser, sizeof(cuser), 0) < 0) + { + printf("%s: read error (maybe no such id?)\n", argv[i]); + continue; + } + + cuser.userlevel = userlevel; + + if (rec_put(fpath, &cuser, sizeof(cuser), 0, NULL) < 0) + printf("%s: write error\n", argv[i]); + } +} diff --git a/util/setusr.c b/util/setusr.c new file mode 100644 index 0000000..2407574 --- /dev/null +++ b/util/setusr.c @@ -0,0 +1,166 @@ +/*-------------------------------------------------------*/ +/* util/setusr.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ³]©w¨Ï¥ÎªÌ¸ê®Æ */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/* create : 01/07/16 */ +/* update : */ +/*-------------------------------------------------------*/ + + +#if 0 + ³]©w itoc ªº ©m¦W¬°¤ý¤j©ú ¼ÊºÙ¬°¤j©ú »È¹ô¦³1000 ª÷¹ô¦³500 + setusr -r ¤ý¤j©ú -n ¤j©ú -m 1000 -g 500 itoc + + ³]©w itoc ªºÅv + setusr -p 11100...1101 itoc (Åv¦³ 32 = NUMPERMS ºØ) + ^^^^^ 32 Ó 0 ©M 1 + + ³]©w itoc ªº²ßºD + setusr -f 11100...1101 itoc (²ßºD¦³ 27 = NUMUFOS ºØ) + ^^^^^ 27 Ó 0 ©M 1 + + ¸Ó¨Ï¥ÎªÌ¥²¶·¤£¦b½u¤W¤~¦³®Ä +#endif + + +#include "bbs.h" + + +#define MAXUSIES 9 /* ¦@¦³ 9 ºØ¥i¥H§ïªº */ + +static void +usage(msg) + char *msg; +{ + int i, len; + char buf[80]; + char *usies[MAXUSIES] = + { + "r realname", "n username", "m money", "g gold", "# userno", + "e email", "j 1/0(justify)", "p userlevel", "f ufo" + }; + + + printf("Usage: %s [-%s] [-%s] [-%s] ... [-%s] UserID\n", + msg, usies[0], usies[1], usies[2], usies[MAXUSIES - 1]); + len = strlen(msg); + sprintf(buf, "%%%ds-%%s\n", len + MAXUSIES); + for (i = 0; i < MAXUSIES; i++) + printf(buf, "", usies[i]); +} + + +static usint +bitcfg(len, str) /* config bits */ + int len; /* ¸ÓÄæ¦ìªºªø«× */ + char *str; /* optarg */ +{ + int i; + char c; + usint bits; + + if (strlen(str) != len) /* ª½±µµ¹Ó¼Æ¦r */ + { + bits = (usint) atoi(str); + } + else + { + bits = 0; + for (i = 0; i < len; i++) + { + c = str[i]; + + if (c != '0' && c != '1') + { + printf("bit ¤@©wn¬O 0 ©Î 1\n"); + exit(1); + } + + bits <<= 1; + bits |= c - '0'; + } + } + + return bits; +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int c; + char *userid, fpath[64]; + ACCT acct; + + if (argc < 4 || argc % 2) /* argc n¬O°¸¼Æ */ + { + usage(argv[0]); + exit(1); + } + + chdir(BBSHOME); + + userid = argv[argc - 1]; + usr_fpath(fpath, userid, FN_ACCT); + if (rec_get(fpath, &acct, sizeof(ACCT), 0) < 0) + { + printf("%s: read error (maybe no such id?)\n", userid); + exit(1); + } + + while ((c = getopt(argc, argv, "r:n:m:g:#:e:j:p:f:")) != -1) + { + switch (c) + { + case 'r': /* realname */ + strcpy(acct.realname, optarg); + break; + + case 'n': /* username */ + strcpy(acct.username, optarg); + break; + + case 'm': /* money */ + acct.money = atoi(optarg); + break; + + case 'g': /* gold */ + acct.gold = atoi(optarg); + break; + + case '#': /* userno */ + acct.userno = atoi(optarg); + break; + + case 'e': /* email */ + strcpy(acct.email, optarg); + break; + + case 'j': /* justify */ + if (atoi(optarg)) /* »{ÃÒ³q¹L */ + acct.userlevel |= PERM_VALID; + else + acct.userlevel &= ~PERM_VALID; + time(&acct.tvalid); + break; + + case 'p': /* userlevel */ + acct.userlevel = bitcfg(NUMPERMS, optarg); + break; + + case 'f': /* ufo */ + acct.ufo = bitcfg(NUMUFOS, optarg); + break; + + default: + usage(argv[0]); + exit(0); + } + } + + if (rec_put(fpath, &acct, sizeof(ACCT), 0, NULL) < 0) + printf("%s: write error\n", userid); +} diff --git a/util/showACCT.c b/util/showACCT.c new file mode 100644 index 0000000..9df3d4b --- /dev/null +++ b/util/showACCT.c @@ -0,0 +1,116 @@ +/*-------------------------------------------------------*/ +/* util/showACCT.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : Åã¥Ü¨Ï¥ÎªÌ¸ê®Æ */ +/* create : 01/07/16 */ +/* update : */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +//#undef SHOW_PASSWORD /* Åã¥Ü±K½X («Ü¯Ó®É¶¡) */ + + + +//#ifdef SHOW_PASSWORD + +#define GUESS_LEN 8 /* ¥u´ú¤T½X(§t)¥H¤Uªº±K½X²Õ¦X (³Ì¦h¬O PSWDLEN) */ + +static char * +_bitmsg(str, level) + char *str; + int level; +{ + int cc; + int num; + static char msg[33]; + + num = 0; + while (cc = *str) + { + msg[num] = (level & 1) ? cc : '-'; + level >>= 1; + str++; + num++; + } + msg[num] = 0; + + return msg; +} + + +static inline void +showACCT(acct) + ACCT *acct; +{ + char msg1[40], msg2[40], msg3[40], msg4[40], msg5[40], msg6[40]; + + strcpy(msg1, _bitmsg(STR_PERM, acct->userlevel)); + strcpy(msg2, _bitmsg(STR_UFO, acct->ufo)); + strcpy(msg3, Btime(&(acct->firstlogin))); + strcpy(msg4, Btime(&(acct->lastlogin))); + strcpy(msg5, Btime(&(acct->tcheck))); + strcpy(msg6, Btime(&(acct->tvalid))); + + printf("> ------------------------------------------------------------------------------------------ \n" + "½s¸¹: %-15d [ID]: %-15s ©m¦W: %-15s ¼ÊºÙ: %-15s \n" + "Åv: %-37s ³]©w: %-37s \n" + "ñ¦W: %-37d ©Ê§O: %-15.2s \n" + "»È¹ô: %-15d ª÷¹ô: %-15d ¥Í¤é: %02d/%02d/%02d \n" + "¤W¯¸: %-15d ¤å³¹: %-15d µo«H: %-15d \n" + "º¦¸: %-37s ¤W¦¸: %-30s \n" + "Àˬd: %-37s ³q¹L: %-30s \n" + "µn¤J: %-30s \n" + "«H½c: %-60s \n", + acct->userno, acct->userid, acct->realname, acct->username, + msg1, msg2, + acct->signature, "¡H¡ñ¡ð" + (acct->sex << 1), + acct->money, acct->gold, acct->year, acct->month, acct->day, + acct->numlogins, acct->numposts, acct->numemails, + msg3, msg4, + msg5, msg6, + acct->lasthost, + acct->email); + +//#ifdef SHOW_PASSWORD + printf("%s\n", acct->passwd); +//#endif +} + + +int +main(argc, argv) + int argc; + char **argv; +{ + int i; + + if (argc < 2) + { + printf("Usage: %s UserID1 [UserID2] ...\n", argv[0]); + return -1; + } + + chdir(BBSHOME); + + for (i = 1; i < argc; i++) + { + ACCT acct; + char fpath[64]; + + usr_fpath(fpath, argv[i], FN_ACCT); + if (rec_get(fpath, &acct, sizeof(ACCT), 0) < 0) + { + printf("%s: read error (maybe no such id?)\n", argv[i]); + continue; + } + + showACCT(&acct); + } + printf("> ------------------------------------------------------------------------------------------ \n"); + + return 0; +} diff --git a/util/showBRD.c b/util/showBRD.c new file mode 100644 index 0000000..c5fae0a --- /dev/null +++ b/util/showBRD.c @@ -0,0 +1,79 @@ +/*-------------------------------------------------------*/ +/* util/showBRD.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : show board info */ +/* create : 01/10/05 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : showBRD [target_board] */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +static void +_bitmsg(msg, str, level) + char *msg, *str; + int level; +{ + int cc; + + printf(msg); + while (cc = *str) + { + printf("%c", (level & 1) ? cc : '-'); + level >>= 1; + str++; + } + printf("\n"); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int show_allbrd; + BRD brd; + FILE *fp; + + if (argc < 2) + show_allbrd = 1; + else + show_allbrd = 0; + + chdir(BBSHOME); + + if (!(fp = fopen(FN_BRD, "r"))) + return -1; + + int boards = 0; + + while (fread(&brd, sizeof(BRD), 1, fp) == 1) + { + if (show_allbrd || !str_cmp(brd.brdname, argv[1])) + { + printf("¬ÝªO¦WºÙ¡G%-13s ¬ÝªO¼ÐÃD¡G[%s] %s\n", brd.brdname, brd.class, brd.title); + printf("§ë²¼ª¬ºA¡G%-13d ¬ÝªOªO¥D¡G%s\n", brd.bvote, brd.BM); + _bitmsg(MSG_READPERM, STR_PERM, brd.readlevel); + _bitmsg(MSG_POSTPERM, STR_PERM, brd.postlevel); + _bitmsg(MSG_BRDATTR, STR_BATTR, brd.battr); + printf("¤å³¹½g¼Æ¡G%d\n", brd.bpost); + printf("¶}ªO®É¶¡¡G%s\n", Btime(&brd.bstamp)); + printf(".DIR®É¶¡¡G%s\n", Btime(&brd.btime)); + printf("³Ì«á¤@½g¡G%s\n", Btime(&brd.blast)); + + boards ++; + if (!show_allbrd) + break; + } + } + + fclose(fp); + + printf ("Total Boards = %d\n", boards); + return 0; +} diff --git a/util/showDIR.c b/util/showDIR.c new file mode 100644 index 0000000..bbf403c --- /dev/null +++ b/util/showDIR.c @@ -0,0 +1,81 @@ +/*-------------------------------------------------------*/ +/* util/showDIR.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : Åã¥Ü .DIR ¸ê®Æ */ +/* create : 03/05/24 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +static char * +_bitmsg(str, level) + char *str; + int level; +{ + int cc; + int num; + static char msg[33]; + + num = 0; + while (cc = *str) + { + msg[num] = (level & 1) ? cc : '-'; + level >>= 1; + str++; + num++; + } + msg[num] = 0; + + return msg; +} + + +static inline void +showHDR(hdr) + HDR *hdr; +{ + char msg1[40], msg2[40]; + + strcpy(msg1, Btime(&(hdr->chrono))); + strcpy(msg2, _bitmsg("0123456789ABCDEFGHIJKLMNOPQRSTUV", hdr->xmode)); + printf("> ------------------------------------------------------------------------------------------ \n" + "®É¶¡: %s\nmode: %s\nÀÉ®×: %s\n§@ªÌ: %s\n¼ÊºÙ: %s\n¤é´Á: %s\n¥DÃD: %s\n", + msg1, msg2, hdr->xname, hdr->owner, hdr->nick, hdr->date, hdr->title, hdr->title); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int pos; + char *fname; + HDR hdr; + + if (argc < 2) + { + printf("Usage: %s .DIR_path\n", argv[0]); + exit(1); + } + + fname = argv[1]; + if (strcmp(fname + strlen(fname) - 4, FN_DIR)) + { + printf("This is not a .DIR file.\n"); + exit(1); + } + + pos = 0; + while (!rec_get(fname, &hdr, sizeof(HDR), pos)) + { + showHDR(&hdr); + pos++; + } + + printf("> ------------------------------------------------------------------------------------------ \n"); +} diff --git a/util/showUSR.c b/util/showUSR.c new file mode 100644 index 0000000..915bc8e --- /dev/null +++ b/util/showUSR.c @@ -0,0 +1,57 @@ +/*-------------------------------------------------------*/ +/* util/showUSR.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : ¨q¥X FN_SCHEMA */ +/* create : / / */ +/* update : 02/11/03 */ +/*-------------------------------------------------------*/ +/* syntax : showUSR */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +int +main() +{ + int fd, n; + SCHEMA *usr; + struct stat st; + + chdir(BBSHOME); + + if ((fd = open(FN_SCHEMA, O_RDONLY)) < 0) + { + printf("ERROR at open file\n"); + exit(1); + } + + fstat(fd, &st); + usr = (SCHEMA *) malloc(st.st_size); + read(fd, usr, st.st_size); + close(fd); + + printf("\n%s ==> %d bytes\n", FN_SCHEMA, st.st_size); + + fd = st.st_size / sizeof(SCHEMA); + for (n = 0; n < fd; n++) + { + /* userno: ¦b .USR ¤¤¬O²Ä´XÓ slot */ + /* uptime: µù¥Uªº®É¶¡ (Y ID ¬OªÅ¥Õ«h¬O³Q reaper ±¼ªº®É¶¡) */ + /* userid: ID (Y¬OªÅ¥Õªí¥Ü¦¹¤H³Q reaper ¤F) */ + + printf("userno:%d uptime:%s userid:%-12.12s\n", + n + 1, Btime(&usr[n].uptime), usr[n].userid); + + if (n % 23 == 22) /* ¨C 23 µ§«ö¥ô·NÁäÄ~Äò */ + { + printf("-== Press ENTER to continue and 'q + ENTER' to quit ==-\n"); + if (getchar() == 'q') + break; + } + } + + free(usr); + return 0; +} diff --git a/util/showperm.c b/util/showperm.c new file mode 100644 index 0000000..cca85e1 --- /dev/null +++ b/util/showperm.c @@ -0,0 +1,53 @@ +/*-------------------------------------------------------*/ +/* util/showperm.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : Åã¥Ü¾Ö¦³¬YºØÅvªº¨Ï¥ÎªÌ */ +/* author : chensc.bbs@sony.tfcis.org */ +/* create : 06/09/03 */ +/* update : */ +/*-------------------------------------------------------*/ + +#include "bbs.h" + +int +main() +{ + int i,fd; + SCHEMA *usr; + struct stat st; + + chdir(BBSHOME); + + if ((fd = open(FN_SCHEMA, O_RDONLY)) < 0) + { + printf("ERROR at open file\n"); + exit(1); + } + + fstat(fd, &st); + usr = (SCHEMA *) malloc(st.st_size); + read(fd, usr, st.st_size); + close(fd); + + fd = st.st_size / sizeof(SCHEMA); + + for (i = 0; i < fd; i++) + { + ACCT cuser; + char fpath[64]; + + usr_fpath(fpath, usr[i].userid, FN_ACCT); + if (rec_get(fpath, &cuser, sizeof(cuser), 0) < 0) + { + // printf("%s: read error (maybe no such id?)\n", usr[i].userid); + continue; + } + + if(HAS_PERM(PERM_CHANGEID)) + printf("%s\n",usr[i].userid); + + if (rec_put(fpath, &cuser, sizeof(cuser), 0, NULL) < 0) + printf("%s: write error\n", usr[i].userid); + + } +} diff --git a/util/topgem.c b/util/topgem.c new file mode 100644 index 0000000..3e047d7 --- /dev/null +++ b/util/topgem.c @@ -0,0 +1,161 @@ +/*-------------------------------------------------------*/ +/* util/gem-expire.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : pºâ¥¼½sºëµØ°Ï & ¥¼½s¤Ñ¼ÆºëµØ°Ï±Æ¦æº] */ +/* create : 99/11/26 */ +/* update : 01/08/27 */ +/* author : Jimmy.bbs@whshs.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : gem-expire */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#define OUTFILE_GEMEMPTY "gem/@/@-gem_empty" +#define OUTFILE_GEMOVERDUE "gem/@/@-gem_overdue" + + +/*-------------------------------------------------------*/ +/* BRD shm ³¡¤À¶·»P cache.c ¬Û®e */ +/*-------------------------------------------------------*/ + + +static BCACHE *bshm; + + +static void +init_bshm() +{ + /* itoc.030727: ¦b¶}±Ò bbsd ¤§«e¡AÀ³¸Ó´Nn°õ¦æ¹L account¡A + ©Ò¥H bshm À³¸Ó¤w³]©w¦n */ + + bshm = shm_new(BRDSHM_KEY, sizeof(BCACHE)); + + if (bshm->uptime <= 0) /* bshm ¥¼³]©w§¹¦¨ */ + exit(0); +} + + +/*-------------------------------------------------------*/ +/* ¥Dµ{¦¡ */ +/*-------------------------------------------------------*/ + + +typedef struct +{ + int day; /* ´X¤Ñ¨S¾ã²zºëµØ°Ï */ + char brdname[BNLEN + 1]; /* ªO¦W */ + char BM[BMLEN + 1]; /* ªO¥D */ +} BRDDATA; + + +static int +int_cmp(a, b) + BRDDATA *a, *b; +{ + return (b->day - a->day); /* ¥Ñ¤j±Æ¨ì¤p */ +} + + +static BRDDATA board[MAXBOARD]; +static int locus = 0; /* Á`¦@°O¿ý¤F´XÓªO */ + + +static void +topgem() +{ + time_t now; + struct stat st; + BRD *bhdr, *tail; + char fpath[64], *brdname; + + time(&now); + + bhdr = bshm->bcache; + tail = bhdr + bshm->number; + do + { + /* ¸õ¹L¤£¦C¤J±Æ¦æº]ªº¬ÝªO */ + if ((bhdr->readlevel | bhdr->postlevel) >= (PERM_VALID << 1)) /* (BASIC + ... + VALID) < (VALID << 1) */ + continue; + + brdname = bhdr->brdname; + sprintf(fpath, "gem/brd/%s/@/@log", brdname); + + if (stat(fpath, &st) != -1) /* ¦³ºëµØ°ÏªÌÀˬd´X¤Ñ¥¼½s */ + board[locus].day = (now - st.st_mtime) / 86400; + else /* µLºëµØ°ÏªÌ */ + board[locus].day = 999; + strcpy(board[locus].brdname, brdname); + strcpy(board[locus].BM, bhdr->BM); + + locus++; + } while (++bhdr < tail); + + qsort(board, locus, sizeof(BRDDATA), int_cmp); +} + + +static void +write_data() +{ + time_t now; + struct tm *ptime; + FILE *fpe, *fpo; + int i, m, n; + + time(&now); + ptime = localtime(&now); + + fpe = fopen(OUTFILE_GEMEMPTY, "w"); + fpo = fopen(OUTFILE_GEMOVERDUE, "w"); + + fprintf(fpe, + " \033[1;34m-----\033[37m=====\033[41m ¬ÝªOºëµØ°Ï¥¼½s¤§¬ÝªO (¦Ü %d ¤ë %d ¤é¤î) \033[;1;37m=====\033[34m-----\033[m\n" + " \033[1;42m ¦W¦¸ \033[44m ¬ÝªO¦WºÙ \033[42m ºëµØ°Ï¥¼½s \033[44m ªO ¥D \033[m\n", + ptime->tm_mon + 1, ptime->tm_mday); + + fprintf(fpo, + " \033[1;34m-----\033[37m=====\033[41m ¬ÝªOºëµØ°Ï¥¼½s¤Ñ¼Æ¤§¬ÝªO (¦Ü %d ¤ë %d ¤é¤î) \033[;1;37m=====\033[34m-----\033[m\n" + " \033[1;42m ¦W¦¸ \033[44m ¬ÝªO¦WºÙ \033[42m ºëµØ°Ï¥¼½s¤Ñ¼Æ \033[44m ªO ¥D \033[m\n", + ptime->tm_mon + 1, ptime->tm_mday); + + m = 1; + n = 1; + + for (i = 0; i < locus; i++) + { + if (board[i].day == 999) + { + fprintf(fpe, " %3d %12s %s %.20s\n", + m, board[i].brdname, "©|¥¼½s¿èºëµØ°Ï", board[i].BM); + m++; + } + else + { + fprintf(fpo, " %s%3d %12s %4d %.20s\033[m\n", + n <= 3 ? "\033[1m" : (n <= 10 ? "\033[1;31m" : "\033[m"), + n, board[i].brdname, board[i].day, board[i].BM); + n++; + } + } + + fclose(fpe); + fclose(fpo); +} + + +int +main() +{ + chdir(BBSHOME); + + init_bshm(); + + topgem(); + write_data(); + + return 0; +} diff --git a/util/topsong.c b/util/topsong.c new file mode 100644 index 0000000..948f325 --- /dev/null +++ b/util/topsong.c @@ -0,0 +1,91 @@ +/*-------------------------------------------------------*/ +/* util/topsong.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ºq¥»¨Ï¥Î±Æ¦W */ +/* create : 01/09/28 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : topsong */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#ifdef LOG_SONG_USIES + + +#define OUTFILE_TOPSONG "gem/@/@-topsong" + + +static void +write_data(songs, num) + SONGDATA *songs; + int num; +{ + int n; + FILE *fp; + + if (!(fp = fopen(OUTFILE_TOPSONG, "w"))) + return; + + fprintf(fp, " \033[36m¢w¢w\033[37m¦W¦¸\033[36m¢w¢w¢w¢w¢w¢w\033[37mºq ¦W" + "\033[36m¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\033[37m¦¸¼Æ\033[36m¢w¢w\033[m\n"); + + for (n = 0; n < 50 && n < num; n++) /* ¥u¨ú«e 50 ¦W */ + { + fprintf(fp, " %5d. %-38.38s %4d ¦¸\033[m\n", + n + 1, songs[n].title, songs[n].count); + } + + fclose(fp); +} + + +static int +count_cmp(b, a) + SONGDATA *a, *b; +{ + return (a->count - b->count); +} + + +int +main() +{ + int fd, size; + struct stat st; + SONGDATA *songs; + + chdir(BBSHOME); + + if ((fd = open(FN_RUN_SONGUSIES, O_RDWR)) < 0) + return 0; + + if (!fstat(fd, &st) && (size = st.st_size) >= sizeof(SONGDATA)) + { + songs = (SONGDATA *) malloc(size); + size = read(fd, songs, size); + + qsort(songs, size / sizeof(SONGDATA), sizeof(SONGDATA), count_cmp); + + lseek(fd, 0, SEEK_SET); + write(fd, songs, size); + ftruncate(fd, size); + + write_data(songs, size / sizeof(SONGDATA)); + free(songs); + } + + close(fd); + return 0; +} + +#else +int +main() +{ + printf("You shoule define LOG_SONG_USIES first.\n"); + return 0; +} +#endif /* LOG_SONG_USIES */ diff --git a/util/topusr.c b/util/topusr.c new file mode 100644 index 0000000..f126be0 --- /dev/null +++ b/util/topusr.c @@ -0,0 +1,751 @@ +/*-------------------------------------------------------*/ +/* util/topusr.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : ¨Ï¥ÎªÌ¸ê®Æ²Îp¤Î±Æ¦W */ +/* create : 99/03/29 */ +/* update : 01/10/01 */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +/* itoc.µù¸Ñ: ±N ¤W¯¸¦¸¼Æ/Äé¤ô¦¸¼Æ/»È¹ô/ª÷¹ô/¦~ÄÖ/¬P®y/©Ê§O/¹Ø¬P ¤@¨Ö²Îp¡A§K±o±`±`¦b¶} .ACCT */ + +#include "bbs.h" + + +#define OUTFILE_TOPLOGIN BBSHOME"/gem/@/@-toplogin" +#define OUTFILE_TOPPOST BBSHOME"/gem/@/@-toppost" +#define OUTFILE_TOPMONEY BBSHOME"/gem/@/@-topmoney" +#define OUTFILE_TOPGOLD BBSHOME"/gem/@/@-topgold" +#define OUTFILE_AGE BBSHOME"/gem/@/@-age" +#define OUTFILE_STAR BBSHOME"/gem/@/@-star" +#define OUTFILE_SEX BBSHOME"/gem/@/@-sex" +#define OUTFILE_BIRTHDAY BBSHOME"/gem/@/@-birthday" +#define TMPFILE_BIRTHMON BBSHOME"/tmp/birthmon" + + +/*-------------------------------------------------------*/ +/* author : mat.bbs@fall.twbbs.org */ +/* modify : gslin@abpe.org */ +/* target : ¤W¯¸¦¸¼Æ¡BÄé¤ô¦¸¼Æ¡Bª÷»È¹ô±Æ¦æº] */ +/*-------------------------------------------------------*/ + + +#define TOPNUM 36 +#define TOPNUM_HALF (TOPNUM / 2) + + +typedef struct +{ + char userid[IDLEN + 1]; + char username[UNLEN + 1]; + int num; /* ¼ÆÈ */ + int rank; /* ¦W¦¸ */ +} DATA; + +static DATA toplogins[TOPNUM], topposts[TOPNUM], topmoney[TOPNUM], topgold[TOPNUM]; + + +static int +sort_compare(p1, p2) + const void *p1; + const void *p2; +{ + int k; + DATA *a1, *a2; + + a1 = (DATA *) p1; + a2 = (DATA *) p2; + + k = a2->num - a1->num; + return k ? k : str_cmp(a1->userid, a2->userid); +} + + +static DATA * +findmin(src) + DATA *src; +{ + int i; + DATA *p; + + p = src; + for (i = 0; i < TOPNUM; i++) + { + if (src[i].num < p->num) + p = src + i; + } + return p; +} + + +static void +sort_rank(data) /* µ¹©w¦W¦¸ */ + DATA *data; /* ¤w¨Ì data->num ±Æ§Ç */ +{ + int i, rank; + + data[0].rank = rank = 1; + for (i = 1; i < TOPNUM; i++) + { + if (data[i].num != data[i - 1].num) + rank = i + 1; + data[i].rank = rank; + } +} + + +static void +merge_id_nick(dst, userid, nick) + char *dst; + char *userid; + char *nick; +{ + if (*userid) + { + sprintf(dst, "%s (%s)", userid, nick); + + if (strlen(dst) > 25) + dst[25] = '\0'; + } + else + dst[0] = '\0'; +} + + +static void +write_data(fpath, title, data) + char *fpath; + char *title; + DATA *data; +{ + FILE *fp; + char buf[256]; + int i, num1, num2; + + sort_rank(data); + + if (!(fp = fopen(fpath, "w"))) + return; + + i = 12 - (strlen(title) >> 1); + sprintf(buf, " \033[1;33m¡³ ¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¡÷ \033[41m%%%ds%%s%%%ds\033[40m ¡ö¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w ¡³\033[m\n\n", i, i); + fprintf(fp, buf, "", title, ""); + + fprintf(fp, + "\033[1;37m¦W¦¸ \033[33m¥N¸¹(¼ÊºÙ) \033[36m¼Æ¶q\033[m " + "\033[1;37m¦W¦¸ \033[33m¥N¸¹(¼ÊºÙ) \033[36m¼Æ¶q\033[m\n" + "\033[1;32m%s\033[m\n", MSG_SEPERATOR); + + for (i = 0; i < TOPNUM_HALF; i++) + { + char buf1[80], buf2[80]; + + merge_id_nick(buf1, data[i].userid, data[i].username); + merge_id_nick(buf2, data[i + TOPNUM_HALF].userid, + data[i + TOPNUM_HALF].username); + + /* itoc.010408: ¸Ñ¨M¿ú¤Ó¦h¡Aµe±Ãz±¼ªº°ÝÃD */ + num1 = data[i].num / 1000000; + num2 = data[i + TOPNUM_HALF].num / 1000000; + if (num2) /* ¨º»ò data[i].num ¤]¥²©w > 10^6 */ + { + fprintf(fp, "[%2d] %-25s %5dM [%2d] %-25s %5dM\n", + data[i].rank, buf1, num1, + data[i + TOPNUM_HALF].rank, buf2, num2); + } + else if (num1) + { + fprintf(fp, "[%2d] %-25s %5dM [%2d] %-25s %6d\n", + data[i].rank, buf1, num1, + data[i + TOPNUM_HALF].rank, buf2, data[i + TOPNUM_HALF].num); + } + else + { + fprintf(fp, "[%2d] %-25s %6d [%2d] %-25s %6d\n", + data[i].rank, buf1, data[i].num, + data[i + TOPNUM_HALF].rank, buf2, data[i + TOPNUM_HALF].num); + } + } + + fprintf(fp, "\n"); + fclose(fp); +} + + +static inline void +topusr(acct) + ACCT *acct; +{ + DATA *p; + + if ((p = findmin(&toplogins))->num < acct->numlogins) + { + str_ncpy(p->userid, acct->userid, sizeof(p->userid)); + str_ncpy(p->username, acct->username, sizeof(p->username)); + p->num = acct->numlogins; + } + + if ((p = findmin(&topposts))->num < acct->numposts) + { + str_ncpy(p->userid, acct->userid, sizeof(p->userid)); + str_ncpy(p->username, acct->username, sizeof(p->username)); + p->num = acct->numposts; + } + + if ((p = findmin(&topmoney))->num < acct->money) + { + str_ncpy(p->userid, acct->userid, sizeof(p->userid)); + str_ncpy(p->username, acct->username, sizeof(p->username)); + p->num = acct->money; + } + + if ((p = findmin(&topgold))->num < acct->gold) + { + str_ncpy(p->userid, acct->userid, sizeof(p->userid)); + str_ncpy(p->username, acct->username, sizeof(p->username)); + p->num = acct->gold; + } +} + + +/*-------------------------------------------------------*/ +/* author : wsyfish.bbs@fpg.m4.ntu.edu.tw */ +/* target : ¯¸¤W¦~ÄÖ²Îp */ +/*-------------------------------------------------------*/ + + +#define MAX_LINE 16 + +static int act_age[25]; /* 24ºØ¦~ÄÖ¡BÁ`¦X */ + + +static inline void +count_age(acct, year) + ACCT *acct; + int year; +{ + int age; + + age = year - 11 - acct->year; /* acct->year ¬O¥Á°ê¦~¥÷ */ + + /* ¥u²Îp 10~33 ·³ */ + if (age >= 10 && age <= 10 + 24 - 1) + { + act_age[age - 10]++; + act_age[24]++; + } +} + + +static void +fouts(fp, buf, mode) + FILE *fp; + char buf[], mode; +{ + static char state = '0'; + + if (state != mode) + fprintf(fp, "\033[3%cm", state = mode); + if (buf[0]) + { + fprintf(fp, buf); + buf[0] = 0; + } +} + + +static inline void +write_age(fpath, year, month, day) + char *fpath; + int year, month, day; +{ + char buf[256]; + FILE *fp; + int i, j; + int age, max, item, maxage, totalage; + + if ((fp = fopen(fpath, "w")) == NULL) + { + printf("cann't open %s\n", fpath); + return; + } + + max = maxage = totalage = 0; + for (i = 0; i < 24; i++) + { + totalage += act_age[i] * (i + 10); + if (act_age[i] > max) + { + max = act_age[i]; + maxage = i; + } + } + + item = max / MAX_LINE + 1; + + fprintf(fp, "\t\t\t \033[1;33;45m " BBSNAME " ¦~ÄÖ²Îp [%02d/%02d/%02d] \033[m\n\n", + year % 100, month, day); + + for (i = MAX_LINE + 1; i > 0; i--) + { + strcpy(buf, " "); + for (j = 0; j < 24; j++) + { + max = item * i; + age = act_age[j]; + if (age && (max > age) && (max - item <= age)) + { + fouts(fp, buf, '7'); + fprintf(fp, "%-3d", age); + } + else if (max <= age) + { + fouts(fp, buf, '4'); + fprintf(fp, "¢i "); + } + else + strcat(buf, " "); + } + fprintf(fp, "\n"); + } + + fprintf(fp, " \033[1;35mùæùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùè \n" + " \033[1;32m10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33\n" + "\t\t \033[36m¦³®Ä²Îp¤H¦¸¡G\033[37m%-9d\033[36m¥§¡¦~ÄÖ¡G\033[37m%d\033[40;0m\n", + act_age[24], (int) totalage / (act_age[24] ? act_age[24] : 1)); + + fclose(fp); +} + + +/*-------------------------------------------------------*/ +/* author : wsyfish.bbs@fpg.m4.ntu.edu.tw */ +/* target : ¯¸¤W¬P®y²Îp */ +/*-------------------------------------------------------*/ + + +static int act_star[13]; /* ¤Q¤G¬P®y¡B¨ä¥L */ + + +static inline void +count_star(acct) + ACCT *acct; +{ + switch (acct->month) + { + case 1: + if (acct->day <= 19) + act_star[9]++; + else + act_star[10]++; + break; + case 2: + if (acct->day <= 18) + act_star[10]++; + else + act_star[11]++; + break; + case 3: + if (acct->day <= 20) + act_star[11]++; + else + act_star[0]++; + break; + case 4: + if (acct->day <= 19) + act_star[0]++; + else + act_star[1]++; + break; + case 5: + if (acct->day <= 20) + act_star[1]++; + else + act_star[2]++; + break; + case 6: + if (acct->day <= 21) + act_star[2]++; + else + act_star[3]++; + break; + case 7: + if (acct->day <= 22) + act_star[3]++; + else + act_star[4]++; + break; + case 8: + if (acct->day <= 22) + act_star[4]++; + else + act_star[5]++; + break; + case 9: + if (acct->day <= 22) + act_star[5]++; + else + act_star[6]++; + break; + case 10: + if (acct->day <= 23) + act_star[6]++; + else + act_star[7]++; + break; + case 11: + if (acct->day <= 22) + act_star[7]++; + else + act_star[8]++; + break; + case 12: + if (acct->day <= 21) + act_star[8]++; + else + act_star[9]++; + break; + default: + act_star[12]++; + } +} + + +static inline void +write_star(fpath, year, month, day) + char *fpath; + int year, month, day; +{ + FILE *fp; + int i, j; + int max, item, maxstar; + + char name[13][7] = + { + "¨d¦Ï®y", + "ª÷¤û®y", + "Âù¤l®y", + "¥¨ÃÉ®y", + "·à¤l®y", + "³B¤k®y", + "¤Ñ¯¯®y", + "¤ÑÃÈ®y", + "®g¤â®y", + "¼¯½~®y", + "¤ô²~®y", + "Âù³½®y", + "¤£¥i¦Ò" + }; + + char blk[10][3] = + { + " ", "¢j", "¢k", "¢l", "¢m", + "¢n", "¢o", "¢p", "¢i", "¢i", + }; + + + if ((fp = fopen(fpath, "w")) == NULL) + { + printf("cann't open %s\n", fpath); + return; + } + + max = maxstar = 0; + + for (i = 0; i < 13; i++) + { + if (act_star[i] > max) + { + max = act_star[i]; + maxstar = i; + } + } + + item = max / 30 + 1; + + fprintf(fp, "\t\t\t \033[1;33;45m " BBSNAME " ¬P®y²Îp [%02d/%02d/%02d] \033[m\n\n", + year % 100, month, day); + + for (i = 0; i < 13; i++) + { + fprintf(fp, " \033[1;37m%s ", name[i]); + fprintf(fp, "%s", i%2 ==1 ? "\033[0;36m" : "\033[0;34m"); + for (j = 0; j < act_star[i] / item; j++) + { + fprintf(fp, "%2s", blk[9]); + } + fprintf(fp, "%2s \033[1;37m%d\033[m\n", blk[(act_star[i] % item) * 10 / item], + act_star[i]); + } + + fclose(fp); +} + + +/*-------------------------------------------------------*/ +/* author : BioStar.bbs@micro.bio.ncue.edu.tw */ +/* target : ¯¸¤W©Ê§O²Îp */ +/*-------------------------------------------------------*/ + + +static int act_sex[3]; /* ¤¤©Ê¡B¨k©Ê¡B¤k©Ê */ + + +static inline void +count_sex(acct) + ACCT *acct; +{ + switch (acct->sex) + { + case 1: + case 2: + act_sex[acct->sex]++; + break; + default: + act_sex[0]++; + } +} + + +static inline void +write_sex(fpath, year, month, day) + char *fpath; + int year, month, day; +{ + FILE *fp; + int i, j; + int max, item, maxsex; + + char name[3][7] = + { + " ¤¤©Ê", + " ¨k©Ê", + " ¤k©Ê" + }; + + char blk[10][3] = + { + " ", "¢j", "¢k", "¢l", "¢m", + "¢n", "¢o", "¢p", "¢i", "¢i", + }; + + + if ((fp = fopen(fpath, "w")) == NULL) + { + printf("cann't open %s\n", fpath); + return; + } + + max = maxsex = 0; + + for (i = 0; i < 3; i++) + { + if (act_sex[i] > max) + { + max = act_sex[i]; + maxsex = i; + } + } + + item = max / 30 + 1; + + fprintf(fp, "\t\t\t \033[1;33;45m " BBSNAME " ©Ê§O²Îp [%02d/%02d/%02d] \033[m\n\n", + year % 100, month, day); + + for (i = 0; i < 3; i++) + { + fprintf(fp, " \033[1;37m%s ", name[i]); + fprintf(fp, "%s", i%2 ==1 ? "\033[0;36m" : "\033[0;34m"); + for (j = 0; j < act_sex[i] / item; j++) + { + fprintf(fp, "%2s", blk[9]); + } + fprintf(fp, "%2s \033[1;37m%d\033[m\n", blk[(act_sex[i] % item) * 10 / item], + act_sex[i]); + } + + fclose(fp); +} + +/*-------------------------------------------------------*/ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/* target : ¯¸¤W¹Ø¬P²Îp */ +/*-------------------------------------------------------*/ + + +static inline void +write_birthday(fpath, year, month, day) + char *fpath; + int year, month, day; +{ + FILE *fp; + + if (!(fp = fopen(fpath, "w"))) + return; + + fprintf(fp, "\t\t\t \033[1;33;45m " BBSNAME " ¥»¤é¹Ø¬P [%02d/%02d/%02d] \033[m\n\n", + year % 100, month, day); + + fclose(fp); +} + + +static inline void +write_birthmon(fpath, year, month, day) + char *fpath; + int year, month, day; +{ + FILE *fp; + + /* §â¥»¤ë¹Ø¬P±µ¦b OUTFILE_BIRTHDAY «á± */ + + if (!(fp = fopen(fpath, "a"))) + return; + + fprintf(fp, "\n\n\t\t\t \033[1;33;45m " BBSNAME " ¥»¤ë¹Ø¬P [%02d/%02d/%02d] \033[m\n\n", + year % 100, month, day); + + f_suck(fp, TMPFILE_BIRTHMON); + unlink(TMPFILE_BIRTHMON); + + fclose(fp); +} + + +static inline void +check_birth(fpath, acct, year, month, day) + char *fpath; + ACCT *acct; + int year, month, day; /* ¤µ¤Ñ¬O´X¦~´X¤ë´X¤é */ +{ + static int birthday_num = 0; /* ¦³´XÓ¤H¤µ¤Ñ¥Í¤é */ + static int birthmon_num = 0; /* ¦³´XÓ¤H¥»¤ë¥Í¤é */ + + if (acct->month == month) + { + FILE *fp; + char buf[50]; + + if (acct->day == day) /* ¥»¤é¹Ø¬P */ + { + if (!(fp = fopen(fpath, "a"))) + return; + + birthday_num++; + merge_id_nick(buf, acct->userid, acct->username); + + fprintf(fp, "[%3d] %-25s ¤W¯¸¦¸¼Æ: %-5d ¤å³¹½g¼Æ: %-5d %2d ·³¥Í¤é\n", + birthday_num, buf, acct->numlogins, acct->numposts, year - 11 - acct->year); + + fclose(fp); + } + else /* ¥»¤ë¹Ø¬P */ + { + if (!(fp = fopen(TMPFILE_BIRTHMON, "a"))) + return; + + birthmon_num++; + merge_id_nick(buf, acct->userid, acct->username); + + fprintf(fp, "[%3d] %-25s ¤W¯¸¦¸¼Æ: %-5d ¤å³¹½g¼Æ: %-5d ¥Í: %02d/%02d\n", + birthmon_num, buf, acct->numlogins, acct->numposts, month, acct->day); + + fclose(fp); + } + } +} + + +/*-------------------------------------------------------*/ +/* ¥Dµ{¦¡ */ +/*-------------------------------------------------------*/ + + +int +main() +{ + char c; + int year, month, day; + time_t now; + struct tm *ptime; + + memset(&toplogins, 0, sizeof(toplogins)); + memset(&topposts, 0, sizeof(topposts)); + memset(&topmoney, 0, sizeof(topmoney)); + memset(&topgold, 0, sizeof(topgold)); + + memset(act_age, 0, sizeof(act_age)); + memset(act_star, 0, sizeof(act_star)); + memset(act_sex, 0, sizeof(act_sex)); + + now = time(NULL); + ptime = localtime(&now); + + year = ptime->tm_year; + month = ptime->tm_mon + 1; + day = ptime->tm_mday; + + write_birthday(OUTFILE_BIRTHDAY, year, month, day); + + for (c = 'a'; c <= 'z'; c++) + { + char buf[64]; + struct dirent *de; + DIR *dirp; + + sprintf(buf, BBSHOME "/usr/%c", c); + chdir(buf); + + if (!(dirp = opendir("."))) + continue; + + while (de = readdir(dirp)) + { + ACCT acct; + int fd; + char *fname; + + fname = de->d_name; + if (*fname <= ' ' || *fname == '.') + continue; + + sprintf(buf, "%s/.ACCT", fname); + if ((fd = open(buf, O_RDONLY)) < 0) + continue; + + read(fd, &acct, sizeof(ACCT)); + close(fd); + + topusr(&acct); + count_age(&acct, year); + count_star(&acct); + count_sex(&acct); + check_birth(OUTFILE_BIRTHDAY, &acct, year, month, day); + } + + closedir(dirp); + } + + write_birthmon(OUTFILE_BIRTHDAY, year, month, day); + + qsort(toplogins, TOPNUM, sizeof(DATA), sort_compare); + write_data(OUTFILE_TOPLOGIN, "¤W¯¸¦¸¼Æ±Æ¦æº]", &toplogins); + + qsort(topposts, TOPNUM, sizeof(DATA), sort_compare); + write_data(OUTFILE_TOPPOST, "Äé¤ô½g¼Æ^¶¯º]", &topposts); + + qsort(topmoney, TOPNUM, sizeof(DATA), sort_compare); + write_data(OUTFILE_TOPMONEY, "»È¹ô´I¯Î«Ê¯«º]", &topmoney); + + qsort(topgold, TOPNUM, sizeof(DATA), sort_compare); + write_data(OUTFILE_TOPGOLD, "ª÷¹ô´I»¨§ì¨gº]", &topgold); + + write_age(OUTFILE_AGE, year, month, day); + + write_star(OUTFILE_STAR, year, month, day); + + write_sex(OUTFILE_SEX, year, month, day); + + return 0; +} diff --git a/util/tran/Makefile b/util/tran/Makefile new file mode 100644 index 0000000..bd62ab8 --- /dev/null +++ b/util/tran/Makefile @@ -0,0 +1,66 @@ +# ------------------------------------------------------- # +# util/tran/Makefile ( NTHU CS MapleBBS Ver 3.10 ) # +# ------------------------------------------------------- # +# target : Makefile for ±H«H¡B²Îp¡B³Æ¥÷¡B¨t²ÎºûÅ@¤u¨ã # +# create : 01/03/02 # +# update : / / # +# ------------------------------------------------------- # + + +# ------------------------------------------------------ # +# ¤U¦Cªº make rules ¤£»Ý×§ï # +# ------------------------------------------------------ # + + +EXE = brd2gem transacct transbrd \ + ats2bmw ats2brd ats2gem ats2mf ats2pal ats2usr \ + cola2brd cola2gem cola2post cola2usr \ + fb2brd fb2gem fb2pal fb2usr \ + mag2brd mag2gem mag2usr \ + snap2usr snap2brd \ + sob2brd sob2gem sob2pal sob2usr \ + wd2bmw wd2brd wd2gem wd2list wd2mf wd2pal wd2pip wd2usr \ + windtop2brd windtop2pip windtop2usr + +all: + @echo "Please enter 'make sys-type', " + @echo " make sun : for Sun-OS 4.x and maybe some BSD systems, cc or gcc" + @echo " make linux : for Linux" + @echo " make solaris : for Sun-OS 5.x gcc" + @echo " make sol-x86 : for Solaris 7 x86" + @echo " make freebsd : for BSD 4.4 systems" + @echo " make bsd : for BSD systems, cc or gcc, if not in the above lists" + @echo " make cygwin : for Microsoft Windows and Cygwin gcc" + +sun: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -fomit-frame-pointer -Wunused -I../../include" LDFLAGS="-s -L../../lib -ldao" $(EXE) + +linux: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao" $(EXE) + +solaris: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao -lsocket -lnsl -L/usr/ucblib -lucb" $(EXE) + +sol-x86: + @$(MAKE) CC=gcc CFLAGS="-O2 -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao -lsocket -lnsl" $(EXE) + +freebsd: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao" $(EXE) + +bsd: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao" $(EXE) + +cygwin: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao" $(EXE) + + +.c: ; $(CC) -o $@ $@.c $(CFLAGS) $(LDFLAGS) + + +install: $(EXE) +# ¤£½Æ»s¨ì bin/ ¤U +# install -m 0700 $? $(HOME)/bin + @echo "ok!" + +clean: + rm -f $(EXE) *.exe *.o *~ diff --git a/util/tran/ats.h b/util/tran/ats.h new file mode 100644 index 0000000..89a98b6 --- /dev/null +++ b/util/tran/ats.h @@ -0,0 +1,274 @@ +/*-------------------------------------------------------*/ +/* util/tran/ats.h */ +/*-------------------------------------------------------*/ +/* target : ATS ¦Ü Maple 3.02 Âà´« */ +/* create : 02/10/26 */ +/* author : ernie@micro8.ee.nthu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ³]©w OLD_BBSHOME¡BFN_PASSWD¡BFN_BOARD + 2. ×§ï©Ò¦³ªº old struct + + 3. ¥²¶·¦b brd Âà§¹¤~¥i¥HÂà´« gem + 4. ¥²¶·¦b usr ¤Î brd ³£Âà§¹¤~¥i¥HÂà´« mf + 5. ¥²¶·¦b usr ¤Î brd ³£Âà§¹¤~¥i¥HÂà´« pal + 6. ¥²¶·¦b usr Âà§¹¤~¥i¥HÂà´« bmw + 7. «ØÄ³Âà´«¶¶§Ç¬° usr -> brd -> gem -> mf -> pal -> bmw + +#endif + + +#include "bbs.h" + +/* --------------------- ½Ðª`·N ³o¤ªÌ¥u¯à¾Ü¤@©w¸q ---------------------- */ +#define NEW_STATION /* ©w¸q¬° ·s«Ø/¼Ð·Ç ¯¸¥x */ +#undef OLD_ATSVERSION /* ©w¸q¬°Âªº¨È¯¸ª©¥» (1.20a ¥H«á) */ + /* ±ýÅýª©¥»¨Ï¥Î³Ì¤p¨Ï¥ÎªÌ¸ê®Æµ²ºc */ + /* ¥²»Ý°õ¦æÂà´«µ{¦¡ single_multi_st */ +#undef TRANS_FROM_SOB /* ©w¸q¬°¨FÅyÂà´« */ +#undef TRANS_FROM_FB3 /* ©w¸q¬°¤õ³¾Âà´« */ +#undef TRANS_FROM_COLA /* ©w¸q¬°¥i¼ÖÂà´« */ +/* ---------------------------------------------------------------------- */ + +#ifdef TRANS_FROM_FB3 + #undef ENCPASSLEN /* ©w¸qY¤õ³¾Âà´« ¦³µL³]©w ENCPASSLEN */ +#endif +#ifndef OLD_ATSVERSION +#undef MIN_USEREC_STRUCT /* ©w¸q¨Ï¥Î³Ì¤p¨Ï¥ÎªÌ¸ê®Æµ²ºc ¦¹¥\¯à */ +#endif /* ¤£«ØÄ³¨Ï¥Î ·|¥¢¥h³\¦h¥\¯à °£«D¯¸ */ + /* ¥x¦³ÄY«µwÅé¨î ¥B¤£·Q¶]¤Ó¦h¥\¯à */ + + +#define OLD_BBSHOME "/home/bbs/bbsrs" /* SOB */ +#define FN_PASSWD "/home/bbs/bbsrs/.PASSWDS" /* SOB */ +#define FN_BOARD "/home/bbs/bbsrs/.BOARDS" /* SOB */ + + +#undef HAVE_PERSONAL_GEM /* SOB ¬O¨S¦³Ó¤HºëµØ°Ïªº */ + + +#define ASTRLEN 80 /* Length of most string data */ +#define ABTLEN 48 /* Length of board title */ +#define ATTLEN 72 /* Length of title */ +#define ANAMELEN 40 /* Length of username/realname */ +#define AFNLEN 33 /* Length of filename */ +#define AIDLEN 12 /* Length of bid/uid */ + + #define APASSLEN 14 /* Length of encrypted passwd field for ATS */ + +#define AREGLEN 38 /* Length of registration data */ + +/* ----------------------------------------------------- */ +/* .PASSWDS struct : 1024 bytes */ +/* ----------------------------------------------------- */ + +struct userec { + char userid[AIDLEN + 1]; + char realname[20]; + char username[24]; + char passwd[APASSLEN]; + uschar uflag; + usint userlevel; + unsigned long int numlogins; + unsigned long int numposts; + time_t firstlogin; + time_t lastlogin; + char lasthost[80]; + char remoteuser[8]; + char email[50]; + char address[50]; + char justify[AREGLEN + 1]; + uschar month; + uschar day; + uschar year; + uschar sex; + uschar state; + + int havemoney; + +#ifndef MIN_USEREC_STRUCT + int havetoolsnumber; + int havetools[20]; + int addexp; + usint nowlevel; + char working[20]; + + uschar hp; + uschar str; + uschar mgc; + uschar skl; + uschar spd; + uschar luk; + uschar def; + uschar mdf; + + uschar spcskl[6]; + uschar wepnlv[2][10]; + uschar curwepnlv[2][1]; + uschar curwepnatt; + uschar curwepnhit; + uschar curwepnweg; + uschar curwepnspc[4]; + + char lover[AIDLEN+1]; + char commander; + char belong[21]; + char curwepclass[10]; + char class[7]; +#endif + +#ifndef NO_USE_MULTI_STATION + char station[AIDLEN+1]; +#endif + +#ifndef MIN_USEREC_STRUCT + char classsex; + char wephavespc[5]; + + char cmdrname[AIDLEN+1]; + char class_spc_skll[6]; +#endif + + usint welcomeflag; + +#ifndef MIN_USEREC_STRUCT + int win; + int lost; + int test_exp; +#endif + + char tty_name[20]; + char extra_mode[10]; + +#ifndef MIN_USEREC_STRUCT + char class_spc_test[32]; + char mov; + char toki_level; + + int will_value; + int effect_value; + int belive_value; + int leader_value; + + char action_value; +#endif + +#ifndef NO_USE_MULTI_STATION + char station_member[40]; +#endif + + uschar now_stno; + usint good_posts; + +#ifdef CHANGE_USER_MAIL_LIMIT + int max_mail_number; + int max_mail_kbytes; +#endif + +#ifdef TRANS_FROM_COLA + usint staytime; + #ifdef CHANGE_USER_MAIL_LIMIT + int backup_int[41]; + #else + int backup_int[43]; + #endif +#else + #ifdef CHANGE_USER_MAIL_LIMIT + int backup_int[42]; + #else + int backup_int[44]; + #endif +#endif + +#ifndef MIN_USEREC_STRUCT + int ara_money; +#endif + +#ifdef TRANS_FROM_COLA + char blood; + char normal_post; + char backup_char[118]; +#else + char normal_post; + char backup_char[119]; +#endif + +#ifndef MIN_USEREC_STRUCT + int turn; +#endif +}; +typedef struct userec userec; + +/* ----------------------------------------------------- */ +/* DIR of board struct */ +/* ----------------------------------------------------- */ + +#ifndef TRANS_FROM_FB3 /* struct size = 256 bytes */ + #ifndef TRANS_FROM_COLA +struct fileheader { + char filename[AFNLEN-1]; /* M.109876543210.A */ + char report; /* Dopin : ·s¨î´£³ø */ + char savemode; /* file save mode */ + char owner[AIDLEN + 2]; /* uid[.] */ + char date[6]; /* [02/02] or space(5) */ + char title[ATTLEN]; + uschar goodpost; /* ±ÀÂˤ峹 */ + uschar filemode; /* must be last field @ boards.c */ +}; + #else +struct fileheader { /* For Cola BBS */ + char filename[ASTRLEN]; + char owner[ASTRLEN]; + char title[ASTRLEN]; + char date[6]; /* ¸É¤W for ATS/SOB */ + char savemode; + uschar filemode; + char report; + uschar goodpost; + char backup_char[6]; /* ¨ì³o¸Ì */ +}; + #endif +#else +struct fileheader { /* This structure is used to hold data in */ + char filename[ASTRLEN-2]; /* the DIR files */ + char report; /* ¨È¯¸´£³ø */ + char savemode; /* file save mode */ + char owner[ASTRLEN-6]; + char date[6]; + char title[ASTRLEN]; + unsigned level; + unsigned char accessed[10]; + uschar goodpost; /* ±ÀÂˤ峹 */ + uschar filemode; /* must be last field @ boards.c */ +}; +#endif + +typedef struct fileheader fileheader; + + +/* ----------------------------------------------------- */ +/* BOARDS struct : Standard 656 bytes */ +/* ----------------------------------------------------- */ + +struct boardheader { + char brdname[(AIDLEN+1)*2]; /* bid */ + char title[ABTLEN + 1]; + char BM[AIDLEN * 3 + 3]; /* BMs' uid, token '/' */ + char pad[11]; + time_t bupdate; /* note update time */ + char pad2[3]; + uschar bvote; /* Vote flags */ + time_t vtime; /* Vote close time */ + usint level; + char document[128 * 3]; /* add extra document */ + char station[16]; + char sysop[16]; + char pastbrdname[16]; + char yankflags[16]; + char backup[64]; +}; +typedef struct boardheader boardheader; diff --git a/util/tran/ats2bmw.c b/util/tran/ats2bmw.c new file mode 100644 index 0000000..3cd1ee4 --- /dev/null +++ b/util/tran/ats2bmw.c @@ -0,0 +1,143 @@ +/*-------------------------------------------------------*/ +/* util/transbmw.c */ +/*-------------------------------------------------------*/ +/* target : WD ¦Ü Maple 3.02 ¤ô²y°O¿ýÂà´« */ +/* create : 02/01/22 */ +/* update : / / */ +/* author : itoc.bbs@bbs.ee.nctu.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transbmw */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ×§ï transbmw() + + ps. ¨Ï¥Î«e½Ð¥ý¦æ³Æ¥÷¡Ause on ur own risk. µ{¦¡©å¦H½Ð¥]²[ :p + ps. ·PÁ lkchu ªº Maple 3.02 for FreeBSD + +#endif + + +#include "ats.h" + + +/* ----------------------------------------------------- */ +/* 3.02 functions */ +/* ----------------------------------------------------- */ + + +static void +_mail_self(userid, fpath, owner, title) /* itoc.011115: ±HÀÉ®×µ¹¦Û¤v */ + char *userid; /* ¦¬¥óªÌ */ + char *fpath; /* Àɮ׸ô®| */ + char *owner; /* ±H¥ó¤H */ + char *title; /* ¶l¥ó¼ÐÃD */ +{ + HDR fhdr; + char folder[64]; + + usr_fpath(folder, userid, FN_DIR); + close(hdr_stamp(folder, HDR_LINK, &fhdr, fpath)); + str_ncpy(fhdr.owner, owner, sizeof(fhdr.owner)); + str_ncpy(fhdr.title, title, sizeof(fhdr.title)); + fhdr.xmode = 0; + rec_add(folder, &fhdr, sizeof(fhdr)); +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transbmw(userid) + char *userid; +{ + ACCT acct; + int fd; + char buf[64],buf2[64],buf3[64]; + + + printf("¶}©l³Æ¥÷ %-15s ¤ô²y°O¿ý¡®¦n¤Í¦W³æ¡®§Úªº³Ì·R\n",acct.userid); + /* sob ªº usr ¥Ø¿ý¦³¤À¤j¤p¼g¡A©Ò¥Hn¥ý¨ú±o¤j¤p¼g */ + usr_fpath(buf, userid, FN_ACCT); + if ((fd = open(buf, O_RDONLY)) >= 0) + { + read(fd, &acct, sizeof(ACCT)); + close(fd); + } + else + { + return; + } + + sprintf(buf, OLD_BBSHOME"/home/%s/writelog", acct.userid); /* ªº¤ô²y°O¿ý */ + + if (dashf(buf)) + _mail_self(acct.userid, buf, "[³Æ¥÷]", "¤ô²y°O¿ý"); + + sprintf(buf2, OLD_BBSHOME"/home/%s/overrides", acct.userid); /* ªº¦n¤Í¦W³æ */ + + if (dashf(buf2)) + _mail_self(acct.userid, buf2, "[³Æ¥÷]", "¦n¤Í¦W³æ"); + + sprintf(buf3, OLD_BBSHOME"/home/%s/favor_boards", acct.userid); /* ªº§Úªº³Ì·R */ + + if (dashf(buf3)) + _mail_self(acct.userid, buf3, "[³Æ¥÷]", "§Úªº³Ì·R"); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + char c; + char buf[64]; + struct dirent *de; + DIR *dirp; + + /* argc == 1 Âà¥þ³¡¨Ï¥ÎªÌ */ + /* argc == 2 Âà¬Y¯S©w¨Ï¥ÎªÌ */ + + if (argc > 2) + { + printf("Usage: %s [target_user]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (argc == 2) + { + transbmw(argv[1]); + exit(1); + } + + /* Âà´«¨Ï¥ÎªÌ¤ô²y°O¿ý */ + for (c = 'a'; c <= 'z'; c++) + { + sprintf(buf, "usr/%c", c); + + if (!(dirp = opendir(buf))) + continue; + + while (de = readdir(dirp)) + { + char *str; + + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + transbmw(str); + } + + closedir(dirp); + } + return 0; +} diff --git a/util/tran/ats2brd.c b/util/tran/ats2brd.c new file mode 100644 index 0000000..3904a9e --- /dev/null +++ b/util/tran/ats2brd.c @@ -0,0 +1,233 @@ +/*-------------------------------------------------------*/ +/* util/transbrd.c */ +/*-------------------------------------------------------*/ +/* target : Maple Sob 2.36 ¦Ü Maple 3.02 ¬ÝªOÂà´« */ +/* .BOARDS => .BRD */ +/* create : / / */ +/* update : 98/06/14 */ +/* author : ernie@micro8.ee.nthu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transbrd [target_board] */ +/*-------------------------------------------------------*/ + +#if 0 + + 1. ×§ï struct boardheader ¤Î transbrd() + (boardheader ¨âª©©w¸qªº¦r¦êªø«×¤£¤@¡A½Ð¦Û¦æ´«¦¨¼Æ¦r) + 2. §ë²¼¤£Âà´« + 3. ¶iªOµe± copy + 4. ¦p¦³»Ýn½Ð chmod 644 `find PATH -perm 600` + 5. ¶} gem ¥Ø¿ý gem/target_board/? ¦ý¤£Âà´« gem + 6. ¤£·|§ó·s bshm¡A¨Ï¥Î«á½Ð¦Û¦æ§ó·s + 7. Âà´««á½Ð¤â°Ê³]¬ÝªOÅv + + ps. Use on ur own risk. + +#endif + + +#include "ats.h" + + +static time_t +trans_hdr_chrono(filename) + char *filename; +{ + char time_str[11]; + + /* M.1087654321.A ©Î M.987654321.A */ + str_ncpy(time_str, filename + 2, filename[2] == '1' ? 11 : 10); + + return (time_t) atoi(time_str); +} + + +static void +trans_hdr_stamp(folder, t, hdr, fpath) + char *folder; + time_t t; + HDR *hdr; + char *fpath; +{ + FILE *fp; + char *fname, *family; + int rc; + + fname = fpath; + while (rc = *folder++) + { + *fname++ = rc; + if (rc == '/') + family = fname; + } + fname = family + 1; + *fname++ = '/'; + *fname++ = 'A'; + + for (;;) + { + *family = radix32[t & 31]; + archiv32(t, fname); + + if (fp = fopen(fpath, "r")) + { + fclose(fp); + t++; + } + else + { + memset(hdr, 0, sizeof(HDR)); + hdr->chrono = t; + str_stamp(hdr->date, &hdr->chrono); + strcpy(hdr->xname, --fname); + break; + } + } +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transbrd(bh) + boardheader *bh; +{ + static time_t stamp = 0; + + int fd; + char index[64], folder[64], buf[64], fpath[64]; + fileheader fh; + HDR hdr; + BRD newboard; + time_t chrono; + + printf("Âà´« %s ¬ÝªO\n", bh->brdname); + + brd_fpath(buf, bh->brdname, NULL); + if (dashd(buf)) + { + printf("%s ¤w¸g¦³¦¹¬ÝªO\n", bh->brdname); + return; + } + + if (!stamp) + time(&stamp); + + /* Âà´« .BRD */ + + memset(&newboard, 0, sizeof(newboard)); + str_ncpy(newboard.brdname, bh->brdname, sizeof(newboard.brdname)); + str_ncpy(newboard.class, bh->title, sizeof(newboard.class)); + str_ncpy(newboard.title, bh->title, sizeof(newboard.title)); + + str_ncpy(newboard.BM, bh->BM, sizeof(newboard.BM)); + newboard.bstamp = stamp++; + newboard.battr = BRD_NOTRAN; /* ¹w³]¤£Âà«H */ + newboard.readlevel = 0; + newboard.postlevel = PERM_POST; + + rec_add(FN_BRD, &newboard, sizeof(newboard)); /* §O§Ñ¤F¥Î brd2gem.c ¨ÓÂà´« Class */ + + /* ¶}·s¥Ø¿ý */ + + sprintf(fpath, "gem/brd/%s", newboard.brdname); + mak_dirs(fpath); + mak_dirs(fpath + 4); + + /* Âà´«¶iªOµe± */ + + sprintf(buf, OLD_BBSHOME "/boards/%s/notes", bh->brdname); + + if (dashf(buf)) + { + brd_fpath(fpath, newboard.brdname, FN_NOTE); + f_cp(buf, fpath, O_TRUNC); + } + + /* Âà´«¤å³¹ */ + + sprintf(index, OLD_BBSHOME "/boards/%s/.DIR", bh->brdname); /* ªº .DIR */ + brd_fpath(folder, newboard.brdname, ".DIR"); /* ·sªº .DIR */ + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + sprintf(buf, OLD_BBSHOME "/boards/%s/%s", bh->brdname, fh.filename); + if (dashf(buf)) /* ¤å³¹Àɮצb¤~°µÂà´« */ + { + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + trans_hdr_stamp(folder, chrono, &hdr, fpath); + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ansi(hdr.title, fh.title, sizeof(hdr.title)); + hdr.xmode = (fh.filemode & 0x2) ? POST_MARKED : 0; + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + f_cp(buf, fpath, O_TRUNC); + } + } + close(fd); + } +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int fd; + int count=0; + boardheader bh; + + /* argc == 1 Âà¥þ³¡ªO */ + /* argc == 2 Âà¬Y¯S©wªO */ + + if (argc > 2) + { + printf("Usage: %s [target_board]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (!dashf(FN_BOARD)) + { + printf("ERROR! Can't open " FN_BOARD "\n"); + exit(-1); + } + if (!dashd(OLD_BBSHOME "/boards")) + { + printf("ERROR! Can't open " OLD_BBSHOME "/boards\n"); + exit(-1); + } + + if ((fd = open(FN_BOARD, O_RDONLY)) >= 0) + { + while (read(fd, &bh, sizeof(bh)) == sizeof(bh)) + { + if (argc == 1) + { + transbrd(&bh); + count++; + } + else if (!strcmp(bh.brdname, argv[1])) + { + transbrd(&bh); + count++; + exit(1); + } + } + close(fd); + } + + printf("\n\nÁ`¦@Âà´« %d ӬݪO\n\n",count); + exit(0); +} diff --git a/util/tran/ats2gem.c b/util/tran/ats2gem.c new file mode 100644 index 0000000..691f88f --- /dev/null +++ b/util/tran/ats2gem.c @@ -0,0 +1,250 @@ +/*-------------------------------------------------------*/ +/* util/transman.c */ +/*-------------------------------------------------------*/ +/* target : Maple Sob 2.36 ¦Ü Maple 3.02 ºëµØ°ÏÂà´« */ +/* create : 98/06/15 */ +/* update : 02/10/26 */ +/* author : ernie@micro8.ee.nthu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transman [target_board] */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. µ{¦¡¤£¶}¥Ø¿ý¡A¨Ï¥Î«e¥ý½T©w gem/target_board/? ¥Ø¿ý¦s¦b + if not¡A¥ý¶}·sªO or transbrd + 2. ¥uÂà M.*.A ¤Î D.*.A¡A¨ä¥L link ¤£Âà´« + 3. ¦p¦³»Ýn½Ð¥ý chmod 644 `find PATH -perm 600` + + ps. User on ur own risk. + +#endif + + +#include "ats.h" + + +/* ----------------------------------------------------- */ +/* Âà´«ºëµØ°Ï */ +/* ----------------------------------------------------- */ + + +static time_t +trans_hdr_chrono(filename) + char *filename; +{ + char time_str[11]; + + /* M.1087654321.A ©Î M.987654321.A */ + str_ncpy(time_str, filename + 2, filename[2] == '1' ? 11 : 10); + + return (time_t) atoi(time_str); +} + + +static void +trans_man_stamp(folder, token, hdr, fpath, time) + char *folder; + int token; + HDR *hdr; + char *fpath; + time_t time; +{ + char *fname, *family; + int rc; + + fname = fpath; + while (rc = *folder++) + { + *fname++ = rc; + if (rc == '/') + family = fname; + } + if (*family != '.') + { + fname = family; + family -= 2; + } + else + { + fname = family + 1; + *fname++ = '/'; + } + + *fname++ = token; + + *family = radix32[time & 31]; + archiv32(time, fname); + + if (rc = open(fpath, O_WRONLY | O_CREAT | O_EXCL, 0600)) + { + memset(hdr, 0, sizeof(HDR)); + hdr->chrono = time; + str_stamp(hdr->date, &hdr->chrono); + strcpy(hdr->xname, --fname); + close(rc); + } + return; +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transman(index, folder) + char *index, *folder; +{ + static int count = 100; + + int fd; + char *ptr, buf[1024], fpath[64]; + fileheader fh; + HDR hdr; + time_t chrono; + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + strcpy(buf, index); + ptr = strrchr(buf, '/') + 1; + strcpy(ptr, fh.filename); + + if (*fh.filename == 'M' && dashf(buf)) /* ¥uÂà M.xxxx.A ¤Î D.xxxx.a */ + { + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + trans_man_stamp(folder, 'A', &hdr, fpath, chrono); + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ncpy(hdr.title, fh.title + 3, sizeof(hdr.title)); + + hdr.xmode = 0; + if (strstr(fh.title + 3, "[Hide]")) + hdr.xmode |= GEM_RESTRICT; + + if (strstr(fh.title + 3, "[ÁôÂÃ]")) + hdr.xmode |= GEM_RESTRICT; + + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + f_cp(buf, fpath, O_TRUNC); + } + else if (*fh.filename == 'D' && dashd(buf)) + { + char sub_index[512]; + + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = ++count; /* WD ªº¥Ø¿ý©R¦W¤ñ¸û©_©Ç¡A¥u¦n¦Û¤vµ¹¼Æ¦r */ + trans_man_stamp(folder, 'F', &hdr, fpath, chrono); + hdr.xmode = GEM_FOLDER; + if (strstr(fh.title + 3, "[Hide]")) + hdr.xmode |= GEM_RESTRICT; + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ncpy(hdr.title, fh.title + 3, sizeof(hdr.title)); + rec_add(folder, &hdr, sizeof(HDR)); + + /* recursive ¶i¥hÂà´«¤l¥Ø¿ý */ + strcpy(sub_index, buf); + ptr = strrchr(sub_index, '/') + 1; + sprintf(ptr, "%s/.DIR", fh.filename); + transman(sub_index, fpath); + } + } + close(fd); + } +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int fd,count=0,i; + char *brdname, index[64], folder[64]; + char bbname[30][30]; + boardheader bh; + + /* argc == 1 Âà¥þ³¡ªO */ + /* argc == 2 Âà¬Y¯S©wªO */ + + if (argc > 2) + { + printf("Usage: %s [target_board]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (!dashf(FN_BOARD)) + { + printf("ERROR! Can't open " FN_BOARD "\n"); + exit(-1); + } + if (!dashd(OLD_BBSHOME "/man/boards")) + { + printf("ERROR! Can't open " OLD_BBSHOME "/man/boards\n"); + exit(-1); + } + + if (argc == 1) + { + if ((fd = open(FN_BOARD, O_RDONLY)) >= 0) + { + while (read(fd, &bh, sizeof(bh)) == sizeof(bh)) + { + brdname = bh.brdname; + + sprintf(folder, "gem/brd/%s", brdname); + if (!dashd(folder)) + { + printf("ERROR! %s not exist. New it first.\n", folder); + strcpy(bbname[count] , brdname ); + count++; + continue; + } + + sprintf(index, OLD_BBSHOME "/man/boards/%s/.DIR", brdname); + sprintf(folder, "gem/brd/%s/%s", brdname, FN_DIR); + + printf("Âà´« %s ºëµØ°Ï\n", brdname); + transman(index, folder); + } + close(fd); + } + } + else + { + brdname = argv[1]; + + sprintf(folder, "gem/brd/%s", brdname); + if (!dashd(folder)) + { + printf("ERROR! %s not exist. New it first.\n", folder); + exit(-1); + } + + sprintf(index, OLD_BBSHOME "/man/boards/%s/.DIR", brdname); + sprintf(folder, "gem/brd/%s/%s", brdname, FN_DIR); + + printf("Âà´« %s ºëµØ°Ï\n", brdname); + transman(index, folder); + + exit(1); + } + + printf("\n\n¤£¦s¦bºëµØ°Ï¡A½ÐÀˬd¡C\n\n"); + for(i=0;i<count;i++) + printf("%s\n",bbname[i]); + + printf("\n"); + exit(0); +} diff --git a/util/tran/ats2mf.c b/util/tran/ats2mf.c new file mode 100644 index 0000000..a4630cf --- /dev/null +++ b/util/tran/ats2mf.c @@ -0,0 +1,173 @@ +/*-------------------------------------------------------*/ +/* util/transfavor.c */ +/*-------------------------------------------------------*/ +/* target : WD ¦Ü Maple 3.02 §Úªº³Ì·RÂà´« */ +/* create : 01/09/15 */ +/* update : / / */ +/* author : itoc.bbs@bbs.ee.nctu.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transfavor */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ×§ï transmf() + 2. Âà´«¦n¤Í¦W³æ¤§«e¡A±z¥²¶·¥ýÂà´«§¹¬ÝªO¤Î¨Ï¥ÎªÌ¡C + + ps. ¨Ï¥Î«e½Ð¥ý¦æ³Æ¥÷¡Ause on ur own risk. µ{¦¡©å¦H½Ð¥]²[ :p + ps. ·PÁ lkchu ªº Maple 3.02 for FreeBSD + +#endif + + +#include "ats.h" + +#ifdef MY_FAVORITE + + +/* ----------------------------------------------------- */ +/* 3.02 functions */ +/* ----------------------------------------------------- */ + + +static void +_mf_fpath(fpath, userid, fname) + char *fpath; + char *userid; /* lower ID */ + char *fname; +{ + if (fname) + sprintf(fpath, "usr/%c/%s/MF/%s", userid[0], userid, fname); + else + sprintf(fpath, "usr/%c/%s/MF", userid[0], userid); +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transmf(userid) + char *userid; +{ + ACCT acct; + FILE *fp; + int fd, num; + char fpath[64], buf[64]; + char *str, brdname[IDLEN + 1]; + MF mf; + + /* «Ø¥ß¥Ø¿ý */ + _mf_fpath(fpath, userid, NULL); + mkdir(fpath, 0700); + + /* sob ªº usr ¥Ø¿ý¦³¤À¤j¤p¼g¡A©Ò¥Hn¥ý¨ú±o¤j¤p¼g */ + usr_fpath(buf, userid, FN_ACCT); + if ((fd = open(buf, O_RDONLY)) >= 0) + { + read(fd, &acct, sizeof(ACCT)); + close(fd); + } + else + { + return; + } + + sprintf(buf, OLD_BBSHOME"/home/%s/favor_boards", acct.userid); /* ªº§Úªº³Ì·R */ + + printf("Âà´« %s ¡G§Úªº³Ì·R\n",acct.userid); + + if (!(fp = fopen(buf, "r"))) + return; + + _mf_fpath(fpath, userid, FN_MF); + num = 0; + + while (fgets(brdname, IDLEN + 1, fp)) + { + for (str = brdname; *str; str++) + { + if (*str <= ' ') + { + *str = '\0'; + break; + } + } + + brd_fpath(buf, brdname, NULL); + if (dashd(buf)) /* ªº½T¦³³oÓªO */ + { + mf.chrono = ++num; + mf.mftype = MF_BOARD; + str_ncpy(mf.xname, brdname, sizeof(mf.xname)); + mf.title[0] = '\0'; /* ¬ÝªO±¶®|¨S¦³ mf.title */ + rec_add(fpath, &mf, sizeof(MF)); + } + } + + fclose(fp); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + char c; + char buf[64]; + struct dirent *de; + DIR *dirp; + + /* argc == 1 Âà¥þ³¡¨Ï¥ÎªÌ */ + /* argc == 2 Âà¬Y¯S©w¨Ï¥ÎªÌ */ + + if (argc > 2) + { + printf("Usage: %s [target_user]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (argc == 2) + { + transmf(argv[1]); + exit(1); + } + + /* Âà´«¨Ï¥ÎªÌ§Úªº³Ì·R */ + for (c = 'a'; c <= 'z'; c++) + { + sprintf(buf, "usr/%c", c); + + if (!(dirp = opendir(buf))) + continue; + + while (de = readdir(dirp)) + { + char *str; + + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + transmf(str); + } + + closedir(dirp); + } + return 0; +} + +#else +int +main() +{ + printf("You should define MY_FAVORITE first.\n"); + return -1; +} +#endif /* MY_FAVORITE */ diff --git a/util/tran/ats2pal.c b/util/tran/ats2pal.c new file mode 100644 index 0000000..8a32647 --- /dev/null +++ b/util/tran/ats2pal.c @@ -0,0 +1,185 @@ +/*-------------------------------------------------------*/ +/* util/transpal.c */ +/*-------------------------------------------------------*/ +/* target : SOB ¦Ü Maple 3.02 (¬ÝªO)¦n¤Í¦W³æÂà´« */ +/* create : 01/09/08 */ +/* update : / / */ +/* author : itoc.bbs@bbs.ee.nctu.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transpal */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ³]©w OLD_BBSHOME (sob config.h) + 2. ×§ï struct FRIEND ©M transfer_pal() transfer_brdpal() + 3. Âà´«(¬ÝªO)¦n¤Í¦W³æ¤§«e¡A±z¥²¶·¥ýÂà´«§¹¬ÝªO¤Î¨Ï¥ÎªÌ¡C + + ps. ¨Ï¥Î«e½Ð¥ý¦æ³Æ¥÷¡Ause on ur own risk. µ{¦¡©å¦H½Ð¥]²[ :p + ps. ·PÁ lkchu ªº Maple 3.02 for FreeBSD + +#endif + + +#include "bbs.h" + + +#define OLD_BBSHOME "/home/bbs/bbsrs" /* 2.36 */ + + +/* ----------------------------------------------------- */ +/* 3.02 functions */ +/* ----------------------------------------------------- */ + + +static int +acct_uno(userid) + char *userid; +{ + int fd; + int userno; + char fpath[80]; + + usr_fpath(fpath, userid, FN_ACCT); + fd = open(fpath, O_RDONLY); + if (fd >= 0) + { + read(fd, &userno, sizeof(userno)); + close(fd); + return userno; + } + return -1; +} + + +/* ----------------------------------------------------- */ + + +static void +transfer_pal(userid) + char *userid; +{ + ACCT acct; + FILE *fp; + int fd, friend_userno; + char fpath[64], buf[64], friend_userid[80]; + PAL pal; + + usr_fpath(fpath, userid, FN_PAL); /* ·sªº¦n¤Í¦W³æ */ + + /* sob ªº usr ¥Ø¿ý¦³¤À¤j¤p¼g¡A©Ò¥Hn¥ý¨ú±o¤j¤p¼g */ + usr_fpath(buf, userid, FN_ACCT); + if ((fd = open(buf, O_RDONLY)) >= 0) + { + read(fd, &acct, sizeof(ACCT)); + close(fd); + } + sprintf(buf, OLD_BBSHOME"/home/%s/overrides", acct.userid); /* ªº¦n¤Í¦W³æ */ + + if (dashf(fpath)) + unlink(fpath); /* ²M±¼««Ø */ + + if (!(fp = fopen(buf, "r"))) + return; + + while (fscanf(fp, "%s", friend_userid) == 1) + { + if ((friend_userno = acct_uno(friend_userid)) >= 0) + { + memset(&pal, 0, sizeof(PAL)); + str_ncpy(pal.userid, friend_userid, sizeof(pal.userid)); + pal.ftype = 0; + str_ncpy(pal.ship, "", sizeof(pal.ship)); + pal.userno = friend_userno; + rec_add(fpath, &pal, sizeof(PAL)); + } + } + + fclose(fp); +} + + +static void +transfer_brdpal(userid) + char *userid; +{ + FILE *fp; + int friend_userno; + char fpath[64], buf[64], friend_userid[80]; + PAL pal; + + brd_fpath(fpath, userid, FN_PAL); /* ·sªº¬ÝªO¦n¤Í¦W³æ */ + sprintf(buf, OLD_BBSHOME"/boards/%s/permlist", userid); /* ªº¬ÝªO¦n¤Í¦W³æ */ + + if (dashf(fpath)) + unlink(fpath); /* ²M±¼««Ø */ + + if (!(fp = fopen(buf, "r"))) + return; + + while (fscanf(fp, "%s", friend_userid) == 1) + { + if ((friend_userno = acct_uno(friend_userid)) >= 0) + { + memset(&pal, 0, sizeof(PAL)); + str_ncpy(pal.userid, friend_userid, sizeof(pal.userid)); + pal.ftype = 0; + str_ncpy(pal.ship, "", sizeof(pal.ship)); + pal.userno = friend_userno; + rec_add(fpath, &pal, sizeof(PAL)); + } + } + + fclose(fp); +} + + +int +main() +{ + char c, *str; + char buf[64]; + struct dirent *de; + DIR *dirp; + + chdir(BBSHOME); + + printf("\n\n[¦n¤Í¦W³æ]\n\n"); + /* Âà´«¨Ï¥ÎªÌ¦n¤Í¦W³æ */ + for (c = 'a'; c <= 'z'; c++) + { + sprintf(buf, "usr/%c", c); + + if (!(dirp = opendir(buf))) + continue; + + while (de = readdir(dirp)) + { + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + transfer_pal(str); + } + closedir(dirp); + } + + printf("\n\n[ªO¤Í¦W³æ]\n\n"); + /* Âà´«¬ÝªO¦n¤Í¦W³æ */ + if (!(dirp = opendir("brd"))) + return 0; + + while (de = readdir(dirp)) + { + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + transfer_brdpal(str); + } + + closedir(dirp); + + return 0; +} diff --git a/util/tran/ats2usr.c b/util/tran/ats2usr.c new file mode 100644 index 0000000..7385249 --- /dev/null +++ b/util/tran/ats2usr.c @@ -0,0 +1,592 @@ +/*-------------------------------------------------------*/ +/* util/transusr.c */ +/*-------------------------------------------------------*/ +/* target : Maple Sob 2.36 ¦Ü Maple 3.02 ¨Ï¥ÎªÌÂà´« */ +/* .PASSWDS => .USR .ACCT */ +/* create : 98/06/14 */ +/* update : 02/10/26 */ +/* author : ernie@micro8.ee.nthu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transusr */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ×§ï struct userec ¤Î creat_dirs() + (userec ¨âª©©w¸qªº¦r¦êªø«×¤£¤@¡A½Ð¦Û¦æ´«¦¨¼Æ¦r) + 2. °£ plans ÀɦW¡A¦n¤Í¦W³æ¡B¼È¦sÀɵ¥³£¤£Âà´« + 3. Sob ¦³¤EÓñ¦WÀÉ¡A¥uÂà«e¤TÓ + 4. «H½c¤¤ªº internet mail ¦p¦³»Ýn½Ð¥ý chmod 644 `find PATH -perm 600` + + ps. ¨Ï¥Î«e½Ð¥ý¦æ³Æ¥÷¡Ause on ur own risk. µ{¦¡©å¦H½Ð¥]²[ :p + ps. ·PÁ lkchu ªº Maple 3.02 for FreeBSD + +#endif + + +#include "ats.h" + + +/* ----------------------------------------------------- */ +/* Âà´« .ACCT */ +/* ----------------------------------------------------- */ + + +static inline int +is_bad_userid(userid) + char *userid; +{ + register char ch; + + if (strlen(userid) < 2) + return 1; + + if (!isalpha(*userid)) + return 1; + + if (!str_cmp(userid, "new")) + return 1; + + while (ch = *(++userid)) + { + if (!isalnum(ch)) + return 1; + } + return 0; +} + + +static inline int +uniq_userno(fd) + int fd; +{ + char buf[4096]; + int userno, size; + SCHEMA *sp; /* record length 16 ¥i¾ã°£ 4096 */ + + userno = 1; + + while ((size = read(fd, buf, sizeof(buf))) > 0) + { + sp = (SCHEMA *) buf; + do + { + if (sp->userid[0] == '\0') + { + lseek(fd, -size, SEEK_CUR); + return userno; + } + userno++; + size -= sizeof(SCHEMA); + sp++; + } while (size); + } + + return userno; +} + + +#define LEVEL_BASIC 000000000001 /* °ò¥»Åv¤O */ +#define LEVEL_CHAT 000000000002 /* ¶i¤J²á¤Ñ«Ç */ +#define LEVEL_PAGE 000000000004 /* §ä¤H²á¤Ñ */ +#define LEVEL_POST 000000000010 /* µoªí¤å³¹ */ +#define LEVEL_LOGINOK 000000000020 /* µù¥Uµ{§Ç»{ÃÒ */ +#define LEVEL_MAILLIMIT 000000000040 /* «H¥óµL¤W */ +#define LEVEL_CLOAK 000000000100 /* Áô¨³N */ +#define LEVEL_SEECLOAK 000000000200 /* ¬Ý¨£§ÔªÌ */ +#define LEVEL_XEMPT 000000000400 /* ¥Ã¤[«O¯d±b¸¹ */ +#define LEVEL_BM 000000002000 /* ªO¥D */ +#define LEVEL_ACCOUNTS 000000004000 /* ±b¸¹Á`ºÞ */ +#define LEVEL_CHATROOM 000000010000 /* ²á¤Ñ«ÇÁ`ºÞ */ +#define LEVEL_BOARD 000000020000 /* ¬ÝªOÁ`ºÞ */ +#define LEVEL_SYSOP 000000040000 /* ¯¸ªø */ + + +static inline usint +trans_acct_level(perm) + usint perm; +{ + usint userlevel; + + userlevel = 0; + + if (perm & LEVEL_BASIC) + userlevel |= PERM_BASIC; + + if (perm & LEVEL_CHAT) + userlevel |= PERM_CHAT; + + if (perm & LEVEL_PAGE) + userlevel |= PERM_PAGE; + + if (perm & LEVEL_POST) + userlevel |= PERM_POST; + + if (perm & LEVEL_LOGINOK) + userlevel |= PERM_VALID; + + if (perm & LEVEL_MAILLIMIT) + userlevel |= PERM_MBOX; + + if (perm & LEVEL_CLOAK) + userlevel |= PERM_CLOAK; + + if (perm & LEVEL_SEECLOAK) + userlevel |= PERM_SEECLOAK; + + if (perm & LEVEL_XEMPT) + userlevel |= PERM_XEMPT; + + if (perm & LEVEL_BM) + userlevel |= PERM_BM; +/* + if (perm & LEVEL_ACCOUNTS) + userlevel |= PERM_ACCOUNTS; + + if (perm & LEVEL_CHATROOM) + userlevel |= PERM_CHATROOM; + + if (perm & LEVEL_BOARD) + userlevel |= PERM_BOARD; + + if (perm & LEVEL_SYSOP) + userlevel |= PERM_SYSOP; +*/ + + return userlevel; +} + + +static inline void +creat_dirs(old) + userec *old; +{ + ACCT new; + SCHEMA slot; + int fd; + char fpath[64]; + + memset(&new, 0, sizeof(new)); + memset(&slot, 0, sizeof(slot)); + + str_ncpy(new.userid, old->userid, sizeof(new.userid)); + str_ncpy(new.passwd, old->passwd, sizeof(new.passwd)); + str_ncpy(new.realname, old->realname, sizeof(new.realname)); + str_ncpy(new.username, old->username, sizeof(new.username)); + new.userlevel = trans_acct_level(old->userlevel); + new.ufo = UFO_DEFAULT_NEW; + new.signature = 0; + new.year = (old->year-11); + new.month = old->month; + new.day = old->day; + new.sex = old->sex ? 1 : 0; + new.money = 1000; /* ¹w³]»È¹ô = 1000 ª÷¹ô = 0 */ + new.gold = 0; + new.numlogins = old->numlogins; + new.numposts = old->numposts; + new.numemails = 0; + new.firstlogin = old->firstlogin; + new.lastlogin = old->lastlogin; + new.tcheck = time(&new.tvalid); + + str_ncpy(new.lasthost, old->lasthost, sizeof(new.lasthost)); + str_ncpy(new.email, old->email, sizeof(new.email)); + + slot.uptime = time(0); + strcpy(slot.userid, new.userid); + + fd = open(FN_SCHEMA, O_RDWR | O_CREAT, 0600); + new.userno = uniq_userno(fd); + write(fd, &slot, sizeof(slot)); + close(fd); + + usr_fpath(fpath, new.userid, NULL); + mkdir(fpath, 0700); + strcat(fpath, "/@"); + mkdir(fpath, 0700); + usr_fpath(fpath, new.userid, "MF"); + mkdir(fpath, 0700); + usr_fpath(fpath, new.userid, "gem"); /* itoc.010727: Ó¤HºëµØ°Ï */ + mak_links(fpath); + + usr_fpath(fpath, new.userid, ".ACCT"); + fd = open(fpath, O_WRONLY | O_CREAT, 0600); + write(fd, &new, sizeof(ACCT)); + close(fd); +} + + +/* ----------------------------------------------------- */ +/* Âà´«»{ÃÒ¸ê®Æ */ +/* ----------------------------------------------------- */ + + +static inline void +trans_justify(old) + userec *old; +{ + char fpath[64]; + FILE *fp; + + usr_fpath(fpath, old->userid, FN_JUSTIFY); + if (fp = fopen(fpath, "a")) + { + fprintf(fp, "RPY: %s\n", old->justify); /* Âà´«¹w³]¥H email »{ÃÒ */ + fclose(fp); + } +} + + +/* ----------------------------------------------------- */ +/* Âഫñ¦WÀÉ¡BpµeÀÉ */ +/* ----------------------------------------------------- */ +static void +_mail_self(userid, fpath, owner, title) /* itoc.011115: ±HÀÉ®×µ¹¦Û¤v */ + char *userid; /* ¦¬¥óªÌ */ + char *fpath; /* Àɮ׸ô®| */ + char *owner; /* ±H¥ó¤H */ + char *title; /* ¶l¥ó¼ÐÃD */ +{ + HDR fhdr; + char folder[64]; + + usr_fpath(folder, userid, FN_DIR); + close(hdr_stamp(folder, HDR_LINK, &fhdr, fpath)); + str_ncpy(fhdr.owner, owner, sizeof(fhdr.owner)); + str_ncpy(fhdr.title, title, sizeof(fhdr.title)); + fhdr.xmode = 0; + rec_add(folder, &fhdr, sizeof(fhdr)); +} + + +static inline void +trans_sig(old) + userec *old; +{ + int i; + char buf[64], fpath[64], f_sig[20],buf1[20]; + + for (i = 1; i <= 3; i++) /* Maple 3.0 ¥u¦³¤TÓñ¦W */ + { + sprintf(buf, OLD_BBSHOME "/home/%s/sig.%d", old->userid, i); /* ªºÃ±¦WÀÉ */ + if (dashf(buf)) + { + sprintf(f_sig, "%s.%d", FN_SIGN, i); + usr_fpath(fpath, old->userid, f_sig); + f_cp(buf, fpath, O_TRUNC); + } + } + for(i=4;i<=10;i++) + { + sprintf(buf, OLD_BBSHOME "/home/%s/sig.%d", old->userid, i); + sprintf(buf1,"ñ¦WÀÉ sig.%d",i); + if (dashf(buf)) + _mail_self(old->userid, buf, "[³Æ¥÷]", buf1); + } +} + + +static inline void +trans_plans(old) + userec *old; +{ + char buf[64], fpath[64]; + + sprintf(buf, OLD_BBSHOME "/home/%s/plans", old->userid); + if (dashf(buf)) + { + usr_fpath(fpath, old->userid, FN_PLANS); + f_cp(buf, fpath, O_TRUNC); + } + return; +} + + +/* ----------------------------------------------------- */ +/* Âà´««H¥ó */ +/* ----------------------------------------------------- */ + + +static time_t +trans_hdr_chrono(filename) + char *filename; +{ + char time_str[11]; + + /* M.1087654321.A ©Î M.987654321.A */ + str_ncpy(time_str, filename + 2, filename[2] == '1' ? 11 : 10); + + return (time_t) atoi(time_str); +} + + +static inline void +trans_mail(old) + userec *old; +{ + int fd; + char index[64], folder[64], buf[64], fpath[64]; + fileheader fh; + HDR hdr; + + sprintf(index, OLD_BBSHOME "/home/%s/.DIR", old->userid); + usr_fpath(folder, old->userid, FN_DIR); + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + sprintf(buf, OLD_BBSHOME "/home/%s/%s", old->userid, fh.filename); + + if (dashf(buf)) /* ¤å³¹Àɮצb¤~°µÂà´« */ + { + time_t chrono; + char new_name[10] = "@"; + + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + new_name[1] = radix32[chrono & 31]; + archiv32(chrono, new_name + 1); + + hdr.chrono = chrono; + str_ncpy(hdr.xname, new_name, sizeof(hdr.xname)); + str_ncpy(hdr.owner, strstr(fh.owner, "[³Æ.") ? "[³Æ§Ñ¿ý]" : fh.owner, sizeof(hdr.owner)); /* [³Æ.§Ñ.¿ý] */ + str_ncpy(hdr.title, fh.title, sizeof(hdr.title)); + str_stamp(hdr.date, &hdr.chrono); + hdr.xmode = (fh.filemode & 0x2) ? (MAIL_MARKED | MAIL_READ) : MAIL_READ; /* ³]¬°¤wŪ */ + + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + usr_fpath(fpath, old->userid, "@/"); + strcat(fpath, new_name); + f_cp(buf, fpath, O_TRUNC); + } + } + close(fd); + } +} + + +/* ----------------------------------------------------- */ +/* Âà´«Ó¤HºëµØ°Ï */ +/* ----------------------------------------------------- */ + + +#ifdef HAVE_PERSONAL_GEM +static void +trans_man_stamp(folder, token, hdr, fpath, time) + char *folder; + int token; + HDR *hdr; + char *fpath; + time_t time; +{ + char *fname, *family; + int rc; + + fname = fpath; + while (rc = *folder++) + { + *fname++ = rc; + if (rc == '/') + family = fname; + } + if (*family != '.') + { + fname = family; + family -= 2; + } + else + { + fname = family + 1; + *fname++ = '/'; + } + + *fname++ = token; + + *family = radix32[time & 31]; + archiv32(time, fname); + + if (rc = open(fpath, O_WRONLY | O_CREAT | O_EXCL, 0600)) + { + memset(hdr, 0, sizeof(HDR)); + hdr->chrono = time; + str_stamp(hdr->date, &hdr->chrono); + strcpy(hdr->xname, --fname); + close(rc); + } + return; +} + + +static void +transman(index, folder) + char *index, *folder; +{ + static int count = 100; + + int fd; + char *ptr, buf[256], fpath[64]; + fileheader fh; + HDR hdr; + time_t chrono; + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + strcpy(buf, index); + ptr = strrchr(buf, '/') + 1; + strcpy(ptr, fh.filename); + + if (*fh.filename == 'M' && dashf(buf)) /* ¥uÂà M.xxxx.A ¤Î D.xxxx.a */ + { + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + trans_man_stamp(folder, 'A', &hdr, fpath, chrono); + hdr.xmode = 0; + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ncpy(hdr.title, fh.title + 3, sizeof(hdr.title)); + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + f_cp(buf, fpath, O_TRUNC); + } + else if (*fh.filename == 'D' && dashd(buf)) + { + char sub_index[256]; + + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = ++count; /* WD ªº¥Ø¿ý©R¦W¤ñ¸û©_©Ç¡A¥u¦n¦Û¤vµ¹¼Æ¦r */ + trans_man_stamp(folder, 'F', &hdr, fpath, chrono); + hdr.xmode = GEM_FOLDER; + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ncpy(hdr.title, fh.title + 3, sizeof(hdr.title)); + rec_add(folder, &hdr, sizeof(HDR)); + + /* recursive ¶i¥hÂà´«¤l¥Ø¿ý */ + strcpy(sub_index, buf); + ptr = strrchr(sub_index, '/') + 1; + sprintf(ptr, "%s/.DIR", fh.filename); + transman(sub_index, fpath); + } + } + close(fd); + } +} +#endif + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transusr(user) + userec *user; +{ + char buf[64]; + + printf("Âà´« %s ¨Ï¥ÎªÌ\n", user->userid); + + if (is_bad_userid(user->userid)) + { + printf("%s ¤£¬O¦Xªk ID\n", user->userid); + return; + } + + usr_fpath(buf, user->userid, NULL); + if (dashd(buf)) + { + printf("%s ¤w¸g¦³¦¹ ID\n", user->userid); + return; + } + + sprintf(buf, OLD_BBSHOME "/home/%s", user->userid); + if (!dashd(buf)) + { + printf("%s ªºÀɮפ£¦s¦b\n", user->userid); + return; + } + + creat_dirs(user); + trans_justify(user); + trans_sig(user); + trans_plans(user); + trans_mail(user); + + +#ifdef HAVE_PERSONAL_GEM + sprintf(buf, OLD_BBSHOME "/home/%s/man", user->userid); + if (dashd(buf)) + { + char index[64], folder[64]; + + sprintf(index, "%s/.DIR", buf); + usr_fpath(folder, user->userid, "gem/" FN_DIR); + transman(index, folder); + } +#endif + +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int fd,count=0; + userec user; + + /* argc == 1 Âà¥þ³¡¨Ï¥ÎªÌ */ + /* argc == 2 Âà¬Y¯S©w¨Ï¥ÎªÌ */ + + if (argc > 2) + { + printf("Usage: %s [target_user]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (!dashf(FN_PASSWD)) + { + printf("ERROR! Can't open " FN_PASSWD "\n"); + exit(-1); + } + if (!dashd(OLD_BBSHOME "/home")) + { + printf("ERROR! Can't open " OLD_BBSHOME "/home\n"); + exit(-1); + } + + if ((fd = open(FN_PASSWD, O_RDONLY)) >= 0) + { + while (read(fd, &user, sizeof(user)) == sizeof(user)) + { + if (argc == 1) + { + transusr(&user); + count++; + } + else if (!strcmp(user.userid, argv[1])) + { + transusr(&user); + count++; + exit(1); + } + } + close(fd); + } + + printf("\n\n¥þ³¡Âà´« %d ¦ì¨Ï¥ÎªÌ¡C\n\n",count); + exit(0); +} diff --git a/util/tran/brd2gem.c b/util/tran/brd2gem.c new file mode 100644 index 0000000..3473d74 --- /dev/null +++ b/util/tran/brd2gem.c @@ -0,0 +1,104 @@ +/*-------------------------------------------------------*/ +/* util/brd2gem.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¬ÝªO¤ÀÃþ¨ìºëµØ°Ï */ +/* create : 01/09/09 */ +/* update : 03/02/13 */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : brd2gem ¤ÀÃþ Classname */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#if 0 /* ¨Ï¥Î¤èªk */ + + ³oÓµ{¦¡¬O®³¨Óµ¹ bbs ª©¥»Âà´«®É¡A¦Û°Ê«Ø¥ß @Class ¥Îªº¡C + ©Î¬O¦b»~¬å¤ÀÃþ®É¡A¤]¥i¥H®³¥X¨Ó««Ø @Class ¥Î¡C + + °²³]n§â©Ò¦³¤ÀÃþ¬°¡u¨t²Î¡v©M¡u¯¸¤º¡vªº¬ÝªO³£©ñ¦b¡uBBS¡v³oÓ¤ÀÃþ¸Ì±¡A + ¥H¤Î§â©Ò¦³¤ÀÃþ¬°¡uÓ¤H¡vªº¬ÝªO³£©ñ¦b¡uPersonal¡v³oÓ¤ÀÃþ¸Ì±¡C + + 1. ¤W BBS ¯¸¡A¦b (A)nnounce/Class ¸Ì± Ctrl+P ¿ï (C)¡A«Ø¥ßÀɦW¬° BBS ªº¤ÀÃþ (¼ÐÃD¥ô·N)¡C + 2. ¤W BBS ¯¸¡A¦b (A)nnounce/Class ¸Ì± Ctrl+P ¿ï (C)¡A«Ø¥ßÀɦW¬° Personal ªº¤ÀÃþ (¼ÐÃD¥ô·N)¡C + 3. ¦b¤u§@¯¸¤¤¥H bbs ¨¤À°õ¦æ + % ~bbs/src/util/tran/brd2gem ¨t²Î BBS + % ~bbs/src/util/tran/brd2gem ¯¸¤º BBS + % ~bbs/src/util/tran/brd2gem Ó¤H Personal + +#endif + + +static void +brd_2_gem(brd, gem) + BRD *brd; + HDR *gem; +{ + memset(gem, 0, sizeof(HDR)); + time(&gem->chrono); + strcpy(gem->xname, brd->brdname); + sprintf(gem->title, "%-13s%-5s%s", brd->brdname, brd->class, brd->title); + gem->xmode = GEM_BOARD | GEM_FOLDER; + +#ifdef HAVE_MODERATED_BOARD + /* ¯µ±KªO¡B¦n¤ÍªO */ + if (brd->readlevel == PERM_SYSOP || brd->readlevel == PERM_BOARD) + gem->xmode |= GEM_RESTRICT; +#endif +} + + +static int +hdr_cmp(a, b) + HDR *a; + HDR *b; +{ + /* itoc.010413: ¤ÀÃþ/ªO¦W¥æ¤e¤ñ¹ï */ + int k = strncmp(a->title + BNLEN + 1, b->title + BNLEN + 1, BCLEN); + return k ? k : str_cmp(a->xname, b->xname); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int fd; + char folder[64]; + BRD brd; + HDR hdr; + + chdir(BBSHOME); + + if (argc != 3) + { + printf("Usage: %s ¤ÀÃþ Classname\n", argv[0]); + exit(-1); + } + + if (strlen(argv[1]) > BCLEN || strlen(argv[2]) > BNLEN) + { + printf("¡u¤ÀÃþ¡vnµu©ó %d¡AClassname nµu©ó %d\n", BCLEN, BNLEN); + exit(-1); + } + + sprintf(folder, "gem/@/@%s", argv[2]); + + if ((fd = open(FN_BRD, O_RDONLY)) >= 0) + { + while (read(fd, &brd, sizeof(BRD)) == sizeof(BRD)) + { + if (!strcmp(brd.class, argv[1])) + { + brd_2_gem(&brd, &hdr); + rec_add(folder, &hdr, sizeof(HDR)); + } + } + close(fd); + } + + rec_sync(folder, sizeof(HDR), hdr_cmp, NULL); +} diff --git a/util/tran/cola.h b/util/tran/cola.h new file mode 100644 index 0000000..9bfa18f --- /dev/null +++ b/util/tran/cola.h @@ -0,0 +1,74 @@ +/*-------------------------------------------------------*/ +/* util/cola.h */ +/*-------------------------------------------------------*/ +/* target : Cola ¦Ü Maple 3.02 Âà´« */ +/* create : 03/02/11 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + 0. ½Ð¥ý©ó Cola §â©Ò¦³¬ÝªO^¤å¦W¦r§ï¦b 12 ¦r¥H¤º¡C + + 1. ¥²¶·¦b brd Âà§¹¤~¥i¥HÂà´« gem + 2. «ØÄ³Âà´«¶¶§Ç¬° usr -> brd -> gem -> post + + 3. ³]©w COLABBS_HOME¡BCOLABBS_BOARDS¡BCOLABBS_MAN¡BFN_BOARD + +#endif + + +#include "bbs.h" + + +#define COLABBS_HOME "/tmp/home" /* ªº Cola BBS ªº¨Ï¥ÎªÌ¥Ø¿ý */ +#define COLABBS_BOARDS "/tmp/boards" /* ªº Cola BBS ªº¬ÝªO¥Ø¿ý */ +#define COLABBS_MAN "/tmp/man" /* ªº Cola BBS ªººëµØ°Ï¥Ø¿ý */ +#define FN_BOARD "/tmp/.boards" /* ªº Cola BBS ªº .boards */ + + +/* ----------------------------------------------------- */ +/* old .PASSWDS struct : 512 bytes */ +/* ----------------------------------------------------- */ + +/* itoc.030211: ¥uÂà´« userid ©M passwd */ +typedef struct +{ + char userid[13]; + char blank1; + char passwd[14]; + char username[40]; + char realname[80]; + char blank2[364]; +} userec; + + +/* ----------------------------------------------------- */ +/* old DIR of board struct : 128 bytes */ +/* ----------------------------------------------------- */ + +typedef struct +{ + char filename[34]; /* M.9876543210.A */ + char blank1[46]; + char owner[14]; /* userid[.] */ + char blank2[57]; + char date[6]; /* [08/27] or space(5) */ + char title[74]; + char blank3[25]; +} fileheader; + + +/* ----------------------------------------------------- */ +/* old BOARDS struct : 512 bytes */ +/* ----------------------------------------------------- */ + +/* itoc.030211: ¥uÂà´« brdname ©M title */ +typedef struct +{ + char brdname[13]; + char blank1[147]; + char title[96]; +} boardheader; diff --git a/util/tran/cola2brd.c b/util/tran/cola2brd.c new file mode 100644 index 0000000..0f4d4de --- /dev/null +++ b/util/tran/cola2brd.c @@ -0,0 +1,212 @@ +/*-------------------------------------------------------*/ +/* util/cola2brd.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : Cola ¦Ü Maple 3.02 ¬ÝªOÂà´« */ +/* create : 03/02/11 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "cola.h" + + +static inline time_t +trans_hdr_chrono(filename) + char *filename; +{ + char time_str[11]; + + /* M.1087654321.A ©Î M.987654321.A */ + str_ncpy(time_str, filename + 2, filename[2] == '1' ? 11 : 10); + + return (time_t) atoi(time_str); +} + + +static inline void +trans_hdr_stamp(folder, t, hdr, fpath) + char *folder; + time_t t; + HDR *hdr; + char *fpath; +{ + FILE *fp; + char *fname, *family; + int rc; + + fname = fpath; + while (rc = *folder++) + { + *fname++ = rc; + if (rc == '/') + family = fname; + } + fname = family + 1; + *fname++ = '/'; + *fname++ = 'A'; + + for (;;) + { + *family = radix32[t & 31]; + archiv32(t, fname); + + if (fp = fopen(fpath, "r")) + { + fclose(fp); + t++; + } + else + { + memset(hdr, 0, sizeof(HDR)); + hdr->chrono = t; + str_stamp(hdr->date, &hdr->chrono); + strcpy(hdr->xname, --fname); + break; + } + } +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transbrd(bh) + boardheader *bh; +{ + static time_t stamp = 0; + + int fd; + char fpath[64], folder[64], index[64], buf[64]; + fileheader fh; + BRD newboard; + HDR hdr; + time_t chrono; + + printf("Âà´« %s ¬ÝªO\n", bh->brdname); + + brd_fpath(buf, bh->brdname, NULL); + if (dashd(buf)) + { + printf("%s ¤w¸g¦³¦¹¬ÝªO\n", bh->brdname); + return; + } + + if (!stamp) + time(&stamp); + + /* Âà´« .BRD */ + + memset(&newboard, 0, sizeof(newboard)); + str_ncpy(newboard.brdname, bh->brdname, sizeof(newboard.brdname)); + str_ncpy(newboard.class, bh->title + 2, sizeof(newboard.class)); + str_ncpy(newboard.title, bh->title + 12, sizeof(newboard.title)); + /* newboard.BM[0] = '\0'; */ /* ªO¥D¤£Âà´« */ + newboard.bstamp = stamp++; + newboard.battr = BRD_NOTRAN; + newboard.readlevel = 0; + newboard.postlevel = PERM_POST; + + rec_add(FN_BRD, &newboard, sizeof(newboard)); /* §O§Ñ¤F¥Î brd2gem.c ¨ÓÂà´« Class */ + + /* ¶}·s¥Ø¿ý */ + + sprintf(fpath, "gem/brd/%s", newboard.brdname); + mak_dirs(fpath); + mak_dirs(fpath + 4); + + /* Âà´«¶iªOµe± */ + + sprintf(buf, COLABBS_BOARDS "/%s/.Welcome", bh->brdname); + + if (dashf(buf)) + { + brd_fpath(fpath, newboard.brdname, FN_NOTE); + f_cp(buf, fpath, O_TRUNC); + } + + /* Âà´«¤å³¹ */ + + sprintf(index, COLABBS_BOARDS "/%s/.DIR", bh->brdname); /* ªº .DIR */ + brd_fpath(folder, newboard.brdname, ".DIR"); /* ·sªº .DIR */ + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + sprintf(buf, COLABBS_BOARDS "/%s/%s", bh->brdname, fh.filename); + + if (dashf(buf)) /* ¤å³¹Àɮצb¤~°µÂà´« */ + { + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + trans_hdr_stamp(folder, chrono, &hdr, fpath); + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ansi(hdr.title, fh.title + 3, sizeof(hdr.title)); + hdr.xmode = 0; + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + f_cp(buf, fpath, O_TRUNC); + } + } + close(fd); + } +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int fd; + boardheader bh; + + /* argc == 1 Âà¥þ³¡ªO */ + /* argc == 2 Âà¬Y¯S©wªO */ + + if (argc > 2) + { + printf("Usage: %s [target_board]\n", argv[0]); + return -1; + } + + chdir(BBSHOME); + + if (!dashf(FN_BOARD)) + { + printf("ERROR! Can't open " FN_BOARD "\n"); + return -1; + } + if (!dashd(COLABBS_BOARDS)) + { + printf("ERROR! Can't open " COLABBS_BOARDS "\n"); + return -1; + } + + if ((fd = open(FN_BOARD, O_RDONLY)) >= 0) + { + while (read(fd, &bh, sizeof(bh)) == sizeof(bh)) + { + bh.brdname[BNLEN] = '\0'; /* itoc.030211: Cola ªº¬ÝªO¦W¥i¯à¶W¹L BNLEN */ + + if (argc == 1) + { + transbrd(&bh); + } + else if (!strcmp(bh.brdname, argv[1])) + { + transbrd(&bh); + return 1; + } + } + close(fd); + } + + return 0; +} diff --git a/util/tran/cola2gem.c b/util/tran/cola2gem.c new file mode 100644 index 0000000..4d93c14 --- /dev/null +++ b/util/tran/cola2gem.c @@ -0,0 +1,211 @@ +/*-------------------------------------------------------*/ +/* util/cola2gem.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : Cola ¦Ü Maple 3.02 ºëµØ°ÏÂà´« */ +/* create : 03/02/11 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "cola.h" + + +/* ----------------------------------------------------- */ +/* Âà´«ºëµØ°Ï */ +/* ----------------------------------------------------- */ + + +static time_t +trans_hdr_chrono(filename) + char *filename; +{ + char time_str[11]; + + /* M.1087654321.A ©Î M.987654321.A */ + str_ncpy(time_str, filename + 2, filename[2] == '1' ? 11 : 10); + + return (time_t) atoi(time_str); +} + + +static void +trans_man_stamp(folder, token, hdr, fpath, time) + char *folder; + int token; + HDR *hdr; + char *fpath; + time_t time; +{ + char *fname, *family; + int rc; + + fname = fpath; + while (rc = *folder++) + { + *fname++ = rc; + if (rc == '/') + family = fname; + } + if (*family != '.') + { + fname = family; + family -= 2; + } + else + { + fname = family + 1; + *fname++ = '/'; + } + + *fname++ = token; + + *family = radix32[time & 31]; + archiv32(time, fname); + + if (rc = open(fpath, O_WRONLY | O_CREAT | O_EXCL, 0600)) + { + memset(hdr, 0, sizeof(HDR)); + hdr->chrono = time; + str_stamp(hdr->date, &hdr->chrono); + strcpy(hdr->xname, --fname); + close(rc); + } + return; +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transman(index, folder) + char *index, *folder; +{ + int fd; + char *ptr, buf[256], fpath[64]; + fileheader fh; + HDR hdr; + time_t chrono; + + if ((fd = open(index , O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + strcpy(buf, index); + ptr = strrchr(buf, '/') + 1; + strcpy(ptr, fh.filename); + + if (*fh.filename == 'M' && dashf(buf)) /* ¥uÂà M.xxxx.A ¤Î D.xxxx.a */ + { + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + trans_man_stamp(folder, 'A', &hdr, fpath, chrono); + hdr.xmode = 0; + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ncpy(hdr.title, fh.title + 3, sizeof(hdr.title)); + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + f_cp(buf, fpath, O_TRUNC); + } + else if (*fh.filename == 'D' && dashd(buf)) + { + char sub_index[256]; + + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + trans_man_stamp(folder, 'F', &hdr, fpath, chrono); + hdr.xmode = GEM_FOLDER; + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ncpy(hdr.title, fh.title + 3, sizeof(hdr.title)); + rec_add(folder, &hdr, sizeof(HDR)); + + /* recursive ¶i¥hÂà´«¤l¥Ø¿ý */ + strcpy(sub_index, buf); + ptr = strrchr(sub_index, '/') + 1; + sprintf(ptr, "%s/.DIR", fh.filename); + transman(sub_index, fpath); + } + } + close(fd); + } +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int fd; + char *brdname, index[64], folder[64]; + boardheader bh; + + /* argc == 1 Âà¥þ³¡ªO */ + /* argc == 2 Âà¬Y¯S©wªO */ + + if (argc > 2) + { + printf("Usage: %s [target_board]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (!dashf(FN_BOARD)) + { + printf("ERROR! Can't open " FN_BOARD "\n"); + exit(-1); + } + + if (argc == 1) + { + if ((fd = open(FN_BOARD, O_RDONLY)) >= 0) + { + while (read(fd, &bh, sizeof(bh)) == sizeof(bh)) + { + brdname = bh.brdname; + + sprintf(folder, "gem/brd/%s", brdname); + if (!dashd(folder)) + { + printf("ERROR! %s not exist. New it first.\n", folder); + continue; + } + + sprintf(index, COLABBS_MAN "/%s/.DIR", brdname); + sprintf(folder, "gem/brd/%s/%s", brdname, FN_DIR); + + printf("Âà´« %s ºëµØ°Ï\n", brdname); + transman(index, folder); + } + close(fd); + } + } + else + { + brdname = argv[1]; + + sprintf(folder, "gem/brd/%s", brdname); + if (!dashd(folder)) + { + printf("ERROR! %s not exist. New it first.\n", folder); + exit(-1); + } + + sprintf(index, COLABBS_MAN "/%s/.DIR", brdname); + sprintf(folder, "gem/brd/%s/%s", brdname, FN_DIR); + + printf("Âà´« %s ºëµØ°Ï\n", brdname); + transman(index, folder); + + exit(1); + } + + exit(0); +} diff --git a/util/tran/cola2post.c b/util/tran/cola2post.c new file mode 100644 index 0000000..f62ae6e --- /dev/null +++ b/util/tran/cola2post.c @@ -0,0 +1,223 @@ +/*-------------------------------------------------------*/ +/* util/cola2post.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : Cola ¦Ü Maple 3.02 ¬ÝªO¤å³¹®æ¦¡Âà´« */ +/* create : 03/02/21 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#if 0 + + ¥H¤U³oÓ¬O ColaBBS ¤å³¹Àɮתº½d¨Ò + +*[m*[47;34m §@ªÌ *[44;37m userid (¼ÊºÙ) *[47;34m «H°Ï *[44;37m SYSOP *[m\n\r +*[47;34m ¼ÐÃD *[44;37m Re: °Õ°Õ°Õ°Õ°Õ°Õ *[m\n\r +*[47;34m ®É¶¡ *[44;37m Fri Mar 15 11:33:20 2002 *[m\n\r +*[36m¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w*[m\n\r +\n\r +¤å³¹¤º®e²Ä¤@¦æ\n\r +¤å³¹¤º®e²Ä¤G¦æ\n\r + + n§ï¦¨³o¼Ë + +§@ªÌ: userid (¼ÊºÙ) ¯¸¤º: SYSOP\n +¼ÐÃD: Re: °Õ°Õ°Õ°Õ°Õ°Õ\n +®É¶¡: Fri Mar 15 11:33:20 2002\n +\n +¤å³¹¤º®e²Ä¤@¦æ\n +¤å³¹¤º®e²Ä¤G¦æ\n + +#endif + + +static void +reaper(fpath) + char *fpath; +{ + FILE *fpr, *fpw; + char src[256], dst[256]; + char fnew[64]; + char *ptr; + int i; + + if (!(fpr = fopen(fpath, "r"))) + return; + + sprintf(fnew, "%s.new", fpath); + fpw = fopen(fnew, "w"); + + i = 0; + while (fgets(src, 256, fpr)) + { + if (ptr = strchr(src, '\r')) + *ptr = '\0'; + if (ptr = strchr(src, '\n')) + *ptr = '\0'; + + if (i < 4) /* «e¥|¦æÀÉÀY */ + { + i++; + + if (*src == '\033') /* ¦¹¬°ÀÉÀY */ + { + str_ansi(dst, src, sizeof(dst)); /* ¥h±¼ ANSI */ + + if (i <= 3 && dst[0] == ' ' && dst[5] == ' ') /* §@ªÌ: */ + { + dst[5] = ':'; + fprintf(fpw, "%.78s\n", dst + 1); /* ¥h°£²Ä¤@®æªÅ¥Õ */ + continue; + } + else if (i == 4 && !strncmp(dst, "¢w¢w¢w¢w", 8)) + { + /* ¤À¹j½u¤£n¤F */ + continue; + } + } + } + + fprintf(fpw, "%s\n", src); /* ¤º®e·Ó§Û */ + } + + fclose(fpr); + fclose(fpw); + + unlink(fpath); + rename(fnew, fpath); +} + + +static void +expireBrd(brdname) + char *brdname; +{ + int fd; + char folder[64], fpath[64]; + HDR hdr; + + printf("Âà´« %s ¬ÝªO\n", brdname); + + brd_fpath(folder, brdname, FN_DIR); + + if ((fd = open(folder, O_RDONLY)) >= 0) + { + while (read(fd, &hdr, sizeof(HDR)) == sizeof(HDR)) + { + sprintf(fpath, "brd/%s/%c/%s", brdname, hdr.xname[7], hdr.xname); + reaper(fpath); + } + close(fd); + } +} + + +static void +expireGem(brdname) + char *brdname; +{ + int i; + char c; + char fpath[64], *str; + struct dirent *de; + DIR *dirp; + + printf("Âà´« %s ºëµØ°Ï\n", brdname); + + for (i = 0; i < 32; i++) + { + c = radix32[i]; + sprintf(fpath, "gem/brd/%s/%c", brdname, c); + + if (!(dirp = opendir(fpath))) + continue; + + while (de = readdir(dirp)) + { + str = de->d_name; + if (*str <= ' ' || *str == '.' || *str == 'F') + continue; + + sprintf(fpath, "gem/brd/%s/%c/%s", brdname, c, str); + reaper(fpath); + } + + closedir(dirp); + } +} + + +static void +expireUsr(userid) + char *userid; +{ + int fd; + char folder[64], fpath[64]; + HDR hdr; + + printf("Âà´« %s «H¥ó\n", userid); + + usr_fpath(folder, userid, FN_DIR); + + if ((fd = open(folder, O_RDONLY)) >= 0) + { + while (read(fd, &hdr, sizeof(HDR)) == sizeof(HDR)) + { + sprintf(fpath, "usr/%c/%s/@/%s", *userid, userid, hdr.xname); + reaper(fpath); + } + close(fd); + } +} + + +int +main() +{ + int fd; + char c, *str, buf[64]; + BRD brd; + struct dirent *de; + DIR *dirp; + + chdir(BBSHOME); + + /* Âà´«¬ÝªO/ºëµØ°Ï¤å³¹ */ + + if ((fd = open(FN_BRD, O_RDONLY)) >= 0) + { + while (read(fd, &brd, sizeof(BRD)) == sizeof(BRD)) + { + str = brd.brdname; + expireBrd(str); + expireGem(str); + } + close(fd); + } + + /* Âà´«¨Ï¥ÎªÌ«H¥ó */ + + for (c = 'a'; c <= 'z'; c++) + { + sprintf(buf, "usr/%c", c); + if (!(dirp = opendir(buf))) + continue; + + while (de = readdir(dirp)) + { + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + expireUsr(str); + } + + closedir(dirp); + } + + return 0; +} diff --git a/util/tran/cola2usr.c b/util/tran/cola2usr.c new file mode 100644 index 0000000..51bac0e --- /dev/null +++ b/util/tran/cola2usr.c @@ -0,0 +1,291 @@ +/*-------------------------------------------------------*/ +/* util/cola2usr.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : Cola ¦Ü Maple 3.02 ¨Ï¥ÎªÌÂà´« */ +/* create : 03/02/11 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "cola.h" + + +/* ----------------------------------------------------- */ +/* Âà´« .ACCT */ +/* ----------------------------------------------------- */ + + +static inline int +is_bad_userid(userid) + char *userid; +{ + register char ch; + + if (strlen(userid) < 2) + return 1; + + if (!isalpha(*userid)) + return 1; + + if (!str_cmp(userid, "new")) + return 1; + + while (ch = *(++userid)) + { + if (!isalnum(ch)) + return 1; + } + return 0; +} + + +static inline int +uniq_userno(fd) + int fd; +{ + char buf[4096]; + int userno, size; + SCHEMA *sp; /* record length 16 ¥i¾ã°£ 4096 */ + + userno = 1; + + while ((size = read(fd, buf, sizeof(buf))) > 0) + { + sp = (SCHEMA *) buf; + do + { + if (sp->userid[0] == '\0') + { + lseek(fd, -size, SEEK_CUR); + return userno; + } + userno++; + size -= sizeof(SCHEMA); + sp++; + } while (size); + } + + return userno; +} + + +static inline void +creat_dirs(old) + userec *old; +{ + ACCT new; + SCHEMA slot; + int fd; + char fpath[64]; + time_t now; + + time(&now); + + memset(&new, 0, sizeof(new)); + memset(&slot, 0, sizeof(slot)); + + str_ncpy(new.userid, old->userid, sizeof(new.userid)); + str_ncpy(new.passwd, old->passwd, sizeof(new.passwd)); + str_ncpy(new.username, old->username, sizeof(new.username)); + str_ncpy(new.realname, old->realname, sizeof(new.realname)); + new.userlevel = PERM_DEFAULT; + new.ufo = UFO_DEFAULT_NEW; + new.numlogins = 1; + new.firstlogin = now; + new.lastlogin = now; + new.tcheck = now; + new.tvalid = now; + + slot.uptime = now; + strcpy(slot.userid, new.userid); + + fd = open(FN_SCHEMA, O_RDWR | O_CREAT, 0600); + new.userno = uniq_userno(fd); + write(fd, &slot, sizeof(slot)); + close(fd); + + usr_fpath(fpath, new.userid, NULL); + mkdir(fpath, 0700); + strcat(fpath, "/@"); + mkdir(fpath, 0700); + usr_fpath(fpath, new.userid, "MF"); + mkdir(fpath, 0700); + usr_fpath(fpath, new.userid, "gem"); /* itoc.010727: Ó¤HºëµØ°Ï */ + mak_links(fpath); + + usr_fpath(fpath, new.userid, ".ACCT"); + fd = open(fpath, O_WRONLY | O_CREAT, 0600); + write(fd, &new, sizeof(ACCT)); + close(fd); +} + + +/* ----------------------------------------------------- */ +/* Âഫñ¦WÀÉ¡BpµeÀÉ */ +/* ----------------------------------------------------- */ + + +static inline void +trans_sig(old) + userec *old; +{ + char buf[64], fpath[64], f_sig[20]; + + sprintf(buf, COLABBS_HOME "/%s/signatures", old->blank2); + if (dashf(buf)) + { + sprintf(f_sig, "%s.1", FN_SIGN); + usr_fpath(fpath, old->userid, f_sig); + f_cp(buf, fpath, O_TRUNC); + } +} + + +static inline void +trans_plans(old) + userec *old; +{ + char buf[64], fpath[64]; + + sprintf(buf, COLABBS_HOME "/%s/PLANS", old->blank2); + if (dashf(buf)) + { + usr_fpath(fpath, old->userid, FN_PLANS); + f_cp(buf, fpath, O_TRUNC); + } +} + + +/* ----------------------------------------------------- */ +/* Âà´««H¥ó */ +/* ----------------------------------------------------- */ + + +static time_t +trans_hdr_chrono(filename) + char *filename; +{ + char time_str[11]; + + /* M.1087654321.A ©Î M.987654321.A */ + str_ncpy(time_str, filename + 2, filename[2] == '1' ? 11 : 10); + + return (time_t) atoi(time_str); +} + + +static inline void +trans_mail(old) + userec *old; +{ + int fd; + char *ptr, index[64], folder[64], buf[64], fpath[64]; + fileheader fh; + HDR hdr; + time_t chrono; + + sprintf(index, COLABBS_HOME "/%s/mail/.DIR", old->blank2); + usr_fpath(folder, old->userid, FN_DIR); + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + sprintf(buf, COLABBS_HOME "/%s/mail/%s", old->blank2, fh.filename); + + if (dashf(buf)) /* ¤å³¹Àɮצb¤~°µÂà´« */ + { + char new_name[10] = "@"; + + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + new_name[1] = radix32[chrono & 31]; + archiv32(chrono, new_name + 1); + + hdr.chrono = chrono; + str_ncpy(hdr.xname, new_name, sizeof(hdr.xname)); + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + if (ptr = strchr(hdr.owner, ' ')) + *ptr = '\0'; + str_ncpy(hdr.title, fh.title + 3, sizeof(hdr.title)); + str_stamp(hdr.date, &hdr.chrono); + hdr.xmode = MAIL_READ; /* ³]¬°¤wŪ */ + + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + usr_fpath(fpath, old->userid, "@/"); + strcat(fpath, new_name); + f_cp(buf, fpath, O_TRUNC); + } + } + close(fd); + } +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transusr(user) + userec *user; +{ + char buf[64]; + + printf("Âà´« %s ¨Ï¥ÎªÌ\n", user->userid); + + if (is_bad_userid(user->userid)) + { + printf("%s ¤£¬O¦Xªk ID\n", user->userid); + return; + } + + usr_fpath(buf, user->userid, NULL); + if (dashd(buf)) + { + printf("%s ¤w¸g¦³¦¹ ID\n", user->userid); + return; + } + + creat_dirs(user); + trans_plans(user); + trans_sig(user); + trans_mail(user); +} + + +int +main() +{ + char *str, buf[64]; + struct dirent *de; + DIR *dirp; + userec user; + + chdir(BBSHOME); + + if (!(dirp = opendir(COLABBS_HOME))) + return -1; + + while (de = readdir(dirp)) + { + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + sprintf(buf, COLABBS_HOME "/%s/USERDATA.DAT", str); + rec_get(buf, &user, sizeof(user), 0); + strcpy(user.blank2, str); /* ɥ൬° path */ + + transusr(&user); + } + + closedir(dirp); + + return 0; +} diff --git a/util/tran/fb.h b/util/tran/fb.h new file mode 100644 index 0000000..12c5fab --- /dev/null +++ b/util/tran/fb.h @@ -0,0 +1,154 @@ +/*----------------------------------------------------------*/ +/* util/fb/fb.h */ +/*----------------------------------------------------------*/ +/* target : firebird 3.0 Âà Maple 3.x */ +/* create : 00/11/22 */ +/* update : / / */ +/* author : hightman@263.net */ +/*----------------------------------------------------------*/ + + +#if 0 + + 1. ³]©w OLD_BBSHOME¡BFN_PASSWD¡BFN_BOARD + 2. ×§ï©Ò¦³ªº old struct + + 3. ¥²¶·¦b brd Âà§¹¤~¥i¥HÂà´« gem + 4. ¥²¶·¦b usr ¤Î brd ³£Âà§¹¤~¥i¥HÂà´« pal + 5. «ØÄ³Âà´«¶¶§Ç¬° usr -> brd -> gem ->pal + +#endif + + +#include "bbs.h" + + +#define OLD_BBSHOME "/home/oldbbs" /* FB */ +#define FN_PASSWD "/home/oldbbs/.PASSWDS" /* FB */ +#define FN_BOARD "/home/oldbbs/.BOARDS" /* FB */ + +#define NOBOARD "1002" + + +/* ----------------------------------------------------- */ +/* ·sºX¼Ð/Åv¹ïÀ³ */ +/* ----------------------------------------------------- */ + +struct BITS +{ + int old; + int new; +}; +typedef struct BITS BITS; + + +#ifdef TRANS_BITS_BRD +static BITS flag[] = +{ + {0x2, BRD_NOZAP}, + {0x8, BRD_ANONYMOUS}, + {0x4, BRD_NOTRAN} +}; +#endif + + +#ifdef TRANS_BITS_PERM +static BITS perm[] = +{ + {0x00000001, PERM_BASIC}, /* BASIC */ + {0x00000002, PERM_CHAT}, /* CHAT */ + {0x00000004, PERM_PAGE}, /* PAGE */ + {0x00000008, PERM_POST}, /* POST */ + {0x00000010, PERM_VALID}, /* LOGIN */ + {0x00000020, PERM_DENYPOST}, /* DENYPOST */ + {0x00000040, PERM_CLOAK}, /* CLOAK */ + {0x00000080, PERM_SEECLOAK}, /* SEECLOAK */ + {0x00000100, PERM_XEMPT}, /* XEMPT */ + {0x00000400, PERM_BM}, /* BM */ + {0x00000800, PERM_ACCOUNTS}, /* ACCOUNTS */ + {0x00001000, PERM_CHATROOM}, /* CHATROOM */ + {0x00002000, PERM_BOARD}, /* BOARD */ + {0x00004000, PERM_SYSOP} /* SYSOP */ +}; +#endif + + +/* ----------------------------------------------------- */ +/* old .PASSWDS struct : 512 bytes */ +/* ----------------------------------------------------- */ + +struct userec +{ /* Structure used to hold information in */ + char userid[15]; + time_t firstlogin; + char lasthost[16]; + unsigned int numlogins; + unsigned int numposts; + char flags[2]; + char passwd[14]; /* Y¬O MD5¡An±N 14 §ï¦¨ 35 */ + char username[40]; + char ident[40]; + char termtype[16]; + char reginfo[80 - 16]; + unsigned int userlevel; + time_t lastlogin; + time_t stay; + char realname[40]; + char address[80]; + char email[80 - 12]; + unsigned int nummails; + time_t lastjustify; + char gender; + unsigned char birthyear; + unsigned char birthmonth; + unsigned char birthday; + int signature; + unsigned int userdefine; + time_t notedate; + int noteline; +}; +typedef struct userec userec; + + +/* ----------------------------------------------------- */ +/* old DIR of board struct : 256 bytes */ +/* ----------------------------------------------------- */ + +struct fileheader +{ /* This structure is used to hold data in */ + char filename[80]; /* the DIR files */ + char owner[80]; + char title[80]; + unsigned level; + unsigned char accessed[12]; /* struct size = 256 bytes */ +}; +typedef struct fileheader fileheader; + + +/* ----------------------------------------------------- */ +/* old BOARDS struct : 276 bytes */ +/* ----------------------------------------------------- */ + +struct boardheader +{ /* This structure is used to hold data i n */ + char filename[80]; /* the BOARDS files */ + char owner[80 - 60]; + char BM[80 - 1]; + char flag; + char title[80]; + unsigned level; + unsigned char accessed[12]; +}; +typedef struct boardheader boardheader; + + +/* ----------------------------------------------------- */ +/* old FRIEND struct : 128 bytes */ +/* ----------------------------------------------------- */ + +struct FRIEND +{ + char id[13]; + char exp[40]; +}; +typedef struct FRIEND FRIEND; diff --git a/util/tran/fb2brd.c b/util/tran/fb2brd.c new file mode 100644 index 0000000..8c8d66e --- /dev/null +++ b/util/tran/fb2brd.c @@ -0,0 +1,234 @@ +/*-------------------------------------------------------*/ +/* util/fb/fb2brd.c */ +/*-------------------------------------------------------*/ +/* target : firebird 3.0 Âà Maple 3.x ¬ÝªO */ +/* .BOARDS => .BRD */ +/* create : 00/11/22 */ +/* update : / / */ +/* author : hightman@263.net */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#define TRANS_BITS_BRD +#define TRANS_BITS_PERM + + +#include "fb.h" + + +static inline void +trans_hdr_stamp(folder, t, hdr, fpath) + char *folder; + time_t t; + HDR *hdr; + char *fpath; +{ + FILE *fp; + char *fname, *family; + int rc; + + fname = fpath; + while (rc = *folder++) + { + *fname++ = rc; + if (rc == '/') + family = fname; + } + fname = family + 1; + *fname++ = '/'; + *fname++ = 'A'; + + for (;;) + { + *family = radix32[t & 31]; + archiv32(t, fname); + + if (fp = fopen(fpath, "r")) + { + fclose(fp); + t++; + } + else + { + memset(hdr, 0, sizeof(HDR)); + hdr->chrono = t; + str_stamp(hdr->date, &hdr->chrono); + strcpy(hdr->xname, --fname); + break; + } + } +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transbrd(bh) + boardheader *bh; +{ + static time_t stamp = 0; + + int fd; + char *ptr, index[64], folder[64], buf[64], fpath[64]; + fileheader fh; + HDR hdr; + BRD newboard; + BITS *p; + time_t chrono; + + printf("Âà´« %s ¬ÝªO\n", bh->filename); + + brd_fpath(buf, bh->filename, NULL); + if (dashd(buf)) + { + printf("%s ¤w¸g¦³¦¹¬ÝªO\n", bh->filename); + return; + } + + if (!stamp) + time(&stamp); + + /* Âà´« .BRD */ + + memset(&newboard, 0, sizeof(BRD)); + str_ncpy(newboard.brdname, bh->filename, sizeof(newboard.brdname)); + str_ncpy(newboard.class, (bh->flag |= 0x4) ? "¡ô¡õ" : "¡÷¡ö", sizeof(newboard.class)); + str_ncpy(newboard.title, bh->title + 10, sizeof(newboard.title)); + newboard.bstamp = stamp++; + if (bh->BM[0] > ' ') + { + /* ±N©Ò¦³ªº ',' ´«¦¨ '/' */ + for (ptr = bh->BM; *ptr; ptr++) + { + if (*ptr == ',') + *ptr = '/'; + } + str_ncpy(newboard.BM, bh->BM, sizeof(newboard.BM)); + } + for (p = flag; p->old; p++) + { + if (bh->flag & p->old) + newboard.battr |= p->new; + } + for (p = perm; p->old; p++) + { + if (bh->level & p->old) + newboard.readlevel |= p->new; + } + newboard.postlevel = newboard.readlevel; + rec_add(FN_BRD, &newboard, sizeof(BRD)); + + /* ¶}·s¥Ø¿ý */ + + sprintf(fpath, "gem/brd/%s", newboard.brdname); + mak_dirs(fpath); + mak_dirs(fpath + 4); + + /* Âà´«¶iªOµe± */ + + sprintf(buf, OLD_BBSHOME "/boards/%s/notes", bh->filename); + + if (dashf(buf)) + { + brd_fpath(fpath, newboard.brdname, FN_NOTE); + f_cp(buf, fpath, O_TRUNC); + } + + /* Âà´«§ë²¼µ²ªG */ + + sprintf(buf, OLD_BBSHOME "/boards/%s/results", bh->filename); + + if (dashf(buf)) + { + brd_fpath(fpath, newboard.brdname, "@/@vote"); + f_cp(buf, fpath, O_TRUNC); + } + + /* Âà´«¤å³¹ */ + + sprintf(index, OLD_BBSHOME "/boards/%s/.DIR", bh->filename); /* ªº .DIR */ + brd_fpath(folder, newboard.brdname, ".DIR"); /* ·sªº .DIR */ + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + sprintf(buf, OLD_BBSHOME "/boards/%s/%s", bh->filename, fh.filename); + if (dashf(buf)) /* ¤å³¹Àɮצb¤~°µÂà´« */ + { + struct stat st; + + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + stat(buf, &st); + chrono = st.st_mtime; + trans_hdr_stamp(folder, chrono, &hdr, fpath); + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ansi(hdr.title, fh.title, sizeof(hdr.title)); + hdr.xmode = 0; + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + f_cp(buf, fpath, O_TRUNC); + } + } + close(fd); + } + + +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int fd; + boardheader bh; + + /* argc == 1 Âà¥þ³¡ªO */ + /* argc == 2 Âà¬Y¯S©wªO */ + + if (argc > 2) + { + printf("Usage: %s [target_board]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (!dashf(FN_BOARD)) + { + printf("ERROR! Can't open " FN_BOARD "\n"); + exit(-1); + } + if (!dashd(OLD_BBSHOME "/boards")) + { + printf("ERROR! Can't open " OLD_BBSHOME "/boards\n"); + exit(-1); + } + + if ((fd = open(FN_BOARD, O_RDONLY)) >= 0) + { + while (read(fd, &bh, sizeof(bh)) == sizeof(bh)) + { + if (argc == 1) + { + transbrd(&bh); + } + else if (!strcmp(bh.filename, argv[1])) + { + transbrd(&bh); + exit(1); + } + } + close(fd); + } + + exit(0); +} diff --git a/util/tran/fb2gem.c b/util/tran/fb2gem.c new file mode 100644 index 0000000..f4488b9 --- /dev/null +++ b/util/tran/fb2gem.c @@ -0,0 +1,381 @@ +/*-------------------------------------------------------*/ +/* util/fb/fb2gem.c */ +/*-------------------------------------------------------*/ +/* target : firebird 3.0 Âà Maple 3.x ºëµØ°Ï */ +/* 0Announce => gem/@Class */ +/* create : 00/11/22 */ +/* update : / / */ +/* author : hightman@263.net */ +/*----------------------------------------------------------*/ + + +#include "fb.h" + + +static int ndir; +static int nfile; +static time_t chrono; +static int level; +static char gpath[1024]; +static char tmp_name[128]; + +static int mandex(char *board, char *fpath, int deep); +static void Names_class(char *fpath); + +static char *fn_names = ".Names"; + + +/* ------------------------------------------------------------- */ +/* «Ø¥ß gem/.DIR ¤Î gem/@/@Class */ +/* ------------------------------------------------------------- */ + + +static void +new_class() +{ + HDR hdr; + + memset(&hdr, 0, sizeof(HDR)); + time(&hdr.chrono); + strcpy(hdr.owner, STR_SYSOP); + strcpy(hdr.nick, SYSOPNICK); + str_stamp(hdr.date, &hdr.chrono); + strcpy(hdr.xname, "@Class"); + strcpy(hdr.title, "Class/ ¬ÝªOºëµØ°Ï"); + hdr.xmode = GEM_FOLDER; + rec_add("gem/.DIR", &hdr, sizeof(HDR)); +} + + +/* ------------------------------------------------------------- */ +/* Tran_Group */ +/* ------------------------------------------------------------- */ + + +static void +tran_group(title, fname, flag) + char *title; + char *fname; + int flag; +{ + HDR hdr; + char buf[1024]; + + memset(&hdr, 0, sizeof(HDR)); + time(&hdr.chrono); + strcpy(hdr.owner, STR_SYSOP); + strcpy(hdr.nick, SYSOPNICK); + str_stamp(hdr.date, &hdr.chrono); + + if (flag == 1) /* ¨÷©v */ + { + strcpy(tmp_name, fname); + + sprintf(hdr.xname, "@%s", fname); + str_ncpy(hdr.title, title, sizeof(hdr.title)); + hdr.xmode = GEM_FOLDER; + rec_add("gem/@/@Class", &hdr, sizeof(HDR)); + + sprintf(buf, "%s/0Announce/groups/%s/%s", OLD_BBSHOME, fname, fn_names); + Names_class(buf); + } + else if (flag == 2) /* ¬ÝªO */ + { + strcpy(hdr.xname, fname); + str_ncpy(hdr.title, title, sizeof(hdr.title)); + hdr.xmode = GEM_BOARD | GEM_FOLDER; + + sprintf(buf, "gem/@/@%s", tmp_name); + rec_add(buf, &hdr, sizeof(HDR)); + + sprintf(buf, "%s/0Announce/groups/%s/%s/%s", OLD_BBSHOME, tmp_name, fname, fn_names); + mandex(fname, buf, 0); + } +} + + +/* ------------------------------------------------------------- */ +/* Names Path ... */ +/* ------------------------------------------------------------- */ + + +static void +Names_class(fpath) + char *fpath; +{ + FILE *fp; + char *ptr, buf[256]; + char title[TTLEN + 1], fname[32]; + int flag; + + if (fp = fopen(fpath, "r")) + { + while (fgets(buf, sizeof(buf), fp)) + { + if (ptr = strchr(buf, '\n')) + *ptr = '\0'; + + if (!memcmp(buf, "Name=", 5)) + { + str_ncpy(title, buf + 5, sizeof(title)); + } + else if (!memcmp(buf, "Path=", 5)) + { + ptr = buf + 7; + if (!memcmp(ptr, "../", 3) || (*ptr == '/') || !strcmp(ptr, ".index") || (*ptr == '\0')) + continue; + + str_ncpy(fname, ptr, sizeof(fname)); + if (strstr(fname, "GROUP")) + flag = 1; + else + flag = 2; + + tran_group(title, fname, flag); + } + } + + fclose(fp); + } +} + + +/* ------------------------------------------------------------- */ +/* Group */ +/* ------------------------------------------------------------- */ + + +static void +group_class() +{ + char fpath[1024]; + + sprintf(fpath, "%s/0Announce/groups/%s", OLD_BBSHOME, fn_names); + Names_class(fpath); +} + + +/* ------------------------------------------------------------- */ +/* 0Announce */ +/* ------------------------------------------------------------- */ + + +static int +mandex(board, fpath, deep) + char *board; + char *fpath; + int deep; +{ + FILE *fgem, *fxx; + char *fname, *gname, *ptr, *str, buf[256], site[64]; + struct stat st; + int cc, xmode, gport; + HDR ghdr; + + if (board) + { + level = 0; + if (strcmp(board, NOBOARD)) + { + sprintf(gpath, "gem/brd/%s", board); + mkdir(gpath, 0700); + } + cc = '0'; + for (;;) + { + if (!strcmp(board, NOBOARD)) + sprintf(gpath, "gem/%c", cc); + else + sprintf(gpath, "gem/brd/%s/%c", board, cc); + mkdir(gpath, 0700); + if (cc == '9') + cc = '@'; + else + { + if (++cc == 'W') + break; + } + } + if (!strcmp(board, NOBOARD)) + sprintf(gpath, "gem/.DIR"); + else + sprintf(gpath, "gem/brd/%s/.DIR", board); + ndir = nfile = 0; + chrono = 10000; + } + + if (!(gname = strrchr(gpath, '/'))) + return -1; + if (gname[1] == '.') + gname++; + else + gname--; + + if (!(fxx = fopen(gpath, "a"))) + return -1; + + if (!(fgem = fopen(fpath, "r"))) + { + fclose(fxx); + return -1; + } + + if (deep > level) + level = deep; + + gport = -1; + fname = strrchr(fpath, '.'); + + while (fgets(buf, sizeof(buf), fgem)) + { + if (gport < 0) + { + *fname = xmode = gport = 0; + memset(&ghdr, 0, sizeof(HDR)); + } + ptr = buf + 5; + if (str = strchr(buf, '\n')) + *str = '\0'; + if (!memcmp(buf, "Name=", 5)) + { + if (!memcmp(ptr, "¡ó ", 3) || !memcmp(ptr, "¡ô ", 3) || !memcmp(ptr, "¡ñ", 3) || + !memcmp(ptr, "¡ð ", 3) || !memcmp(ptr, "¡Ñ ", 3)) + { + ptr += 3; + } + else if (!memcmp(ptr, "¡õ ", 3) || !memcmp(ptr, "¡ö ", 3)) + { + ptr += 3; + gport = 70; + } + if (*ptr == '#') + { + if (*++ptr == ' ') + ptr++; + xmode = GEM_RESTRICT; + } + str_ncpy(ghdr.title, ptr, sizeof(ghdr.title)); + } + else if (!memcmp(buf, "Edit=", 5)) /* server */ + { + if (gport) + { + str = site; + do + { + cc = *ptr++; + if (cc >= 'A' && cc <= 'Z') + cc |= 0x20; + *str++ = cc; + } while (cc); + } + else + { + str_ncpy(ghdr.owner, ptr, sizeof(ghdr.owner)); + } + } + else if (!memcmp(buf, "Date=", 5)) /* port */ + { + if (gport) + gport = atoi(ptr); + else if (ptr[2] != '/' || ptr[5] != '/') + str_ncpy(ghdr.date, ptr, sizeof(ghdr.date)); + } + else if (!memcmp(buf, "Path=", 5)) + { + ptr += 2; + if (!memcmp(ptr, "../", 3) || (*ptr == '/') || !strcmp(ptr, ".index")) + { + printf("\tskip: %s, %s\n", fpath, ptr); + gport = -1; + continue; + } + if (!memcmp(ptr, "groups", 6) && deep == 0) + { + printf("GROUPS! wait...\n"); + group_class(); + gport = -1; + continue; + } + ghdr.chrono = ++chrono; + + if (gport) /* Gopher ´N·í¦¨¤@¯ë¤å³¹©Î¨÷©v */ + { + xmode = 0; + if (*ptr == '1') + xmode |= GEM_FOLDER; + sprintf(ghdr.xname, "%s/%s", site, ptr); + } + else + { + strcpy(fname, ptr); + if (stat(fpath, &st)) + { + gport = -1; + continue; + } + archiv32(chrono, gname + 3); + *gname = gname[9]; + gname[1] = '/'; + str = ghdr.date; + if (!*str) + { + struct tm *p = localtime(&st.st_mtime); + sprintf(str, "%02d/%02d/%02d", p->tm_year % 100, p->tm_mon + 1, p->tm_mday); + } + if (S_ISREG(st.st_mode))/* file */ + { + gname[2] = 'A'; + strcpy(ghdr.xname, gname + 2); + link(fpath, gpath); + nfile++; + } + else if (S_ISDIR(st.st_mode)) /* dir */ + { + gname[2] = 'F'; + strcpy(ghdr.xname, gname + 2); + strcat(fpath, "/"); + strcat(fpath, fn_names); + if (mandex(NULL, fpath, deep + 1)) + { + gport = -1; + continue; + } + xmode |= GEM_FOLDER; + ndir++; + } + else + { + gport = -1; + continue; + } + } + ghdr.xmode = xmode; + fwrite(&ghdr, sizeof(HDR), 1, fxx); + gport = -1; + } + } + fclose(fxx); + fclose(fgem); + + if (board) /* report */ + printf("\td:%d\tf:%d\t(%d)\n", ndir, nfile, level); + + return 0; +} + + +int +main() +{ + char fpath[1024]; + + chdir(BBSHOME); + + new_class(); + + sprintf(fpath, "%s/0Announce/%s", OLD_BBSHOME, fn_names); + mandex(NOBOARD, fpath, 0); + + return 0; +} diff --git a/util/tran/fb2pal.c b/util/tran/fb2pal.c new file mode 100644 index 0000000..3aae6c7 --- /dev/null +++ b/util/tran/fb2pal.c @@ -0,0 +1,177 @@ +/*-------------------------------------------------------*/ +/* util/transpal.c */ +/*-------------------------------------------------------*/ +/* target : WD ¦Ü Maple 3.02 (¬ÝªO)¦n¤Í¦W³æÂà´« */ +/* create : 01/09/08 */ +/* update : / / */ +/* author : itoc.bbs@bbs.ee.nctu.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transpal */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ×§ï struct FRIEND ©M transpal() transbrdpal() + 2. Âà´«(¬ÝªO)¦n¤Í¦W³æ¤§«e¡A±z¥²¶·¥ýÂà´«§¹¬ÝªO¤Î¨Ï¥ÎªÌ¡C + + ps. ¨Ï¥Î«e½Ð¥ý¦æ³Æ¥÷¡Ause on ur own risk. µ{¦¡©å¦H½Ð¥]²[ :p + ps. ·PÁ lkchu ªº Maple 3.02 for FreeBSD + +#endif + + +#include "fb.h" + + +static char uperid[80]; /* ¤j¼gªº ID */ + +static void /* ´«¤j¼g */ +str_uper(dst, src) + char *dst, *src; +{ + int ch; + do + { + ch = *src++; + if (ch >= 'a' && ch <= 'z') + ch = ch - 32; + *dst++ = ch; + } while (ch); +} + + +/* ----------------------------------------------------- */ +/* 3.02 functions */ +/* ----------------------------------------------------- */ + + +static int +acct_uno(userid) + char *userid; +{ + int fd; + int userno; + char fpath[64]; + + usr_fpath(fpath, userid, FN_ACCT); + fd = open(fpath, O_RDONLY); + if (fd >= 0) + { + read(fd, &userno, sizeof(userno)); + close(fd); + return userno; + } + return -1; +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transpal(userid) + char *userid; +{ + ACCT acct; + int fd, friend_userno, i; + char fpath[64], buf[64]; + PAL pal; + FRIEND friend; + + /* FireBird ¬O¥Î¤j¼g id */ + str_uper(uperid, userid); + + /* FB ªº usr ¥Ø¿ý¦³¤À¤j¤p¼g¡A©Ò¥Hn¥ý¨ú±o¤j¤p¼g */ + usr_fpath(buf, userid, FN_ACCT); + if ((fd = open(buf, O_RDONLY)) >= 0) + { + read(fd, &acct, sizeof(ACCT)); + close(fd); + } + else + { + return; + } + + usr_fpath(fpath, userid, FN_PAL); /* ·sªº¦n¤Í¦W³æ */ + + if (dashf(fpath)) + unlink(fpath); /* ²M±¼««Ø */ + + for (i = 0; i <= 1; i++) /* ¦n¤Í¦W³æ/Ãa¤H¦W³æ ¤G¥÷ */ + { + sprintf(buf, OLD_BBSHOME "/home/%c/%s/%s", *uperid, acct.userid, i ? "friends" : "rejects"); /* ªº¦n¤Í¦W³æ */ + + if ((fd = open(buf, O_RDONLY)) < 0) + return; + + while (read(fd, &friend, sizeof(FRIEND)) == sizeof(FRIEND)) + { + if ((friend_userno = acct_uno(friend.id)) >= 0 && + strcmp(friend.id, acct.userid)) + { + memset(&pal, 0, sizeof(PAL)); + str_ncpy(pal.userid, friend.id, sizeof(pal.userid)); + pal.ftype = i ? 0 : PAL_BAD; /* ¦n¤Í vs ·l¤Í */ + str_ncpy(pal.ship, friend.exp, sizeof(pal.ship)); + pal.userno = friend_userno; + rec_add(fpath, &pal, sizeof(PAL)); + } + } + close(fd); + } +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + char c, *str; + char buf[64]; + struct dirent *de; + DIR *dirp; + + /* argc == 1 Âà¥þ³¡¨Ï¥ÎªÌ¤Î¬ÝªO */ + /* argc == 2 Âà¬Y¯S©w¨Ï¥ÎªÌ */ + + if (argc > 2) + { + printf("Usage: %s [target_user]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (argc == 2) + { + transpal(argv[1]); + exit(1); + } + + /* Âà´«¨Ï¥ÎªÌ¦n¤Í¦W³æ */ + for (c = 'a'; c <= 'z'; c++) + { + sprintf(buf, "usr/%c", c); + + if (!(dirp = opendir(buf))) + continue; + + while (de = readdir(dirp)) + { + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + transpal(str); + } + + closedir(dirp); + } + + return 0; +} diff --git a/util/tran/fb2usr.c b/util/tran/fb2usr.c new file mode 100644 index 0000000..41f8893 --- /dev/null +++ b/util/tran/fb2usr.c @@ -0,0 +1,328 @@ +/*-------------------------------------------------------*/ +/* util/fb/fb2usr.c */ +/*-------------------------------------------------------*/ +/* target : firebird 3.0 Âà Maple 3.x ¨Ï¥ÎªÌ¸ê®Æ */ +/* .PASSWDS => .USR .ACCT */ +/* create : 00/11/22 */ +/* update : / / */ +/* author : hightman@263.net */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#define TRANS_BITS_PERM + +#include "fb.h" + + +static char uperid[80]; /* ¤j¼gªº ID */ + + +/* ----------------------------------------------------- */ +/* Âà´« .ACCT */ +/* ----------------------------------------------------- */ + + +static inline int +is_bad_userid(userid) + char *userid; +{ + register char ch; + + if (strlen(userid) < 2) + return 1; + + if (!isalpha(*userid)) + return 1; + + if (!str_cmp(userid, "new")) + return 1; + + while (ch = *(++userid)) + { + if (!isalnum(ch)) + return 1; + } + return 0; +} + + +static inline int +uniq_userno(fd) + int fd; +{ + char buf[4096]; + int userno, size; + SCHEMA *sp; /* record length 16 ¥i¾ã°£ 4096 */ + + userno = 1; + + while ((size = read(fd, buf, sizeof(buf))) > 0) + { + sp = (SCHEMA *) buf; + do + { + if (sp->userid[0] == '\0') + { + lseek(fd, -size, SEEK_CUR); + return userno; + } + userno++; + size -= sizeof(SCHEMA); + sp++; + } while (size); + } + + return userno; +} + + +static void /* ´«¤j¼g */ +str_uper(dst, src) + char *dst, *src; +{ + int ch; + do + { + ch = *src++; + if (ch >= 'a' && ch <= 'z') + ch = ch - 32; + *dst++ = ch; + } while (ch); +} + + +static inline void +creat_dirs(old) + userec *old; +{ + ACCT new; + SCHEMA slot; + int fd; + char fpath[64]; + BITS *p; + + memset(&new, 0, sizeof(ACCT)); + memset(&slot, 0, sizeof(slot)); + + str_ncpy(new.userid, old->userid, sizeof(new.userid)); + str_ncpy(new.passwd, old->passwd, sizeof(new.passwd)); + str_ncpy(new.realname, old->realname, sizeof(new.realname)); + str_ncpy(new.username, old->username, sizeof(new.username)); + + for (p = perm; p->old; p++) + { + if (old->userlevel & p->old) + new.userlevel |= p->new; + } + new.ufo = UFO_DEFAULT_NEW; + new.signature = old->signature; + + new.year = old->birthyear; + new.month = old->birthmonth; + new.day = old->birthday; + new.sex = 1; + new.money = 0; + new.gold = 0; + + new.numlogins = old->numlogins; + new.numposts = old->numposts; + new.numemails = old->nummails; + + new.firstlogin = old->firstlogin; + new.lastlogin = old->lastlogin; + time(&new.tcheck); + time(&new.tvalid); + + str_ncpy(new.lasthost, old->lasthost, sizeof(new.lasthost)); + str_ncpy(new.email, old->email, sizeof(new.email)); + + slot.uptime = time(0); + strcpy(slot.userid, new.userid); + + fd = open(FN_SCHEMA, O_RDWR | O_CREAT, 0600); + new.userno = uniq_userno(fd); + write(fd, &slot, sizeof(slot)); + close(fd); + + usr_fpath(fpath, new.userid, NULL); + mkdir(fpath, 0700); + strcat(fpath, "/@"); + mkdir(fpath, 0700); + usr_fpath(fpath, new.userid, "MF"); + mkdir(fpath, 0700); + usr_fpath(fpath, new.userid, "gem"); /* itoc.010727: Ó¤HºëµØ°Ï */ + mak_links(fpath); + + usr_fpath(fpath, new.userid, ".ACCT"); + fd = open(fpath, O_WRONLY | O_CREAT, 0600); + write(fd, &new, sizeof(ACCT)); + close(fd); +} + + +/* ----------------------------------------------------- */ +/* Âà´««H¥ó */ +/* ----------------------------------------------------- */ + + +static inline void +trans_mail(old) + userec *old; +{ + int fd; + char index[64], folder[64], buf[64], fpath[64]; + fileheader fh; + HDR hdr; + time_t chrono; + + time(&chrono); + + sprintf(index, OLD_BBSHOME "/mail/%c/%s/.DIR", *uperid, old->userid); + usr_fpath(folder, old->userid, FN_DIR); + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + sprintf(buf, OLD_BBSHOME "/mail/%c/%s/%s", *uperid, old->userid, fh.filename); + + if (dashf(buf)) /* ¤å³¹Àɮצb¤~°µÂà´« */ + { + char new_name[10] = "@"; + + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono++; + new_name[1] = radix32[chrono & 31]; + archiv32(chrono, new_name + 1); + + hdr.chrono = chrono; + str_ncpy(hdr.xname, new_name, sizeof(hdr.xname)); + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ncpy(hdr.title, fh.title, sizeof(hdr.title)); + str_stamp(hdr.date, &chrono); + hdr.xmode = MAIL_READ; /* ³]¬°¤wŪ */ + + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + usr_fpath(fpath, old->userid, "@/"); + strcat(fpath, new_name); + f_cp(buf, fpath, O_TRUNC); + } + } + close(fd); + } + + +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transusr(user) + userec *user; +{ + char buf[64], fpath[64]; + + printf("Âà´« %s ¨Ï¥ÎªÌ\n", user->userid); + + if (is_bad_userid(user->userid)) + { + printf("%s ¤£¬O¦Xªk ID\n", user->userid); + return; + } + + usr_fpath(buf, user->userid, NULL); + if (dashd(buf)) + { + printf("%s ¤w¸g¦³¦¹ ID\n", user->userid); + return; + } + + /* FireBird ¬O¥Î¤j¼g id */ + str_uper(uperid, user->userid); + + sprintf(buf, OLD_BBSHOME "/home/%c/%s", *uperid, user->userid); + if (!dashd(buf)) + { + printf("%s ªºÀɮפ£¦s¦b\n", user->userid); + return; + } + + /* Âà´« .ACCT */ + creat_dirs(user); + + /* Âà´«pµeÀÉ/ñ¦WÀÉ */ + sprintf(buf, OLD_BBSHOME "/home/%c/%s/plans", *uperid, user->userid); + if (dashf(buf)) + { + usr_fpath(fpath, user->userid, FN_PLANS); + f_cp(buf, fpath, O_TRUNC); + } + sprintf(buf, OLD_BBSHOME "/home/%c/%s/signatures", *uperid, user->userid); + if (dashf(buf)) + { + usr_fpath(fpath, user->userid, FN_SIGN".1"); + f_cp(buf, fpath, O_TRUNC); + } + + /* Âà´««H¥ó */ + trans_mail(user); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int fd; + userec user; + + /* argc == 1 Âà¥þ³¡¨Ï¥ÎªÌ */ + /* argc == 2 Âà¬Y¯S©w¨Ï¥ÎªÌ */ + + if (argc > 2) + { + printf("Usage: %s [target_user]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (!dashf(FN_PASSWD)) + { + printf("ERROR! Can't open " FN_PASSWD "\n"); + exit(-1); + } + if (!dashd(OLD_BBSHOME "/home")) + { + printf("ERROR! Can't open " OLD_BBSHOME "/home\n"); + exit(-1); + } + + if ((fd = open(FN_PASSWD, O_RDONLY)) >= 0) + { + while (read(fd, &user, sizeof(user)) == sizeof(user)) + { + if (argc == 1) + { + transusr(&user); + } + else if (!strcmp(user.userid, argv[1])) + { + transusr(&user); + exit(1); + } + } + close(fd); + } + + exit(0); +} diff --git a/util/tran/mag.h b/util/tran/mag.h new file mode 100644 index 0000000..8c6f934 --- /dev/null +++ b/util/tran/mag.h @@ -0,0 +1,111 @@ +/*-------------------------------------------------------*/ +/* util/mag.h */ +/*-------------------------------------------------------*/ +/* target : Magic ¦Ü Maple 3.02 ¨Ï¥ÎªÌÂà´« */ +/* create : 02/01/03 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ³]©w FN_PASSWD¡BFN_BOARD¡BOLD_MAILPATH¡BOLD_BOARDPATH¡BOLD_MANPATH + 2. ×§ï©Ò¦³ªº old struct + + 3. §â ¯¸ªº mail ²¾¨ì OLD_MAILPATH + 4. §â ¯¸ªº boards/brdname ²¾¨ì OLD_BOARDPATH/brdname + 5. §â ¯¸ªº 0Announce/groups/ooxx.faq/brdname ²¾¨ì OLD_MANPATH/brdname + + 6. ¥²¶·¦b brd Âà§¹¤~¥i¥HÂà´« gem + 7. «ØÄ³Âà´«¶¶§Ç¬° usr -> brd -> gem + +#endif + + +#include "bbs.h" + + +#define FN_PASSWDS "/home/oldbbs/.PASSWDS" +#define FN_BOARDS "/home/oldbbs/.BOARDS" +#define OLD_MAILPATH "/home/oldbbs/mail" +#define OLD_BOARDPATH "/home/oldbbs/boards" +#define OLD_MANPATH "/home/oldbbs/groups" + + +/* ----------------------------------------------------- */ +/* old .PASSWDS struct : 512 bytes */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + char userid[14]; + time_t firstlogin; + char termtype[16]; + unsigned int numlogins; + unsigned int numposts; + char flags[2]; + char passwd[14]; + char username[40]; + char ident[40]; + char lasthost[40]; + char realemail[40]; + unsigned userlevel; + time_t lastlogin; + time_t stay; + char realname[40]; + char address[80]; + char email[80]; + int signature; + unsigned int userdefine; + int editor; + unsigned int showfile; + int magic; + int addmagic; + uschar bmonth; + uschar bday; + uschar byear; + uschar sex; + int money; + int bank; + int lent; + + int card; + uschar mind; + int unused1; + usint unsign_0000; + usint unsign_ffff; +} userec; + + +/* ----------------------------------------------------- */ +/* old DIR of board struct : 256 bytes */ +/* ----------------------------------------------------- */ + + +typedef struct /* the DIR files */ +{ + char filename[80]; + char owner[80]; + char title[80]; + unsigned level; + unsigned char accessed[12]; +} fileheader; + + +/* ----------------------------------------------------- */ +/* old BOARDS struct : 256 bytes */ +/* ----------------------------------------------------- */ + + +typedef struct /* the BOARDS files */ +{ + char filename[80]; + char owner[60]; + char BM[19]; + char flag; + char title[80]; + unsigned level; + unsigned char accessed[12]; +} boardheader; diff --git a/util/tran/mag2brd.c b/util/tran/mag2brd.c new file mode 100644 index 0000000..43004ef --- /dev/null +++ b/util/tran/mag2brd.c @@ -0,0 +1,239 @@ +/*-------------------------------------------------------*/ +/* util/transbrd.c */ +/*-------------------------------------------------------*/ +/* target : Magic ¦Ü Maple 3.02 ¬ÝªOÂà´« */ +/* .BOARDS => .BRD */ +/* create : 02/09/09 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + 0. ¾A¥Î Magic/FireBird Âà Maple ºëµØ°Ï + 1. µ{¦¡¤£¶}¥Ø¿ý¡A¨Ï¥Î«e¥ý½T©w gem/target_board/? ¥Ø¿ý¦s¦b + if not¡A¥ý¶}·sªO or transbrd + + ps. User on ur own risk. + +#endif + + +#include "mag.h" + + +/*-------------------------------------------------------*/ +/* basic function */ +/*-------------------------------------------------------*/ + + +static inline time_t +trans_hdr_chrono(filename) + char *filename; +{ + char time_str[11]; + + /* M.1087654321.A ©Î M.987654321.A */ + str_ncpy(time_str, filename + 2, filename[2] == '1' ? 11 : 10); + + return (time_t) atoi(time_str); +} + + +static inline void +trans_hdr_stamp(folder, t, hdr, fpath) + char *folder; + time_t t; + HDR *hdr; + char *fpath; +{ + FILE *fp; + char *fname, *family; + int rc; + + fname = fpath; + while (rc = *folder++) + { + *fname++ = rc; + if (rc == '/') + family = fname; + } + fname = family + 1; + *fname++ = '/'; + *fname++ = 'A'; + + for (;;) + { + *family = radix32[t & 31]; + archiv32(t, fname); + + if (fp = fopen(fpath, "r")) + { + fclose(fp); + t++; + } + else + { + memset(hdr, 0, sizeof(HDR)); + hdr->chrono = t; + str_stamp(hdr->date, &hdr->chrono); + strcpy(hdr->xname, --fname); + break; + } + } +} + + +static void +trans_owner(hdr, old) + HDR *hdr; + char *old; +{ + char *left, *right; + char owner[128]; + + str_ncpy(owner, old, sizeof(owner)); + + if (strchr(owner, '.')) /* innbbsd ==> bbs */ + { + /* ®æ¦¡: itoc.bbs@bbs.tnfsh.tn.edu.tw (§Úªº¼ÊºÙ) */ + + hdr->xmode = POST_INCOME; + + left = strchr(owner, '('); + right = strrchr(owner, ')'); + + if (!left || !right) + { + str_ncpy(hdr->owner, "§H¦W", sizeof(hdr->owner)); + } + else + { + *(left - 1) = '\0'; + str_ncpy(hdr->owner, owner, sizeof(hdr->owner)); + *right = '\0'; + str_ncpy(hdr->nick, left + 1, sizeof(hdr->nick)); + } + } + else if (left = strchr(owner, '(')) /* local post */ + { + /* ®æ¦¡: itoc (§Úªº¼ÊºÙ) */ + + *(left - 1) = '\0'; + str_ncpy(hdr->owner, owner, sizeof(hdr->owner)); + if (right = strchr(owner, ')')) + { + *right = '\0'; + str_ncpy(hdr->nick, left + 1, sizeof(hdr->nick)); + } + } + else + { + /* ®æ¦¡: itoc */ + + str_ncpy(hdr->owner, owner, sizeof(hdr->owner)); + } +} + + +/*-------------------------------------------------------*/ +/* Âà´«µ{¦¡ */ +/*-------------------------------------------------------*/ + + +static void +trans_brd(bh) + boardheader *bh; +{ + static time_t stamp = 0; + + int fd; + char *brdname, index[64], folder[64], buf[64], fpath[64]; + fileheader fh; + HDR hdr; + BRD brd; + time_t chrono; + + brdname = bh->filename; + if (strlen(brdname) > BNLEN) + { + printf("%s name is too long!\n", brdname); + return; + } + + if (!stamp) + time(&stamp); + + /* Âà´« .BRD */ + memset(&brd, 0, sizeof(BRD)); + str_ncpy(brd.brdname, brdname, sizeof(brd.brdname)); + str_ncpy(brd.class, bh->title + 2, sizeof(brd.class)); + str_ncpy(brd.title, bh->title + 13, sizeof(brd.title)); + /* str_ncpy(brd.BM, bh->BM, sizeof(brd.BM)); */ /* ¨S¦³ bh->BM? ¯¸ªø¤â°Ê§ï */ + brd.bstamp = stamp++; + brd.readlevel = 0; /* ¥ý¹w³] read/post level¡A¯¸ªø¦A¦Û¤v¤â°Ê§ï */ + brd.postlevel = PERM_POST; + brd.battr = BRD_NOTRAN; + rec_add(FN_BRD, &brd, sizeof(BRD)); + + /* «Ø¥Ø¿ý */ + sprintf(buf, "gem/brd/%s", brdname); + mak_dirs(buf); + mak_dirs(buf + 4); + + /* Âà´«¶iªOµe± */ + sprintf(index, "%s/%s/notes", OLD_BOARDPATH, brdname); + brd_fpath(folder, brdname, FN_NOTE); + f_cp(index, folder, O_TRUNC); + + /* Âà´«§ë²¼°O¿ý */ + sprintf(index, "%s/%s/results", OLD_BOARDPATH, brdname); + sprintf(folder, "brd/%s/@/@vote", brdname); + f_cp(index, folder, O_TRUNC); + + /* Âà´« .DIR */ + sprintf(index, "%s/%s/.DIR", OLD_BOARDPATH, brdname); /* ªº .DIR */ + brd_fpath(folder, brdname, FN_DIR); /* ·sªº .DIR */ + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + sprintf(buf, OLD_BOARDPATH "/%s/%s", brdname, fh.filename); + + chrono = trans_hdr_chrono(fh.filename); + trans_hdr_stamp(folder, chrono, &hdr, fpath); + trans_owner(&hdr, fh.owner); + str_ansi(hdr.title, fh.title, sizeof(hdr.title)); + if (fh.accessed[0] & 0x8) /* FILE_MARDKED */ + hdr.xmode |= POST_MARKED; + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + f_cp(buf, fpath, O_TRUNC); + } + close(fd); + } + + printf("%s transfer ok!\n", brdname); +} + + +int +main() +{ + int fd; + boardheader bh; + + chdir(BBSHOME); + + if ((fd = open(FN_BOARDS, O_RDONLY)) >= 0) + { + while (read(fd, &bh, sizeof(bh)) == sizeof(bh)) + trans_brd(&bh); + close(fd); + } + + return 0; +} diff --git a/util/tran/mag2gem.c b/util/tran/mag2gem.c new file mode 100644 index 0000000..04b692d --- /dev/null +++ b/util/tran/mag2gem.c @@ -0,0 +1,180 @@ +/*-------------------------------------------------------*/ +/* util/transman.c */ +/*-------------------------------------------------------*/ +/* target : Magic ¦Ü Maple 3.02 ºëµØ°ÏÂà´« */ +/* create : 01/10/03 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + 0. ¾A¥Î Magic/Napoleon Âà Maple ºëµØ°Ï + 1. µ{¦¡¤£¶}¥Ø¿ý¡A¨Ï¥Î«e¥ý½T©w gem/target_board/? ¥Ø¿ý¦s¦b + if not¡A¥ý¶}·sªO or transbrd + + ps. User on ur own risk. + +#endif + + +#include "mag.h" + + +/* ----------------------------------------------------- */ +/* basic functions */ +/* ----------------------------------------------------- */ + + +static void +merge_msg(msg) /* fget() ¦r¦ê³Ì«á¦³ '\n' n³B²z±¼ */ + char *msg; +{ + int end; + + end = 0; + while (end < 80) + { + if (msg[end] == '\n') + { + msg[end] = '\0'; + return; + } + + end++; + } + msg[end] = '\0'; /* ±j¨îÂ_¦b 80 ¦r */ +} + + +static int /* 'A':¤å³¹ 'F':¥Ø¿ý */ +get_record(src, src_folder, title, path, num) /* Ū¥X .Name */ + char *src; + char *src_folder; + char *title, *path; + int num; +{ + FILE *fp; + char Name[128], Path[128], buf[128]; + int i, j; + + if (fp = fopen(src_folder, "r")) + { + /* «e¤T¦æ¨S¥Î */ + j = num * 4 + 3; + for (i = 0; i < j; i++) + { + fgets(buf, 80, fp); + } + + /* ¨CÓ¯Á¤Þ¦³¥|¦æ */ + fgets(Name, 80, fp); + fgets(Path, 80, fp); + fgets(buf, 80, fp); + fgets(buf, 80, fp); + + fclose(fp); + + if (Name[0] != '#' && Path[0] != '#') + { + merge_msg(Name); + merge_msg(Path); + + strcpy(title, Name + 5); + strcpy(path, Path + 7); + + sprintf(buf, "%s/%s", src, path); + + if (dashf(buf)) + return 'A'; + else if (dashd(buf)) + return 'F'; + } + } + + return 0; +} + + +/* ----------------------------------------------------- */ +/* Âà´«µ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transman(brdname, src, dst_folder) + char *brdname; /* ¬ÝªOªO¦W */ + char *src; /* ¯¸ªº¥Ø¿ý */ + char *dst_folder; /* ·s¯¸ªº .DIR ©Î FXXXXXXX */ +{ + int num; + int type; + char src_folder[80]; /* ¯¸ªº .Names */ + char sub_src[80]; + char sub_dst_folder[80]; + char title[80], path[80]; + char cmd[256]; + HDR hdr; + + num = 0; + sprintf(src_folder, "%s/.Names", src); + + while ((type = get_record(src, src_folder, title, path, num))) + { + if (type == 'A') /* ¤å¥ó */ + { + close(hdr_stamp(dst_folder, 'A', &hdr, cmd)); + str_ncpy(hdr.title, title, sizeof(hdr.title)); + rec_add(dst_folder, &hdr, sizeof(HDR)); + + sprintf(cmd, "cp %s/%s gem/brd/%s/%c/%s", src, path, brdname, hdr.xname[7], hdr.xname); + system(cmd); + } + else if (type == 'F') /* ¥Ø¿ý */ + { + close(hdr_stamp(dst_folder, 'F', &hdr, cmd)); + hdr.xmode = GEM_FOLDER; + str_ncpy(hdr.title, title, sizeof(hdr.title)); + rec_add(dst_folder, &hdr, sizeof(HDR)); + + sprintf(sub_src, "%s/%s", src, path); + sprintf(sub_dst_folder, "gem/brd/%s/%c/%s", brdname, hdr.xname[7], hdr.xname); + transman(brdname, sub_src, sub_dst_folder); + } + num++; + } +} + + +int +main() +{ + int fd; + char src[64], dst_folder[64]; + BRD brd; + + chdir(BBSHOME); + + if ((fd = open(FN_BRD, O_RDONLY)) >= 0) + { + while (read(fd, &brd, sizeof(BRD)) == sizeof(BRD)) + { + sprintf(src, OLD_MANPATH "/%s", brd.brdname); + + if (dashd(src)) + { + sprintf(dst_folder, "gem/brd/%s", brd.brdname); + + if (dashd(dst_folder)) + { + sprintf(dst_folder, "gem/brd/%s/.DIR", brd.brdname); + transman(brd.brdname, src, dst_folder); /* ·s¯¸³£n¦³³oӬݪO¤~Âà */ + } + } + } + close(fd); + } + + exit(0); +} diff --git a/util/tran/mag2usr.c b/util/tran/mag2usr.c new file mode 100644 index 0000000..10b729c --- /dev/null +++ b/util/tran/mag2usr.c @@ -0,0 +1,259 @@ +/*-------------------------------------------------------*/ +/* util/transusr.c */ +/*-------------------------------------------------------*/ +/* target : Magic ¦Ü Maple 3.02 ¨Ï¥ÎªÌÂà´« */ +/* create : 02/09/09 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + 0. ¾A¥Î Magic Âà .ACCT ¤Î«H½c + + ps. User on ur own risk. + +#endif + + +#include "mag.h" + + +/*-------------------------------------------------------*/ +/* Âà´«.ACCT */ +/*-------------------------------------------------------*/ + + +static void +trans_acct() +{ + int fd, count; + char *userid, buf[64]; + userec old; + ACCT new; + SCHEMA slot; + + count = 1; /* userno ±q 1 °_ºâ */ + + if ((fd = open(FN_PASSWDS, O_RDONLY)) >= 0) + { + while (read(fd, &old, sizeof(old)) == sizeof(old)) + { + if (!isalpha(old.userid[0])) + continue; + + new.userno = count; + count++; + + str_ncpy(new.userid, old.userid, sizeof(new.userid)); + str_ncpy(new.passwd, old.passwd, sizeof(new.passwd)); + str_ncpy(new.realname, old.realname, sizeof(new.realname)); + str_ncpy(new.username, old.username, sizeof(new.username)); + + new.userlevel = PERM_BASIC | PERM_CHAT | PERM_PAGE | PERM_POST | PERM_VALID; + new.ufo = UFO_DEFAULT_NEW; + + new.signature = 0; + new.year = old.byear; + new.month = old.bmonth; + new.day = old.bday; + new.sex = 0; + + new.money = old.money; + new.gold = 0; + + new.numlogins = old.numlogins; + new.numposts = old.numposts; + new.numemails = 0; + + new.firstlogin = old.firstlogin; + new.lastlogin = old.lastlogin; + new.tcheck = time(&new.tvalid); + + str_ncpy(new.lasthost, old.lasthost, sizeof(new.lasthost)); + str_ncpy(new.email, old.email, sizeof(new.email)); + + userid = new.userid; + usr_fpath(buf, userid, NULL); + mkdir(buf, 0700); + strcat(buf, "/@"); + mkdir(buf, 0700); + usr_fpath(buf, userid, "gem"); /* itoc.010727: Ó¤HºëµØ°Ï */ + mak_links(buf); /* itoc.010924: ´î¤ÖÓ¤HºëµØ°Ï¥Ø¿ý */ +#ifdef MY_FAVORITE + usr_fpath(buf, userid, "MF"); + mkdir(buf, 0700); +#endif + + usr_fpath(buf, userid, FN_ACCT); + rec_add(buf, &new, sizeof(ACCT)); + + memset(&slot, 0, sizeof(SCHEMA)); + slot.uptime = count; + memcpy(slot.userid, new.userid, IDLEN); + rec_add(FN_SCHEMA, &slot, sizeof(SCHEMA)); + } + close(fd); + } +} + + +/*-------------------------------------------------------*/ +/* Âà´««H½c */ +/*-------------------------------------------------------*/ + + +static time_t +trans_hdr_chrono(filename) + char *filename; +{ + char time_str[11]; + + /* M.1087654321.A ©Î M.987654321.A */ + str_ncpy(time_str, filename + 2, filename[2] == '1' ? 11 : 10); + + return (time_t) atoi(time_str); +} + + +static void +trans_owner(hdr, old) + HDR *hdr; + char *old; +{ + char *left, *right; + char owner[128]; + + str_ncpy(owner, old, sizeof(owner)); + + if (strchr(owner, '.')) /* innbbsd ==> bbs */ + { + /* ®æ¦¡: itoc.bbs@bbs.tnfsh.tn.edu.tw (§Úªº¼ÊºÙ) */ + + left = strchr(owner, '('); + right = strrchr(owner, ')'); + + if (!left || !right) + { + str_ncpy(hdr->owner, "§H¦W", sizeof(hdr->owner)); + } + else + { + *(left - 1) = '\0'; + str_ncpy(hdr->owner, owner, sizeof(hdr->owner)); + *right = '\0'; + str_ncpy(hdr->nick, left + 1, sizeof(hdr->nick)); + } + } + else if (left = strchr(owner, '(')) /* local post */ + { + /* ®æ¦¡: itoc (§Úªº¼ÊºÙ) */ + + *(left - 1) = '\0'; + str_ncpy(hdr->owner, owner, sizeof(hdr->owner)); + if (right = strchr(owner, ')')) + { + *right = '\0'; + str_ncpy(hdr->nick, left + 1, sizeof(hdr->nick)); + } + } + else + { + /* ®æ¦¡: itoc */ + + str_ncpy(hdr->owner, owner, sizeof(hdr->owner)); + } +} + + +static void +trans_mail(userid) + char *userid; +{ + int fd; + char ch, index[64], folder[64], buf[64], fpath[64]; + fileheader fh; + HDR hdr; + time_t chrono; + + ch = userid[0]; + if (ch >= 'a' && ch <= 'z') /* ´«¤j¼g */ + ch -= 32; + + sprintf(index, "%s/%c/%s/.DIR", OLD_MAILPATH, ch, userid); /* ªº header */ + usr_fpath(folder, userid, FN_DIR); /* ·sªº header */ + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + sprintf(buf, "%s/%c/%s/%s", OLD_MAILPATH, ch, userid, fh.filename); + + if (dashf(buf)) /* ¤å³¹Àɮצb¤~°µÂà´« */ + { + char new_name[10] = "@"; + + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + new_name[1] = radix32[chrono & 31]; + archiv32(chrono, new_name + 1); + + hdr.chrono = chrono; + str_ncpy(hdr.xname, new_name, sizeof(hdr.xname)); + trans_owner(&hdr, fh.owner); + str_ncpy(hdr.title, fh.title, sizeof(hdr.title)); + str_stamp(hdr.date, &hdr.chrono); + hdr.xmode = MAIL_READ; + if (fh.accessed[0] & 0x8) /* FILE_MARDKED */ + hdr.xmode |= POST_MARKED; + + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + usr_fpath(fpath, userid, "@/"); + strcat(fpath, new_name); + f_cp(buf, fpath, O_TRUNC); + } + } + close(fd); + } +} + + +int +main() +{ + char c, *userid; + char buf[64]; + struct dirent *de; + DIR *dirp; + + chdir(BBSHOME); + + /* ¥ýÂà .ACCT¡A«Ø¥Ø¿ý */ + trans_acct(); + + /* ¥Ñ¦³®Äªº¨Ï¥ÎªÌ ID ¨ÓÂà´««H½c */ + for (c = 'a'; c <= 'z'; c++) + { + sprintf(buf, "usr/%c", c); + + if (!(dirp = opendir(buf))) + continue; + + while (de = readdir(dirp)) + { + userid = de->d_name; + if (*userid <= ' ' || *userid == '.') + continue; + + trans_mail(userid); + } + + closedir(dirp); + } + + return 0; +} diff --git a/util/tran/snap.h b/util/tran/snap.h new file mode 100644 index 0000000..3be2bcc --- /dev/null +++ b/util/tran/snap.h @@ -0,0 +1,110 @@ +/*-------------------------------------------------------*/ +/* util/snap.h */ +/*-------------------------------------------------------*/ +/* target : Maple Âà´« */ +/* create : 98/12/15 */ +/* update : 02/04/29 */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + 0. «O¯dì¨Ó brd/ gem/ usr/ .USR¡A¨ä¾l´«¦¨·sª©ªº + + 1. §Q¥Î snap2brd Âà´« .BRD + + 2. §Q¥Î snap2usr Âà´« .ACCT + + 3. ±N·sª©ªº gem/@/ ¤Uªº³o¨ÇÀɮ׽ƻs¹L¨Ó + @apply @e-mail @goodbye @index @justify @newuser @opening.0 + @opening.1 @opening.2 @post @re-reg @tryout @welcome + + 4. ¤W BBS ¯¸¡A¦b (A)nnounce ¸Ì±¡A«Ø¥H¤U¤GÓ¨÷©vªº©Ò¦³¸ê®Æ + {¸ÜÃD} ¼öªù°Q½× + {±Æ¦æ} ²Îp¸ê®Æ + +#endif + + +#include "bbs.h" + +#define MAK_DIRS /* «Ø¥Ø¿ý MF/ ¤Î gem/ */ + + +/* ----------------------------------------------------- */ +/* (ªº) ¨Ï¥ÎªÌ±b¸¹ .ACCT struct */ +/* ----------------------------------------------------- */ + + +typedef struct /* n©Mª©µ{¦¡ struct ¤@¼Ë */ +{ + int userno; /* unique positive code */ + char userid[13]; + char passwd[14]; + uschar signature; + char realname[20]; + char username[24]; + usint userlevel; + int numlogins; + int numposts; + usint ufo; + time_t firstlogin; + time_t lastlogin; + time_t staytime; /* Á`¦@°±¯d®É¶¡ */ + time_t tcheck; /* time to check mbox/pal */ + char lasthost[32]; + int numemail; /* ±Hµo Inetrnet E-mail ¦¸¼Æ */ + time_t tvalid; /* ³q¹L»{ÃÒ¡B§ó§ï mail address ªº®É¶¡ */ + char email[60]; + char address[60]; + char justify[60]; /* FROM of replied justify mail */ + char vmail[60]; /* ³q¹L»{ÃÒ¤§ email */ + char ident[140 - 20]; + time_t vtime; /* validate time */ +} userec; + + +/* ----------------------------------------------------- */ +/* (ªº) ¨Ï¥ÎªÌ²ßºD ufo */ +/* ----------------------------------------------------- */ + +/* old UFO */ /* n©Mª©µ{¦¡ struct ¤@¼Ë */ + +#define HABIT_COLOR BFLAG(0) /* true if the ANSI color mode open */ +#define HABIT_MOVIE BFLAG(1) /* true if show movie */ +#define HABIT_BRDNEW BFLAG(2) /* ·s¤å³¹¼Ò¦¡ */ +#define HABIT_BNOTE BFLAG(3) /* Åã¥Ü¶iªOµe± */ +#define HABIT_VEDIT BFLAG(4) /* ²¤Æ½s¿è¾¹ */ +#define HABIT_PAGER BFLAG(5) /* Ãö³¬©I¥s¾¹ */ +#define HABIT_QUIET BFLAG(6) /* µ²Ãf¦b¤H¹Ò¡A¦ÓµL¨®°¨³Ù */ +#define HABIT_PAL BFLAG(7) /* true if show pals only */ +#define HABIT_ALOHA BFLAG(8) /* ¤W¯¸®É¥D°Ê³qª¾¦n¤Í */ +#define HABIT_MOTD BFLAG(9) /* ²¤Æ¶i¯¸µe± */ +#define HABIT_CLOAK BFLAG(19) /* true if cloak was ON */ +#define HABIT_ACL BFLAG(20) /* true if ACL was ON */ +#define HABIT_MPAGER BFLAG(10) /* lkchu.990428: ¹q¤l¶l¥ó¶Ç©I */ +#define HABIT_NWLOG BFLAG(11) /* lkchu.990510: ¤£¦s¹ï¸Ü¬ö¿ý */ +#define HABIT_NTLOG BFLAG(12) /* lkchu.990510: ¤£¦s²á¤Ñ¬ö¿ý */ + + +/* ----------------------------------------------------- */ +/* (ªº) BOARDS struct */ +/* ----------------------------------------------------- */ + +typedef struct +{ + char brdname[13]; /* board ID */ + char title[49]; + char BM[37]; /* BMs' uid, token '/' */ + + uschar bvote; /* ¦@¦³´X¶µ§ë²¼Á|¦æ¤¤ */ + + time_t bstamp; /* «Ø¥ß¬ÝªOªº®É¶¡, unique */ + usint readlevel; /* ¾\ۤ峹ªºÅv */ + usint postlevel; /* µoªí¤å³¹ªºÅv */ + usint battr; /* ¬ÝªOÄÝ©Ê */ + time_t btime; /* .DIR ªº st_mtime */ + int bpost; /* ¦@¦³´X½g post */ + time_t blast; /* ³Ì«á¤@½g post ªº®É¶¡ */ +} boardheader; diff --git a/util/tran/snap2brd.c b/util/tran/snap2brd.c new file mode 100644 index 0000000..fd63dd2 --- /dev/null +++ b/util/tran/snap2brd.c @@ -0,0 +1,59 @@ +/*-------------------------------------------------------*/ +/* util/snap2brd.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : M3 BRD Âà´«µ{¦¡ */ +/* create : 03/07/09 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "snap.h" + + +#define FN_BRD_TMP ".BRD.tmp" + +int +main() +{ + boardheader bh; + BRD brd; + FILE *fp; + + chdir(BBSHOME); + + if (!(fp = fopen(FN_BRD, "r"))) + return -1; + + while (fread(&bh, sizeof(bh), 1, fp) == 1) + { + if (!*bh.brdname) /* ¦¹ªO¤w³Q§R°£ */ + continue; + + memset(&brd, 0, sizeof(BRD)); + + /* Âà´«ªº°Ê§@¦b¦¹ */ + str_ncpy(brd.brdname, bh.brdname, sizeof(brd.brdname)); + str_ncpy(brd.class, "¡H¡H", sizeof(brd.class)); /* ¤ÀÃþn«³] */ + str_ncpy(brd.title, bh.title + 3, sizeof(brd.title)); /* ¸õ¹L "¡¼ " */ + str_ncpy(brd.BM, bh.BM, sizeof(brd.BM)); + brd.bvote = bh.bvote ? 1 : 0; + brd.bstamp = bh.bstamp; + brd.readlevel = bh.readlevel; + brd.postlevel = bh.postlevel; + brd.battr = bh.battr; + brd.btime = 0; + brd.bpost = 0; + brd.blast = 0; + + rec_add(FN_BRD_TMP, &brd, sizeof(BRD)); + } + + fclose(fp); + + /* §R°£Âªº¡A§â·sªº§ó¦W */ + unlink(FN_BRD); + rename(FN_BRD_TMP, FN_BRD); + + return 0; +} diff --git a/util/tran/snap2usr.c b/util/tran/snap2usr.c new file mode 100644 index 0000000..14d76fb --- /dev/null +++ b/util/tran/snap2usr.c @@ -0,0 +1,174 @@ +/*-------------------------------------------------------*/ +/* util/snap2usr.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : M3 ACCT Âà´«µ{¦¡ */ +/* create : 98/12/15 */ +/* update : 02/04/29 */ +/* author : mat.bbs@fall.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : snap2usr [userid] */ +/*-------------------------------------------------------*/ + + +#include "snap.h" + + +static usint +transfer_ufo(oldufo) + usint oldufo; +{ + usint ufo; + + ufo = 0; + + if (oldufo & HABIT_MOVIE) + ufo |= UFO_MOVIE; + + if (oldufo & HABIT_BNOTE) + ufo |= UFO_BRDNOTE; + + if (oldufo & HABIT_VEDIT) + ufo |= UFO_VEDIT; + + if (oldufo & HABIT_MOTD) + ufo |= UFO_MOTD; + + if (oldufo & HABIT_PAGER) + ufo |= UFO_PAGER; + + if (oldufo & HABIT_QUIET) + ufo |= UFO_QUIET; + + if (oldufo & HABIT_PAL) + ufo |= UFO_PAL; + + if (oldufo & HABIT_ALOHA) + ufo |= UFO_ALOHA; + + if (oldufo & HABIT_NWLOG) + ufo |= UFO_NWLOG; + + if (oldufo & HABIT_NTLOG) + ufo |= UFO_NTLOG; + + if (oldufo & HABIT_CLOAK) + ufo |= UFO_CLOAK; + + if (oldufo & HABIT_ACL) + ufo |= UFO_ACL; + + return ufo; +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +trans_acct(old, new) + userec *old; + ACCT *new; +{ + memset(new, 0, sizeof(ACCT)); + + new->userno = old->userno; + + str_ncpy(new->userid, old->userid, sizeof(new->userid)); + str_ncpy(new->passwd, old->passwd, sizeof(new->passwd)); + str_ncpy(new->realname, old->realname, sizeof(new->realname)); + str_ncpy(new->username, old->username, sizeof(new->username)); + + new->userlevel = old->userlevel; + new->ufo = transfer_ufo(old->ufo); /* itoc.010917: ufo Äæ¦ì¥¼¥²¤@¼Ë */ + new->signature = old->signature; + + new->year = 0; /* µ¹ªì©lÈ */ + new->month = 0; + new->day = 0; + new->sex = 0; + new->money = 100; + new->gold = 1; + + new->numlogins = old->numlogins; + new->numposts = old->numposts; + new->numemails = old->numemail; + + new->firstlogin = old->firstlogin; + new->lastlogin = old->lastlogin; + new->tcheck = old->tcheck; + new->tvalid = old->tvalid; + + str_ncpy(new->lasthost, old->lasthost, sizeof(new->lasthost)); + str_ncpy(new->email, old->email, sizeof(new->email)); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + ACCT new; + char c; + + if (argc > 2) + { + printf("Usage: %s [userid]\n", argv[0]); + return -1; + } + + for (c = 'a'; c <= 'z'; c++) + { + char buf[64]; + struct dirent *de; + DIR *dirp; + + sprintf(buf, BBSHOME "/usr/%c", c); + chdir(buf); + + if (!(dirp = opendir("."))) + continue; + + while (de = readdir(dirp)) + { + userec old; + int fd; + char *str; + + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + if ((argc == 2) && str_cmp(str, argv[1])) + continue; + +#ifdef MAK_DIRS + sprintf(buf, "%s/MF", str); + mkdir(buf, 0700); + sprintf(buf, "%s/gem", str); + mak_links(buf); +#endif + + sprintf(buf, "%s/" FN_ACCT, str); + if ((fd = open(buf, O_RDONLY)) < 0) + continue; + + read(fd, &old, sizeof(userec)); + close(fd); + unlink(buf); /* itoc.010831: ¬å±¼ì¨Óªº FN_ACCT */ + + trans_acct(&old, &new); + + fd = open(buf, O_WRONLY | O_CREAT, 0600); /* itoc.010831: ««Ø·sªº FN_ACCT */ + write(fd, &new, sizeof(ACCT)); + close(fd); + } + + closedir(dirp); + } + + return 0; +} diff --git a/util/tran/sob.h b/util/tran/sob.h new file mode 100644 index 0000000..73efade --- /dev/null +++ b/util/tran/sob.h @@ -0,0 +1,96 @@ +/*-------------------------------------------------------*/ +/* util/sob.h */ +/*-------------------------------------------------------*/ +/* target : SOB ¦Ü Maple 3.02 Âà´« */ +/* create : 02/10/26 */ +/* author : ernie@micro8.ee.nthu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ³]©w OLD_BBSHOME¡BFN_PASSWD¡BFN_BOARD + 2. ×§ï©Ò¦³ªº old struct + + 3. ¥²¶·¦b brd Âà§¹¤~¥i¥HÂà´« gem + 4. ¥²¶·¦b usr ¤Î brd ³£Âà§¹¤~¥i¥HÂà´« pal + 5. «ØÄ³Âà´«¶¶§Ç¬° usr -> brd -> gem ->pal + +#endif + + +#include "bbs.h" + + +#define OLD_BBSHOME "/home/oldbbs" /* SOB */ +#define FN_PASSWD "/home/oldbbs/.PASSWDS" /* SOB */ +#define FN_BOARD "/home/oldbbs/.BOARDS" /* SOB */ + + +#undef HAVE_PERSONAL_GEM /* SOB ¬O¨S¦³Ó¤HºëµØ°Ïªº */ + + +/* ----------------------------------------------------- */ +/* old .PASSWDS struct : 256 bytes */ +/* ----------------------------------------------------- */ + +struct userec +{ + char userid[13]; + char realname[20]; + char username[24]; + char passwd[14]; + uschar uflag; + usint userlevel; + unsigned short numlogins; + unsigned short numposts; + time_t firstlogin; + time_t lastlogin; + char lasthost[16]; + char remoteuser[8]; + char email[50]; + char address[50]; + char justify[39]; + uschar month; + uschar day; + uschar year; + uschar sex; + uschar state; +}; +typedef struct userec userec; + + +/* ----------------------------------------------------- */ +/* old DIR of board struct : 128 bytes */ +/* ----------------------------------------------------- */ + +struct fileheader +{ + char filename[33]; /* M.9876543210.A */ + char savemode; /* file save mode */ + char owner[14]; /* uid[.] */ + char date[6]; /* [02/02] or space(5) */ + char title[73]; + uschar filemode; /* must be last field @ boards.c */ +}; +typedef struct fileheader fileheader; + + +/* ----------------------------------------------------- */ +/* old BOARDS struct : 128 bytes */ +/* ----------------------------------------------------- */ + +struct boardheader +{ + char brdname[13]; /* bid */ + char title[49]; + char BM[39]; /* BMs' uid, token '/' */ + char pad[11]; + time_t bupdate; /* note update time */ + char pad2[3]; + uschar bvote; /* Vote flags */ + time_t vtime; /* Vote close time */ + usint level; +}; +typedef struct boardheader boardheader; diff --git a/util/tran/sob2brd.c b/util/tran/sob2brd.c new file mode 100644 index 0000000..4f70b45 --- /dev/null +++ b/util/tran/sob2brd.c @@ -0,0 +1,228 @@ +/*-------------------------------------------------------*/ +/* util/transbrd.c */ +/*-------------------------------------------------------*/ +/* target : Maple Sob 2.36 ¦Ü Maple 3.02 ¬ÝªOÂà´« */ +/* .BOARDS => .BRD */ +/* create : / / */ +/* update : 98/06/14 */ +/* author : ernie@micro8.ee.nthu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transbrd [target_board] */ +/*-------------------------------------------------------*/ + +#if 0 + + 1. ×§ï struct boardheader ¤Î transbrd() + (boardheader ¨âª©©w¸qªº¦r¦êªø«×¤£¤@¡A½Ð¦Û¦æ´«¦¨¼Æ¦r) + 2. §ë²¼¤£Âà´« + 3. ¶iªOµe± copy + 4. ¦p¦³»Ýn½Ð chmod 644 `find PATH -perm 600` + 5. ¶} gem ¥Ø¿ý gem/target_board/? ¦ý¤£Âà´« gem + 6. ¤£·|§ó·s bshm¡A¨Ï¥Î«á½Ð¦Û¦æ§ó·s + 7. Âà´««á½Ð¤â°Ê³]¬ÝªOÅv + + ps. Use on ur own risk. + +#endif + + +#include "sob.h" + + +static time_t +trans_hdr_chrono(filename) + char *filename; +{ + char time_str[11]; + + /* M.1087654321.A ©Î M.987654321.A */ + str_ncpy(time_str, filename + 2, filename[2] == '1' ? 11 : 10); + + return (time_t) atoi(time_str); +} + + +static void +trans_hdr_stamp(folder, t, hdr, fpath) + char *folder; + time_t t; + HDR *hdr; + char *fpath; +{ + FILE *fp; + char *fname, *family; + int rc; + + fname = fpath; + while (rc = *folder++) + { + *fname++ = rc; + if (rc == '/') + family = fname; + } + fname = family + 1; + *fname++ = '/'; + *fname++ = 'A'; + + for (;;) + { + *family = radix32[t & 31]; + archiv32(t, fname); + + if (fp = fopen(fpath, "r")) + { + fclose(fp); + t++; + } + else + { + memset(hdr, 0, sizeof(HDR)); + hdr->chrono = t; + str_stamp(hdr->date, &hdr->chrono); + strcpy(hdr->xname, --fname); + break; + } + } +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transbrd(bh) + boardheader *bh; +{ + static time_t stamp = 0; + + int fd; + char index[64], folder[64], buf[64], fpath[64]; + fileheader fh; + HDR hdr; + BRD newboard; + time_t chrono; + + printf("Âà´« %s ¬ÝªO\n", bh->brdname); + + brd_fpath(buf, bh->brdname, NULL); + if (dashd(buf)) + { + printf("%s ¤w¸g¦³¦¹¬ÝªO\n", bh->brdname); + return; + } + + if (!stamp) + time(&stamp); + + /* Âà´« .BRD */ + + memset(&newboard, 0, sizeof(newboard)); + str_ncpy(newboard.brdname, bh->brdname, sizeof(newboard.brdname)); + str_ncpy(newboard.class, bh->title, sizeof(newboard.class)); + str_ncpy(newboard.title, bh->title + 4, sizeof(newboard.title)); + str_ncpy(newboard.BM, bh->BM, sizeof(newboard.BM)); + newboard.bstamp = stamp++; + newboard.battr = BRD_NOTRAN; /* ¹w³]¤£Âà«H */ + newboard.readlevel = 0; + newboard.postlevel = PERM_POST; + + rec_add(FN_BRD, &newboard, sizeof(newboard)); /* §O§Ñ¤F¥Î brd2gem.c ¨ÓÂà´« Class */ + + /* ¶}·s¥Ø¿ý */ + + sprintf(fpath, "gem/brd/%s", newboard.brdname); + mak_dirs(fpath); + mak_dirs(fpath + 4); + + /* Âà´«¶iªOµe± */ + + sprintf(buf, OLD_BBSHOME "/boards/%s/notes", bh->brdname); + + if (dashf(buf)) + { + brd_fpath(fpath, newboard.brdname, FN_NOTE); + f_cp(buf, fpath, O_TRUNC); + } + + /* Âà´«¤å³¹ */ + + sprintf(index, OLD_BBSHOME "/boards/%s/.DIR", bh->brdname); /* ªº .DIR */ + brd_fpath(folder, newboard.brdname, ".DIR"); /* ·sªº .DIR */ + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + sprintf(buf, OLD_BBSHOME "/boards/%s/%s", bh->brdname, fh.filename); + if (dashf(buf)) /* ¤å³¹Àɮצb¤~°µÂà´« */ + { + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + trans_hdr_stamp(folder, chrono, &hdr, fpath); + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ansi(hdr.title, fh.title, sizeof(hdr.title)); + hdr.xmode = (fh.filemode & 0x2) ? POST_MARKED : 0; + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + f_cp(buf, fpath, O_TRUNC); + } + } + close(fd); + } +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int fd; + boardheader bh; + + /* argc == 1 Âà¥þ³¡ªO */ + /* argc == 2 Âà¬Y¯S©wªO */ + + if (argc > 2) + { + printf("Usage: %s [target_board]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (!dashf(FN_BOARD)) + { + printf("ERROR! Can't open " FN_BOARD "\n"); + exit(-1); + } + if (!dashd(OLD_BBSHOME "/boards")) + { + printf("ERROR! Can't open " OLD_BBSHOME "/boards\n"); + exit(-1); + } + + if ((fd = open(FN_BOARD, O_RDONLY)) >= 0) + { + while (read(fd, &bh, sizeof(bh)) == sizeof(bh)) + { + if (argc == 1) + { + transbrd(&bh); + } + else if (!strcmp(bh.brdname, argv[1])) + { + transbrd(&bh); + exit(1); + } + } + close(fd); + } + + exit(0); +} diff --git a/util/tran/sob2gem.c b/util/tran/sob2gem.c new file mode 100644 index 0000000..5a78186 --- /dev/null +++ b/util/tran/sob2gem.c @@ -0,0 +1,233 @@ +/*-------------------------------------------------------*/ +/* util/transman.c */ +/*-------------------------------------------------------*/ +/* target : Maple Sob 2.36 ¦Ü Maple 3.02 ºëµØ°ÏÂà´« */ +/* create : 98/06/15 */ +/* update : 02/10/26 */ +/* author : ernie@micro8.ee.nthu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transman [target_board] */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. µ{¦¡¤£¶}¥Ø¿ý¡A¨Ï¥Î«e¥ý½T©w gem/target_board/? ¥Ø¿ý¦s¦b + if not¡A¥ý¶}·sªO or transbrd + 2. ¥uÂà M.*.A ¤Î D.*.A¡A¨ä¥L link ¤£Âà´« + 3. ¦p¦³»Ýn½Ð¥ý chmod 644 `find PATH -perm 600` + + ps. User on ur own risk. + +#endif + + +#include "sob.h" + + +/* ----------------------------------------------------- */ +/* Âà´«ºëµØ°Ï */ +/* ----------------------------------------------------- */ + + +static time_t +trans_hdr_chrono(filename) + char *filename; +{ + char time_str[11]; + + /* M.1087654321.A ©Î M.987654321.A */ + str_ncpy(time_str, filename + 2, filename[2] == '1' ? 11 : 10); + + return (time_t) atoi(time_str); +} + + +static void +trans_man_stamp(folder, token, hdr, fpath, time) + char *folder; + int token; + HDR *hdr; + char *fpath; + time_t time; +{ + char *fname, *family; + int rc; + + fname = fpath; + while (rc = *folder++) + { + *fname++ = rc; + if (rc == '/') + family = fname; + } + if (*family != '.') + { + fname = family; + family -= 2; + } + else + { + fname = family + 1; + *fname++ = '/'; + } + + *fname++ = token; + + *family = radix32[time & 31]; + archiv32(time, fname); + + if (rc = open(fpath, O_WRONLY | O_CREAT | O_EXCL, 0600)) + { + memset(hdr, 0, sizeof(HDR)); + hdr->chrono = time; + str_stamp(hdr->date, &hdr->chrono); + strcpy(hdr->xname, --fname); + close(rc); + } + return; +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transman(index, folder) + char *index, *folder; +{ + static int count = 100; + + int fd; + char *ptr, buf[256], fpath[64]; + fileheader fh; + HDR hdr; + time_t chrono; + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + strcpy(buf, index); + ptr = strrchr(buf, '/') + 1; + strcpy(ptr, fh.filename); + + if (*fh.filename == 'M' && dashf(buf)) /* ¥uÂà M.xxxx.A ¤Î D.xxxx.a */ + { + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + trans_man_stamp(folder, 'A', &hdr, fpath, chrono); + hdr.xmode = 0; + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ncpy(hdr.title, fh.title + 3, sizeof(hdr.title)); + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + f_cp(buf, fpath, O_TRUNC); + } + else if (*fh.filename == 'D' && dashd(buf)) + { + char sub_index[256]; + + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = ++count; /* WD ªº¥Ø¿ý©R¦W¤ñ¸û©_©Ç¡A¥u¦n¦Û¤vµ¹¼Æ¦r */ + trans_man_stamp(folder, 'F', &hdr, fpath, chrono); + hdr.xmode = GEM_FOLDER; + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ncpy(hdr.title, fh.title + 3, sizeof(hdr.title)); + rec_add(folder, &hdr, sizeof(HDR)); + + /* recursive ¶i¥hÂà´«¤l¥Ø¿ý */ + strcpy(sub_index, buf); + ptr = strrchr(sub_index, '/') + 1; + sprintf(ptr, "%s/.DIR", fh.filename); + transman(sub_index, fpath); + } + } + close(fd); + } +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int fd; + char *brdname, index[64], folder[64]; + boardheader bh; + + /* argc == 1 Âà¥þ³¡ªO */ + /* argc == 2 Âà¬Y¯S©wªO */ + + if (argc > 2) + { + printf("Usage: %s [target_board]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (!dashf(FN_BOARD)) + { + printf("ERROR! Can't open " FN_BOARD "\n"); + exit(-1); + } + if (!dashd(OLD_BBSHOME "/man/boards")) + { + printf("ERROR! Can't open " OLD_BBSHOME "/man/boards\n"); + exit(-1); + } + + if (argc == 1) + { + if ((fd = open(FN_BOARD, O_RDONLY)) >= 0) + { + while (read(fd, &bh, sizeof(bh)) == sizeof(bh)) + { + brdname = bh.brdname; + + sprintf(folder, "gem/brd/%s", brdname); + if (!dashd(folder)) + { + printf("ERROR! %s not exist. New it first.\n", folder); + continue; + } + + sprintf(index, OLD_BBSHOME "/man/boards/%s/.DIR", brdname); + sprintf(folder, "gem/brd/%s/%s", brdname, FN_DIR); + + printf("Âà´« %s ºëµØ°Ï\n", brdname); + transman(index, folder); + } + close(fd); + } + } + else + { + brdname = argv[1]; + + sprintf(folder, "gem/brd/%s", brdname); + if (!dashd(folder)) + { + printf("ERROR! %s not exist. New it first.\n", folder); + exit(-1); + } + + sprintf(index, OLD_BBSHOME "/man/boards/%s/.DIR", brdname); + sprintf(folder, "gem/brd/%s/%s", brdname, FN_DIR); + + printf("Âà´« %s ºëµØ°Ï\n", brdname); + transman(index, folder); + + exit(1); + } + + exit(0); +} diff --git a/util/tran/sob2pal.c b/util/tran/sob2pal.c new file mode 100644 index 0000000..5c6a293 --- /dev/null +++ b/util/tran/sob2pal.c @@ -0,0 +1,182 @@ +/*-------------------------------------------------------*/ +/* util/transpal.c */ +/*-------------------------------------------------------*/ +/* target : SOB ¦Ü Maple 3.02 (¬ÝªO)¦n¤Í¦W³æÂà´« */ +/* create : 01/09/08 */ +/* update : / / */ +/* author : itoc.bbs@bbs.ee.nctu.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transpal */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ³]©w OLD_BBSHOME (sob config.h) + 2. ×§ï struct FRIEND ©M transfer_pal() transfer_brdpal() + 3. Âà´«(¬ÝªO)¦n¤Í¦W³æ¤§«e¡A±z¥²¶·¥ýÂà´«§¹¬ÝªO¤Î¨Ï¥ÎªÌ¡C + + ps. ¨Ï¥Î«e½Ð¥ý¦æ³Æ¥÷¡Ause on ur own risk. µ{¦¡©å¦H½Ð¥]²[ :p + ps. ·PÁ lkchu ªº Maple 3.02 for FreeBSD + +#endif + + +#include "bbs.h" + + +#define OLD_BBSHOME "/home/oldbbs" /* 2.36 */ + + +/* ----------------------------------------------------- */ +/* 3.02 functions */ +/* ----------------------------------------------------- */ + + +static int +acct_uno(userid) + char *userid; +{ + int fd; + int userno; + char fpath[64]; + + usr_fpath(fpath, userid, FN_ACCT); + fd = open(fpath, O_RDONLY); + if (fd >= 0) + { + read(fd, &userno, sizeof(userno)); + close(fd); + return userno; + } + return -1; +} + + +/* ----------------------------------------------------- */ + + +static void +transfer_pal(userid) + char *userid; +{ + ACCT acct; + FILE *fp; + int fd, friend_userno; + char fpath[64], buf[64], friend_userid[80]; + PAL pal; + + usr_fpath(fpath, userid, FN_PAL); /* ·sªº¦n¤Í¦W³æ */ + + /* sob ªº usr ¥Ø¿ý¦³¤À¤j¤p¼g¡A©Ò¥Hn¥ý¨ú±o¤j¤p¼g */ + usr_fpath(buf, userid, FN_ACCT); + if ((fd = open(buf, O_RDONLY)) >= 0) + { + read(fd, &acct, sizeof(ACCT)); + close(fd); + } + sprintf(buf, OLD_BBSHOME"/home/%s/overrides", acct.userid); /* ªº¦n¤Í¦W³æ */ + + if (dashf(fpath)) + unlink(fpath); /* ²M±¼««Ø */ + + if (!(fp = fopen(buf, "r"))) + return; + + while (fscanf(fp, "%s", friend_userid) == 1) + { + if ((friend_userno = acct_uno(friend_userid)) >= 0) + { + memset(&pal, 0, sizeof(PAL)); + str_ncpy(pal.userid, friend_userid, sizeof(pal.userid)); + pal.ftype = 0; + str_ncpy(pal.ship, "", sizeof(pal.ship)); + pal.userno = friend_userno; + rec_add(fpath, &pal, sizeof(PAL)); + } + } + + fclose(fp); +} + + +static void +transfer_brdpal(userid) + char *userid; +{ + FILE *fp; + int friend_userno; + char fpath[64], buf[64], friend_userid[80]; + PAL pal; + + brd_fpath(fpath, userid, FN_PAL); /* ·sªº¬ÝªO¦n¤Í¦W³æ */ + sprintf(buf, OLD_BBSHOME"/boards/%s/visable", userid); /* ªº¬ÝªO¦n¤Í¦W³æ */ + + if (dashf(fpath)) + unlink(fpath); /* ²M±¼««Ø */ + + if (!(fp = fopen(buf, "r"))) + return; + + while (fscanf(fp, "%s", friend_userid) == 1) + { + if ((friend_userno = acct_uno(friend_userid)) >= 0) + { + memset(&pal, 0, sizeof(PAL)); + str_ncpy(pal.userid, friend_userid, sizeof(pal.userid)); + pal.ftype = 0; + str_ncpy(pal.ship, "", sizeof(pal.ship)); + pal.userno = friend_userno; + rec_add(fpath, &pal, sizeof(PAL)); + } + } + + fclose(fp); +} + + +int +main() +{ + char c, *str; + char buf[64]; + struct dirent *de; + DIR *dirp; + + chdir(BBSHOME); + + /* Âà´«¨Ï¥ÎªÌ¦n¤Í¦W³æ */ + for (c = 'a'; c <= 'z'; c++) + { + sprintf(buf, "usr/%c", c); + + if (!(dirp = opendir(buf))) + continue; + + while (de = readdir(dirp)) + { + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + transfer_pal(str); + } + closedir(dirp); + } + + /* Âà´«¬ÝªO¦n¤Í¦W³æ */ + if (!(dirp = opendir("brd"))) + return 0; + + while (de = readdir(dirp)) + { + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + transfer_brdpal(str); + } + closedir(dirp); + + return 0; +} diff --git a/util/tran/sob2usr.c b/util/tran/sob2usr.c new file mode 100644 index 0000000..cbaa8a4 --- /dev/null +++ b/util/tran/sob2usr.c @@ -0,0 +1,564 @@ +/*-------------------------------------------------------*/ +/* util/transusr.c */ +/*-------------------------------------------------------*/ +/* target : Maple Sob 2.36 ¦Ü Maple 3.02 ¨Ï¥ÎªÌÂà´« */ +/* .PASSWDS => .USR .ACCT */ +/* create : 98/06/14 */ +/* update : 02/10/26 */ +/* author : ernie@micro8.ee.nthu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transusr */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ×§ï struct userec ¤Î creat_dirs() + (userec ¨âª©©w¸qªº¦r¦êªø«×¤£¤@¡A½Ð¦Û¦æ´«¦¨¼Æ¦r) + 2. °£ plans ÀɦW¡A¦n¤Í¦W³æ¡B¼È¦sÀɵ¥³£¤£Âà´« + 3. Sob ¦³¤EÓñ¦WÀÉ¡A¥uÂà«e¤TÓ + 4. «H½c¤¤ªº internet mail ¦p¦³»Ýn½Ð¥ý chmod 644 `find PATH -perm 600` + + ps. ¨Ï¥Î«e½Ð¥ý¦æ³Æ¥÷¡Ause on ur own risk. µ{¦¡©å¦H½Ð¥]²[ :p + ps. ·PÁ lkchu ªº Maple 3.02 for FreeBSD + +#endif + + +#include "sob.h" + + +/* ----------------------------------------------------- */ +/* Âà´« .ACCT */ +/* ----------------------------------------------------- */ + + +static inline int +is_bad_userid(userid) + char *userid; +{ + register char ch; + + if (strlen(userid) < 2) + return 1; + + if (!isalpha(*userid)) + return 1; + + if (!str_cmp(userid, "new")) + return 1; + + while (ch = *(++userid)) + { + if (!isalnum(ch)) + return 1; + } + return 0; +} + + +static inline int +uniq_userno(fd) + int fd; +{ + char buf[4096]; + int userno, size; + SCHEMA *sp; /* record length 16 ¥i¾ã°£ 4096 */ + + userno = 1; + + while ((size = read(fd, buf, sizeof(buf))) > 0) + { + sp = (SCHEMA *) buf; + do + { + if (sp->userid[0] == '\0') + { + lseek(fd, -size, SEEK_CUR); + return userno; + } + userno++; + size -= sizeof(SCHEMA); + sp++; + } while (size); + } + + return userno; +} + + +#define LEVEL_BASIC 000000000001 /* °ò¥»Åv¤O */ +#define LEVEL_CHAT 000000000002 /* ¶i¤J²á¤Ñ«Ç */ +#define LEVEL_PAGE 000000000004 /* §ä¤H²á¤Ñ */ +#define LEVEL_POST 000000000010 /* µoªí¤å³¹ */ +#define LEVEL_LOGINOK 000000000020 /* µù¥Uµ{§Ç»{ÃÒ */ +#define LEVEL_MAILLIMIT 000000000040 /* «H¥óµL¤W */ +#define LEVEL_CLOAK 000000000100 /* Áô¨³N */ +#define LEVEL_SEECLOAK 000000000200 /* ¬Ý¨£§ÔªÌ */ +#define LEVEL_XEMPT 000000000400 /* ¥Ã¤[«O¯d±b¸¹ */ +#define LEVEL_BM 000000002000 /* ªO¥D */ +#define LEVEL_ACCOUNTS 000000004000 /* ±b¸¹Á`ºÞ */ +#define LEVEL_CHATROOM 000000010000 /* ²á¤Ñ«ÇÁ`ºÞ */ +#define LEVEL_BOARD 000000020000 /* ¬ÝªOÁ`ºÞ */ +#define LEVEL_SYSOP 000000040000 /* ¯¸ªø */ + + +static inline usint +trans_acct_level(perm) + usint perm; +{ + usint userlevel; + + userlevel = 0; + + if (perm & LEVEL_BASIC) + userlevel |= PERM_BASIC; + + if (perm & LEVEL_CHAT) + userlevel |= PERM_CHAT; + + if (perm & LEVEL_PAGE) + userlevel |= PERM_PAGE; + + if (perm & LEVEL_POST) + userlevel |= PERM_POST; + + if (perm & LEVEL_LOGINOK) + userlevel |= PERM_VALID; + + if (perm & LEVEL_MAILLIMIT) + userlevel |= PERM_MBOX; + + if (perm & LEVEL_CLOAK) + userlevel |= PERM_CLOAK; + + if (perm & LEVEL_SEECLOAK) + userlevel |= PERM_SEECLOAK; + + if (perm & LEVEL_XEMPT) + userlevel |= PERM_XEMPT; + + if (perm & LEVEL_BM) + userlevel |= PERM_BM; + + if (perm & LEVEL_ACCOUNTS) + userlevel |= PERM_ACCOUNTS; + + if (perm & LEVEL_CHATROOM) + userlevel |= PERM_CHATROOM; + + if (perm & LEVEL_BOARD) + userlevel |= PERM_BOARD; + + if (perm & LEVEL_SYSOP) + userlevel |= PERM_SYSOP; + + return userlevel; +} + + +static inline void +creat_dirs(old) + userec *old; +{ + ACCT new; + SCHEMA slot; + int fd; + char fpath[64]; + + memset(&new, 0, sizeof(new)); + memset(&slot, 0, sizeof(slot)); + + str_ncpy(new.userid, old->userid, sizeof(new.userid)); + str_ncpy(new.passwd, old->passwd, sizeof(new.passwd)); + str_ncpy(new.realname, old->realname, sizeof(new.realname)); + str_ncpy(new.username, old->username, sizeof(new.username)); + new.userlevel = trans_acct_level(old->userlevel); + new.ufo = UFO_DEFAULT_NEW; + new.signature = 0; + new.year = old->year; + new.month = old->month; + new.day = old->day; + new.sex = old->sex ? 1 : 0; + new.money = 1000; /* ¹w³]»È¹ô = 1000 ª÷¹ô = 0 */ + new.gold = 0; + new.numlogins = old->numlogins; + new.numposts = old->numposts; + new.numemails = 0; + new.firstlogin = old->firstlogin; + new.lastlogin = old->lastlogin; + new.tcheck = time(&new.tvalid); + str_ncpy(new.lasthost, old->lasthost, sizeof(new.lasthost)); + str_ncpy(new.email, old->email, sizeof(new.email)); + + slot.uptime = time(0); + strcpy(slot.userid, new.userid); + + fd = open(FN_SCHEMA, O_RDWR | O_CREAT, 0600); + new.userno = uniq_userno(fd); + write(fd, &slot, sizeof(slot)); + close(fd); + + usr_fpath(fpath, new.userid, NULL); + mkdir(fpath, 0700); + strcat(fpath, "/@"); + mkdir(fpath, 0700); + usr_fpath(fpath, new.userid, "MF"); + mkdir(fpath, 0700); + usr_fpath(fpath, new.userid, "gem"); /* itoc.010727: Ó¤HºëµØ°Ï */ + mak_links(fpath); + + usr_fpath(fpath, new.userid, ".ACCT"); + fd = open(fpath, O_WRONLY | O_CREAT, 0600); + write(fd, &new, sizeof(ACCT)); + close(fd); +} + + +/* ----------------------------------------------------- */ +/* Âà´«»{ÃÒ¸ê®Æ */ +/* ----------------------------------------------------- */ + + +static inline void +trans_justify(old) + userec *old; +{ + char fpath[64]; + FILE *fp; + + usr_fpath(fpath, old->userid, FN_JUSTIFY); + if (fp = fopen(fpath, "a")) + { + fprintf(fp, "RPY: %s\n", old->justify); /* Âà´«¹w³]¥H email »{ÃÒ */ + fclose(fp); + } +} + + +/* ----------------------------------------------------- */ +/* Âഫñ¦WÀÉ¡BpµeÀÉ */ +/* ----------------------------------------------------- */ + + +static inline void +trans_sig(old) + userec *old; +{ + int i; + char buf[64], fpath[64], f_sig[20]; + + for (i = 1; i <= 3; i++) /* Maple 3.0 ¥u¦³¤TÓñ¦W */ + { + sprintf(buf, OLD_BBSHOME "/home/%s/sig.%d", old->userid, i); /* ªºÃ±¦WÀÉ */ + if (dashf(buf)) + { + sprintf(f_sig, "%s.%d", FN_SIGN, i); + usr_fpath(fpath, old->userid, f_sig); + f_cp(buf, fpath, O_TRUNC); + } + } + + return; +} + + +static inline void +trans_plans(old) + userec *old; +{ + char buf[64], fpath[64]; + + sprintf(buf, OLD_BBSHOME "/home/%s/plans", old->userid); + if (dashf(buf)) + { + usr_fpath(fpath, old->userid, FN_PLANS); + f_cp(buf, fpath, O_TRUNC); + } + return; +} + + +/* ----------------------------------------------------- */ +/* Âà´««H¥ó */ +/* ----------------------------------------------------- */ + + +static time_t +trans_hdr_chrono(filename) + char *filename; +{ + char time_str[11]; + + /* M.1087654321.A ©Î M.987654321.A */ + str_ncpy(time_str, filename + 2, filename[2] == '1' ? 11 : 10); + + return (time_t) atoi(time_str); +} + + +static inline void +trans_mail(old) + userec *old; +{ + int fd; + char index[64], folder[64], buf[64], fpath[64]; + fileheader fh; + HDR hdr; + + sprintf(index, OLD_BBSHOME "/home/%s/.DIR", old->userid); + usr_fpath(folder, old->userid, FN_DIR); + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + sprintf(buf, OLD_BBSHOME "/home/%s/%s", old->userid, fh.filename); + + if (dashf(buf)) /* ¤å³¹Àɮצb¤~°µÂà´« */ + { + time_t chrono; + char new_name[10] = "@"; + + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + new_name[1] = radix32[chrono & 31]; + archiv32(chrono, new_name + 1); + + hdr.chrono = chrono; + str_ncpy(hdr.xname, new_name, sizeof(hdr.xname)); + str_ncpy(hdr.owner, strstr(fh.owner, "[³Æ.") ? "[³Æ§Ñ¿ý]" : fh.owner, sizeof(hdr.owner)); /* [³Æ.§Ñ.¿ý] */ + str_ncpy(hdr.title, fh.title, sizeof(hdr.title)); + str_stamp(hdr.date, &hdr.chrono); + hdr.xmode = (fh.filemode & 0x2) ? (MAIL_MARKED | MAIL_READ) : MAIL_READ; /* ³]¬°¤wŪ */ + + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + usr_fpath(fpath, old->userid, "@/"); + strcat(fpath, new_name); + f_cp(buf, fpath, O_TRUNC); + } + } + close(fd); + } +} + + +/* ----------------------------------------------------- */ +/* Âà´«Ó¤HºëµØ°Ï */ +/* ----------------------------------------------------- */ + + +#ifdef HAVE_PERSONAL_GEM +static void +trans_man_stamp(folder, token, hdr, fpath, time) + char *folder; + int token; + HDR *hdr; + char *fpath; + time_t time; +{ + char *fname, *family; + int rc; + + fname = fpath; + while (rc = *folder++) + { + *fname++ = rc; + if (rc == '/') + family = fname; + } + if (*family != '.') + { + fname = family; + family -= 2; + } + else + { + fname = family + 1; + *fname++ = '/'; + } + + *fname++ = token; + + *family = radix32[time & 31]; + archiv32(time, fname); + + if (rc = open(fpath, O_WRONLY | O_CREAT | O_EXCL, 0600)) + { + memset(hdr, 0, sizeof(HDR)); + hdr->chrono = time; + str_stamp(hdr->date, &hdr->chrono); + strcpy(hdr->xname, --fname); + close(rc); + } + return; +} + + +static void +transman(index, folder) + char *index, *folder; +{ + static int count = 100; + + int fd; + char *ptr, buf[256], fpath[64]; + fileheader fh; + HDR hdr; + time_t chrono; + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + strcpy(buf, index); + ptr = strrchr(buf, '/') + 1; + strcpy(ptr, fh.filename); + + if (*fh.filename == 'M' && dashf(buf)) /* ¥uÂà M.xxxx.A ¤Î D.xxxx.a */ + { + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + trans_man_stamp(folder, 'A', &hdr, fpath, chrono); + hdr.xmode = 0; + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ncpy(hdr.title, fh.title + 3, sizeof(hdr.title)); + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + f_cp(buf, fpath, O_TRUNC); + } + else if (*fh.filename == 'D' && dashd(buf)) + { + char sub_index[256]; + + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = ++count; /* WD ªº¥Ø¿ý©R¦W¤ñ¸û©_©Ç¡A¥u¦n¦Û¤vµ¹¼Æ¦r */ + trans_man_stamp(folder, 'F', &hdr, fpath, chrono); + hdr.xmode = GEM_FOLDER; + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ncpy(hdr.title, fh.title + 3, sizeof(hdr.title)); + rec_add(folder, &hdr, sizeof(HDR)); + + /* recursive ¶i¥hÂà´«¤l¥Ø¿ý */ + strcpy(sub_index, buf); + ptr = strrchr(sub_index, '/') + 1; + sprintf(ptr, "%s/.DIR", fh.filename); + transman(sub_index, fpath); + } + } + close(fd); + } +} +#endif + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transusr(user) + userec *user; +{ + char buf[64]; + + printf("Âà´« %s ¨Ï¥ÎªÌ\n", user->userid); + + if (is_bad_userid(user->userid)) + { + printf("%s ¤£¬O¦Xªk ID\n", user->userid); + return; + } + + usr_fpath(buf, user->userid, NULL); + if (dashd(buf)) + { + printf("%s ¤w¸g¦³¦¹ ID\n", user->userid); + return; + } + + sprintf(buf, OLD_BBSHOME "/home/%s", user->userid); + if (!dashd(buf)) + { + printf("%s ªºÀɮפ£¦s¦b\n", user->userid); + return; + } + + creat_dirs(user); + trans_justify(user); + trans_sig(user); + trans_plans(user); + trans_mail(user); + + +#ifdef HAVE_PERSONAL_GEM + sprintf(buf, OLD_BBSHOME "/home/%s/man", user->userid); + if (dashd(buf)) + { + char index[64], folder[64]; + + sprintf(index, "%s/.DIR", buf); + usr_fpath(folder, user->userid, "gem/" FN_DIR); + transman(index, folder); + } +#endif +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int fd; + userec user; + + /* argc == 1 Âà¥þ³¡¨Ï¥ÎªÌ */ + /* argc == 2 Âà¬Y¯S©w¨Ï¥ÎªÌ */ + + if (argc > 2) + { + printf("Usage: %s [target_user]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (!dashf(FN_PASSWD)) + { + printf("ERROR! Can't open " FN_PASSWD "\n"); + exit(-1); + } + if (!dashd(OLD_BBSHOME "/home")) + { + printf("ERROR! Can't open " OLD_BBSHOME "/home\n"); + exit(-1); + } + + if ((fd = open(FN_PASSWD, O_RDONLY)) >= 0) + { + while (read(fd, &user, sizeof(user)) == sizeof(user)) + { + if (argc == 1) + { + transusr(&user); + } + else if (!strcmp(user.userid, argv[1])) + { + transusr(&user); + exit(1); + } + } + close(fd); + } + + exit(0); +} diff --git a/util/tran/transacct.c b/util/tran/transacct.c new file mode 100644 index 0000000..ac50c59 --- /dev/null +++ b/util/tran/transacct.c @@ -0,0 +1,212 @@ +/*-------------------------------------------------------*/ +/* util/transacct.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : M3 ACCT Âà´«µ{¦¡ */ +/* create : 98/12/15 */ +/* update : 02/04/29 */ +/* author : mat.bbs@fall.twbbs.org */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transacct [userid] */ +/*-------------------------------------------------------*/ + + +#if 0 + + ¨Ï¥Î¤èªk¡G + + 0. For Maple 3.X To Maple 3.X + + 1. ¨Ï¥Î«e½Ð¥ý§Q¥Î backupacct.c ³Æ¥÷ .ACCT + + 2. ½Ð¦Û¦æ§ï struct NEW ©M struct OLD + + 3. ¨Ì¤£¦Pªº NEW¡BOLD ¨Ó§ï trans_acct()¡C + +#endif + + +#include "bbs.h" + + +/* ----------------------------------------------------- */ +/* (·sªº) ¨Ï¥ÎªÌ±b¸¹ .ACCT struct */ +/* ----------------------------------------------------- */ + + +typedef struct /* n©M·sª©µ{¦¡ struct ¤@¼Ë */ +{ + int userno; /* unique positive code */ + + char userid[IDLEN + 1]; /* ID */ + char passwd[PASSLEN + 1]; /* ±K½X */ + char realname[RNLEN + 1]; /* ¯u¹ê©m¦W */ + char username[UNLEN + 1]; /* ¼ÊºÙ */ + + usint userlevel; /* Åv */ + usint ufo; /* user favor option */ + uschar signature; /* ¹w³]ñ¦WÀÉ */ + + char year; /* ¥Í¤é(¥Á°ê¦~) */ + char month; /* ¥Í¤é(¤ë) */ + char day; /* ¥Í¤é(¤é) */ + char sex; /* ©Ê§O 0:¤¤©Ê ©_¼Æ:¨k©Ê °¸¼Æ:¤k©Ê */ + int money; /* »È¹ô */ + int gold; /* ª÷¹ô */ + + int numlogins; /* ¤W¯¸¦¸¼Æ */ + int numposts; /* µoªí¦¸¼Æ */ + int numemails; /* ±Hµo Inetrnet E-mail ¦¸¼Æ */ + + time_t firstlogin; /* ²Ä¤@¦¸¤W¯¸®É¶¡ */ + time_t lastlogin; /* ¤W¤@¦¸¤W¯¸®É¶¡ */ + time_t tcheck; /* ¤W¦¸ check «H½c/¦n¤Í¦W³æªº®É¶¡ */ + time_t tvalid; /* ³q¹L»{ÃÒªº®É¶¡ */ + + char lasthost[30]; /* ¤W¦¸µn¤J¨Ó·½ */ + char email[60]; /* ¥Ø«eµn°Oªº¹q¤l«H½c */ +} NEW; + + +/* ----------------------------------------------------- */ +/* (ªº) ¨Ï¥ÎªÌ±b¸¹ .ACCT struct */ +/* ----------------------------------------------------- */ + + +typedef struct /* n©Mª©µ{¦¡ struct ¤@¼Ë */ +{ + int userno; /* unique positive code */ + + char userid[IDLEN + 1]; /* ID */ + char passwd[PASSLEN + 1]; /* ±K½X */ + char realname[RNLEN + 1]; /* ¯u¹ê©m¦W */ + char username[UNLEN + 1]; /* ¼ÊºÙ */ + + usint userlevel; /* Åv */ + usint ufo; /* user favor option */ + uschar signature; /* ¹w³]ñ¦WÀÉ */ + + char year; /* ¥Í¤é(¥Á°ê¦~) */ + char month; /* ¥Í¤é(¤ë) */ + char day; /* ¥Í¤é(¤é) */ + char sex; /* ©Ê§O 0:¤¤©Ê ©_¼Æ:¨k©Ê °¸¼Æ:¤k©Ê */ + int money; /* »È¹ô */ + int gold; /* ª÷¹ô */ + + int numlogins; /* ¤W¯¸¦¸¼Æ */ + int numposts; /* µoªí¦¸¼Æ */ + int numemails; /* ±Hµo Inetrnet E-mail ¦¸¼Æ */ + + time_t firstlogin; /* ²Ä¤@¦¸¤W¯¸®É¶¡ */ + time_t lastlogin; /* ¤W¤@¦¸¤W¯¸®É¶¡ */ + time_t tcheck; /* ¤W¦¸ check «H½c/¦n¤Í¦W³æªº®É¶¡ */ + time_t tvalid; /* ³q¹L»{ÃÒªº®É¶¡ */ + + char lasthost[30]; /* ¤W¦¸µn¤J¨Ó·½ */ + char email[60]; /* ¥Ø«eµn°Oªº¹q¤l«H½c */ +} OLD; + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +trans_acct(old, new) + OLD *old; + NEW *new; +{ + memset(new, 0, sizeof(NEW)); + + new->userno = old->userno; + + str_ncpy(new->userid, old->userid, sizeof(new->userid)); + str_ncpy(new->passwd, old->passwd, sizeof(new->passwd)); + str_ncpy(new->realname, old->realname, sizeof(new->realname)); + str_ncpy(new->username, old->username, sizeof(new->username)); + + new->userlevel = old->userlevel; + new->ufo = old->ufo; + new->signature = old->signature; + + new->year = old->year; + new->month = old->month; + new->day = old->day; + new->sex = old->sex; + new->money = old->money; + new->gold = old->gold; + + new->numlogins = old->numlogins; + new->numposts = old->numposts; + new->numemails = old->numemails; + + new->firstlogin = old->firstlogin; + new->lastlogin = old->lastlogin; + new->tcheck = old->tcheck; + new->tvalid = old->tvalid; + + str_ncpy(new->lasthost, old->lasthost, sizeof(new->lasthost)); + str_ncpy(new->email, old->email, sizeof(new->email)); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + NEW new; + char c; + + if (argc > 2) + { + printf("Usage: %s [userid]\n", argv[0]); + return -1; + } + + for (c = 'a'; c <= 'z'; c++) + { + char buf[64]; + struct dirent *de; + DIR *dirp; + + sprintf(buf, BBSHOME "/usr/%c", c); + chdir(buf); + + if (!(dirp = opendir("."))) + continue; + + while (de = readdir(dirp)) + { + OLD old; + int fd; + char *str; + + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + if ((argc == 2) && str_cmp(str, argv[1])) + continue; + + sprintf(buf, "%s/" FN_ACCT, str); + if ((fd = open(buf, O_RDONLY)) < 0) + continue; + + read(fd, &old, sizeof(OLD)); + close(fd); + unlink(buf); /* itoc.010831: ¬å±¼ì¨Óªº FN_ACCT */ + + trans_acct(&old, &new); + + fd = open(buf, O_WRONLY | O_CREAT, 0600); /* itoc.010831: ««Ø·sªº FN_ACCT */ + write(fd, &new, sizeof(NEW)); + close(fd); + } + + closedir(dirp); + } + + return 0; +} diff --git a/util/tran/transbrd.c b/util/tran/transbrd.c new file mode 100644 index 0000000..23207c9 --- /dev/null +++ b/util/tran/transbrd.c @@ -0,0 +1,125 @@ +/*-------------------------------------------------------*/ +/* util/transacct.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : M3 BRD Âà´«µ{¦¡ */ +/* create : 05/05/19 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + ¨Ï¥Î¤èªk¡G + + 0. For Maple 3.X To Maple 3.X + + 1. ¨Ï¥Î«e½Ð¥ý³Æ¥÷ .BRD + + 2. ½Ð¦Û¦æ§ï struct NEW ©M struct OLD + +#endif + + +#include "bbs.h" + + +/* ----------------------------------------------------- */ +/* (·sªº) ¬ÝªO .BRD struct */ +/* ----------------------------------------------------- */ + + +typedef struct /* n©M·sª©µ{¦¡ struct ¤@¼Ë */ +{ + char brdname[BNLEN + 1]; /* board name */ + char class[BCLEN + 1]; + char title[BTLEN + 1]; + char BM[BMLEN + 1]; /* BMs' uid, token '/' */ + + char bvote; /* 0:µL§ë²¼ -1:¦³½ä½L(¥i¯à¦³§ë²¼) 1:¦³§ë²¼ */ + + time_t bstamp; /* «Ø¥ß¬ÝªOªº®É¶¡, unique */ + usint readlevel; /* ¾\ۤ峹ªºÅv */ + usint postlevel; /* µoªí¤å³¹ªºÅv */ + usint battr; /* ¬ÝªOÄÝ©Ê */ + time_t btime; /* -1:bpost/blast »Ýn§ó·s */ + int bpost; /* ¦@¦³´X½g post */ + time_t blast; /* ³Ì«á¤@½g post ªº®É¶¡ */ +} NEW; + + +/* ----------------------------------------------------- */ +/* (ªº) ¬ÝªO .BRD struct */ +/* ----------------------------------------------------- */ + + +typedef struct /* n©Mª©µ{¦¡ struct ¤@¼Ë */ +{ + char brdname[BNLEN + 1]; /* board name */ + char class[BCLEN + 1]; + char title[BTLEN + 1]; + char BM[BMLEN + 1]; /* BMs' uid, token '/' */ + + char bvote; /* 0:µL§ë²¼ -1:¦³½ä½L(¥i¯à¦³§ë²¼) 1:¦³§ë²¼ */ + + time_t bstamp; /* «Ø¥ß¬ÝªOªº®É¶¡, unique */ + usint readlevel; /* ¾\ۤ峹ªºÅv */ + usint postlevel; /* µoªí¤å³¹ªºÅv */ + usint battr; /* ¬ÝªOÄÝ©Ê */ + time_t btime; /* -1:bpost/blast »Ýn§ó·s */ + int bpost; /* ¦@¦³´X½g post */ + time_t blast; /* ³Ì«á¤@½g post ªº®É¶¡ */ +} OLD; + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +#define FN_BRD_TMP ".BRD.tmp" + + +int +main() +{ + int fd; + OLD old; + NEW new; + + chdir(BBSHOME); + + if ((fd = open(FN_BRD, O_RDONLY)) >= 0) + { + while (read(fd, &old, sizeof(OLD)) == sizeof(OLD)) + { + if (!*old.brdname) /* ¦¹ªO¤w³Q§R°£ */ + continue; + + memset(&new, 0, sizeof(NEW)); + + /* Âà´«ªº°Ê§@¦b¦¹ */ + str_ncpy(new.brdname, old.brdname, sizeof(new.brdname)); + str_ncpy(new.class, old.class, sizeof(new.class)); + str_ncpy(new.title, old.title, sizeof(new.title)); + str_ncpy(new.BM, old.BM, sizeof(new.BM)); + new.bvote = old.bvote; + new.bstamp = old.bstamp; + new.readlevel = old.readlevel; + new.postlevel = old.postlevel; + new.battr = old.battr; + new.btime = old.btime; + new.bpost = old.bpost; + new.blast = old.blast; + + rec_add(FN_BRD_TMP, &new, sizeof(NEW)); + } + close(fd); + } + + /* §R°£Âªº¡A§â·sªº§ó¦W */ + unlink(FN_BRD); + rename(FN_BRD_TMP, FN_BRD); + + return 0; +} diff --git a/util/tran/wd.h b/util/tran/wd.h new file mode 100644 index 0000000..8fc22ea --- /dev/null +++ b/util/tran/wd.h @@ -0,0 +1,141 @@ +/*-------------------------------------------------------*/ +/* util/wd.h */ +/*-------------------------------------------------------*/ +/* target : WD ¦Ü Maple 3.02 Âà´« */ +/* create : 02/01/03 */ +/* author : ernie@micro8.ee.nthu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ³]©w OLD_BBSHOME¡BFN_PASSWD¡BFN_BOARD + 2. ×§ï©Ò¦³ªº old struct + + 3. ¥²¶·¦b brd Âà§¹¤~¥i¥HÂà´« gem + 4. ¥²¶·¦b usr ¤Î brd ³£Âà§¹¤~¥i¥HÂà´« mf + 5. ¥²¶·¦b usr ¤Î brd ³£Âà§¹¤~¥i¥HÂà´« pal + 6. ¥²¶·¦b usr Âà§¹¤~¥i¥HÂà´« bmw pip list + 7. «ØÄ³Âà´«¶¶§Ç¬° usr -> brd -> gem -> mf -> pal -> bmw -> pip -> list + +#endif + + +#include "bbs.h" + + +#define OLD_BBSHOME "/home/oldbbs" /* WD */ +#define FN_PASSWD "/home/oldbbs/.PASSWDS" /* WD */ +#define FN_BOARD "/home/oldbbs/.BOARDS" /* WD */ + + +#define HAVE_PERSONAL_GEM /* WD ¬O¦³Ó¤HºëµØ°Ïªº */ + + +/* ----------------------------------------------------- */ +/* old .PASSWDS struct : 512 bytes */ +/* ----------------------------------------------------- */ + +struct userec +{ + char userid[13]; /* ¨Ï¥ÎªÌ¦WºÙ 13 bytes */ + char realname[20]; /* ¯u¹ê©m¦W 20 bytes */ + char username[24]; /* ¼ÊºÙ 24 bytes */ + char passwd[14]; /* ±K½X 14 bytes */ + uschar uflag; /* ¨Ï¥ÎªÌ¿ï¶µ 1 byte */ + usint userlevel; /* ¨Ï¥ÎªÌÅv 4 bytes */ + ushort numlogins; /* ¤W¯¸¦¸¼Æ 2 bytes */ + ushort numposts; /* POST¦¸¼Æ 2 bytes */ + time_t firstlogin; /* µù¥U®É¶¡ 4 bytes */ + time_t lastlogin; /* «e¦¸¤W¯¸ 4 bytes */ + char lasthost[24]; /* ¤W¯¸¦aÂI 24 bytes */ + char vhost[24]; /* µêÀÀºô§} 24 bytes */ + char email[50]; /* E-MAIL 50 bytes */ + char address[50]; /* ¦a§} 50 bytes */ + char justify[39]; /* µù¥U¸ê®Æ 39 bytes */ + uschar month; /* ¥X¥Í¤ë¥÷ 1 byte */ + uschar day; /* ¥X¥Í¤é´Á 1 byte */ + uschar year; /* ¥X¥Í¦~¥÷ 1 byte */ + uschar sex; /* ©Ê§O 1 byte */ + uschar state; /* ª¬ºA?? 1 byte */ + usint habit; /* ³ß¦n³]©w 4 bytes */ + uschar pager; /* ¤ß±¡ÃC¦â 1 bytes */ + uschar invisible; /* Áô¨¼Ò¦¡ 1 bytes */ + usint exmailbox; /* «H½c«Ê¼Æ 4 bytes */ + usint exmailboxk; /* «H½cK¼Æ 4 bytes */ + usint toquery; /* ¦n©_«× 4 bytes */ + usint bequery; /* ¤H®ð«× 4 bytes */ + char toqid[13]; /* «e¦¸¬d½Ö 13 bytes */ + char beqid[13]; /* «e¦¸³Q½Ö¬d 13 bytes */ + unsigned long int totaltime; /* ¤W½uÁ`®É¼Æ 8 bytes */ + usint sendmsg; /* µo°T®§¦¸¼Æ 4 bytes */ + usint receivemsg; /* ¦¬°T®§¦¸¼Æ 4 bytes */ + unsigned long int goldmoney; /* ·¹Ðª÷¹ô 8 bytes */ + unsigned long int silvermoney; /* »È¹ô 8 bytes */ + unsigned long int exp; /* ¸gÅçÈ 8 bytes */ + time_t dtime; /* ¦s´Ú®É¶¡ 4 bytes */ + int limitmoney; /* ª÷¿ú¤U 4 bytes */ +}; +typedef struct userec userec; + + +/* ----------------------------------------------------- */ +/* old DIR of board struct : 128 bytes */ +/* ----------------------------------------------------- */ + +struct fileheader +{ + char filename[33]; /* M.9876543210.A */ + char savemode; /* file save mode */ + char owner[14]; /* uid[.] */ + char date[6]; /* [02/02] or space(5) */ + char title[73]; + uschar filemode; /* must be last field @ boards.c */ +}; +typedef struct fileheader fileheader; + + +/* ----------------------------------------------------- */ +/* old BOARDS struct : 512 bytes */ +/* ----------------------------------------------------- */ + +struct boardheader +{ + char brdname[13]; /* ¬ÝªO^¤å¦WºÙ 13 bytes */ + char title[49]; /* ¬ÝªO¤¤¤å¦WºÙ 49 bytes */ + char BM[39]; /* ªO¥DID©M"/" 39 bytes */ + usint brdattr; /* ¬ÝªOªºÄÝ©Ê 4 bytes */ + time_t bupdate; /* note update time 4 bytes */ + uschar bvote; /* Vote flags 1 bytes */ + time_t vtime; /* Vote close time 4 bytes */ + usint level; /* ¥i¥H¬Ý¦¹ªOªºÅv 4 bytes */ + unsigned long int totalvisit; /* Á`«ô³X¤H¼Æ 8 bytes */ + unsigned long int totaltime; /* Á`°±¯d®É¶¡ 8 bytes */ + char lastvisit[13]; /* ³Ì«á¬Ý¸ÓªOªº¤H 13 bytes */ + time_t opentime; /* ¶}ªO®É¶¡ 4 bytes */ + time_t lastime; /* ³Ì«á«ô³X®É¶¡ 4 bytes */ + char passwd[14]; /* ±K½X 14 bytes */ + unsigned long int postotal; /* Á`¤ô¶q :p 8 bytes */ + usint maxpost; /* ¤å³¹¤W 4 bytes */ + usint maxtime; /* ¤å³¹«O¯d®É¶¡ 4 bytes */ + char desc[3][80]; /* ¤¤¤å´yz 240 bytes */ + char pad[87]; +}; +typedef struct boardheader boardheader; + + +/* ----------------------------------------------------- */ +/* old FRIEND struct : 128 bytes */ +/* ----------------------------------------------------- */ + +struct FRIEND +{ + char userid[33]; /* list name/userid */ + char savemode; + char owner[14]; /* bbcall */ + char date[6]; /* birthday */ + char desc[73]; /* list/user description */ + uschar ftype; /* mode: PAL, BAD */ +}; +typedef struct FRIEND FRIEND; diff --git a/util/tran/wd2bmw.c b/util/tran/wd2bmw.c new file mode 100644 index 0000000..36c5a7f --- /dev/null +++ b/util/tran/wd2bmw.c @@ -0,0 +1,131 @@ +/*-------------------------------------------------------*/ +/* util/transbmw.c */ +/*-------------------------------------------------------*/ +/* target : WD ¦Ü Maple 3.02 ¤ô²y°O¿ýÂà´« */ +/* create : 02/01/22 */ +/* update : / / */ +/* author : itoc.bbs@bbs.ee.nctu.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transbmw */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ×§ï transbmw() + + ps. ¨Ï¥Î«e½Ð¥ý¦æ³Æ¥÷¡Ause on ur own risk. µ{¦¡©å¦H½Ð¥]²[ :p + ps. ·PÁ lkchu ªº Maple 3.02 for FreeBSD + +#endif + + +#include "wd.h" + + +/* ----------------------------------------------------- */ +/* 3.02 functions */ +/* ----------------------------------------------------- */ + + +static void +_mail_self(userid, fpath, owner, title) /* itoc.011115: ±HÀÉ®×µ¹¦Û¤v */ + char *userid; /* ¦¬¥óªÌ */ + char *fpath; /* Àɮ׸ô®| */ + char *owner; /* ±H¥ó¤H */ + char *title; /* ¶l¥ó¼ÐÃD */ +{ + HDR fhdr; + char folder[64]; + + usr_fpath(folder, userid, FN_DIR); + close(hdr_stamp(folder, HDR_LINK, &fhdr, fpath)); + str_ncpy(fhdr.owner, owner, sizeof(fhdr.owner)); + str_ncpy(fhdr.title, title, sizeof(fhdr.title)); + fhdr.xmode = 0; + rec_add(folder, &fhdr, sizeof(fhdr)); +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transbmw(userid) + char *userid; +{ + ACCT acct; + int fd; + char buf[64]; + + /* sob ªº usr ¥Ø¿ý¦³¤À¤j¤p¼g¡A©Ò¥Hn¥ý¨ú±o¤j¤p¼g */ + usr_fpath(buf, userid, FN_ACCT); + if ((fd = open(buf, O_RDONLY)) >= 0) + { + read(fd, &acct, sizeof(ACCT)); + close(fd); + } + else + { + return; + } + + sprintf(buf, OLD_BBSHOME"/home/%s/writelog", acct.userid); /* ªº¤ô²y°O¿ý */ + + if (dashf(buf)) + _mail_self(acct.userid, buf, "[³Æ§Ñ¿ý]", "¼ö½u\033[41m°O¿ý\033[m"); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + char c; + char buf[64]; + struct dirent *de; + DIR *dirp; + + /* argc == 1 Âà¥þ³¡¨Ï¥ÎªÌ */ + /* argc == 2 Âà¬Y¯S©w¨Ï¥ÎªÌ */ + + if (argc > 2) + { + printf("Usage: %s [target_user]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (argc == 2) + { + transbmw(argv[1]); + exit(1); + } + + /* Âà´«¨Ï¥ÎªÌ¤ô²y°O¿ý */ + for (c = 'a'; c <= 'z'; c++) + { + sprintf(buf, "usr/%c", c); + + if (!(dirp = opendir(buf))) + continue; + + while (de = readdir(dirp)) + { + char *str; + + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + transbmw(str); + } + + closedir(dirp); + } + return 0; +} diff --git a/util/tran/wd2brd.c b/util/tran/wd2brd.c new file mode 100644 index 0000000..fb7bff3 --- /dev/null +++ b/util/tran/wd2brd.c @@ -0,0 +1,289 @@ +/*-------------------------------------------------------*/ +/* util/transbrd.c */ +/*-------------------------------------------------------*/ +/* target : WD ¦Ü Maple 3.02 ¬ÝªOÂà´« */ +/* .BOARDS => .BRD */ +/* create : 98/06/15 */ +/* update : 02/01/05 */ +/* author : ernie@micro8.ee.nthu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + +#if 0 + + 1. ×§ï struct boardheader ¤Î transbrd() + (boardheader ¨âª©©w¸qªº¦r¦êªø«×¤£¤@¡A½Ð¦Û¦æ´«¦¨¼Æ¦r) + 2. WD ¬ÝªO¤ÀÃþ(boardheader.title «e 4 bytes)±Ë±ó + 3. §ë²¼¤£Âà´« + 4. ¶iªOµe±ª½±µ copy + 5. ¦p¦³»Ýn½Ð chmod 644 `find PATH -perm 600` + 6. ¶} gem ¥Ø¿ý gem/target_board/? ¦ý¤£Âà´« gem + 7. ¤£·|§ó·s bshm¡A¨Ï¥Î«á½Ð¦Û¦æ§ó·s + + ps. Use on ur own risk. + +#endif + + +#include "wd.h" + + +static inline usint +trans_brd_battr(brdattr) /* itoc.010426: Âà´«¬ÝªOÄÝ©Ê */ + usint brdattr; +{ + usint battr; + + battr = 0; + + if (brdattr & 00001) + battr |= BRD_NOZAP; + + if (brdattr & 00002) + battr |= BRD_NOCOUNT; + + if (brdattr & 00004) + battr |= BRD_NOTRAN; + +#ifdef HAVE_ANONYMOUS + if (brdattr & 00100) + battr |= BRD_ANONYMOUS; +#endif + +#ifdef HAVE_MODERATED_BOARD + if (brdattr & (00020 | 01000)) /* ÁôÂêO§ë²¼¤£¤½§i */ + battr |= BRD_NOVOTE; +#endif + + return battr; +} + + +static inline usint +trans_brd_rlevel(brdattr) /* itoc.010426: Âà´«¬ÝªO¾\ŪÅv */ + usint brdattr; +{ +#ifdef HAVE_MODERATED_BOARD + if (brdattr & 00020) /* ÁôÂêO */ + return PERM_SYSOP; + else if (brdattr & 01000) /* ¦n¤ÍªO */ + return PERM_BOARD; + else /* ¤@¯ë¬ÝªO */ +#endif + return 0; +} + + +static inline usint +trans_brd_plevel(brdattr) /* itoc.010426: Âà´«¬ÝªOµoªíÅv */ + usint brdattr; +{ +#ifdef HAVE_MODERATED_BOARD + if (brdattr & 00020) /* ÁôÂêO */ + return 0; + else if (brdattr & 01000) /* ¦n¤ÍªO */ + return 0; + else /* ¤@¯ë¬ÝªO */ +#endif + return PERM_POST; /* ¤@¯ë¬ÝªO¹w³]¬° POST_POST */ +} + + +static inline time_t +trans_hdr_chrono(filename) + char *filename; +{ + char time_str[11]; + + /* M.1087654321.A ©Î M.987654321.A */ + str_ncpy(time_str, filename + 2, filename[2] == '1' ? 11 : 10); + + return (time_t) atoi(time_str); +} + + +static inline void +trans_hdr_stamp(folder, t, hdr, fpath) + char *folder; + time_t t; + HDR *hdr; + char *fpath; +{ + FILE *fp; + char *fname, *family; + int rc; + + fname = fpath; + while (rc = *folder++) + { + *fname++ = rc; + if (rc == '/') + family = fname; + } + fname = family + 1; + *fname++ = '/'; + *fname++ = 'A'; + + for (;;) + { + *family = radix32[t & 31]; + archiv32(t, fname); + + if (fp = fopen(fpath, "r")) + { + fclose(fp); + t++; + } + else + { + memset(hdr, 0, sizeof(HDR)); + hdr->chrono = t; + str_stamp(hdr->date, &hdr->chrono); + strcpy(hdr->xname, --fname); + break; + } + } +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transbrd(bh) + boardheader *bh; +{ + static time_t stamp = 0; + + int fd; + char index[64], folder[64], buf[64], fpath[64]; + fileheader fh; + HDR hdr; + BRD newboard; + time_t chrono; + + printf("Âà´« %s ¬ÝªO\n", bh->brdname); + + brd_fpath(buf, bh->brdname, NULL); + if (dashd(buf)) + { + printf("%s ¤w¸g¦³¦¹¬ÝªO\n", bh->brdname); + return; + } + + if (!stamp) + time(&stamp); + + /* Âà´« .BRD */ + + memset(&newboard, 0, sizeof(newboard)); + str_ncpy(newboard.brdname, bh->brdname, sizeof(newboard.brdname)); + str_ncpy(newboard.class, bh->title, sizeof(newboard.class)); + str_ncpy(newboard.title, bh->title + 7, sizeof(newboard.title)); + str_ncpy(newboard.BM, bh->BM, sizeof(newboard.BM)); + newboard.bstamp = stamp++; + newboard.battr = trans_brd_battr(bh->brdattr); + newboard.readlevel = trans_brd_rlevel(bh->brdattr); + newboard.postlevel = trans_brd_plevel(bh->brdattr); + + rec_add(FN_BRD, &newboard, sizeof(newboard)); /* §O§Ñ¤F¥Î brd2gem.c ¨ÓÂà´« Class */ + + /* ¶}·s¥Ø¿ý */ + + sprintf(fpath, "gem/brd/%s", newboard.brdname); + mak_dirs(fpath); + mak_dirs(fpath + 4); + + /* Âà´«¶iªOµe± */ + + sprintf(buf, OLD_BBSHOME "/boards/%s/notes", bh->brdname); + + if (dashf(buf)) + { + brd_fpath(fpath, newboard.brdname, FN_NOTE); + f_cp(buf, fpath, O_TRUNC); + } + + /* Âà´«¤å³¹ */ + + sprintf(index, OLD_BBSHOME "/boards/%s/.DIR", bh->brdname); /* ªº .DIR */ + brd_fpath(folder, newboard.brdname, ".DIR"); /* ·sªº .DIR */ + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + sprintf(buf, OLD_BBSHOME "/boards/%s/%s", bh->brdname, fh.filename); + if (dashf(buf)) /* ¤å³¹Àɮצb¤~°µÂà´« */ + { + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + trans_hdr_stamp(folder, chrono, &hdr, fpath); + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ansi(hdr.title, fh.title, sizeof(hdr.title)); + hdr.xmode = (fh.filemode & 0x2) ? POST_MARKED : 0; + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + f_cp(buf, fpath, O_TRUNC); + } + } + close(fd); + } +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int fd; + boardheader bh; + + /* argc == 1 Âà¥þ³¡ªO */ + /* argc == 2 Âà¬Y¯S©wªO */ + + if (argc > 2) + { + printf("Usage: %s [target_board]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (!dashf(FN_BOARD)) + { + printf("ERROR! Can't open " FN_BOARD "\n"); + exit(-1); + } + if (!dashd(OLD_BBSHOME "/boards")) + { + printf("ERROR! Can't open " OLD_BBSHOME "/boards\n"); + exit(-1); + } + + if ((fd = open(FN_BOARD, O_RDONLY)) >= 0) + { + while (read(fd, &bh, sizeof(bh)) == sizeof(bh)) + { + if (argc == 1) + { + transbrd(&bh); + } + else if (!strcmp(bh.brdname, argv[1])) + { + transbrd(&bh); + exit(1); + } + } + close(fd); + } + + + + exit(0); +} diff --git a/util/tran/wd2gem.c b/util/tran/wd2gem.c new file mode 100644 index 0000000..8649450 --- /dev/null +++ b/util/tran/wd2gem.c @@ -0,0 +1,232 @@ +/*-------------------------------------------------------*/ +/* util/transman.c */ +/*-------------------------------------------------------*/ +/* target : Ptt WD ¦Ü Maple 3.02 ºëµØ°ÏÂà´« */ +/* create : 98/06/15 */ +/* update : 02/01/05 */ +/* author : ernie@micro8.ee.nthu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + 0. ¾A¥Î WD Ptt Âà maple ºëµØ°Ï¡C + 1. µ{¦¡¤£¶}¥Ø¿ý¡A¨Ï¥Î«e¥ý½T©w gem/target_board/? ¥Ø¿ý¦s¦b + if not¡A¥ý¶}·sªO or transbrd + 2. ¥uÂà M.*.A ¤Î D.*.A¡A¨ä¥L link ¤£Âà´« + 3. ¦p¦³»Ýn½Ð¥ý chmod 644 `find PATH -perm 600` + + ps. User on ur own risk. + +#endif + + +#include "wd.h" + + +/* ----------------------------------------------------- */ +/* Âà´«ºëµØ°Ï */ +/* ----------------------------------------------------- */ + + +static time_t +trans_hdr_chrono(filename) + char *filename; +{ + char time_str[11]; + + /* M.1087654321.A ©Î M.987654321.A */ + str_ncpy(time_str, filename + 2, filename[2] == '1' ? 11 : 10); + + return (time_t) atoi(time_str); +} + + +static void +trans_man_stamp(folder, token, hdr, fpath, time) + char *folder; + int token; + HDR *hdr; + char *fpath; + time_t time; +{ + char *fname, *family; + int rc; + + fname = fpath; + while (rc = *folder++) + { + *fname++ = rc; + if (rc == '/') + family = fname; + } + if (*family != '.') + { + fname = family; + family -= 2; + } + else + { + fname = family + 1; + *fname++ = '/'; + } + + *fname++ = token; + + *family = radix32[time & 31]; + archiv32(time, fname); + + if (rc = open(fpath, O_WRONLY | O_CREAT | O_EXCL, 0600)) + { + memset(hdr, 0, sizeof(HDR)); + hdr->chrono = time; + str_stamp(hdr->date, &hdr->chrono); + strcpy(hdr->xname, --fname); + close(rc); + } + return; +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transman(index, folder) + char *index, *folder; +{ + static int count = 100; + + int fd; + char *ptr, buf[256], fpath[64]; + fileheader fh; + HDR hdr; + time_t chrono; + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + strcpy(buf, index); + ptr = strrchr(buf, '/') + 1; + strcpy(ptr, fh.filename); + + if (*fh.filename == 'M' && dashf(buf)) /* ¥uÂà M.xxxx.A ¤Î D.xxxx.a */ + { + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + trans_man_stamp(folder, 'A', &hdr, fpath, chrono); + hdr.xmode = 0; + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ncpy(hdr.title, fh.title + 3, sizeof(hdr.title)); + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + f_cp(buf, fpath, O_TRUNC); + } + else if (*fh.filename == 'D' && dashd(buf)) + { + char sub_index[256]; + + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = ++count; /* WD ªº¥Ø¿ý©R¦W¤ñ¸û©_©Ç¡A¥u¦n¦Û¤vµ¹¼Æ¦r */ + trans_man_stamp(folder, 'F', &hdr, fpath, chrono); + hdr.xmode = GEM_FOLDER; + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ncpy(hdr.title, fh.title + 3, sizeof(hdr.title)); + rec_add(folder, &hdr, sizeof(HDR)); + + /* recursive ¶i¥hÂà´«¤l¥Ø¿ý */ + strcpy(sub_index, buf); + ptr = strrchr(sub_index, '/') + 1; + sprintf(ptr, "%s/.DIR", fh.filename); + transman(sub_index, fpath); + } + } + close(fd); + } +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int fd; + char *brdname, index[64], folder[64]; + boardheader bh; + + /* argc == 1 Âà¥þ³¡ªO */ + /* argc == 2 Âà¬Y¯S©wªO */ + + if (argc > 2) + { + printf("Usage: %s [target_board]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (!dashf(FN_BOARD)) + { + printf("ERROR! Can't open " FN_BOARD "\n"); + exit(-1); + } + if (!dashd(OLD_BBSHOME "/man/boards")) + { + printf("ERROR! Can't open " OLD_BBSHOME "/man/boards\n"); + exit(-1); + } + + if (argc == 1) + { + if ((fd = open(FN_BOARD, O_RDONLY)) >= 0) + { + while (read(fd, &bh, sizeof(bh)) == sizeof(bh)) + { + brdname = bh.brdname; + + sprintf(folder, "gem/brd/%s", brdname); + if (!dashd(folder)) + { + printf("ERROR! %s not exist. New it first.\n", folder); + continue; + } + + sprintf(index, OLD_BBSHOME "/man/boards/%s/.DIR", brdname); + sprintf(folder, "gem/brd/%s/%s", brdname, FN_DIR); + + printf("Âà´« %s ºëµØ°Ï\n", brdname); + transman(index, folder); + } + close(fd); + } + } + else + { + brdname = argv[1]; + + sprintf(folder, "gem/brd/%s", brdname); + if (!dashd(folder)) + { + printf("ERROR! %s not exist. New it first.\n", folder); + exit(-1); + } + + sprintf(index, OLD_BBSHOME "/man/boards/%s/.DIR", brdname); + sprintf(folder, "gem/brd/%s/%s", brdname, FN_DIR); + + printf("Âà´« %s ºëµØ°Ï\n", brdname); + transman(index, folder); + + exit(1); + } + + exit(0); +} diff --git a/util/tran/wd2list.c b/util/tran/wd2list.c new file mode 100644 index 0000000..235b9b1 --- /dev/null +++ b/util/tran/wd2list.c @@ -0,0 +1,172 @@ +/*-------------------------------------------------------*/ +/* util/translist.c */ +/*-------------------------------------------------------*/ +/* target : WD ¦Ü Maple 3.02 ¯S®í¦W³æÂà´« */ +/* create : 02/01/26 */ +/* update : / / */ +/* author : itoc.bbs@bbs.ee.nctu.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : translist */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ×§ï translist() + 2. ¥uÂà list.1 ~ list.5 + + ps. ¨Ï¥Î«e½Ð¥ý¦æ³Æ¥÷¡Ause on ur own risk. µ{¦¡©å¦H½Ð¥]²[ :p + ps. ·PÁ lkchu ªº Maple 3.02 for FreeBSD + +#endif + + +#include "wd.h" + +#ifdef HAVE_LIST + +/* ----------------------------------------------------- */ +/* 3.02 functions */ +/* ----------------------------------------------------- */ + + +static int +acct_uno(userid) + char *userid; +{ + int fd; + int userno; + char fpath[64]; + + usr_fpath(fpath, userid, FN_ACCT); + fd = open(fpath, O_RDONLY); + if (fd >= 0) + { + read(fd, &userno, sizeof(userno)); + close(fd); + return userno; + } + return -1; +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +translist(userid) + char *userid; +{ + ACCT acct; + int pos, fd, friend_userno, i; + char fpath[64], buf[64]; + PAL pal; + FRIEND friend; + + /* sob ªº usr ¥Ø¿ý¦³¤À¤j¤p¼g¡A©Ò¥Hn¥ý¨ú±o¤j¤p¼g */ + usr_fpath(buf, userid, FN_ACCT); + if ((fd = open(buf, O_RDONLY)) >= 0) + { + read(fd, &acct, sizeof(ACCT)); + close(fd); + } + + for (i = 1; i <= 5; i++) /* ¥uÂà list.1 ~ list.5 */ + { + sprintf(buf, "%s.%d", FN_LIST, i); + usr_fpath(fpath, userid, buf); /* ·sªº¯S®í¦W³æ */ + sprintf(buf, OLD_BBSHOME "/home/%s/list.%d", acct.userid, i);/* ªº¯S®í¦W³æ */ + + if (dashf(fpath)) + unlink(fpath); /* ²M±¼««Ø */ + + pos = 0; + fd = open(buf, O_RDONLY); + if (fd < 0) + continue; + + while (fd) + { + lseek(fd, (off_t) (sizeof(FRIEND) * pos), SEEK_SET); + if (read(fd, &friend, sizeof(FRIEND)) == sizeof(FRIEND)) + { + if ((friend_userno = acct_uno(friend.userid)) >= 0) + { + str_ncpy(pal.userid, friend.userid, sizeof(pal.userid)); + pal.ftype = 0; /* ¯S®í¦W³æ¤@«ß¬°¦n¤Í */ + str_ncpy(pal.ship, friend.desc, sizeof(pal.ship)); + pal.userno = friend_userno; + rec_add(fpath, &pal, sizeof(PAL)); + } + pos++; + } + else + { + close(fd); + break; + } + } + } +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + char c; + char buf[64]; + struct dirent *de; + DIR *dirp; + + /* argc == 1 Âà¥þ³¡¨Ï¥ÎªÌ */ + /* argc == 2 Âà¬Y¯S©w¨Ï¥ÎªÌ */ + + if (argc > 2) + { + printf("Usage: %s [target_user]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (argc == 2) + { + translist(argv[1]); + exit(1); + } + + /* Âà´«¨Ï¥ÎªÌ¯S®í¦W³æ */ + for (c = 'a'; c <= 'z'; c++) + { + sprintf(buf, "usr/%c", c); + + if (!(dirp = opendir(buf))) + continue; + + while (de = readdir(dirp)) + { + char *str; + + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + translist(str); + } + + closedir(dirp); + } + return 0; +} +#else +int +main() +{ + printf("You should define HAVE_LIST first.\n"); + return -1; +} +#endif /* HAVE_LIST */ diff --git a/util/tran/wd2mf.c b/util/tran/wd2mf.c new file mode 100644 index 0000000..c08c230 --- /dev/null +++ b/util/tran/wd2mf.c @@ -0,0 +1,171 @@ +/*-------------------------------------------------------*/ +/* util/transfavor.c */ +/*-------------------------------------------------------*/ +/* target : WD ¦Ü Maple 3.02 §Úªº³Ì·RÂà´« */ +/* create : 01/09/15 */ +/* update : / / */ +/* author : itoc.bbs@bbs.ee.nctu.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transfavor */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ×§ï transmf() + 2. Âà´«(¬ÝªO)¦n¤Í¦W³æ¤§«e¡A±z¥²¶·¥ýÂà´«§¹¬ÝªO¤Î¨Ï¥ÎªÌ¡C + + ps. ¨Ï¥Î«e½Ð¥ý¦æ³Æ¥÷¡Ause on ur own risk. µ{¦¡©å¦H½Ð¥]²[ :p + ps. ·PÁ lkchu ªº Maple 3.02 for FreeBSD + +#endif + + +#include "wd.h" + +#ifdef MY_FAVORITE + + +/* ----------------------------------------------------- */ +/* 3.02 functions */ +/* ----------------------------------------------------- */ + + +static void +_mf_fpath(fpath, userid, fname) + char *fpath; + char *userid; /* lower ID */ + char *fname; +{ + if (fname) + sprintf(fpath, "usr/%c/%s/MF/%s", userid[0], userid, fname); + else + sprintf(fpath, "usr/%c/%s/MF", userid[0], userid); +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transmf(userid) + char *userid; +{ + ACCT acct; + FILE *fp; + int fd, num; + char fpath[64], buf[64]; + char *str, brdname[BNLEN + 1]; + MF mf; + + /* «Ø¥ß¥Ø¿ý */ + _mf_fpath(fpath, userid, NULL); + mkdir(fpath, 0700); + + /* sob ªº usr ¥Ø¿ý¦³¤À¤j¤p¼g¡A©Ò¥Hn¥ý¨ú±o¤j¤p¼g */ + usr_fpath(buf, userid, FN_ACCT); + if ((fd = open(buf, O_RDONLY)) >= 0) + { + read(fd, &acct, sizeof(ACCT)); + close(fd); + } + else + { + return; + } + + sprintf(buf, OLD_BBSHOME"/home/%s/favorite", acct.userid); /* ªº§Úªº³Ì·R */ + + if (!(fp = fopen(buf, "r"))) + return; + + _mf_fpath(fpath, userid, FN_MF); + num = 0; + + while (fgets(brdname, BNLEN + 1, fp)) + { + for (str = brdname; *str; str++) + { + if (*str <= ' ') + { + *str = '\0'; + break; + } + } + + brd_fpath(buf, brdname, NULL); + if (dashd(buf)) /* ªº½T¦³³oÓªO */ + { + mf.chrono = ++num; + mf.mftype = MF_BOARD; + str_ncpy(mf.xname, brdname, sizeof(mf.xname)); + mf.title[0] = '\0'; /* ¬ÝªO±¶®|¨S¦³ mf.title */ + rec_add(fpath, &mf, sizeof(MF)); + } + } + + fclose(fp); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + char c; + char buf[64]; + struct dirent *de; + DIR *dirp; + + /* argc == 1 Âà¥þ³¡¨Ï¥ÎªÌ¤Î¬ÝªO */ + /* argc == 2 Âà¬Y¯S©w¨Ï¥ÎªÌ */ + + if (argc > 2) + { + printf("Usage: %s [target_user]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (argc == 2) + { + transmf(argv[1]); + exit(1); + } + + /* Âà´«¨Ï¥ÎªÌ§Úªº³Ì·R */ + for (c = 'a'; c <= 'z'; c++) + { + sprintf(buf, "usr/%c", c); + + if (!(dirp = opendir(buf))) + continue; + + while (de = readdir(dirp)) + { + char *str; + + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + transmf(str); + } + + closedir(dirp); + } + return 0; +} + +#else +int +main() +{ + printf("You should define MY_FAVORITE first.\n"); + return -1; +} +#endif /* MY_FAVORITE */ diff --git a/util/tran/wd2pal.c b/util/tran/wd2pal.c new file mode 100644 index 0000000..c1f1d75 --- /dev/null +++ b/util/tran/wd2pal.c @@ -0,0 +1,213 @@ +/*-------------------------------------------------------*/ +/* util/transpal.c */ +/*-------------------------------------------------------*/ +/* target : WD ¦Ü Maple 3.02 (¬ÝªO)¦n¤Í¦W³æÂà´« */ +/* create : 01/09/08 */ +/* update : / / */ +/* author : itoc.bbs@bbs.ee.nctu.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transpal */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ×§ï struct FRIEND ©M transpal() transbrdpal() + 2. Âà´«(¬ÝªO)¦n¤Í¦W³æ¤§«e¡A±z¥²¶·¥ýÂà´«§¹¬ÝªO¤Î¨Ï¥ÎªÌ¡C + + ps. ¨Ï¥Î«e½Ð¥ý¦æ³Æ¥÷¡Ause on ur own risk. µ{¦¡©å¦H½Ð¥]²[ :p + ps. ·PÁ lkchu ªº Maple 3.02 for FreeBSD + +#endif + + +#include "wd.h" + + +/* ----------------------------------------------------- */ +/* 3.02 functions */ +/* ----------------------------------------------------- */ + + +static int +acct_uno(userid) + char *userid; +{ + int fd; + int userno; + char fpath[64]; + + usr_fpath(fpath, userid, FN_ACCT); + fd = open(fpath, O_RDONLY); + if (fd >= 0) + { + read(fd, &userno, sizeof(userno)); + close(fd); + return userno; + } + return -1; +} + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transpal(userid) + char *userid; +{ + ACCT acct; + int fd, friend_userno; + char fpath[64], buf[64]; + PAL pal; + FRIEND friend; + + usr_fpath(fpath, userid, FN_PAL); /* ·sªº¦n¤Í¦W³æ */ + + /* sob ªº usr ¥Ø¿ý¦³¤À¤j¤p¼g¡A©Ò¥Hn¥ý¨ú±o¤j¤p¼g */ + usr_fpath(buf, userid, FN_ACCT); + if ((fd = open(buf, O_RDONLY)) >= 0) + { + read(fd, &acct, sizeof(ACCT)); + close(fd); + } + else + { + return; + } + + sprintf(buf, OLD_BBSHOME "/home/%s/pal", acct.userid); /* ªº¦n¤Í¦W³æ */ + + if (dashf(fpath)) + unlink(fpath); /* ²M±¼««Ø */ + + if ((fd = open(buf, O_RDONLY)) < 0) + return; + + while (read(fd, &friend, sizeof(FRIEND)) == sizeof(FRIEND)) + { + if ((friend_userno = acct_uno(friend.userid)) >= 0 && + strcmp(friend.userid, acct.userid)) + { + memset(&pal, 0, sizeof(PAL)); + str_ncpy(pal.userid, friend.userid, sizeof(pal.userid)); + pal.ftype = (friend.savemode & 0x02) ? 0 : PAL_BAD; /* ¦n¤Í vs ·l¤Í */ + str_ncpy(pal.ship, friend.desc, sizeof(pal.ship)); + pal.userno = friend_userno; + rec_add(fpath, &pal, sizeof(PAL)); + } + } + close(fd); +} + + +static void +transbrdpal(brdname) + char *brdname; +{ + int pos, fd, friend_userno; + char fpath[64], buf[64]; + PAL pal; + FRIEND friend; + + brd_fpath(fpath, brdname, FN_PAL); /* ·sªº¦n¤Í¦W³æ */ + sprintf(buf, OLD_BBSHOME "/boards/%s/.LIST", brdname);/* ªº¦n¤Í¦W³æ */ + + if (dashf(fpath)) + unlink(fpath); /* ²M±¼««Ø */ + + pos = 0; + if ((fd = open(buf, O_RDONLY)) < 0) + return; + + while (fd) + { + lseek(fd, (off_t) (sizeof(FRIEND) * pos), SEEK_SET); + if (read(fd, &friend, sizeof(FRIEND)) == sizeof(FRIEND)) + { + if ((friend_userno = acct_uno(friend.userid)) >= 0) + { + memset(&pal, 0, sizeof(PAL)); + str_ncpy(pal.userid, friend.userid, sizeof(pal.userid)); + pal.ftype = 0; /* ¬ÝªO¦n¤Í¤@©w¬O¦n¤Í */ + str_ncpy(pal.ship, friend.desc, sizeof(pal.ship)); + pal.userno = friend_userno; + rec_add(fpath, &pal, sizeof(PAL)); + } + pos++; + } + else + { + close(fd); + break; + } + } +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + char c, *str; + char buf[64]; + struct dirent *de; + DIR *dirp; + + /* argc == 1 Âà¥þ³¡¨Ï¥ÎªÌ¤Î¬ÝªO */ + /* argc == 2 Âà¬Y¯S©w¨Ï¥ÎªÌ */ + + if (argc > 2) + { + printf("Usage: %s [target_user]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (argc == 2) + { + transpal(argv[1]); + exit(1); + } + + /* Âà´«¨Ï¥ÎªÌ¦n¤Í¦W³æ */ + for (c = 'a'; c <= 'z'; c++) + { + sprintf(buf, "usr/%c", c); + + if (!(dirp = opendir(buf))) + continue; + + while (de = readdir(dirp)) + { + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + transpal(str); + } + + closedir(dirp); + } + + /* Âà´«¬ÝªO¦n¤Í¦W³æ */ + if (!(dirp = opendir("brd"))) + return 0; + + while (de = readdir(dirp)) + { + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + transbrdpal(str); + } + + closedir(dirp); + + return 0; +} diff --git a/util/tran/wd2pip.c b/util/tran/wd2pip.c new file mode 100644 index 0000000..82041db --- /dev/null +++ b/util/tran/wd2pip.c @@ -0,0 +1,498 @@ +/*-------------------------------------------------------*/ +/* util/transpip.c */ +/*-------------------------------------------------------*/ +/* target : WD ¦Ü Maple 3.02 ¤pÂû¸ê®ÆÂà´« */ +/* create : 02/01/26 */ +/* update : / / */ +/* author : itoc.bbs@bbs.ee.nctu.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transpip */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ×§ï transpip() + 2. ¥uÂà chicken¡Achicken.bak* ´N¤£Âà¤F + + ps. ¨Ï¥Î«e½Ð¥ý¦æ³Æ¥÷¡Ause on ur own risk. µ{¦¡©å¦H½Ð¥]²[ :p + ps. ·PÁ lkchu ªº Maple 3.02 for FreeBSD + +#endif + + +#include "wd.h" + +#ifdef HAVE_GAME + +#include "../../pip/pipstruct.h" /* ¤Þ¤J·s¤pÂûªº°Ñ¼Æ³]©w */ + + +/* ----------------------------------------------------- */ +/* ¤pÂû°Ñ¼Æ³]©w */ +/* ----------------------------------------------------- */ + + +struct chicken +{ + /* ---°ò¥»ªº¸ê®Æ--- */ + char name[20]; /* ©m ¦W */ + char birth[21]; /* ¥Í ¤é */ + int year; /* ¥Í¤é ¦~ */ + int month; /* ¥Í¤é ¤ë */ + int day; /* ¥Í¤é ¤é */ + int sex; /* ©Ê §O 1:¡ñ 2:¡ð */ + int death; /* 1: ¦º¤` 2:©ß±ó 3:µ²§½ */ + int nodone; /* 1: ¥¼°µ */ + int relation; /* ¨â¤HÃö«Y */ + int liveagain; /* ´_¬¡¦¸¼Æ */ + int dataB; + int dataC; + int dataD; + int dataE; + + /* ---¨Å骺°Ñ¼Æ--- */ + int hp; /* Åé ¤O */ + int maxhp; /* ³Ì¤jÅé¤O */ + int weight; /* Åé « */ + int tired; /* ¯h ³Ò «× */ + int sick; /* ¯f ®ð */ + int shit; /* ²M ¼ä «× */ + int wrist; /* µÃ ¤O */ + int bodyA; + int bodyB; + int bodyC; + int bodyD; + int bodyE; + + /* ---µû»ùªº°Ñ¼Æ--- */ + int social; /* ªÀ¥æµû»ù */ + int family; /* ®a¨Æµû»ù */ + int hexp; /* ¾Ô°«µû»ù */ + int mexp; /* Å]ªkµû»ù */ + int tmpA; + int tmpB; + int tmpC; + int tmpD; + int tmpE; + + /* ---¾Ô°«¥Î°Ñ¼Æ--- */ + int mp; /* ªk ¤O */ + int maxmp; /* ³Ì¤jªk¤O */ + int attack; /* §ð À» ¤O */ + int resist; /* ¨¾ ¿m ¤O */ + int speed; /* ³t «× */ + int hskill; /* ¾Ô°«§Þ³N */ + int mskill; /* Å]ªk§Þ³N */ + int mresist; /* §ÜÅ]¯à¤O */ + int magicmode; /* Å]ªk«¬ºA */ + int fightB; + int fightC; + int fightD; + int fightE; + + + /* ---ªZ¾¹ªº°Ñ¼Æ--- */ + int weaponhead; /* ÀY³¡ªZ¾¹ */ + int weaponrhand; /* ¥k¤âªZ¾¹ */ + int weaponlhand; /* ¥ª¤âªZ¾¹ */ + int weaponbody; /* ¨ÅéªZ¾¹ */ + int weaponfoot; /* ¸}ªºªZ¾¹ */ + int weaponA; + int weaponB; + int weaponC; + int weaponD; + int weaponE; + + /* ---¦U¯à¤O°Ñ¼Æ--- */ + int toman; /* «Ý¤H±µª« */ + int character; /* ®ð ½è «× */ + int love; /* ·R ¤ß */ + int wisdom; /* ´¼ ¼z */ + int art; /* ÃÀ³N¯à¤O */ + int etchics; /* ¹D ¼w */ + int brave; /* «i ´± */ + int homework; /* ±½¦a¬~¦ç */ + int charm; /* ¾y ¤O */ + int manners; /* § »ö */ + int speech; /* ½Í ¦R */ + int cookskill; /* ²i ¶¹ */ + int learnA; + int learnB; + int learnC; + int learnD; + int learnE; + + + /* ---¦Uª¬ºA¼ÆÈ--- */ + int happy; /* §Ö ¼Ö «× */ + int satisfy; /* º¡ ·N «× */ + int fallinlove; /* ÅÊ·R«ü¼Æ */ + int belief; /* «H ¥õ */ + int offense; /* ¸o Ä^ */ + int affect; /* ·P ¨ü */ + int stateA; + int stateB; + int stateC; + int stateD; + int stateE; + + /* ---¦YªºªF¦è°Õ--- */ + int food; /* ¹ ª« */ + int medicine; /* ÆF ªÛ */ + int bighp; /* ¤j ¸É ¤Y */ + int cookie; /* ¹s ¹ */ + int ginseng; /* ¤d¦~¤Hçx */ + int snowgrass; /* ¤Ñ¤s³·½¬ */ + int eatC; + int eatD; + int eatE; + + /* ---¾Ö¦³ªºªF¦è--- */ + int book; /* ®Ñ ¥» */ + int playtool; /* ª± ¨ã */ + int money; /* ª÷ ¿ú */ + int thingA; + int thingB; + int thingC; + int thingD; + int thingE; + + /* ---²q®±ªº°Ñ¼Æ--- */ + int winn; + int losee; + + /* ---°Ñ¨£¤ý¦Ú-- */ + int royalA; /* from¦u½Ã */ + int royalB; /* fromªñ½Ã */ + int royalC; /* from±Nx */ + int royalD; /* from¤j¦Ú */ + int royalE; /* from²½¥q */ + int royalF; /* fromÃd¦m */ + int royalG; /* from¤ý¦m */ + int royalH; /* from°ê¤ý */ + int royalI; /* from¤p¤¡ */ + int royalJ; /* from¤ý¤l */ + int seeroyalJ; /* ¬O§_¤w¸g¬Ý¹L¤ý¤l¤F */ + int seeA; + int seeB; + int seeC; + int seeD; + int seeE; + + /* ---µ²§½---- */ + int wantend; /* 20·³µ²§½ 1:¤£n¥B¥¼±B 2:¤£n¥B¤w±B 3:¤£n¥B·í²Ä¤TªÌ 4:n¥B¥¼±B 5:n¥B¤w±B 6:n¥B·í²Ä¤TªÌ */ + int lover; /* ·R¤H 0:¨S¦³ 1:Å]¤ý 2:Às±Ú 3:A 4:B 5:C 6:D 7:E */ + + /* -------¤u§@¦¸¼Æ-------- */ + int workA; /* ®a¨Æ */ + int workB; /* «O©i */ + int workC; /* ®È©± */ + int workD; /* ¹A³õ */ + int workE; /* À\ÆU */ + int workF; /* ±Ð°ó */ + int workG; /* ¦aÅu */ + int workH; /* ¥ï¤ì */ + int workI; /* ¬ü¾v */ + int workJ; /* Ây¤H */ + int workK; /* ¤u¦a */ + int workL; /* ¦u¹Ó */ + int workM; /* ®a±Ð */ + int workN; /* °s®a */ + int workO; /* °s©± */ + int workP; /* ©]Á`·| */ + int workQ; + int workR; + int workS; + int workT; + int workU; + int workV; + int workW; + int workX; + int workY; + int workZ; + + /* -------¤W½Ò¦¸¼Æ-------- */ + int classA; + int classB; + int classC; + int classD; + int classE; + int classF; + int classG; + int classH; + int classI; + int classJ; + int classK; + int classL; + int classM; + int classN; + int classO; + + /* ---¤pÂûªº®É¶¡--- */ + time_t bbtime; +}; +typedef struct chicken chicken; + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transpip(userid) + char *userid; +{ + ACCT acct; + int fd; + char fpath[64]; + FILE *fp; + struct chicken d; /* ¤pÂû */ + struct CHICKEN p; /* ·s¤pÂû */ + + + /* sob ªº usr ¥Ø¿ý¦³¤À¤j¤p¼g¡A©Ò¥Hn¥ý¨ú±o¤j¤p¼g */ + usr_fpath(fpath, userid, FN_ACCT); + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + read(fd, &acct, sizeof(ACCT)); + close(fd); + } + sprintf(fpath, OLD_BBSHOME "/home/%s/chicken", acct.userid); /* ªº¤pÂû¸ê®Æ */ + + if (fp = fopen(fpath, "r")) + { + /* Ū¥X¤pÂû¸ê®Æ */ + + fgets(fpath, 20, fp); + d.bbtime = (time_t) atoi(fpath); + + fscanf(fp, + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %d %d", + &(d.year), &(d.month), &(d.day), &(d.sex), &(d.death), &(d.nodone), &(d.relation), &(d.liveagain), &(d.dataB), &(d.dataC), &(d.dataD), &(d.dataE), + &(d.hp), &(d.maxhp), &(d.weight), &(d.tired), &(d.sick), &(d.shit), &(d.wrist), &(d.bodyA), &(d.bodyB), &(d.bodyC), &(d.bodyD), &(d.bodyE), + &(d.social), &(d.family), &(d.hexp), &(d.mexp), &(d.tmpA), &(d.tmpB), &(d.tmpC), &(d.tmpD), &(d.tmpE), + &(d.mp), &(d.maxmp), &(d.attack), &(d.resist), &(d.speed), &(d.hskill), &(d.mskill), &(d.mresist), &(d.magicmode), &(d.fightB), &(d.fightC), &(d.fightD), &(d.fightE), + &(d.weaponhead), &(d.weaponrhand), &(d.weaponlhand), &(d.weaponbody), &(d.weaponfoot), &(d.weaponA), &(d.weaponB), &(d.weaponC), &(d.weaponD), &(d.weaponE), + &(d.toman), &(d.character), &(d.love), &(d.wisdom), &(d.art), &(d.etchics), &(d.brave), &(d.homework), &(d.charm), &(d.manners), &(d.speech), &(d.cookskill), &(d.learnA), &(d.learnB), &(d.learnC), &(d.learnD), &(d.learnE), + &(d.happy), &(d.satisfy), &(d.fallinlove), &(d.belief), &(d.offense), &(d.affect), &(d.stateA), &(d.stateB), &(d.stateC), &(d.stateD), &(d.stateE), + &(d.food), &(d.medicine), &(d.bighp), &(d.cookie), &(d.ginseng), &(d.snowgrass), &(d.eatC), &(d.eatD), &(d.eatE), + &(d.book), &(d.playtool), &(d.money), &(d.thingA), &(d.thingB), &(d.thingC), &(d.thingD), &(d.thingE), + &(d.winn), &(d.losee), + &(d.royalA), &(d.royalB), &(d.royalC), &(d.royalD), &(d.royalE), &(d.royalF), &(d.royalG), &(d.royalH), &(d.royalI), &(d.royalJ), &(d.seeroyalJ), &(d.seeA), &(d.seeB), &(d.seeC), &(d.seeD), &(d.seeE), + &(d.wantend), &(d.lover), d.name, + &(d.classA), &(d.classB), &(d.classC), &(d.classD), &(d.classE), + &(d.classF), &(d.classG), &(d.classH), &(d.classI), &(d.classJ), + &(d.classK), &(d.classL), &(d.classM), &(d.classN), &(d.classO), + &(d.workA), &(d.workB), &(d.workC), &(d.workD), &(d.workE), + &(d.workF), &(d.workG), &(d.workH), &(d.workI), &(d.workJ), + &(d.workK), &(d.workL), &(d.workM), &(d.workN), &(d.workO), + &(d.workP), &(d.workQ), &(d.workR), &(d.workS), &(d.workT), + &(d.workU), &(d.workV), &(d.workW), &(d.workX), &(d.workY), &(d.workZ)); + + fclose(fp); + + /* Âà´«¤pÂû¸ê®Æ */ + + memset(&p, 0, sizeof(p)); + + str_ncpy(p.name, d.name, sizeof(p.name)); + sprintf(p.birth, "%02d/%02d/%02d", d.year % 100, d.month, d.day); + + p.bbtime = d.bbtime; + + p.year = d.year; + p.month = d.month; + p.day = d.day; + p.sex = d.sex; + p.death = d.death; + p.liveagain = d.liveagain; + p.wantend = d.wantend; + p.lover = d.lover; + p.seeroyalJ = d.seeroyalJ; + p.quest = 0; /* ¹q¤lÂû¨S¦³¥ô°È */ + + p.relation = d.relation; + p.happy = d.happy; + p.satisfy = p.satisfy; + p.fallinlove = d.fallinlove; + p.belief = d.belief; + p.sin = d.offense; + p.affect = d.affect; + + p.weight = d.weight; + p.tired = d.tired; + p.sick = d.sick; + p.shit = d.shit; + + p.social = d.social; + p.family = d.family; + p.hexp = d.hexp; + p.mexp = d.mexp; + + p.toman = d.toman; + p.character = d.character; + p.love = d.love; + p.wisdom = d.wisdom; + p.art = d.art; + p.etchics = d.etchics; + p.brave = d.brave; + p.homework = d.homework; + p.charm = d.charm; + p.manners = d.manners; + p.speech = d.speech; + p.cook = d.cookskill; + p.attack = d.attack; + p.resist = d.resist; + p.speed = d.speed; + p.hskill = d.hskill; + p.mskill = d.mskill; + p.immune = d.mresist; + + p.level = 1; /* ±q 1 ¯Å¶}©l */ + p.exp = 0; + p.hp = d.hp; + p.maxhp = d.maxhp; + p.mp = d.mp; + p.maxmp = d.maxmp; + p.vp = d.hp; /* ¹q¤lÂû¨S¦³ vp/sp ®³ hp/mp ¨Ó®M */ + p.maxvp = d.maxhp; + p.sp = d.mp; + p.maxsp = d.maxmp; + + /* ¹q¤lÂû¨S¦³§Þ¯à¡A¹w³]¬° 0 */ + + /* ªZ¾¹³q³q«¸m¬° 0¡A¥H§KªZ¾¹¦Cªí¤£¦P */ + + p.food = d.food; + p.cookie = d.cookie; + p.pill = 0; + p.medicine = d.medicine; + p.burger = d.bighp; + p.ginseng = d.ginseng; + p.paste = 0; + p.snowgrass = d.snowgrass; + + p.money = d.money; + p.book = d.book; + p.toy = d.playtool; + p.playboy = 0; + + p.royalA = d.royalA; + p.royalB = d.royalB; + p.royalC = d.royalC; + p.royalD = d.royalD; + p.royalE = d.royalE; + p.royalF = d.royalF; + p.royalG = d.royalG; + p.royalH = d.royalH; + p.royalI = d.royalI; + p.royalJ = d.royalJ; + + p.workA = d.workA; + p.workB = d.workB; + p.workC = d.workC; + p.workD = d.workD; + p.workE = d.workE; + p.workF = d.workF; + p.workG = d.workG; + p.workH = d.workH; + p.workI = d.workI; + p.workJ = d.workJ; + p.workK = d.workK; + p.workL = d.workL; + p.workM = d.workM; + p.workN = d.workN; + p.workO = d.workO; + p.workP = d.workP; + + p.winn = d.winn; + p.losee = d.losee; + p.classA = d.classA; + p.classB = d.classB; + p.classC = d.classC; + p.classD = d.classD; + p.classE = d.classE; + p.classF = d.classF; + p.classG = d.classG; + p.classH = d.classH; + p.classI = d.classI; + p.classJ = d.classJ; + + /* ¼g¤J·s¤pÂû¸ê®Æ */ + + usr_fpath(fpath, acct.userid, "chicken"); /* ·sªº¤pÂû¸ê®Æ */ + fd = open(fpath, O_WRONLY | O_CREAT, 0600); + write(fd, &p, sizeof(CHICKEN)); + close(fd); + } +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + char c; + char buf[64]; + struct dirent *de; + DIR *dirp; + + /* argc == 1 Âà¥þ³¡¨Ï¥ÎªÌ */ + /* argc == 2 Âà¬Y¯S©w¨Ï¥ÎªÌ */ + + if (argc > 2) + { + printf("Usage: %s [target_user]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (argc == 2) + { + transpip(argv[1]); + exit(1); + } + + /* Âà´«¨Ï¥ÎªÌ¤pÂû¸ê®Æ */ + for (c = 'a'; c <= 'z'; c++) + { + sprintf(buf, "usr/%c", c); + + if (!(dirp = opendir(buf))) + continue; + + while (de = readdir(dirp)) + { + char *str; + + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + transpip(str); + } + + closedir(dirp); + } + return 0; +} +#else +int +main() +{ + printf("You should define HAVE_GAME first.\n"); + return -1; +} +#endif /* HAVE_GAME */ diff --git a/util/tran/wd2usr.c b/util/tran/wd2usr.c new file mode 100644 index 0000000..ea4143b --- /dev/null +++ b/util/tran/wd2usr.c @@ -0,0 +1,597 @@ +/*-------------------------------------------------------*/ +/* util/transusr.c */ +/*-------------------------------------------------------*/ +/* target : WD ¦Ü Maple 3.02 ¨Ï¥ÎªÌÂà´« */ +/* .PASSWDS => .USR .ACCT */ +/* create : 98/06/14 */ +/* update : 02/01/05 */ +/* author : ernie@micro8.ee.nthu.edu.tw */ +/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ×§ï struct userec ¤Î creat_dirs() + (userec ¨âª©©w¸qªº¦r¦êªø«×¤£¤@¡A½Ð¦Û¦æ´«¦¨¼Æ¦r) + 2. °£ plans ÀɦW¡A¦n¤Í¦W³æ¡B¼È¦sÀɵ¥³£¤£Âà´« + 3. Sob ¦³¤EÓñ¦WÀÉ¡A¥uÂà«e¤TÓ + 4. «H½c¤¤ªº internet mail ¦p¦³»Ýn½Ð¥ý chmod 644 `find PATH -perm 600` + + ps. ¨Ï¥Î«e½Ð¥ý¦æ³Æ¥÷¡Ause on ur own risk. µ{¦¡©å¦H½Ð¥]²[ :p + ps. ·PÁ lkchu ªº Maple 3.02 for FreeBSD + +#endif + + +#include "wd.h" + + +/* ----------------------------------------------------- */ +/* Âà´« .ACCT */ +/* ----------------------------------------------------- */ + + +static inline int +is_bad_userid(userid) + char *userid; +{ + register char ch; + + if (strlen(userid) < 2) + return 1; + + if (!isalpha(*userid)) + return 1; + + if (!str_cmp(userid, "new")) + return 1; + + while (ch = *(++userid)) + { + if (!isalnum(ch)) + return 1; + } + return 0; +} + + +static inline int +uniq_userno(fd) + int fd; +{ + char buf[4096]; + int userno, size; + SCHEMA *sp; /* record length 16 ¥i¾ã°£ 4096 */ + + userno = 1; + + while ((size = read(fd, buf, sizeof(buf))) > 0) + { + sp = (SCHEMA *) buf; + do + { + if (sp->userid[0] == '\0') + { + lseek(fd, -size, SEEK_CUR); + return userno; + } + userno++; + size -= sizeof(SCHEMA); + sp++; + } while (size); + } + + return userno; +} + + +#define LEVEL_BASIC 000000000001 /* °ò¥»Åv¤O */ +#define LEVEL_CHAT 000000000002 /* ¶i¤J²á¤Ñ«Ç */ +#define LEVEL_PAGE 000000000004 /* §ä¤H²á¤Ñ */ +#define LEVEL_POST 000000000010 /* µoªí¤å³¹ */ +#define LEVEL_LOGINOK 000000000020 /* µù¥Uµ{§Ç»{ÃÒ */ +#define LEVEL_MAILLIMIT 000000000040 /* «H¥óµL¤W */ +#define LEVEL_CLOAK 000000000100 /* Áô¨³N */ +#define LEVEL_SEECLOAK 000000000200 /* ¬Ý¨£§ÔªÌ */ +#define LEVEL_XEMPT 000000000400 /* ¥Ã¤[«O¯d±b¸¹ */ +#define LEVEL_BM 000000002000 /* ªO¥D */ +#define LEVEL_ACCOUNTS 000000004000 /* ±b¸¹Á`ºÞ */ +#define LEVEL_CHATROOM 000000010000 /* ²á¤Ñ«ÇÁ`ºÞ */ +#define LEVEL_BOARD 000000020000 /* ¬ÝªOÁ`ºÞ */ +#define LEVEL_SYSOP 000000040000 /* ¯¸ªø */ + + +static inline usint +trans_acct_level(perm) + usint perm; +{ + usint userlevel; + + userlevel = 0; + + if (perm & LEVEL_BASIC) + userlevel |= PERM_BASIC; + + if (perm & LEVEL_CHAT) + userlevel |= PERM_CHAT; + + if (perm & LEVEL_PAGE) + userlevel |= PERM_PAGE; + + if (perm & LEVEL_POST) + userlevel |= PERM_POST; + + if (perm & LEVEL_LOGINOK) + userlevel |= PERM_VALID; + + if (perm & LEVEL_MAILLIMIT) + userlevel |= PERM_MBOX; + + if (perm & LEVEL_CLOAK) + userlevel |= PERM_CLOAK; + + if (perm & LEVEL_SEECLOAK) + userlevel |= PERM_SEECLOAK; + + if (perm & LEVEL_XEMPT) + userlevel |= PERM_XEMPT; + + if (perm & LEVEL_BM) + userlevel |= PERM_BM; + + if (perm & LEVEL_ACCOUNTS) + userlevel |= PERM_ACCOUNTS; + + if (perm & LEVEL_CHATROOM) + userlevel |= PERM_CHATROOM; + + if (perm & LEVEL_BOARD) + userlevel |= PERM_BOARD; + + if (perm & LEVEL_SYSOP) + userlevel |= PERM_SYSOP; + + return userlevel; +} + + +#define OLDUFO_MOVIE 000000000001 /* ¶}/Ãö°ÊºA¬ÝªO */ +#define OLDUFO_COLOR 000000000002 /* ±m¦â/¶Â¥Õ¤Á´« */ +#define OLDUFO_NOTE 000000000004 /* Åã¥Ü¯d¨¥ªO */ +#define OLDUFO_ALARM 000000000010 /* ¥bÂI³ø®É */ +#define OLDUFO_BELL 000000000020 /* Ánµ */ +#define OLDUFO_BOARDLIST 000000000040 /* ¬ÝªO¦CªíÅã¥Ü¤å³¹¼Æ©Î¬O½s¸¹ */ +#define OLDUFO_SEELOG 000000000100 /* ¤W¯¸³£¥h¬Ý¬ö¿ý±Æ¦W? */ +#define OLDUFO_CYCLE 000000000200 /* ´`Àô¦¡¾\Ū */ +#define OLDUFO_RPG 000000000400 +#define OLDUFO_FEELING 000000001000 +#define OLDUFO_FROM 000000002000 +#define OLDUFO_NOTEMONEY 000000004000 +#define OLDUFO_ALREADYSET 000000010000 /* ¨C¦¸¤W¯¸³£³]©w? */ +#define OLDUFO_BIG5GB 000000020000 /* use big5 code or gb */ + + +static inline usint +trans_acct_ufo(oldufo) + usint oldufo; +{ + usint ufo; + + ufo = UFO_DEFAULT_NEW; + + if (oldufo & OLDUFO_MOVIE) + ufo |= UFO_MOVIE; + else + ufo &= ~UFO_MOVIE; + + if (oldufo & OLDUFO_NOTE) + ufo &= ~UFO_MOTD; + else + ufo |= UFO_MOTD; + + return ufo; +} + + +static inline void +creat_dirs(old) + userec *old; +{ + ACCT new; + SCHEMA slot; + int fd; + char fpath[64]; + + memset(&new, 0, sizeof(new)); + memset(&slot, 0, sizeof(slot)); + + str_ncpy(new.userid, old->userid, sizeof(new.userid)); + str_ncpy(new.passwd, old->passwd, sizeof(new.passwd)); + str_ncpy(new.realname, old->realname, sizeof(new.realname)); + str_ncpy(new.username, old->username, sizeof(new.username)); + new.userlevel = trans_acct_level(old->userlevel); + new.ufo = trans_acct_ufo(old->habit); + new.signature = 0; + new.year = old->year - 11; /* ¦è¤¸´«¦¨¥Á°ê */ + new.month = old->month; + new.day = old->day; + new.sex = 1 - (old->sex % 2); /* (0)¸¯®æ (1)©j±µ (2)©³} (3)¬ü¬Ü (4)Á¦¨û (5)ªü«¼ (6)´Óª« (7)Äqª« */ + new.money = old->silvermoney; + new.gold = old->goldmoney; + new.numlogins = old->numlogins; + new.numposts = old->numposts; + new.numemails = 0; + new.firstlogin = old->firstlogin; + new.lastlogin = old->lastlogin; + new.tcheck = time(&new.tvalid); + str_ncpy(new.lasthost, old->lasthost, sizeof(new.lasthost)); + str_ncpy(new.email, old->email, sizeof(new.email)); + + slot.uptime = time(0); + strcpy(slot.userid, new.userid); + + fd = open(FN_SCHEMA, O_RDWR | O_CREAT, 0600); + new.userno = uniq_userno(fd); + write(fd, &slot, sizeof(slot)); + close(fd); + + usr_fpath(fpath, new.userid, NULL); + mkdir(fpath, 0700); + strcat(fpath, "/@"); + mkdir(fpath, 0700); + usr_fpath(fpath, new.userid, "MF"); + mkdir(fpath, 0700); + usr_fpath(fpath, new.userid, "gem"); /* itoc.010727: Ó¤HºëµØ°Ï */ + mak_links(fpath); + + usr_fpath(fpath, new.userid, ".ACCT"); + fd = open(fpath, O_WRONLY | O_CREAT, 0600); + write(fd, &new, sizeof(ACCT)); + close(fd); +} + + +/* ----------------------------------------------------- */ +/* Âà´«»{ÃÒ¸ê®Æ */ +/* ----------------------------------------------------- */ + + +static inline void +trans_justify(old) + userec *old; +{ + char fpath[64]; + FILE *fp; + + usr_fpath(fpath, old->userid, FN_JUSTIFY); + if (fp = fopen(fpath, "a")) + { + fprintf(fp, "RPY: %s\n", old->justify); /* Âà´«¹w³]¥H email »{ÃÒ */ + fclose(fp); + } +} + + +/* ----------------------------------------------------- */ +/* Âഫñ¦WÀÉ¡BpµeÀÉ */ +/* ----------------------------------------------------- */ + + +static inline void +trans_sig(old) + userec *old; +{ + int i; + char buf[64], fpath[64], f_sig[20]; + + for (i = 1; i <= 3; i++) /* Maple 3.0 ¥u¦³¤TÓñ¦W */ + { + sprintf(buf, OLD_BBSHOME "/home/%s/sig.%d", old->userid, i); /* ªºÃ±¦WÀÉ */ + if (dashf(buf)) + { + sprintf(f_sig, "%s.%d", FN_SIGN, i); + usr_fpath(fpath, old->userid, f_sig); + f_cp(buf, fpath, O_TRUNC); + } + } +} + + +static inline void +trans_plans(old) + userec *old; +{ + char buf[64], fpath[64]; + + sprintf(buf, OLD_BBSHOME "/home/%s/plans", old->userid); + if (dashf(buf)) + { + usr_fpath(fpath, old->userid, FN_PLANS); + f_cp(buf, fpath, O_TRUNC); + } +} + + +/* ----------------------------------------------------- */ +/* Âà´««H¥ó */ +/* ----------------------------------------------------- */ + + +static time_t +trans_hdr_chrono(filename) + char *filename; +{ + char time_str[11]; + + /* M.1087654321.A ©Î M.987654321.A */ + str_ncpy(time_str, filename + 2, filename[2] == '1' ? 11 : 10); + + return (time_t) atoi(time_str); +} + + +static inline void +trans_mail(old) + userec *old; +{ + int fd; + char index[64], folder[64], buf[64], fpath[64]; + fileheader fh; + HDR hdr; + time_t chrono; + + sprintf(index, OLD_BBSHOME "/home/%s/.DIR", old->userid); + usr_fpath(folder, old->userid, FN_DIR); + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + sprintf(buf, OLD_BBSHOME "/home/%s/%s", old->userid, fh.filename); + + if (dashf(buf)) /* ¤å³¹Àɮצb¤~°µÂà´« */ + { + char new_name[10] = "@"; + + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + new_name[1] = radix32[chrono & 31]; + archiv32(chrono, new_name + 1); + + hdr.chrono = chrono; + str_ncpy(hdr.xname, new_name, sizeof(hdr.xname)); + str_ncpy(hdr.owner, strstr(fh.owner, "[³Æ.") ? "[³Æ§Ñ¿ý]" : fh.owner, sizeof(hdr.owner)); /* [³Æ.§Ñ.¿ý] */ + str_ncpy(hdr.title, fh.title, sizeof(hdr.title)); + str_stamp(hdr.date, &hdr.chrono); + hdr.xmode = (fh.filemode & 0x2) ? (MAIL_MARKED | MAIL_READ) : MAIL_READ; /* ³]¬°¤wŪ */ + + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + usr_fpath(fpath, old->userid, "@/"); + strcat(fpath, new_name); + f_cp(buf, fpath, O_TRUNC); + } + } + close(fd); + } +} + + +/* ----------------------------------------------------- */ +/* Âà´«Ó¤HºëµØ°Ï */ +/* ----------------------------------------------------- */ + + +#ifdef HAVE_PERSONAL_GEM +static void +trans_man_stamp(folder, token, hdr, fpath, time) + char *folder; + int token; + HDR *hdr; + char *fpath; + time_t time; +{ + char *fname, *family; + int rc; + + fname = fpath; + while (rc = *folder++) + { + *fname++ = rc; + if (rc == '/') + family = fname; + } + if (*family != '.') + { + fname = family; + family -= 2; + } + else + { + fname = family + 1; + *fname++ = '/'; + } + + *fname++ = token; + + *family = radix32[time & 31]; + archiv32(time, fname); + + if (rc = open(fpath, O_WRONLY | O_CREAT | O_EXCL, 0600)) + { + memset(hdr, 0, sizeof(HDR)); + hdr->chrono = time; + str_stamp(hdr->date, &hdr->chrono); + strcpy(hdr->xname, --fname); + close(rc); + } + return; +} + + +static void +transman(index, folder) + char *index, *folder; +{ + static int count = 100; + + int fd; + char *ptr, buf[256], fpath[64]; + fileheader fh; + HDR hdr; + time_t chrono; + + if ((fd = open(index, O_RDONLY)) >= 0) + { + while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) + { + strcpy(buf, index); + ptr = strrchr(buf, '/') + 1; + strcpy(ptr, fh.filename); + + if (*fh.filename == 'M' && dashf(buf)) /* ¥uÂà M.xxxx.A ¤Î D.xxxx.a */ + { + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = trans_hdr_chrono(fh.filename); + trans_man_stamp(folder, 'A', &hdr, fpath, chrono); + hdr.xmode = 0; + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ncpy(hdr.title, fh.title + 3, sizeof(hdr.title)); + rec_add(folder, &hdr, sizeof(HDR)); + + /* «þ¨©ÀÉ®× */ + f_cp(buf, fpath, O_TRUNC); + } + else if (*fh.filename == 'D' && dashd(buf)) + { + char sub_index[256]; + + /* Âà´«¤å³¹ .DIR */ + memset(&hdr, 0, sizeof(HDR)); + chrono = ++count; /* WD ªº¥Ø¿ý©R¦W¤ñ¸û©_©Ç¡A¥u¦n¦Û¤vµ¹¼Æ¦r */ + trans_man_stamp(folder, 'F', &hdr, fpath, chrono); + hdr.xmode = GEM_FOLDER; + str_ncpy(hdr.owner, fh.owner, sizeof(hdr.owner)); + str_ncpy(hdr.title, fh.title + 3, sizeof(hdr.title)); + rec_add(folder, &hdr, sizeof(HDR)); + + /* recursive ¶i¥hÂà´«¤l¥Ø¿ý */ + strcpy(sub_index, buf); + ptr = strrchr(sub_index, '/') + 1; + sprintf(ptr, "%s/.DIR", fh.filename); + transman(sub_index, fpath); + } + } + close(fd); + } +} +#endif + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transusr(user) + userec *user; +{ + char buf[64]; + + printf("Âà´« %s ¨Ï¥ÎªÌ\n", user->userid); + + if (is_bad_userid(user->userid)) + { + printf("%s ¤£¬O¦Xªk ID\n", user->userid); + return; + } + + usr_fpath(buf, user->userid, NULL); + if (dashd(buf)) + { + printf("%s ¤w¸g¦³¦¹ ID\n", user->userid); + return; + } + + sprintf(buf, OLD_BBSHOME "/home/%s", user->userid); + if (!dashd(buf)) + { + printf("%s ªºÀɮפ£¦s¦b\n", user->userid); + return; + } + + creat_dirs(user); + trans_justify(user); + trans_sig(user); + trans_plans(user); + trans_mail(user); + + +#ifdef HAVE_PERSONAL_GEM + sprintf(buf, OLD_BBSHOME "/home/%s/man", user->userid); + if (dashd(buf)) + { + char index[64], folder[64]; + + sprintf(index, "%s/.DIR", buf); + usr_fpath(folder, user->userid, "gem/" FN_DIR); + transman(index, folder); + } +#endif +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int fd; + userec user; + + /* argc == 1 Âà¥þ³¡¨Ï¥ÎªÌ */ + /* argc == 2 Âà¬Y¯S©w¨Ï¥ÎªÌ */ + + if (argc > 2) + { + printf("Usage: %s [target_user]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (!dashf(FN_PASSWD)) + { + printf("ERROR! Can't open " FN_PASSWD "\n"); + exit(-1); + } + if (!dashd(OLD_BBSHOME "/home")) + { + printf("ERROR! Can't open " OLD_BBSHOME "/home\n"); + exit(-1); + } + + if ((fd = open(FN_PASSWD, O_RDONLY)) >= 0) + { + while (read(fd, &user, sizeof(user)) == sizeof(user)) + { + if (argc == 1) + { + transusr(&user); + } + else if (!strcmp(user.userid, argv[1])) + { + transusr(&user); + exit(1); + } + } + close(fd); + } + + exit(0); +} diff --git a/util/tran/windtop.h b/util/tran/windtop.h new file mode 100644 index 0000000..80f59de --- /dev/null +++ b/util/tran/windtop.h @@ -0,0 +1,131 @@ +/*-------------------------------------------------------*/ +/* util/windtop.h */ +/*-------------------------------------------------------*/ +/* target : WindTop ¦Ü Maple Âà´« */ +/* create : 03/06/30 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#if 0 + + 0. «O¯dì¨Ó brd/ gem/ usr/ .USR¡A¨ä¾l´«¦¨·sª©ªº + + 1. ³]©w FN_BOARD + + 2. §Q¥Î windtop2brd Âà´« .BRD + + 3. §Q¥Î windtop2usr Âà´« .ACCT + + 4. §Q¥Î windtop2pip Âà´« chicken + + 5. ±N·sª©ªº gem/@/ ¤Uªº³o¨ÇÀɮ׽ƻs¹L¨Ó + @apply @e-mail @goodbye @index @justify @newuser @opening.0 + @opening.1 @opening.2 @post @re-reg @tryout @welcome + + 6. ¤W BBS ¯¸¡A¦b (A)nnounce ¸Ì±¡A«Ø¥H¤U¤GÓ¨÷©vªº©Ò¦³¸ê®Æ + {¸ÜÃD} ¼öªù°Q½× + {±Æ¦æ} ²Îp¸ê®Æ + +#endif + + +#include "bbs.h" + + +#define FN_BOARD "/tmp/.BRD" /* WindTop BBS ªº .BRD */ + + +/* ----------------------------------------------------- */ +/* old ACCT struct */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + int userno; /* unique positive code */ + char userid[13]; /* userid */ + char passwd[14];; /* user password crypt by DES */ + uschar signature; /* user signature number */ + char realname[20]; /* user realname */ + char username[24]; /* user nickname */ + usint userlevel; /* user perm */ + int numlogins; /* user login times */ + int numposts; /* user post times */ + usint ufo; /* user basic flags */ + time_t firstlogin; /* user first login time */ + time_t lastlogin; /* user last login time */ + time_t staytime; /* user total stay time */ + time_t tcheck; /* time to check mbox/pal */ + char lasthost[32]; /* user last login remote host */ + int numemail; /* ±Hµo Inetrnet E-mail ¦¸¼Æ */ + time_t tvalid; /* ³q¹L»{ÃÒ¡B§ó§ï mail address ªº®É¶¡ */ + char email[60]; /* user email */ + char address[60]; /* user address */ + char justify[60]; /* FROM of replied justify mail */ + char vmail[60]; /* ³q¹L»{ÃÒ¤§ email */ + time_t deny; /* user violatelaw time */ + int request; /* ÂIºq¨t²Î */ + usint ufo2; /* ©µ¦ùªºÓ¤H³]©w */ + char ident[108]; /* user remote host ident */ + time_t vtime; /* validate time */ +} userec; + + +/* ----------------------------------------------------- */ +/* old BRD struct */ +/* ----------------------------------------------------- */ + + +typedef struct +{ + char brdname[13]; /* board ID */ + char title[43]; + char color; + char class[5]; + char BM[37]; /* BMs' uid, token '/' */ + + uschar bvote; /* ¦@¦³´X¶µ§ë²¼Á|¦æ¤¤ */ + + time_t bstamp; /* «Ø¥ß¬ÝªOªº®É¶¡, unique */ + usint readlevel; /* ¾\ۤ峹ªºÅv */ + usint postlevel; /* µoªí¤å³¹ªºÅv */ + usint battr; /* ¬ÝªOÄÝ©Ê */ + time_t btime; /* .DIR ªº st_mtime */ + int bpost; /* ¦@¦³´X½g post */ + time_t blast; /* ³Ì«á¤@½g post ªº®É¶¡ */ + usint expiremax; /* Expire Max Post */ + usint expiremin; /* Expire Min Post */ + usint expireday; /* Expire old Post */ + usint n_reads; /* ¬ÝªO¾\Ū²Öp times/hour */ + usint n_posts; /* ¬ÝªOµoªí²Öp times/hour */ + usint n_news; /* ¬ÝªOÂà«H²Öp times/hour */ + usint n_bans; /* ¬ÝªOÀÉ«H²Öp times/hour */ + char reserve[100]; /* «O¯d¥¼¥Î */ +} boardheader; + + +/* ----------------------------------------------------- */ +/* old BRD battr */ +/* ----------------------------------------------------- */ + + +#define BATTR_NOZAP 0x0001 /* ¤£¥i zap */ +#define BATTR_NOTRAN 0x0002 /* ¤£Âà«H */ +#define BATTR_NOCOUNT 0x0004 /* ¤£p¤å³¹µoªí½g¼Æ */ +#define BATTR_NOSTAT 0x0008 /* ¤£¯Ç¤J¼öªù¸ÜÃD²Îp */ +#define BATTR_NOVOTE 0x0010 /* ¤£¤½§G§ë²¼µ²ªG©ó [sysop] ªO */ +#define BATTR_ANONYMOUS 0x0020 /* °Î¦W¬ÝªO */ +#define BATTR_NOFORWARD 0x0040 /* lkchu.981201: ¤£¥iÂà±H */ +#define BATTR_LOGEMAIL 0x0080 /* ¦Û°Êªþ¥[e-mail */ +#define BATTR_NOBAN 0x0100 /* ¤£¾×«H */ +#define BATTR_NOLOG 0x0200 /* ¤£¬ö¿ý¯¸¤º¹Hªk */ +#define BATTR_NOCNTCROSS 0x0400 /* ¤£¬ö¿ý cross post */ +#define BATTR_NOREPLY 0x0800 /* ¤£¯à¦^¤å³¹ */ +#define BATTR_NOLOGREAD 0x1000 /* ¤£¬ö¿ý¬Ýª©¾\Ū²v */ +#define BATTR_CHECKWATER 0x2000 /* ¬ö¿ýÄé¤ô¦¸¼Æ */ +#define BATTR_CHANGETITLE 0x4000 /* ª©¥Dק睊¦W */ +#define BATTR_MODIFY 0x8000 /* ¨Ï¥ÎªÌ×§ï¤å³¹ */ +#define BATTR_PRH 0x10000 /* ±ÀÂˤ峹 */ +#define BATTR_NOTOTAL 0x20000 /* ¤£²Îp¬ÝªO¨Ï¥Î¬ö¿ý */ diff --git a/util/tran/windtop2brd.c b/util/tran/windtop2brd.c new file mode 100644 index 0000000..6cdc951 --- /dev/null +++ b/util/tran/windtop2brd.c @@ -0,0 +1,88 @@ +/*-------------------------------------------------------*/ +/* util/wintop2brd.c */ +/*-------------------------------------------------------*/ +/* target : WindTop .BRD Âà´« */ +/* create : 03/06/30 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "windtop.h" + + +static usint +trans_battr(oldbattr) + usint oldbattr; +{ + usint battr; + + battr = 0; + + if (oldbattr & BATTR_NOZAP) + battr |= BRD_NOZAP; + + if (oldbattr & BATTR_NOTRAN) + battr |= BRD_NOTRAN; + + if (oldbattr & BATTR_NOCOUNT) + battr |= BRD_NOCOUNT; + + if (oldbattr & BATTR_NOSTAT) + battr |= BRD_NOSTAT; + + if (oldbattr & BATTR_NOVOTE) + battr |= BRD_NOVOTE; + + if (oldbattr & BATTR_ANONYMOUS) + battr |= BRD_ANONYMOUS; + + return battr; +} + + +int +main() +{ + int fd; + BRD brd; + boardheader bh; + char buf[256]; + + chdir(BBSHOME); + + unlink(FN_BRD); + + if ((fd = open(FN_BOARD, O_RDONLY)) >= 0) + { + while (read(fd, &bh, sizeof(bh)) == sizeof(bh)) + { + if (*bh.brdname) + { + /* Âà´« .BRD */ + memset(&brd, 0, sizeof(BRD)); + + str_ncpy(brd.brdname, bh.brdname, sizeof(brd.brdname)); + str_ncpy(brd.class, bh.class, sizeof(brd.class)); + str_ncpy(brd.title, bh.title, sizeof(brd.title)); + str_ncpy(brd.BM, bh.BM, sizeof(brd.BM)); + brd.bvote = bh.bvote ? 1 : 0; + brd.bstamp = bh.bstamp; + brd.readlevel = bh.readlevel; + brd.postlevel = bh.postlevel; + brd.battr = trans_battr(bh.battr); + + rec_add(FN_BRD, &brd, sizeof(BRD)); + + /* «Ø¥ß expire.conf */ + if (bh.expireday && bh.expiremax && bh.expiremin) + { + sprintf(buf, "%s\t%d\t%d\t%d\n", brd.brdname, bh.expireday, bh.expiremax, bh.expiremin); + f_cat("etc/expire.conf", buf); + } + } + } + } + + return 0; +} diff --git a/util/tran/windtop2pip.c b/util/tran/windtop2pip.c new file mode 100644 index 0000000..0b32c0a --- /dev/null +++ b/util/tran/windtop2pip.c @@ -0,0 +1,490 @@ +/*-------------------------------------------------------*/ +/* util/transpip.c */ +/*-------------------------------------------------------*/ +/* target : WD ¦Ü Maple 3.02 ¤pÂû¸ê®ÆÂà´« */ +/* create : 02/01/26 */ +/* update : / / */ +/* author : itoc.bbs@bbs.ee.nctu.edu.tw */ +/*-------------------------------------------------------*/ +/* syntax : transpip */ +/*-------------------------------------------------------*/ + + +#if 0 + + 1. ×§ï transpip() + 2. ¥uÂà chicken¡Achicken.bak* ´N¤£Âà¤F + + ps. ¨Ï¥Î«e½Ð¥ý¦æ³Æ¥÷¡Ause on ur own risk. µ{¦¡©å¦H½Ð¥]²[ :p + ps. ·PÁ lkchu ªº Maple 3.02 for FreeBSD + +#endif + + +#include "windtop.h" + +#ifdef HAVE_GAME + +#include "../../pip/pipstruct.h" /* ¤Þ¤J·s¤pÂûªº°Ñ¼Æ³]©w */ + + +/* ----------------------------------------------------- */ +/* ¤pÂû°Ñ¼Æ³]©w */ +/* ----------------------------------------------------- */ + + +struct chicken +{ + /* ---°ò¥»ªº¸ê®Æ--- */ + char name[20]; /* ©m ¦W */ + char birth[21]; /* ¥Í ¤é */ + int year; /* ¥Í¤é ¦~ */ + int month; /* ¥Í¤é ¤ë */ + int day; /* ¥Í¤é ¤é */ + int sex; /* ©Ê §O 1:¡ñ 2:¡ð */ + int death; /* 1: ¦º¤` 2:©ß±ó 3:µ²§½ */ + int nodone; /* 1: ¥¼°µ */ + int relation; /* ¨â¤HÃö«Y */ + int liveagain; /* ´_¬¡¦¸¼Æ */ + int dataB; + int dataC; + int dataD; + int dataE; + + /* ---¨Å骺°Ñ¼Æ--- */ + int hp; /* Åé ¤O */ + int maxhp; /* ³Ì¤jÅé¤O */ + int weight; /* Åé « */ + int tired; /* ¯h ³Ò «× */ + int sick; /* ¯f ®ð */ + int shit; /* ²M ¼ä «× */ + int wrist; /* µÃ ¤O */ + int bodyA; + int bodyB; + int bodyC; + int bodyD; + int bodyE; + + /* ---µû»ùªº°Ñ¼Æ--- */ + int social; /* ªÀ¥æµû»ù */ + int family; /* ®a¨Æµû»ù */ + int hexp; /* ¾Ô°«µû»ù */ + int mexp; /* Å]ªkµû»ù */ + int tmpA; + int tmpB; + int tmpC; + int tmpD; + int tmpE; + + /* ---¾Ô°«¥Î°Ñ¼Æ--- */ + int mp; /* ªk ¤O */ + int maxmp; /* ³Ì¤jªk¤O */ + int attack; /* §ð À» ¤O */ + int resist; /* ¨¾ ¿m ¤O */ + int speed; /* ³t «× */ + int hskill; /* ¾Ô°«§Þ³N */ + int mskill; /* Å]ªk§Þ³N */ + int mresist; /* §ÜÅ]¯à¤O */ + int magicmode; /* Å]ªk«¬ºA */ + int fightB; + int fightC; + int fightD; + int fightE; + + + /* ---ªZ¾¹ªº°Ñ¼Æ--- */ + int weaponhead; /* ÀY³¡ªZ¾¹ */ + int weaponrhand; /* ¥k¤âªZ¾¹ */ + int weaponlhand; /* ¥ª¤âªZ¾¹ */ + int weaponbody; /* ¨ÅéªZ¾¹ */ + int weaponfoot; /* ¸}ªºªZ¾¹ */ + int weaponA; + int weaponB; + int weaponC; + int weaponD; + int weaponE; + + /* ---¦U¯à¤O°Ñ¼Æ--- */ + int toman; /* «Ý¤H±µª« */ + int character; /* ®ð ½è «× */ + int love; /* ·R ¤ß */ + int wisdom; /* ´¼ ¼z */ + int art; /* ÃÀ³N¯à¤O */ + int etchics; /* ¹D ¼w */ + int brave; /* «i ´± */ + int homework; /* ±½¦a¬~¦ç */ + int charm; /* ¾y ¤O */ + int manners; /* § »ö */ + int speech; /* ½Í ¦R */ + int cookskill; /* ²i ¶¹ */ + int learnA; + int learnB; + int learnC; + int learnD; + int learnE; + + + /* ---¦Uª¬ºA¼ÆÈ--- */ + int happy; /* §Ö ¼Ö «× */ + int satisfy; /* º¡ ·N «× */ + int fallinlove; /* ÅÊ·R«ü¼Æ */ + int belief; /* «H ¥õ */ + int offense; /* ¸o Ä^ */ + int affect; /* ·P ¨ü */ + int stateA; + int stateB; + int stateC; + int stateD; + int stateE; + + /* ---¦YªºªF¦è°Õ--- */ + int food; /* ¹ ª« */ + int medicine; /* ÆF ªÛ */ + int bighp; /* ¤j ¸É ¤Y */ + int cookie; /* ¹s ¹ */ + int ginseng; /* ¤d¦~¤Hçx */ + int snowgrass; /* ¤Ñ¤s³·½¬ */ + int eatC; + int eatD; + int eatE; + + /* ---¾Ö¦³ªºªF¦è--- */ + int book; /* ®Ñ ¥» */ + int playtool; /* ª± ¨ã */ + int money; /* ª÷ ¿ú */ + int thingA; + int thingB; + int thingC; + int thingD; + int thingE; + + /* ---²q®±ªº°Ñ¼Æ--- */ + int winn; + int losee; + + /* ---°Ñ¨£¤ý¦Ú-- */ + int royalA; /* from¦u½Ã */ + int royalB; /* fromªñ½Ã */ + int royalC; /* from±Nx */ + int royalD; /* from¤j¦Ú */ + int royalE; /* from²½¥q */ + int royalF; /* fromÃd¦m */ + int royalG; /* from¤ý¦m */ + int royalH; /* from°ê¤ý */ + int royalI; /* from¤p¤¡ */ + int royalJ; /* from¤ý¤l */ + int seeroyalJ; /* ¬O§_¤w¸g¬Ý¹L¤ý¤l¤F */ + int seeA; + int seeB; + int seeC; + int seeD; + int seeE; + + /* ---µ²§½---- */ + int wantend; /* 20·³µ²§½ 1:¤£n¥B¥¼±B 2:¤£n¥B¤w±B 3:¤£n¥B·í²Ä¤TªÌ 4:n¥B¥¼±B 5:n¥B¤w±B 6:n¥B·í²Ä¤TªÌ */ + int lover; /* ·R¤H 0:¨S¦³ 1:Å]¤ý 2:Às±Ú 3:A 4:B 5:C 6:D 7:E */ + + /* -------¤u§@¦¸¼Æ-------- */ + int workA; /* ®a¨Æ */ + int workB; /* «O©i */ + int workC; /* ®È©± */ + int workD; /* ¹A³õ */ + int workE; /* À\ÆU */ + int workF; /* ±Ð°ó */ + int workG; /* ¦aÅu */ + int workH; /* ¥ï¤ì */ + int workI; /* ¬ü¾v */ + int workJ; /* Ây¤H */ + int workK; /* ¤u¦a */ + int workL; /* ¦u¹Ó */ + int workM; /* ®a±Ð */ + int workN; /* °s®a */ + int workO; /* °s©± */ + int workP; /* ©]Á`·| */ + int workQ; + int workR; + int workS; + int workT; + int workU; + int workV; + int workW; + int workX; + int workY; + int workZ; + + /* -------¤W½Ò¦¸¼Æ-------- */ + int classA; + int classB; + int classC; + int classD; + int classE; + int classF; + int classG; + int classH; + int classI; + int classJ; + int classK; + int classL; + int classM; + int classN; + int classO; + + /* ---¤pÂûªº®É¶¡--- */ + time_t bbtime; +}; +typedef struct chicken chicken; + + +/* ----------------------------------------------------- */ +/* Âà´«¥Dµ{¦¡ */ +/* ----------------------------------------------------- */ + + +static void +transpip(userid) + char *userid; +{ + int fd; + char fpath[64], buf[20]; + FILE *fp; + struct chicken d; /* ¤pÂû */ + struct CHICKEN p; /* ·s¤pÂû */ + + + usr_fpath(fpath, userid, "chicken"); + + if (fp = fopen(fpath, "r")) + { + /* Ū¥X¤pÂû¸ê®Æ */ + + fgets(buf, 20, fp); + d.bbtime = (time_t) atoi(buf); + + fscanf(fp, + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d " + "%d %d %d", + &(d.year), &(d.month), &(d.day), &(d.sex), &(d.death), &(d.nodone), &(d.relation), &(d.liveagain), &(d.dataB), &(d.dataC), &(d.dataD), &(d.dataE), + &(d.hp), &(d.maxhp), &(d.weight), &(d.tired), &(d.sick), &(d.shit), &(d.wrist), &(d.bodyA), &(d.bodyB), &(d.bodyC), &(d.bodyD), &(d.bodyE), + &(d.social), &(d.family), &(d.hexp), &(d.mexp), &(d.tmpA), &(d.tmpB), &(d.tmpC), &(d.tmpD), &(d.tmpE), + &(d.mp), &(d.maxmp), &(d.attack), &(d.resist), &(d.speed), &(d.hskill), &(d.mskill), &(d.mresist), &(d.magicmode), &(d.fightB), &(d.fightC), &(d.fightD), &(d.fightE), + &(d.weaponhead), &(d.weaponrhand), &(d.weaponlhand), &(d.weaponbody), &(d.weaponfoot), &(d.weaponA), &(d.weaponB), &(d.weaponC), &(d.weaponD), &(d.weaponE), + &(d.toman), &(d.character), &(d.love), &(d.wisdom), &(d.art), &(d.etchics), &(d.brave), &(d.homework), &(d.charm), &(d.manners), &(d.speech), &(d.cookskill), &(d.learnA), &(d.learnB), &(d.learnC), &(d.learnD), &(d.learnE), + &(d.happy), &(d.satisfy), &(d.fallinlove), &(d.belief), &(d.offense), &(d.affect), &(d.stateA), &(d.stateB), &(d.stateC), &(d.stateD), &(d.stateE), + &(d.food), &(d.medicine), &(d.bighp), &(d.cookie), &(d.ginseng), &(d.snowgrass), &(d.eatC), &(d.eatD), &(d.eatE), + &(d.book), &(d.playtool), &(d.money), &(d.thingA), &(d.thingB), &(d.thingC), &(d.thingD), &(d.thingE), + &(d.winn), &(d.losee), + &(d.royalA), &(d.royalB), &(d.royalC), &(d.royalD), &(d.royalE), &(d.royalF), &(d.royalG), &(d.royalH), &(d.royalI), &(d.royalJ), &(d.seeroyalJ), &(d.seeA), &(d.seeB), &(d.seeC), &(d.seeD), &(d.seeE), + &(d.wantend), &(d.lover), d.name, + &(d.classA), &(d.classB), &(d.classC), &(d.classD), &(d.classE), + &(d.classF), &(d.classG), &(d.classH), &(d.classI), &(d.classJ), + &(d.classK), &(d.classL), &(d.classM), &(d.classN), &(d.classO), + &(d.workA), &(d.workB), &(d.workC), &(d.workD), &(d.workE), + &(d.workF), &(d.workG), &(d.workH), &(d.workI), &(d.workJ), + &(d.workK), &(d.workL), &(d.workM), &(d.workN), &(d.workO), + &(d.workP), &(d.workQ), &(d.workR), &(d.workS), &(d.workT), + &(d.workU), &(d.workV), &(d.workW), &(d.workX), &(d.workY), &(d.workZ)); + + fclose(fp); + + /* Âà´«¤pÂû¸ê®Æ */ + + memset(&p, 0, sizeof(p)); + + str_ncpy(p.name, d.name, sizeof(p.name)); + sprintf(p.birth, "%02d/%02d/%02d", d.year % 100, d.month, d.day); + + p.bbtime = d.bbtime; + + p.year = d.year; + p.month = d.month; + p.day = d.day; + p.sex = d.sex; + p.death = d.death; + p.liveagain = d.liveagain; + p.wantend = d.wantend; + p.lover = d.lover; + p.seeroyalJ = d.seeroyalJ; + p.quest = 0; /* ¹q¤lÂû¨S¦³¥ô°È */ + + p.relation = d.relation; + p.happy = d.happy; + p.satisfy = p.satisfy; + p.fallinlove = d.fallinlove; + p.belief = d.belief; + p.sin = d.offense; + p.affect = d.affect; + + p.weight = d.weight; + p.tired = d.tired; + p.sick = d.sick; + p.shit = d.shit; + + p.social = d.social; + p.family = d.family; + p.hexp = d.hexp; + p.mexp = d.mexp; + + p.toman = d.toman; + p.character = d.character; + p.love = d.love; + p.wisdom = d.wisdom; + p.art = d.art; + p.etchics = d.etchics; + p.brave = d.brave; + p.homework = d.homework; + p.charm = d.charm; + p.manners = d.manners; + p.speech = d.speech; + p.cook = d.cookskill; + p.attack = d.attack; + p.resist = d.resist; + p.speed = d.speed; + p.hskill = d.hskill; + p.mskill = d.mskill; + p.immune = d.mresist; + + p.level = 1; /* ±q 1 ¯Å¶}©l */ + p.exp = 0; + p.hp = d.hp; + p.maxhp = d.maxhp; + p.mp = d.mp; + p.maxmp = d.maxmp; + p.vp = d.hp; /* ¹q¤lÂû¨S¦³ vp/sp ®³ hp/mp ¨Ó®M */ + p.maxvp = d.maxhp; + p.sp = d.mp; + p.maxsp = d.maxmp; + + /* ¹q¤lÂû¨S¦³§Þ¯à¡A¹w³]¬° 0 */ + + /* ªZ¾¹³q³q«¸m¬° 0¡A¥H§KªZ¾¹¦Cªí¤£¦P */ + + p.food = d.food; + p.cookie = d.cookie; + p.pill = 0; + p.medicine = d.medicine; + p.burger = d.bighp; + p.ginseng = d.ginseng; + p.paste = 0; + p.snowgrass = d.snowgrass; + + p.money = d.money; + p.book = d.book; + p.toy = d.playtool; + p.playboy = 0; + + p.royalA = d.royalA; + p.royalB = d.royalB; + p.royalC = d.royalC; + p.royalD = d.royalD; + p.royalE = d.royalE; + p.royalF = d.royalF; + p.royalG = d.royalG; + p.royalH = d.royalH; + p.royalI = d.royalI; + p.royalJ = d.royalJ; + + p.workA = d.workA; + p.workB = d.workB; + p.workC = d.workC; + p.workD = d.workD; + p.workE = d.workE; + p.workF = d.workF; + p.workG = d.workG; + p.workH = d.workH; + p.workI = d.workI; + p.workJ = d.workJ; + p.workK = d.workK; + p.workL = d.workL; + p.workM = d.workM; + p.workN = d.workN; + p.workO = d.workO; + p.workP = d.workP; + + p.winn = d.winn; + p.losee = d.losee; + p.classA = d.classA; + p.classB = d.classB; + p.classC = d.classC; + p.classD = d.classD; + p.classE = d.classE; + p.classF = d.classF; + p.classG = d.classG; + p.classH = d.classH; + p.classI = d.classI; + p.classJ = d.classJ; + + /* ¼g¤J·s¤pÂû¸ê®Æ */ + + unlink(fpath); /* ««ØÓ·sªº */ + fd = open(fpath, O_WRONLY | O_CREAT, 0600); + write(fd, &p, sizeof(CHICKEN)); + close(fd); + } +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + char c; + char buf[64]; + struct dirent *de; + DIR *dirp; + + /* argc == 1 Âà¥þ³¡¨Ï¥ÎªÌ */ + /* argc == 2 Âà¬Y¯S©w¨Ï¥ÎªÌ */ + + if (argc > 2) + { + printf("Usage: %s [target_user]\n", argv[0]); + exit(-1); + } + + chdir(BBSHOME); + + if (argc == 2) + { + transpip(argv[1]); + exit(1); + } + + /* Âà´«¨Ï¥ÎªÌ¤pÂû¸ê®Æ */ + for (c = 'a'; c <= 'z'; c++) + { + sprintf(buf, "usr/%c", c); + + if (!(dirp = opendir(buf))) + continue; + + while (de = readdir(dirp)) + { + char *str; + + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + + transpip(str); + } + + closedir(dirp); + } + return 0; +} +#else +int +main() +{ + printf("You should define HAVE_GAME first.\n"); + return -1; +} +#endif /* HAVE_GAME */ diff --git a/util/tran/windtop2usr.c b/util/tran/windtop2usr.c new file mode 100644 index 0000000..a5830db --- /dev/null +++ b/util/tran/windtop2usr.c @@ -0,0 +1,192 @@ +/*-------------------------------------------------------*/ +/* util/windtop2usr.c */ +/*-------------------------------------------------------*/ +/* target : WindTop .ACCT Âà´« */ +/* create : 03/06/30 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "windtop.h" + +#define MAK_DIRS /* «Ø¥Ø¿ý MF/ ¤Î gem/ */ + + +#define OLDUFO_PAGER BFLAG(5) /* Ãö³¬©I¥s¾¹ */ +#define OLDUFO_QUIET BFLAG(6) /* µ²Ãf¦b¤H¹Ò¡A¦ÓµL¨®°¨³Ù */ +#define OLDUFO_MAXMSG BFLAG(7) /* °T®§¤W©Ú¦¬°T®§ */ +#define OLDUFO_FORWARD BFLAG(8) /* ¦Û°ÊÂà±H */ +#define OLDUFO_CLASSTABLE BFLAG(9) /* ¥\½Òªí³qª¾ */ +#define OLDUFO_BROADCAST BFLAG(14) /* ©Ú¦¬¼s¼½ */ +#define OLDUFO_HIDEDN BFLAG(18) /* ÁôÂèӷ½ */ +#define OLDUFO_CLOAK BFLAG(19) /* true if cloak was ON */ +#define OLDUFO_WEB BFLAG(22) /* visor.020325: WEB */ +#define OLDUFO_MPAGER BFLAG(10) /* lkchu.990428: ¹q¤l¶l¥ó¶Ç©I */ +#define OLDUFO_MESSAGE BFLAG(23) /* visor.991030: °T®§¥þÃö */ +#define OLDUFO_PAGER1 BFLAG(26) /* visor.991030: ©I¥s¾¹¥þÃö */ + +#define OLDUFO2_COLOR BFLAG(0) /* true if the ANSI color mode open */ +#define OLDUFO2_MOVIE BFLAG(1) /* true if show movie */ +#define OLDUFO2_BRDNEW BFLAG(2) /* ·s¤å³¹¼Ò¦¡ */ +#define OLDUFO2_BNOTE BFLAG(3) /* Åã¥Ü¶iªOµe± */ +#define OLDUFO2_VEDIT BFLAG(4) /* ²¤Æ½s¿è¾¹ */ +#define OLDUFO2_PAL BFLAG(5) /* true if show pals only */ +#define OLDUFO2_MOTD BFLAG(6) /* ²¤Æ¶i¯¸µe± */ +#define OLDUFO2_MIME BFLAG(7) /* MIME ¸Ñ½X */ +#define OLDUFO2_SIGN BFLAG(8) /* ñ¦WÀÉ */ +#define OLDUFO2_SHOWUSER BFLAG(9) /* Åã¥Ü ID ©M ¼ÊºÙ */ +#define OLDUFO2_PRH BFLAG(10) /* Åã¥Ü±ÀÂˤ峹¤À¼Æ */ +#define OLDUFO2_SHIP BFLAG(11) /* visor.991030: ¦n¤Í´yz */ +#define OLDUFO2_NWLOG BFLAG(12) /* lkchu.990510: ¤£¦s¹ï¸Ü¬ö¿ý */ +#define OLDUFO2_NTLOG BFLAG(13) /* lkchu.990510: ¤£¦s²á¤Ñ¬ö¿ý */ +#define OLDUFO2_CIRCLE BFLAG(14) /* ´`Àô¾\Ū */ +#define OLDUFO2_ORIGUI BFLAG(15) /* Ãö³¬·¤§¶ð¶W¬¯¤¶± */ +#define OLDUFO2_DEF_ANONY BFLAG(16) /* ¹w³]¤£°Î¦W */ +#define OLDUFO2_DEF_LEAVE BFLAG(17) /* ¹w³]¤£Â÷¯¸ */ +#define OLDUFO2_ACL BFLAG(24) /* true if ACL was ON */ +#define OLDUFO2_REALNAME BFLAG(28) /* visor.991030: ¯u¹ê©m¦W */ + + +static usint +trans_ufo(oldufo, oldufo2) + usint oldufo, oldufo2; +{ + usint ufo; + + ufo = 0; + + if (oldufo2 & OLDUFO2_MOVIE) + ufo |= UFO_MOVIE; + + if (oldufo2 & OLDUFO2_BRDNEW) + ufo |= UFO_BRDPOST; + + if (oldufo2 & OLDUFO2_BNOTE) + ufo |= UFO_BRDNOTE; + + if (oldufo2 & OLDUFO2_VEDIT) + ufo |= UFO_VEDIT; + + if (oldufo2 & OLDUFO2_MOTD) + ufo |= UFO_MOTD; + + if (oldufo & OLDUFO_PAGER) + ufo |= UFO_PAGER; + + if (oldufo & OLDUFO_BROADCAST) + ufo |= UFO_RCVER; + + if (oldufo & OLDUFO_QUIET) + ufo |= UFO_QUIET; + + if (oldufo2 & OLDUFO2_PAL) + ufo |= UFO_PAL; + + ufo |= UFO_ALOHA; /* ¹w³] */ + + /* ufo |= UFO_BMWDISPLAY; */ /* ¹w³]¤£n */ + + if (oldufo2 & OLDUFO2_NWLOG) + ufo |= UFO_NWLOG; + + if (oldufo2 & OLDUFO2_NTLOG) + ufo |= UFO_NTLOG; + + ufo |= UFO_NOSIGN; /* ¹w³] */ + + /* ufo |= UFO_SHOWSIGN; */ /* ¹w³]¤£n */ + + if (oldufo & OLDUFO_CLOAK) + ufo |= UFO_CLOAK; + + if (oldufo2 & OLDUFO2_ACL) + ufo |= UFO_ACL; + + return ufo; +} + + +int +main() +{ + ACCT new; + char c; + + for (c = 'a'; c <= 'z'; c++) + { + char buf[64]; + struct dirent *de; + DIR *dirp; + + sprintf(buf, BBSHOME "/usr/%c", c); + chdir(buf); + + if (!(dirp = opendir("."))) + continue; + + while (de = readdir(dirp)) + { + userec old; + int fd; + char *str; + + str = de->d_name; + if (*str <= ' ' || *str == '.') + continue; + +#ifdef MAK_DIRS + sprintf(buf, "%s/MF", str); + mkdir(buf, 0700); + sprintf(buf, "%s/gem", str); + mak_links(buf); +#endif + + sprintf(buf, "%s/" FN_ACCT, str); + if ((fd = open(buf, O_RDONLY)) < 0) + continue; + + read(fd, &old, sizeof(userec)); + close(fd); + unlink(buf); /* itoc.010831: ¬å±¼ì¨Óªº FN_ACCT */ + + memset(&new, 0, sizeof(ACCT)); + + new.userno = old.userno; + + str_ncpy(new.userid, old.userid, sizeof(new.userid)); + str_ncpy(new.passwd, old.passwd, sizeof(new.passwd)); + str_ncpy(new.realname, old.realname, sizeof(new.realname)); + str_ncpy(new.username, old.username, sizeof(new.username)); + + new.userlevel = old.userlevel; + new.ufo = trans_ufo(old.ufo, old.ufo2); + new.signature = old.signature; + + new.year = 0; + new.month = 0; + new.day = 0; + new.sex = 1; /* µ¹ªì©lÈ */ + new.money = 100; + new.gold = 1; + + new.numlogins = old.numlogins; + new.numposts = old.numposts; + new.numemails = old.numemail; + + new.firstlogin = old.firstlogin; + new.lastlogin = old.lastlogin; + new.tcheck = old.tcheck; + new.tvalid = old.tvalid; + + str_ncpy(new.lasthost, old.lasthost, sizeof(new.lasthost)); + str_ncpy(new.email, old.email, sizeof(new.email)); + + fd = open(buf, O_WRONLY | O_CREAT, 0600); /* itoc.010831: ««Ø·sªº FN_ACCT */ + write(fd, &new, sizeof(ACCT)); + close(fd); + } + + closedir(dirp); + } +} diff --git a/util/umodestat.c b/util/umodestat.c new file mode 100644 index 0000000..a7aaa89 --- /dev/null +++ b/util/umodestat.c @@ -0,0 +1,69 @@ +/*-------------------------------------------------------*/ +/* util/modestat.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : ²Îp¨Ï¥ÎªÌ°ÊºA */ +/* create : 95/11/21 */ +/* update : 97/11/21 */ +/*-------------------------------------------------------*/ +/* syntax : modestat [log_filename] */ +/*-------------------------------------------------------*/ + + +#define _MODES_C_ + +#include "bbs.h" + + +int +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef MODE_STAT + char *fname; + FILE *fp; + UMODELOG mlog; + register int i, c; + char buf[80]; + time_t sum; + + if (argc < 2) + { + chdir(BBSHOME); + fname = FN_RUN_MODE_CUR; + } + else + fname = argv[1]; + + if (!(fp = fopen(fname, "rb"))) + { + perror("Can't open file"); + exit(1); + } + + while (fread(&mlog, sizeof(UMODELOG), 1, fp)) + { + for (i = c = 0, sum = 0; i <= M_MAX; i++) + { + struct tm *tt; + + sum += mlog.used_time[i]; + tt = localtime(&mlog.used_time[i]); + sprintf(buf + (c * 22), "%-12s%02d¤À%02d¬í ", ModeTypeTable[i], tt->tm_min, tt->tm_sec); + + if (++c == 3) + { + printf(buf); + printf("\n"); + c = 0; + } + } + printf("Á`¦@°±¯d®É¶¡: %s\n", Btime(&sum)); + } + + + fclose(fp); +#endif /* MODE_STAT */ + + exit(0); +} diff --git a/util/uno/0readme b/util/uno/0readme new file mode 100644 index 0000000..f8eb919 --- /dev/null +++ b/util/uno/0readme @@ -0,0 +1,22 @@ + ¥H¤U´X¤äµ{¦¡¬O®³¨Ó¸Ñ¨M Maple3 userno «ÂаÝÃDªº¡G + + collect_uno ±q usr/_/* ©³¤U©Ò¦³ªº .ACCT ¦¬¶°¥þ¯¸ªº userno¡A°O¿ý©ó all_user_uno + conflict_uno ¥i¥H§â all_user_uno ªºµ²ªG²³æ¤ÀªR¡A¨q¥X«ÂЪº userno + fix_uno «³]©Ò¦³¤Hªº userno¡A¨Ã««Ø pal/list.?/aloha/frienz/benz + + ¥¿½T¨Ï¥Îªº¶¶§Ç¡G + + 1. ½Ð¥ý³Æ¥÷ usr/ + 2. °õ¦æ«e¥ý½ð¤HÃö¯¸ + + 3. °õ¦æ collect_uno + 4. °õ¦æ conflict_uno + 5. ¥i¥H¬Ý¨ìµ²ªG¬O§_¦³½s¸¹«ÂÐ + + 6. ¦pªG¦³½s¸¹«ÂЪº¸Ü¡A°õ¦æ fix_uno + + 7. ¦A«×°õ¦æ collect_uno + 8. ¦A«×°õ¦æ conflict_uno + 9. ¬Ý¬Ý«¾ã«áªºµ²ªG¬O§_ÁÙ¦³½s¸¹«ÂÐ + + 10. §¹¦¨¡A«·s¶}¯¸ diff --git a/util/uno/Makefile b/util/uno/Makefile new file mode 100644 index 0000000..b8141ae --- /dev/null +++ b/util/uno/Makefile @@ -0,0 +1,59 @@ +# ------------------------------------------------------- # +# util/uno/Makefile ( NTHU CS MapleBBS Ver 3.10 ) # +# ------------------------------------------------------- # +# target : Makefile for ±H«H¡B²Îp¡B³Æ¥÷¡B¨t²ÎºûÅ@¤u¨ã # +# create : 01/03/02 # +# update : / / # +# ------------------------------------------------------- # + + +# ------------------------------------------------------ # +# ¤U¦Cªº make rules ¤£»Ý×§ï # +# ------------------------------------------------------ # + + +EXE = collect_uno conflict_uno fix_uno + + +all: + @echo "Please enter 'make sys-type', " + @echo " make sun : for Sun-OS 4.x and maybe some BSD systems, cc or gcc" + @echo " make linux : for Linux" + @echo " make solaris : for Sun-OS 5.x gcc" + @echo " make sol-x86 : for Solaris 7 x86" + @echo " make freebsd : for BSD 4.4 systems" + @echo " make bsd : for BSD systems, cc or gcc, if not in the above lists" + @echo " make cygwin : for Microsoft Windows and Cygwin gcc" + +sun: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -fomit-frame-pointer -Wunused -I../../include" LDFLAGS="-s -L../../lib -ldao" $(EXE) + +linux: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao" $(EXE) + +solaris: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao -lsocket -lnsl -L/usr/ucblib -lucb" $(EXE) + +sol-x86: + @$(MAKE) CC=gcc CFLAGS="-O2 -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao -lsocket -lnsl" $(EXE) + +freebsd: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao" $(EXE) + +bsd: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao" $(EXE) + +cygwin: + @$(MAKE) CC=gcc CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused" LDFLAGS="-s -L../../lib -ldao" $(EXE) + + +.c: ; $(CC) -o $@ $@.c $(CFLAGS) $(LDFLAGS) + + +install: $(EXE) +# ¤£½Æ»s¨ì bin/ ¤U +# install -m 0700 $? $(HOME)/bin + @echo "ok!" + +clean: + rm -f $(EXE) *.exe *.o *~ diff --git a/util/uno/collect_uno.c b/util/uno/collect_uno.c new file mode 100644 index 0000000..4a15323 --- /dev/null +++ b/util/uno/collect_uno.c @@ -0,0 +1,77 @@ +/*-------------------------------------------------------*/ +/* util/collect_uno.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¦¬¶°¥þ¯¸©Ò¦³¤Hªº userno */ +/* create : 04/10/16 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +typedef struct +{ + int userno; + char userid[IDLEN + 1]; +} COLLECTION; + + +static void +collect_uno(userid) + char *userid; +{ + int fd; + char fpath[64]; + ACCT acct; + COLLECTION collection; + + usr_fpath(fpath, userid, FN_ACCT); + if ((fd = open(fpath, O_RDONLY)) >= 0) + { + read(fd, &acct, sizeof(ACCT)); + close(fd); + + memset(&collection, 0, sizeof(COLLECTION)); + collection.userno = acct.userno; + strcpy(collection.userid, acct.userid); + rec_add("tmp/all_user_uno", &collection, sizeof(COLLECTION)); + } +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + char c; + char *userid, fpath[64]; + struct dirent *de; + DIR *dirp; + + chdir(BBSHOME); + + unlink("tmp/all_user_uno"); + + for (c = 'a'; c <= 'z'; c++) + { + sprintf(fpath, "usr/%c", c); + + if (!(dirp = opendir(fpath))) + continue; + + while (de = readdir(dirp)) + { + userid = de->d_name; + if (*userid <= ' ' || *userid == '.') + continue; + collect_uno(userid); + } + + closedir(dirp); + } + + return 0; +} diff --git a/util/uno/conflict_uno.c b/util/uno/conflict_uno.c new file mode 100644 index 0000000..2e59940 --- /dev/null +++ b/util/uno/conflict_uno.c @@ -0,0 +1,65 @@ +/*-------------------------------------------------------*/ +/* util/conflict_uno.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ¤ÀªR all_user_uno ¬Ý¬Ý¬O§_¦³«ÂЪº userno */ +/* create : 04/10/16 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +typedef struct +{ + int userno; + char userid[IDLEN + 1]; +} COLLECTION; + + +static int +cmp_collection(i, j) + COLLECTION *i, *j; +{ + return i->userno - j->userno; +} + + +int +main() +{ + int fd, n; + COLLECTION *usr; + struct stat st; + + chdir(BBSHOME); + + if ((fd = open("tmp/all_user_uno", O_RDONLY)) < 0) + { + printf("±z¥²¶·¥ý°õ¦æ collect_uno\n"); + return -1; + } + + fstat(fd, &st); + n = st.st_size; + usr = (COLLECTION *) malloc(n); + read(fd, usr, n); + close(fd); + + fd = n / sizeof(COLLECTION); + if (fd > 1) + { + qsort(usr, fd, sizeof(COLLECTION), cmp_collection); + + for (n = 1; n < fd; n++) + { + if (usr[n].userno == usr[n - 1].userno) + printf("%d %s <====> %s\n", usr[n].userno, usr[n - 1].userid, usr[n].userid); + } + } + + free(usr); + + return 0; +} diff --git a/util/uno/fix_uno.c b/util/uno/fix_uno.c new file mode 100644 index 0000000..67097c8 --- /dev/null +++ b/util/uno/fix_uno.c @@ -0,0 +1,520 @@ +/*-------------------------------------------------------*/ +/* util/fix_uno.c ( NTHU CS MapleBBS Ver 3.10 ) */ +/*-------------------------------------------------------*/ +/* target : ««Ø©Ò¦³¨Ï¥ÎªÌªº userno */ +/* create : 04/10/16 */ +/* update : / / */ +/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + + +#define VERBOSE /* ¬O§_Åã¥Ü¸Ô²Ó°T®§ */ + +#ifdef VERBOSE +#define DEBUG(arg) printf arg +#else +#define DEBUG(arg) ; +#endif + + +#define FN_OLDACCT "olduserno" /* °O¿ý¥þ¯¸Âªº userno */ + + +typedef struct +{ + int userno; + char userid[IDLEN + 1]; +} UNO; + + +/*-------------------------------------------------------*/ +/* ««Ø .ACCT ¤Î .USR */ +/*-------------------------------------------------------*/ + + +static int +new_acct(userid) + char *userid; +{ + static int userno = 1; /* userno ±q 1 ¶}©l */ + static time_t now = 100000; /* ÀH«Kµ¹¤@Ӯɶ¡ */ + + char fpath[64]; + ACCT acct; + SCHEMA slot; + UNO uno; + + usr_fpath(fpath, userid, FN_ACCT); + if (rec_get(fpath, &acct, sizeof(ACCT), 0) < 0) + { + /* ¦pªG§ä¤£¨ì .ACCT¡An§R°£©Ò¦³¦W³æ */ + usr_fpath(fpath, userid, FN_PAL); + unlink(fpath); +#ifdef HAVE_LIST + usr_fpath(fpath, userid, FN_LIST); + unlink(fpath); +#endif +#ifdef HAVE_ALOHA + usr_fpath(fpath, userid, FN_ALOHA); + unlink(fpath); +#endif + + DEBUG(("±Â¤© %s ·sªº userno ¥¢±Ñ => µLªkŪ¨ú¸Ó¨Ï¥ÎªÌªº¸ê®Æ\n", userid)); + return; + } + + /* ±N쥻ªº userno ³Æ¥÷µ¹¤ô²y¦CªíÂà´«¨Ï¥Î */ + memset(&uno, 0, sizeof(UNO)); + uno.userno = acct.userno; + str_ncpy(uno.userid, acct.userid, sizeof(uno.userid)); + rec_add(FN_OLDACCT, &uno, sizeof(UNO)); + + acct.userno = userno++; + unlink(fpath); + rec_add(fpath, &acct, sizeof(ACCT)); + + memset(&slot, 0, sizeof(SCHEMA)); + slot.uptime = now++; + memcpy(slot.userid, acct.userid, IDLEN); + rec_add(FN_SCHEMA, &slot, sizeof(SCHEMA)); + + DEBUG(("±Â¤© %s ·sªº userno ¦¨¥\\\n", userid)); +} + + +/*-------------------------------------------------------*/ +/* ¬d userno */ +/*-------------------------------------------------------*/ + + +static int new_num; +static UNO *new_uno; + + +static int +uno_cmp_userid(a, b) + UNO *a, *b; +{ + return strcmp(a->userid, b->userid); +} + + +static void +collect_new_uno() +{ + int fd, num; + SCHEMA slot; + + if ((new_num = rec_num(FN_SCHEMA, sizeof(SCHEMA))) > 0) + { + new_uno = (UNO *) malloc(new_num * sizeof(UNO)); + + if ((fd = open(FN_SCHEMA, O_RDONLY)) >= 0) + { + num = 0; + while (read(fd, &slot, sizeof(SCHEMA)) == sizeof(SCHEMA) && num < new_num) + { + new_uno[num].userno = num + 1; + str_ncpy(new_uno[num].userid, slot.userid, sizeof(new_uno[num].userid)); /* slot.userid ¤£§t '\0' */ + num++; + } + close(fd); + } + + if (new_num > 1) + qsort(new_uno, new_num, sizeof(UNO), uno_cmp_userid); + } +} + + +static int +acct_uno(userid) /* ¥Î ID §ä·sªº userno */ + char *userid; +{ + UNO uno, *find; + + str_ncpy(uno.userid, userid, sizeof(uno.userid)); /* ¨ä¹ê¥Î strcpy §Y¥i¡A¦ý¥H¨¾¸U¤@ */ + if (find = bsearch(&uno, new_uno, new_num, sizeof(UNO), uno_cmp_userid)) + return find->userno; + return 0; +} + + +static int old_num; +static UNO *old_uno; + + +static int +uno_cmp_userno(a, b) + UNO *a, *b; +{ + return a->userno - b->userno; +} + + +static void +collect_old_uno() +{ + int fsize; + + if (old_uno = (UNO *) f_img(FN_OLDACCT, &fsize)) + { + old_num = fsize / sizeof(UNO); + if (old_num > 1) + qsort(old_uno, old_num, sizeof(UNO), uno_cmp_userno); + } +} + + +static int +acct_uno2(olduno) /* ¥Îªº userno §ä·sªº userno */ + int olduno; +{ + UNO uno, *find; + + uno.userno = olduno; + if (find = bsearch(&uno, old_uno, old_num, sizeof(UNO), uno_cmp_userno)) + return acct_uno(find->userid); + return 0; +} + + +/*-------------------------------------------------------*/ +/* ««Ø pal/list.?/aloha/benz/bpal */ +/*-------------------------------------------------------*/ + + +#define BENZ_MAX 512 /* °²³]¨CÓ¤Hªº¨t²Î¨ó´M¤£¶W¹L 512 ¤H */ + +static int rec_max; +static char *rec_pool; + + +static int +new_pal(userid) + char *userid; +{ + int fd, num; + char folder[64]; + PAL pal; + + usr_fpath(folder, userid, FN_PAL); + if ((fd = open(folder, O_RDONLY)) >= 0) + { + num = 0; + while (read(fd, &pal, sizeof(PAL)) == sizeof(PAL) && num < rec_max) + { + if ((pal.userno = acct_uno(pal.userid)) > 0) + { + memcpy(rec_pool + num * sizeof(PAL), &pal, sizeof(PAL)); + num++; + } + } + close(fd); + + unlink(folder); + rec_add(folder, rec_pool, num * sizeof(PAL)); + DEBUG(("¦¨¥\\««Ø %s ªºªB¤Í¦W³æ¡A¦@ %d ¤H\n", userid, num)); + } +} + + +#ifdef HAVE_LIST +static int +new_list(userid) + char *userid; +{ + int fd, ch, num; + char folder[64], fname[16]; + PAL pal; + + for (ch = '1'; ch <= '5'; ch++) + { + sprintf(fname, "%s.%c", FN_LIST, ch); + usr_fpath(folder, userid, fname); + if ((fd = open(folder, O_RDONLY)) >= 0) + { + num = 0; + while (read(fd, &pal, sizeof(PAL)) == sizeof(PAL) && num < rec_max) + { + if ((pal.userno = acct_uno(pal.userid)) > 0) + { + memcpy(rec_pool + num * sizeof(PAL), &pal, sizeof(PAL)); + num++; + } + } + close(fd); + + unlink(folder); + rec_add(folder, rec_pool, num * sizeof(PAL)); + DEBUG(("¦¨¥\\««Ø %s ªº¯S®í¦W³æ¡A¦@ %d ¤H\n", userid, num)); + } + } +} +#endif + + +#ifdef HAVE_ALOHA +static int +new_aloha(userid) + char *userid; +{ + int fd, num; + char folder[64]; + ALOHA aloha; + + FRIENZ frienz; + char fpath[64]; + + usr_fpath(folder, userid, FN_ALOHA); + if ((fd = open(folder, O_RDONLY)) >= 0) + { + /* ·Ç³Æ¦nn¥[¤J¹ï¤èªº frienz */ + memset(&frienz, 0, sizeof(FRIENZ)); + strcpy(frienz.userid, userid); + if ((frienz.userno = acct_uno(userid)) > 0) + { + num = 0; + while (read(fd, &aloha, sizeof(ALOHA)) == sizeof(ALOHA) && num < rec_max) + { + if ((aloha.userno = acct_uno(aloha.userid)) > 0) + { + memcpy(rec_pool + num * sizeof(ALOHA), &aloha, sizeof(ALOHA)); + num++; + + /* §â¦Û¤v¥[¤J¹ï¤èªº frienz ¤¤ */ + usr_fpath(fpath, aloha.userid, FN_FRIENZ); + rec_add(fpath, &frienz, sizeof(FRIENZ)); + DEBUG(("¦¨¥\\««Ø %s ªº¤W¯¸³qª¾¦W³æ¡A¦@ %d ¤H\n", userid, num)); + } + } + } + close(fd); + + unlink(folder); + rec_add(folder, rec_pool, num * sizeof(ALOHA)); + } +} +#endif + + +#ifdef LOGIN_NOTIFY +static int +new_benz(userid) + char *userid; +{ + int fd, num; + char folder[64]; + BENZ benz; + + usr_fpath(folder, userid, FN_BENZ); + if ((fd = open(folder, O_RDONLY)) >= 0) + { + num = 0; + while (read(fd, &benz, sizeof(BENZ)) == sizeof(BENZ) && num < rec_max) + { + if ((benz.userno = acct_uno(benz.userid)) > 0) + { + memcpy(rec_pool + num * sizeof(BENZ), &benz, sizeof(BENZ)); + num++; + } + } + close(fd); + + unlink(folder); + rec_add(folder, rec_pool, num * sizeof(BENZ)); + DEBUG(("¦¨¥\\««Ø %s ªº¨t²Î¨ó´M¦W³æ¡A¦@ %d ¤H\n", userid, num)); + } +} +#endif + + +static int +new_bmw(userid) + char *userid; +{ + int fsize; + char folder[64]; + BMW *data, *head, *tail; + + usr_fpath(folder, userid, FN_BMW); + if (data = (BMW *) f_img(folder, &fsize)) + { + head = data; + tail = data + (fsize / sizeof(BMW)); + do + { + head->sender = acct_uno2(head->sender); + head->recver = acct_uno2(head->recver); + } while (++head < tail); + + unlink(folder); + rec_add(folder, data, fsize); + free(data); + + DEBUG(("¦¨¥\\««Ø %s ªº¤ô²y¦Cªí¡A¦@ %d Ó\n", userid, fsize / sizeof(BMW))); + } +} + + +#ifdef HAVE_MODERATED_BOARD +static int +new_bpal(brdname) + char *brdname; +{ + int fd, num; + char folder[64]; + PAL pal; + + brd_fpath(folder, brdname, FN_PAL); + if ((fd = open(folder, O_RDONLY)) >= 0) + { + num = 0; + while (read(fd, &pal, sizeof(PAL)) == sizeof(PAL) && num < rec_max) + { + if ((pal.userno = acct_uno(pal.userid)) > 0) + { + memcpy(rec_pool + num * sizeof(PAL), &pal, sizeof(PAL)); + num++; + } + } + close(fd); + + unlink(folder); + rec_add(folder, rec_pool, num * sizeof(PAL)); + DEBUG(("¦¨¥\\««Ø %s ªºªO¤Í¦W³æ¡A¦@ %d ¤H\n", brdname, num)); + } +} +#endif + + +/*-------------------------------------------------------*/ +/* ¥D¨ç¦¡ */ +/*-------------------------------------------------------*/ + + +int +main() +{ + char c; + char *userid, fpath[64]; + struct dirent *de; + DIR *dirp; +#ifdef HAVE_MODERATED_BOARD + FILE *fp; +#endif + + chdir(BBSHOME); + + /* itoc.050113: ¥ýµe¤@¶ô°O¾ÐÅé¨Ó¦s¡A³Ì«á¦A¤@¦¸¼g¦^¡A¸`¬Ù I/O */ + rec_max = PAL_MAX; +#ifdef HAVE_ALOHA + if (rec_max < ALOHA_MAX) + rec_max = ALOHA_MAX; +#endif +#ifdef LOGIN_NOTIFY + if (rec_max < BENZ_MAX) + rec_max = BENZ_MAX; +#endif + rec_pool = (char *) malloc(REC_SIZ * rec_max); + + /*-----------------------------------------------------*/ + /* ²Ä¤@°é: ±Â¤©·sªº userno¡A¨Ã§R°£ frienz */ + /*-----------------------------------------------------*/ + + unlink(FN_SCHEMA); + + for (c = 'a'; c <= 'z'; c++) + { + printf("±Â¤©·sªº userno: ¶}©l³B²z %c ¶}ÀYªº ID\n", c); + sprintf(fpath, "usr/%c", c); + + if (!(dirp = opendir(fpath))) + continue; + + while (de = readdir(dirp)) + { + userid = de->d_name; + if (*userid <= ' ' || *userid == '.') + continue; + + /* ±N .ACCT ´«·sªº userno¡A¨Ã¼g¦^ .USR */ + new_acct(userid); + +#ifdef HAVE_ALOHA + /* §R°£ frienz */ + usr_fpath(fpath, userid, FN_FRIENZ); + unlink(fpath); +#endif + } + + closedir(dirp); + } + + collect_new_uno(); + collect_old_uno(); + printf("±Â¤©©Ò¦³¤H·sªº userno §¹¦¨¡A¥þ¯¸¦@ %d ¤H\n", new_num); + + + /*-----------------------------------------------------*/ + /* ²Ä¤G°é: ««Ø©Ò¦³¤Hªº pal/list.?/aloha/benz/bmw */ + /*-----------------------------------------------------*/ + + for (c = 'a'; c <= 'z'; c++) + { + printf("««Ø·sªº pal/list/aloha/benz: ¶}©l³B²z %c ¶}ÀYªº ID\n", c); + sprintf(fpath, "usr/%c", c); + + if (!(dirp = opendir(fpath))) + continue; + + while (de = readdir(dirp)) + { + userid = de->d_name; + if (*userid <= ' ' || *userid == '.') + continue; + + new_pal(userid); +#ifdef HAVE_LIST + new_list(userid); +#endif +#ifdef HAVE_ALOHA + new_aloha(userid); +#endif +#ifdef LOGIN_NOTIFY + new_benz(userid); +#endif + new_bmw(userid); + } + + closedir(dirp); + } + + +#ifdef HAVE_MODERATED_BOARD + /*-----------------------------------------------------*/ + /* ²Ä¤T°é: ««Ø©Ò¦³¬ÝªOªº bpal */ + /*-----------------------------------------------------*/ + + printf("««Ø·sªº bpal\n"); + if (fp = fopen(FN_BRD, "r")) + { + BRD brd; + while (fread(&brd, sizeof(BRD), 1, fp) == 1) + { + if (*brd.brdname) + new_bpal(brd.brdname); + } + } +#endif + + free(rec_pool); + free(new_uno); + free(old_uno); + unlink(FN_OLDACCT); + + return 0; +} diff --git a/util/webc.c b/util/webc.c new file mode 100644 index 0000000..176e1ad --- /dev/null +++ b/util/webc.c @@ -0,0 +1,137 @@ +/*-------------------------------------------------------*/ +/* util/webc.c ( NTHU CS MapleBBS Ver 3.00 ) */ +/*-------------------------------------------------------*/ +/* target : WEB client (command-line mode) */ +/* create : 95/03/29 */ +/* update : 97/03/29 */ +/*-------------------------------------------------------*/ +/* syntax : webc file host URL [port] */ +/*-------------------------------------------------------*/ + + +#include "bbs.h" + +#include <netinet/in.h> +#include <sys/socket.h> +#include <netdb.h> + + +static char pool[4096]; + + +static int +webc(file, host, path, port) + char *file; + char *host; + char *path; + int port; +{ + int cc, sock, tlen; + FILE *fp; + char *xhead, *xtail, buf[120], tag[8]; + + sock = dns_open(host, port); + if (sock < 0) + return -1; + + sprintf(buf, "GET %s\n\n", path); + cc = strlen(buf); + if (send(sock, buf, cc, 0) != cc) + { + close(sock); + return -1; + } + + xhead = pool; + xtail = pool; + tlen = 0; + + strcpy(buf, file); + strcat(buf, "-"); + fp = fopen(buf, "w"); + + for (;;) + { + if (xhead >= xtail) + { + xhead = pool; + cc = recv(sock, xhead, sizeof(pool), 0); + if (cc <= 0) + break; + xtail = xhead + cc; + } + + cc = *xhead++; + if (cc == '<') + { + tlen = 1; + continue; + } + + if (tlen) + { + /* support <br> and <P> */ + + if (cc == '>') + { + if (tlen == 3 && !str_ncmp(tag, "br", 2)) + { + fputc('\n', fp); + } + else if (tlen == 2 && !str_ncmp(tag, "P", 1)) + { + fputc('\n', fp); + fputc('\n', fp); + } + + tlen = 0; + continue; + } + + if (tlen <= 2) + { + tag[tlen - 1] = cc; + } + + tlen++; + continue; + } + + if (cc != '\r') + fputc(cc, fp); + } + + close(sock); + + fputc('\n', fp); + fclose(fp); + rename(buf, file); + return cc; +} + + +/* ----------------------------------------------------- */ +/* main routines */ +/* ----------------------------------------------------- */ + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + if (argc < 4 || argc > 5) + { + printf("Usage: %s file host URL [port]\n", argv[0]); + return -1; + } + + close(0); + close(1); + close(2); + + dns_init(); + + webc(argv[1], argv[2], argv[3], argc == 4 ? 80 : atoi(argv[4])); + return 0; +} |