summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.cvsignore2
-rw-r--r--LICENSE340
-rw-r--r--Makefile9
-rw-r--r--README12
-rw-r--r--docs/ANCESTOR23
-rw-r--r--docs/CHANGE76
-rw-r--r--docs/FAQ146
-rw-r--r--docs/INSTALL49
-rw-r--r--include/common.h198
-rw-r--r--include/config.h197
-rw-r--r--include/gomo.h2156
-rw-r--r--include/modes.h152
-rw-r--r--include/perm.h56
-rw-r--r--include/proto.h522
-rw-r--r--include/pttbbs.conf17
-rw-r--r--include/pttstruct.h390
-rw-r--r--include/pttstruct.h.save363
-rw-r--r--innbbsd/.cvsignore6
-rw-r--r--innbbsd/Makefile206
-rw-r--r--innbbsd/antisplam.h37
-rw-r--r--innbbsd/bbslib.c712
-rw-r--r--innbbsd/bbslib.h62
-rw-r--r--innbbsd/bbslink.c2021
-rw-r--r--innbbsd/bbslink2.c2017
-rw-r--r--innbbsd/bbsnnrp.c1187
-rw-r--r--innbbsd/clibrary.h131
-rw-r--r--innbbsd/closeonexec.c66
-rw-r--r--innbbsd/connectsock.c452
-rw-r--r--innbbsd/ctlinnbbsd.c160
-rw-r--r--innbbsd/daemon.c173
-rw-r--r--innbbsd/daemon.h54
-rw-r--r--innbbsd/dbz.c1918
-rw-r--r--innbbsd/dbz.h32
-rw-r--r--innbbsd/dbztool.c88
-rw-r--r--innbbsd/echobbslib.c713
-rw-r--r--innbbsd/externs.h16
-rw-r--r--innbbsd/file.c185
-rw-r--r--innbbsd/his.c474
-rw-r--r--innbbsd/his.h80
-rw-r--r--innbbsd/innbbsconf.h192
-rw-r--r--innbbsd/innbbsd.c775
-rw-r--r--innbbsd/innbbsd.h9
-rw-r--r--innbbsd/inndchannel.c657
-rw-r--r--innbbsd/inntobbs.c323
-rw-r--r--innbbsd/inntobbs.h39
-rw-r--r--innbbsd/mkhistory.c14
-rw-r--r--innbbsd/nntp.h145
-rw-r--r--innbbsd/pmain.c62
-rw-r--r--innbbsd/port.c28
-rw-r--r--innbbsd/receive_article.c1204
-rw-r--r--innbbsd/rfc931.c144
-rw-r--r--mbbsd/.cvsignore2
-rw-r--r--mbbsd/Makefile45
-rw-r--r--mbbsd/admin.c1105
-rw-r--r--mbbsd/announce.c1590
-rw-r--r--mbbsd/args.c62
-rw-r--r--mbbsd/bbcall.c268
-rw-r--r--mbbsd/bbs.c1904
-rw-r--r--mbbsd/board.c1098
-rw-r--r--mbbsd/cache.c1053
-rw-r--r--mbbsd/cal.c512
-rw-r--r--mbbsd/calendar.c284
-rw-r--r--mbbsd/card.c625
-rw-r--r--mbbsd/chat.c623
-rw-r--r--mbbsd/chc_draw.c187
-rw-r--r--mbbsd/chc_net.c28
-rw-r--r--mbbsd/chc_play.c277
-rw-r--r--mbbsd/chc_rule.c186
-rw-r--r--mbbsd/chicken.c989
-rw-r--r--mbbsd/dark.c456
-rw-r--r--mbbsd/descrypt.c616
-rw-r--r--mbbsd/dice.c447
-rw-r--r--mbbsd/edit.c2256
-rw-r--r--mbbsd/friend.c509
-rw-r--r--mbbsd/gamble.c361
-rw-r--r--mbbsd/gomo.c417
-rw-r--r--mbbsd/gomo1.c136
-rw-r--r--mbbsd/guess.c364
-rw-r--r--mbbsd/indict.c184
-rw-r--r--mbbsd/io.c611
-rw-r--r--mbbsd/kaede.c95
-rw-r--r--mbbsd/lovepaper.c120
-rw-r--r--mbbsd/mail.c1675
-rw-r--r--mbbsd/mbbsd.c1465
-rw-r--r--mbbsd/menu.c596
-rw-r--r--mbbsd/more.c931
-rw-r--r--mbbsd/name.c473
-rw-r--r--mbbsd/osdep.c79
-rw-r--r--mbbsd/othello.c541
-rw-r--r--mbbsd/page.c130
-rw-r--r--mbbsd/passwd.c138
-rw-r--r--mbbsd/read.c998
-rw-r--r--mbbsd/record.c536
-rw-r--r--mbbsd/register.c339
-rw-r--r--mbbsd/screen.c559
-rw-r--r--mbbsd/stuff.c524
-rw-r--r--mbbsd/syspost.c102
-rw-r--r--mbbsd/talk.c2663
-rw-r--r--mbbsd/term.c144
-rw-r--r--mbbsd/toolkit.c14
-rw-r--r--mbbsd/topsong.c79
-rw-r--r--mbbsd/uptime23
-rw-r--r--mbbsd/user.c980
-rw-r--r--mbbsd/var.c268
-rw-r--r--mbbsd/vice.c151
-rw-r--r--mbbsd/vote.c1068
-rw-r--r--mbbsd/voteboard.c447
-rw-r--r--mbbsd/xyz.c448
-rw-r--r--sample/Makefile11
-rw-r--r--sample/crontab56
-rw-r--r--sample/etc/Logout20
-rw-r--r--sample/etc/Makefile18
-rw-r--r--sample/etc/Welcome18
-rw-r--r--sample/etc/Welcome_birth23
-rw-r--r--sample/etc/Welcome_login12
-rw-r--r--sample/etc/chickens/Makefile23
-rw-r--r--sample/etc/chickens/a011
-rw-r--r--sample/etc/chickens/a111
-rw-r--r--sample/etc/chickens/a1015
-rw-r--r--sample/etc/chickens/a1115
-rw-r--r--sample/etc/chickens/a1213
-rw-r--r--sample/etc/chickens/a1314
-rw-r--r--sample/etc/chickens/a1417
-rw-r--r--sample/etc/chickens/a1515
-rw-r--r--sample/etc/chickens/a1615
-rw-r--r--sample/etc/chickens/a214
-rw-r--r--sample/etc/chickens/a313
-rw-r--r--sample/etc/chickens/a413
-rw-r--r--sample/etc/chickens/a515
-rw-r--r--sample/etc/chickens/a613
-rw-r--r--sample/etc/chickens/a716
-rw-r--r--sample/etc/chickens/a813
-rw-r--r--sample/etc/chickens/a914
-rw-r--r--sample/etc/chickens/b09
-rw-r--r--sample/etc/chickens/b19
-rw-r--r--sample/etc/chickens/b1014
-rw-r--r--sample/etc/chickens/b1114
-rw-r--r--sample/etc/chickens/b1215
-rw-r--r--sample/etc/chickens/b1317
-rw-r--r--sample/etc/chickens/b1416
-rw-r--r--sample/etc/chickens/b1517
-rw-r--r--sample/etc/chickens/b1618
-rw-r--r--sample/etc/chickens/b211
-rw-r--r--sample/etc/chickens/b310
-rw-r--r--sample/etc/chickens/b411
-rw-r--r--sample/etc/chickens/b512
-rw-r--r--sample/etc/chickens/b612
-rw-r--r--sample/etc/chickens/b712
-rw-r--r--sample/etc/chickens/b813
-rw-r--r--sample/etc/chickens/b913
-rw-r--r--sample/etc/chickens/buymedicine14
-rw-r--r--sample/etc/chickens/buyoo14
-rw-r--r--sample/etc/chickens/c08
-rw-r--r--sample/etc/chickens/c19
-rw-r--r--sample/etc/chickens/c1011
-rw-r--r--sample/etc/chickens/c1110
-rw-r--r--sample/etc/chickens/c1212
-rw-r--r--sample/etc/chickens/c1311
-rw-r--r--sample/etc/chickens/c1412
-rw-r--r--sample/etc/chickens/c1512
-rw-r--r--sample/etc/chickens/c1611
-rw-r--r--sample/etc/chickens/c29
-rw-r--r--sample/etc/chickens/c38
-rw-r--r--sample/etc/chickens/c411
-rw-r--r--sample/etc/chickens/c512
-rw-r--r--sample/etc/chickens/c610
-rw-r--r--sample/etc/chickens/c712
-rw-r--r--sample/etc/chickens/c812
-rw-r--r--sample/etc/chickens/c911
-rw-r--r--sample/etc/chickens/clean14
-rw-r--r--sample/etc/chickens/d010
-rw-r--r--sample/etc/chickens/d19
-rw-r--r--sample/etc/chickens/d1011
-rw-r--r--sample/etc/chickens/d1115
-rw-r--r--sample/etc/chickens/d1213
-rw-r--r--sample/etc/chickens/d1313
-rw-r--r--sample/etc/chickens/d1413
-rw-r--r--sample/etc/chickens/d1511
-rw-r--r--sample/etc/chickens/d1611
-rw-r--r--sample/etc/chickens/d211
-rw-r--r--sample/etc/chickens/d316
-rw-r--r--sample/etc/chickens/d412
-rw-r--r--sample/etc/chickens/d514
-rw-r--r--sample/etc/chickens/d612
-rw-r--r--sample/etc/chickens/d716
-rw-r--r--sample/etc/chickens/d814
-rw-r--r--sample/etc/chickens/d913
-rw-r--r--sample/etc/chickens/deadth15
-rw-r--r--sample/etc/chickens/e06
-rw-r--r--sample/etc/chickens/e16
-rw-r--r--sample/etc/chickens/e1012
-rw-r--r--sample/etc/chickens/e1114
-rw-r--r--sample/etc/chickens/e1215
-rw-r--r--sample/etc/chickens/e1314
-rw-r--r--sample/etc/chickens/e1413
-rw-r--r--sample/etc/chickens/e1513
-rw-r--r--sample/etc/chickens/e1614
-rw-r--r--sample/etc/chickens/e26
-rw-r--r--sample/etc/chickens/e36
-rw-r--r--sample/etc/chickens/e48
-rw-r--r--sample/etc/chickens/e59
-rw-r--r--sample/etc/chickens/e69
-rw-r--r--sample/etc/chickens/e711
-rw-r--r--sample/etc/chickens/e811
-rw-r--r--sample/etc/chickens/e912
-rw-r--r--sample/etc/chickens/eat14
-rw-r--r--sample/etc/chickens/f09
-rw-r--r--sample/etc/chickens/f19
-rw-r--r--sample/etc/chickens/f1015
-rw-r--r--sample/etc/chickens/f1114
-rw-r--r--sample/etc/chickens/f1214
-rw-r--r--sample/etc/chickens/f1314
-rw-r--r--sample/etc/chickens/f1414
-rw-r--r--sample/etc/chickens/f1515
-rw-r--r--sample/etc/chickens/f1615
-rw-r--r--sample/etc/chickens/f212
-rw-r--r--sample/etc/chickens/f312
-rw-r--r--sample/etc/chickens/f413
-rw-r--r--sample/etc/chickens/f513
-rw-r--r--sample/etc/chickens/f614
-rw-r--r--sample/etc/chickens/f714
-rw-r--r--sample/etc/chickens/f815
-rw-r--r--sample/etc/chickens/f915
-rw-r--r--sample/etc/chickens/food14
-rw-r--r--sample/etc/chickens/g05
-rw-r--r--sample/etc/chickens/g15
-rw-r--r--sample/etc/chickens/g1013
-rw-r--r--sample/etc/chickens/g1115
-rw-r--r--sample/etc/chickens/g1215
-rw-r--r--sample/etc/chickens/g1314
-rw-r--r--sample/etc/chickens/g1414
-rw-r--r--sample/etc/chickens/g1514
-rw-r--r--sample/etc/chickens/g1614
-rw-r--r--sample/etc/chickens/g25
-rw-r--r--sample/etc/chickens/g36
-rw-r--r--sample/etc/chickens/g46
-rw-r--r--sample/etc/chickens/g58
-rw-r--r--sample/etc/chickens/g610
-rw-r--r--sample/etc/chickens/g711
-rw-r--r--sample/etc/chickens/g814
-rw-r--r--sample/etc/chickens/g914
-rw-r--r--sample/etc/chickens/h09
-rw-r--r--sample/etc/chickens/h19
-rw-r--r--sample/etc/chickens/h1015
-rw-r--r--sample/etc/chickens/h1114
-rw-r--r--sample/etc/chickens/h1214
-rw-r--r--sample/etc/chickens/h1314
-rw-r--r--sample/etc/chickens/h1414
-rw-r--r--sample/etc/chickens/h1515
-rw-r--r--sample/etc/chickens/h1615
-rw-r--r--sample/etc/chickens/h212
-rw-r--r--sample/etc/chickens/h312
-rw-r--r--sample/etc/chickens/h413
-rw-r--r--sample/etc/chickens/h513
-rw-r--r--sample/etc/chickens/h614
-rw-r--r--sample/etc/chickens/h714
-rw-r--r--sample/etc/chickens/h815
-rw-r--r--sample/etc/chickens/h915
-rw-r--r--sample/etc/chickens/hit14
-rw-r--r--sample/etc/chickens/i09
-rw-r--r--sample/etc/chickens/i19
-rw-r--r--sample/etc/chickens/i1015
-rw-r--r--sample/etc/chickens/i1114
-rw-r--r--sample/etc/chickens/i1214
-rw-r--r--sample/etc/chickens/i1314
-rw-r--r--sample/etc/chickens/i1414
-rw-r--r--sample/etc/chickens/i1515
-rw-r--r--sample/etc/chickens/i1615
-rw-r--r--sample/etc/chickens/i212
-rw-r--r--sample/etc/chickens/i312
-rw-r--r--sample/etc/chickens/i413
-rw-r--r--sample/etc/chickens/i513
-rw-r--r--sample/etc/chickens/i614
-rw-r--r--sample/etc/chickens/i714
-rw-r--r--sample/etc/chickens/i815
-rw-r--r--sample/etc/chickens/i915
-rw-r--r--sample/etc/chickens/j08
-rw-r--r--sample/etc/chickens/j19
-rw-r--r--sample/etc/chickens/j1012
-rw-r--r--sample/etc/chickens/j1112
-rw-r--r--sample/etc/chickens/j1211
-rw-r--r--sample/etc/chickens/j1312
-rw-r--r--sample/etc/chickens/j1413
-rw-r--r--sample/etc/chickens/j1513
-rw-r--r--sample/etc/chickens/j1613
-rw-r--r--sample/etc/chickens/j27
-rw-r--r--sample/etc/chickens/j310
-rw-r--r--sample/etc/chickens/j49
-rw-r--r--sample/etc/chickens/j512
-rw-r--r--sample/etc/chickens/j69
-rw-r--r--sample/etc/chickens/j710
-rw-r--r--sample/etc/chickens/j810
-rw-r--r--sample/etc/chickens/j911
-rw-r--r--sample/etc/chickens/k013
-rw-r--r--sample/etc/chickens/k111
-rw-r--r--sample/etc/chickens/k1013
-rw-r--r--sample/etc/chickens/k1113
-rw-r--r--sample/etc/chickens/k1212
-rw-r--r--sample/etc/chickens/k1312
-rw-r--r--sample/etc/chickens/k1412
-rw-r--r--sample/etc/chickens/k1514
-rw-r--r--sample/etc/chickens/k1614
-rw-r--r--sample/etc/chickens/k210
-rw-r--r--sample/etc/chickens/k311
-rw-r--r--sample/etc/chickens/k412
-rw-r--r--sample/etc/chickens/k512
-rw-r--r--sample/etc/chickens/k613
-rw-r--r--sample/etc/chickens/k714
-rw-r--r--sample/etc/chickens/k810
-rw-r--r--sample/etc/chickens/k911
-rw-r--r--sample/etc/chickens/kiss14
-rw-r--r--sample/etc/chickens/l09
-rw-r--r--sample/etc/chickens/l19
-rw-r--r--sample/etc/chickens/l1015
-rw-r--r--sample/etc/chickens/l1114
-rw-r--r--sample/etc/chickens/l1214
-rw-r--r--sample/etc/chickens/l1314
-rw-r--r--sample/etc/chickens/l1414
-rw-r--r--sample/etc/chickens/l1515
-rw-r--r--sample/etc/chickens/l1615
-rw-r--r--sample/etc/chickens/l212
-rw-r--r--sample/etc/chickens/l312
-rw-r--r--sample/etc/chickens/l413
-rw-r--r--sample/etc/chickens/l513
-rw-r--r--sample/etc/chickens/l614
-rw-r--r--sample/etc/chickens/l714
-rw-r--r--sample/etc/chickens/l815
-rw-r--r--sample/etc/chickens/l915
-rw-r--r--sample/etc/chickens/m09
-rw-r--r--sample/etc/chickens/m19
-rw-r--r--sample/etc/chickens/m1015
-rw-r--r--sample/etc/chickens/m1114
-rw-r--r--sample/etc/chickens/m1214
-rw-r--r--sample/etc/chickens/m1314
-rw-r--r--sample/etc/chickens/m1414
-rw-r--r--sample/etc/chickens/m1515
-rw-r--r--sample/etc/chickens/m1615
-rw-r--r--sample/etc/chickens/m212
-rw-r--r--sample/etc/chickens/m312
-rw-r--r--sample/etc/chickens/m413
-rw-r--r--sample/etc/chickens/m513
-rw-r--r--sample/etc/chickens/m614
-rw-r--r--sample/etc/chickens/m714
-rw-r--r--sample/etc/chickens/m815
-rw-r--r--sample/etc/chickens/m915
-rw-r--r--sample/etc/chickens/medicine14
-rw-r--r--sample/etc/chickens/nofood18
-rw-r--r--sample/etc/chickens/nohp16
-rw-r--r--sample/etc/chickens/nosatis6
-rw-r--r--sample/etc/chickens/oo14
-rw-r--r--sample/etc/chickens/read14
-rw-r--r--sample/etc/chickens/sell23
-rw-r--r--sample/etc/chickens/toofat17
-rw-r--r--sample/etc/chickens/tootired15
-rw-r--r--sample/etc/domain_name_query256
-rw-r--r--sample/etc/feast47
-rw-r--r--sample/etc/goodbye19
-rw-r--r--sample/etc/register17
-rw-r--r--sample/etc/registered21
-rw-r--r--sample/etc/today_boring22
-rw-r--r--sample/etc/ve.hlp127
-rw-r--r--sample/innd/Makefile9
-rw-r--r--sample/innd/bbsname.bbs1
-rw-r--r--sample/innd/newsfeeds.bbs3
-rw-r--r--sample/innd/nodelist.bbs4
-rw-r--r--sample/innd/ntu.active1
-rw-r--r--sample/pttbbs.conf10
-rw-r--r--sample/rc.local4
-rw-r--r--util/.cvsignore42
-rw-r--r--util/BM_money.c117
-rw-r--r--util/BM_money.sh5
-rw-r--r--util/BOARDS.bidbin0 -> 1006592 bytes
-rw-r--r--util/DEADJOE9
-rw-r--r--util/LocalVars.pm.sample22
-rw-r--r--util/Makefile167
-rw-r--r--util/Makefile.save152
-rw-r--r--util/a.outbin0 -> 14661 bytes
-rw-r--r--util/account.c414
-rw-r--r--util/antispam.c122
-rw-r--r--util/backpasswd.sh11
-rw-r--r--util/bbsctl.c63
-rw-r--r--util/bbsmail.c239
-rw-r--r--util/bbsrf.c148
-rw-r--r--util/birth.c99
-rw-r--r--util/buildAnnounce.c69
-rw-r--r--util/buildAnnounce.sh5
-rw-r--r--util/buildir.c124
-rw-r--r--util/countalldice.c95
-rw-r--r--util/cpdeadbrd.c41
-rw-r--r--util/dailybackup.pl48
-rw-r--r--util/daymandex.c269
-rw-r--r--util/deluserfile.c147
-rw-r--r--util/descrypt.c616
-rw-r--r--util/expire.c226
-rw-r--r--util/horoscope.c157
-rw-r--r--util/in2outmailbin0 -> 39392 bytes
-rw-r--r--util/in2outmail.c288
-rw-r--r--util/initbbs.c223
-rw-r--r--util/inndBM.c194
-rw-r--r--util/jungo.c202
-rw-r--r--util/kenben.c44
-rw-r--r--util/mailog.sh9
-rw-r--r--util/mandex.c263
-rw-r--r--util/merge_board.c106
-rw-r--r--util/merge_passwd.c106
-rw-r--r--util/opendice.sh10
-rw-r--r--util/openticket.c198
-rw-r--r--util/openticket.sh10
-rw-r--r--util/openvice.c54
-rw-r--r--util/outmail.c274
-rw-r--r--util/parse_news.c78
-rw-r--r--util/post.c61
-rw-r--r--util/poststat.c497
-rw-r--r--util/reaper.c69
-rw-r--r--util/rmuid.c50
-rw-r--r--util/shmsweep.c43
-rw-r--r--util/showboard.c70
-rw-r--r--util/smtest.c296
-rw-r--r--util/smtest.c.save172
-rw-r--r--util/smtest.result1191
-rw-r--r--util/smtest.result23
-rw-r--r--util/smtest.temp231
-rw-r--r--util/stock.perl31
-rw-r--r--util/stock.sh5
-rw-r--r--util/tarqueue.pl75
-rw-r--r--util/testkenben.txt11
-rw-r--r--util/toplazyBBM.c203
-rw-r--r--util/toplazyBBM.sh3
-rw-r--r--util/toplazyBM.c211
-rw-r--r--util/toplazyBM.sh3
-rw-r--r--util/topsong.sh5
-rw-r--r--util/topusr.c205
-rw-r--r--util/tunepasswd.c77
-rw-r--r--util/uhash_loader.c129
-rw-r--r--util/userlist.c48
-rw-r--r--util/util.h31
-rw-r--r--util/util_cache.c518
-rw-r--r--util/util_passwd.c139
-rw-r--r--util/util_record.c245
-rw-r--r--util/waterball.pl149
-rw-r--r--util/weather.perl31
-rw-r--r--util/weather.sh5
-rw-r--r--util/webgrep.c46
-rw-r--r--util/xchatd.c3504
-rw-r--r--util/xchatd.h111
-rw-r--r--util/yearsold.c112
446 files changed, 68629 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 00000000..80c7b7f0
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1,2 @@
+tmp
+pttbbs.conf
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..d60c31a9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..dabc6044
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,9 @@
+SUBDIR= mbbsd util innbbsd
+BBSHOME?=$(HOME)
+
+all install clean:
+ @for i in $(SUBDIR); do\
+ cd $$i;\
+ make BBSHOME=$(BBSHOME) OSTYPE=$(OSTYPE) $@;\
+ cd ..;\
+ done
diff --git a/README b/README
new file mode 100644
index 00000000..672bb33c
--- /dev/null
+++ b/README
@@ -0,0 +1,12 @@
+
+§Ö³t¦w¸Ë¤èªk½Ð°Ñ¾\ INSTALL
+
+±`¨£°ÝÃD¤Î sendmail.cf ªº³]ªk½Ð¨£ FAQ
+
+sample ¤U¦³ crontab ¤Î rc.local ªº½d¨Ò
+
+¦³¥ô¦ó°ÝÃD½Ðmailµ¹ pttbbs@ptt2.csie.ntu.edu.tw
+
+¤]¥i¨ì ptt2.csie.ntu.edu.tw / ptt2.twbbs.org ªº PttSrc ªO¸ß°Ý
+
+ÁÂÁÂ :)
diff --git a/docs/ANCESTOR b/docs/ANCESTOR
new file mode 100644
index 00000000..269e7cea
--- /dev/null
+++ b/docs/ANCESTOR
@@ -0,0 +1,23 @@
+Pirate Bulletin Board System Version: 1.00
+Copyright (C) 1990 Edward A. Luke
+
+Eagles Bulletin Board System Version: 2.00-3.00
+Copyright (C) 1992, 1993, 1994 Raymond R. Rocker, Dominic B. Tynes
+ Guy T. Vega
+
+Phoenix Bulletin Board System Version: 3.00-4.0
+Copyright (C) 1993, 1994 Ming-Feng Chen, Ji-Tzay Yang
+ Tsun-Yi Wen
+
+¯µ±K±¡¤H¸ê°T¯¸ Version: 3.1-4.0
+Copyright (C) 1994 ²ÅãŲ, ¼B¨Î®p
+
+MapleBridge Bulletin Board System Version: 2.36
+Copyright (C) 1994-1995 Jeng-Hermes Lin, Hung-Pin Chen
+ SoC, Xshadow
+
+SunOfBeach Bulletin Board System Version: 0.22
+Copyleft ($) 1996 Kaede, woju
+
+Ptt Bulletin Board System Ptt, Jaky, Action, Heat, Dunk
+§å½ð½ð¹ê·~§{ CharlieL, DickG, DavidYu
diff --git a/docs/CHANGE b/docs/CHANGE
new file mode 100644
index 00000000..2ddb6869
--- /dev/null
+++ b/docs/CHANGE
@@ -0,0 +1,76 @@
+Version 1.0.2 2001/07/17
+
+* ·s¼W util/merge_passwd
+* ·s¼W util/merge_board
+* ­×¥¿ load fromcache ¶W¹L 300 ¦æ·| segfault ªº bug
+* ­×¥¿¨Ó·½¦r¦ê¦b FreeBSD ¤U·|¦³¶Ã½Xªº°ÝÃD
+* ­×¥¿ mbbsd ¤¤ select() ¤£¦nªº¥Îªk
+* ­×¥¿ more.c ¤¤ªº¦w¥þ°ÝÃD (by kcwu)
+
+--------------------------------------------------
+Version 1.0.1 2001/04/26
+
+* ±N¤å¥ó·h¦Ü docs ¥Ø¿ý¤U
+* ­×§ï config.h ¤¤ªº MAX_ACTIVE, MAX_CPULOAD
+ ¨Ã¥[¤J FORCE_PROCESS_REGISTER_FORM ªº¿ï¶µ
+* ·s¼W­×´_¿ò¥¢¬ÝªOªº¥\¯à (press 'R')
+* ­×¥¿°T®§ªº¿ù»~
+* ­×¥¿«ÕÆF¤ô²y
+* ²¾°£¦b¨Ï¥ÎªÌ¦W³æ«ö'N'­×§ï¼ÊºÙªº¥\¯à, ¸Ó¥\¯à¥i¯à¦³bug¦s¦b
+* ·s¼W util/shmsweep
+
+--------------------------------------------------
+Version 1.0.0 2000/09/16
+
+* ­×¥¿ Select ¬ÝªOªº bug
+* ·s¼W Reaper, §R°£¹L´Á±b¸¹
+* ·s¼W chickens ¨ì sample ¤¤
+* ·s¼W initbbs ªº¥\¯à: ªì©l¤Æ°ÊºA¬ÝªO, ½d¥»ºëÆF
+* ·s¼W FAQ
+
+--------------------------------------------------
+Version 0.9.7 2000/08/31
+
+* ·s¼W tunepasswd
+* ­×¥¿ innbbsd ªº bug
+* xchatd ¹B§@¥¿±`
+* ¾ã¦X buildir
+* ­×¥¿ Makefile ¦b¬Y¨Ç Linux ¤WµLªk¥¿±`¤u§@ªº bug
+* ¦b sample ªº¥Ø¿ý¤U¥´ make install §Y¥i¦Û°Ê¦w¸Ë sample ³]©wÀÉ
+
+--------------------------------------------------
+Version 0.9.6 2000/06/28
+
+* ­×¥¿¨Ï¥Î¼È¦sÀÉ·|·í±¼ªº bug
+* ¾ã¦X FreeBSD ©M Linux ªº Makefile, ¤£»Ý­n¦A¤â°Ê­×§ï
+* §â pttbbs.conf ±q include ·h¨ì pttsrc ¤U
+* ·s¼W outmail ¨ú¥N bmda
+* ¾ã¦X xchatd (¥¼´ú¸Õ)
+* ¾ã¦X innbbsd (¥¼´ú¸Õ)
+
+--------------------------------------------------
+Version 0.9.5 2000/06/07
+
+* ­×¥¿¦b Linux µLªk talk ªº bug
+* ¦pªG¬ÝªO¦Cªí¬OªÅªºªº¸Ü, ¦Û°Ê¶i¤J¶}ªO¥\¯à
+* ·s¼W initbbs ¤u¨ãµ{¦¡
+* ·s¼W BBSHOME environment variable ªº¨Ï¥Î (¨£ INSTALL)
+* ·h²¾³¡¥÷³]©w¨ì include/pttbbs.conf
+* ­×¥¿¦bFreeBSD¤WµLªk¨ú±o swapinfo ªº bug
+
+--------------------------------------------------
+Version 0.9.4 2000/06/03
+
+* §âµ{¦¡¤¤¦³¥Î¨ì ncurses ªº¦a¤è²¾°£, ¤£¦A»Ý­n -ltermcap, -lncurses
+* ­×¥¿¤@­Ó³y¦¨µL½a°j°éªº Bug
+* ²¾°£¥H¨Ï¥ÎªÌ¦WºÙ·j´M¥þ¯¸¤å³¹ªº¥\¯à
+
+--------------------------------------------------
+Version 0.9.3 2000/05/23
+
+* ­×¥¿¦b Linux ¤W Makefile ªº°ÝÃD
+
+--------------------------------------------------
+Version 0.9.2 2000/05/20
+
+* port ¨ì Linux ¤W
diff --git a/docs/FAQ b/docs/FAQ
new file mode 100644
index 00000000..bc2904a0
--- /dev/null
+++ b/docs/FAQ
@@ -0,0 +1,146 @@
+ §@ªÌ DavidYu (^^Y) ¬ÝªO PttSrc
+ ¼ÐÃD Re: ¦w¸Ë§¹³s½u®É.....
+ ®É¶¡ Thu May 18 15:08:04 2000
+¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢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¡mJamesCheng (ºô²y¤ñ±Æ²y¦nª±°Õ¡I)¡n¤§»Ê¨¥¡G
+: §Ú¦b¦w¸Ë§¹¤§«á ¥Îroot°õ¦æ mbbsd 23
+: ³s½u¬Ý¥X²{
+: Escape character is '^]'.
+: ¡iª«ªv¼Ö¶é¡j¡· ª«ªv²Ä¤G¯¸ ¡·(pt.mc.ntu.edu.tw)
+: ½Õ´T(140.112.122.44) ¨t²Î­t²ü 0.00 0.01 0.00
+: Connection closed by foreign host.
+: µM«á¨t²Î¥X²{¤U¦C°T®§
+: [shmget error] key = 8ab
+: errno = 12: Cannot allocate memory
+: ³o¬O¦ó­ì¦]©O¡H
+shared memory­n¥[¤j
+¦bkernel config file¤¤¥[¤@¦æ
+options SHMMAXPGS=4100
+­«·smake kernel
+
+--
+¡° µo«H¯¸: §å½ð½ð¹ê·~§{(ptt.twbbs.org)
+¡» From: oio.m6.ntu.edu.t
+
+ §@ªÌ DavidYu (Do it YOURSELF!) ¬ÝªO PttSrc
+ ¼ÐÃD Re: ½Ð°Ý¤@¤U...
+ ®É¶¡ Sat May 27 18:41:39 2000
+¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢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¡mclifflu ( ·Ð§r·Ð§r·Ð~~~)¡n¤§»Ê¨¥¡G
+: ¡° ¤Þ­z¡mhscat (´_¯¸¤F¡I)¡n¤§»Ê¨¥¡G
+: : ¤£¹L§Ú¦³¤@­Ó¤p¤pªº°ÝÃD
+: : ¯à¤£¯à«ü¾É¤@¤U...·Q­n¶}·sªºª©À³¸Ó±q­þÃä¶}©O¡H
+: ¥D¿ï³æ¤Uªº (0)Admin ??
+: : ¦]¬°§Ú¹ê¦b§ä¤£¨ì«ç»ò¶}·s¬ÝªO...:~~~~...
+¤£¤£¤£..
+¶}ªO­n±q¤ÀÃþ¬ÝªOªº¦a¤è¶},³o³¡¥÷¦³ÂI¤p¤pªº½ÆÂø,
+©M¥H©¹ªºª©¥»¤£¤@¼Ë,§Ú¨Ó²³æ»¡©ú¤@¤U:
+
+­º¥ý¤¶²Ð¬ÝªO.
+¬ÝªO¦³¨âºØ, ¤@¯ë¬ÝªO©M¸s²Õ¬ÝªO. ¦pªG¥ÎÀɮרt²Îªº¬[ºc¨Ó¬Ýªº¸Ü,
+¤@¯ë¬ÝªO¦p¦P file, ¦Ó¸s²Õ¬ÝªO´N¬O directory
+(¦b©Ò¦³¬ÝªO¦Cªíªº¦a¤è¥u·|¥X²{¤@¯ë¬ÝªO)
+
+¤@­Ó¬ÝªO¦³UID¤ÎGID³o¨â­ÓÄÝ©Ê. UID¬Ouniqueªº,±q1¶}©l¤À°t,¨t²Î¦b¶}ªO®É·|¦
+Û°Êallocate¤@­Ó. ¦ÓGID¬O«ü©w³o­Ó¬ÝªO¦b­þ¤@­Ó¸s²Õ¬ÝªO¤§¤U(¬ÝªO¬O¾ðª¬¬[ºcªº)
+©Ò¥H¦pªG¦³¤@­Ó¸s²Õ¬ÝªOªºUID¬Ox, «hGID¬°xªº¬ÝªO³£·|Â\¦b¸Ó¸s²Õ¬ÝªO¤§¤U
+¦Ó¦pªG¬ÝªOGID¬°0(«O¯dªºUID)ªº¸Ü,¸Ó¬ÝªO´N·|¥X²{¦b¤@¶}©l±q¥D¿ï³æ¶iCLASSªº
+¨º­Ó¦a¤è
+
+¦Ü©ó¶}ªOªº¤èªk.
+­º¥ý±qCLASS¶i¨ì§A·Q­n¶}·sªOªºÃþ§O¤U,µM«á«ö¤jB³]©w
+¦p¦¹·s¶}ªºªO´N·|¦Û°Êassign GID ¨ì¨º­ÓÃþ§O¤U
+
+¦pªG­n¯ë°Ê¤@­Ó¤w¸g¶}¦nªºªO¨ì¨ä¥LÃþ§Oªº¸Ü
+¥ý§ä¥X¨º­ÓÃþ§O(¸s²Õ¬ÝªO)ªºUID, «ö¤jE¥i¥H¬Ý¨ì
+µM«á§â­n·h°ÊªºªOªºGID³]¦¨¨º­ÓUID¤Î¥i
+
+­È±oª`·Nªº¬O, ¦pªG§â¬Y­Ó¨Ï¥ÎªÌ³]¦¨¬Y¸s²Õ¬ÝªOªºªO¥Dªº¸Ü
+«h·í¥L±qCLASS¶i¨ì¨º­Ó¸s²Õ®É·|Àò±o¤p²ÕªøªºÅv­­(¥i¥H¶}ªO,³]©w¬ÝªOµ¥µ¥)
+­n¯S§O¤p¤ß
+
+¤ñ¸û³Â·Ðªº¦a¤è:
+¤@­Ó·s¶}ªº¸s²Õ¸Ì­±¨Ã¨S¦³¥ô¦ó¬ÝªO,©Ò¥HµLªk±q¿ï³æ¶i¥h¸Ì­±¶}ªO
+³o®É­Ô´N»Ý­n¦b¥i¶}ªOªº¦a¤è¥ý¶}­ÓªO,µM«á¦A§â¨º­ÓªOªºGID³]¹L¥h§Y¥i
+(³o¤]¬O¬°¤°»ò»Ý­n¤@­Óinitialªº.BOARDSªº­ì¦] :p)
+
+--
+¡° µo«H¯¸: §å½ð½ð¹ê·~§{(ptt.twbbs.org)
+¡» From: meow.cc.ntu.edu.
+
+ §@ªÌ DavidYu (ÜI~~~~~~~~~~) ¬ÝªO PttSrc
+ ¼ÐÃD sendmail.cf­n§ïªº¦a¤è(°Ñ¦Ò¥Î)
+ ®É¶¡ Sun Jul 9 09:39:53 2000
+¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w
+
+¦³ÃC¦âªº¬O­n¥[¤W¥hªº
+­nª`·N,tab©Mspace¤£¯à²V¥Î
+
+######################################
+### Ruleset 0 -- Parse Address ###
+######################################
+S0
+
+R$* $: $>Parse0 $1 initial parsing
+R<@> $#local $: <@> special case error msgs
+R$* $: $>98 $1 handle local hacks
+R$+.bbs < @ $=w .> $#bbsmail $: $1 bbs mail gateway
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+R$* $: $>Parse1 $1 final parsing
+
+......
+
+# handle locally delivered names
+R$+.bbs $#bbsmail $:$1 bbs mail gateway
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+R$=L $#local $: @ $1 special local names
+R$+ $#local $: $1 regular local names
+
+###########################################################################
+### Ruleset 5 -- special rewriting after aliases have been expanded ###
+###########################################################################
+
+......
+
+##################################################
+### Local and Program Mailer specification ###
+##################################################
+
+##### @(#)local.m4 8.30 (Berkeley) 6/30/1998 #####
+
+Mlocal, P=/usr/libexec/mail.local, F=lsDFMAw5:/|@qSXfmnz9P, S=10/30, R=
+ T=DNS/RFC822/X-Unix,
+ A=mail.local -l
+Mprog, P=/bin/sh, F=lsDFMoqeu9, S=10/30, R=20/40, D=$z:/,
+ T=X-Unix,
+ A=sh -c $u
+Mbbsmail, P=/home/bbs/bin/bbsmail, F=lsSDFMhPu, U=bbs, S=10,R=20/40,
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ A=bbsmail $u
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+--
+¡° µo«H¯¸: §å½ð½ð¹ê·~§{(ptt.twbbs.org)
+¡» From: oio.m6.ntu.edu.t
+
+ §@ªÌ DavidYu (ï~~~~~~~~~~~~~~~) ¬ÝªO PttSrc
+ ¼ÐÃD [anno] tunepasswd
+ ®É¶¡ Sat Jul 29 09:18:06 2000
+¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w
+
+·s¼W¤F¤@­Ó tunepasswd ªºµ{¦¡
+
+¦pªG§A¦b .PASSWD «Ø¥ß«á¤S§ï¹L¤F MAX_USERS
+
+§A¥²¶·­n°õ¦æ tunepasswd ¤@¦¸¨Ó­×§ï .PASSWD Àɪº¤j¤p
+
+°õ¦æªº®É­Ô¤£¥i¥H¦³¥ô¦óBBSªºµ{¦¡¦b°õ¦æ
+
+shared memory ¤]À³¸Ó­n²M°£, §_«h·|¦³¤£¹w´Áªº¿ù»~µo¥Í
+
+°õ¦æ tunepasswd ·|²£¥Í¤@­Ó­ì¨Óªº³Æ¥÷ÀÉ .PASSWD~
+
+--
+¡° µo«H¯¸: §å½ð½ð¹ê·~§{(ptt.twbbs.org)
+¡» From: oio.m6.ntu.edu.t
diff --git a/docs/INSTALL b/docs/INSTALL
new file mode 100644
index 00000000..5bd484d5
--- /dev/null
+++ b/docs/INSTALL
@@ -0,0 +1,49 @@
+©³¤U¬O§Ö³t¦w¸Ëªº¤èªk
+
+==
+
+¥ý¨ú±o root Åv­­
+
+1. ¥´ vipw, ¥[¤J©³¤U¨â¦æ
+
+ bbs:*:9999:99::0:0:Ptt BBS:/home/bbs:/home/bbs/bin/bbsrf
+ bbsadm::9999:99::0:0:Ptt BBS:/home/bbs:/bin/csh
+
+2. °õ¦æ passwd bbsadm ³] bbsadmªº±K½X
+3. ¦b /etc/group ¤¤¥[¤J¤@¦æ
+
+ bbs:*:99:
+
+4. °õ¦æ mkdir /home/bbs
+5. °õ¦æ chown bbs.bbs /home/bbs
+6. °õ¦æ chmod 700 /home/bbs
+
+µM«á¤Á´«¦¨ bbsadm ªº¨­¥÷
+
+7. ¨ú±o¸Ñ¶} pttbbs-VERSION.tar.gz (¥ô¦ó¥Ø¿ý¤U¬Ò¥i).
+8. °õ¦æ cd pttbbs
+9. ¦pªG¤§«e¨S¦³³]©w¹L pttbbs.conf ªº¸Ü, ½Ð cp sample/pttbbs.conf pttbbs.conf
+10. ­×§ï pttbbs.conf
+11. °õ¦æ make OSTYPE=FreeBSD BBSHOME=/home/bbs all install
+ (Linux¨Ï¥ÎªÌ½Ð§â "FreeBSD" §ï¦¨ "linux")
+12. ¦pªG¬O·s¬[°_¨Óªº¯¸, ½Ð°õ¦æ cd sample; make install
+12. °õ¦æ cd /home/bbs; bin/initbbs
+
+°²¦p¤@¤Á³£«Ü¶¶§Qªº¸Ü,³o¼Ë¤l¤j·§´N¦w¸Ë§¹¤F
+±µ¤U¨Ó¬O±Ò°Ê bbs ªº³¡¥÷
+
+13. °õ¦æ bin/uhash_loader (*µù1)
+14. ¥Î root °õ¦æ bin/mbbsd 23 (µù2)
+
+telnet localhost 23 ¬Ý¬Ý
+new¤@­Ó±b¸¹¥sSYSOP,µM«álogout¦Alogin, ³o¼Ë¤l´N·|¾Ö¦³¯¸ªøÅv­­Åo~
+¦Anew¤@­Ó±b¸¹¥s guest, ³o¼Ë¤l§O¤H´N¥i¥H¥Î guest °ÑÆ[§Aªº¯¸¤F
+¶}ªO,¶}¸s²Õ,¥H¤Î·h°Ê¸s²Õªº¤èªk½Ð¬Ý PttSrc ªOªº¤åºK
+
+µù:
+1. ³o­Óµ{¦¡¬O¦b initial shared memory ¥Îªº, ¥u¦³¶}¾÷«á²Ä¤@¦¸°õ¦æ, ©Î¬O
+ §A¤â°Ê²M°£ shm «á¤~»Ý­n°õ¦æ
+
+2. bin/mbbsd 23 ¬O«ü©w­n bind 23 port, ¨Ì·Ó UNIX ³W©w, 1024 ¥H¤Uªº port
+ ¶·­n¦³ root Åv­­, ©Ò¥H¦pªG­n bind 23 port ªº¸Ü´N­n¥Î root ¥h°õ¦æ,
+ 3000 port «h¤£»Ý­n
diff --git a/include/common.h b/include/common.h
new file mode 100644
index 00000000..333bed8c
--- /dev/null
+++ b/include/common.h
@@ -0,0 +1,198 @@
+/* $Id: common.h,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#ifndef INCLUDE_COMMON_H
+#define INCLUDE_COMMON_H
+
+#define STR_GUEST "guest"
+#define DEFAULT_BOARD str_sysop
+
+#define FN_PASSWD BBSHOME "/.PASSWDS" /* User records */
+#define FN_USSONG "ussong" /* ÂIºq²Î­p */
+#define FN_POST_NOTE "post.note" /* po¤å³¹³Æ§Ñ¿ý */
+#define FN_APPLICATION "application"
+#define FN_MONEY "etc/money"
+#define FN_OVERRIDES "overrides"
+#define FN_REJECT "reject"
+#define FN_WATER "water"
+#define FN_CANVOTE "can_vote"
+#define FN_VISABLE "visable"
+#define FN_USIES "usies" /* BBS log */
+#define FN_BOARD ".BRD" /* board list */
+#define FN_USEBOARD "usboard" /* ¬Ýª©²Î­p */
+#define FN_NOTE_ANS "note.ans"
+#define FN_TOPSONG "etc/topsong"
+#define FN_OVERRIDES "overrides"
+#define FN_TICKET "ticket"
+#define FN_TICKET_END "ticket.end"
+#define FN_TICKET_ITEMS "ticket.items"
+#define FN_TICKET_RECORD "ticket.data"
+#define FN_TICKET_USER "ticket.user"
+#define FN_TICKET_OUTCOME "ticket.outcome"
+#define FN_TICKET_BRDLIST "boardlist"
+
+#define MSG_DEL_CANCEL "¨ú®ø§R°£"
+#define MSG_SELECT_BOARD "\033[7m¡i ¿ï¾Ü¬ÝªO ¡j\033[m\n" \
+ "½Ð¿é¤J¬ÝªO¦WºÙ(«öªÅ¥ÕÁä¦Û°Ê·j´M)¡G"
+#define MSG_CLOAKED "«¢«¢¡I§ÚÁô§Î¤F¡I¬Ý¤£¨ì°Ç... :P"
+#define MSG_UNCLOAK "§Ú­n­«²{¦¿´ò¤F...."
+#define MSG_BIG_BOY "§Ú¬O¤j«Ó­ô! ^o^Y"
+#define MSG_BIG_GIRL "¥@¬ö¤j¬ü¤k *^-^*"
+#define MSG_LITTLE_BOY "§Ú¬O©³­}°Õ... =)"
+#define MSG_LITTLE_GIRL "³Ì¥i·Rªº¬ü¬Ü! :>"
+#define MSG_MAN "³Á·í³Ò¨û¨û (^O^)"
+#define MSG_WOMAN "¥s§Ú¤pªü«¼!! /:>"
+#define MSG_PLANT "´Óª«¤]¦³©Ê§O³á.."
+#define MSG_MIME "Äqª«Á`¨S©Ê§O¤F§a"
+#define MSG_PASSWD "½Ð¿é¤J±zªº±K½X: "
+#define MSG_POSTER "\033[34;46m ¤å³¹¿ïŪ "\
+ "\033[31;47m (y)\033[30m¦^«H "\
+ "\033[31m(=[]<>)\033[30m¬ÛÃö¥DÃD "\
+ "\033[31m(/?)\033[30m·j´M¼ÐÃD "\
+ "\033[31m(aA)\033[30m·j´M§@ªÌ "\
+ "\033[31m(x)\033[30mÂà¿ý "\
+ "\033[31m(V)\033[30m§ë²¼ \033[m"
+#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_CLOAKED "«¢«¢¡I§ÚÁô§Î¤F¡I¬Ý¤£¨ì°Ç... :P"
+#define MSG_UNCLOAK "§Ú­n­«²{¦¿´ò¤F...."
+
+#define MSG_WORKING "³B²z¤¤¡A½Ðµy­Ô..."
+
+#define MSG_CANCEL "¨ú®ø¡C"
+#define MSG_USR_LEFT "User ¤w¸gÂ÷¶}¤F"
+#define MSG_NOBODY "¥Ø«eµL¤H¤W½u"
+
+#define MSG_DEL_OK "§R°£§¹²¦"
+#define MSG_DEL_CANCEL "¨ú®ø§R°£"
+#define MSG_DEL_ERROR "§R°£¿ù»~"
+#define MSG_DEL_NY "½Ð½T©w§R°£(Y/N)?[N] "
+
+#define MSG_FWD_OK "¤å³¹Âà±H§¹¦¨!"
+#define MSG_FWD_ERR1 "Âà±H¥¢»~: system error"
+#define MSG_FWD_ERR2 "Âà±H¥¢»~: address error"
+
+#define MSG_SURE_NY "½Ð±z½T©w(Y/N)¡H[N] "
+#define MSG_SURE_YN "½Ð±z½T©w(Y/N)¡H[Y] "
+
+#define MSG_BID "½Ð¿é¤J¬ÝªO¦WºÙ¡G"
+#define MSG_UID "½Ð¿é¤J¨Ï¥ÎªÌ¥N¸¹¡G"
+#define MSG_PASSWD "½Ð¿é¤J±zªº±K½X: "
+
+#define MSG_BIG_BOY "§Ú¬O¤j«Ó­ô! ^o^Y"
+#define MSG_BIG_GIRL "¥@¬ö¤j¬ü¤k *^-^*"
+#define MSG_LITTLE_BOY "§Ú¬O©³­}°Õ... =)"
+#define MSG_LITTLE_GIRL "³Ì¥i·Rªº¬ü¬Ü! :>"
+#define MSG_MAN "³Á·í³Ò¨û¨û (^O^)"
+#define MSG_WOMAN "¥s§Ú¤pªü«¼!! /:>"
+#define MSG_PLANT "´Óª«¤]¦³©Ê§O³á.."
+#define MSG_MIME "Äqª«Á`¨S©Ê§O¤F§a"
+
+#define ERR_BOARD_OPEN ".BOARD ¶}±Ò¿ù»~"
+#define ERR_BOARD_UPDATE ".BOARD §ó·s¦³»~"
+#define ERR_PASSWD_OPEN ".PASSWDS ¶}±Ò¿ù»~"
+
+#define ERR_BID "§A·d¿ù¤F°Õ¡I¨S¦³³o­ÓªO³á¡I"
+#define ERR_UID "³o¸Ì¨S¦³³o­Ó¤H°Õ¡I"
+#define ERR_PASSWD "±K½X¤£¹ï³á¡I§A¦³¨S¦³«_¥Î¤H®aªº¦W¦r°Ú¡H"
+#define ERR_FILENAME "ÀɦW¤£¦Xªk¡I"
+#define MSG_MAILER \
+"\033[34;46m ÂE¶­©¹ªð \033[31;47m(R)\033[30m¦^«H\033[31m(x)\033[30mÂà¹F\
+\033[31m(y)\033[30m¸s²Õ¦^«H\033[31m(D)\033[30m§R°£\
+\033[31m(c)\033[30m¦¬¤J«H¥ó§¨\033[31m(z)\033[30m«H¥ó§¨ \033[31m[G]\033[30mÄ~Äò?\033[0m"
+#define MSG_SHORTULIST "\033[7m\
+¨Ï¥ÎªÌ¥N¸¹ ¥Ø«eª¬ºA ¢x¨Ï¥ÎªÌ¥N¸¹ ¥Ø«eª¬ºA ¢x¨Ï¥ÎªÌ¥N¸¹ ¥Ø«eª¬ºA \033[0m"
+
+
+#define STR_AUTHOR1 "§@ªÌ:"
+#define STR_AUTHOR2 "µo«H¤H:"
+#define STR_POST1 "¬ÝªO:"
+#define STR_POST2 "¯¸¤º:"
+
+/* Flags to getdata input function */
+#define NOECHO 0
+#define DOECHO 1
+#define LCECHO 2
+
+#define YEA 1 /* Booleans (Yep, for true and false) */
+#define NA 0
+
+
+#define IRH 1 /* ¦n¤ÍÃö«Y */
+#define HRM 2
+#define IBH 4
+#define IFH 8
+#define HFM 16
+#define ST_FRIEND (IBH | IFH | HFM)
+#define ST_REJECT (IRH | HRM)
+
+/* Áä½L³]©w */
+#define KEY_TAB 9
+#define KEY_ESC 27
+#define KEY_UP 0x0101
+#define KEY_DOWN 0x0102
+#define KEY_RIGHT 0x0103
+#define KEY_LEFT 0x0104
+#define KEY_HOME 0x0201
+#define KEY_INS 0x0202
+#define KEY_DEL 0x0203
+#define KEY_END 0x0204
+#define KEY_PGUP 0x0205
+#define KEY_PGDN 0x0206
+
+#define QCAST int (*)(const void *, const void *)
+#define Ctrl(c) (c & 037)
+#define chartoupper(c) ((c >= 'a' && c <= 'z') ? c+'A'-'a' : c)
+
+#define LEN_AUTHOR1 5
+#define LEN_AUTHOR2 7
+
+/* ----------------------------------------------------- */
+/* ¸s²Õ¦W³æ¼Ò¦¡ Ptt */
+/* ----------------------------------------------------- */
+#define FRIEND_OVERRIDE 0
+#define FRIEND_REJECT 1
+#define FRIEND_ALOHA 2
+#define FRIEND_POST 3
+#define FRIEND_SPECIAL 4
+#define FRIEND_CANVOTE 5
+#define BOARD_WATER 6
+#define BOARD_VISABLE 7
+
+#define LOCK_THIS 1 // lock³o½u¤£¯à­«½Æª±
+#define LOCK_MULTI 2 // lock©Ò¦³½u¤£¯à­«½Æª±
+
+#define I_TIMEOUT (-2) /* Used for the getchar routine select call */
+#define I_OTHERDATA (-333) /* interface, (-3) will conflict with chinese */
+
+#define CHE_O(c) ((c) >> 3)
+#define CHE_P(c) ((c) & 7)
+#define RTL(x) (((x) - 3) >> 1)
+#define dim(x) (sizeof(x) / sizeof(x[0]))
+#define LTR(x) ((x) * 2 + 3)
+#define CHE(a, b) ((a) | ((b) << 3))
+
+#define BRD_NOZAP 00001 /* ¤£¥izap */
+#define BRD_NOCOUNT 00002 /* ¤£¦C¤J²Î­p */
+#define BRD_NOTRAN 00004 /* ¤£Âà«H */
+#define BRD_GROUPBOARD 00010 /* ¸s²ÕªO */
+#define BRD_HIDE 00020 /* ÁôÂêO (¬ÝªO¦n¤Í¤~¥i¬Ý) */
+#define BRD_POSTMASK 00040 /* ­­¨îµoªí©Î¾\Ū */
+#define BRD_ANONYMOUS 00100 /* °Î¦WªO */
+#define BRD_DEFAULTANONYMOUS 00200 /* ¹w³]°Î¦WªO */
+#define BRD_BAD 00400 /* ¹Hªk§ï¶i¤¤¬ÝªO */
+#define BRD_VOTEBOARD 01000 /* ³s¸p¾÷¬ÝªO */
+
+#define MAX_MODES 80
+
+#ifndef MIN
+#define MIN(a,b) ((a<b)?a:b)
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a>b)?a:b)
+#endif
+
+#define char_lower(c) ((c >= 'A' && c <= 'Z') ? c|32 : c)
+
+#define STR_CURSOR "¡´"
+#define STR_UNCUR " "
+#endif
diff --git a/include/config.h b/include/config.h
new file mode 100644
index 00000000..3eb6e64a
--- /dev/null
+++ b/include/config.h
@@ -0,0 +1,197 @@
+/* $Id: config.h,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#ifndef INCLUDE_CONFIG_H
+#define INCLUDE_CONFIG_H
+
+#include <syslog.h>
+#include "../pttbbs.conf"
+
+#define BBSPROG BBSHOME "/bin/mbbsd" /* ¥Dµ{¦¡ */
+#define BAN_FILE "BAN" /* Ãö¯¸³q§iÀÉ */
+#define LOAD_FILE "/proc/loadavg" /* for Linux */
+
+#ifndef RELAY_SERVER_IP /* ±H¯¸¥~«Hªº mail server */
+#define RELAY_SERVER_IP "127.0.0.1"
+#endif
+
+#ifndef MAX_USERS /* ³Ì°ªµù¥U¤H¼Æ */
+#define MAX_USERS (150000)
+#endif
+
+#ifndef MAX_ACTIVE
+#define MAX_ACTIVE (1024) /* ³Ì¦h¦P®É¤W¯¸¤H¼Æ */
+#endif
+
+#ifndef MAX_CPULOAD
+#define MAX_CPULOAD (70) /* CPU ³Ì°ªload */
+#endif
+
+#ifndef MAX_POST_MONEY /* µoªí¤å³¹½Z¶Oªº¤W­­ */
+#define MAX_POST_MONEY 100
+#endif
+
+#ifndef MAX_CHICKEN_MONEY /* ¾iÂû³õì§Q¤W­­ */
+#define MAX_CHICKEN_MONEY 100
+#endif
+
+#ifndef MAX_GUEST_LIFE /* ³Ìªø¥¼»{ÃҨϥΪ̫O¯d®É¶¡(¬í) */
+#define MAX_GUEST_LIFE (3 * 24 * 60 * 60)
+#endif
+
+#ifndef MAX_LIFE /* ³Ìªø¨Ï¥ÎªÌ«O¯d®É¶¡(¬í) */
+#define MAX_LIFE (120 * 24 * 60 * 60)
+#endif
+
+#ifndef MAX_FROM
+#define MAX_FROM (300) /* ³Ì¦h¬G¶m¼Æ */
+#endif
+
+#ifndef HAVE_JCEE /* ¤j¾ÇÁp¦Ò¬dº]¨t²Î */
+#define HAVE_JCEE 1
+#endif
+
+#ifndef HAVE_FREECLOAK
+#define HAVE_FREECLOAK 0
+#endif
+
+#ifndef FORCE_PROCESS_REGISTER_FORM
+#define FORCE_PROCESS_REGISTER_FORM 0
+#endif
+
+#ifndef TITLE_COLOR
+#define TITLE_COLOR "\033[0;1;37;46m"
+#endif
+
+#ifndef SYSLOG_FACILITY
+#define SYSLOG_FACILITY LOG_LOCAL0
+#endif
+
+#ifndef TAR_PATH
+#define TAR_PATH "tar"
+#endif
+
+#ifndef HBFLexpire
+#define HBFLexpire (432000) /* 5 days */
+#endif
+
+/* ¥H¤UÁÙ¥¼¾ã²z */
+#define DIRCACHESIZE (40) /* cache ¤å³¹¦Cªí¤¤³Ì«á40½g */
+#define MAX_FRIEND (256) /* ¸ü¤J cache ¤§³Ì¦hªB¤Í¼Æ¥Ø */
+#define MAX_REJECT (32) /* ¸ü¤J cache ¤§³Ì¦hÃa¤H¼Æ¥Ø */
+#define MAX_MSGS (10) /* ¤ô²y(¼ö°T)§Ô­@¤W­­ */
+#define MAX_BOARD (8192) /* ³Ì¤j¶}ª©­Ó¼Æ */
+#define MAX_MOVIE (999) /* ³Ì¦h°ÊºA¬Ýª©¼Æ */
+#define MAX_MOVIE_SECTION (10) /* ³Ì¦h°ÊºA¬ÝªOÃþ§O */
+#define MAX_ITEMS (1000) /* ¤@­Ó¥Ø¿ý³Ì¦h¦³´X¶µ */
+#define MAX_HISTORY (12) /* °ÊºA¬ÝªO«O«ù 12 µ§¾ú¥v°O¿ý */
+#define MAX_CROSSNUM (9) /* ³Ì¦hcrosspost¦¸¼Æ */
+#define MAX_QUERYLINES (16) /* Åã¥Ü Query/Plan °T®§³Ì¤j¦æ¼Æ */
+#define MAX_LOGIN_INFO (128) /* ³Ì¦h¤W½u³qª¾¤H¼Æ */
+#define MAX_POST_INFO (32) /* ³Ì¦h·s¤å³¹³qª¾¤H¼Æ */
+#define MAX_NAMELIST (128) /* ³Ì¦h¨ä¥L¯S§O¦W³æ¤H¼Æ */
+#define MAX_PAGES (999) /* more.c ¤¤¤å³¹­¶¼Æ¤W­­(lines/22) */
+#define MAX_KEEPMAIL (200) /* ³Ì¦h«O¯d´X«Ê MAIL¡H */
+#define MAX_EXKEEPMAIL (1000) /* ³Ì¦h«H½c¥[¤j¦h¤Ö«Ê */
+#define MAX_NOTE (20) /* ³Ì¦h«O¯d´X½g¯d¨¥¡H */
+#define MAX_SIGLINES (6) /* ñ¦WÀɤޤJ³Ì¤j¦æ¼Æ */
+#define MAX_CROSSNUM (9) /* ³Ì¦hcrosspost¦¸¼Æ */
+#define MAX_REVIEW (7) /* ³Ì¦h¤ô²y¦^ÅU */
+#define NUMVIEWFILE (14) /* ¶i¯¸µe­±³Ì¦h¼Æ */
+#define MAX_SWAPUSED (0.7) /* SWAP³Ì°ª¨Ï¥Î²v */
+#define LOGINATTEMPTS (3) /* ³Ì¤j¶i¯¸¥¢»~¦¸¼Æ */
+#define WHERE /* ¬O§_¦³¬G¶m¥\¯à */
+#undef LOG_BOARD /* ¬Ýª©¬O§_log */
+#undef SUPPORT_GB /* ¬O§_¤ä´©gb */
+
+
+#define DEFAULTBOARD "SYSOP" /* ¹w³]¬ÝªO */
+#define LOGINASNEW /* ±Ä¥Î¤W¯¸¥Ó½Ð±b¸¹¨î«× */
+#define NO_WATER_POST /* ¨¾¤îBlahBlah¦¡Äé¤ô */
+#define USE_BSMTP /* ¨Ï¥ÎopusªºBSMTP ±H¦¬«H? */
+#define HAVE_ANONYMOUS /* ´£¨Ñ Anonymous ªO */
+#undef POSTNOTIFY /* ·s¤å³¹³qª¾¥\¯à */
+#define INTERNET_EMAIL /* ¤ä´© InterNet Email ¥\¯à(§t Forward) */
+#define HAVE_ORIGIN /* Åã¥Ü author ¨Ó¦Û¦ó³B */
+#undef HAVE_MAILCLEAN /* ²M²z©Ò¦³¨Ï¥ÎªÌ­Ó¤H«H½c */
+#undef HAVE_SUICIDE /* ´£¨Ñ¨Ï¥ÎªÌ¦Û±þ¥\¯à */
+#undef HAVE_REPORT /* ¨t²Î°lÂܳø§i */
+#undef HAVE_INFO /* Åã¥Üµ{¦¡ª©¥»»¡©ú */
+#undef HAVE_LICENSE /* Åã¥Ü GNU ª©Åvµe­± */
+#undef HAVE_TIN /* ´£¨Ñ news reader */
+#undef HAVE_GOPHER /* ´£¨Ñ gopher */
+#undef HAVE_WWW /* ´£¨Ñ www browser */
+#define FAST_LOGIN /* Login ¤£Àˬd»·ºÝ¨Ï¥ÎªÌ */
+#define HAVE_CAL /* ´£¥\­pºâ¾÷ */
+#undef HAVE_ARCHIE /* have arche */
+#undef POSTBUG /* board/mail post ¨S¦³ bug ¤F */
+#undef HAVE_REPORT /* ¨t²Î°lÂܳø§i */
+#undef EMAIL_JUSTIFY /* µo¥X InterNet Email ¨­¥÷»{ÃÒ«H¨ç */
+#undef NEWUSER_LIMIT /* ·s¤â¤W¸ôªº¤T¤Ñ­­¨î */
+#undef HAVE_X_BOARDS
+
+#define USE_LYNX /* ¨Ï¥Î¥~³¡lynx dump ? */
+#undef USE_PROXY
+#ifdef USE_PROXY
+#define PROXYSERVER "140.112.28.165"
+#define PROXYPORT 3128
+#endif
+#define LOCAL_PROXY /* ¬O§_¶}±Òlocal ªºproxy */
+#ifdef LOCAL_PROXY
+#define HPROXYDAY 1 /* localªºproxy refresh¤Ñ¼Æ */
+#endif
+
+#define SHOWMIND /* ¬Ý¨£¤ß±¡ */
+#define SHOWUID /* ¬Ý¨£¨Ï¥ÎªÌ UID */
+#define SHOWBOARD /* ¬Ý¨£¨Ï¥ÎªÌ¬ÝªO */
+#define SHOWPID /* ¬Ý¨£¨Ï¥ÎªÌ PID */
+
+#define REALINFO /* ¯u¹ê©m¦W */
+#ifdef REALINFO
+#undef ACTS_REALNAMES /* ¥D¥Ø¿ýªº (U)ser Åã¥Ü¯u¹ê©m¦W */
+#undef POST_REALNAMES /* ¶K¤å¥ó®Éªþ¤W¯u¹ê©m¦W */
+#undef MAIL_REALNAMES /* ±H¯¸¤º«H¥ó®Éªþ¤W¯u¹ê©m¦W */
+#endif
+
+#define DOTIMEOUT
+#ifdef DOTIMEOUT
+#define IDLE_TIMEOUT (30*60) /* ¤@¯ë±¡ªp¤§ timeout */
+#define MONITOR_TIMEOUT (20*60) /* monitor ®É¤§ timeout */
+#define SHOW_IDLE_TIME /* Åã¥Ü¶¢¸m®É¶¡ */
+#endif
+
+#define SEM_ENTER -1 /* enter semaphore */
+#define SEM_LEAVE 1 /* leave semaphore */
+#define SEM_RESET 0 /* reset semaphore */
+
+#define MAGIC_KEY 1234 /* ¨­¤À»{ÃÒ«H¨ç½s½X */
+
+#define BRDSHM_KEY 1208
+#define UHASH_KEY 1218 /* userid->uid hash */
+#define UTMPSHM_KEY 2221
+#define PTTSHM_KEY 1220 /* °ÊºA¬Ýª© , ¸`¤é */
+#define FROMSHM_KEY 1223 /* whereis, ³Ì¦h¨Ï¥ÎªÌ */
+
+#define BRDSEM_KEY 2005 /* semaphore key */
+#define PTTSEM_KEY 2000 /* semaphore key */
+#define FROMSEM_KEY 2003 /* semaphore key */
+#define PASSWDSEM_KEY 2010
+
+#define NEW_CHATPORT 3838
+#define CHATPORT 5722
+
+#define MAX_ROOM 16 /* ³Ì¦h¦³´X¶¡¥]´[¡H */
+
+#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"
+#define BADCIDCHARS " *" /* Chat Room ¤¤¸T¥Î©ó nick ªº¦r¤¸ */
+
+#define ALLPOST "ALLPOST"
+
+#endif
diff --git a/include/gomo.h b/include/gomo.h
new file mode 100644
index 00000000..c51bb283
--- /dev/null
+++ b/include/gomo.h
@@ -0,0 +1,2156 @@
+
+#define BBLANK (0) /* ªÅ¥Õ */
+#define BBLACK (1) /* ¶Â¤l, ¥ý¤â */
+#define BWHITE (2) /* ¥Õ¤l, «á¤â */
+#define MAX_TIME (300) /*³Ìªøidle¬í¼Æ*/
+#ifndef BRDSIZ
+#define BRDSIZ (15) /* ´Ñ½L³æÃä¤j¤p */
+#endif
+
+#define BGOTO(x, y) move( 16 - y , x * 2 + 3)
+#define BGOTOCUR(x, y) move(16 - y, x * 2 + 4)
+
+/*
+ 0 0 0 = #@# : len= 3 : NO 00 NO
+ 1 1 0 = #_@# : len= 4 : NO 00 NO
+ 2 1 1 = #_@_# : len= 5 : NO 00 NO
+ 3 2 0 = #O@# : len= 4 : NO 00 NO
+ 4 2 1 = #O@_# : len= 5 : NO 00 NO
+ 5 2 2 = #O@O# : len= 5 : NO 00 NO
+ 6 3 0 = #__@# : len= 5 : NO 00 NO
+ 7 3 1 = #__@_# : len= 6 : NO 00 NO
+ 8 3 2 = #__@O# : len= 6 : NO 00 NO
+ 9 3 3 = #__@__# : len= 7 : NO 00 NO
+ 10 4 0 = #_O@# : len= 5 : NO 00 NO
+ 11 4 1 = #_O@_# : len= 6 : NO 00 NO
+ 12 4 2 = #_O@O# : len= 6 : NO 00 NO
+ 13 4 3 = #_O@__# : len= 7 : NO 00 NO
+ 14 4 4 = #_O@O_# : len= 7 : NO 00 NO
+ 15 5 0 = #O_@# : len= 5 : NO 00 NO
+ 16 5 1 = #O_@_# : len= 6 : NO 00 NO
+ 17 5 2 = #O_@O# : len= 6 : NO 00 NO
+ 18 5 3 = #O_@__# : len= 7 : NO 00 NO
+ 19 5 4 = #O_@O_# : len= 7 : NO 00 NO
+ 20 5 5 = #O_@_O# : len= 7 : NO 00 NO
+ 21 6 0 = #OO@# : len= 5 : NO 00 NO
+ 22 6 1 = #OO@_# : len= 6 : NO 00 NO
+ 23 6 2 = #OO@O# : len= 6 : NO 00 NO
+ 24 6 3 = #OO@__# : len= 7 : NO 00 NO
+ 25 6 4 = #OO@O_# : len= 7 : S4 00 S4
+ 26 6 5 = #OO@_O# : len= 7 : D4 00 D4
+ 27 6 6 = #OO@OO# : len= 7 : L5 00 L5
+ 28 7 0 = #___@# : len= 6 : NO 00 NO
+ 29 7 1 = #___@_# : len= 7 : NO 00 NO
+ 30 7 2 = #___@O# : len= 7 : NO 00 NO
+ 31 7 3 = #___@__# : len= 8 : NO 00 NO
+ 32 7 4 = #___@O_# : len= 8 : NO 00 NO
+ 33 7 5 = #___@_O# : len= 8 : NO 00 NO
+ 34 7 6 = #___@OO# : len= 8 : NO 00 NO
+ 35 7 7 = #___@___# : len= 9 : NO 00 NO
+ 36 8 0 = #__O@# : len= 6 : NO 00 NO
+ 37 8 1 = #__O@_# : len= 7 : NO 00 NO
+ 38 8 2 = #__O@O# : len= 7 : NO 00 NO
+ 39 8 3 = #__O@__# : len= 8 : NO 00 NO
+ 40 8 4 = #__O@O_# : len= 8 : H3 22 H3
+ 41 8 5 = #__O@_O# : len= 8 : NO 00 NO
+ 42 8 6 = #__O@OO# : len= 8 : S4 00 S4
+ 43 8 7 = #__O@___# : len= 9 : NO 00 NO
+ 44 8 8 = #__O@O__# : len= 9 : H3 22 H3
+ 45 9 0 = #_O_@# : len= 6 : NO 00 NO
+ 46 9 1 = #_O_@_# : len= 7 : NO 00 NO
+ 47 9 2 = #_O_@O# : len= 7 : NO 00 NO
+ 48 9 3 = #_O_@__# : len= 8 : NO 00 NO
+ 49 9 4 = #_O_@O_# : len= 8 : D3 10 D3
+ 50 9 5 = #_O_@_O# : len= 8 : NO 00 NO
+ 51 9 6 = #_O_@OO# : len= 8 : D4 00 D4
+ 52 9 7 = #_O_@___# : len= 9 : NO 00 NO
+ 53 9 8 = #_O_@O__# : len= 9 : D3 10 D3
+ 54 9 9 = #_O_@_O_# : len= 9 : NO 00 NO
+ 55 10 0 = #_OO@# : len= 6 : NO 00 NO
+ 56 10 1 = #_OO@_# : len= 7 : NO 00 NO
+ 57 10 2 = #_OO@O# : len= 7 : S4 00 S4
+ 58 10 3 = #_OO@__# : len= 8 : H3 31 H3
+ 59 10 4 = #_OO@O_# : len= 8 : H4 00 H4
+ 60 10 5 = #_OO@_O# : len= 8 : D4 00 D4
+ 61 10 6 = #_OO@OO# : len= 8 : L5 00 L5
+ 62 10 7 = #_OO@___# : len= 9 : H3 31 H3
+ 63 10 8 = #_OO@O__# : len= 9 : H4 00 H4
+ 64 10 9 = #_OO@_O_# : len= 9 : D4 00 D4
+ 65 10 10 = #_OO@OO_# : len= 9 : L5 00 L5
+ 66 11 0 = #O__@# : len= 6 : NO 00 NO
+ 67 11 1 = #O__@_# : len= 7 : NO 00 NO
+ 68 11 2 = #O__@O# : len= 7 : NO 00 NO
+ 69 11 3 = #O__@__# : len= 8 : NO 00 NO
+ 70 11 4 = #O__@O_# : len= 8 : NO 00 NO
+ 71 11 5 = #O__@_O# : len= 8 : NO 00 NO
+ 72 11 6 = #O__@OO# : len= 8 : NO 00 NO
+ 73 11 7 = #O__@___# : len= 9 : NO 00 NO
+ 74 11 8 = #O__@O__# : len= 9 : NO 00 NO
+ 75 11 9 = #O__@_O_# : len= 9 : NO 00 NO
+ 76 11 10 = #O__@OO_# : len= 9 : NO 00 H3
+ 77 11 11 = #O__@__O# : len= 9 : NO 00 NO
+ 78 12 0 = #O_O@# : len= 6 : NO 00 NO
+ 79 12 1 = #O_O@_# : len= 7 : NO 00 NO
+ 80 12 2 = #O_O@O# : len= 7 : D4 00 D4
+ 81 12 3 = #O_O@__# : len= 8 : NO 00 NO
+ 82 12 4 = #O_O@O_# : len= 8 : D4 00 D4
+ 83 12 5 = #O_O@_O# : len= 8 : NO 00 NO
+ 84 12 6 = #O_O@OO# : len= 8 : NO 00 D4
+ 85 12 7 = #O_O@___# : len= 9 : NO 00 NO
+ 86 12 8 = #O_O@O__# : len= 9 : D4 00 D4
+ 87 12 9 = #O_O@_O_# : len= 9 : NO 00 D3
+ 88 12 10 = #O_O@OO_# : len= 9 : S4 00 H4
+ 89 12 11 = #O_O@__O# : len= 9 : NO 00 NO
+ 90 12 12 = #O_O@O_O# : len= 9 : X4 00 X4
+ 91 13 0 = #OO_@# : len= 6 : NO 00 NO
+ 92 13 1 = #OO_@_# : len= 7 : NO 00 NO
+ 93 13 2 = #OO_@O# : len= 7 : D4 00 D4
+ 94 13 3 = #OO_@__# : len= 8 : NO 00 NO
+ 95 13 4 = #OO_@O_# : len= 8 : D4 00 D4
+ 96 13 5 = #OO_@_O# : len= 8 : NO 00 NO
+ 97 13 6 = #OO_@OO# : len= 8 : NO 00 D4
+ 98 13 7 = #OO_@___# : len= 9 : NO 00 NO
+ 99 13 8 = #OO_@O__# : len= 9 : D4 00 D4
+ 100 13 9 = #OO_@_O_# : len= 9 : NO 00 NO
+ 101 13 10 = #OO_@OO_# : len= 9 : NO 00 D4
+ 102 13 11 = #OO_@__O# : len= 9 : NO 00 NO
+ 103 13 12 = #OO_@O_O# : len= 9 : D4 00 D4
+ 104 13 13 = #OO_@_OO# : len= 9 : NO 00 NO
+ 105 14 0 = #OOO@# : len= 6 : NO 00 NO
+ 106 14 1 = #OOO@_# : len= 7 : S4 00 S4
+ 107 14 2 = #OOO@O# : len= 7 : L5 00 L5
+ 108 14 3 = #OOO@__# : len= 8 : S4 00 S4
+ 109 14 4 = #OOO@O_# : len= 8 : L5 00 L5
+ 110 14 5 = #OOO@_O# : len= 8 : NO 00 D4
+ 111 14 6 = #OOO@OO# : len= 8 : L6 00 L6
+ 112 14 7 = #OOO@___# : len= 9 : S4 00 S4
+ 113 14 8 = #OOO@O__# : len= 9 : L5 00 L5
+ 114 14 9 = #OOO@_O_# : len= 9 : NO 00 D4
+ 115 14 10 = #OOO@OO_# : len= 9 : L6 00 L6
+ 116 14 11 = #OOO@__O# : len= 9 : S4 00 S4
+ 117 14 12 = #OOO@O_O# : len= 9 : L5 00 L5
+ 118 14 13 = #OOO@_OO# : len= 9 : NO 00 D4
+ 119 14 14 = #OOO@OOO# : len= 9 : L6 00 L6
+ 120 15 0 = #____@# : len= 7 : NO 00 NO
+ 121 15 1 = #____@_# : len= 8 : NO 00 NO
+ 122 15 2 = #____@O# : len= 8 : NO 00 NO
+ 123 15 3 = #____@__# : len= 9 : NO 00 NO
+ 124 15 4 = #____@O_# : len= 9 : NO 00 NO
+ 125 15 5 = #____@_O# : len= 9 : NO 00 NO
+ 126 15 6 = #____@OO# : len= 9 : NO 00 NO
+ 127 15 7 = #____@___# : len=10 : NO 00 NO
+ 128 15 8 = #____@O__# : len=10 : NO 00 NO
+ 129 15 9 = #____@_O_# : len=10 : NO 00 NO
+ 130 15 10 = #____@OO_# : len=10 : H3 13 H3
+ 131 15 11 = #____@__O# : len=10 : NO 00 NO
+ 132 15 12 = #____@O_O# : len=10 : NO 00 NO
+ 133 15 13 = #____@_OO# : len=10 : NO 00 NO
+ 134 15 14 = #____@OOO# : len=10 : S4 00 S4
+ 135 15 15 = #____@____# : len=11 : NO 00 NO
+ 136 16 0 = #___O@# : len= 7 : NO 00 NO
+ 137 16 1 = #___O@_# : len= 8 : NO 00 NO
+ 138 16 2 = #___O@O# : len= 8 : NO 00 NO
+ 139 16 3 = #___O@__# : len= 9 : NO 00 NO
+ 140 16 4 = #___O@O_# : len= 9 : H3 22 H3
+ 141 16 5 = #___O@_O# : len= 9 : NO 00 NO
+ 142 16 6 = #___O@OO# : len= 9 : S4 00 S4
+ 143 16 7 = #___O@___# : len=10 : NO 00 NO
+ 144 16 8 = #___O@O__# : len=10 : H3 22 H3
+ 145 16 9 = #___O@_O_# : len=10 : D3 01 D3
+ 146 16 10 = #___O@OO_# : len=10 : H4 00 H4
+ 147 16 11 = #___O@__O# : len=10 : NO 00 NO
+ 148 16 12 = #___O@O_O# : len=10 : D4 00 D4
+ 149 16 13 = #___O@_OO# : len=10 : D4 00 D4
+ 150 16 14 = #___O@OOO# : len=10 : L5 00 L5
+ 151 16 15 = #___O@____# : len=11 : NO 00 NO
+ 152 16 16 = #___O@O___# : len=11 : H3 22 H3
+ 153 17 0 = #__O_@# : len= 7 : NO 00 NO
+ 154 17 1 = #__O_@_# : len= 8 : NO 00 NO
+ 155 17 2 = #__O_@O# : len= 8 : NO 00 NO
+ 156 17 3 = #__O_@__# : len= 9 : NO 00 NO
+ 157 17 4 = #__O_@O_# : len= 9 : D3 10 D3
+ 158 17 5 = #__O_@_O# : len= 9 : NO 00 NO
+ 159 17 6 = #__O_@OO# : len= 9 : D4 00 D4
+ 160 17 7 = #__O_@___# : len=10 : NO 00 NO
+ 161 17 8 = #__O_@O__# : len=10 : D3 10 D3
+ 162 17 9 = #__O_@_O_# : len=10 : NO 00 NO
+ 163 17 10 = #__O_@OO_# : len=10 : D4 00 D4
+ 164 17 11 = #__O_@__O# : len=10 : NO 00 NO
+ 165 17 12 = #__O_@O_O# : len=10 : NO 00 D3
+ 166 17 13 = #__O_@_OO# : len=10 : NO 00 NO
+ 167 17 14 = #__O_@OOO# : len=10 : NO 00 D4
+ 168 17 15 = #__O_@____# : len=11 : NO 00 NO
+ 169 17 16 = #__O_@O___# : len=11 : D3 10 D3
+ 170 17 17 = #__O_@_O__# : len=11 : NO 00 NO
+ 171 18 0 = #__OO@# : len= 7 : NO 00 NO
+ 172 18 1 = #__OO@_# : len= 8 : H3 31 H3
+ 173 18 2 = #__OO@O# : len= 8 : S4 00 S4
+ 174 18 3 = #__OO@__# : len= 9 : H3 31 H3
+ 175 18 4 = #__OO@O_# : len= 9 : H4 00 H4
+ 176 18 5 = #__OO@_O# : len= 9 : D4 00 D4
+ 177 18 6 = #__OO@OO# : len= 9 : L5 00 L5
+ 178 18 7 = #__OO@___# : len=10 : H3 31 H3
+ 179 18 8 = #__OO@O__# : len=10 : H4 00 H4
+ 180 18 9 = #__OO@_O_# : len=10 : D4 00 D4
+ 181 18 10 = #__OO@OO_# : len=10 : L5 00 L5
+ 182 18 11 = #__OO@__O# : len=10 : H3 31 H3
+ 183 18 12 = #__OO@O_O# : len=10 : S4 00 H4
+ 184 18 13 = #__OO@_OO# : len=10 : NO 00 D4
+ 185 18 14 = #__OO@OOO# : len=10 : L6 00 L6
+ 186 18 15 = #__OO@____# : len=11 : H3 31 H3
+ 187 18 16 = #__OO@O___# : len=11 : H4 00 H4
+ 188 18 17 = #__OO@_O__# : len=11 : D4 00 D4
+ 189 18 18 = #__OO@OO__# : len=11 : L5 00 L5
+ 190 19 0 = #_O__@# : len= 7 : NO 00 NO
+ 191 19 1 = #_O__@_# : len= 8 : NO 00 NO
+ 192 19 2 = #_O__@O# : len= 8 : NO 00 NO
+ 193 19 3 = #_O__@__# : len= 9 : NO 00 NO
+ 194 19 4 = #_O__@O_# : len= 9 : NO 00 NO
+ 195 19 5 = #_O__@_O# : len= 9 : NO 00 NO
+ 196 19 6 = #_O__@OO# : len= 9 : NO 00 NO
+ 197 19 7 = #_O__@___# : len=10 : NO 00 NO
+ 198 19 8 = #_O__@O__# : len=10 : NO 00 NO
+ 199 19 9 = #_O__@_O_# : len=10 : NO 00 NO
+ 200 19 10 = #_O__@OO_# : len=10 : NO 00 H3
+ 201 19 11 = #_O__@__O# : len=10 : NO 00 NO
+ 202 19 12 = #_O__@O_O# : len=10 : NO 00 NO
+ 203 19 13 = #_O__@_OO# : len=10 : NO 00 NO
+ 204 19 14 = #_O__@OOO# : len=10 : S4 00 S4
+ 205 19 15 = #_O__@____# : len=11 : NO 00 NO
+ 206 19 16 = #_O__@O___# : len=11 : NO 00 NO
+ 207 19 17 = #_O__@_O__# : len=11 : NO 00 NO
+ 208 19 18 = #_O__@OO__# : len=11 : H3 13 H3
+ 209 19 19 = #_O__@__O_# : len=11 : NO 00 NO
+ 210 20 0 = #_O_O@# : len= 7 : NO 00 NO
+ 211 20 1 = #_O_O@_# : len= 8 : D3 20 D3
+ 212 20 2 = #_O_O@O# : len= 8 : D4 00 D4
+ 213 20 3 = #_O_O@__# : len= 9 : D3 20 D3
+ 214 20 4 = #_O_O@O_# : len= 9 : D4 00 D4
+ 215 20 5 = #_O_O@_O# : len= 9 : NO 00 D3
+ 216 20 6 = #_O_O@OO# : len= 9 : NO 00 D4
+ 217 20 7 = #_O_O@___# : len=10 : D3 20 D3
+ 218 20 8 = #_O_O@O__# : len=10 : D4 00 D4
+ 219 20 9 = #_O_O@_O_# : len=10 : NO 00 D3
+ 220 20 10 = #_O_O@OO_# : len=10 : S4 00 H4
+ 221 20 11 = #_O_O@__O# : len=10 : D3 20 D3
+ 222 20 12 = #_O_O@O_O# : len=10 : X4 00 X4
+ 223 20 13 = #_O_O@_OO# : len=10 : D4 00 D4
+ 224 20 14 = #_O_O@OOO# : len=10 : L5 00 L5
+ 225 20 15 = #_O_O@____# : len=11 : D3 20 D3
+ 226 20 16 = #_O_O@O___# : len=11 : D4 00 D4
+ 227 20 17 = #_O_O@_O__# : len=11 : NO 00 D3
+ 228 20 18 = #_O_O@OO__# : len=11 : S4 00 H4
+ 229 20 19 = #_O_O@__O_# : len=11 : D3 20 D3
+ 230 20 20 = #_O_O@O_O_# : len=11 : X4 00 X4
+ 231 21 0 = #_OO_@# : len= 7 : NO 00 NO
+ 232 21 1 = #_OO_@_# : len= 8 : D3 10 D3
+ 233 21 2 = #_OO_@O# : len= 8 : D4 00 D4
+ 234 21 3 = #_OO_@__# : len= 9 : D3 10 D3
+ 235 21 4 = #_OO_@O_# : len= 9 : D4 00 D4
+ 236 21 5 = #_OO_@_O# : len= 9 : NO 00 D3
+ 237 21 6 = #_OO_@OO# : len= 9 : NO 00 D4
+ 238 21 7 = #_OO_@___# : len=10 : D3 10 D3
+ 239 21 8 = #_OO_@O__# : len=10 : D4 00 D4
+ 240 21 9 = #_OO_@_O_# : len=10 : NO 00 D3
+ 241 21 10 = #_OO_@OO_# : len=10 : NO 00 D4
+ 242 21 11 = #_OO_@__O# : len=10 : D3 10 D3
+ 243 21 12 = #_OO_@O_O# : len=10 : D4 00 D4
+ 244 21 13 = #_OO_@_OO# : len=10 : NO 00 D3
+ 245 21 14 = #_OO_@OOO# : len=10 : NO 00 D4
+ 246 21 15 = #_OO_@____# : len=11 : D3 10 D3
+ 247 21 16 = #_OO_@O___# : len=11 : D4 00 D4
+ 248 21 17 = #_OO_@_O__# : len=11 : NO 00 D3
+ 249 21 18 = #_OO_@OO__# : len=11 : NO 00 D4
+ 250 21 19 = #_OO_@__O_# : len=11 : D3 10 D3
+ 251 21 20 = #_OO_@O_O_# : len=11 : D4 00 D4
+ 252 21 21 = #_OO_@_OO_# : len=11 : NO 00 D3
+ 253 22 0 = #_OOO@# : len= 7 : S4 00 S4
+ 254 22 1 = #_OOO@_# : len= 8 : H4 00 H4
+ 255 22 2 = #_OOO@O# : len= 8 : L5 00 L5
+ 256 22 3 = #_OOO@__# : len= 9 : H4 00 H4
+ 257 22 4 = #_OOO@O_# : len= 9 : L5 00 L5
+ 258 22 5 = #_OOO@_O# : len= 9 : S4 00 H4
+ 259 22 6 = #_OOO@OO# : len= 9 : L6 00 L6
+ 260 22 7 = #_OOO@___# : len=10 : H4 00 H4
+ 261 22 8 = #_OOO@O__# : len=10 : L5 00 L5
+ 262 22 9 = #_OOO@_O_# : len=10 : S4 00 H4
+ 263 22 10 = #_OOO@OO_# : len=10 : L6 00 L6
+ 264 22 11 = #_OOO@__O# : len=10 : H4 00 H4
+ 265 22 12 = #_OOO@O_O# : len=10 : L5 00 L5
+ 266 22 13 = #_OOO@_OO# : len=10 : S4 00 H4
+ 267 22 14 = #_OOO@OOO# : len=10 : L6 00 L6
+ 268 22 15 = #_OOO@____# : len=11 : H4 00 H4
+ 269 22 16 = #_OOO@O___# : len=11 : L5 00 L5
+ 270 22 17 = #_OOO@_O__# : len=11 : S4 00 H4
+ 271 22 18 = #_OOO@OO__# : len=11 : L6 00 L6
+ 272 22 19 = #_OOO@__O_# : len=11 : H4 00 H4
+ 273 22 20 = #_OOO@O_O_# : len=11 : L5 00 L5
+ 274 22 21 = #_OOO@_OO_# : len=11 : S4 00 H4
+ 275 22 22 = #_OOO@OOO_# : len=11 : L6 00 L6
+ 276 23 0 = #O___@# : len= 7 : NO 00 NO
+ 277 23 1 = #O___@_# : len= 8 : NO 00 NO
+ 278 23 2 = #O___@O# : len= 8 : NO 00 NO
+ 279 23 3 = #O___@__# : len= 9 : NO 00 NO
+ 280 23 4 = #O___@O_# : len= 9 : NO 00 NO
+ 281 23 5 = #O___@_O# : len= 9 : NO 00 NO
+ 282 23 6 = #O___@OO# : len= 9 : NO 00 NO
+ 283 23 7 = #O___@___# : len=10 : NO 00 NO
+ 284 23 8 = #O___@O__# : len=10 : NO 00 NO
+ 285 23 9 = #O___@_O_# : len=10 : NO 00 NO
+ 286 23 10 = #O___@OO_# : len=10 : H3 13 H3
+ 287 23 11 = #O___@__O# : len=10 : NO 00 NO
+ 288 23 12 = #O___@O_O# : len=10 : NO 00 NO
+ 289 23 13 = #O___@_OO# : len=10 : NO 00 NO
+ 290 23 14 = #O___@OOO# : len=10 : S4 00 S4
+ 291 23 15 = #O___@____# : len=11 : NO 00 NO
+ 292 23 16 = #O___@O___# : len=11 : NO 00 NO
+ 293 23 17 = #O___@_O__# : len=11 : NO 00 NO
+ 294 23 18 = #O___@OO__# : len=11 : H3 13 H3
+ 295 23 19 = #O___@__O_# : len=11 : NO 00 NO
+ 296 23 20 = #O___@O_O_# : len=11 : D3 02 D3
+ 297 23 21 = #O___@_OO_# : len=11 : D3 01 D3
+ 298 23 22 = #O___@OOO_# : len=11 : H4 00 H4
+ 299 23 23 = #O___@___O# : len=11 : NO 00 NO
+ 300 24 0 = #O__O@# : len= 7 : NO 00 NO
+ 301 24 1 = #O__O@_# : len= 8 : NO 00 NO
+ 302 24 2 = #O__O@O# : len= 8 : NO 00 NO
+ 303 24 3 = #O__O@__# : len= 9 : NO 00 NO
+ 304 24 4 = #O__O@O_# : len= 9 : NO 00 H3
+ 305 24 5 = #O__O@_O# : len= 9 : NO 00 NO
+ 306 24 6 = #O__O@OO# : len= 9 : S4 00 S4
+ 307 24 7 = #O__O@___# : len=10 : NO 00 NO
+ 308 24 8 = #O__O@O__# : len=10 : H3 22 H3
+ 309 24 9 = #O__O@_O_# : len=10 : D3 01 D3
+ 310 24 10 = #O__O@OO_# : len=10 : H4 00 H4
+ 311 24 11 = #O__O@__O# : len=10 : NO 00 NO
+ 312 24 12 = #O__O@O_O# : len=10 : D4 00 D4
+ 313 24 13 = #O__O@_OO# : len=10 : D4 00 D4
+ 314 24 14 = #O__O@OOO# : len=10 : L5 00 L5
+ 315 24 15 = #O__O@____# : len=11 : NO 00 NO
+ 316 24 16 = #O__O@O___# : len=11 : H3 22 H3
+ 317 24 17 = #O__O@_O__# : len=11 : D3 01 D3
+ 318 24 18 = #O__O@OO__# : len=11 : H4 00 H4
+ 319 24 19 = #O__O@__O_# : len=11 : NO 00 NO
+ 320 24 20 = #O__O@O_O_# : len=11 : D4 00 D4
+ 321 24 21 = #O__O@_OO_# : len=11 : D4 00 D4
+ 322 24 22 = #O__O@OOO_# : len=11 : L5 00 L5
+ 323 24 23 = #O__O@___O# : len=11 : NO 00 NO
+ 324 24 24 = #O__O@O__O# : len=11 : NO 00 H3
+ 325 25 0 = #O_O_@# : len= 7 : NO 00 NO
+ 326 25 1 = #O_O_@_# : len= 8 : NO 00 NO
+ 327 25 2 = #O_O_@O# : len= 8 : NO 00 NO
+ 328 25 3 = #O_O_@__# : len= 9 : NO 00 NO
+ 329 25 4 = #O_O_@O_# : len= 9 : NO 00 D3
+ 330 25 5 = #O_O_@_O# : len= 9 : NO 00 NO
+ 331 25 6 = #O_O_@OO# : len= 9 : D4 00 D4
+ 332 25 7 = #O_O_@___# : len=10 : NO 00 NO
+ 333 25 8 = #O_O_@O__# : len=10 : NO 00 D3
+ 334 25 9 = #O_O_@_O_# : len=10 : NO 00 NO
+ 335 25 10 = #O_O_@OO_# : len=10 : D4 00 D4
+ 336 25 11 = #O_O_@__O# : len=10 : NO 00 NO
+ 337 25 12 = #O_O_@O_O# : len=10 : NO 00 D3
+ 338 25 13 = #O_O_@_OO# : len=10 : NO 00 NO
+ 339 25 14 = #O_O_@OOO# : len=10 : NO 00 D4
+ 340 25 15 = #O_O_@____# : len=11 : NO 00 NO
+ 341 25 16 = #O_O_@O___# : len=11 : NO 00 D3
+ 342 25 17 = #O_O_@_O__# : len=11 : NO 00 NO
+ 343 25 18 = #O_O_@OO__# : len=11 : D4 00 D4
+ 344 25 19 = #O_O_@__O_# : len=11 : NO 00 NO
+ 345 25 20 = #O_O_@O_O_# : len=11 : NO 00 D3
+ 346 25 21 = #O_O_@_OO_# : len=11 : NO 00 D3
+ 347 25 22 = #O_O_@OOO_# : len=11 : S4 00 H4
+ 348 25 23 = #O_O_@___O# : len=11 : NO 00 NO
+ 349 25 24 = #O_O_@O__O# : len=11 : NO 00 D3
+ 350 25 25 = #O_O_@_O_O# : len=11 : NO 00 NO
+ 351 26 0 = #O_OO@# : len= 7 : D4 00 D4
+ 352 26 1 = #O_OO@_# : len= 8 : D4 00 D4
+ 353 26 2 = #O_OO@O# : len= 8 : NO 00 D4
+ 354 26 3 = #O_OO@__# : len= 9 : D4 00 D4
+ 355 26 4 = #O_OO@O_# : len= 9 : S4 00 H4
+ 356 26 5 = #O_OO@_O# : len= 9 : X4 00 X4
+ 357 26 6 = #O_OO@OO# : len= 9 : L5 00 L5
+ 358 26 7 = #O_OO@___# : len=10 : D4 00 D4
+ 359 26 8 = #O_OO@O__# : len=10 : S4 00 H4
+ 360 26 9 = #O_OO@_O_# : len=10 : X4 00 X4
+ 361 26 10 = #O_OO@OO_# : len=10 : L5 00 L5
+ 362 26 11 = #O_OO@__O# : len=10 : D4 00 D4
+ 363 26 12 = #O_OO@O_O# : len=10 : NO 00 H4
+ 364 26 13 = #O_OO@_OO# : len=10 : D4 00 X4
+ 365 26 14 = #O_OO@OOO# : len=10 : L6 00 L6
+ 366 26 15 = #O_OO@____# : len=11 : D4 00 D4
+ 367 26 16 = #O_OO@O___# : len=11 : S4 00 H4
+ 368 26 17 = #O_OO@_O__# : len=11 : X4 00 X4
+ 369 26 18 = #O_OO@OO__# : len=11 : L5 00 L5
+ 370 26 19 = #O_OO@__O_# : len=11 : D4 00 D4
+ 371 26 20 = #O_OO@O_O_# : len=11 : NO 00 H4
+ 372 26 21 = #O_OO@_OO_# : len=11 : D4 00 X4
+ 373 26 22 = #O_OO@OOO_# : len=11 : L6 00 L6
+ 374 26 23 = #O_OO@___O# : len=11 : D4 00 D4
+ 375 26 24 = #O_OO@O__O# : len=11 : S4 00 H4
+ 376 26 25 = #O_OO@_O_O# : len=11 : X4 00 X4
+ 377 26 26 = #O_OO@OO_O# : len=11 : L5 00 L5
+ 378 27 0 = #OO__@# : len= 7 : NO 00 NO
+ 379 27 1 = #OO__@_# : len= 8 : NO 00 NO
+ 380 27 2 = #OO__@O# : len= 8 : NO 00 NO
+ 381 27 3 = #OO__@__# : len= 9 : NO 00 NO
+ 382 27 4 = #OO__@O_# : len= 9 : NO 00 NO
+ 383 27 5 = #OO__@_O# : len= 9 : NO 00 NO
+ 384 27 6 = #OO__@OO# : len= 9 : NO 00 NO
+ 385 27 7 = #OO__@___# : len=10 : NO 00 NO
+ 386 27 8 = #OO__@O__# : len=10 : NO 00 NO
+ 387 27 9 = #OO__@_O_# : len=10 : NO 00 NO
+ 388 27 10 = #OO__@OO_# : len=10 : NO 00 H3
+ 389 27 11 = #OO__@__O# : len=10 : NO 00 NO
+ 390 27 12 = #OO__@O_O# : len=10 : NO 00 NO
+ 391 27 13 = #OO__@_OO# : len=10 : NO 00 NO
+ 392 27 14 = #OO__@OOO# : len=10 : S4 00 S4
+ 393 27 15 = #OO__@____# : len=11 : NO 00 NO
+ 394 27 16 = #OO__@O___# : len=11 : NO 00 NO
+ 395 27 17 = #OO__@_O__# : len=11 : NO 00 NO
+ 396 27 18 = #OO__@OO__# : len=11 : H3 13 H3
+ 397 27 19 = #OO__@__O_# : len=11 : NO 00 NO
+ 398 27 20 = #OO__@O_O_# : len=11 : D3 02 D3
+ 399 27 21 = #OO__@_OO_# : len=11 : D3 01 D3
+ 400 27 22 = #OO__@OOO_# : len=11 : H4 00 H4
+ 401 27 23 = #OO__@___O# : len=11 : NO 00 NO
+ 402 27 24 = #OO__@O__O# : len=11 : NO 00 NO
+ 403 27 25 = #OO__@_O_O# : len=11 : NO 00 NO
+ 404 27 26 = #OO__@OO_O# : len=11 : D4 00 D4
+ 405 27 27 = #OO__@__OO# : len=11 : NO 00 NO
+ 406 28 0 = #OO_O@# : len= 7 : D4 00 D4
+ 407 28 1 = #OO_O@_# : len= 8 : D4 00 D4
+ 408 28 2 = #OO_O@O# : len= 8 : NO 00 D4
+ 409 28 3 = #OO_O@__# : len= 9 : D4 00 D4
+ 410 28 4 = #OO_O@O_# : len= 9 : NO 00 D4
+ 411 28 5 = #OO_O@_O# : len= 9 : D4 00 D4
+ 412 28 6 = #OO_O@OO# : len= 9 : NO 00 D4
+ 413 28 7 = #OO_O@___# : len=10 : D4 00 D4
+ 414 28 8 = #OO_O@O__# : len=10 : NO 00 D4
+ 415 28 9 = #OO_O@_O_# : len=10 : D4 00 D4
+ 416 28 10 = #OO_O@OO_# : len=10 : S4 00 H4
+ 417 28 11 = #OO_O@__O# : len=10 : D4 00 D4
+ 418 28 12 = #OO_O@O_O# : len=10 : D4 00 X4
+ 419 28 13 = #OO_O@_OO# : len=10 : X4 00 X4
+ 420 28 14 = #OO_O@OOO# : len=10 : L5 00 L5
+ 421 28 15 = #OO_O@____# : len=11 : D4 00 D4
+ 422 28 16 = #OO_O@O___# : len=11 : NO 00 D4
+ 423 28 17 = #OO_O@_O__# : len=11 : D4 00 D4
+ 424 28 18 = #OO_O@OO__# : len=11 : S4 00 H4
+ 425 28 19 = #OO_O@__O_# : len=11 : D4 00 D4
+ 426 28 20 = #OO_O@O_O_# : len=11 : D4 00 X4
+ 427 28 21 = #OO_O@_OO_# : len=11 : X4 00 X4
+ 428 28 22 = #OO_O@OOO_# : len=11 : L5 00 L5
+ 429 28 23 = #OO_O@___O# : len=11 : D4 00 D4
+ 430 28 24 = #OO_O@O__O# : len=11 : NO 00 D4
+ 431 28 25 = #OO_O@_O_O# : len=11 : D4 00 D4
+ 432 28 26 = #OO_O@OO_O# : len=11 : NO 00 H4
+ 433 28 27 = #OO_O@__OO# : len=11 : D4 00 D4
+ 434 28 28 = #OO_O@O_OO# : len=11 : NO 00 X4
+ 435 29 0 = #OOO_@# : len= 7 : D4 00 D4
+ 436 29 1 = #OOO_@_# : len= 8 : D4 00 D4
+ 437 29 2 = #OOO_@O# : len= 8 : NO 00 D4
+ 438 29 3 = #OOO_@__# : len= 9 : D4 00 D4
+ 439 29 4 = #OOO_@O_# : len= 9 : NO 00 D4
+ 440 29 5 = #OOO_@_O# : len= 9 : D4 00 D4
+ 441 29 6 = #OOO_@OO# : len= 9 : NO 00 D4
+ 442 29 7 = #OOO_@___# : len=10 : D4 00 D4
+ 443 29 8 = #OOO_@O__# : len=10 : NO 00 D4
+ 444 29 9 = #OOO_@_O_# : len=10 : D4 00 D4
+ 445 29 10 = #OOO_@OO_# : len=10 : NO 00 D4
+ 446 29 11 = #OOO_@__O# : len=10 : D4 00 D4
+ 447 29 12 = #OOO_@O_O# : len=10 : NO 00 D4
+ 448 29 13 = #OOO_@_OO# : len=10 : D4 00 D4
+ 449 29 14 = #OOO_@OOO# : len=10 : NO 00 D4
+ 450 29 15 = #OOO_@____# : len=11 : D4 00 D4
+ 451 29 16 = #OOO_@O___# : len=11 : NO 00 D4
+ 452 29 17 = #OOO_@_O__# : len=11 : D4 00 D4
+ 453 29 18 = #OOO_@OO__# : len=11 : NO 00 D4
+ 454 29 19 = #OOO_@__O_# : len=11 : D4 00 D4
+ 455 29 20 = #OOO_@O_O_# : len=11 : NO 00 D4
+ 456 29 21 = #OOO_@_OO_# : len=11 : D4 00 D4
+ 457 29 22 = #OOO_@OOO_# : len=11 : S4 00 H4
+ 458 29 23 = #OOO_@___O# : len=11 : D4 00 D4
+ 459 29 24 = #OOO_@O__O# : len=11 : NO 00 D4
+ 460 29 25 = #OOO_@_O_O# : len=11 : D4 00 D4
+ 461 29 26 = #OOO_@OO_O# : len=11 : D4 00 X4
+ 462 29 27 = #OOO_@__OO# : len=11 : D4 00 D4
+ 463 29 28 = #OOO_@O_OO# : len=11 : D4 00 X4
+ 464 29 29 = #OOO_@_OOO# : len=11 : X4 00 X4
+ 465 30 0 = #OOOO@# : len= 7 : L5 00 L5
+ 466 30 1 = #OOOO@_# : len= 8 : L5 00 L5
+ 467 30 2 = #OOOO@O# : len= 8 : L6 00 L6
+ 468 30 3 = #OOOO@__# : len= 9 : L5 00 L5
+ 469 30 4 = #OOOO@O_# : len= 9 : L6 00 L6
+ 470 30 5 = #OOOO@_O# : len= 9 : L5 00 L5
+ 471 30 6 = #OOOO@OO# : len= 9 : L6 00 L6
+ 472 30 7 = #OOOO@___# : len=10 : L5 00 L5
+ 473 30 8 = #OOOO@O__# : len=10 : L6 00 L6
+ 474 30 9 = #OOOO@_O_# : len=10 : L5 00 L5
+ 475 30 10 = #OOOO@OO_# : len=10 : L6 00 L6
+ 476 30 11 = #OOOO@__O# : len=10 : L5 00 L5
+ 477 30 12 = #OOOO@O_O# : len=10 : L6 00 L6
+ 478 30 13 = #OOOO@_OO# : len=10 : L5 00 L5
+ 479 30 14 = #OOOO@OOO# : len=10 : L6 00 L6
+ 480 30 15 = #OOOO@____# : len=11 : L5 00 L5
+ 481 30 16 = #OOOO@O___# : len=11 : L6 00 L6
+ 482 30 17 = #OOOO@_O__# : len=11 : L5 00 L5
+ 483 30 18 = #OOOO@OO__# : len=11 : L6 00 L6
+ 484 30 19 = #OOOO@__O_# : len=11 : L5 00 L5
+ 485 30 20 = #OOOO@O_O_# : len=11 : L6 00 L6
+ 486 30 21 = #OOOO@_OO_# : len=11 : L5 00 L5
+ 487 30 22 = #OOOO@OOO_# : len=11 : L6 00 L6
+ 488 30 23 = #OOOO@___O# : len=11 : L5 00 L5
+ 489 30 24 = #OOOO@O__O# : len=11 : L6 00 L6
+ 490 30 25 = #OOOO@_O_O# : len=11 : L5 00 L5
+ 491 30 26 = #OOOO@OO_O# : len=11 : L6 00 L6
+ 492 30 27 = #OOOO@__OO# : len=11 : L5 00 L5
+ 493 30 28 = #OOOO@O_OO# : len=11 : L6 00 L6
+ 494 30 29 = #OOOO@_OOO# : len=11 : L5 00 L5
+ 495 30 30 = #OOOO@OOOO# : len=11 : L6 00 L6
+ 496 31 0 = _____@# : len= 7 : NO 00 NO
+ 497 31 1 = _____@_# : len= 8 : NO 00 NO
+ 498 31 2 = _____@O# : len= 8 : NO 00 NO
+ 499 31 3 = _____@__# : len= 9 : NO 00 NO
+ 500 31 4 = _____@O_# : len= 9 : NO 00 NO
+ 501 31 5 = _____@_O# : len= 9 : NO 00 NO
+ 502 31 6 = _____@OO# : len= 9 : NO 00 NO
+ 503 31 7 = _____@___# : len=10 : NO 00 NO
+ 504 31 8 = _____@O__# : len=10 : NO 00 NO
+ 505 31 9 = _____@_O_# : len=10 : NO 00 NO
+ 506 31 10 = _____@OO_# : len=10 : H3 13 H3
+ 507 31 11 = _____@__O# : len=10 : NO 00 NO
+ 508 31 12 = _____@O_O# : len=10 : NO 00 NO
+ 509 31 13 = _____@_OO# : len=10 : NO 00 NO
+ 510 31 14 = _____@OOO# : len=10 : S4 00 S4
+ 511 31 15 = _____@____# : len=11 : NO 00 NO
+ 512 31 16 = _____@O___# : len=11 : NO 00 NO
+ 513 31 17 = _____@_O__# : len=11 : NO 00 NO
+ 514 31 18 = _____@OO__# : len=11 : H3 13 H3
+ 515 31 19 = _____@__O_# : len=11 : NO 00 NO
+ 516 31 20 = _____@O_O_# : len=11 : D3 02 D3
+ 517 31 21 = _____@_OO_# : len=11 : D3 01 D3
+ 518 31 22 = _____@OOO_# : len=11 : H4 00 H4
+ 519 31 23 = _____@___O# : len=11 : NO 00 NO
+ 520 31 24 = _____@O__O# : len=11 : NO 00 NO
+ 521 31 25 = _____@_O_O# : len=11 : NO 00 NO
+ 522 31 26 = _____@OO_O# : len=11 : D4 00 D4
+ 523 31 27 = _____@__OO# : len=11 : NO 00 NO
+ 524 31 28 = _____@O_OO# : len=11 : D4 00 D4
+ 525 31 29 = _____@_OOO# : len=11 : D4 00 D4
+ 526 31 30 = _____@OOOO# : len=11 : L5 00 L5
+ 527 31 31 = _____@_____ : len=11 : NO 00 NO
+ 528 32 0 = ____O@# : len= 7 : NO 00 NO
+ 529 32 1 = ____O@_# : len= 8 : NO 00 NO
+ 530 32 2 = ____O@O# : len= 8 : NO 00 NO
+ 531 32 3 = ____O@__# : len= 9 : NO 00 NO
+ 532 32 4 = ____O@O_# : len= 9 : H3 22 H3
+ 533 32 5 = ____O@_O# : len= 9 : NO 00 NO
+ 534 32 6 = ____O@OO# : len= 9 : S4 00 S4
+ 535 32 7 = ____O@___# : len=10 : NO 00 NO
+ 536 32 8 = ____O@O__# : len=10 : H3 22 H3
+ 537 32 9 = ____O@_O_# : len=10 : D3 01 D3
+ 538 32 10 = ____O@OO_# : len=10 : H4 00 H4
+ 539 32 11 = ____O@__O# : len=10 : NO 00 NO
+ 540 32 12 = ____O@O_O# : len=10 : D4 00 D4
+ 541 32 13 = ____O@_OO# : len=10 : D4 00 D4
+ 542 32 14 = ____O@OOO# : len=10 : L5 00 L5
+ 543 32 15 = ____O@____# : len=11 : NO 00 NO
+ 544 32 16 = ____O@O___# : len=11 : H3 22 H3
+ 545 32 17 = ____O@_O__# : len=11 : D3 01 D3
+ 546 32 18 = ____O@OO__# : len=11 : H4 00 H4
+ 547 32 19 = ____O@__O_# : len=11 : NO 00 NO
+ 548 32 20 = ____O@O_O_# : len=11 : D4 00 D4
+ 549 32 21 = ____O@_OO_# : len=11 : D4 00 D4
+ 550 32 22 = ____O@OOO_# : len=11 : L5 00 L5
+ 551 32 23 = ____O@___O# : len=11 : NO 00 NO
+ 552 32 24 = ____O@O__O# : len=11 : H3 22 H3
+ 553 32 25 = ____O@_O_O# : len=11 : NO 00 D3
+ 554 32 26 = ____O@OO_O# : len=11 : S4 00 H4
+ 555 32 27 = ____O@__OO# : len=11 : NO 00 NO
+ 556 32 28 = ____O@O_OO# : len=11 : NO 00 D4
+ 557 32 29 = ____O@_OOO# : len=11 : NO 00 D4
+ 558 32 30 = ____O@OOOO# : len=11 : L6 00 L6
+ 559 32 31 = ____O@_____ : len=11 : NO 00 NO
+ 560 32 32 = ____O@O____ : len=11 : H3 22 H3
+ 561 33 0 = ___O_@# : len= 7 : NO 00 NO
+ 562 33 1 = ___O_@_# : len= 8 : NO 00 NO
+ 563 33 2 = ___O_@O# : len= 8 : NO 00 NO
+ 564 33 3 = ___O_@__# : len= 9 : NO 00 NO
+ 565 33 4 = ___O_@O_# : len= 9 : D3 10 D3
+ 566 33 5 = ___O_@_O# : len= 9 : NO 00 NO
+ 567 33 6 = ___O_@OO# : len= 9 : D4 00 D4
+ 568 33 7 = ___O_@___# : len=10 : NO 00 NO
+ 569 33 8 = ___O_@O__# : len=10 : D3 10 D3
+ 570 33 9 = ___O_@_O_# : len=10 : NO 00 NO
+ 571 33 10 = ___O_@OO_# : len=10 : D4 00 D4
+ 572 33 11 = ___O_@__O# : len=10 : NO 00 NO
+ 573 33 12 = ___O_@O_O# : len=10 : NO 00 D3
+ 574 33 13 = ___O_@_OO# : len=10 : NO 00 NO
+ 575 33 14 = ___O_@OOO# : len=10 : NO 00 D4
+ 576 33 15 = ___O_@____# : len=11 : NO 00 NO
+ 577 33 16 = ___O_@O___# : len=11 : D3 10 D3
+ 578 33 17 = ___O_@_O__# : len=11 : NO 00 NO
+ 579 33 18 = ___O_@OO__# : len=11 : D4 00 D4
+ 580 33 19 = ___O_@__O_# : len=11 : NO 00 NO
+ 581 33 20 = ___O_@O_O_# : len=11 : NO 00 D3
+ 582 33 21 = ___O_@_OO_# : len=11 : NO 00 D3
+ 583 33 22 = ___O_@OOO_# : len=11 : S4 00 H4
+ 584 33 23 = ___O_@___O# : len=11 : NO 00 NO
+ 585 33 24 = ___O_@O__O# : len=11 : D3 10 D3
+ 586 33 25 = ___O_@_O_O# : len=11 : NO 00 NO
+ 587 33 26 = ___O_@OO_O# : len=11 : X4 00 X4
+ 588 33 27 = ___O_@__OO# : len=11 : NO 00 NO
+ 589 33 28 = ___O_@O_OO# : len=11 : D4 00 D4
+ 590 33 29 = ___O_@_OOO# : len=11 : D4 00 D4
+ 591 33 30 = ___O_@OOOO# : len=11 : L5 00 L5
+ 592 33 31 = ___O_@_____ : len=11 : NO 00 NO
+ 593 33 32 = ___O_@O____ : len=11 : D3 10 D3
+ 594 33 33 = ___O_@_O___ : len=11 : NO 00 NO
+ 595 34 0 = ___OO@# : len= 7 : NO 00 NO
+ 596 34 1 = ___OO@_# : len= 8 : H3 31 H3
+ 597 34 2 = ___OO@O# : len= 8 : S4 00 S4
+ 598 34 3 = ___OO@__# : len= 9 : H3 31 H3
+ 599 34 4 = ___OO@O_# : len= 9 : H4 00 H4
+ 600 34 5 = ___OO@_O# : len= 9 : D4 00 D4
+ 601 34 6 = ___OO@OO# : len= 9 : L5 00 L5
+ 602 34 7 = ___OO@___# : len=10 : H3 31 H3
+ 603 34 8 = ___OO@O__# : len=10 : H4 00 H4
+ 604 34 9 = ___OO@_O_# : len=10 : D4 00 D4
+ 605 34 10 = ___OO@OO_# : len=10 : L5 00 L5
+ 606 34 11 = ___OO@__O# : len=10 : H3 31 H3
+ 607 34 12 = ___OO@O_O# : len=10 : S4 00 H4
+ 608 34 13 = ___OO@_OO# : len=10 : NO 00 D4
+ 609 34 14 = ___OO@OOO# : len=10 : L6 00 L6
+ 610 34 15 = ___OO@____# : len=11 : H3 31 H3
+ 611 34 16 = ___OO@O___# : len=11 : H4 00 H4
+ 612 34 17 = ___OO@_O__# : len=11 : D4 00 D4
+ 613 34 18 = ___OO@OO__# : len=11 : L5 00 L5
+ 614 34 19 = ___OO@__O_# : len=11 : H3 31 H3
+ 615 34 20 = ___OO@O_O_# : len=11 : S4 00 H4
+ 616 34 21 = ___OO@_OO_# : len=11 : NO 00 D4
+ 617 34 22 = ___OO@OOO_# : len=11 : L6 00 L6
+ 618 34 23 = ___OO@___O# : len=11 : H3 31 H3
+ 619 34 24 = ___OO@O__O# : len=11 : H4 00 H4
+ 620 34 25 = ___OO@_O_O# : len=11 : D4 00 D4
+ 621 34 26 = ___OO@OO_O# : len=11 : L5 00 L5
+ 622 34 27 = ___OO@__OO# : len=11 : H3 31 H3
+ 623 34 28 = ___OO@O_OO# : len=11 : S4 00 H4
+ 624 34 29 = ___OO@_OOO# : len=11 : NO 00 D4
+ 625 34 30 = ___OO@OOOO# : len=11 : L6 00 L6
+ 626 34 31 = ___OO@_____ : len=11 : H3 31 H3
+ 627 34 32 = ___OO@O____ : len=11 : H4 00 H4
+ 628 34 33 = ___OO@_O___ : len=11 : D4 00 D4
+ 629 34 34 = ___OO@OO___ : len=11 : L5 00 L5
+ 630 35 0 = __O__@# : len= 7 : NO 00 NO
+ 631 35 1 = __O__@_# : len= 8 : NO 00 NO
+ 632 35 2 = __O__@O# : len= 8 : NO 00 NO
+ 633 35 3 = __O__@__# : len= 9 : NO 00 NO
+ 634 35 4 = __O__@O_# : len= 9 : NO 00 NO
+ 635 35 5 = __O__@_O# : len= 9 : NO 00 NO
+ 636 35 6 = __O__@OO# : len= 9 : NO 00 NO
+ 637 35 7 = __O__@___# : len=10 : NO 00 NO
+ 638 35 8 = __O__@O__# : len=10 : NO 00 NO
+ 639 35 9 = __O__@_O_# : len=10 : NO 00 NO
+ 640 35 10 = __O__@OO_# : len=10 : NO 00 H3
+ 641 35 11 = __O__@__O# : len=10 : NO 00 NO
+ 642 35 12 = __O__@O_O# : len=10 : NO 00 NO
+ 643 35 13 = __O__@_OO# : len=10 : NO 00 NO
+ 644 35 14 = __O__@OOO# : len=10 : S4 00 S4
+ 645 35 15 = __O__@____# : len=11 : NO 00 NO
+ 646 35 16 = __O__@O___# : len=11 : NO 00 NO
+ 647 35 17 = __O__@_O__# : len=11 : NO 00 NO
+ 648 35 18 = __O__@OO__# : len=11 : H3 13 H3
+ 649 35 19 = __O__@__O_# : len=11 : NO 00 NO
+ 650 35 20 = __O__@O_O_# : len=11 : D3 02 D3
+ 651 35 21 = __O__@_OO_# : len=11 : D3 01 D3
+ 652 35 22 = __O__@OOO_# : len=11 : H4 00 H4
+ 653 35 23 = __O__@___O# : len=11 : NO 00 NO
+ 654 35 24 = __O__@O__O# : len=11 : NO 00 NO
+ 655 35 25 = __O__@_O_O# : len=11 : NO 00 NO
+ 656 35 26 = __O__@OO_O# : len=11 : D4 00 D4
+ 657 35 27 = __O__@__OO# : len=11 : NO 00 NO
+ 658 35 28 = __O__@O_OO# : len=11 : D4 00 D4
+ 659 35 29 = __O__@_OOO# : len=11 : D4 00 D4
+ 660 35 30 = __O__@OOOO# : len=11 : L5 00 L5
+ 661 35 31 = __O__@_____ : len=11 : NO 00 NO
+ 662 35 32 = __O__@O____ : len=11 : NO 00 NO
+ 663 35 33 = __O__@_O___ : len=11 : NO 00 NO
+ 664 35 34 = __O__@OO___ : len=11 : H3 13 H3
+ 665 35 35 = __O__@__O__ : len=11 : NO 00 NO
+ 666 36 0 = __O_O@# : len= 7 : NO 00 NO
+ 667 36 1 = __O_O@_# : len= 8 : D3 20 D3
+ 668 36 2 = __O_O@O# : len= 8 : D4 00 D4
+ 669 36 3 = __O_O@__# : len= 9 : D3 20 D3
+ 670 36 4 = __O_O@O_# : len= 9 : D4 00 D4
+ 671 36 5 = __O_O@_O# : len= 9 : NO 00 D3
+ 672 36 6 = __O_O@OO# : len= 9 : NO 00 D4
+ 673 36 7 = __O_O@___# : len=10 : D3 20 D3
+ 674 36 8 = __O_O@O__# : len=10 : D4 00 D4
+ 675 36 9 = __O_O@_O_# : len=10 : NO 00 D3
+ 676 36 10 = __O_O@OO_# : len=10 : S4 00 H4
+ 677 36 11 = __O_O@__O# : len=10 : D3 20 D3
+ 678 36 12 = __O_O@O_O# : len=10 : X4 00 X4
+ 679 36 13 = __O_O@_OO# : len=10 : D4 00 D4
+ 680 36 14 = __O_O@OOO# : len=10 : L5 00 L5
+ 681 36 15 = __O_O@____# : len=11 : D3 20 D3
+ 682 36 16 = __O_O@O___# : len=11 : D4 00 D4
+ 683 36 17 = __O_O@_O__# : len=11 : NO 00 D3
+ 684 36 18 = __O_O@OO__# : len=11 : S4 00 H4
+ 685 36 19 = __O_O@__O_# : len=11 : D3 20 D3
+ 686 36 20 = __O_O@O_O_# : len=11 : X4 00 X4
+ 687 36 21 = __O_O@_OO_# : len=11 : D4 00 D4
+ 688 36 22 = __O_O@OOO_# : len=11 : L5 00 L5
+ 689 36 23 = __O_O@___O# : len=11 : D3 20 D3
+ 690 36 24 = __O_O@O__O# : len=11 : D4 00 D4
+ 691 36 25 = __O_O@_O_O# : len=11 : NO 00 D3
+ 692 36 26 = __O_O@OO_O# : len=11 : NO 00 H4
+ 693 36 27 = __O_O@__OO# : len=11 : D3 20 D3
+ 694 36 28 = __O_O@O_OO# : len=11 : D4 00 X4
+ 695 36 29 = __O_O@_OOO# : len=11 : NO 00 D4
+ 696 36 30 = __O_O@OOOO# : len=11 : L6 00 L6
+ 697 36 31 = __O_O@_____ : len=11 : D3 20 D3
+ 698 36 32 = __O_O@O____ : len=11 : D4 00 D4
+ 699 36 33 = __O_O@_O___ : len=11 : NO 00 D3
+ 700 36 34 = __O_O@OO___ : len=11 : S4 00 H4
+ 701 36 35 = __O_O@__O__ : len=11 : D3 20 D3
+ 702 36 36 = __O_O@O_O__ : len=11 : X4 00 X4
+ 703 37 0 = __OO_@# : len= 7 : NO 00 NO
+ 704 37 1 = __OO_@_# : len= 8 : D3 10 D3
+ 705 37 2 = __OO_@O# : len= 8 : D4 00 D4
+ 706 37 3 = __OO_@__# : len= 9 : D3 10 D3
+ 707 37 4 = __OO_@O_# : len= 9 : D4 00 D4
+ 708 37 5 = __OO_@_O# : len= 9 : NO 00 D3
+ 709 37 6 = __OO_@OO# : len= 9 : NO 00 D4
+ 710 37 7 = __OO_@___# : len=10 : D3 10 D3
+ 711 37 8 = __OO_@O__# : len=10 : D4 00 D4
+ 712 37 9 = __OO_@_O_# : len=10 : NO 00 D3
+ 713 37 10 = __OO_@OO_# : len=10 : NO 00 D4
+ 714 37 11 = __OO_@__O# : len=10 : D3 10 D3
+ 715 37 12 = __OO_@O_O# : len=10 : D4 00 D4
+ 716 37 13 = __OO_@_OO# : len=10 : NO 00 D3
+ 717 37 14 = __OO_@OOO# : len=10 : NO 00 D4
+ 718 37 15 = __OO_@____# : len=11 : D3 10 D3
+ 719 37 16 = __OO_@O___# : len=11 : D4 00 D4
+ 720 37 17 = __OO_@_O__# : len=11 : NO 00 D3
+ 721 37 18 = __OO_@OO__# : len=11 : NO 00 D4
+ 722 37 19 = __OO_@__O_# : len=11 : D3 10 D3
+ 723 37 20 = __OO_@O_O_# : len=11 : D4 00 D4
+ 724 37 21 = __OO_@_OO_# : len=11 : NO 00 D3
+ 725 37 22 = __OO_@OOO_# : len=11 : S4 00 H4
+ 726 37 23 = __OO_@___O# : len=11 : D3 10 D3
+ 727 37 24 = __OO_@O__O# : len=11 : D4 00 D4
+ 728 37 25 = __OO_@_O_O# : len=11 : NO 00 D3
+ 729 37 26 = __OO_@OO_O# : len=11 : D4 00 X4
+ 730 37 27 = __OO_@__OO# : len=11 : D3 10 D3
+ 731 37 28 = __OO_@O_OO# : len=11 : X4 00 X4
+ 732 37 29 = __OO_@_OOO# : len=11 : D4 00 D4
+ 733 37 30 = __OO_@OOOO# : len=11 : L5 00 L5
+ 734 37 31 = __OO_@_____ : len=11 : D3 10 D3
+ 735 37 32 = __OO_@O____ : len=11 : D4 00 D4
+ 736 37 33 = __OO_@_O___ : len=11 : NO 00 D3
+ 737 37 34 = __OO_@OO___ : len=11 : NO 00 D4
+ 738 37 35 = __OO_@__O__ : len=11 : D3 10 D3
+ 739 37 36 = __OO_@O_O__ : len=11 : D4 00 D4
+ 740 37 37 = __OO_@_OO__ : len=11 : NO 00 D3
+ 741 38 0 = __OOO@# : len= 7 : S4 00 S4
+ 742 38 1 = __OOO@_# : len= 8 : H4 00 H4
+ 743 38 2 = __OOO@O# : len= 8 : L5 00 L5
+ 744 38 3 = __OOO@__# : len= 9 : H4 00 H4
+ 745 38 4 = __OOO@O_# : len= 9 : L5 00 L5
+ 746 38 5 = __OOO@_O# : len= 9 : S4 00 H4
+ 747 38 6 = __OOO@OO# : len= 9 : L6 00 L6
+ 748 38 7 = __OOO@___# : len=10 : H4 00 H4
+ 749 38 8 = __OOO@O__# : len=10 : L5 00 L5
+ 750 38 9 = __OOO@_O_# : len=10 : S4 00 H4
+ 751 38 10 = __OOO@OO_# : len=10 : L6 00 L6
+ 752 38 11 = __OOO@__O# : len=10 : H4 00 H4
+ 753 38 12 = __OOO@O_O# : len=10 : L5 00 L5
+ 754 38 13 = __OOO@_OO# : len=10 : S4 00 H4
+ 755 38 14 = __OOO@OOO# : len=10 : L6 00 L6
+ 756 38 15 = __OOO@____# : len=11 : H4 00 H4
+ 757 38 16 = __OOO@O___# : len=11 : L5 00 L5
+ 758 38 17 = __OOO@_O__# : len=11 : S4 00 H4
+ 759 38 18 = __OOO@OO__# : len=11 : L6 00 L6
+ 760 38 19 = __OOO@__O_# : len=11 : H4 00 H4
+ 761 38 20 = __OOO@O_O_# : len=11 : L5 00 L5
+ 762 38 21 = __OOO@_OO_# : len=11 : S4 00 H4
+ 763 38 22 = __OOO@OOO_# : len=11 : L6 00 L6
+ 764 38 23 = __OOO@___O# : len=11 : H4 00 H4
+ 765 38 24 = __OOO@O__O# : len=11 : L5 00 L5
+ 766 38 25 = __OOO@_O_O# : len=11 : S4 00 H4
+ 767 38 26 = __OOO@OO_O# : len=11 : L6 00 L6
+ 768 38 27 = __OOO@__OO# : len=11 : H4 00 H4
+ 769 38 28 = __OOO@O_OO# : len=11 : L5 00 L5
+ 770 38 29 = __OOO@_OOO# : len=11 : S4 00 H4
+ 771 38 30 = __OOO@OOOO# : len=11 : L6 00 L6
+ 772 38 31 = __OOO@_____ : len=11 : H4 00 H4
+ 773 38 32 = __OOO@O____ : len=11 : L5 00 L5
+ 774 38 33 = __OOO@_O___ : len=11 : S4 00 H4
+ 775 38 34 = __OOO@OO___ : len=11 : L6 00 L6
+ 776 38 35 = __OOO@__O__ : len=11 : H4 00 H4
+ 777 38 36 = __OOO@O_O__ : len=11 : L5 00 L5
+ 778 38 37 = __OOO@_OO__ : len=11 : S4 00 H4
+ 779 38 38 = __OOO@OOO__ : len=11 : L6 00 L6
+ 780 39 0 = _O___@# : len= 7 : NO 00 NO
+ 781 39 1 = _O___@_# : len= 8 : NO 00 NO
+ 782 39 2 = _O___@O# : len= 8 : NO 00 NO
+ 783 39 3 = _O___@__# : len= 9 : NO 00 NO
+ 784 39 4 = _O___@O_# : len= 9 : NO 00 NO
+ 785 39 5 = _O___@_O# : len= 9 : NO 00 NO
+ 786 39 6 = _O___@OO# : len= 9 : NO 00 NO
+ 787 39 7 = _O___@___# : len=10 : NO 00 NO
+ 788 39 8 = _O___@O__# : len=10 : NO 00 NO
+ 789 39 9 = _O___@_O_# : len=10 : NO 00 NO
+ 790 39 10 = _O___@OO_# : len=10 : H3 13 H3
+ 791 39 11 = _O___@__O# : len=10 : NO 00 NO
+ 792 39 12 = _O___@O_O# : len=10 : NO 00 NO
+ 793 39 13 = _O___@_OO# : len=10 : NO 00 NO
+ 794 39 14 = _O___@OOO# : len=10 : S4 00 S4
+ 795 39 15 = _O___@____# : len=11 : NO 00 NO
+ 796 39 16 = _O___@O___# : len=11 : NO 00 NO
+ 797 39 17 = _O___@_O__# : len=11 : NO 00 NO
+ 798 39 18 = _O___@OO__# : len=11 : H3 13 H3
+ 799 39 19 = _O___@__O_# : len=11 : NO 00 NO
+ 800 39 20 = _O___@O_O_# : len=11 : D3 02 D3
+ 801 39 21 = _O___@_OO_# : len=11 : D3 01 D3
+ 802 39 22 = _O___@OOO_# : len=11 : H4 00 H4
+ 803 39 23 = _O___@___O# : len=11 : NO 00 NO
+ 804 39 24 = _O___@O__O# : len=11 : NO 00 NO
+ 805 39 25 = _O___@_O_O# : len=11 : NO 00 NO
+ 806 39 26 = _O___@OO_O# : len=11 : D4 00 D4
+ 807 39 27 = _O___@__OO# : len=11 : NO 00 NO
+ 808 39 28 = _O___@O_OO# : len=11 : D4 00 D4
+ 809 39 29 = _O___@_OOO# : len=11 : D4 00 D4
+ 810 39 30 = _O___@OOOO# : len=11 : L5 00 L5
+ 811 39 31 = _O___@_____ : len=11 : NO 00 NO
+ 812 39 32 = _O___@O____ : len=11 : NO 00 NO
+ 813 39 33 = _O___@_O___ : len=11 : NO 00 NO
+ 814 39 34 = _O___@OO___ : len=11 : H3 13 H3
+ 815 39 35 = _O___@__O__ : len=11 : NO 00 NO
+ 816 39 36 = _O___@O_O__ : len=11 : D3 02 D3
+ 817 39 37 = _O___@_OO__ : len=11 : D3 01 D3
+ 818 39 38 = _O___@OOO__ : len=11 : H4 00 H4
+ 819 39 39 = _O___@___O_ : len=11 : NO 00 NO
+ 820 40 0 = _O__O@# : len= 7 : NO 00 NO
+ 821 40 1 = _O__O@_# : len= 8 : NO 00 NO
+ 822 40 2 = _O__O@O# : len= 8 : NO 00 NO
+ 823 40 3 = _O__O@__# : len= 9 : NO 00 NO
+ 824 40 4 = _O__O@O_# : len= 9 : NO 00 H3
+ 825 40 5 = _O__O@_O# : len= 9 : NO 00 NO
+ 826 40 6 = _O__O@OO# : len= 9 : S4 00 S4
+ 827 40 7 = _O__O@___# : len=10 : NO 00 NO
+ 828 40 8 = _O__O@O__# : len=10 : H3 22 H3
+ 829 40 9 = _O__O@_O_# : len=10 : D3 01 D3
+ 830 40 10 = _O__O@OO_# : len=10 : H4 00 H4
+ 831 40 11 = _O__O@__O# : len=10 : NO 00 NO
+ 832 40 12 = _O__O@O_O# : len=10 : D4 00 D4
+ 833 40 13 = _O__O@_OO# : len=10 : D4 00 D4
+ 834 40 14 = _O__O@OOO# : len=10 : L5 00 L5
+ 835 40 15 = _O__O@____# : len=11 : NO 00 NO
+ 836 40 16 = _O__O@O___# : len=11 : H3 22 H3
+ 837 40 17 = _O__O@_O__# : len=11 : D3 01 D3
+ 838 40 18 = _O__O@OO__# : len=11 : H4 00 H4
+ 839 40 19 = _O__O@__O_# : len=11 : NO 00 NO
+ 840 40 20 = _O__O@O_O_# : len=11 : D4 00 D4
+ 841 40 21 = _O__O@_OO_# : len=11 : D4 00 D4
+ 842 40 22 = _O__O@OOO_# : len=11 : L5 00 L5
+ 843 40 23 = _O__O@___O# : len=11 : NO 00 NO
+ 844 40 24 = _O__O@O__O# : len=11 : NO 00 H3
+ 845 40 25 = _O__O@_O_O# : len=11 : NO 00 D3
+ 846 40 26 = _O__O@OO_O# : len=11 : S4 00 H4
+ 847 40 27 = _O__O@__OO# : len=11 : NO 00 NO
+ 848 40 28 = _O__O@O_OO# : len=11 : NO 00 D4
+ 849 40 29 = _O__O@_OOO# : len=11 : NO 00 D4
+ 850 40 30 = _O__O@OOOO# : len=11 : L6 00 L6
+ 851 40 31 = _O__O@_____ : len=11 : NO 00 NO
+ 852 40 32 = _O__O@O____ : len=11 : H3 22 H3
+ 853 40 33 = _O__O@_O___ : len=11 : D3 01 D3
+ 854 40 34 = _O__O@OO___ : len=11 : H4 00 H4
+ 855 40 35 = _O__O@__O__ : len=11 : NO 00 NO
+ 856 40 36 = _O__O@O_O__ : len=11 : D4 00 D4
+ 857 40 37 = _O__O@_OO__ : len=11 : D4 00 D4
+ 858 40 38 = _O__O@OOO__ : len=11 : L5 00 L5
+ 859 40 39 = _O__O@___O_ : len=11 : NO 00 NO
+ 860 40 40 = _O__O@O__O_ : len=11 : NO 00 H3
+ 861 41 0 = _O_O_@# : len= 7 : NO 00 NO
+ 862 41 1 = _O_O_@_# : len= 8 : NO 00 NO
+ 863 41 2 = _O_O_@O# : len= 8 : NO 00 NO
+ 864 41 3 = _O_O_@__# : len= 9 : NO 00 NO
+ 865 41 4 = _O_O_@O_# : len= 9 : NO 00 D3
+ 866 41 5 = _O_O_@_O# : len= 9 : NO 00 NO
+ 867 41 6 = _O_O_@OO# : len= 9 : D4 00 D4
+ 868 41 7 = _O_O_@___# : len=10 : NO 00 NO
+ 869 41 8 = _O_O_@O__# : len=10 : NO 00 D3
+ 870 41 9 = _O_O_@_O_# : len=10 : NO 00 NO
+ 871 41 10 = _O_O_@OO_# : len=10 : D4 00 D4
+ 872 41 11 = _O_O_@__O# : len=10 : NO 00 NO
+ 873 41 12 = _O_O_@O_O# : len=10 : NO 00 D3
+ 874 41 13 = _O_O_@_OO# : len=10 : NO 00 NO
+ 875 41 14 = _O_O_@OOO# : len=10 : NO 00 D4
+ 876 41 15 = _O_O_@____# : len=11 : NO 00 NO
+ 877 41 16 = _O_O_@O___# : len=11 : NO 00 D3
+ 878 41 17 = _O_O_@_O__# : len=11 : NO 00 NO
+ 879 41 18 = _O_O_@OO__# : len=11 : D4 00 D4
+ 880 41 19 = _O_O_@__O_# : len=11 : NO 00 NO
+ 881 41 20 = _O_O_@O_O_# : len=11 : NO 00 D3
+ 882 41 21 = _O_O_@_OO_# : len=11 : NO 00 D3
+ 883 41 22 = _O_O_@OOO_# : len=11 : S4 00 H4
+ 884 41 23 = _O_O_@___O# : len=11 : NO 00 NO
+ 885 41 24 = _O_O_@O__O# : len=11 : NO 00 D3
+ 886 41 25 = _O_O_@_O_O# : len=11 : NO 00 NO
+ 887 41 26 = _O_O_@OO_O# : len=11 : X4 00 X4
+ 888 41 27 = _O_O_@__OO# : len=11 : NO 00 NO
+ 889 41 28 = _O_O_@O_OO# : len=11 : D4 00 D4
+ 890 41 29 = _O_O_@_OOO# : len=11 : D4 00 D4
+ 891 41 30 = _O_O_@OOOO# : len=11 : L5 00 L5
+ 892 41 31 = _O_O_@_____ : len=11 : NO 00 NO
+ 893 41 32 = _O_O_@O____ : len=11 : NO 00 D3
+ 894 41 33 = _O_O_@_O___ : len=11 : NO 00 NO
+ 895 41 34 = _O_O_@OO___ : len=11 : D4 00 D4
+ 896 41 35 = _O_O_@__O__ : len=11 : NO 00 NO
+ 897 41 36 = _O_O_@O_O__ : len=11 : NO 00 D3
+ 898 41 37 = _O_O_@_OO__ : len=11 : NO 00 D3
+ 899 41 38 = _O_O_@OOO__ : len=11 : S4 00 H4
+ 900 41 39 = _O_O_@___O_ : len=11 : NO 00 NO
+ 901 41 40 = _O_O_@O__O_ : len=11 : NO 00 D3
+ 902 41 41 = _O_O_@_O_O_ : len=11 : NO 00 NO
+ 903 42 0 = _O_OO@# : len= 7 : D4 00 D4
+ 904 42 1 = _O_OO@_# : len= 8 : D4 00 D4
+ 905 42 2 = _O_OO@O# : len= 8 : NO 00 D4
+ 906 42 3 = _O_OO@__# : len= 9 : D4 00 D4
+ 907 42 4 = _O_OO@O_# : len= 9 : S4 00 H4
+ 908 42 5 = _O_OO@_O# : len= 9 : X4 00 X4
+ 909 42 6 = _O_OO@OO# : len= 9 : L5 00 L5
+ 910 42 7 = _O_OO@___# : len=10 : D4 00 D4
+ 911 42 8 = _O_OO@O__# : len=10 : S4 00 H4
+ 912 42 9 = _O_OO@_O_# : len=10 : X4 00 X4
+ 913 42 10 = _O_OO@OO_# : len=10 : L5 00 L5
+ 914 42 11 = _O_OO@__O# : len=10 : D4 00 D4
+ 915 42 12 = _O_OO@O_O# : len=10 : NO 00 H4
+ 916 42 13 = _O_OO@_OO# : len=10 : D4 00 X4
+ 917 42 14 = _O_OO@OOO# : len=10 : L6 00 L6
+ 918 42 15 = _O_OO@____# : len=11 : D4 00 D4
+ 919 42 16 = _O_OO@O___# : len=11 : S4 00 H4
+ 920 42 17 = _O_OO@_O__# : len=11 : X4 00 X4
+ 921 42 18 = _O_OO@OO__# : len=11 : L5 00 L5
+ 922 42 19 = _O_OO@__O_# : len=11 : D4 00 D4
+ 923 42 20 = _O_OO@O_O_# : len=11 : NO 00 H4
+ 924 42 21 = _O_OO@_OO_# : len=11 : D4 00 X4
+ 925 42 22 = _O_OO@OOO_# : len=11 : L6 00 L6
+ 926 42 23 = _O_OO@___O# : len=11 : D4 00 D4
+ 927 42 24 = _O_OO@O__O# : len=11 : S4 00 H4
+ 928 42 25 = _O_OO@_O_O# : len=11 : X4 00 X4
+ 929 42 26 = _O_OO@OO_O# : len=11 : L5 00 L5
+ 930 42 27 = _O_OO@__OO# : len=11 : D4 00 D4
+ 931 42 28 = _O_OO@O_OO# : len=11 : NO 00 H4
+ 932 42 29 = _O_OO@_OOO# : len=11 : D4 00 X4
+ 933 42 30 = _O_OO@OOOO# : len=11 : L6 00 L6
+ 934 42 31 = _O_OO@_____ : len=11 : D4 00 D4
+ 935 42 32 = _O_OO@O____ : len=11 : S4 00 H4
+ 936 42 33 = _O_OO@_O___ : len=11 : X4 00 X4
+ 937 42 34 = _O_OO@OO___ : len=11 : L5 00 L5
+ 938 42 35 = _O_OO@__O__ : len=11 : D4 00 D4
+ 939 42 36 = _O_OO@O_O__ : len=11 : NO 00 H4
+ 940 42 37 = _O_OO@_OO__ : len=11 : D4 00 X4
+ 941 42 38 = _O_OO@OOO__ : len=11 : L6 00 L6
+ 942 42 39 = _O_OO@___O_ : len=11 : D4 00 D4
+ 943 42 40 = _O_OO@O__O_ : len=11 : S4 00 H4
+ 944 42 41 = _O_OO@_O_O_ : len=11 : X4 00 X4
+ 945 42 42 = _O_OO@OO_O_ : len=11 : L5 00 L5
+ 946 43 0 = _OO__@# : len= 7 : NO 00 NO
+ 947 43 1 = _OO__@_# : len= 8 : NO 00 NO
+ 948 43 2 = _OO__@O# : len= 8 : NO 00 NO
+ 949 43 3 = _OO__@__# : len= 9 : NO 00 NO
+ 950 43 4 = _OO__@O_# : len= 9 : NO 00 NO
+ 951 43 5 = _OO__@_O# : len= 9 : NO 00 NO
+ 952 43 6 = _OO__@OO# : len= 9 : NO 00 NO
+ 953 43 7 = _OO__@___# : len=10 : NO 00 NO
+ 954 43 8 = _OO__@O__# : len=10 : NO 00 NO
+ 955 43 9 = _OO__@_O_# : len=10 : NO 00 NO
+ 956 43 10 = _OO__@OO_# : len=10 : NO 00 H3
+ 957 43 11 = _OO__@__O# : len=10 : NO 00 NO
+ 958 43 12 = _OO__@O_O# : len=10 : NO 00 NO
+ 959 43 13 = _OO__@_OO# : len=10 : NO 00 NO
+ 960 43 14 = _OO__@OOO# : len=10 : S4 00 S4
+ 961 43 15 = _OO__@____# : len=11 : NO 00 NO
+ 962 43 16 = _OO__@O___# : len=11 : NO 00 NO
+ 963 43 17 = _OO__@_O__# : len=11 : NO 00 NO
+ 964 43 18 = _OO__@OO__# : len=11 : H3 13 H3
+ 965 43 19 = _OO__@__O_# : len=11 : NO 00 NO
+ 966 43 20 = _OO__@O_O_# : len=11 : D3 02 D3
+ 967 43 21 = _OO__@_OO_# : len=11 : D3 01 D3
+ 968 43 22 = _OO__@OOO_# : len=11 : H4 00 H4
+ 969 43 23 = _OO__@___O# : len=11 : NO 00 NO
+ 970 43 24 = _OO__@O__O# : len=11 : NO 00 NO
+ 971 43 25 = _OO__@_O_O# : len=11 : NO 00 NO
+ 972 43 26 = _OO__@OO_O# : len=11 : D4 00 D4
+ 973 43 27 = _OO__@__OO# : len=11 : NO 00 NO
+ 974 43 28 = _OO__@O_OO# : len=11 : D4 00 D4
+ 975 43 29 = _OO__@_OOO# : len=11 : D4 00 D4
+ 976 43 30 = _OO__@OOOO# : len=11 : L5 00 L5
+ 977 43 31 = _OO__@_____ : len=11 : NO 00 NO
+ 978 43 32 = _OO__@O____ : len=11 : NO 00 NO
+ 979 43 33 = _OO__@_O___ : len=11 : NO 00 NO
+ 980 43 34 = _OO__@OO___ : len=11 : H3 13 H3
+ 981 43 35 = _OO__@__O__ : len=11 : NO 00 NO
+ 982 43 36 = _OO__@O_O__ : len=11 : D3 02 D3
+ 983 43 37 = _OO__@_OO__ : len=11 : D3 01 D3
+ 984 43 38 = _OO__@OOO__ : len=11 : H4 00 H4
+ 985 43 39 = _OO__@___O_ : len=11 : NO 00 NO
+ 986 43 40 = _OO__@O__O_ : len=11 : NO 00 NO
+ 987 43 41 = _OO__@_O_O_ : len=11 : NO 00 NO
+ 988 43 42 = _OO__@OO_O_ : len=11 : D4 00 D4
+ 989 43 43 = _OO__@__OO_ : len=11 : NO 00 NO
+ 990 44 0 = _OO_O@# : len= 7 : D4 00 D4
+ 991 44 1 = _OO_O@_# : len= 8 : D4 00 D4
+ 992 44 2 = _OO_O@O# : len= 8 : NO 00 D4
+ 993 44 3 = _OO_O@__# : len= 9 : D4 00 D4
+ 994 44 4 = _OO_O@O_# : len= 9 : NO 00 D4
+ 995 44 5 = _OO_O@_O# : len= 9 : D4 00 D4
+ 996 44 6 = _OO_O@OO# : len= 9 : NO 00 D4
+ 997 44 7 = _OO_O@___# : len=10 : D4 00 D4
+ 998 44 8 = _OO_O@O__# : len=10 : NO 00 D4
+ 999 44 9 = _OO_O@_O_# : len=10 : D4 00 D4
+ 1000 44 10 = _OO_O@OO_# : len=10 : S4 00 H4
+ 1001 44 11 = _OO_O@__O# : len=10 : D4 00 D4
+ 1002 44 12 = _OO_O@O_O# : len=10 : D4 00 X4
+ 1003 44 13 = _OO_O@_OO# : len=10 : X4 00 X4
+ 1004 44 14 = _OO_O@OOO# : len=10 : L5 00 L5
+ 1005 44 15 = _OO_O@____# : len=11 : D4 00 D4
+ 1006 44 16 = _OO_O@O___# : len=11 : NO 00 D4
+ 1007 44 17 = _OO_O@_O__# : len=11 : D4 00 D4
+ 1008 44 18 = _OO_O@OO__# : len=11 : S4 00 H4
+ 1009 44 19 = _OO_O@__O_# : len=11 : D4 00 D4
+ 1010 44 20 = _OO_O@O_O_# : len=11 : D4 00 X4
+ 1011 44 21 = _OO_O@_OO_# : len=11 : X4 00 X4
+ 1012 44 22 = _OO_O@OOO_# : len=11 : L5 00 L5
+ 1013 44 23 = _OO_O@___O# : len=11 : D4 00 D4
+ 1014 44 24 = _OO_O@O__O# : len=11 : NO 00 D4
+ 1015 44 25 = _OO_O@_O_O# : len=11 : D4 00 D4
+ 1016 44 26 = _OO_O@OO_O# : len=11 : NO 00 H4
+ 1017 44 27 = _OO_O@__OO# : len=11 : D4 00 D4
+ 1018 44 28 = _OO_O@O_OO# : len=11 : NO 00 X4
+ 1019 44 29 = _OO_O@_OOO# : len=11 : D4 00 X4
+ 1020 44 30 = _OO_O@OOOO# : len=11 : L6 00 L6
+ 1021 44 31 = _OO_O@_____ : len=11 : D4 00 D4
+ 1022 44 32 = _OO_O@O____ : len=11 : NO 00 D4
+ 1023 44 33 = _OO_O@_O___ : len=11 : D4 00 D4
+ 1024 44 34 = _OO_O@OO___ : len=11 : S4 00 H4
+ 1025 44 35 = _OO_O@__O__ : len=11 : D4 00 D4
+ 1026 44 36 = _OO_O@O_O__ : len=11 : D4 00 X4
+ 1027 44 37 = _OO_O@_OO__ : len=11 : X4 00 X4
+ 1028 44 38 = _OO_O@OOO__ : len=11 : L5 00 L5
+ 1029 44 39 = _OO_O@___O_ : len=11 : D4 00 D4
+ 1030 44 40 = _OO_O@O__O_ : len=11 : NO 00 D4
+ 1031 44 41 = _OO_O@_O_O_ : len=11 : D4 00 D4
+ 1032 44 42 = _OO_O@OO_O_ : len=11 : NO 00 H4
+ 1033 44 43 = _OO_O@__OO_ : len=11 : D4 00 D4
+ 1034 44 44 = _OO_O@O_OO_ : len=11 : NO 00 X4
+ 1035 45 0 = _OOO_@# : len= 7 : D4 00 D4
+ 1036 45 1 = _OOO_@_# : len= 8 : D4 00 D4
+ 1037 45 2 = _OOO_@O# : len= 8 : NO 00 D4
+ 1038 45 3 = _OOO_@__# : len= 9 : D4 00 D4
+ 1039 45 4 = _OOO_@O_# : len= 9 : NO 00 D4
+ 1040 45 5 = _OOO_@_O# : len= 9 : D4 00 D4
+ 1041 45 6 = _OOO_@OO# : len= 9 : NO 00 D4
+ 1042 45 7 = _OOO_@___# : len=10 : D4 00 D4
+ 1043 45 8 = _OOO_@O__# : len=10 : NO 00 D4
+ 1044 45 9 = _OOO_@_O_# : len=10 : D4 00 D4
+ 1045 45 10 = _OOO_@OO_# : len=10 : NO 00 D4
+ 1046 45 11 = _OOO_@__O# : len=10 : D4 00 D4
+ 1047 45 12 = _OOO_@O_O# : len=10 : NO 00 D4
+ 1048 45 13 = _OOO_@_OO# : len=10 : D4 00 D4
+ 1049 45 14 = _OOO_@OOO# : len=10 : NO 00 D4
+ 1050 45 15 = _OOO_@____# : len=11 : D4 00 D4
+ 1051 45 16 = _OOO_@O___# : len=11 : NO 00 D4
+ 1052 45 17 = _OOO_@_O__# : len=11 : D4 00 D4
+ 1053 45 18 = _OOO_@OO__# : len=11 : NO 00 D4
+ 1054 45 19 = _OOO_@__O_# : len=11 : D4 00 D4
+ 1055 45 20 = _OOO_@O_O_# : len=11 : NO 00 D4
+ 1056 45 21 = _OOO_@_OO_# : len=11 : D4 00 D4
+ 1057 45 22 = _OOO_@OOO_# : len=11 : S4 00 H4
+ 1058 45 23 = _OOO_@___O# : len=11 : D4 00 D4
+ 1059 45 24 = _OOO_@O__O# : len=11 : NO 00 D4
+ 1060 45 25 = _OOO_@_O_O# : len=11 : D4 00 D4
+ 1061 45 26 = _OOO_@OO_O# : len=11 : D4 00 X4
+ 1062 45 27 = _OOO_@__OO# : len=11 : D4 00 D4
+ 1063 45 28 = _OOO_@O_OO# : len=11 : D4 00 X4
+ 1064 45 29 = _OOO_@_OOO# : len=11 : X4 00 X4
+ 1065 45 30 = _OOO_@OOOO# : len=11 : L5 00 L5
+ 1066 45 31 = _OOO_@_____ : len=11 : D4 00 D4
+ 1067 45 32 = _OOO_@O____ : len=11 : NO 00 D4
+ 1068 45 33 = _OOO_@_O___ : len=11 : D4 00 D4
+ 1069 45 34 = _OOO_@OO___ : len=11 : NO 00 D4
+ 1070 45 35 = _OOO_@__O__ : len=11 : D4 00 D4
+ 1071 45 36 = _OOO_@O_O__ : len=11 : NO 00 D4
+ 1072 45 37 = _OOO_@_OO__ : len=11 : D4 00 D4
+ 1073 45 38 = _OOO_@OOO__ : len=11 : S4 00 H4
+ 1074 45 39 = _OOO_@___O_ : len=11 : D4 00 D4
+ 1075 45 40 = _OOO_@O__O_ : len=11 : NO 00 D4
+ 1076 45 41 = _OOO_@_O_O_ : len=11 : D4 00 D4
+ 1077 45 42 = _OOO_@OO_O_ : len=11 : D4 00 X4
+ 1078 45 43 = _OOO_@__OO_ : len=11 : D4 00 D4
+ 1079 45 44 = _OOO_@O_OO_ : len=11 : D4 00 X4
+ 1080 45 45 = _OOO_@_OOO_ : len=11 : X4 00 X4
+ 1081 46 0 = _OOOO@# : len= 7 : L5 00 L5
+ 1082 46 1 = _OOOO@_# : len= 8 : L5 00 L5
+ 1083 46 2 = _OOOO@O# : len= 8 : L6 00 L6
+ 1084 46 3 = _OOOO@__# : len= 9 : L5 00 L5
+ 1085 46 4 = _OOOO@O_# : len= 9 : L6 00 L6
+ 1086 46 5 = _OOOO@_O# : len= 9 : L5 00 L5
+ 1087 46 6 = _OOOO@OO# : len= 9 : L6 00 L6
+ 1088 46 7 = _OOOO@___# : len=10 : L5 00 L5
+ 1089 46 8 = _OOOO@O__# : len=10 : L6 00 L6
+ 1090 46 9 = _OOOO@_O_# : len=10 : L5 00 L5
+ 1091 46 10 = _OOOO@OO_# : len=10 : L6 00 L6
+ 1092 46 11 = _OOOO@__O# : len=10 : L5 00 L5
+ 1093 46 12 = _OOOO@O_O# : len=10 : L6 00 L6
+ 1094 46 13 = _OOOO@_OO# : len=10 : L5 00 L5
+ 1095 46 14 = _OOOO@OOO# : len=10 : L6 00 L6
+ 1096 46 15 = _OOOO@____# : len=11 : L5 00 L5
+ 1097 46 16 = _OOOO@O___# : len=11 : L6 00 L6
+ 1098 46 17 = _OOOO@_O__# : len=11 : L5 00 L5
+ 1099 46 18 = _OOOO@OO__# : len=11 : L6 00 L6
+ 1100 46 19 = _OOOO@__O_# : len=11 : L5 00 L5
+ 1101 46 20 = _OOOO@O_O_# : len=11 : L6 00 L6
+ 1102 46 21 = _OOOO@_OO_# : len=11 : L5 00 L5
+ 1103 46 22 = _OOOO@OOO_# : len=11 : L6 00 L6
+ 1104 46 23 = _OOOO@___O# : len=11 : L5 00 L5
+ 1105 46 24 = _OOOO@O__O# : len=11 : L6 00 L6
+ 1106 46 25 = _OOOO@_O_O# : len=11 : L5 00 L5
+ 1107 46 26 = _OOOO@OO_O# : len=11 : L6 00 L6
+ 1108 46 27 = _OOOO@__OO# : len=11 : L5 00 L5
+ 1109 46 28 = _OOOO@O_OO# : len=11 : L6 00 L6
+ 1110 46 29 = _OOOO@_OOO# : len=11 : L5 00 L5
+ 1111 46 30 = _OOOO@OOOO# : len=11 : L6 00 L6
+ 1112 46 31 = _OOOO@_____ : len=11 : L5 00 L5
+ 1113 46 32 = _OOOO@O____ : len=11 : L6 00 L6
+ 1114 46 33 = _OOOO@_O___ : len=11 : L5 00 L5
+ 1115 46 34 = _OOOO@OO___ : len=11 : L6 00 L6
+ 1116 46 35 = _OOOO@__O__ : len=11 : L5 00 L5
+ 1117 46 36 = _OOOO@O_O__ : len=11 : L6 00 L6
+ 1118 46 37 = _OOOO@_OO__ : len=11 : L5 00 L5
+ 1119 46 38 = _OOOO@OOO__ : len=11 : L6 00 L6
+ 1120 46 39 = _OOOO@___O_ : len=11 : L5 00 L5
+ 1121 46 40 = _OOOO@O__O_ : len=11 : L6 00 L6
+ 1122 46 41 = _OOOO@_O_O_ : len=11 : L5 00 L5
+ 1123 46 42 = _OOOO@OO_O_ : len=11 : L6 00 L6
+ 1124 46 43 = _OOOO@__OO_ : len=11 : L5 00 L5
+ 1125 46 44 = _OOOO@O_OO_ : len=11 : L6 00 L6
+ 1126 46 45 = _OOOO@_OOO_ : len=11 : L5 00 L5
+ 1127 46 46 = _OOOO@OOOO_ : len=11 : L6 00 L6
+ 1128 47 0 = O____@# : len= 7 : NO 00 NO
+ 1129 47 1 = O____@_# : len= 8 : NO 00 NO
+ 1130 47 2 = O____@O# : len= 8 : NO 00 NO
+ 1131 47 3 = O____@__# : len= 9 : NO 00 NO
+ 1132 47 4 = O____@O_# : len= 9 : NO 00 NO
+ 1133 47 5 = O____@_O# : len= 9 : NO 00 NO
+ 1134 47 6 = O____@OO# : len= 9 : NO 00 NO
+ 1135 47 7 = O____@___# : len=10 : NO 00 NO
+ 1136 47 8 = O____@O__# : len=10 : NO 00 NO
+ 1137 47 9 = O____@_O_# : len=10 : NO 00 NO
+ 1138 47 10 = O____@OO_# : len=10 : H3 13 H3
+ 1139 47 11 = O____@__O# : len=10 : NO 00 NO
+ 1140 47 12 = O____@O_O# : len=10 : NO 00 NO
+ 1141 47 13 = O____@_OO# : len=10 : NO 00 NO
+ 1142 47 14 = O____@OOO# : len=10 : S4 00 S4
+ 1143 47 15 = O____@____# : len=11 : NO 00 NO
+ 1144 47 16 = O____@O___# : len=11 : NO 00 NO
+ 1145 47 17 = O____@_O__# : len=11 : NO 00 NO
+ 1146 47 18 = O____@OO__# : len=11 : H3 13 H3
+ 1147 47 19 = O____@__O_# : len=11 : NO 00 NO
+ 1148 47 20 = O____@O_O_# : len=11 : D3 02 D3
+ 1149 47 21 = O____@_OO_# : len=11 : D3 01 D3
+ 1150 47 22 = O____@OOO_# : len=11 : H4 00 H4
+ 1151 47 23 = O____@___O# : len=11 : NO 00 NO
+ 1152 47 24 = O____@O__O# : len=11 : NO 00 NO
+ 1153 47 25 = O____@_O_O# : len=11 : NO 00 NO
+ 1154 47 26 = O____@OO_O# : len=11 : D4 00 D4
+ 1155 47 27 = O____@__OO# : len=11 : NO 00 NO
+ 1156 47 28 = O____@O_OO# : len=11 : D4 00 D4
+ 1157 47 29 = O____@_OOO# : len=11 : D4 00 D4
+ 1158 47 30 = O____@OOOO# : len=11 : L5 00 L5
+ 1159 47 31 = O____@_____ : len=11 : NO 00 NO
+ 1160 47 32 = O____@O____ : len=11 : NO 00 NO
+ 1161 47 33 = O____@_O___ : len=11 : NO 00 NO
+ 1162 47 34 = O____@OO___ : len=11 : H3 13 H3
+ 1163 47 35 = O____@__O__ : len=11 : NO 00 NO
+ 1164 47 36 = O____@O_O__ : len=11 : D3 02 D3
+ 1165 47 37 = O____@_OO__ : len=11 : D3 01 D3
+ 1166 47 38 = O____@OOO__ : len=11 : H4 00 H4
+ 1167 47 39 = O____@___O_ : len=11 : NO 00 NO
+ 1168 47 40 = O____@O__O_ : len=11 : NO 00 NO
+ 1169 47 41 = O____@_O_O_ : len=11 : NO 00 NO
+ 1170 47 42 = O____@OO_O_ : len=11 : D4 00 D4
+ 1171 47 43 = O____@__OO_ : len=11 : NO 00 NO
+ 1172 47 44 = O____@O_OO_ : len=11 : D4 00 D4
+ 1173 47 45 = O____@_OOO_ : len=11 : D4 00 D4
+ 1174 47 46 = O____@OOOO_ : len=11 : L5 00 L5
+ 1175 47 47 = O____@____O : len=11 : NO 00 NO
+ 1176 48 0 = O___O@# : len= 7 : NO 00 NO
+ 1177 48 1 = O___O@_# : len= 8 : NO 00 NO
+ 1178 48 2 = O___O@O# : len= 8 : NO 00 NO
+ 1179 48 3 = O___O@__# : len= 9 : NO 00 NO
+ 1180 48 4 = O___O@O_# : len= 9 : H3 22 H3
+ 1181 48 5 = O___O@_O# : len= 9 : NO 00 NO
+ 1182 48 6 = O___O@OO# : len= 9 : S4 00 S4
+ 1183 48 7 = O___O@___# : len=10 : NO 00 NO
+ 1184 48 8 = O___O@O__# : len=10 : H3 22 H3
+ 1185 48 9 = O___O@_O_# : len=10 : D3 01 D3
+ 1186 48 10 = O___O@OO_# : len=10 : H4 00 H4
+ 1187 48 11 = O___O@__O# : len=10 : NO 00 NO
+ 1188 48 12 = O___O@O_O# : len=10 : D4 00 D4
+ 1189 48 13 = O___O@_OO# : len=10 : D4 00 D4
+ 1190 48 14 = O___O@OOO# : len=10 : L5 00 L5
+ 1191 48 15 = O___O@____# : len=11 : NO 00 NO
+ 1192 48 16 = O___O@O___# : len=11 : H3 22 H3
+ 1193 48 17 = O___O@_O__# : len=11 : D3 01 D3
+ 1194 48 18 = O___O@OO__# : len=11 : H4 00 H4
+ 1195 48 19 = O___O@__O_# : len=11 : NO 00 NO
+ 1196 48 20 = O___O@O_O_# : len=11 : D4 00 D4
+ 1197 48 21 = O___O@_OO_# : len=11 : D4 00 D4
+ 1198 48 22 = O___O@OOO_# : len=11 : L5 00 L5
+ 1199 48 23 = O___O@___O# : len=11 : NO 00 NO
+ 1200 48 24 = O___O@O__O# : len=11 : H3 22 H3
+ 1201 48 25 = O___O@_O_O# : len=11 : NO 00 D3
+ 1202 48 26 = O___O@OO_O# : len=11 : S4 00 H4
+ 1203 48 27 = O___O@__OO# : len=11 : NO 00 NO
+ 1204 48 28 = O___O@O_OO# : len=11 : NO 00 D4
+ 1205 48 29 = O___O@_OOO# : len=11 : NO 00 D4
+ 1206 48 30 = O___O@OOOO# : len=11 : L6 00 L6
+ 1207 48 31 = O___O@_____ : len=11 : NO 00 NO
+ 1208 48 32 = O___O@O____ : len=11 : H3 22 H3
+ 1209 48 33 = O___O@_O___ : len=11 : D3 01 D3
+ 1210 48 34 = O___O@OO___ : len=11 : H4 00 H4
+ 1211 48 35 = O___O@__O__ : len=11 : NO 00 NO
+ 1212 48 36 = O___O@O_O__ : len=11 : D4 00 D4
+ 1213 48 37 = O___O@_OO__ : len=11 : D4 00 D4
+ 1214 48 38 = O___O@OOO__ : len=11 : L5 00 L5
+ 1215 48 39 = O___O@___O_ : len=11 : NO 00 NO
+ 1216 48 40 = O___O@O__O_ : len=11 : H3 22 H3
+ 1217 48 41 = O___O@_O_O_ : len=11 : NO 00 D3
+ 1218 48 42 = O___O@OO_O_ : len=11 : S4 00 H4
+ 1219 48 43 = O___O@__OO_ : len=11 : NO 00 NO
+ 1220 48 44 = O___O@O_OO_ : len=11 : NO 00 D4
+ 1221 48 45 = O___O@_OOO_ : len=11 : NO 00 D4
+ 1222 48 46 = O___O@OOOO_ : len=11 : L6 00 L6
+ 1223 48 47 = O___O@____O : len=11 : NO 00 NO
+ 1224 48 48 = O___O@O___O : len=11 : H3 22 H3
+ 1225 49 0 = O__O_@# : len= 7 : NO 00 NO
+ 1226 49 1 = O__O_@_# : len= 8 : NO 00 NO
+ 1227 49 2 = O__O_@O# : len= 8 : NO 00 NO
+ 1228 49 3 = O__O_@__# : len= 9 : NO 00 NO
+ 1229 49 4 = O__O_@O_# : len= 9 : D3 10 D3
+ 1230 49 5 = O__O_@_O# : len= 9 : NO 00 NO
+ 1231 49 6 = O__O_@OO# : len= 9 : D4 00 D4
+ 1232 49 7 = O__O_@___# : len=10 : NO 00 NO
+ 1233 49 8 = O__O_@O__# : len=10 : D3 10 D3
+ 1234 49 9 = O__O_@_O_# : len=10 : NO 00 NO
+ 1235 49 10 = O__O_@OO_# : len=10 : D4 00 D4
+ 1236 49 11 = O__O_@__O# : len=10 : NO 00 NO
+ 1237 49 12 = O__O_@O_O# : len=10 : NO 00 D3
+ 1238 49 13 = O__O_@_OO# : len=10 : NO 00 NO
+ 1239 49 14 = O__O_@OOO# : len=10 : NO 00 D4
+ 1240 49 15 = O__O_@____# : len=11 : NO 00 NO
+ 1241 49 16 = O__O_@O___# : len=11 : D3 10 D3
+ 1242 49 17 = O__O_@_O__# : len=11 : NO 00 NO
+ 1243 49 18 = O__O_@OO__# : len=11 : D4 00 D4
+ 1244 49 19 = O__O_@__O_# : len=11 : NO 00 NO
+ 1245 49 20 = O__O_@O_O_# : len=11 : NO 00 D3
+ 1246 49 21 = O__O_@_OO_# : len=11 : NO 00 D3
+ 1247 49 22 = O__O_@OOO_# : len=11 : S4 00 H4
+ 1248 49 23 = O__O_@___O# : len=11 : NO 00 NO
+ 1249 49 24 = O__O_@O__O# : len=11 : D3 10 D3
+ 1250 49 25 = O__O_@_O_O# : len=11 : NO 00 NO
+ 1251 49 26 = O__O_@OO_O# : len=11 : X4 00 X4
+ 1252 49 27 = O__O_@__OO# : len=11 : NO 00 NO
+ 1253 49 28 = O__O_@O_OO# : len=11 : D4 00 D4
+ 1254 49 29 = O__O_@_OOO# : len=11 : D4 00 D4
+ 1255 49 30 = O__O_@OOOO# : len=11 : L5 00 L5
+ 1256 49 31 = O__O_@_____ : len=11 : NO 00 NO
+ 1257 49 32 = O__O_@O____ : len=11 : D3 10 D3
+ 1258 49 33 = O__O_@_O___ : len=11 : NO 00 NO
+ 1259 49 34 = O__O_@OO___ : len=11 : D4 00 D4
+ 1260 49 35 = O__O_@__O__ : len=11 : NO 00 NO
+ 1261 49 36 = O__O_@O_O__ : len=11 : NO 00 D3
+ 1262 49 37 = O__O_@_OO__ : len=11 : NO 00 D3
+ 1263 49 38 = O__O_@OOO__ : len=11 : S4 00 H4
+ 1264 49 39 = O__O_@___O_ : len=11 : NO 00 NO
+ 1265 49 40 = O__O_@O__O_ : len=11 : D3 10 D3
+ 1266 49 41 = O__O_@_O_O_ : len=11 : NO 00 NO
+ 1267 49 42 = O__O_@OO_O_ : len=11 : X4 00 X4
+ 1268 49 43 = O__O_@__OO_ : len=11 : NO 00 NO
+ 1269 49 44 = O__O_@O_OO_ : len=11 : D4 00 D4
+ 1270 49 45 = O__O_@_OOO_ : len=11 : D4 00 D4
+ 1271 49 46 = O__O_@OOOO_ : len=11 : L5 00 L5
+ 1272 49 47 = O__O_@____O : len=11 : NO 00 NO
+ 1273 49 48 = O__O_@O___O : len=11 : D3 10 D3
+ 1274 49 49 = O__O_@_O__O : len=11 : NO 00 NO
+ 1275 50 0 = O__OO@# : len= 7 : NO 00 NO
+ 1276 50 1 = O__OO@_# : len= 8 : NO 00 H3
+ 1277 50 2 = O__OO@O# : len= 8 : S4 00 S4
+ 1278 50 3 = O__OO@__# : len= 9 : H3 31 H3
+ 1279 50 4 = O__OO@O_# : len= 9 : H4 00 H4
+ 1280 50 5 = O__OO@_O# : len= 9 : D4 00 D4
+ 1281 50 6 = O__OO@OO# : len= 9 : L5 00 L5
+ 1282 50 7 = O__OO@___# : len=10 : H3 31 H3
+ 1283 50 8 = O__OO@O__# : len=10 : H4 00 H4
+ 1284 50 9 = O__OO@_O_# : len=10 : D4 00 D4
+ 1285 50 10 = O__OO@OO_# : len=10 : L5 00 L5
+ 1286 50 11 = O__OO@__O# : len=10 : NO 00 H3
+ 1287 50 12 = O__OO@O_O# : len=10 : S4 00 H4
+ 1288 50 13 = O__OO@_OO# : len=10 : NO 00 D4
+ 1289 50 14 = O__OO@OOO# : len=10 : L6 00 L6
+ 1290 50 15 = O__OO@____# : len=11 : H3 31 H3
+ 1291 50 16 = O__OO@O___# : len=11 : H4 00 H4
+ 1292 50 17 = O__OO@_O__# : len=11 : D4 00 D4
+ 1293 50 18 = O__OO@OO__# : len=11 : L5 00 L5
+ 1294 50 19 = O__OO@__O_# : len=11 : NO 00 H3
+ 1295 50 20 = O__OO@O_O_# : len=11 : S4 00 H4
+ 1296 50 21 = O__OO@_OO_# : len=11 : NO 00 D4
+ 1297 50 22 = O__OO@OOO_# : len=11 : L6 00 L6
+ 1298 50 23 = O__OO@___O# : len=11 : H3 31 H3
+ 1299 50 24 = O__OO@O__O# : len=11 : H4 00 H4
+ 1300 50 25 = O__OO@_O_O# : len=11 : D4 00 D4
+ 1301 50 26 = O__OO@OO_O# : len=11 : L5 00 L5
+ 1302 50 27 = O__OO@__OO# : len=11 : NO 00 H3
+ 1303 50 28 = O__OO@O_OO# : len=11 : S4 00 H4
+ 1304 50 29 = O__OO@_OOO# : len=11 : NO 00 D4
+ 1305 50 30 = O__OO@OOOO# : len=11 : L6 00 L6
+ 1306 50 31 = O__OO@_____ : len=11 : H3 31 H3
+ 1307 50 32 = O__OO@O____ : len=11 : H4 00 H4
+ 1308 50 33 = O__OO@_O___ : len=11 : D4 00 D4
+ 1309 50 34 = O__OO@OO___ : len=11 : L5 00 L5
+ 1310 50 35 = O__OO@__O__ : len=11 : NO 00 H3
+ 1311 50 36 = O__OO@O_O__ : len=11 : S4 00 H4
+ 1312 50 37 = O__OO@_OO__ : len=11 : NO 00 D4
+ 1313 50 38 = O__OO@OOO__ : len=11 : L6 00 L6
+ 1314 50 39 = O__OO@___O_ : len=11 : H3 31 H3
+ 1315 50 40 = O__OO@O__O_ : len=11 : H4 00 H4
+ 1316 50 41 = O__OO@_O_O_ : len=11 : D4 00 D4
+ 1317 50 42 = O__OO@OO_O_ : len=11 : L5 00 L5
+ 1318 50 43 = O__OO@__OO_ : len=11 : NO 00 H3
+ 1319 50 44 = O__OO@O_OO_ : len=11 : S4 00 H4
+ 1320 50 45 = O__OO@_OOO_ : len=11 : NO 00 D4
+ 1321 50 46 = O__OO@OOOO_ : len=11 : L6 00 L6
+ 1322 50 47 = O__OO@____O : len=11 : H3 31 H3
+ 1323 50 48 = O__OO@O___O : len=11 : H4 00 H4
+ 1324 50 49 = O__OO@_O__O : len=11 : D4 00 D4
+ 1325 50 50 = O__OO@OO__O : len=11 : L5 00 L5
+ 1326 51 0 = O_O__@# : len= 7 : NO 00 NO
+ 1327 51 1 = O_O__@_# : len= 8 : NO 00 NO
+ 1328 51 2 = O_O__@O# : len= 8 : NO 00 NO
+ 1329 51 3 = O_O__@__# : len= 9 : NO 00 NO
+ 1330 51 4 = O_O__@O_# : len= 9 : NO 00 NO
+ 1331 51 5 = O_O__@_O# : len= 9 : NO 00 NO
+ 1332 51 6 = O_O__@OO# : len= 9 : NO 00 NO
+ 1333 51 7 = O_O__@___# : len=10 : NO 00 NO
+ 1334 51 8 = O_O__@O__# : len=10 : NO 00 NO
+ 1335 51 9 = O_O__@_O_# : len=10 : NO 00 NO
+ 1336 51 10 = O_O__@OO_# : len=10 : NO 00 H3
+ 1337 51 11 = O_O__@__O# : len=10 : NO 00 NO
+ 1338 51 12 = O_O__@O_O# : len=10 : NO 00 NO
+ 1339 51 13 = O_O__@_OO# : len=10 : NO 00 NO
+ 1340 51 14 = O_O__@OOO# : len=10 : S4 00 S4
+ 1341 51 15 = O_O__@____# : len=11 : NO 00 NO
+ 1342 51 16 = O_O__@O___# : len=11 : NO 00 NO
+ 1343 51 17 = O_O__@_O__# : len=11 : NO 00 NO
+ 1344 51 18 = O_O__@OO__# : len=11 : H3 13 H3
+ 1345 51 19 = O_O__@__O_# : len=11 : NO 00 NO
+ 1346 51 20 = O_O__@O_O_# : len=11 : D3 02 D3
+ 1347 51 21 = O_O__@_OO_# : len=11 : D3 01 D3
+ 1348 51 22 = O_O__@OOO_# : len=11 : H4 00 H4
+ 1349 51 23 = O_O__@___O# : len=11 : NO 00 NO
+ 1350 51 24 = O_O__@O__O# : len=11 : NO 00 NO
+ 1351 51 25 = O_O__@_O_O# : len=11 : NO 00 NO
+ 1352 51 26 = O_O__@OO_O# : len=11 : D4 00 D4
+ 1353 51 27 = O_O__@__OO# : len=11 : NO 00 NO
+ 1354 51 28 = O_O__@O_OO# : len=11 : D4 00 D4
+ 1355 51 29 = O_O__@_OOO# : len=11 : D4 00 D4
+ 1356 51 30 = O_O__@OOOO# : len=11 : L5 00 L5
+ 1357 51 31 = O_O__@_____ : len=11 : NO 00 NO
+ 1358 51 32 = O_O__@O____ : len=11 : NO 00 NO
+ 1359 51 33 = O_O__@_O___ : len=11 : NO 00 NO
+ 1360 51 34 = O_O__@OO___ : len=11 : H3 13 H3
+ 1361 51 35 = O_O__@__O__ : len=11 : NO 00 NO
+ 1362 51 36 = O_O__@O_O__ : len=11 : D3 02 D3
+ 1363 51 37 = O_O__@_OO__ : len=11 : D3 01 D3
+ 1364 51 38 = O_O__@OOO__ : len=11 : H4 00 H4
+ 1365 51 39 = O_O__@___O_ : len=11 : NO 00 NO
+ 1366 51 40 = O_O__@O__O_ : len=11 : NO 00 NO
+ 1367 51 41 = O_O__@_O_O_ : len=11 : NO 00 NO
+ 1368 51 42 = O_O__@OO_O_ : len=11 : D4 00 D4
+ 1369 51 43 = O_O__@__OO_ : len=11 : NO 00 NO
+ 1370 51 44 = O_O__@O_OO_ : len=11 : D4 00 D4
+ 1371 51 45 = O_O__@_OOO_ : len=11 : D4 00 D4
+ 1372 51 46 = O_O__@OOOO_ : len=11 : L5 00 L5
+ 1373 51 47 = O_O__@____O : len=11 : NO 00 NO
+ 1374 51 48 = O_O__@O___O : len=11 : NO 00 NO
+ 1375 51 49 = O_O__@_O__O : len=11 : NO 00 NO
+ 1376 51 50 = O_O__@OO__O : len=11 : NO 00 H3
+ 1377 51 51 = O_O__@__O_O : len=11 : NO 00 NO
+ 1378 52 0 = O_O_O@# : len= 7 : NO 00 NO
+ 1379 52 1 = O_O_O@_# : len= 8 : NO 00 D3
+ 1380 52 2 = O_O_O@O# : len= 8 : D4 00 D4
+ 1381 52 3 = O_O_O@__# : len= 9 : NO 00 D3
+ 1382 52 4 = O_O_O@O_# : len= 9 : D4 00 D4
+ 1383 52 5 = O_O_O@_O# : len= 9 : NO 00 D3
+ 1384 52 6 = O_O_O@OO# : len= 9 : NO 00 D4
+ 1385 52 7 = O_O_O@___# : len=10 : NO 00 D3
+ 1386 52 8 = O_O_O@O__# : len=10 : D4 00 D4
+ 1387 52 9 = O_O_O@_O_# : len=10 : NO 00 D3
+ 1388 52 10 = O_O_O@OO_# : len=10 : S4 00 H4
+ 1389 52 11 = O_O_O@__O# : len=10 : NO 00 D3
+ 1390 52 12 = O_O_O@O_O# : len=10 : X4 00 X4
+ 1391 52 13 = O_O_O@_OO# : len=10 : D4 00 D4
+ 1392 52 14 = O_O_O@OOO# : len=10 : L5 00 L5
+ 1393 52 15 = O_O_O@____# : len=11 : NO 00 D3
+ 1394 52 16 = O_O_O@O___# : len=11 : D4 00 D4
+ 1395 52 17 = O_O_O@_O__# : len=11 : NO 00 D3
+ 1396 52 18 = O_O_O@OO__# : len=11 : S4 00 H4
+ 1397 52 19 = O_O_O@__O_# : len=11 : NO 00 D3
+ 1398 52 20 = O_O_O@O_O_# : len=11 : X4 00 X4
+ 1399 52 21 = O_O_O@_OO_# : len=11 : D4 00 D4
+ 1400 52 22 = O_O_O@OOO_# : len=11 : L5 00 L5
+ 1401 52 23 = O_O_O@___O# : len=11 : NO 00 D3
+ 1402 52 24 = O_O_O@O__O# : len=11 : D4 00 D4
+ 1403 52 25 = O_O_O@_O_O# : len=11 : NO 00 D3
+ 1404 52 26 = O_O_O@OO_O# : len=11 : NO 00 H4
+ 1405 52 27 = O_O_O@__OO# : len=11 : NO 00 D3
+ 1406 52 28 = O_O_O@O_OO# : len=11 : D4 00 X4
+ 1407 52 29 = O_O_O@_OOO# : len=11 : NO 00 D4
+ 1408 52 30 = O_O_O@OOOO# : len=11 : L6 00 L6
+ 1409 52 31 = O_O_O@_____ : len=11 : NO 00 D3
+ 1410 52 32 = O_O_O@O____ : len=11 : D4 00 D4
+ 1411 52 33 = O_O_O@_O___ : len=11 : NO 00 D3
+ 1412 52 34 = O_O_O@OO___ : len=11 : S4 00 H4
+ 1413 52 35 = O_O_O@__O__ : len=11 : NO 00 D3
+ 1414 52 36 = O_O_O@O_O__ : len=11 : X4 00 X4
+ 1415 52 37 = O_O_O@_OO__ : len=11 : D4 00 D4
+ 1416 52 38 = O_O_O@OOO__ : len=11 : L5 00 L5
+ 1417 52 39 = O_O_O@___O_ : len=11 : NO 00 D3
+ 1418 52 40 = O_O_O@O__O_ : len=11 : D4 00 D4
+ 1419 52 41 = O_O_O@_O_O_ : len=11 : NO 00 D3
+ 1420 52 42 = O_O_O@OO_O_ : len=11 : NO 00 H4
+ 1421 52 43 = O_O_O@__OO_ : len=11 : NO 00 D3
+ 1422 52 44 = O_O_O@O_OO_ : len=11 : D4 00 X4
+ 1423 52 45 = O_O_O@_OOO_ : len=11 : NO 00 D4
+ 1424 52 46 = O_O_O@OOOO_ : len=11 : L6 00 L6
+ 1425 52 47 = O_O_O@____O : len=11 : NO 00 D3
+ 1426 52 48 = O_O_O@O___O : len=11 : D4 00 D4
+ 1427 52 49 = O_O_O@_O__O : len=11 : NO 00 D3
+ 1428 52 50 = O_O_O@OO__O : len=11 : S4 00 H4
+ 1429 52 51 = O_O_O@__O_O : len=11 : NO 00 D3
+ 1430 52 52 = O_O_O@O_O_O : len=11 : X4 00 X4
+ 1431 53 0 = O_OO_@# : len= 7 : NO 00 NO
+ 1432 53 1 = O_OO_@_# : len= 8 : NO 00 D3
+ 1433 53 2 = O_OO_@O# : len= 8 : D4 00 D4
+ 1434 53 3 = O_OO_@__# : len= 9 : NO 00 D3
+ 1435 53 4 = O_OO_@O_# : len= 9 : D4 00 D4
+ 1436 53 5 = O_OO_@_O# : len= 9 : NO 00 D3
+ 1437 53 6 = O_OO_@OO# : len= 9 : NO 00 D4
+ 1438 53 7 = O_OO_@___# : len=10 : NO 00 D3
+ 1439 53 8 = O_OO_@O__# : len=10 : D4 00 D4
+ 1440 53 9 = O_OO_@_O_# : len=10 : NO 00 D3
+ 1441 53 10 = O_OO_@OO_# : len=10 : NO 00 D4
+ 1442 53 11 = O_OO_@__O# : len=10 : NO 00 D3
+ 1443 53 12 = O_OO_@O_O# : len=10 : D4 00 D4
+ 1444 53 13 = O_OO_@_OO# : len=10 : NO 00 D3
+ 1445 53 14 = O_OO_@OOO# : len=10 : NO 00 D4
+ 1446 53 15 = O_OO_@____# : len=11 : NO 00 D3
+ 1447 53 16 = O_OO_@O___# : len=11 : D4 00 D4
+ 1448 53 17 = O_OO_@_O__# : len=11 : NO 00 D3
+ 1449 53 18 = O_OO_@OO__# : len=11 : NO 00 D4
+ 1450 53 19 = O_OO_@__O_# : len=11 : NO 00 D3
+ 1451 53 20 = O_OO_@O_O_# : len=11 : D4 00 D4
+ 1452 53 21 = O_OO_@_OO_# : len=11 : NO 00 D3
+ 1453 53 22 = O_OO_@OOO_# : len=11 : S4 00 H4
+ 1454 53 23 = O_OO_@___O# : len=11 : NO 00 D3
+ 1455 53 24 = O_OO_@O__O# : len=11 : D4 00 D4
+ 1456 53 25 = O_OO_@_O_O# : len=11 : NO 00 D3
+ 1457 53 26 = O_OO_@OO_O# : len=11 : D4 00 X4
+ 1458 53 27 = O_OO_@__OO# : len=11 : NO 00 D3
+ 1459 53 28 = O_OO_@O_OO# : len=11 : X4 00 X4
+ 1460 53 29 = O_OO_@_OOO# : len=11 : D4 00 D4
+ 1461 53 30 = O_OO_@OOOO# : len=11 : L5 00 L5
+ 1462 53 31 = O_OO_@_____ : len=11 : NO 00 D3
+ 1463 53 32 = O_OO_@O____ : len=11 : D4 00 D4
+ 1464 53 33 = O_OO_@_O___ : len=11 : NO 00 D3
+ 1465 53 34 = O_OO_@OO___ : len=11 : NO 00 D4
+ 1466 53 35 = O_OO_@__O__ : len=11 : NO 00 D3
+ 1467 53 36 = O_OO_@O_O__ : len=11 : D4 00 D4
+ 1468 53 37 = O_OO_@_OO__ : len=11 : NO 00 D3
+ 1469 53 38 = O_OO_@OOO__ : len=11 : S4 00 H4
+ 1470 53 39 = O_OO_@___O_ : len=11 : NO 00 D3
+ 1471 53 40 = O_OO_@O__O_ : len=11 : D4 00 D4
+ 1472 53 41 = O_OO_@_O_O_ : len=11 : NO 00 D3
+ 1473 53 42 = O_OO_@OO_O_ : len=11 : D4 00 X4
+ 1474 53 43 = O_OO_@__OO_ : len=11 : NO 00 D3
+ 1475 53 44 = O_OO_@O_OO_ : len=11 : X4 00 X4
+ 1476 53 45 = O_OO_@_OOO_ : len=11 : D4 00 D4
+ 1477 53 46 = O_OO_@OOOO_ : len=11 : L5 00 L5
+ 1478 53 47 = O_OO_@____O : len=11 : NO 00 D3
+ 1479 53 48 = O_OO_@O___O : len=11 : D4 00 D4
+ 1480 53 49 = O_OO_@_O__O : len=11 : NO 00 D3
+ 1481 53 50 = O_OO_@OO__O : len=11 : NO 00 D4
+ 1482 53 51 = O_OO_@__O_O : len=11 : NO 00 D3
+ 1483 53 52 = O_OO_@O_O_O : len=11 : D4 00 D4
+ 1484 53 53 = O_OO_@_OO_O : len=11 : NO 00 D3
+ 1485 54 0 = O_OOO@# : len= 7 : NO 00 D4
+ 1486 54 1 = O_OOO@_# : len= 8 : S4 00 H4
+ 1487 54 2 = O_OOO@O# : len= 8 : L5 00 L5
+ 1488 54 3 = O_OOO@__# : len= 9 : S4 00 H4
+ 1489 54 4 = O_OOO@O_# : len= 9 : L5 00 L5
+ 1490 54 5 = O_OOO@_O# : len= 9 : NO 00 H4
+ 1491 54 6 = O_OOO@OO# : len= 9 : L6 00 L6
+ 1492 54 7 = O_OOO@___# : len=10 : S4 00 H4
+ 1493 54 8 = O_OOO@O__# : len=10 : L5 00 L5
+ 1494 54 9 = O_OOO@_O_# : len=10 : NO 00 H4
+ 1495 54 10 = O_OOO@OO_# : len=10 : L6 00 L6
+ 1496 54 11 = O_OOO@__O# : len=10 : S4 00 H4
+ 1497 54 12 = O_OOO@O_O# : len=10 : L5 00 L5
+ 1498 54 13 = O_OOO@_OO# : len=10 : NO 00 H4
+ 1499 54 14 = O_OOO@OOO# : len=10 : L6 00 L6
+ 1500 54 15 = O_OOO@____# : len=11 : S4 00 H4
+ 1501 54 16 = O_OOO@O___# : len=11 : L5 00 L5
+ 1502 54 17 = O_OOO@_O__# : len=11 : NO 00 H4
+ 1503 54 18 = O_OOO@OO__# : len=11 : L6 00 L6
+ 1504 54 19 = O_OOO@__O_# : len=11 : S4 00 H4
+ 1505 54 20 = O_OOO@O_O_# : len=11 : L5 00 L5
+ 1506 54 21 = O_OOO@_OO_# : len=11 : NO 00 H4
+ 1507 54 22 = O_OOO@OOO_# : len=11 : L6 00 L6
+ 1508 54 23 = O_OOO@___O# : len=11 : S4 00 H4
+ 1509 54 24 = O_OOO@O__O# : len=11 : L5 00 L5
+ 1510 54 25 = O_OOO@_O_O# : len=11 : NO 00 H4
+ 1511 54 26 = O_OOO@OO_O# : len=11 : L6 00 L6
+ 1512 54 27 = O_OOO@__OO# : len=11 : S4 00 H4
+ 1513 54 28 = O_OOO@O_OO# : len=11 : L5 00 L5
+ 1514 54 29 = O_OOO@_OOO# : len=11 : NO 00 H4
+ 1515 54 30 = O_OOO@OOOO# : len=11 : L6 00 L6
+ 1516 54 31 = O_OOO@_____ : len=11 : S4 00 H4
+ 1517 54 32 = O_OOO@O____ : len=11 : L5 00 L5
+ 1518 54 33 = O_OOO@_O___ : len=11 : NO 00 H4
+ 1519 54 34 = O_OOO@OO___ : len=11 : L6 00 L6
+ 1520 54 35 = O_OOO@__O__ : len=11 : S4 00 H4
+ 1521 54 36 = O_OOO@O_O__ : len=11 : L5 00 L5
+ 1522 54 37 = O_OOO@_OO__ : len=11 : NO 00 H4
+ 1523 54 38 = O_OOO@OOO__ : len=11 : L6 00 L6
+ 1524 54 39 = O_OOO@___O_ : len=11 : S4 00 H4
+ 1525 54 40 = O_OOO@O__O_ : len=11 : L5 00 L5
+ 1526 54 41 = O_OOO@_O_O_ : len=11 : NO 00 H4
+ 1527 54 42 = O_OOO@OO_O_ : len=11 : L6 00 L6
+ 1528 54 43 = O_OOO@__OO_ : len=11 : S4 00 H4
+ 1529 54 44 = O_OOO@O_OO_ : len=11 : L5 00 L5
+ 1530 54 45 = O_OOO@_OOO_ : len=11 : NO 00 H4
+ 1531 54 46 = O_OOO@OOOO_ : len=11 : L6 00 L6
+ 1532 54 47 = O_OOO@____O : len=11 : S4 00 H4
+ 1533 54 48 = O_OOO@O___O : len=11 : L5 00 L5
+ 1534 54 49 = O_OOO@_O__O : len=11 : NO 00 H4
+ 1535 54 50 = O_OOO@OO__O : len=11 : L6 00 L6
+ 1536 54 51 = O_OOO@__O_O : len=11 : S4 00 H4
+ 1537 54 52 = O_OOO@O_O_O : len=11 : L5 00 L5
+ 1538 54 53 = O_OOO@_OO_O : len=11 : NO 00 H4
+ 1539 54 54 = O_OOO@OOO_O : len=11 : L6 00 L6
+ 1540 55 0 = OO___@# : len= 7 : NO 00 NO
+ 1541 55 1 = OO___@_# : len= 8 : NO 00 NO
+ 1542 55 2 = OO___@O# : len= 8 : NO 00 NO
+ 1543 55 3 = OO___@__# : len= 9 : NO 00 NO
+ 1544 55 4 = OO___@O_# : len= 9 : NO 00 NO
+ 1545 55 5 = OO___@_O# : len= 9 : NO 00 NO
+ 1546 55 6 = OO___@OO# : len= 9 : NO 00 NO
+ 1547 55 7 = OO___@___# : len=10 : NO 00 NO
+ 1548 55 8 = OO___@O__# : len=10 : NO 00 NO
+ 1549 55 9 = OO___@_O_# : len=10 : NO 00 NO
+ 1550 55 10 = OO___@OO_# : len=10 : H3 13 H3
+ 1551 55 11 = OO___@__O# : len=10 : NO 00 NO
+ 1552 55 12 = OO___@O_O# : len=10 : NO 00 NO
+ 1553 55 13 = OO___@_OO# : len=10 : NO 00 NO
+ 1554 55 14 = OO___@OOO# : len=10 : S4 00 S4
+ 1555 55 15 = OO___@____# : len=11 : NO 00 NO
+ 1556 55 16 = OO___@O___# : len=11 : NO 00 NO
+ 1557 55 17 = OO___@_O__# : len=11 : NO 00 NO
+ 1558 55 18 = OO___@OO__# : len=11 : H3 13 H3
+ 1559 55 19 = OO___@__O_# : len=11 : NO 00 NO
+ 1560 55 20 = OO___@O_O_# : len=11 : D3 02 D3
+ 1561 55 21 = OO___@_OO_# : len=11 : D3 01 D3
+ 1562 55 22 = OO___@OOO_# : len=11 : H4 00 H4
+ 1563 55 23 = OO___@___O# : len=11 : NO 00 NO
+ 1564 55 24 = OO___@O__O# : len=11 : NO 00 NO
+ 1565 55 25 = OO___@_O_O# : len=11 : NO 00 NO
+ 1566 55 26 = OO___@OO_O# : len=11 : D4 00 D4
+ 1567 55 27 = OO___@__OO# : len=11 : NO 00 NO
+ 1568 55 28 = OO___@O_OO# : len=11 : D4 00 D4
+ 1569 55 29 = OO___@_OOO# : len=11 : D4 00 D4
+ 1570 55 30 = OO___@OOOO# : len=11 : L5 00 L5
+ 1571 55 31 = OO___@_____ : len=11 : NO 00 NO
+ 1572 55 32 = OO___@O____ : len=11 : NO 00 NO
+ 1573 55 33 = OO___@_O___ : len=11 : NO 00 NO
+ 1574 55 34 = OO___@OO___ : len=11 : H3 13 H3
+ 1575 55 35 = OO___@__O__ : len=11 : NO 00 NO
+ 1576 55 36 = OO___@O_O__ : len=11 : D3 02 D3
+ 1577 55 37 = OO___@_OO__ : len=11 : D3 01 D3
+ 1578 55 38 = OO___@OOO__ : len=11 : H4 00 H4
+ 1579 55 39 = OO___@___O_ : len=11 : NO 00 NO
+ 1580 55 40 = OO___@O__O_ : len=11 : NO 00 NO
+ 1581 55 41 = OO___@_O_O_ : len=11 : NO 00 NO
+ 1582 55 42 = OO___@OO_O_ : len=11 : D4 00 D4
+ 1583 55 43 = OO___@__OO_ : len=11 : NO 00 NO
+ 1584 55 44 = OO___@O_OO_ : len=11 : D4 00 D4
+ 1585 55 45 = OO___@_OOO_ : len=11 : D4 00 D4
+ 1586 55 46 = OO___@OOOO_ : len=11 : L5 00 L5
+ 1587 55 47 = OO___@____O : len=11 : NO 00 NO
+ 1588 55 48 = OO___@O___O : len=11 : NO 00 NO
+ 1589 55 49 = OO___@_O__O : len=11 : NO 00 NO
+ 1590 55 50 = OO___@OO__O : len=11 : H3 13 H3
+ 1591 55 51 = OO___@__O_O : len=11 : NO 00 NO
+ 1592 55 52 = OO___@O_O_O : len=11 : NO 00 D3
+ 1593 55 53 = OO___@_OO_O : len=11 : NO 00 D3
+ 1594 55 54 = OO___@OOO_O : len=11 : S4 00 H4
+ 1595 55 55 = OO___@___OO : len=11 : NO 00 NO
+ 1596 56 0 = OO__O@# : len= 7 : NO 00 NO
+ 1597 56 1 = OO__O@_# : len= 8 : NO 00 NO
+ 1598 56 2 = OO__O@O# : len= 8 : NO 00 NO
+ 1599 56 3 = OO__O@__# : len= 9 : NO 00 NO
+ 1600 56 4 = OO__O@O_# : len= 9 : NO 00 H3
+ 1601 56 5 = OO__O@_O# : len= 9 : NO 00 NO
+ 1602 56 6 = OO__O@OO# : len= 9 : S4 00 S4
+ 1603 56 7 = OO__O@___# : len=10 : NO 00 NO
+ 1604 56 8 = OO__O@O__# : len=10 : H3 22 H3
+ 1605 56 9 = OO__O@_O_# : len=10 : D3 01 D3
+ 1606 56 10 = OO__O@OO_# : len=10 : H4 00 H4
+ 1607 56 11 = OO__O@__O# : len=10 : NO 00 NO
+ 1608 56 12 = OO__O@O_O# : len=10 : D4 00 D4
+ 1609 56 13 = OO__O@_OO# : len=10 : D4 00 D4
+ 1610 56 14 = OO__O@OOO# : len=10 : L5 00 L5
+ 1611 56 15 = OO__O@____# : len=11 : NO 00 NO
+ 1612 56 16 = OO__O@O___# : len=11 : H3 22 H3
+ 1613 56 17 = OO__O@_O__# : len=11 : D3 01 D3
+ 1614 56 18 = OO__O@OO__# : len=11 : H4 00 H4
+ 1615 56 19 = OO__O@__O_# : len=11 : NO 00 NO
+ 1616 56 20 = OO__O@O_O_# : len=11 : D4 00 D4
+ 1617 56 21 = OO__O@_OO_# : len=11 : D4 00 D4
+ 1618 56 22 = OO__O@OOO_# : len=11 : L5 00 L5
+ 1619 56 23 = OO__O@___O# : len=11 : NO 00 NO
+ 1620 56 24 = OO__O@O__O# : len=11 : NO 00 H3
+ 1621 56 25 = OO__O@_O_O# : len=11 : NO 00 D3
+ 1622 56 26 = OO__O@OO_O# : len=11 : S4 00 H4
+ 1623 56 27 = OO__O@__OO# : len=11 : NO 00 NO
+ 1624 56 28 = OO__O@O_OO# : len=11 : NO 00 D4
+ 1625 56 29 = OO__O@_OOO# : len=11 : NO 00 D4
+ 1626 56 30 = OO__O@OOOO# : len=11 : L6 00 L6
+ 1627 56 31 = OO__O@_____ : len=11 : NO 00 NO
+ 1628 56 32 = OO__O@O____ : len=11 : H3 22 H3
+ 1629 56 33 = OO__O@_O___ : len=11 : D3 01 D3
+ 1630 56 34 = OO__O@OO___ : len=11 : H4 00 H4
+ 1631 56 35 = OO__O@__O__ : len=11 : NO 00 NO
+ 1632 56 36 = OO__O@O_O__ : len=11 : D4 00 D4
+ 1633 56 37 = OO__O@_OO__ : len=11 : D4 00 D4
+ 1634 56 38 = OO__O@OOO__ : len=11 : L5 00 L5
+ 1635 56 39 = OO__O@___O_ : len=11 : NO 00 NO
+ 1636 56 40 = OO__O@O__O_ : len=11 : NO 00 H3
+ 1637 56 41 = OO__O@_O_O_ : len=11 : NO 00 D3
+ 1638 56 42 = OO__O@OO_O_ : len=11 : S4 00 H4
+ 1639 56 43 = OO__O@__OO_ : len=11 : NO 00 NO
+ 1640 56 44 = OO__O@O_OO_ : len=11 : NO 00 D4
+ 1641 56 45 = OO__O@_OOO_ : len=11 : NO 00 D4
+ 1642 56 46 = OO__O@OOOO_ : len=11 : L6 00 L6
+ 1643 56 47 = OO__O@____O : len=11 : NO 00 NO
+ 1644 56 48 = OO__O@O___O : len=11 : H3 22 H3
+ 1645 56 49 = OO__O@_O__O : len=11 : D3 01 D3
+ 1646 56 50 = OO__O@OO__O : len=11 : H4 00 H4
+ 1647 56 51 = OO__O@__O_O : len=11 : NO 00 NO
+ 1648 56 52 = OO__O@O_O_O : len=11 : D4 00 D4
+ 1649 56 53 = OO__O@_OO_O : len=11 : D4 00 D4
+ 1650 56 54 = OO__O@OOO_O : len=11 : L5 00 L5
+ 1651 56 55 = OO__O@___OO : len=11 : NO 00 NO
+ 1652 56 56 = OO__O@O__OO : len=11 : NO 00 H3
+ 1653 57 0 = OO_O_@# : len= 7 : NO 00 NO
+ 1654 57 1 = OO_O_@_# : len= 8 : NO 00 NO
+ 1655 57 2 = OO_O_@O# : len= 8 : NO 00 NO
+ 1656 57 3 = OO_O_@__# : len= 9 : NO 00 NO
+ 1657 57 4 = OO_O_@O_# : len= 9 : NO 00 D3
+ 1658 57 5 = OO_O_@_O# : len= 9 : NO 00 NO
+ 1659 57 6 = OO_O_@OO# : len= 9 : D4 00 D4
+ 1660 57 7 = OO_O_@___# : len=10 : NO 00 NO
+ 1661 57 8 = OO_O_@O__# : len=10 : NO 00 D3
+ 1662 57 9 = OO_O_@_O_# : len=10 : NO 00 NO
+ 1663 57 10 = OO_O_@OO_# : len=10 : D4 00 D4
+ 1664 57 11 = OO_O_@__O# : len=10 : NO 00 NO
+ 1665 57 12 = OO_O_@O_O# : len=10 : NO 00 D3
+ 1666 57 13 = OO_O_@_OO# : len=10 : NO 00 NO
+ 1667 57 14 = OO_O_@OOO# : len=10 : NO 00 D4
+ 1668 57 15 = OO_O_@____# : len=11 : NO 00 NO
+ 1669 57 16 = OO_O_@O___# : len=11 : NO 00 D3
+ 1670 57 17 = OO_O_@_O__# : len=11 : NO 00 NO
+ 1671 57 18 = OO_O_@OO__# : len=11 : D4 00 D4
+ 1672 57 19 = OO_O_@__O_# : len=11 : NO 00 NO
+ 1673 57 20 = OO_O_@O_O_# : len=11 : NO 00 D3
+ 1674 57 21 = OO_O_@_OO_# : len=11 : NO 00 D3
+ 1675 57 22 = OO_O_@OOO_# : len=11 : S4 00 H4
+ 1676 57 23 = OO_O_@___O# : len=11 : NO 00 NO
+ 1677 57 24 = OO_O_@O__O# : len=11 : NO 00 D3
+ 1678 57 25 = OO_O_@_O_O# : len=11 : NO 00 NO
+ 1679 57 26 = OO_O_@OO_O# : len=11 : X4 00 X4
+ 1680 57 27 = OO_O_@__OO# : len=11 : NO 00 NO
+ 1681 57 28 = OO_O_@O_OO# : len=11 : D4 00 D4
+ 1682 57 29 = OO_O_@_OOO# : len=11 : D4 00 D4
+ 1683 57 30 = OO_O_@OOOO# : len=11 : L5 00 L5
+ 1684 57 31 = OO_O_@_____ : len=11 : NO 00 NO
+ 1685 57 32 = OO_O_@O____ : len=11 : NO 00 D3
+ 1686 57 33 = OO_O_@_O___ : len=11 : NO 00 NO
+ 1687 57 34 = OO_O_@OO___ : len=11 : D4 00 D4
+ 1688 57 35 = OO_O_@__O__ : len=11 : NO 00 NO
+ 1689 57 36 = OO_O_@O_O__ : len=11 : NO 00 D3
+ 1690 57 37 = OO_O_@_OO__ : len=11 : NO 00 D3
+ 1691 57 38 = OO_O_@OOO__ : len=11 : S4 00 H4
+ 1692 57 39 = OO_O_@___O_ : len=11 : NO 00 NO
+ 1693 57 40 = OO_O_@O__O_ : len=11 : NO 00 D3
+ 1694 57 41 = OO_O_@_O_O_ : len=11 : NO 00 NO
+ 1695 57 42 = OO_O_@OO_O_ : len=11 : X4 00 X4
+ 1696 57 43 = OO_O_@__OO_ : len=11 : NO 00 NO
+ 1697 57 44 = OO_O_@O_OO_ : len=11 : D4 00 D4
+ 1698 57 45 = OO_O_@_OOO_ : len=11 : D4 00 D4
+ 1699 57 46 = OO_O_@OOOO_ : len=11 : L5 00 L5
+ 1700 57 47 = OO_O_@____O : len=11 : NO 00 NO
+ 1701 57 48 = OO_O_@O___O : len=11 : NO 00 D3
+ 1702 57 49 = OO_O_@_O__O : len=11 : NO 00 NO
+ 1703 57 50 = OO_O_@OO__O : len=11 : D4 00 D4
+ 1704 57 51 = OO_O_@__O_O : len=11 : NO 00 NO
+ 1705 57 52 = OO_O_@O_O_O : len=11 : NO 00 D3
+ 1706 57 53 = OO_O_@_OO_O : len=11 : NO 00 D3
+ 1707 57 54 = OO_O_@OOO_O : len=11 : NO 00 H4
+ 1708 57 55 = OO_O_@___OO : len=11 : NO 00 NO
+ 1709 57 56 = OO_O_@O__OO : len=11 : NO 00 D3
+ 1710 57 57 = OO_O_@_O_OO : len=11 : NO 00 NO
+ 1711 58 0 = OO_OO@# : len= 7 : NO 00 D4
+ 1712 58 1 = OO_OO@_# : len= 8 : NO 00 D4
+ 1713 58 2 = OO_OO@O# : len= 8 : NO 00 D4
+ 1714 58 3 = OO_OO@__# : len= 9 : NO 00 D4
+ 1715 58 4 = OO_OO@O_# : len= 9 : S4 00 H4
+ 1716 58 5 = OO_OO@_O# : len= 9 : D4 00 X4
+ 1717 58 6 = OO_OO@OO# : len= 9 : L5 00 L5
+ 1718 58 7 = OO_OO@___# : len=10 : NO 00 D4
+ 1719 58 8 = OO_OO@O__# : len=10 : S4 00 H4
+ 1720 58 9 = OO_OO@_O_# : len=10 : D4 00 X4
+ 1721 58 10 = OO_OO@OO_# : len=10 : L5 00 L5
+ 1722 58 11 = OO_OO@__O# : len=10 : NO 00 D4
+ 1723 58 12 = OO_OO@O_O# : len=10 : NO 00 H4
+ 1724 58 13 = OO_OO@_OO# : len=10 : NO 00 X4
+ 1725 58 14 = OO_OO@OOO# : len=10 : L6 00 L6
+ 1726 58 15 = OO_OO@____# : len=11 : NO 00 D4
+ 1727 58 16 = OO_OO@O___# : len=11 : S4 00 H4
+ 1728 58 17 = OO_OO@_O__# : len=11 : D4 00 X4
+ 1729 58 18 = OO_OO@OO__# : len=11 : L5 00 L5
+ 1730 58 19 = OO_OO@__O_# : len=11 : NO 00 D4
+ 1731 58 20 = OO_OO@O_O_# : len=11 : NO 00 H4
+ 1732 58 21 = OO_OO@_OO_# : len=11 : NO 00 X4
+ 1733 58 22 = OO_OO@OOO_# : len=11 : L6 00 L6
+ 1734 58 23 = OO_OO@___O# : len=11 : NO 00 D4
+ 1735 58 24 = OO_OO@O__O# : len=11 : S4 00 H4
+ 1736 58 25 = OO_OO@_O_O# : len=11 : D4 00 X4
+ 1737 58 26 = OO_OO@OO_O# : len=11 : L5 00 L5
+ 1738 58 27 = OO_OO@__OO# : len=11 : NO 00 D4
+ 1739 58 28 = OO_OO@O_OO# : len=11 : NO 00 H4
+ 1740 58 29 = OO_OO@_OOO# : len=11 : NO 00 X4
+ 1741 58 30 = OO_OO@OOOO# : len=11 : L6 00 L6
+ 1742 58 31 = OO_OO@_____ : len=11 : NO 00 D4
+ 1743 58 32 = OO_OO@O____ : len=11 : S4 00 H4
+ 1744 58 33 = OO_OO@_O___ : len=11 : D4 00 X4
+ 1745 58 34 = OO_OO@OO___ : len=11 : L5 00 L5
+ 1746 58 35 = OO_OO@__O__ : len=11 : NO 00 D4
+ 1747 58 36 = OO_OO@O_O__ : len=11 : NO 00 H4
+ 1748 58 37 = OO_OO@_OO__ : len=11 : NO 00 X4
+ 1749 58 38 = OO_OO@OOO__ : len=11 : L6 00 L6
+ 1750 58 39 = OO_OO@___O_ : len=11 : NO 00 D4
+ 1751 58 40 = OO_OO@O__O_ : len=11 : S4 00 H4
+ 1752 58 41 = OO_OO@_O_O_ : len=11 : D4 00 X4
+ 1753 58 42 = OO_OO@OO_O_ : len=11 : L5 00 L5
+ 1754 58 43 = OO_OO@__OO_ : len=11 : NO 00 D4
+ 1755 58 44 = OO_OO@O_OO_ : len=11 : NO 00 H4
+ 1756 58 45 = OO_OO@_OOO_ : len=11 : NO 00 X4
+ 1757 58 46 = OO_OO@OOOO_ : len=11 : L6 00 L6
+ 1758 58 47 = OO_OO@____O : len=11 : NO 00 D4
+ 1759 58 48 = OO_OO@O___O : len=11 : S4 00 H4
+ 1760 58 49 = OO_OO@_O__O : len=11 : D4 00 X4
+ 1761 58 50 = OO_OO@OO__O : len=11 : L5 00 L5
+ 1762 58 51 = OO_OO@__O_O : len=11 : NO 00 D4
+ 1763 58 52 = OO_OO@O_O_O : len=11 : NO 00 H4
+ 1764 58 53 = OO_OO@_OO_O : len=11 : NO 00 X4
+ 1765 58 54 = OO_OO@OOO_O : len=11 : L6 00 L6
+ 1766 58 55 = OO_OO@___OO : len=11 : NO 00 D4
+ 1767 58 56 = OO_OO@O__OO : len=11 : S4 00 H4
+ 1768 58 57 = OO_OO@_O_OO : len=11 : D4 00 X4
+ 1769 58 58 = OO_OO@OO_OO : len=11 : L5 00 L5
+ 1770 59 0 = OOO__@# : len= 7 : NO 00 NO
+ 1771 59 1 = OOO__@_# : len= 8 : NO 00 NO
+ 1772 59 2 = OOO__@O# : len= 8 : NO 00 NO
+ 1773 59 3 = OOO__@__# : len= 9 : NO 00 NO
+ 1774 59 4 = OOO__@O_# : len= 9 : NO 00 NO
+ 1775 59 5 = OOO__@_O# : len= 9 : NO 00 NO
+ 1776 59 6 = OOO__@OO# : len= 9 : NO 00 NO
+ 1777 59 7 = OOO__@___# : len=10 : NO 00 NO
+ 1778 59 8 = OOO__@O__# : len=10 : NO 00 NO
+ 1779 59 9 = OOO__@_O_# : len=10 : NO 00 NO
+ 1780 59 10 = OOO__@OO_# : len=10 : NO 00 H3
+ 1781 59 11 = OOO__@__O# : len=10 : NO 00 NO
+ 1782 59 12 = OOO__@O_O# : len=10 : NO 00 NO
+ 1783 59 13 = OOO__@_OO# : len=10 : NO 00 NO
+ 1784 59 14 = OOO__@OOO# : len=10 : S4 00 S4
+ 1785 59 15 = OOO__@____# : len=11 : NO 00 NO
+ 1786 59 16 = OOO__@O___# : len=11 : NO 00 NO
+ 1787 59 17 = OOO__@_O__# : len=11 : NO 00 NO
+ 1788 59 18 = OOO__@OO__# : len=11 : H3 13 H3
+ 1789 59 19 = OOO__@__O_# : len=11 : NO 00 NO
+ 1790 59 20 = OOO__@O_O_# : len=11 : D3 02 D3
+ 1791 59 21 = OOO__@_OO_# : len=11 : D3 01 D3
+ 1792 59 22 = OOO__@OOO_# : len=11 : H4 00 H4
+ 1793 59 23 = OOO__@___O# : len=11 : NO 00 NO
+ 1794 59 24 = OOO__@O__O# : len=11 : NO 00 NO
+ 1795 59 25 = OOO__@_O_O# : len=11 : NO 00 NO
+ 1796 59 26 = OOO__@OO_O# : len=11 : D4 00 D4
+ 1797 59 27 = OOO__@__OO# : len=11 : NO 00 NO
+ 1798 59 28 = OOO__@O_OO# : len=11 : D4 00 D4
+ 1799 59 29 = OOO__@_OOO# : len=11 : D4 00 D4
+ 1800 59 30 = OOO__@OOOO# : len=11 : L5 00 L5
+ 1801 59 31 = OOO__@_____ : len=11 : NO 00 NO
+ 1802 59 32 = OOO__@O____ : len=11 : NO 00 NO
+ 1803 59 33 = OOO__@_O___ : len=11 : NO 00 NO
+ 1804 59 34 = OOO__@OO___ : len=11 : H3 13 H3
+ 1805 59 35 = OOO__@__O__ : len=11 : NO 00 NO
+ 1806 59 36 = OOO__@O_O__ : len=11 : D3 02 D3
+ 1807 59 37 = OOO__@_OO__ : len=11 : D3 01 D3
+ 1808 59 38 = OOO__@OOO__ : len=11 : H4 00 H4
+ 1809 59 39 = OOO__@___O_ : len=11 : NO 00 NO
+ 1810 59 40 = OOO__@O__O_ : len=11 : NO 00 NO
+ 1811 59 41 = OOO__@_O_O_ : len=11 : NO 00 NO
+ 1812 59 42 = OOO__@OO_O_ : len=11 : D4 00 D4
+ 1813 59 43 = OOO__@__OO_ : len=11 : NO 00 NO
+ 1814 59 44 = OOO__@O_OO_ : len=11 : D4 00 D4
+ 1815 59 45 = OOO__@_OOO_ : len=11 : D4 00 D4
+ 1816 59 46 = OOO__@OOOO_ : len=11 : L5 00 L5
+ 1817 59 47 = OOO__@____O : len=11 : NO 00 NO
+ 1818 59 48 = OOO__@O___O : len=11 : NO 00 NO
+ 1819 59 49 = OOO__@_O__O : len=11 : NO 00 NO
+ 1820 59 50 = OOO__@OO__O : len=11 : NO 00 H3
+ 1821 59 51 = OOO__@__O_O : len=11 : NO 00 NO
+ 1822 59 52 = OOO__@O_O_O : len=11 : NO 00 D3
+ 1823 59 53 = OOO__@_OO_O : len=11 : NO 00 D3
+ 1824 59 54 = OOO__@OOO_O : len=11 : S4 00 H4
+ 1825 59 55 = OOO__@___OO : len=11 : NO 00 NO
+ 1826 59 56 = OOO__@O__OO : len=11 : NO 00 NO
+ 1827 59 57 = OOO__@_O_OO : len=11 : NO 00 NO
+ 1828 59 58 = OOO__@OO_OO : len=11 : NO 00 D4
+ 1829 59 59 = OOO__@__OOO : len=11 : NO 00 NO
+ 1830 60 0 = OOO_O@# : len= 7 : NO 00 D4
+ 1831 60 1 = OOO_O@_# : len= 8 : NO 00 D4
+ 1832 60 2 = OOO_O@O# : len= 8 : NO 00 D4
+ 1833 60 3 = OOO_O@__# : len= 9 : NO 00 D4
+ 1834 60 4 = OOO_O@O_# : len= 9 : NO 00 D4
+ 1835 60 5 = OOO_O@_O# : len= 9 : NO 00 D4
+ 1836 60 6 = OOO_O@OO# : len= 9 : NO 00 D4
+ 1837 60 7 = OOO_O@___# : len=10 : NO 00 D4
+ 1838 60 8 = OOO_O@O__# : len=10 : NO 00 D4
+ 1839 60 9 = OOO_O@_O_# : len=10 : NO 00 D4
+ 1840 60 10 = OOO_O@OO_# : len=10 : S4 00 H4
+ 1841 60 11 = OOO_O@__O# : len=10 : NO 00 D4
+ 1842 60 12 = OOO_O@O_O# : len=10 : D4 00 X4
+ 1843 60 13 = OOO_O@_OO# : len=10 : D4 00 X4
+ 1844 60 14 = OOO_O@OOO# : len=10 : L5 00 L5
+ 1845 60 15 = OOO_O@____# : len=11 : NO 00 D4
+ 1846 60 16 = OOO_O@O___# : len=11 : NO 00 D4
+ 1847 60 17 = OOO_O@_O__# : len=11 : NO 00 D4
+ 1848 60 18 = OOO_O@OO__# : len=11 : S4 00 H4
+ 1849 60 19 = OOO_O@__O_# : len=11 : NO 00 D4
+ 1850 60 20 = OOO_O@O_O_# : len=11 : D4 00 X4
+ 1851 60 21 = OOO_O@_OO_# : len=11 : D4 00 X4
+ 1852 60 22 = OOO_O@OOO_# : len=11 : L5 00 L5
+ 1853 60 23 = OOO_O@___O# : len=11 : NO 00 D4
+ 1854 60 24 = OOO_O@O__O# : len=11 : NO 00 D4
+ 1855 60 25 = OOO_O@_O_O# : len=11 : NO 00 D4
+ 1856 60 26 = OOO_O@OO_O# : len=11 : NO 00 H4
+ 1857 60 27 = OOO_O@__OO# : len=11 : NO 00 D4
+ 1858 60 28 = OOO_O@O_OO# : len=11 : NO 00 X4
+ 1859 60 29 = OOO_O@_OOO# : len=11 : NO 00 X4
+ 1860 60 30 = OOO_O@OOOO# : len=11 : L6 00 L6
+ 1861 60 31 = OOO_O@_____ : len=11 : NO 00 D4
+ 1862 60 32 = OOO_O@O____ : len=11 : NO 00 D4
+ 1863 60 33 = OOO_O@_O___ : len=11 : NO 00 D4
+ 1864 60 34 = OOO_O@OO___ : len=11 : S4 00 H4
+ 1865 60 35 = OOO_O@__O__ : len=11 : NO 00 D4
+ 1866 60 36 = OOO_O@O_O__ : len=11 : D4 00 X4
+ 1867 60 37 = OOO_O@_OO__ : len=11 : D4 00 X4
+ 1868 60 38 = OOO_O@OOO__ : len=11 : L5 00 L5
+ 1869 60 39 = OOO_O@___O_ : len=11 : NO 00 D4
+ 1870 60 40 = OOO_O@O__O_ : len=11 : NO 00 D4
+ 1871 60 41 = OOO_O@_O_O_ : len=11 : NO 00 D4
+ 1872 60 42 = OOO_O@OO_O_ : len=11 : NO 00 H4
+ 1873 60 43 = OOO_O@__OO_ : len=11 : NO 00 D4
+ 1874 60 44 = OOO_O@O_OO_ : len=11 : NO 00 X4
+ 1875 60 45 = OOO_O@_OOO_ : len=11 : NO 00 X4
+ 1876 60 46 = OOO_O@OOOO_ : len=11 : L6 00 L6
+ 1877 60 47 = OOO_O@____O : len=11 : NO 00 D4
+ 1878 60 48 = OOO_O@O___O : len=11 : NO 00 D4
+ 1879 60 49 = OOO_O@_O__O : len=11 : NO 00 D4
+ 1880 60 50 = OOO_O@OO__O : len=11 : S4 00 H4
+ 1881 60 51 = OOO_O@__O_O : len=11 : NO 00 D4
+ 1882 60 52 = OOO_O@O_O_O : len=11 : D4 00 X4
+ 1883 60 53 = OOO_O@_OO_O : len=11 : D4 00 X4
+ 1884 60 54 = OOO_O@OOO_O : len=11 : L5 00 L5
+ 1885 60 55 = OOO_O@___OO : len=11 : NO 00 D4
+ 1886 60 56 = OOO_O@O__OO : len=11 : NO 00 D4
+ 1887 60 57 = OOO_O@_O_OO : len=11 : NO 00 D4
+ 1888 60 58 = OOO_O@OO_OO : len=11 : NO 00 H4
+ 1889 60 59 = OOO_O@__OOO : len=11 : NO 00 D4
+ 1890 60 60 = OOO_O@O_OOO : len=11 : NO 00 X4
+ 1891 61 0 = OOOO_@# : len= 7 : NO 00 D4
+ 1892 61 1 = OOOO_@_# : len= 8 : NO 00 D4
+ 1893 61 2 = OOOO_@O# : len= 8 : NO 00 D4
+ 1894 61 3 = OOOO_@__# : len= 9 : NO 00 D4
+ 1895 61 4 = OOOO_@O_# : len= 9 : NO 00 D4
+ 1896 61 5 = OOOO_@_O# : len= 9 : NO 00 D4
+ 1897 61 6 = OOOO_@OO# : len= 9 : NO 00 D4
+ 1898 61 7 = OOOO_@___# : len=10 : NO 00 D4
+ 1899 61 8 = OOOO_@O__# : len=10 : NO 00 D4
+ 1900 61 9 = OOOO_@_O_# : len=10 : NO 00 D4
+ 1901 61 10 = OOOO_@OO_# : len=10 : NO 00 D4
+ 1902 61 11 = OOOO_@__O# : len=10 : NO 00 D4
+ 1903 61 12 = OOOO_@O_O# : len=10 : NO 00 D4
+ 1904 61 13 = OOOO_@_OO# : len=10 : NO 00 D4
+ 1905 61 14 = OOOO_@OOO# : len=10 : NO 00 D4
+ 1906 61 15 = OOOO_@____# : len=11 : NO 00 D4
+ 1907 61 16 = OOOO_@O___# : len=11 : NO 00 D4
+ 1908 61 17 = OOOO_@_O__# : len=11 : NO 00 D4
+ 1909 61 18 = OOOO_@OO__# : len=11 : NO 00 D4
+ 1910 61 19 = OOOO_@__O_# : len=11 : NO 00 D4
+ 1911 61 20 = OOOO_@O_O_# : len=11 : NO 00 D4
+ 1912 61 21 = OOOO_@_OO_# : len=11 : NO 00 D4
+ 1913 61 22 = OOOO_@OOO_# : len=11 : S4 00 H4
+ 1914 61 23 = OOOO_@___O# : len=11 : NO 00 D4
+ 1915 61 24 = OOOO_@O__O# : len=11 : NO 00 D4
+ 1916 61 25 = OOOO_@_O_O# : len=11 : NO 00 D4
+ 1917 61 26 = OOOO_@OO_O# : len=11 : D4 00 X4
+ 1918 61 27 = OOOO_@__OO# : len=11 : NO 00 D4
+ 1919 61 28 = OOOO_@O_OO# : len=11 : D4 00 X4
+ 1920 61 29 = OOOO_@_OOO# : len=11 : D4 00 X4
+ 1921 61 30 = OOOO_@OOOO# : len=11 : L5 00 L5
+ 1922 61 31 = OOOO_@_____ : len=11 : NO 00 D4
+ 1923 61 32 = OOOO_@O____ : len=11 : NO 00 D4
+ 1924 61 33 = OOOO_@_O___ : len=11 : NO 00 D4
+ 1925 61 34 = OOOO_@OO___ : len=11 : NO 00 D4
+ 1926 61 35 = OOOO_@__O__ : len=11 : NO 00 D4
+ 1927 61 36 = OOOO_@O_O__ : len=11 : NO 00 D4
+ 1928 61 37 = OOOO_@_OO__ : len=11 : NO 00 D4
+ 1929 61 38 = OOOO_@OOO__ : len=11 : S4 00 H4
+ 1930 61 39 = OOOO_@___O_ : len=11 : NO 00 D4
+ 1931 61 40 = OOOO_@O__O_ : len=11 : NO 00 D4
+ 1932 61 41 = OOOO_@_O_O_ : len=11 : NO 00 D4
+ 1933 61 42 = OOOO_@OO_O_ : len=11 : D4 00 X4
+ 1934 61 43 = OOOO_@__OO_ : len=11 : NO 00 D4
+ 1935 61 44 = OOOO_@O_OO_ : len=11 : D4 00 X4
+ 1936 61 45 = OOOO_@_OOO_ : len=11 : D4 00 X4
+ 1937 61 46 = OOOO_@OOOO_ : len=11 : L5 00 L5
+ 1938 61 47 = OOOO_@____O : len=11 : NO 00 D4
+ 1939 61 48 = OOOO_@O___O : len=11 : NO 00 D4
+ 1940 61 49 = OOOO_@_O__O : len=11 : NO 00 D4
+ 1941 61 50 = OOOO_@OO__O : len=11 : NO 00 D4
+ 1942 61 51 = OOOO_@__O_O : len=11 : NO 00 D4
+ 1943 61 52 = OOOO_@O_O_O : len=11 : NO 00 D4
+ 1944 61 53 = OOOO_@_OO_O : len=11 : NO 00 D4
+ 1945 61 54 = OOOO_@OOO_O : len=11 : NO 00 H4
+ 1946 61 55 = OOOO_@___OO : len=11 : NO 00 D4
+ 1947 61 56 = OOOO_@O__OO : len=11 : NO 00 D4
+ 1948 61 57 = OOOO_@_O_OO : len=11 : NO 00 D4
+ 1949 61 58 = OOOO_@OO_OO : len=11 : NO 00 X4
+ 1950 61 59 = OOOO_@__OOO : len=11 : NO 00 D4
+ 1951 61 60 = OOOO_@O_OOO : len=11 : NO 00 X4
+ 1952 61 61 = OOOO_@_OOOO : len=11 : NO 00 X4
+*/
+
+unsigned char *pat_gomoku /* [1954] */ =
+/* 0 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 16 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x44\x55\xcc\x00\x00\x00\x00"
+/* 32 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x33\x00\x44\x00\x33\x00\x00\x00"
+/* 48 */ "\x00\x22\x00\x55\x00\x22\x00\x00\x00\x44\x33\x66\x55\xcc\x33\x66"
+/* 64 */ "\x55\xcc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00"
+/* 80 */ "\x55\x00\x55\x00\x05\x00\x55\x02\x46\x00\xaa\x00\x00\x55\x00\x55"
+/* 96 */ "\x00\x05\x00\x55\x00\x05\x00\x55\x00\x00\x44\xcc\x44\xcc\x05\xbb"
+/* 112 */ "\x44\xcc\x05\xbb\x44\xcc\x05\xbb\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 128 */ "\x00\x00\x33\x00\x00\x00\x44\x00\x00\x00\x00\x00\x33\x00\x44\x00"
+/* 144 */ "\x33\x22\x66\x00\x55\x55\xcc\x00\x33\x00\x00\x00\x00\x22\x00\x55"
+/* 160 */ "\x00\x22\x00\x55\x00\x02\x00\x05\x00\x22\x00\x00\x33\x44\x33\x66"
+/* 176 */ "\x55\xcc\x33\x66\x55\xcc\x33\x46\x05\xbb\x33\x66\x55\xcc\x00\x00"
+/* 192 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x44\x00\x00\x00"
+/* 208 */ "\x33\x00\x00\x22\x55\x22\x55\x02\x05\x22\x55\x02\x46\x22\xaa\x55"
+/* 224 */ "\xcc\x22\x55\x02\x46\x22\xaa\x00\x22\x55\x22\x55\x02\x05\x22\x55"
+/* 240 */ "\x02\x05\x22\x55\x02\x05\x22\x55\x02\x05\x22\x55\x02\x44\x66\xcc"
+/* 256 */ "\x66\xcc\x46\xbb\x66\xcc\x46\xbb\x66\xcc\x46\xbb\x66\xcc\x46\xbb"
+/* 272 */ "\x66\xcc\x46\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x33\x00"
+/* 288 */ "\x00\x00\x44\x00\x00\x00\x33\x00\x22\x22\x66\x00\x00\x00\x00\x00"
+/* 304 */ "\x03\x00\x44\x00\x33\x22\x66\x00\x55\x55\xcc\x00\x33\x22\x66\x00"
+/* 320 */ "\x55\x55\xcc\x00\x03\x00\x00\x00\x00\x02\x00\x55\x00\x02\x00\x55"
+/* 336 */ "\x00\x02\x00\x05\x00\x02\x00\x55\x00\x02\x02\x46\x00\x02\x00\x55"
+/* 352 */ "\x55\x05\x55\x46\xaa\xcc\x55\x46\xaa\xcc\x55\x06\x5a\xbb\x55\x46"
+/* 368 */ "\xaa\xcc\x55\x06\x5a\xbb\x55\x46\xaa\xcc\x00\x00\x00\x00\x00\x00"
+/* 384 */ "\x00\x00\x00\x00\x03\x00\x00\x00\x44\x00\x00\x00\x33\x00\x22\x22"
+/* 400 */ "\x66\x00\x00\x00\x55\x00\x55\x55\x05\x55\x05\x55\x05\x55\x05\x55"
+/* 416 */ "\x46\x55\x5a\xaa\xcc\x55\x05\x55\x46\x55\x5a\xaa\xcc\x55\x05\x55"
+/* 432 */ "\x06\x55\x0a\x55\x55\x05\x55\x05\x55\x05\x55\x05\x55\x05\x55\x05"
+/* 448 */ "\x55\x05\x55\x05\x55\x05\x55\x05\x55\x46\x55\x05\x55\x5a\x55\x5a"
+/* 464 */ "\xaa\xcc\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb"
+/* 480 */ "\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb"
+/* 496 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x33\x00\x00\x00\x44\x00"
+/* 512 */ "\x00\x00\x33\x00\x22\x22\x66\x00\x00\x00\x55\x00\x55\x55\xcc\x00"
+/* 528 */ "\x00\x00\x00\x00\x33\x00\x44\x00\x33\x22\x66\x00\x55\x55\xcc\x00"
+/* 544 */ "\x33\x22\x66\x00\x55\x55\xcc\x00\x33\x02\x46\x00\x05\x05\xbb\x00"
+/* 560 */ "\x33\x00\x00\x00\x00\x22\x00\x55\x00\x22\x00\x55\x00\x02\x00\x05"
+/* 576 */ "\x00\x22\x00\x55\x00\x02\x02\x46\x00\x22\x00\xaa\x00\x55\x55\xcc"
+/* 592 */ "\x00\x22\x00\x00\x33\x44\x33\x66\x55\xcc\x33\x66\x55\xcc\x33\x46"
+/* 608 */ "\x05\xbb\x33\x66\x55\xcc\x33\x46\x05\xbb\x33\x66\x55\xcc\x33\x46"
+/* 624 */ "\x05\xbb\x33\x66\x55\xcc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 640 */ "\x03\x00\x00\x00\x44\x00\x00\x00\x33\x00\x22\x22\x66\x00\x00\x00"
+/* 656 */ "\x55\x00\x55\x55\xcc\x00\x00\x00\x33\x00\x00\x22\x55\x22\x55\x02"
+/* 672 */ "\x05\x22\x55\x02\x46\x22\xaa\x55\xcc\x22\x55\x02\x46\x22\xaa\x55"
+/* 688 */ "\xcc\x22\x55\x02\x06\x22\x5a\x05\xbb\x22\x55\x02\x46\x22\xaa\x00"
+/* 704 */ "\x22\x55\x22\x55\x02\x05\x22\x55\x02\x05\x22\x55\x02\x05\x22\x55"
+/* 720 */ "\x02\x05\x22\x55\x02\x46\x22\x55\x02\x5a\x22\xaa\x55\xcc\x22\x55"
+/* 736 */ "\x02\x05\x22\x55\x02\x44\x66\xcc\x66\xcc\x46\xbb\x66\xcc\x46\xbb"
+/* 752 */ "\x66\xcc\x46\xbb\x66\xcc\x46\xbb\x66\xcc\x46\xbb\x66\xcc\x46\xbb"
+/* 768 */ "\x66\xcc\x46\xbb\x66\xcc\x46\xbb\x66\xcc\x46\xbb\x00\x00\x00\x00"
+/* 784 */ "\x00\x00\x00\x00\x00\x00\x33\x00\x00\x00\x44\x00\x00\x00\x33\x00"
+/* 800 */ "\x22\x22\x66\x00\x00\x00\x55\x00\x55\x55\xcc\x00\x00\x00\x33\x00"
+/* 816 */ "\x22\x22\x66\x00\x00\x00\x00\x00\x03\x00\x44\x00\x33\x22\x66\x00"
+/* 832 */ "\x55\x55\xcc\x00\x33\x22\x66\x00\x55\x55\xcc\x00\x03\x02\x46\x00"
+/* 848 */ "\x05\x05\xbb\x00\x33\x22\x66\x00\x55\x55\xcc\x00\x03\x00\x00\x00"
+/* 864 */ "\x00\x02\x00\x55\x00\x02\x00\x55\x00\x02\x00\x05\x00\x02\x00\x55"
+/* 880 */ "\x00\x02\x02\x46\x00\x02\x00\xaa\x00\x55\x55\xcc\x00\x02\x00\x55"
+/* 896 */ "\x00\x02\x02\x46\x00\x02\x00\x55\x55\x05\x55\x46\xaa\xcc\x55\x46"
+/* 912 */ "\xaa\xcc\x55\x06\x5a\xbb\x55\x46\xaa\xcc\x55\x06\x5a\xbb\x55\x46"
+/* 928 */ "\xaa\xcc\x55\x06\x5a\xbb\x55\x46\xaa\xcc\x55\x06\x5a\xbb\x55\x46"
+/* 944 */ "\xaa\xcc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00"
+/* 960 */ "\x44\x00\x00\x00\x33\x00\x22\x22\x66\x00\x00\x00\x55\x00\x55\x55"
+/* 976 */ "\xcc\x00\x00\x00\x33\x00\x22\x22\x66\x00\x00\x00\x55\x00\x55\x55"
+/* 992 */ "\x05\x55\x05\x55\x05\x55\x05\x55\x46\x55\x5a\xaa\xcc\x55\x05\x55"
+/* 1008 */ "\x46\x55\x5a\xaa\xcc\x55\x05\x55\x06\x55\x0a\x5a\xbb\x55\x05\x55"
+/* 1024 */ "\x46\x55\x5a\xaa\xcc\x55\x05\x55\x06\x55\x0a\x55\x55\x05\x55\x05"
+/* 1040 */ "\x55\x05\x55\x05\x55\x05\x55\x05\x55\x05\x55\x05\x55\x05\x55\x05"
+/* 1056 */ "\x55\x46\x55\x05\x55\x5a\x55\x5a\xaa\xcc\x55\x05\x55\x05\x55\x05"
+/* 1072 */ "\x55\x46\x55\x05\x55\x5a\x55\x5a\xaa\xcc\xcc\xbb\xcc\xbb\xcc\xbb"
+/* 1088 */ "\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb"
+/* 1104 */ "\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb"
+/* 1120 */ "\xcc\xbb\xcc\xbb\xcc\xbb\xcc\xbb\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 1136 */ "\x00\x00\x33\x00\x00\x00\x44\x00\x00\x00\x33\x00\x22\x22\x66\x00"
+/* 1152 */ "\x00\x00\x55\x00\x55\x55\xcc\x00\x00\x00\x33\x00\x22\x22\x66\x00"
+/* 1168 */ "\x00\x00\x55\x00\x55\x55\xcc\x00\x00\x00\x00\x00\x33\x00\x44\x00"
+/* 1184 */ "\x33\x22\x66\x00\x55\x55\xcc\x00\x33\x22\x66\x00\x55\x55\xcc\x00"
+/* 1200 */ "\x33\x02\x46\x00\x05\x05\xbb\x00\x33\x22\x66\x00\x55\x55\xcc\x00"
+/* 1216 */ "\x33\x02\x46\x00\x05\x05\xbb\x00\x33\x00\x00\x00\x00\x22\x00\x55"
+/* 1232 */ "\x00\x22\x00\x55\x00\x02\x00\x05\x00\x22\x00\x55\x00\x02\x02\x46"
+/* 1248 */ "\x00\x22\x00\xaa\x00\x55\x55\xcc\x00\x22\x00\x55\x00\x02\x02\x46"
+/* 1264 */ "\x00\x22\x00\xaa\x00\x55\x55\xcc\x00\x22\x00\x00\x03\x44\x33\x66"
+/* 1280 */ "\x55\xcc\x33\x66\x55\xcc\x03\x46\x05\xbb\x33\x66\x55\xcc\x03\x46"
+/* 1296 */ "\x05\xbb\x33\x66\x55\xcc\x03\x46\x05\xbb\x33\x66\x55\xcc\x03\x46"
+/* 1312 */ "\x05\xbb\x33\x66\x55\xcc\x03\x46\x05\xbb\x33\x66\x55\xcc\x00\x00"
+/* 1328 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x44\x00\x00\x00"
+/* 1344 */ "\x33\x00\x22\x22\x66\x00\x00\x00\x55\x00\x55\x55\xcc\x00\x00\x00"
+/* 1360 */ "\x33\x00\x22\x22\x66\x00\x00\x00\x55\x00\x55\x55\xcc\x00\x00\x00"
+/* 1376 */ "\x03\x00\x00\x02\x55\x02\x55\x02\x05\x02\x55\x02\x46\x02\xaa\x55"
+/* 1392 */ "\xcc\x02\x55\x02\x46\x02\xaa\x55\xcc\x02\x55\x02\x06\x02\x5a\x05"
+/* 1408 */ "\xbb\x02\x55\x02\x46\x02\xaa\x55\xcc\x02\x55\x02\x06\x02\x5a\x05"
+/* 1424 */ "\xbb\x02\x55\x02\x46\x02\xaa\x00\x02\x55\x02\x55\x02\x05\x02\x55"
+/* 1440 */ "\x02\x05\x02\x55\x02\x05\x02\x55\x02\x05\x02\x55\x02\x46\x02\x55"
+/* 1456 */ "\x02\x5a\x02\xaa\x55\xcc\x02\x55\x02\x05\x02\x55\x02\x46\x02\x55"
+/* 1472 */ "\x02\x5a\x02\xaa\x55\xcc\x02\x55\x02\x05\x02\x55\x02\x05\x46\xcc"
+/* 1488 */ "\x46\xcc\x06\xbb\x46\xcc\x06\xbb\x46\xcc\x06\xbb\x46\xcc\x06\xbb"
+/* 1504 */ "\x46\xcc\x06\xbb\x46\xcc\x06\xbb\x46\xcc\x06\xbb\x46\xcc\x06\xbb"
+/* 1520 */ "\x46\xcc\x06\xbb\x46\xcc\x06\xbb\x46\xcc\x06\xbb\x46\xcc\x06\xbb"
+/* 1536 */ "\x46\xcc\x06\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x33\x00"
+/* 1552 */ "\x00\x00\x44\x00\x00\x00\x33\x00\x22\x22\x66\x00\x00\x00\x55\x00"
+/* 1568 */ "\x55\x55\xcc\x00\x00\x00\x33\x00\x22\x22\x66\x00\x00\x00\x55\x00"
+/* 1584 */ "\x55\x55\xcc\x00\x00\x00\x33\x00\x02\x02\x46\x00\x00\x00\x00\x00"
+/* 1600 */ "\x03\x00\x44\x00\x33\x22\x66\x00\x55\x55\xcc\x00\x33\x22\x66\x00"
+/* 1616 */ "\x55\x55\xcc\x00\x03\x02\x46\x00\x05\x05\xbb\x00\x33\x22\x66\x00"
+/* 1632 */ "\x55\x55\xcc\x00\x03\x02\x46\x00\x05\x05\xbb\x00\x33\x22\x66\x00"
+/* 1648 */ "\x55\x55\xcc\x00\x03\x00\x00\x00\x00\x02\x00\x55\x00\x02\x00\x55"
+/* 1664 */ "\x00\x02\x00\x05\x00\x02\x00\x55\x00\x02\x02\x46\x00\x02\x00\xaa"
+/* 1680 */ "\x00\x55\x55\xcc\x00\x02\x00\x55\x00\x02\x02\x46\x00\x02\x00\xaa"
+/* 1696 */ "\x00\x55\x55\xcc\x00\x02\x00\x55\x00\x02\x02\x06\x00\x02\x00\x05"
+/* 1712 */ "\x05\x05\x05\x46\x5a\xcc\x05\x46\x5a\xcc\x05\x06\x0a\xbb\x05\x46"
+/* 1728 */ "\x5a\xcc\x05\x06\x0a\xbb\x05\x46\x5a\xcc\x05\x06\x0a\xbb\x05\x46"
+/* 1744 */ "\x5a\xcc\x05\x06\x0a\xbb\x05\x46\x5a\xcc\x05\x06\x0a\xbb\x05\x46"
+/* 1760 */ "\x5a\xcc\x05\x06\x0a\xbb\x05\x46\x5a\xcc\x00\x00\x00\x00\x00\x00"
+/* 1776 */ "\x00\x00\x00\x00\x03\x00\x00\x00\x44\x00\x00\x00\x33\x00\x22\x22"
+/* 1792 */ "\x66\x00\x00\x00\x55\x00\x55\x55\xcc\x00\x00\x00\x33\x00\x22\x22"
+/* 1808 */ "\x66\x00\x00\x00\x55\x00\x55\x55\xcc\x00\x00\x00\x03\x00\x02\x02"
+/* 1824 */ "\x46\x00\x00\x00\x05\x00\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05"
+/* 1840 */ "\x46\x05\x5a\x5a\xcc\x05\x05\x05\x46\x05\x5a\x5a\xcc\x05\x05\x05"
+/* 1856 */ "\x06\x05\x0a\x0a\xbb\x05\x05\x05\x46\x05\x5a\x5a\xcc\x05\x05\x05"
+/* 1872 */ "\x06\x05\x0a\x0a\xbb\x05\x05\x05\x46\x05\x5a\x5a\xcc\x05\x05\x05"
+/* 1888 */ "\x06\x05\x0a\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05"
+/* 1904 */ "\x05\x05\x05\x05\x05\x05\x05\x05\x05\x46\x05\x05\x05\x5a\x05\x5a"
+/* 1920 */ "\x5a\xcc\x05\x05\x05\x05\x05\x05\x05\x46\x05\x05\x05\x5a\x05\x5a"
+/* 1936 */ "\x5a\xcc\x05\x05\x05\x05\x05\x05\x05\x06\x05\x05\x05\x0a\x05\x0a"
+/* 1952 */ "\x0a";
+
+unsigned char *adv_gomoku /* [978] */ =
+/* 0 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 16 */ "\x00\x00\x00\x00\xa0\x00\xa0\x00\x04\x00\x04\x00\x00\xd0\x00\xd0"
+/* 32 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 48 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 64 */ "\x00\x70\x00\x00\x00\x00\xa0\x00\xa1\x00\x00\x00\xa0\x00\x04\x00"
+/* 80 */ "\x04\x00\x00\x00\x04\x00\xd0\xd0\x00\xd0\x00\xd0\x00\xd0\x00\x00"
+/* 96 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x70\x08\x08\x00\x08\x00\x08\x00"
+/* 112 */ "\x08\x00\x08\x00\x40\x40\x00\x40\x00\x40\x00\x40\x00\x40\x00\x00"
+/* 128 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70"
+/* 144 */ "\x00\x00\x00\x70\x21\x00\x00\x00\x00\x00\xa1\x00\x00\x00\xa1\x00"
+/* 160 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 176 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 192 */ "\x00\x00\x00\x00\x00\x00\x70\x21\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 208 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 224 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 240 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x00\x00"
+/* 256 */ "\x00\x70\x21\x00\x00\x00\x00\x00\x00\x00\xa0\x00\xa1\x00\x00\x00"
+/* 272 */ "\xa1\x00\x00\x00\xa0\x00\x00\x00\xa0\x00\x04\x00\x04\x00\x00\x00"
+/* 288 */ "\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\xd0\xd0\x00\xd0\x00\xd0"
+/* 304 */ "\x00\xd0\x00\xd0\x00\xd0\x00\xd0\x00\xd0\x00\x00\x00\x00\x00\x00"
+/* 320 */ "\x00\x00\x00\x00\x70\x21\x00\x00\x00\x00\x00\x00\x70\x08\x08\x00"
+/* 336 */ "\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00"
+/* 352 */ "\x40\x40\x00\x40\x00\x40\x00\x40\x00\x40\x00\x40\x00\x40\x00\x40"
+/* 368 */ "\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 384 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x00\x00\x00\x70"
+/* 400 */ "\x21\x00\x00\x00\x00\x00\x00\x70\x21\x00\x00\x00\x00\x00\xa1\x00"
+/* 416 */ "\x00\x00\xa1\x00\x00\x00\x00\x00\x00\x00\xa1\x00\x00\x00\x00\x00"
+/* 432 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 448 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 464 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 480 */ "\x00\x00\x70\x21\x00\x00\x00\x00\x00\x00\x70\x21\x00\x00\x00\x00"
+/* 496 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 512 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 528 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 544 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 560 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x00\x00\x00\x70\x21\x00"
+/* 576 */ "\x00\x00\x00\x00\x00\x70\x21\x00\x00\x00\x00\x00\x00\x00\xa0\x00"
+/* 592 */ "\xa1\x00\x00\x00\xa1\x00\x00\x00\xa0\x00\x00\x00\xa1\x00\x00\x00"
+/* 608 */ "\xa0\x00\x00\x00\xa0\x00\x04\x00\x04\x00\x00\x00\x04\x00\x00\x00"
+/* 624 */ "\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\xd0"
+/* 640 */ "\x00\xd0\x00\x00\x00\xd0\x00\x00\x00\xd0\x00\x00\x00\xd0\x00\x00"
+/* 656 */ "\x00\xd0\x00\x00\x00\xd0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 672 */ "\x70\x21\x00\x00\x00\x00\x00\x00\x70\x21\x00\x00\x00\x00\x00\x00"
+/* 688 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 704 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 720 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 736 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 752 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 768 */ "\x00\x00\x00\x00\x00\x00\x00\x70\x00\x00\x00\x70\x21\x00\x00\x00"
+/* 784 */ "\x00\x00\x00\x70\x21\x00\x00\x00\x00\x00\x00\x70\x00\x00\x00\x00"
+/* 800 */ "\x00\x00\xa1\x00\x00\x00\xa1\x00\x00\x00\x00\x00\x00\x00\xa1\x00"
+/* 816 */ "\x00\x00\x00\x00\x00\x00\xa1\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 832 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 848 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 864 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 880 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x21"
+/* 896 */ "\x00\x00\x00\x00\x00\x00\x70\x21\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 912 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 928 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 944 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 960 */ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+/* 976 */ "\x00";
diff --git a/include/modes.h b/include/modes.h
new file mode 100644
index 00000000..fe3a6b79
--- /dev/null
+++ b/include/modes.h
@@ -0,0 +1,152 @@
+/* $Id: modes.h,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#ifndef INCLUDE_MODES_H
+#define INCLUDE_MODES_H
+
+#define DONOTHING 0 /* Read menu command return states */
+#define FULLUPDATE 1 /* Entire screen was destroyed in this oper */
+#define PARTUPDATE 2 /* Only the top three lines were destroyed */
+#define DOQUIT 3 /* Exit read menu was executed */
+#define NEWDIRECT 4 /* Directory has changed, re-read files */
+#define READ_NEXT 5 /* Direct read next file */
+#define READ_PREV 6 /* Direct read prev file */
+#define DIRCHANGED 8 /* Index file was changed */
+#define READ_REDRAW 9
+#define PART_REDRAW 10
+#define POS_NEXT 101 /* cursor_pos(locmem, locmem->crs_ln + 1, 1);*/
+
+/* user ¾Þ§@ª¬ºA»P¼Ò¦¡ */
+#define IDLE 0
+#define MMENU 1 /* menu mode */
+#define ADMIN 2
+#define MAIL 3
+#define TMENU 4
+#define UMENU 5
+#define XMENU 6
+#define CLASS 7
+#define PMENU 8
+#define NMENU 9
+#define PSALE 10
+#define POSTING 11 /* boards & class */
+#define READBRD 12
+#define READING 13
+#define READNEW 14
+#define SELECT 15
+#define RMAIL 16 /* mail menu */
+#define SMAIL 17
+#define CHATING 18 /* talk menu */
+#define XMODE 19
+#define FRIEND 20
+#define LAUSERS 21
+#define LUSERS 22
+#define MONITOR 23
+#define PAGE 24
+#define TQUERY 25
+#define TALK 26
+#define EDITPLAN 27 /* user menu */
+#define EDITSIG 28
+#define VOTING 29
+#define XINFO 30
+#define MSYSOP 31
+#define WWW 32
+#define BIG2 33
+#define REPLY 34
+#define HIT 35
+#define DBACK 36
+#define NOTE 37
+#define EDITING 38
+#define MAILALL 39
+#define MJ 40
+#define P_FRIEND 41
+#define LOGIN 42 /* main menu */
+#define DICT 43
+#define BRIDGE 44
+#define ARCHIE 45
+#define GOPHER 46
+#define NEWS 47
+#define LOVE 48
+#define EDITEXP 49
+#define IPREG 50
+#define NADM 51
+#define DRINK 52
+#define CAL 53
+#define PROVERB 54
+#define ANNOUNCE 55 /* announce */
+#define EDNOTE 56
+#define CDICT 57
+#define LOBJ 58
+#define OSONG 59
+#define CHICKEN 60
+#define TICKET 61
+#define GUESSNUM 62
+#define AMUSE 63
+#define OTHELLO 64
+#define DICE 65
+#define VICE 66
+#define BBCALL 67
+#define VIOLATELAW 68
+#define M_FIVE 69
+#define JACK_CARD 70
+#define TENHALF 71
+#define CARD_99 72
+#define RAIL_WAY 73
+#define SREG 74
+#define CHC 75 /* Chinese chess */
+#define DARK 76 /* ¤¤°ê·tµX */
+#define TMPJACK 77
+#define JCEE 78
+#define REEDIT 79
+
+/* menu.c ¤¤ªº¼Ò¦¡ */
+#define QUIT 0x666 /* Return value to abort recursive functions */
+#define XEASY 0x333 /* Return value to un-redraw screen */
+
+/* for currmode */
+#define MODE_STARTED 1 /* ¬O§_¤w¸g¶i¤J¨t²Î */
+#define MODE_POST 2 /* ¬O§_¥i¥H¦b currboard µoªí¤å³¹ */
+#define MODE_BOARD 4 /* ¬O§_¥i¥H¦b currboard §R°£¡Bmark¤å³¹ */
+#define MODE_MENU 8 /* ¬O§_¥i¥H¦b MENU ¶}ªO */
+#define MODE_DIGEST 0x10 /* ¬O§_¬° digest mode */
+#define MODE_ETC 0x20 /* ¬O§_¬° etc mode */
+#define MODE_SELECT 0x40 /* ·j´M¨Ï¥ÎªÌ¼ÐÃD */
+#define MODE_DIRTY 0x80 /* ¬O§_§ó°Ê¹L userflag */
+
+/* for curredit */
+#define EDIT_MAIL 1 /* ¥Ø«e¬O mail/board ? */
+#define EDIT_LIST 2 /* ¬O§_¬° mail list ? */
+#define EDIT_BOTH 4 /* both reply to author/board ? */
+#define EDIT_ITEM 8 /* ITEM ? */
+
+/* read.c ¤¤ªº¼Ò¦¡ */
+#define TAG_NIN 0 /* ¤£ÄÝ©ó TagList */
+#define TAG_TOGGLE 1 /* ¤Á´« Taglist */
+#define TAG_INSERT 2 /* ¥[¤J TagList */
+
+
+#define RS_FORWARD 0x01 /* backward */
+#define RS_TITLE 0x02 /* author/title */
+#define RS_RELATED 0x04
+#define RS_FIRST 0x08 /* find first article */
+#define RS_CURRENT 0x10 /* match current read article */
+#define RS_THREAD 0x20 /* search the first article */
+#define RS_AUTHOR 0x40 /* search author's article */
+#define RS_NEWPOST 0x80 /* search new posts */
+
+#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)
+
+enum {STRIP_ALL = 0, ONLY_COLOR, NO_RELOAD};
+
+#define SIG_PK 0
+#define SIG_TALK 1
+#define SIG_BROADCAST 2
+#define SIG_GOMO 3
+#define SIG_CHC 4
+#define SIG_DARK 5
+
+#endif
diff --git a/include/perm.h b/include/perm.h
new file mode 100644
index 00000000..eece624e
--- /dev/null
+++ b/include/perm.h
@@ -0,0 +1,56 @@
+/* $Id: perm.h,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#ifndef INCLUDE_PERM_H
+#define INCLUDE_PERM_H
+
+#define PERM_BASIC 000000000001
+#define PERM_CHAT 000000000002
+#define PERM_PAGE 000000000004
+#define PERM_POST 000000000010
+#define PERM_LOGINOK 000000000020
+#define PERM_MAILLIMIT 000000000040
+#define PERM_CLOAK 000000000100
+#define PERM_SEECLOAK 000000000200
+#define PERM_XEMPT 000000000400
+#define PERM_DENYPOST 000000001000
+#define PERM_BM 000000002000
+#define PERM_ACCOUNTS 000000004000
+#define PERM_CHATROOM 000000010000
+#define PERM_BOARD 000000020000
+#define PERM_SYSOP 000000040000
+#define PERM_BBSADM 000000100000
+#define PERM_NOTOP 000000200000
+#define PERM_VIOLATELAW 000000400000
+#define PERM_NOOUTMAIL 000001000000
+#define PERM_20 000002000000
+#define PERM_VIEWSYSOP 000004000000
+#define PERM_LOGUSER 000010000000
+#define PERM_ANNOUNCE 000020000000
+#define PERM_RELATION 000040000000
+#define PERM_SMG 000100000000
+#define PERM_PRG 000200000000
+#define PERM_ACTION 000400000000
+#define PERM_PAINT 001000000000
+#define PERM_LAW 002000000000
+#define PERM_SYSSUBOP 004000000000
+#define PERM_MSYSOP 010000000000
+#define PERM_PTT 020000000000
+
+#define NUMPERMS 32
+
+#define PERM_DEFAULT (PERM_BASIC | PERM_CHAT | PERM_PAGE )
+#define PERM_MANAGER (PERM_RELATION | PERM_SMG | PERM_ACTION | PERM_PAINT | PERM_LAW)
+#define PERM_ADMIN (PERM_ACCOUNTS | PERM_SYSOP | PERM_SYSSUBOP | PERM_MANAGER | PERM_BM)
+#define PERM_ALLBOARD (PERM_SYSOP | PERM_BOARD)
+#define PERM_LOGINCLOAK (PERM_SYSOP | PERM_ACCOUNTS)
+#define PERM_SEEULEVELS (PERM_SYSOP)
+#define PERM_SEEBLEVELS (PERM_SYSOP | PERM_BM)
+#define PERM_NOTIMEOUT (PERM_SYSOP)
+#define PERM_READMAIL (PERM_BASIC)
+#define PERM_FORWARD (PERM_BASIC) /* to do the forwarding */
+#define PERM_INTERNET (PERM_LOGINOK) /* ¨­¥÷»{ÃÒ¹LÃöªº¤~¯à±H«H¨ì Internet */
+
+#define HAS_PERM(x) ((x) ? cuser.userlevel & (x) : 1)
+#define HAVE_PERM(x) (cuser.userlevel&(x))
+#define PERM_HIDE(u) ((u)->userlevel & PERM_SYSOP && \
+ (u)->userlevel & PERM_DENYPOST)
+#endif
diff --git a/include/proto.h b/include/proto.h
new file mode 100644
index 00000000..8122f5d5
--- /dev/null
+++ b/include/proto.h
@@ -0,0 +1,522 @@
+/* $Id: proto.h,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#ifndef INCLUDE_PROTO_H
+#define INCLUDE_PROTO_H
+
+/* admin */
+int m_mod_board(char *bname);
+int m_newbrd(int recover);
+int scan_register_form(char *regfile, int automode, int neednum);
+int m_user();
+int search_user_bypwd();
+int search_user_bybakpwd();
+int m_board();
+int m_register();
+int cat_register();
+unsigned int setperms(unsigned int pbits, char *pstring[]);
+void setup_man(boardheader_t * board);
+
+/* announce */
+int a_menu(char *maintitle, char *path, int lastlevel);
+void a_copyitem(char* fpath, char* title, char* owner, int mode);
+int Announce();
+void gem(char* maintitle, item_t* path, int update);
+
+/* args */
+void initsetproctitle(int argc, char **argv, char **envp);
+void setproctitle(const char* format, ...);
+
+/* bbcall */
+int main_bbcall();
+
+/* bbs */
+void make_blist();
+int invalid_brdname(char *brd);
+int del_range(int ent, fileheader_t *fhdr, char *direct);
+int cmpfowner(fileheader_t *fhdr);
+int b_note_edit_bname(int bid);
+int Read();
+void anticrosspost();
+int Select();
+void do_reply_title(int row, char *title);
+int cmpfmode(fileheader_t *fhdr);
+int cmpfilename(fileheader_t *fhdr);
+int getindex(char *fpath, char *fname, int size);
+void outgo_post(fileheader_t *fh, char *board);
+int edit_title(int ent, fileheader_t *fhdr, char *direct);
+int whereami(int ent, fileheader_t *fhdr, char *direct);
+void set_board();
+int do_post();
+void ReadSelect();
+int save_violatelaw();
+int board_select();
+int board_etc();
+int board_digest();
+
+/* board */
+int brc_unread(char *fname, int bnum, int *blist);
+int brc_initial(char *boardname);
+void brc_update();
+int Ben_Perm(boardheader_t *bptr);
+int New();
+int Boards();
+int root_board();
+void save_brdbuf(void);
+void init_brdbuf(void);
+
+/* cache */
+int moneyof(int uid);
+int getuser(char *userid);
+void setuserid(int num, char *userid);
+int searchuser(char *userid);
+int getbnum(char *bname);
+void reset_board(int bid);
+void touch_boards();
+void addbrd_touchcache();
+void setapath(char *buf, char *boardname);
+void setutmpmode(int mode);
+void setadir(char *buf, char *path);
+boardheader_t *getbcache(int bid);
+int apply_boards(int (*func)(boardheader_t *));
+int haspostperm(char *bname);
+void inbtotal(int bid, int add);
+void brc_addlist(char *fname);
+void setbtotal(int bid);
+unsigned int safe_sleep(unsigned int seconds);
+int apply_ulist(int (*fptr)(userinfo_t *));
+userinfo_t *search_ulistn(int uid, int unum);
+void purge_utmp(userinfo_t *uentp);
+userinfo_t *search_ulist(int uid);
+int count_multi();
+void resolve_utmp();
+void attach_uhash();
+void getnewutmpent(userinfo_t *up);
+void resolve_garbage();
+void resolve_boards();
+void resolve_fcache();
+void sem_init(int semkey,int *semid);
+void sem_lock(int op,int semid);
+int count_ulist();
+char *u_namearray(char buf[][IDLEN + 1], int *pnum, char *tag);
+char *getuserid(int num);
+int searchnewuser(int mode);
+int count_logins(int uid, int show);
+void remove_from_uhash(int n);
+void add_to_uhash(int n, char *id);
+int setumoney(int uid, int money);
+int getbtotal(int bid);
+userinfo_t *search_ulist_pid(int pid);
+int moneyof(int uid);
+void hbflreload(int bid);
+int hbflcheck(int bid, int uid);
+
+/* cal */
+int vice(int money, char* item);
+int inumoney(char *tuser, int money);
+int cal();
+#define reload_money() cuser.money=moneyof(usernum)
+int demoney(int money);
+int deumoney(int uid, int money);
+int lockutmpmode(int unmode, int state);
+int unlockutmpmode();
+int p_touch_boards();
+int x_file();
+int give_money();
+int p_sysinfo();
+int p_give();
+int p_cloak();
+int p_from();
+int ordersong();
+int p_exmail();
+void mail_redenvelop(char* from, char* to, int money, char mode);
+
+/* card */
+int g_card_jack();
+int g_ten_helf();
+int card_99();
+
+/* chat */
+int t_chat();
+
+/* chc_draw */
+void chc_drawline(board_t board, int line);
+void chc_movecur(int r, int c);
+void chc_redraw(board_t board);
+
+/* chc_net */
+void chc_sendmove(int s);
+int chc_recvmove(int s);
+
+/* chc_play */
+void chc(int s);
+
+/* chc_rule */
+void chc_movechess(board_t board);
+int chc_canmove(board_t board, rc_t from, rc_t to);
+int chc_iskfk(board_t board);
+int chc_ischeck(board_t board, int turn);
+void chc_init_board(board_t board);
+
+/* chicken */
+int show_file(char *filename, int y, int lines, int mode);
+void ch_buyitem(int money, char *picture, int *item);
+int chicken_main();
+int chickenpk(int fd);
+void time_diff(chicken_t *thechicken);
+int isdeadth(chicken_t *thechicken);
+void show_chicken_data(chicken_t *thechicken, chicken_t *pkchicken);
+int reload_chicken();
+
+/* dark */
+int main_dark(int fd,userinfo_t *uin);
+
+/* dice */
+int IsSNum(char *a);
+int dice_main();
+int IsNum(char *a, int n);
+
+/* edit */
+int vedit(char *fpath, int saveheader, int *islocal);
+void write_header(FILE *fp);
+void addsignature(FILE *fp, int ifuseanony);
+void auto_backup();
+void restore_backup();
+char *ask_tmpbuf(int y);
+char *strcasestr(const char* big, const char* little);
+
+/* friend */
+void friend_edit(int type);
+void friend_load();
+int t_override();
+int t_reject();
+void friend_add(char *uident, int type);
+void friend_delete(char *uident, int type);
+
+/* gamble */
+int ticket_main();
+int post_msg(char* bname, char* title, char *msg, char* author);
+int openticket(int bid);
+int ticket(int bid);
+
+/* gomo */
+int gomoku(int fd);
+
+/* gomo1 */
+int getstyle(int x, int y, int color, int limit);
+int chkwin(int style, int limit);
+
+/* guess */
+int guess_main();
+
+/* indict */
+int x_dict();
+int use_dict();
+
+/* io */
+int getdata(int line, int col, char *prompt, char *buf, int len, int echo);
+int igetch();
+int getdata_str(int line, int col, char *prompt, char *buf, int len, int echo, char *defaultstr);
+int getdata_buf(int line, int col, char *prompt, char *buf, int len, int echo);
+int i_get_key();
+void add_io(int fd, int timeout);
+int igetkey();
+void oflush();
+int oldgetdata(int line, int col, char *prompt, char *buf, int len, int echo);
+void output(char *s, int len);
+void init_alarm();
+int num_in_buf();
+int ochar(int c);
+
+/* kaede */
+int Rename(char* src, char* dst);
+int Link(char* src, char* dst);
+char *Ptt_prints(char *str, int mode);
+char *my_ctime(const time_t *t);
+
+/* lovepaper */
+int x_love();
+
+/* mail */
+int load_mailalert(char *userid);
+int mail_muser(userec_t muser, char *title, char *filename);
+int mail_id(char* id, char *title, char *filename, char *owner);
+int m_read();
+int doforward(char *direct, fileheader_t *fh, int mode);
+int mail_reply(int ent, fileheader_t *fhdr, char *direct);
+int bsmtp(char *fpath, char *title, char *rcpt, int method);
+void hold_mail(char *fpath, char *receiver);
+int chkmail(int rechk);
+void m_init();
+int chkmailbox();
+int mail_man();
+int m_new();
+int m_send();
+int mail_list();
+int setforward();
+int m_internet();
+int mail_mbox();
+int built_mail_index();
+int mail_all();
+int invalidaddr(char *addr);
+int do_send(char *userid, char *title);
+void my_send(char *uident);
+
+/* mbbsd */
+void log_usies(char *mode, char *mesg);
+void log_user(char *msg);
+void abort_bbs(int sig);
+void del_distinct(char *fname, char *line);
+void add_distinct(char *fname, char *line);
+void show_last_call_in(int save);
+int dosearchuser(char *userid);
+void u_exit(char *mode);
+
+/* menu */
+void showtitle(char *title, char *mid);
+int egetch();
+void movie(int i);
+void domenu(int cmdmode, char *cmdtitle, int cmd, commands_t cmdtable[]);
+
+/* more */
+int more(char *fpath, int promptend);
+
+/* name */
+void usercomplete(char *prompt, char *data);
+void namecomplete(char *prompt, char *data);
+void AddNameList(char *name);
+void CreateNameList();
+int chkstr(char *otag, char *tag, char *name);
+int InNameList(char *name);
+void ShowNameList(int row, int column, char *prompt);
+int RemoveNameList(char *name);
+void ToggleNameList(int *reciper, char *listfile, char *msg);
+
+/* osdep */
+int cpuload(char *str);
+double swapused(long *total, long *used);
+
+/* othello */
+int othello_main();
+
+/* page */
+int main_railway();
+
+/* read */
+void z_download(char *fpath);
+void i_read(int cmdmode, char *direct, void (*dotitle)(), void (*doentry)(), onekey_t *rcmdlist, int bidcache);
+void fixkeep(char *s, int first);
+keeploc_t *getkeep(char *s, int def_topline, int def_cursline);
+int Tagger(time_t chrono, int recno, int mode);
+
+/* record */
+int substitute_record(char *fpath, void *rptr, int size, int id);
+int get_record(char *fpath, void *rptr, int size, int id);
+void prints(char *fmt, ...);
+int append_record(char *fpath, fileheader_t *record, int size);
+int stampfile(char *fpath, fileheader_t *fh);
+void stampdir(char *fpath, fileheader_t *fh);
+int get_num_records(char *fpath, int size);
+int get_records(char *fpath, void *rptr, int size, int id, int number);
+void stamplink(char *fpath, fileheader_t *fh);
+int delete_record(char fpath[], int size, int id);
+int delete_files(char* dirname, int (*filecheck)(), int record);
+int delete_file(char *dirname, int size, int ent, int (*filecheck)());
+int delete_range(char *fpath, int id1, int id2);
+int apply_record(char *fpath, int (*fptr)(), int size);
+int search_rec(char* dirname, int (*filecheck)());
+int do_append(char *fpath, fileheader_t *record, int size);
+int get_sum_records(char* fpath, int size);
+
+/* register */
+int getnewuserid();
+int bad_user_id(char *userid);
+void new_register();
+int checkpasswd(char *passwd, char *test);
+void check_register();
+char *genpasswd(char *pw);
+
+/* screen */
+void move(int y, int x);
+void outs(char *str);
+void clrtoeol();
+void clear();
+void refresh();
+void clrtobot();
+void mprints(int y, int x, char *str);
+void outmsg(char *msg);
+void region_scroll_up(int top, int bottom);
+void outc(unsigned char ch);
+void redoscr();
+void clrtoline(int line);
+void standout();
+void standend();
+int edit_outs(char *text);
+void outch(unsigned char c);
+void rscroll();
+void scroll();
+void getyx(int *y, int *x);
+void initscr();
+void Jaky_outs(char *str, int line);
+
+/* stuff */
+void setcalfile(char *buf, char *userid);
+void stand_title(char *title);
+void pressanykey();
+int vmsg (const char *fmt,...);
+void trim(char *buf);
+void bell();
+void setbpath(char *buf, char *boardname);
+int dashf(char *fname);
+void sethomepath(char *buf, char *userid);
+void sethomedir(char *buf, char *userid);
+char *Cdate(time_t *clock);
+void sethomefile(char *buf, char *userid, char *fname);
+int log_file(char *filename,char *buf);
+void str_lower(char *t, char *s);
+int strstr_lower(char *str, char *tag);
+int cursor_key(int row, int column);
+int search_num(int ch, int max);
+void setuserfile(char *buf, char *fname);
+int is_BM(char *list);
+long dasht(char *fname);
+int dashd(char *fname);
+int invalid_pname(char *str);
+void setbdir(char *buf, char *boardname);
+void setbfile(char *buf, char *boardname, char *fname);
+int dashl(char *fname);
+char *subject(char *title);
+int not_alnum(char ch);
+void setdirpath(char *buf, char *direct, char *fname);
+int str_checksum(char *str);
+void show_help(char *helptext[]);
+int belong(char *filelist, char *key);
+char *Cdatedate(time_t *clock);
+int isprint2(char ch);
+void sethomeman(char *buf, char *userid);
+off_t dashs(char *fname);
+void cursor_clear(int row, int column);
+void cursor_show(int row, int column);
+void printdash(char *mesg);
+char *Cdatelite(time_t *clock);
+int not_alpha(char ch);
+int valid_ident(char *ident);
+int userid_is_BM(char *userid, char *list);
+int is_uBM(char *list, char *id);
+
+/* syspost */
+void post_newboard(char *bgroup, char *bname, char *bms);
+void post_violatelaw(char *crime, char *police, char *reason, char *result);
+void post_change_perm(int oldperm, int newperm, char *sysopid, char *userid);
+
+/* talk */
+int cmpwatermtime(const void *a, const void *b);
+void water_scr(water_t **currwater, int which, char type);
+void my_write2(void);
+int t_idle();
+char *modestring(userinfo_t * uentp, int simple);
+int isvisible(userinfo_t * me, userinfo_t * uentp);
+int t_users();
+int cmpuids(int uid, userinfo_t * urec);
+int my_write(pid_t pid, char *hint, char *id, int flag);
+void t_display_new();
+void talkreply();
+int t_monitor();
+int t_pager();
+int t_query();
+int t_qchicken();
+int t_talk();
+int t_display();
+int my_query(char *uident);
+int logout_friend_online();
+int login_friend_online();
+int isvisible_uid(int tuid);
+int friend_stat(userinfo_t *me, userinfo_t * ui);
+
+/* tmpjack */
+int reg_barbq();
+int p_ticket_main();
+int j_ticket_main();
+
+/* term */
+void init_tty();
+int term_init();
+void save_cursor();
+void restore_cursor();
+void do_move(int destcol, int destline);
+void scroll_forward();
+void change_scroll_range(int top, int bottom);
+
+/* topsong */
+void sortsong();
+int topsong();
+
+/* user */
+int u_editcalendar();
+void user_display(userec_t *u, int real);
+void uinfo_query(userec_t *u, int real, int unum);
+int showsignature(char *fname);
+void mail_violatelaw(char* crime, char* police, char* reason, char* result);
+void showplans(char *uid);
+int u_info();
+int u_loginview();
+int u_ansi();
+int u_editplan();
+int u_editsig();
+int u_switchproverb();
+int u_editproverb();
+int u_cloak();
+int u_register();
+int u_list();
+
+/* vote */
+int strip_ansi(char *buf, char *str, int mode);
+void b_suckinfile(FILE *fp, char *fname);
+int b_results();
+int b_vote();
+int b_vote_maintain();
+int b_closepolls();
+
+/* vice */
+int vice_main();
+
+/* voteboard */
+int do_voteboard();
+void do_voteboardreply(fileheader_t *fhdr);
+
+/* xyz */
+int m_sysop();
+int x_boardman();
+int x_note();
+int x_login();
+int x_week();
+int x_issue();
+int x_today();
+int x_yesterday();
+int x_user100();
+int x_birth();
+int x_90();
+int x_89();
+int x_88();
+int x_87();
+int x_86();
+int x_history();
+int x_weather();
+int x_stock();
+int note();
+int Goodbye();
+
+/* toolkit */
+unsigned StringHash(unsigned char *s);
+
+/* passwd */
+int passwd_mmap();
+int passwd_update(int num, userec_t *buf);
+int passwd_query(int num, userec_t *buf);
+int passwd_apply(int (*fptr)(userec_t *));
+void passwd_lock();
+void passwd_unlock();
+int passwd_update_money(int num);
+
+/* calendar */
+int calendar();
+
+#endif
diff --git a/include/pttbbs.conf b/include/pttbbs.conf
new file mode 100644
index 00000000..9bd4722d
--- /dev/null
+++ b/include/pttbbs.conf
@@ -0,0 +1,17 @@
+/* ©w¸q BBS ¯¸¦W¦ì§} */
+#define BBSNAME "§å½ð½ð¹ê·~§{" /* ¤¤¤å¯¸¦W */
+#define MYHOSTNAME "ptt.csie.ntu.edu.tw" /* ºô¸ô¦ì§} */
+#define MYIP "140.112.30.142" /* IP¦ì§} */
+#define BBSUSER "bbs"
+#define BBSUID 9999
+#define BBSGID 99
+
+#define MAX_USERS 150000
+#define MAX_ACTIVE 4096
+#define MAX_CPULOAD 50
+#define MAX_FROM 512
+#define RELAY_SERVER_IP "140.112.30.143"
+#define MAX_POST_MONEY 1000
+#define MAX_CHICKEN_MONEY 10000
+#define HAVE_JCEE 0
+#define TITLE_COLOR "\33[0;1;37;44m"
diff --git a/include/pttstruct.h b/include/pttstruct.h
new file mode 100644
index 00000000..76a196a9
--- /dev/null
+++ b/include/pttstruct.h
@@ -0,0 +1,390 @@
+/* $Id: pttstruct.h,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#ifndef INCLUDE_STRUCT_H
+#define INCLUDE_STRUCT_H
+
+/* ¤pÂûªº¸ê®Æ */
+typedef struct chicken_t {
+ char name[20];
+ char type; /* ª«ºØ */
+ unsigned char tech[16]; /* §Þ¯à */
+ time_t birthday; /* ¥Í¤é */
+ time_t lastvisit; /* ¤W¦¸·ÓÅU®É¶¡ */
+ int oo; /* ¸É«~ */
+ int food; /* ­¹ª« */
+ int medicine; /* ÃÄ«~ */
+ int weight; /* Åé­« */
+ int clean; /* °®²b */
+ int run; /* ±Ó±¶«× */
+ int attack; /* §ðÀ»¤O */
+ int book; /* ª¾ÃÑ */
+ int happy; /* §Ö¼Ö */
+ int satis; /* º¡·N«× */
+ int temperament; /* ®ð½è */
+ int tiredstrong; /* ¯h³Ò«× */
+ int sick; /* ¯f®ð«ü¼Æ */
+ int hp; /* ¦å¶q */
+ int hp_max; /* º¡¦å¶q */
+ int mm; /* ªk¤O */
+ int mm_max; /* º¡ªk¤O */
+ time_t cbirth; /* ¹ê»Ú­pºâ¥Îªº¥Í¤é */
+ int pad[2]; /* ¯dµÛ¥H«á¥Î */
+} chicken_t;
+
+#define IDLEN 12 /* Length of bid/uid */
+#define PASSLEN 14 /* Length of encrypted passwd field */
+#define REGLEN 38 /* Length of registration data */
+
+typedef struct userec_t {
+ char userid[IDLEN + 1];
+ char realname[20];
+ char username[24];
+ char passwd[PASSLEN];
+ unsigned char uflag;
+ unsigned int userlevel;
+ unsigned short numlogins;
+ unsigned short numposts;
+ time_t firstlogin;
+ time_t lastlogin;
+ char lasthost[16];
+ int money;
+ char remoteuser[3]; /* «O¯d ¥Ø«e¨S¥Î¨ìªº */
+ char proverb;
+ char email[50];
+ char address[50];
+ char justify[REGLEN + 1];
+ unsigned char month;
+ unsigned char day;
+ unsigned char year;
+ unsigned char sex;
+ unsigned char state;
+ unsigned char pager;
+ unsigned char invisible;
+ unsigned int exmailbox;
+ chicken_t mychicken;
+ time_t lastsong;
+ unsigned int loginview;
+ unsigned char channel; /* °ÊºA¬ÝªO */
+ unsigned short vl_count; /* ViolateLaw counter */
+ unsigned short five_win;
+ unsigned short five_lose;
+ unsigned short five_tie;
+ unsigned short chc_win;
+ unsigned short chc_lose;
+ unsigned short chc_tie;
+ int mobile;
+ int mind;
+ char ident[11];
+ unsigned int uflag2;
+ char pad[72];
+} userec_t;
+/* these are flags in userec_t.uflag */
+#define SIG_FLAG 0x3 /* signature number, 2 bits */
+#define PAGER_FLAG 0x4 /* true if pager was OFF last session */
+#define CLOAK_FLAG 0x8 /* true if cloak was ON last session */
+#define FRIEND_FLAG 0x10 /* true if show friends only */
+#define BRDSORT_FLAG 0x20 /* true if the boards sorted alphabetical */
+#define MOVIE_FLAG 0x40 /* true if show movie */
+#define COLOR_FLAG 0x80 /* true if the color mode open */
+#define MIND_FLAG 0x100 /* true if mind search mode open <-Heat*/
+/* these are flags in userec_t.uflag2 */
+#define WATER_MASK 000003 /* water mask */
+#define WATER_ORIG 0
+#define WATER_NEW 1
+#define WATER_OFO 2
+#define WATERMODE(mode) ((cuser.uflag2 & WATER_MASK) == mode)
+
+
+#define BTLEN 48 /* Length of board title */
+
+typedef struct boardheader_t {
+ char brdname[IDLEN + 1]; /* bid */
+ char title[BTLEN + 1];
+ char BM[IDLEN * 3 + 3]; /* BMs' uid, token '/' */
+ unsigned int brdattr; /* boardªºÄÝ©Ê */
+ char pad[3]; /* ¨S¥Î¨ìªº */
+ time_t bupdate; /* note update time */
+ char pad2[3]; /* ¨S¥Î¨ìªº */
+ unsigned char bvote; /* Vote flags */
+ time_t vtime; /* Vote close time */
+ unsigned int level; /* ¥i¥H¬Ý¦¹ªOªºÅv­­ */
+ int unused; /* ÁÙ¨S¥Î¨ì */
+ int gid; /* ¬ÝªO©ÒÄݪºÃþ§O ID */
+ void *next[2]; /* ¦b¦P¤@­Ógid¤U¤@­Ó¬ÝªO °ÊºA²£¥Í*/
+ void *firstchild[2]; /* ÄÝ©ó³o­Ó¬ÝªOªº²Ä¤@­Ó¤l¬ÝªO */
+ void *parent;
+ char pad3[100];
+} boardheader_t;
+
+#define BRD_NOZAP 00001 /* ¤£¥izap */
+#define BRD_NOCOUNT 00002 /* ¤£¦C¤J²Î­p */
+#define BRD_NOTRAN 00004 /* ¤£Âà«H */
+#define BRD_GROUPBOARD 00010 /* ¸s²ÕªO */
+#define BRD_HIDE 00020 /* ÁôÂêO (¬ÝªO¦n¤Í¤~¥i¬Ý) */
+#define BRD_POSTMASK 00040 /* ­­¨îµoªí©Î¾\Ū */
+#define BRD_ANONYMOUS 00100 /* °Î¦WªO? */
+#define BRD_DEFAULTANONYMOUS 00200 /* ¹w³]°Î¦WªO */
+#define BRD_BAD 00400 /* ¹Hªk§ï¶i¤¤¬ÝªO */
+#define BRD_VOTEBOARD 01000 /* ³s¸p¾÷¬ÝªO */
+#define BRD_WARNDEL 02000 /* ¤wĵ§i­n¼o°£ªº¬ÝªO */
+
+#define TTLEN 64 /* Length of title */
+#define FNLEN 33 /* Length of filename */
+
+#define FHR_REFERENCE (1<<31)
+
+typedef struct fileheader_t {
+ char filename[FNLEN]; /* M.9876543210.A */
+ char savemode; /* file save mode */
+ char owner[IDLEN + 2]; /* uid[.] */
+ char date[6]; /* [02/02] or space(5) */
+ char title[TTLEN + 1];
+ int money; /* rocker: if bit32 on ==> reference */
+ unsigned char filemode; /* must be last field @ boards.c */
+} fileheader_t;
+
+#define FILE_LOCAL 0x1 /* local saved */
+#define FILE_READ 0x1 /* already read : mail only */
+#define FILE_MARKED 0x2 /* opus: 0x8 */
+#define FILE_DIGEST 0x4 /* digest */
+#define FILE_SOLVED 0x10 /* problem solved, sysop only */
+#define FILE_HIDE 0x20 /* hild */
+#define FILE_BM 0x40 /* BM only */
+
+#define STRLEN 80 /* Length of most string data */
+
+
+/* uhash is a userid->uid hash table -- jochang */
+
+#define HASH_BITS 16
+typedef struct uhash_t {
+ char userid[MAX_USERS][IDLEN + 1];
+ int next_in_hash[MAX_USERS];
+ int money[MAX_USERS];
+ int hash_head[1 << HASH_BITS];
+ int number; /* # of users total */
+ int loaded; /* .PASSWD has been loaded? */
+ int hbfl[MAX_BOARD][MAX_FRIEND + 1];
+} uhash_t;
+
+union xitem_t {
+ struct { /* bbs_item */
+ char fdate[9]; /* [mm/dd/yy] */
+ char editor[13]; /* user ID */
+ char fname[31];
+ } B;
+ struct { /* gopher_item */
+ char path[81];
+ char server[48];
+ int port;
+ } G;
+};
+
+typedef struct {
+ char title[63];
+ union xitem_t X;
+} item_t;
+
+typedef struct {
+ item_t *item[MAX_ITEMS];
+ char mtitle[STRLEN];
+ char *path;
+ int num, page, now, level;
+} gmenu_t;
+
+typedef struct msgque_t {
+ pid_t pid;
+ char userid[IDLEN + 1];
+ char last_call_in[80];
+} msgque_t;
+
+typedef struct water_t {
+ pid_t pid;
+ char userid[IDLEN + 1];
+ msgque_t msg[MAX_REVIEW];
+ int top, count;
+} water_t;
+
+#define FAVMAX 74 /* Max boards of Myfavorite */
+#define FAVGMAX 16 /* Max groups of Myfavorite */
+#define FAVGSLEN 8 /* Max Length of Description String */
+
+typedef struct userinfo_t {
+ int uid; /* Used to find user name in passwd file */
+ pid_t pid; /* kill() to notify user of talk request */
+ int sockaddr; /* ... */
+ int destuid; /* talk uses this to identify who called */
+ int destuip; /* dest index in utmpshm->uinfo[] */
+ unsigned char active; /* When allocated this field is true */
+ unsigned char invisible; /* Used by cloaking function in Xyz menu */
+ unsigned char sockactive; /* Used to coordinate talk requests */
+ unsigned int userlevel;
+ unsigned char mode; /* UL/DL, Talk Mode, Chat Mode, ... */
+ unsigned char pager; /* pager toggle, YEA, or NA */
+ unsigned char in_chat; /* for in_chat commands */
+ unsigned char sig; /* signal type */
+ char userid[IDLEN + 1];
+ char chatid[11]; /* chat id, if in chat mode */
+ char realname[20];
+ char username[24];
+ char from[27]; /* machine name the user called in from */
+ int from_alias;
+ char birth; /* ¬O§_¬O¥Í¤é Ptt*/
+ char tty[11]; /* tty port */
+ int friend[MAX_FRIEND];
+ int friend_online[MAX_FRIEND]; /* point¨ì½u¤W¦n¤Í utmpshmªº¦ì¸m */
+ /* ¦n¤Í¤ñ¸ûªºcache «e¨â­Óbit¬Oª¬ºA */
+ int reject[MAX_REJECT];
+ int pad[3];
+ int friendtotal; /* ¦n¤Í¤ñ¸ûªºcache ¤j¤p */
+ unsigned char msgcount;
+ msgque_t msgs[MAX_MSGS];
+ time_t uptime;
+ time_t lastact; /* ¤W¦¸¨Ï¥ÎªÌ°Êªº®É¶¡ */
+ unsigned int brc_id;
+ unsigned char lockmode; /* ¤£­ã multi_login ª±ªºªF¦è */
+ char turn; /* for gomo */
+ char mateid[IDLEN + 1]; /* for gomo */
+ unsigned short int five_win;
+ unsigned short int five_lose;
+ unsigned short int five_tie;
+ int myfavorite[FAVMAX];
+ char gfavorite[FAVGMAX][FAVGSLEN+1];
+ int ninGroup[FAVGMAX];
+ int nGroup;
+ int ninRoot;
+ int mailalert;
+ int sex;
+ char color;
+ int mind;
+} userinfo_t;
+
+typedef struct {
+ fileheader_t *header;
+ char mtitle[STRLEN];
+ char *path;
+ int num, page, now, level;
+} menu_t;
+
+typedef struct onekey_t { /* Used to pass commands to the readmenu */
+ int key;
+ int (*fptr)();
+} onekey_t;
+
+#define ANSILINELEN (511) /* Maximum Screen width in chars */
+
+/* anti_crosspost */
+typedef struct crosspost_t {
+ int checksum[4]; /* 0 -> 'X' cross post 1-3 -> ²¬d¤å³¹¦æ */
+ int times; /* ²Ä´X¦¸ */
+} crosspost_t;
+
+#define SORT_BY_ID 0
+#define SORT_BY_CLASS 1
+#define SORT_BY_STAT 1
+#define SORT_BY_IDLE 2
+#define SORT_BY_FROM 3
+#define SORT_BY_FIVE 4
+#define SORT_BY_SEX 5
+
+typedef struct bcache_t {
+ boardheader_t bcache[MAX_BOARD];
+ boardheader_t *sorted[2][MAX_BOARD]; /* 0: by name 1: by class */
+ fileheader_t dircache[MAX_BOARD][DIRCACHESIZE];
+ int cachetotal[MAX_BOARD];
+ int total[MAX_BOARD];
+ time_t lastposttime[MAX_BOARD];
+ time_t uptime;
+ time_t touchtime;
+ int number;
+ int busystate;
+} bcache_t;
+
+typedef struct keeploc_t {
+ char *key;
+ int top_ln;
+ int crs_ln;
+ struct keeploc_t *next;
+} keeploc_t;
+
+#define USHM_SIZE (MAX_ACTIVE + 4) /* why+4? */
+
+struct utmpfile_t {
+ userinfo_t uinfo[USHM_SIZE];
+ userinfo_t *sorted[2][8][USHM_SIZE];
+ /* ²Ä¤@ºûdouble buffer ¥Ñcurrsorted«ü¦V¥Ø«e¨Ï¥Îªº
+ ²Ä¤Gºûsort type */
+ int currsorted;
+ time_t uptime;
+ int number;
+ int busystate;
+};
+
+struct pttcache_t {
+ char notes[MAX_MOVIE][200*11];
+ char today_is[20];
+ int n_notes[MAX_MOVIE_SECTION]; /* ¤@¸`¤¤¦³´X­Ó ¬ÝªO */
+ int next_refresh[MAX_MOVIE_SECTION]; /* ¤U¤@¦¸­nrefreshªº ¬ÝªO */
+ int max_film;
+ int max_history;
+ time_t uptime;
+ time_t touchtime;
+ int busystate;
+};
+
+typedef struct fromcache_t {
+ char domain[MAX_FROM][50];
+ char replace[MAX_FROM][50];
+ int top;
+ int max_user;
+ time_t max_time;
+ time_t uptime;
+ time_t touchtime;
+ int busystate;
+} fromcache_t;
+
+typedef struct {
+ unsigned char oldlen; /* previous line length */
+ unsigned char len; /* current length of line */
+ unsigned char mode; /* status of line, as far as update */
+ unsigned char smod; /* start of modified data */
+ unsigned char emod; /* end of modified data */
+ unsigned char sso; /* start stand out */
+ unsigned char eso; /* end stand out */
+ unsigned char data[ANSILINELEN + 1];
+} screenline_t;
+
+typedef struct {
+ int r, c;
+} rc_t;
+
+#define BRD_ROW 10
+#define BRD_COL 9
+
+typedef int board_t[BRD_ROW][BRD_COL];
+
+/* name.c ¤¤¹B¥Îªº¸ê®Æµ²ºc */
+typedef struct word_t {
+ char *word;
+ struct word_t *next;
+} word_t;
+
+typedef struct commands_t {
+ int (*cmdfunc)();
+ int level;
+ char *desc; /* next/key/description */
+} commands_t;
+
+typedef struct MailQueue {
+ char filepath[FNLEN];
+ char subject[STRLEN];
+ time_t mailtime;
+ char sender[IDLEN + 1];
+ char username[24];
+ char rcpt[50];
+ int method;
+ char * niamod;
+} MailQueue;
+
+enum {MQ_TEXT, MQ_UUENCODE, MQ_JUSTIFY};
+
+#endif
diff --git a/include/pttstruct.h.save b/include/pttstruct.h.save
new file mode 100644
index 00000000..f73f6413
--- /dev/null
+++ b/include/pttstruct.h.save
@@ -0,0 +1,363 @@
+/* $Id: pttstruct.h.save,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+~#ifndef INCLUDE_STRUCT_H
+#define INCLUDE_STRUCT_H
+
+/* ¤pÂûªº¸ê®Æ */
+typedef struct chicken_t {
+ char name[20];
+ char type; /* ª«ºØ */
+ unsigned char tech[16]; /* §Þ¯à */
+ time_t birthday; /* ¥Í¤é */
+ time_t lastvisit; /* ¤W¦¸·ÓÅU®É¶¡ */
+ int oo; /* ¸É«~ */
+ int food; /* ­¹ª« */
+ int medicine; /* ÃÄ«~ */
+ int weight; /* Åé­« */
+ int clean; /* °®²b */
+ int run; /* ±Ó±¶«× */
+ int attack; /* §ðÀ»¤O */
+ int book; /* ª¾ÃÑ */
+ int happy; /* §Ö¼Ö */
+ int satis; /* º¡·N«× */
+ int temperament; /* ®ð½è */
+ int tiredstrong; /* ¯h³Ò«× */
+ int sick; /* ¯f®ð«ü¼Æ */
+ int hp; /* ¦å¶q */
+ int hp_max; /* º¡¦å¶q */
+ int mm; /* ªk¤O */
+ int mm_max; /* º¡ªk¤O */
+ time_t cbirth; /* ¹ê»Ú­pºâ¥Îªº¥Í¤é */
+ int pad[2]; /* ¯dµÛ¥H«á¥Î */
+} chicken_t;
+
+#define IDLEN 12 /* Length of bid/uid */
+#define PASSLEN 14 /* Length of encrypted passwd field */
+#define REGLEN 38 /* Length of registration data */
+
+typedef struct userec_t {
+ char userid[IDLEN + 1];
+ char realname[20];
+ char username[24];
+ char passwd[PASSLEN];
+ unsigned char uflag;
+ unsigned int userlevel;
+ unsigned short numlogins;
+ unsigned short numposts;
+ time_t firstlogin;
+ time_t lastlogin;
+ char lasthost[16];
+ int money;
+ char remoteuser[3]; /* «O¯d ¥Ø«e¨S¥Î¨ìªº */
+ char proverb;
+ char email[50];
+ char address[50];
+ char justify[REGLEN + 1];
+ unsigned char month;
+ unsigned char day;
+ unsigned char year;
+ unsigned char sex;
+ unsigned char state;
+ unsigned char pager;
+ unsigned char invisible;
+ unsigned int exmailbox;
+ chicken_t mychicken;
+ time_t lastsong;
+ unsigned int loginview;
+ unsigned char channel; /* °ÊºA¬ÝªO */
+ unsigned short vl_count; /* ViolateLaw counter */
+ unsigned short five_win;
+ unsigned short five_lose;
+ unsigned short five_tie;
+ unsigned short chc_win;
+ unsigned short chc_lose;
+ unsigned short chc_tie;
+ char pad[95];
+} userec_t;
+/* these are flags in userec_t.uflag */
+#define SIG_FLAG 0x3 /* signature number, 2 bits */
+#define PAGER_FLAG 0x4 /* true if pager was OFF last session */
+#define CLOAK_FLAG 0x8 /* true if cloak was ON last session */
+#define FRIEND_FLAG 0x10 /* true if show friends only */
+#define BRDSORT_FLAG 0x20 /* true if the boards sorted alphabetical */
+#define MOVIE_FLAG 0x40 /* true if show movie */
+#define COLOR_FLAG 0x80 /* true if the color mode open */
+#define MIND_FLAG 0x100 /* true if mind search mode open <-Heat*/
+
+#define BTLEN 48 /* Length of board title */
+
+typedef struct boardheader_t {
+ char brdname[IDLEN + 1]; /* bid */
+ char title[BTLEN + 1];
+ char BM[IDLEN * 3 + 3]; /* BMs' uid, token '/' */
+ unsigned int brdattr; /* boardªºÄÝ©Ê */
+ char pad[3]; /* ¨S¥Î¨ìªº */
+ time_t bupdate; /* note update time */
+ char pad2[3]; /* ¨S¥Î¨ìªº */
+ unsigned char bvote; /* Vote flags */
+ time_t vtime; /* Vote close time */
+ unsigned int level; /* ¥i¥H¬Ý¦¹ªOªºÅv­­ */
+ int uid; /* ¬ÝªOªºÃþ§O ID */
+ int gid; /* ¬ÝªO©ÒÄݪºÃþ§O ID */
+ void *next[2]; /* ¦b¦P¤@­Ógid¤U¤@­Ó¬ÝªO °ÊºA²£¥Í*/
+ void *firstchild[2]; /* ÄÝ©ó³o­Ó¬ÝªOªº²Ä¤@­Ó¤l¬ÝªO */
+ void *parent;
+ char pad3[100];
+} boardheader_t;
+
+#define BRD_NOZAP 00001 /* ¤£¥izap */
+#define BRD_NOCOUNT 00002 /* ¤£¦C¤J²Î­p */
+#define BRD_NOTRAN 00004 /* ¤£Âà«H */
+#define BRD_GROUPBOARD 00010 /* ¸s²ÕªO */
+#define BRD_HIDE 00020 /* ÁôÂêO (¬ÝªO¦n¤Í¤~¥i¬Ý) */
+#define BRD_POSTMASK 00040 /* ­­¨îµoªí©Î¾\Ū */
+#define BRD_ANONYMOUS 00100 /* °Î¦WªO? */
+#define BRD_DEFAULTANONYMOUS 00200 /* ¹w³]°Î¦WªO */
+#define BRD_BAD 00400 /* ¹Hªk§ï¶i¤¤¬ÝªO */
+#define BRD_VOTEBOARD 01000 /* ³s¸p¾÷¬ÝªO */
+
+#define TTLEN 64 /* Length of title */
+#define FNLEN 33 /* Length of filename */
+
+#define FHR_REFERENCE (1<<31)
+
+typedef struct fileheader_t {
+ char filename[FNLEN]; /* M.9876543210.A */
+ char savemode; /* file save mode */
+ char owner[IDLEN + 2]; /* uid[.] */
+ char date[6]; /* [02/02] or space(5) */
+ char title[TTLEN + 1];
+ int money; /* rocker: if bit32 on ==> reference */
+ unsigned char filemode; /* must be last field @ boards.c */
+} fileheader_t;
+
+#define FILE_LOCAL 0x1 /* local saved */
+#define FILE_READ 0x1 /* already read : mail only */
+#define FILE_MARKED 0x2 /* opus: 0x8 */
+#define FILE_DIGEST 0x4 /* digest */
+#define FILE_TAGED 0x8 /* taged */
+#define FILE_SOLVED 0x10 /* problem solved, sysop only */
+
+#define STRLEN 80 /* Length of most string data */
+
+
+/* uhash is a userid->uid hash table -- jochang */
+
+#define HASH_BITS 16
+typedef struct uhash_t {
+ char userid[MAX_USERS][IDLEN + 1];
+ int money[MAX_USERS];
+ int next_in_hash[MAX_USERS];
+ int hash_head[1 << HASH_BITS];
+ int number; /* # of users total */
+ int loaded; /* .PASSWD has been loaded? */
+} uhash_t;
+
+union xitem_t {
+ struct { /* bbs_item */
+ char fdate[9]; /* [mm/dd/yy] */
+ char editor[13]; /* user ID */
+ char fname[31];
+ } B;
+ struct { /* gopher_item */
+ char path[81];
+ char server[48];
+ int port;
+ } G;
+};
+
+typedef struct {
+ char title[63];
+ union xitem_t X;
+} item_t;
+
+typedef struct {
+ item_t *item[MAX_ITEMS];
+ char mtitle[STRLEN];
+ char *path;
+ int num, page, now, level;
+} gmenu_t;
+
+typedef struct msgque_t {
+ pid_t last_pid;
+ char last_userid[IDLEN + 1];
+ char last_call_in[80];
+} msgque_t;
+
+#define FAVMAX 74 /* Max boards of Myfavorite */
+#define FAVGMAX 16 /* Max groups of Myfavorite */
+#define FAVGSLEN 8 /* Max Length of Description String */
+
+typedef struct userinfo_t {
+ int uid; /* Used to find user name in passwd file */
+ pid_t pid; /* kill() to notify user of talk request */
+ int sockaddr; /* ... */
+ int destuid; /* talk uses this to identify who called */
+ int destuip; /* dest index in utmpshm->uinfo[] */
+ unsigned char active; /* When allocated this field is true */
+ unsigned char invisible; /* Used by cloaking function in Xyz menu */
+ unsigned char sockactive; /* Used to coordinate talk requests */
+ unsigned int userlevel;
+ unsigned char mode; /* UL/DL, Talk Mode, Chat Mode, ... */
+ unsigned char pager; /* pager toggle, YEA, or NA */
+ unsigned char in_chat; /* for in_chat commands */
+ unsigned char sig; /* signal type */
+ char userid[IDLEN + 1];
+ char chatid[11]; /* chat id, if in chat mode */
+ char realname[20];
+ char username[24];
+ char from[27]; /* machine name the user called in from */
+ int from_alias;
+ char birth; /* ¬O§_¬O¥Í¤é Ptt*/
+ char tty[11]; /* tty port */
+ int friend[MAX_FRIEND];
+ void *friend_online[MAX_FRIEND]; /* point¨ì½u¤W¦n¤Í */
+ int friend_state[MAX_FRIEND]; /* ¹ïÀ³¨ìfriend_onlineªºª¬ºA */
+ int reject[MAX_REJECT];
+ unsigned char msgcount;
+ msgque_t msgs[MAX_MSGS];
+ time_t uptime;
+ time_t lastact; /* ¤W¦¸¨Ï¥ÎªÌ°Êªº®É¶¡ */
+ unsigned int brc_id;
+ unsigned char lockmode; /* ¤£­ã multi_login ª±ªºªF¦è */
+ char turn; /* for gomo */
+ char mateid[IDLEN + 1]; /* for gomo */
+ unsigned short int five_win;
+ unsigned short int five_lose;
+ unsigned short int five_tie;
+ int myfavorite[FAVMAX];
+ char gfavorite[FAVGMAX][FAVGSLEN+1];
+ int ninGroup[FAVGMAX];
+ int nGroup;
+ int ninRoot;
+ int mailalert;
+ int sex;
+ char color;
+ int mind;
+} userinfo_t;
+
+typedef struct {
+ fileheader_t *header;
+ char mtitle[STRLEN];
+ char *path;
+ int num, page, now, level;
+} menu_t;
+
+typedef struct onekey_t { /* Used to pass commands to the readmenu */
+ int key;
+ int (*fptr)();
+} onekey_t;
+
+#define ANSILINELEN (511) /* Maximum Screen width in chars */
+
+/* anti_crosspost */
+typedef struct crosspost_t {
+ int checksum[4]; /* 0 -> 'X' cross post 1-3 -> ²¬d¤å³¹¦æ */
+ int times; /* ²Ä´X¦¸ */
+} crosspost_t;
+
+#define SORT_BY_ID 0
+#define SORT_BY_CLASS 1
+#define SORT_BY_STAT 1
+#define SORT_BY_IDLE 2
+#define SORT_BY_FROM 3
+#define SORT_BY_FIVE 4
+#define SORT_BY_SEX 5
+
+typedef struct bcache_t {
+ boardheader_t bcache[MAX_BOARD];
+ boardheader_t *sorted[2][MAX_BOARD]; /* 0: by name 1: by class */
+ fileheader_t dircache[MAX_BOARD][DIRCACHESIZE];
+ unsigned int total[MAX_BOARD];
+ time_t lastposttime[MAX_BOARD];
+ time_t uptime;
+ time_t touchtime;
+ int number;
+ int busystate;
+} bcache_t;
+
+typedef struct keeploc_t {
+ char *key;
+ int top_ln;
+ int crs_ln;
+ struct keeploc_t *next;
+} keeploc_t;
+
+#define USHM_SIZE (MAX_ACTIVE + 4) /* why+4? */
+
+struct utmpfile_t {
+ userinfo_t uinfo[USHM_SIZE];
+ userinfo_t *sorted[8][USHM_SIZE];
+ time_t uptime;
+ int number;
+ int busystate;
+};
+
+struct pttcache_t {
+ char notes[MAX_MOVIE][200*11];
+ char today_is[20];
+ int n_notes[MAX_MOVIE_SECTION]; /* ¤@¸`¤¤¦³´X­Ó ¬ÝªO */
+ int next_refresh[MAX_MOVIE_SECTION]; /* ¤U¤@¦¸­nrefreshªº ¬ÝªO */
+ int max_film;
+ int max_history;
+ time_t uptime;
+ time_t touchtime;
+ int busystate;
+};
+
+typedef struct fromcache_t {
+ char domain[MAX_FROM][50];
+ char replace[MAX_FROM][50];
+ int top;
+ int max_user;
+ time_t max_time;
+ time_t uptime;
+ time_t touchtime;
+ int busystate;
+} fromcache_t;
+
+typedef struct {
+ unsigned char oldlen; /* previous line length */
+ unsigned char len; /* current length of line */
+ unsigned char mode; /* status of line, as far as update */
+ unsigned char smod; /* start of modified data */
+ unsigned char emod; /* end of modified data */
+ unsigned char sso; /* start stand out */
+ unsigned char eso; /* end stand out */
+ unsigned char data[ANSILINELEN + 1];
+} screenline_t;
+
+typedef struct {
+ int r, c;
+} rc_t;
+
+#define BRD_ROW 10
+#define BRD_COL 9
+
+typedef int board_t[BRD_ROW][BRD_COL];
+
+/* name.c ¤¤¹B¥Îªº¸ê®Æµ²ºc */
+typedef struct word_t {
+ char *word;
+ struct word_t *next;
+} word_t;
+
+typedef struct commands_t {
+ int (*cmdfunc)();
+ int level;
+ char *desc; /* next/key/description */
+} commands_t;
+
+typedef struct MailQueue {
+ char filepath[FNLEN];
+ char subject[STRLEN];
+ time_t mailtime;
+ char sender[IDLEN + 1];
+ char username[24];
+ char rcpt[50];
+ int method;
+ char * niamod;
+} MailQueue;
+
+enum {MQ_TEXT, MQ_UUENCODE, MQ_JUSTIFY};
+
+#endif
diff --git a/innbbsd/.cvsignore b/innbbsd/.cvsignore
new file mode 100644
index 00000000..91b3d99d
--- /dev/null
+++ b/innbbsd/.cvsignore
@@ -0,0 +1,6 @@
+bbslink
+bbsnnrp
+ctlinnbbsd
+innbbsd
+mkhistory
+*.o
diff --git a/innbbsd/Makefile b/innbbsd/Makefile
new file mode 100644
index 00000000..fb82be2a
--- /dev/null
+++ b/innbbsd/Makefile
@@ -0,0 +1,206 @@
+# ------------------------------------------------------- #
+# innbbsd/Makefile ( NTHU CS MapleBBS Ver 2.36 ) #
+# ------------------------------------------------------- #
+# target : Makefile for Âà«Hµ{¦¡ innbbsd by skhuang #
+# create : 95/03/29 #
+# update : 95/12/15 #
+# ------------------------------------------------------- #
+
+####################################################
+# this is a bbs <--> news gateway
+#####################################################
+VERSION=0.50beta-4
+LASTVERSION=0.50beta-3
+ADMINUSER= root@your.domain.name
+BBSHOME?=$(HOME)
+BBS_SRC = ..
+TARGET = $(INNBBSD) $(BBSNNRP) $(BBSLINK)
+####################################################
+CC=gcc
+INSTALL=cp
+#
+OPT= -O3 -s -pipe -fomit-frame-pointer -g
+
+BBS_DEP = MapleBBS
+BBS_UTIL = $(BBS_SRC)/util
+BBS_REC = $(BBS_UTIL)/util_record.o $(BBS_UTIL)/util_cache.o $(BBS_UTIL)/util_passwd.o
+
+#########################
+#
+###############
+DEBUGOBJ = /usr/lib/debug/mallocmap.o
+CFLAGS= -c -I. -I$(BBS_SRC)/include -I$(BBS_SRC)/mbbsd -D$(BBS_DEP) \
+$(EXTRAFLAGS) -DDBZDEBUG -DBBSHOME='"$(BBSHOME)"' \
+-D_PATH_BBSHOME=\"$(BBSHOME)\" \
+-DVERSION=\"$(VERSION)\" -DADMINUSER=\"$(ADMINUSER)\"
+#
+####################################################
+
+OBJS = inndchannel.o innbbsd.o connectsock.o rfc931.o \
+ daemon.o file.o pmain.o his.o dbz.o \
+ closeonexec.o dbztool.o inntobbs.o receive_article.o \
+ echobbslib.o $(BBS_REC)
+ # $(BBS_REC)
+SRCS = inndchannel.c innbbsd.c connectsock.c rfc931.c \
+ daemon.c file.c pmain.c parsdate.y his.c dbz.c \
+ closeonexec.c dbztool.c inntobbs.c bbslib.c receive_article.c \
+ port.c
+
+MOBJS = makedbz.o bbslib.o file.o dbz.o closeonexec.o
+HOBJS = mkhistory.o bbslib.o file.o his.o dbz.o port.o closeonexec.o
+DBZOBJS = dbzserver.o dbzinnbbsd.o pmain.o connectsock.o bbslib.o his.o \
+ daemon.o file.o dbz.o dbztool.o rfc931.o port.o closeonexec.o \
+ morelog.o
+NNRPOBJS = bbsnnrp.o pmain.o bbslib.o connectsock.o file.o
+LINKOBJS = bbslink.o pmain.o inntobbs.o echobbslib.o connectsock.o file.o port.o
+LINKOBJS2 = bbslink2.o pmain.o inntobbs.o echobbslib.o connectsock.o file.o port.o
+CTLOBJS = ctlinnbbsd.o pmain.o bbslib.o connectsock.o file.o
+INNBBSD = innbbsd mkhistory bbsnnrp ctlinnbbsd $(BBSLINK)
+BBSNNRP = bbsnnrp
+BBSLINK = bbslink
+BBSLINK2 = bbslink2
+EXES = $(TARGET)
+
+.c.o:
+ $(CC) $(OPT) $(CFLAGS) $*.c
+
+
+all: $(OSTYPE)
+
+sun:
+ @$(MAKE) EXTRAFLAGS="-DMMAP -DGETRUSAGE -DMALLOCMAP" LDFLAGS="$(DEBUGOBJ)" target
+
+
+aix:
+ @$(MAKE) CC=cc EXTRAFLAGS="-DMMAP -DGETRUSAGE -DAIX -DSYSV" target
+
+linux:
+ @$(MAKE) EXTRAFLAGS="-DLINUX -DGETRUSAGE" target
+
+hpux:
+ @$(MAKE) OPT= EXTRAFLAGS="-DMMAP -DHPUX -DSYSV" target
+
+irix:
+ @$(MAKE) EXTRAFLAGS="-DMMAP -DIRIX -DSYSV" target
+
+solaris:
+ @$(MAKE) EXTRAFLAGS="-DMMAP -DSOLARIS -DSYSV" LDFLAGS="-lsocket -lnsl" YACC="bison -y" target
+
+FreeBSD:
+ @$(MAKE) CC=cc EXTRAFLAGS="-DBSD44 -DMMAP -DGETRUSAGE" LIBCRYPT=-lcrypt target
+
+bsd:
+ @$(MAKE) CC=cc EXTRAFLAGS="-DMMAP -DGETRUSAGE" target
+
+alpha:
+ @$(MAKE) CC=cc EXTRAFLAGS="-DMMAP -DDEC_ALPHA -DGETRUSAGE" target
+
+sysv:
+ @$(MAKE) OPT= EXTRAFLAGS="-DMMAP -DSYSV" target
+
+target: $(EXES)
+
+r_port.o: r_port.c
+ $(CC) $(OPT) $(CFLAGS) -DWITH_RECORD_O r_port.c
+
+echobbslib.o: echobbslib.c
+ $(CC) $(OPT) $(CFLAGS) -DWITH_ECHOMAIL echobbslib.c
+
+tar:
+ test -d innbbsd-$(VERSION) || mkdir innbbsd-$(VERSION)
+ cp *.c *.h Makefile innbbsd-$(VERSION)
+ tar zcf innbbsd-$(VERSION).tar.gz innbbsd-$(VERSION)
+ cp innbbsd-$(VERSION).tar.gz /net/ftphome/CSIE/innbbsd
+
+patch:
+ rm -rf /tmp/innbbsd-$(LASTVERSION)
+ zcat /net/ftphome/ftp-data/bbs/misc/innbbsd/innbbsd-$(LASTVERSION).tar.gz | (cd /tmp; tar xf -)
+ (cd /tmp/innbbsd-$(VERSION); make clean; rm -f r_port.c dbzserver.c dbzinnbbsd.c echobbslib.c )
+ (cd /tmp/innbbsd-$(LASTVERSION); make clean; rm -f r_port.c dbzserver.c dbzinnbbsd.c echobbslib.c )
+ (cd /tmp; diff -rcs innbbsd-$(LASTVERSION) innbbsd-$(VERSION) > /tmp/innbbsd-patch.$(LASTVERSION)-$(VERSION); echo "diff -rcs")
+ (cd /tmp/innbbsd-$(VERSION); ln -s port.c r_port.c)
+ (cd /tmp/innbbsd-$(VERSION); ln -s inndchannel.c dbzserver.c)
+ (cd /tmp/innbbsd-$(VERSION); ln -s innbbsd.c dbzinnbbsd.c)
+ (cd /tmp/innbbsd-$(VERSION); ln -s bbslib.c echobbslib.c)
+
+
+distribution:
+ rm -rf /tmp/innbbsd-$(VERSION)
+ test -d /tmp/innbbsd-$(VERSION) || mkdir /tmp/innbbsd-$(VERSION)
+ test -d /tmp/innbbsd-$(VERSION)/innd || mkdir /tmp/innbbsd-$(VERSION)/innd
+ rm -f r_port.c
+ rm -f dbzserver.c
+ rm -f dbzinnbbsd.c
+ rm -f echobbslib.c
+ cp -r doc hisconvert FEATURES CHANGES README* TODO *.c *.h *.y Makefile boards /tmp/innbbsd-$(VERSION)
+ (cd /tmp/innbbsd-$(VERSION); ln -s port.c r_port.c)
+ (cd /tmp/innbbsd-$(VERSION); ln -s inndchannel.c dbzserver.c)
+ (cd /tmp/innbbsd-$(VERSION); ln -s innbbsd.c dbzinnbbsd.c)
+ (cd /tmp/innbbsd-$(VERSION); ln -s bbslib.c echobbslib.c)
+ (cd innd ; cp -r Makefile README innbbs.conf in.bntpd mailpost *.pl bntplink bntplink.palmbbs *.active* *.c *.y *.bbs src /tmp/innbbsd-$(VERSION)/innd)
+ (cd /tmp/innbbsd-$(VERSION); make clean)
+ (cd /tmp; tar zcf innbbsd-$(VERSION).tar.gz innbbsd-$(VERSION) )
+ ln -s port.c r_port.c
+ ln -s inndchannel.c dbzserver.c
+ ln -s innbbsd.c dbzinnbbsd.c
+ ln -s bbslib.c echobbslib.c
+
+remotetest: distribution
+ /usr/local/krb4/rcp /tmp/innbbsd-$(VERSION).tar.gz bbs_src.tar.gz skhuang:/tmp
+ /usr/local/krb4/rcp /tmp/innbbsd-$(VERSION).tar.gz bbs_src.tar.gz linux:/tmp
+ mv /u/staff/skhuang/.tcshrc /u/staff/skhuang/skhuang.tcshrc
+ rcp /tmp/innbbsd-$(VERSION).tar.gz bbs_src.tar.gz ccsun36:/tmp
+ rcp /tmp/innbbsd-$(VERSION).tar.gz bbs_src.tar.gz ccibm1:/tmp
+ mv /u/staff/skhuang/skhuang.tcshrc /u/staff/skhuang/.tcshrc
+ rcp /tmp/innbbsd-$(VERSION).tar.gz bbs_src.tar.gz cciris3:/tmp
+
+ftp: distribution patch
+ rsh ccsun42 mv /home8/ftp/pub/bbs/misc/innbbsd/innbbsd-$(VERSION).tar.gz /home8/ftp/pub/bbs/misc/innbbsd/.innbbsd-$(VERSION).tar.gz
+ rcp /tmp/innbbsd-$(VERSION).tar.gz ccsun42:/home8/ftp/pub/bbs/misc/innbbsd
+ rcp README* ccsun42:/home8/ftp/pub/bbs/misc/innbbsd
+ rcp /tmp/innbbsd-patch.$(LASTVERSION)-$(VERSION) ccsun42:/home8/ftp/pub/bbs/misc/innbbsd
+
+innbbspost.o: innbbspost.c
+ $(CC) $(CFLAGS) -I$(BBS_SRC) -c innbbspost.c
+
+makedbz: $(MOBJS)
+ $(CC) $(OPT) -o makedbz $(MOBJS) $(LDFLAGS)
+
+dbzserver.o: dbzserver.c
+ $(CC) $(CFLAGS) -DDBZSERVER -I$(BBS_SRC) -c dbzserver.c
+
+dbzinnbbsd.o: dbzinnbbsd.c
+ $(CC) $(CFLAGS) -DDBZSERVER -I$(BBS_SRC) -c dbzinnbbsd.c
+
+dbzserver: $(DBZOBJS)
+ $(CC) $(OPT) -o dbzserver $(DBZOBJS) $(LDFLAGS)
+
+bbsnnrp: $(NNRPOBJS)
+ $(CC) -o bbsnnrp $(NNRPOBJS) $(OPT) $(LDFLAGS)
+
+bbslink: $(LINKOBJS)
+ $(CC) -o bbslink $(LINKOBJS) $(OPT) $(LDFLAGS)
+
+bbslink2: $(LINKOBJS2)
+ $(CC) -o bbslink2 $(LINKOBJS2) $(OPT) $(LDFLAGS)
+
+ctlinnbbsd: $(CTLOBJS)
+ $(CC) $(OPT) -o ctlinnbbsd $(CTLOBJS) $(LDFLAGS)
+
+mkhistory: $(HOBJS)
+ $(CC) $(OPT) -o mkhistory $(HOBJS) $(LDFLAGS)
+
+dbz_query_sample: dbz_query_sample.o
+ $(CC) $(OPT) -o dbz_query_sample dbz_query_sample.o $(LDFLAGS)
+
+
+innbbsd: $(OBJS)
+# mv tnrpd.exe tnrpd.exe.old
+ $(CC) -o innbbsd $(OBJS) $(OPT) $(LDFLAGS)
+
+install: $(EXES)
+ install -d $(BBSHOME)/innd/
+ install -c -m 755 $(EXES) $(BBSHOME)/innd/
+
+clean:
+ rm -f *.o $(EXES) core innd/src/*.o
diff --git a/innbbsd/antisplam.h b/innbbsd/antisplam.h
new file mode 100644
index 00000000..30289da1
--- /dev/null
+++ b/innbbsd/antisplam.h
@@ -0,0 +1,37 @@
+#define char_lower(c) ((c >= 'A' && c <= 'Z') ? c|32 : c)
+
+/*void
+str_lower(t, s)
+ char *t, *s;*/
+void str_lower(char *t, char *s)
+{
+ register char ch;
+ do
+ {
+ ch = *s++;
+ *t++ = char_lower(ch);
+ } while (ch);
+}
+
+#if 0 /* string.h , libc */
+int
+strcasestr(str, tag)
+ char *str, *tag; /* tag : lower-case string */
+{
+ char buf[256];
+
+ str_lower(buf, str);
+ return (int) strstr(buf, tag);
+}
+#endif
+
+int
+bad_subject(char *subject)
+{
+ char *badkey[] = {"µL½X","avcd","mp3",NULL};
+ int i;
+ for(i=0; badkey[i]; i++)
+ if(strcasestr(subject, badkey[i])) return 1;
+ return 0;
+}
+
diff --git a/innbbsd/bbslib.c b/innbbsd/bbslib.c
new file mode 100644
index 00000000..0dc808c3
--- /dev/null
+++ b/innbbsd/bbslib.c
@@ -0,0 +1,712 @@
+#if defined( LINUX )
+# include "innbbsconf.h"
+# include "bbslib.h"
+# include <varargs.h>
+#else
+# include <varargs.h>
+# include "innbbsconf.h"
+# include "bbslib.h"
+#endif
+
+char INNBBSCONF[MAXPATHLEN];
+char INNDHOME[MAXPATHLEN];
+char HISTORY[MAXPATHLEN];
+char LOGFILE[MAXPATHLEN];
+char MYBBSID[MAXPATHLEN];
+char ECHOMAIL[MAXPATHLEN];
+char BBSFEEDS[MAXPATHLEN];
+char LOCALDAEMON[MAXPATHLEN];
+
+int His_Maint_Min= HIS_MAINT_MIN;
+int His_Maint_Hour= HIS_MAINT_HOUR;
+int Expiredays = EXPIREDAYS;
+
+nodelist_t *NODELIST=NULL, **NODELIST_BYNODE=NULL;
+newsfeeds_t *NEWSFEEDS=NULL, **NEWSFEEDS_BYBOARD=NULL;
+static char *NODELIST_BUF, *NEWSFEEDS_BUF;
+int NFCOUNT, NLCOUNT;
+int LOCALNODELIST=0, NONENEWSFEEDS=0;
+
+#ifndef _PATH_BBSHOME
+# define _PATH_BBSHOME "/u/staff/bbsroot/csie_util/bntpd/home"
+#endif
+
+static FILE *bbslogfp;
+
+static int
+verboseFlag=0;
+
+static char*
+verboseFilename=NULL;
+static char verbosename[MAXPATHLEN];
+
+verboseon(filename)
+char *filename;
+{
+ verboseFlag = 1;
+ if ( filename != NULL ) {
+ if (strchr(filename,'/') == NULL) {
+ sprintf(verbosename,"%s/innd/%s",BBSHOME,filename);
+ filename = verbosename;
+ }
+ }
+ verboseFilename = filename;
+}
+verboseoff()
+{
+ verboseFlag = 0;
+}
+
+setverboseon()
+{
+ verboseFlag = 1;
+}
+
+isverboselog()
+{
+ return verboseFlag;
+}
+
+setverboseoff()
+{
+ verboseoff();
+ if (bbslogfp != NULL) {
+ fclose(bbslogfp);
+ bbslogfp = NULL;
+ }
+}
+
+verboselog(va_alist)
+va_dcl
+{
+ va_list ap;
+ register char* fmt;
+ char datebuf[40];
+ time_t now;
+
+ if (verboseFlag == 0) return;
+
+ va_start(ap);
+
+ time(&now);
+ strftime(datebuf, sizeof(datebuf), "%b %d %X ", localtime(&now));
+
+ if (bbslogfp == NULL) {
+ if (verboseFilename != NULL)
+ bbslogfp = fopen(verboseFilename, "a");
+ else
+ bbslogfp = fdopen(1, "a");
+ }
+ if (bbslogfp == NULL) { va_end(ap); return; }
+ fmt = va_arg(ap, char *) ;
+ fprintf(bbslogfp,"%s[%d] ",datebuf, getpid());
+ vfprintf(bbslogfp, fmt, ap);
+ fflush(bbslogfp);
+ va_end(ap);
+}
+
+#ifdef PalmBBS
+xbbslog(va_alist)
+#else
+bbslog(va_alist)
+#endif
+va_dcl
+{
+ va_list ap;
+ register char* fmt;
+ char datebuf[40];
+ time_t now;
+
+ va_start(ap);
+
+ time(&now);
+ strftime(datebuf, sizeof(datebuf), "%b %d %X ", localtime(&now));
+
+ if (bbslogfp == NULL) {
+ bbslogfp = fopen(LOGFILE, "a");
+ }
+ if (bbslogfp == NULL) { va_end(ap); return; }
+ fmt = va_arg(ap, char *) ;
+ fprintf(bbslogfp,"%s[%d] ",datebuf,getpid());
+ vfprintf(bbslogfp, fmt, ap);
+ fflush(bbslogfp);
+ va_end(ap);
+}
+
+initial_bbs(outgoing)
+char *outgoing;
+{
+ FILE* FN;
+ struct stat st;
+ int fd, i;
+ char *bbsnameptr=NULL;
+
+/* reopen bbslog */
+ if (bbslogfp != NULL) {
+ fclose(bbslogfp);
+ bbslogfp = NULL;
+ }
+
+#ifdef WITH_ECHOMAIL
+ init_echomailfp();
+ init_bbsfeedsfp();
+#endif
+
+ LOCALNODELIST=0, NONENEWSFEEDS =0;
+ sprintf(INNDHOME,"%s/innd",BBSHOME);
+ sprintf(HISTORY, "%s/history",INNDHOME);
+ sprintf(LOGFILE, "%s/bbslog",INNDHOME);
+ sprintf(ECHOMAIL,"%s/echomail.log",BBSHOME);
+ sprintf(LOCALDAEMON,"%s/.innbbsd",INNDHOME);
+ sprintf(INNBBSCONF,"%s/innbbs.conf",INNDHOME);
+ sprintf(BBSFEEDS,"%s/bbsfeeds.log",INNDHOME);
+
+ if (isfile(INNBBSCONF)) {
+ FILE *conf;
+ char buffer[MAXPATHLEN];
+ conf = fopen(INNBBSCONF,"r");
+ if (conf != NULL) {
+ while (fgets( buffer, sizeof buffer, conf) != NULL) {
+ char *ptr, *front=NULL, *value=NULL, *value2=NULL, *value3=NULL;
+ if ( buffer[0] == '#' || buffer[0] == '\n') continue;
+ for ( front = buffer; *front && isspace(*front); front++);
+ for ( ptr = front; *ptr && !isspace(*ptr) ; ptr++) ;
+ if (*ptr == '\0') continue;
+ *ptr++ = '\0';
+ for ( ; *ptr && isspace(*ptr) ; ptr++) ;
+ if (*ptr == '\0') continue;
+ value = ptr++;
+ for ( ; *ptr && !isspace(*ptr) ; ptr++) ;
+ if (*ptr) {
+ *ptr++ = '\0';
+ for ( ; *ptr && isspace(*ptr) ; ptr++) ;
+ value2 = ptr++;
+ for ( ; *ptr && !isspace(*ptr) ; ptr++) ;
+ if (*ptr) {
+ *ptr++ = '\0';
+ for ( ; *ptr && isspace(*ptr) ; ptr++) ;
+ value3 = ptr++;
+ for ( ; *ptr && !isspace(*ptr) ; ptr++) ;
+ if (*ptr) {
+ *ptr++ = '\0';
+ }
+ }
+ }
+ if ( strcasecmp(front,"expiredays") == 0) {
+ Expiredays = atoi(value);
+ if (Expiredays < 0) {
+ Expiredays = EXPIREDAYS;
+ }
+ } else if ( strcasecmp(front,"expiretime") == 0) {
+ ptr = strchr(value,':');
+ if (ptr == NULL) {
+ fprintf(stderr, "Syntax error in innbbs.conf\n");
+ } else {
+ *ptr++ = '\0';
+ His_Maint_Hour = atoi(value);
+ His_Maint_Min = atoi(ptr);
+ if (His_Maint_Hour < 0)
+ His_Maint_Hour = HIS_MAINT_HOUR;
+ if (His_Maint_Min < 0)
+ His_Maint_Min = HIS_MAINT_MIN;
+ }
+ } else if ( strcasecmp(front,"newsfeeds") == 0) {
+ if (strcmp(value,"none")==0)
+ NONENEWSFEEDS = 1;
+ } else if ( strcasecmp(front,"nodelist") == 0) {
+ if (strcmp(value,"local")==0)
+ LOCALNODELIST = 1;
+ } /*else if ( strcasecmp(front,"newsfeeds") == 0) {
+ printf("newsfeeds %s\n", value);
+ } else if ( strcasecmp(front,"nodelist") == 0) {
+ printf("nodelist %s\n", value);
+ } else if ( strcasecmp(front,"bbsname") == 0) {
+ printf("bbsname %s\n", value);
+ } */
+ }
+ fclose(conf);
+ }
+ }
+
+#ifdef WITH_ECHOMAIL
+ bbsnameptr = (char*) fileglue("%s/bbsname.bbs",INNDHOME);
+ if ((FN = fopen( bbsnameptr ,"r" ))==NULL) {
+ fprintf(stderr,"can't open file %s\n", bbsnameptr);
+ return 0;
+ }
+ while ( fscanf(FN,"%s", MYBBSID) != EOF);
+ fclose(FN);
+ if( ! isdir(fileglue("%s/out.going",BBSHOME)) ) {
+ mkdir( (char*)fileglue("%s/out.going",BBSHOME), 0750 );
+ }
+ if (NONENEWSFEEDS == 0)
+ readnffile(INNDHOME);
+ if (LOCALNODELIST == 0) {
+ if (readnlfile(INNDHOME, outgoing) != 0) return 0;
+ }
+
+#endif
+ return 1;
+}
+
+static int
+nf_byboardcmp(a,b)
+newsfeeds_t **a, **b;
+{
+/*
+ if (!a || !*a || !(*a)->board) return -1;
+ if (!b || !*b || !(*b)->board) return 1;
+*/
+ return strcasecmp((*a)->board, (*b)->board);
+}
+
+static int
+nfcmp(a,b)
+newsfeeds_t *a, *b;
+{
+/*
+ if (!a || !a->newsgroups) return -1;
+ if (!b || !b->newsgroups) return 1;
+*/
+ return strcasecmp(a->newsgroups, b->newsgroups);
+}
+
+static int
+nlcmp(a,b)
+nodelist_t *a, *b;
+{
+/*
+ if (!a || !a->host) return -1;
+ if (!b || !b->host) return 1;
+*/
+ return strcasecmp(a->host, b->host);
+}
+
+static int
+nl_bynodecmp(a,b)
+nodelist_t **a, **b;
+{
+/*
+ if (!a || !*a || !(*a)->node) return -1;
+ if (!b || !*b || !(*b)->node) return 1;
+*/
+ return strcasecmp((*a)->node, (*b)->node);
+}
+
+/* read in newsfeeds.bbs and nodelist.bbs */
+readnlfile(inndhome, outgoing)
+char *inndhome;
+char *outgoing;
+{
+ FILE *fp;
+ char buff[1024];
+ struct stat st;
+ int i, count, j;
+ char *ptr, *nodelistptr;
+ static lastcount=0;
+
+ sprintf(buff,"%s/nodelist.bbs", inndhome);
+ fp = fopen(buff,"r");
+ if (fp == NULL) {
+ fprintf(stderr,"open fail %s",buff);
+ return -1;
+ }
+ if (fstat(fileno(fp),&st) != 0) {
+ fprintf(stderr,"stat fail %s", buff);
+ return -1;
+ }
+ if (NODELIST_BUF == NULL) {
+ NODELIST_BUF = (char*) mymalloc( st.st_size +1);
+ } else {
+ NODELIST_BUF = (char*) myrealloc( NODELIST_BUF, st.st_size +1);
+ }
+ i = 0, count =0;
+ while (fgets(buff, sizeof buff, fp) != NULL) {
+ if (buff[0] == '#') continue;
+ if (buff[0] == '\n') continue;
+ strcpy(NODELIST_BUF+i, buff);
+ i += strlen(buff);
+ count ++;
+ }
+ fclose(fp);
+ if (NODELIST == NULL) {
+ NODELIST = (nodelist_t*) mymalloc(sizeof(nodelist_t) * (count+1));
+ NODELIST_BYNODE = (nodelist_t**) mymalloc(sizeof(nodelist_t*) * (count+1));
+ } else {
+ NODELIST = (nodelist_t*) myrealloc(NODELIST, sizeof(nodelist_t) * (count+1));
+ NODELIST_BYNODE = (nodelist_t**) myrealloc(NODELIST_BYNODE, sizeof(nodelist_t*) * (count+1));
+ }
+ for (i=lastcount; i< count; i++) {
+ NODELIST[i].feedfp = NULL;
+ }
+ lastcount = count;
+ NLCOUNT = 0;
+ for (ptr = NODELIST_BUF; (nodelistptr = (char*)strchr(ptr,'\n')) != NULL; ptr = nodelistptr +1, NLCOUNT++) {
+ char *nptr , *bptr, *pptr, *tptr;
+ *nodelistptr = '\0';
+ NODELIST[NLCOUNT].host = "";
+ NODELIST[NLCOUNT].exclusion = "";
+ NODELIST[NLCOUNT].node = "";
+ NODELIST[NLCOUNT].protocol = "IHAVE(119)";
+ NODELIST[NLCOUNT].comments = "";
+ NODELIST_BYNODE[NLCOUNT] = NODELIST+NLCOUNT;
+ for (nptr= ptr ;*nptr && isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') {
+ bbslog("nodelist.bbs %d entry read error\n", NLCOUNT);
+ return -1;
+ }
+ /*NODELIST[NLCOUNT].id = nptr;*/
+ NODELIST[NLCOUNT].node = nptr;
+ for (nptr++; *nptr && !isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') {
+ bbslog("nodelist.bbs node %d entry read error\n", NLCOUNT);
+ return -1;
+ }
+ *nptr = '\0';
+ if ((tptr = strchr(NODELIST[NLCOUNT].node,'/'))) {
+ *tptr = '\0';
+ NODELIST[NLCOUNT].exclusion = tptr + 1;
+ } else {
+ NODELIST[NLCOUNT].exclusion = "";
+ }
+ for (nptr++ ;*nptr && isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ if (*nptr=='+' || *nptr=='-') {
+ NODELIST[NLCOUNT].feedtype = *nptr;
+ if (NODELIST[NLCOUNT].feedfp != NULL) {
+ fclose(NODELIST[NLCOUNT].feedfp);
+ }
+ if ( NODELIST[NLCOUNT].feedtype == '+')
+ if (outgoing != NULL) {
+ NODELIST[NLCOUNT].feedfp = fopen((char*)fileglue("%s/out.going/%s.%s",BBSHOME, NODELIST[NLCOUNT].node, outgoing),"a");
+ }
+ nptr++;
+ } else {
+ NODELIST[NLCOUNT].feedtype = ' ';
+ }
+ NODELIST[NLCOUNT].host = nptr;
+ for (nptr++; *nptr && !isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') {
+ continue;
+ }
+ *nptr = '\0';
+ for (nptr++;*nptr && isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ NODELIST[NLCOUNT].protocol = nptr;
+ for (nptr++; *nptr && !isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ *nptr = '\0';
+ for (nptr++;*nptr && strchr(" \t\r\n",*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ NODELIST[NLCOUNT].comments = nptr;
+ }
+ qsort(NODELIST, NLCOUNT, sizeof(nodelist_t), nlcmp);
+ qsort(NODELIST_BYNODE, NLCOUNT, sizeof(nodelist_t*), nl_bynodecmp);
+ return 0;
+}
+
+readnffile(inndhome)
+char *inndhome;
+{
+ FILE *fp;
+ char buff[1024];
+ struct stat st;
+ int i, count;
+ char *ptr, *newsfeedsptr;
+
+ sprintf(buff,"%s/newsfeeds.bbs", inndhome);
+ fp = fopen(buff,"r");
+ if (fp == NULL) {
+ fprintf(stderr,"open fail %s",buff);
+ return -1;
+ }
+ if (fstat(fileno(fp),&st) != 0) {
+ fprintf(stderr,"stat fail %s", buff);
+ return -1;
+ }
+ if (NEWSFEEDS_BUF == NULL) {
+ NEWSFEEDS_BUF = (char*) mymalloc( st.st_size +1);
+ } else {
+ NEWSFEEDS_BUF = (char*) myrealloc( NEWSFEEDS_BUF, st.st_size +1);
+ }
+ i = 0, count =0;
+ while (fgets(buff, sizeof buff, fp) != NULL) {
+ if (buff[0] == '#') continue;
+ if (buff[0] == '\n') continue;
+ strcpy(NEWSFEEDS_BUF+i, buff);
+ i += strlen(buff);
+ count ++;
+ }
+ fclose(fp);
+ if (NEWSFEEDS == NULL) {
+ NEWSFEEDS = (newsfeeds_t*) mymalloc(sizeof(newsfeeds_t) * (count+1));
+ NEWSFEEDS_BYBOARD = (newsfeeds_t**) mymalloc(sizeof(newsfeeds_t*) * (count+1));
+ } else {
+ NEWSFEEDS = (newsfeeds_t*) myrealloc(NEWSFEEDS, sizeof(newsfeeds_t) * (count+1));
+ NEWSFEEDS_BYBOARD = (newsfeeds_t**) myrealloc(NEWSFEEDS_BYBOARD, sizeof(newsfeeds_t*) * (count+1));
+ }
+ NFCOUNT = 0;
+ for (ptr = NEWSFEEDS_BUF; (newsfeedsptr = (char*)strchr(ptr,'\n')) != NULL; ptr = newsfeedsptr +1, NFCOUNT++) {
+ char *nptr , *bptr, *pptr;
+ *newsfeedsptr = '\0';
+ NEWSFEEDS[NFCOUNT].newsgroups = "";
+ NEWSFEEDS[NFCOUNT].board = "";
+ NEWSFEEDS[NFCOUNT].path = NULL;
+ NEWSFEEDS_BYBOARD[NFCOUNT] = NEWSFEEDS+NFCOUNT;
+ for (nptr= ptr ;*nptr && isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ NEWSFEEDS[NFCOUNT].newsgroups = nptr;
+ for (nptr++; *nptr && !isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ *nptr = '\0';
+ for (nptr++ ;*nptr && isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ NEWSFEEDS[NFCOUNT].board = nptr;
+ for (nptr++; *nptr && !isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ *nptr = '\0';
+ for (nptr++;*nptr && isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ NEWSFEEDS[NFCOUNT].path = nptr;
+ for (nptr++; *nptr && !strchr("\r\n",*nptr); ) nptr++;
+ *nptr = '\0';
+ }
+ qsort(NEWSFEEDS, NFCOUNT, sizeof(newsfeeds_t), nfcmp);
+ qsort(NEWSFEEDS_BYBOARD, NFCOUNT, sizeof(newsfeeds_t*), nf_byboardcmp);
+}
+
+newsfeeds_t *search_board(board)
+char *board;
+{
+ newsfeeds_t nft, *nftptr, **find;
+ if (NONENEWSFEEDS) return NULL;
+ nft.board = board;
+ nftptr = &nft;
+ find = (newsfeeds_t**)bsearch((char*)&nftptr, NEWSFEEDS_BYBOARD, NFCOUNT, sizeof(newsfeeds_t*), nf_byboardcmp);
+ if (find != NULL) return *find;
+ return NULL;
+}
+
+nodelist_t *search_nodelist_bynode(node)
+char *node;
+{
+ nodelist_t nlt, *nltptr, **find;
+ if (LOCALNODELIST) return NULL;
+ nlt.node = node;
+ nltptr = &nlt;
+ find = (nodelist_t**)bsearch((char*)&nltptr, NODELIST_BYNODE, NLCOUNT, sizeof(nodelist_t*), nl_bynodecmp);
+ if (find != NULL) return *find;
+ return NULL;
+}
+
+
+nodelist_t *search_nodelist(site, identuser)
+char *site;
+char *identuser;
+{
+ nodelist_t nlt, *find;
+ char buffer[1024];
+ if (LOCALNODELIST) return NULL;
+ nlt.host = site;
+ find = (nodelist_t*)bsearch((char*)&nlt, NODELIST, NLCOUNT, sizeof(nodelist_t), nlcmp);
+ if (find == NULL && identuser != NULL) {
+ sprintf(buffer,"%s@%s", identuser, site);
+ nlt.host = buffer;
+ find = (nodelist_t*)bsearch((char*)&nlt, NODELIST, NLCOUNT, sizeof(nodelist_t), nlcmp);
+ }
+ return find;
+}
+
+newsfeeds_t *search_group(newsgroup)
+char *newsgroup;
+{
+ newsfeeds_t nft, *find;
+ if (NONENEWSFEEDS) return NULL;
+ nft.newsgroups = newsgroup;
+ find = (newsfeeds_t*)bsearch((char*)&nft, NEWSFEEDS, NFCOUNT, sizeof(newsfeeds_t), nfcmp);
+ return find;
+}
+
+char *ascii_date(now)
+time_t now;
+{
+ static char datebuf[40];
+ /*time_t now;
+ time(&now);*/
+ strftime(datebuf, sizeof(datebuf), "%d %b %Y %X GMT", gmtime(&now));
+ return datebuf;
+}
+
+char *
+restrdup(ptr, string)
+char *ptr;
+char *string;
+{
+ int len ;
+ if (string == NULL) {
+ if (ptr != NULL) *ptr = '\0';
+ return ptr;
+ }
+ len = strlen(string) + 1;
+ if (ptr != NULL) {
+ ptr = (char*)myrealloc(ptr, len);
+ } else
+ ptr = (char*)mymalloc(len);
+ strcpy(ptr, string);
+ return ptr;
+}
+
+
+
+void *
+mymalloc(size)
+int size;
+{
+ char *ptr = (char*)malloc(size);
+ if (ptr == NULL) {
+ fprintf(stderr, "cant allocate memory\n");
+ syslog(LOG_ERR, "cant allocate memory %m");
+ exit(1);
+ }
+ return ptr;
+}
+
+void *
+myrealloc(optr, size)
+void *optr;
+int size;
+{
+ char *ptr = (char*)realloc(optr, size);
+ if (ptr == NULL) {
+ fprintf(stderr, "cant allocate memory\n");
+ syslog(LOG_ERR, "cant allocate memory %m");
+ exit(1);
+ }
+ return ptr;
+}
+
+testandmkdir(dir)
+char *dir;
+{
+ if (!isdir(dir)) {
+ char path[MAXPATHLEN+12];
+ sprintf(path,"mkdir -p %s",dir);
+ system(path);
+ }
+}
+
+static char splitbuf[2048];
+static char joinbuf[1024];
+#define MAXTOK 50
+static char* Splitptr[MAXTOK];
+char **split(line,pat)
+char *line,*pat;
+{
+ char *p;
+ int i;
+
+ for (i=0;i<MAXTOK;++i) Splitptr[i] = NULL;
+ strncpy(splitbuf,line,sizeof splitbuf - 1 );
+ /*printf("%d %d\n",strlen(line),strlen(splitbuf));*/
+ splitbuf[sizeof splitbuf - 1] = '\0';
+ for (i=0,p=splitbuf;*p && i< MAXTOK -1 ;){
+ for (Splitptr[i++]=p;*p && !strchr(pat,*p);p++);
+ if (*p=='\0') break;
+ for (*p++='\0'; *p && strchr(pat,*p);p++);
+ }
+ return Splitptr;
+}
+
+char **BNGsplit(line)
+char *line;
+{
+ char **ptr = split(line,",");
+ newsfeeds_t *nf1, *nf2;
+ char *n11, *n12, *n21, *n22;
+ int i,j;
+ for (i=0; ptr[i] != NULL; i++) {
+ nf1 = (newsfeeds_t*)search_group(ptr[i]);
+ for (j=i+1; ptr[j] != NULL; j++) {
+ if (strcmp(ptr[i],ptr[j])==0) {
+ *ptr[j] = '\0';
+ continue;
+ }
+ nf2 = (newsfeeds_t*)search_group(ptr[j]);
+ if (nf1 && nf2) {
+ if (strcmp(nf1->board,nf2->board)==0) {
+ *ptr[j] = '\0';
+ continue;
+ }
+ for (n11 = nf1->board, n12 = (char*)strchr(n11,',');
+ n11 && *n11 ; n12 = (char*) strchr(n11,',')) {
+ if (n12) *n12 = '\0';
+ for (n21 = nf2->board, n22 = (char*)strchr(n21,',');
+ n21 && *n21 ; n22 = (char*) strchr(n21,',')) {
+ if (n22) *n22 = '\0';
+ if (strcmp(n11,n21)==0) {
+ *n21 = '\t';
+ }
+ if (n22) {
+ *n22 = ',';
+ n21 = n22 + 1;
+ } else
+ break;
+ }
+ if (n12) {
+ *n12 = ',';
+ n11 = n12 +1;
+ } else
+ break;
+ }
+ }
+ }
+ }
+ return ptr;
+}
+
+char **ssplit(line,pat)
+char *line,*pat;
+{
+ char *p;
+ int i;
+ for (i=0;i<MAXTOK;++i) Splitptr[i] = NULL;
+ strncpy(splitbuf,line,1024);
+ for (i=0,p=splitbuf;*p && i< MAXTOK;){
+ for (Splitptr[i++]=p;*p && !strchr(pat,*p);p++);
+ if (*p=='\0') break;
+ *p=0;p++;
+/* for (*p='\0'; strchr(pat,*p);p++);*/
+ }
+ return Splitptr;
+}
+
+char *join(lineptr,pat,num)
+char **lineptr,*pat;
+int num;
+{
+ int i;
+ joinbuf[0] = '\0';
+ if (lineptr[0] != NULL)
+ strncpy(joinbuf,lineptr[0],1024);
+ else {
+ joinbuf[0]='\0';
+ return joinbuf;
+ }
+ for (i=1;i<num;i++) {
+ strcat(joinbuf,pat);
+ if (lineptr[i] != NULL)
+ strcat(joinbuf,lineptr[i]);
+ else
+ break;
+ }
+ return joinbuf;
+}
+
+#ifdef BBSLIB
+main()
+{
+ initial_bbs("feed");
+ printf("%s\n",ascii_date());
+}
+#endif
+
diff --git a/innbbsd/bbslib.h b/innbbsd/bbslib.h
new file mode 100644
index 00000000..190672b7
--- /dev/null
+++ b/innbbsd/bbslib.h
@@ -0,0 +1,62 @@
+#ifndef BBSLIB_H
+#define BBSLIB_H
+
+typedef struct nodelist_t {
+ char *node;
+ char *exclusion;
+ char *host;
+ char *protocol;
+ char *comments;
+ int feedtype;
+ FILE *feedfp;
+} nodelist_t;
+
+typedef struct newsfeeds_t {
+ char *newsgroups;
+ char *board;
+ char *path;
+} newsfeeds_t;
+
+typedef struct overview_t {
+ char *board, *filename, *group;
+ time_t mtime;
+ char *from, *subject;
+} overview_t;
+
+extern char MYBBSID[];
+extern char ECHOMAIL[];
+extern char BBSFEEDS[];
+extern char LOCALDAEMON[];
+extern char INNDHOME[];
+extern char HISTORY[];
+extern char LOGFILE[];
+extern char INNBBSCONF[];
+extern nodelist_t *NODELIST;
+extern nodelist_t **NODELIST_BYNODE;
+extern newsfeeds_t *NEWSFEEDS, **NEWSFEEDS_BYBOARD;
+extern int NFCOUNT, NLCOUNT;
+extern int Expiredays, His_Maint_Min, His_Maint_Hour;
+extern int LOCALNODELIST, NONENEWSFEEDS;
+extern int Maxclient;
+
+# ifndef ARG
+# ifdef __STDC__
+# define ARG(x) x
+# else
+# define ARG(x) ()
+# endif
+# endif
+
+int initial_bbs ARG((char* ));
+char *restrdup ARG((char *, char *));
+nodelist_t *search_nodelist ARG((char *, char *));
+newsfeeds_t *search_group ARG((char *));
+int bbslog ARG(());
+void *mymalloc ARG((int));
+void *myrealloc ARG((void *, int));
+
+#ifdef PalmBBS
+#define bbslog xbbslog
+#endif
+
+#endif
diff --git a/innbbsd/bbslink.c b/innbbsd/bbslink.c
new file mode 100644
index 00000000..2b0b6f37
--- /dev/null
+++ b/innbbsd/bbslink.c
@@ -0,0 +1,2021 @@
+#if defined( LINUX )
+# include "innbbsconf.h"
+# include "bbslib.h"
+# include <varargs.h>
+#else
+# include <varargs.h>
+# include "innbbsconf.h"
+# include "bbslib.h"
+#endif
+#include "antisplam.h"
+
+#include <sys/mman.h>
+
+#ifndef AIX
+# include <sys/fcntl.h>
+#endif
+
+#if defined(PalmBBS)
+#include <utime.h>
+#endif
+
+
+#include "daemon.h"
+#include "nntp.h"
+#include "externs.h"
+
+/*
+ * TODO 1. read newsfeeds.bbs, read nodelist.bbs, read bbsname.bbs 2. scan
+ * new posts and append to .link 3. rename .link to .send (must lock) 4.
+ * start to send .send out and append not sent to .link
+ *
+ * 5. node.LOCK (with pid) 6. log articles sent
+ */
+
+
+#ifndef MAXBUFLEN
+#define MAXBUFLEN 256
+#endif
+
+#define MAX_OUTGO_POST 100 /* bbslink ¤@¦¸³B²zªºÂà¥X³Ì¤j¤å³¹¼Æ¶q */
+
+typedef struct my_out_bntp
+{
+ char *board, *filename, *userid, *nickname, *subject;
+} my_out_bntp;
+struct my_out_bntp out_bntp[MAX_OUTGO_POST];
+
+int outgo_post=0;
+
+typedef struct Over_t
+{
+ time_t mtime;
+ char date[MAXBUFLEN];
+ char nickname[MAXBUFLEN];
+ char subject[MAXBUFLEN];
+ char from[MAXBUFLEN];
+ char msgid[MAXBUFLEN];
+ char site[MAXBUFLEN];
+ char board[MAXBUFLEN];
+} linkoverview_t;
+
+typedef struct SendOver_t
+{
+ char *board, *filename, *group, *from, *subject;
+ char *outgoingtype, *msgid, *path;
+ char *date, *control;
+ time_t mtime;
+} soverview_t;
+
+typedef struct Stat_t
+{
+ int localsendout;
+ int localfailed;
+ int remotesendout;
+ int remotefailed;
+} stat_t;
+
+static stat_t *BBSLINK_STAT;
+
+static int NoAction = 0;
+static int Verbose = 0;
+static int VisitOnly = 0;
+static int NoVisit = 0;
+static char *DefaultFeedSite = "";
+static int KillFormerBBSLINK = 0;
+
+extern char *SITE;
+extern char *GROUPS;
+
+char NICKNAME[MAXBUFLEN];
+
+char DATE_BUF[MAXBUFLEN];
+extern char *DATE;
+
+char FROM_BUF[MAXBUFLEN];
+extern char *FROM;
+
+#ifndef MapleBBS
+char POSTER_BUF[MAXBUFLEN];
+char *POSTER;
+#endif
+
+char MYADDR[MAXBUFLEN];
+char MYSITE[MAXBUFLEN];
+
+char SUBJECT_BUF[MAXBUFLEN];
+extern char *SUBJECT;
+
+char MSGID_BUF[MAXBUFLEN];
+extern char *MSGID;
+
+char LINKPROTOCOL[MAXBUFLEN];
+int LINKPORT;
+char ORGANIZATION[MAXBUFLEN];
+char NEWSCONTROL[MAXBUFLEN];
+char NEWSAPPROVED[MAXBUFLEN];
+char NNTPHOST_BUF[MAXBUFLEN];
+extern char *NNTPHOST;
+char PATH_BUF[MAXBUFLEN];
+extern char *PATH;
+
+char CONTROL_BUF[MAXBUFLEN];
+extern char *CONTROL;
+
+char *BODY, *HEAD;
+
+int USEIHAVE = 1;
+int USEPOST = 0;
+int USEDATA = 0;
+int FEEDTYPE = ' ';
+
+int NNTP = -1;
+FILE *NNTPrfp = NULL;
+FILE *NNTPwfp = NULL;
+char NNTPbuffer[1024];
+static char *NEWSFEED;
+static char *REMOTE = "REMOTE";
+static char *LOCAL = "LOCAL";
+
+static int FD, FD_SIZE;
+static char *FD_BUF;
+static char *FD_END;
+
+static char *COMMENT = "\n";
+/*"[Ptt °e¥X]\n";*/
+
+char *fileglue();
+int
+is_outgo_post(board, filename, userid, nickname, subject)
+ char *board, *filename, *userid, *nickname, *subject;
+{
+ int mypost;
+
+ for (mypost = 0; mypost < outgo_post; mypost++)
+ {
+ if (!strcmp(out_bntp[mypost].filename, filename))
+ if (!strcmp(out_bntp[mypost].userid, userid))
+ if (!strcmp(out_bntp[mypost].board, board))
+ if (!strcmp(out_bntp[mypost].nickname, nickname))
+ if (!strcmp(out_bntp[mypost].subject, subject)){
+ if (Verbose)
+ printf("bad_cancel: %s, %s(%s), %s, %s\n",
+ board, userid, nickname, subject, filename);
+ bbslog("bad_cancel: %s, %s(%s), %s, %s\n",
+ board, userid, nickname, subject, filename);
+ return 1;
+ }
+ }
+ return 0;
+}
+/*
+woju
+Cross-fs rename()
+*/
+
+Rename(char* src, char* dst)
+{
+ char cmd[200];
+
+ if (rename(src, dst) == 0)
+ return 0;
+
+ sprintf(cmd, "/bin/mv %s %s", src, dst);
+ return system(cmd);
+
+}
+
+
+bbslink_un_lock(file)
+ char *file;
+{
+ char *lockfile = fileglue("%s.LOCK", file);
+
+ if (isfile(lockfile))
+ unlink(lockfile);
+}
+
+bbslink_get_lock(file)
+ char *file;
+{
+ int lockfd;
+ char LockFile[MAXPATHLEN];
+
+ strncpy(LockFile, (char *) fileglue("%s.LOCK", file), sizeof LockFile);
+ if ((lockfd = open(LockFile, O_RDONLY)) >= 0)
+ {
+ char buf[10];
+ int pid;
+
+ if (read(lockfd, buf, sizeof buf) > 0 &&
+ (pid = atoi(buf)) > 0 && kill(pid, 0) == 0)
+ {
+ if (KillFormerBBSLINK)
+ {
+ kill(pid, SIGTERM);
+ unlink(LockFile);
+ }
+ else
+ {
+ fprintf(stderr, "another process [%d] running\n", pid);
+ return 0;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "no process [%d] running, but lock file existed, unlinked\n", pid);
+ unlink(LockFile);
+ }
+ close(lockfd);
+ }
+
+ if ((lockfd = open(LockFile, O_RDWR | O_CREAT | O_EXCL, 0644)) < 0)
+ {
+ fprintf(stderr, "lock %s error: another bbslink process running\n", LockFile);
+ return 0;
+ }
+ else
+ {
+ char buf[10];
+ int pid;
+
+ sprintf(buf, "%-.8d\n", getpid());
+ write(lockfd, buf, strlen(buf));
+ close(lockfd);
+ return 1;
+ }
+}
+
+
+int
+tcpcommand(va_alist)
+va_dcl
+{
+ va_list ap;
+ register char *fmt;
+ char *ptr;
+
+ va_start(ap);
+ fmt = va_arg(ap, char *);
+ vfprintf(NNTPwfp, fmt, ap);
+ fprintf(NNTPwfp, "\r\n");
+ fflush(NNTPwfp);
+
+ fgets(NNTPbuffer, sizeof NNTPbuffer, NNTPrfp);
+ ptr = strchr(NNTPbuffer, '\r');
+ if (ptr)
+ *ptr = '\0';
+ ptr = strchr(NNTPbuffer, '\n');
+ if (ptr)
+ *ptr = '\0';
+ va_end(ap);
+ return atoi(NNTPbuffer);
+}
+
+char *
+tcpmessage()
+{
+ char *ptr;
+
+ ptr = strchr(NNTPbuffer, ' ');
+ if (ptr)
+ return ptr;
+ return NNTPbuffer;
+}
+
+read_article(lover, filename, userid)
+ linkoverview_t *lover;
+ char *filename, *userid;
+{
+ FILE *fp;
+ int fd;
+ struct stat st;
+ time_t mtime;
+ char *buffer;
+ char *artptr, *artend, *artback;
+
+ if (stat(filename, &st) != 0)
+ return 0;
+ lover->mtime = st.st_mtime;
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ {
+ bbslog("<bbslink> Err: can't open %s\n", filename);
+ return 0;
+ }
+
+ if (FD_BUF == NULL)
+ {
+ FD_BUF = mymalloc(st.st_size + 1 + strlen(COMMENT));
+ }
+ else
+ {
+ FD_BUF = myrealloc(FD_BUF, st.st_size + 1 + strlen(COMMENT));
+ }
+ FD_BUF[st.st_size] = '\0';
+ read(fd, FD_BUF, st.st_size);
+ sprintf(FD_BUF + st.st_size, "%s", COMMENT);
+ st.st_size += strlen(COMMENT);
+ FD_SIZE = st.st_size;
+ for (buffer = FD_BUF, artend = FD_BUF + st.st_size,
+ artback = strchr(buffer, '\n');
+ buffer && buffer < artend && *buffer;
+ artback = strchr(buffer, '\n')
+ )
+ {
+ /* while( fgets(buffer, sizeof buffer, fp) != NULL) { */
+ char *m, *n;
+ char *ptr;
+
+ if (artback != NULL)
+ *artback = '\0';
+ if (*buffer == '\0')
+ break;
+
+#ifndef MapleBBS
+ if (strstr(buffer, userid) != NULL)
+ {
+ m = strchr(buffer, '(');
+ n = strrchr(buffer, ')');
+ if (m != NULL && n != NULL)
+ {
+ strncpy(lover->nickname, m + 1, n - m - 1);
+ lover->nickname[n - m - 1] = '\0';
+ }
+ else
+ {
+ *lover->nickname = '\0';
+ }
+ }
+ else if (strncmp(buffer, "Date: ", 11) == 0)
+ {
+ strcpy(lover->date, buffer + 11);
+ }
+ else if (strncmp(buffer, "µo«H¯¸: ", 8) == 0)
+ {
+ m = strchr(buffer, '(');
+ n = strrchr(buffer, ')');
+ strncpy(lover->date, m + 1, n - m - 1);
+ lover->date[n - m - 1] = '\0';
+ }
+#endif
+
+ if (artback != NULL)
+ {
+ *artback = '\n';
+ buffer = artback + 1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (artback != NULL)
+ BODY = artback + 1;
+ else
+ BODY = "";
+ close(fd);
+ return 1;
+}
+
+save_outgoing(sover, filename, userid, poster, mtime)
+ soverview_t *sover, *filename, *userid, *poster;
+ time_t mtime;
+{
+ newsfeeds_t *nf;
+ char *group, *server, *serveraddr;
+ char *subject, *path;
+ char *board;
+ char *ptr1, *ptr2;
+
+ board = sover->board;
+
+ PATH = MYBBSID;
+ nf = (newsfeeds_t *) search_board(board);
+ if (nf == NULL)
+ {
+ bbslog("<bbslink> save_outgoing: No such board %s\n", board);
+ return;
+ }
+ else
+ {
+ group = nf->newsgroups;
+ server = nf->path;
+ }
+ if (!server || !*server)
+ {
+ sprintf(PATH_BUF, "%.*s (local)", sizeof PATH_BUF - 9, MYBBSID);
+ PATH = PATH_BUF;
+ serveraddr = "";
+ sover->path = PATH;
+ }
+ for (ptr1 = server; ptr1 && *ptr1;)
+ {
+ nodelist_t *nl;
+ char savech;
+
+ for (; *ptr1 && isspace(*ptr1); ptr1++);
+ if (!*ptr1)
+ break;
+ for (ptr2 = ptr1; *ptr2 && !isspace(*ptr2); ptr2++);
+ savech = *ptr2;
+ *ptr2 = '\0';
+ nl = (nodelist_t *) search_nodelist_bynode(ptr1);
+ *ptr2 = savech;
+ ptr1 = ptr2++;
+ if (nl == NULL)
+ continue;
+ /* if (nl->feedfp == NULL) continue; */
+
+ if (nl->host && *nl->host)
+ {
+ if (nl->feedfp == NULL)
+ {
+ nl->feedfp = fopen(fileglue("%s/%s.link", INNDHOME, nl->node), "a");
+ if (nl->feedfp == NULL)
+ {
+ bbslog("<save outgoing> append failed for %s/%s.link", INNDHOME, nl->node);
+ }
+ }
+ if (nl->feedfp != NULL)
+ {
+ flock(fileno(nl->feedfp), LOCK_EX);
+ fprintf(nl->feedfp, "%s\t%s\t%s\t%ld\t%s\t%s\n", sover->board, filename, group, mtime, FROM, sover->subject);
+ fflush(nl->feedfp);
+ flock(fileno(nl->feedfp), LOCK_UN);
+ }
+ }
+ if (savech == '\0')
+ break;
+ }
+}
+
+
+#ifndef MapleBBS
+save_article(board, filename, sover)
+ char *board, *filename;
+ soverview_t *sover;
+{
+ FILE *FN;
+
+ if (Verbose)
+ printf("<save_article> %s %s\n", board, filename);
+ FN = fopen(fileglue("%s/boards/%s/%s", BBSHOME, board, filename), "w");
+ if (FN == NULL)
+ {
+ bbslog("<save_article> err: %s %s\n", board, filename);
+ if (Verbose)
+ printf("<save_article> err: %s %s\n", board, filename);
+ return 0;
+ }
+ flock(fileno(FN), LOCK_EX);
+ fprintf(FN, "µo«H¤H: %s, «H°Ï: %s\n", POSTER, sover->board);
+ fprintf(FN, "¼Ð ÃD: %s\n", sover->subject);
+ fprintf(FN, "µo«H¯¸: %s (%s)\n", MYSITE, sover->date);
+ fprintf(FN, "Âà«H¯¸: %s\n", sover->path);
+ fprintf(FN, "\n");
+ fputs(BODY, FN);
+ flock(fileno(FN), LOCK_UN);
+ fclose(FN);
+
+#if defined(PalmBBS)
+ {
+ struct utimbuf times;
+
+ times.actime = sover->mtime;
+ times.modtime = sover->mtime;
+ utime(fileglue("%s/boards/%s/%s", BBSHOME, board, filename), &times);
+ utime(fileglue("%s/.bcache/%s", BBSHOME, board), NULL);
+ }
+#endif
+}
+#endif
+
+/* process_article() read_article() save_outgoing() save_article() */
+
+process_article(board, filename, userid, nickname, subject)
+ char *board, *filename, *userid, *nickname, *subject;
+{
+ char *n, *filepath;
+ char poster[MAXBUFLEN];
+ soverview_t sover;
+
+ if (!*userid)
+ {
+ return;
+ }
+ else if (!subject || !*subject)
+ {
+ subject = "µLÃD";
+ }
+ filepath = fileglue("%s/boards/%s/%s", BBSHOME, board, filename);
+ if (isfile(filepath))
+ {
+ linkoverview_t lover;
+
+ if (read_article(&lover, filepath, userid))
+ {
+
+#ifndef MapleBBS
+ strncpy(POSTER_BUF, fileglue("%s@%s (%s)", userid, MYBBSID, nickname), sizeof POSTER_BUF);
+ POSTER = POSTER_BUF;
+#endif
+
+ strncpy(FROM_BUF, fileglue("%s.bbs@%s (%s)", userid, MYADDR, nickname), sizeof FROM_BUF);
+ FROM = FROM_BUF;
+ sover.from = FROM;
+ sover.board = board;
+ sover.subject = subject;
+ PATH = MYBBSID;
+ sover.path = MYBBSID;
+ sover.date = lover.date;
+ sover.mtime = lover.mtime;
+ if (!VisitOnly)
+ {
+ save_outgoing(&sover, filename, userid, poster, lover.mtime);
+
+#ifndef MapleBBS
+ save_article(board, filename, &sover);
+#endif
+ }
+ }
+ }
+}
+
+
+char *
+baseN(val, base, len)
+ int val, base, len;
+{
+ int n, ans;
+ static char str[MAXBUFLEN];
+ char *pstr = str;
+ int index;
+
+ for (index = len - 1; index >= 0; index--)
+ {
+ n = val % base;
+ val /= base;
+ if (n < 10)
+ {
+ n += '0';
+ }
+ else if (n < 36)
+ {
+ n += 'A' - 10;
+ }
+ else if (n < 62)
+ {
+ n += 'a' - 36;
+ }
+ else
+ {
+ n = '_';
+ }
+ str[index] = n;
+ }
+ str[len] = '\0';
+ return str;
+}
+
+char *
+hash_value(str)
+ char *str;
+{
+ int val, n;
+ char *ptr;
+
+ if (*str)
+ ptr = str + strlen(str) - 1;
+ else
+ ptr = str;
+ val = 0;
+ while (ptr >= str)
+ {
+ n = *ptr;
+ val = (val + n * 0x100) ^ n;
+ ptr--;
+ }
+ return baseN(val, 64, 3);
+}
+
+/* process_cancel() save_outgoing() hash_value(); baseN(); ascii_date(); */
+
+
+read_outgoing(sover)
+ soverview_t *sover;
+{
+ char *board, *filename, *group, *from, *subject, *outgoingtype, *msgid, *path;
+ char *buffer, *bufferp;
+ FILE *ECHOMAIL, *FN;
+ char *hash;
+ char times[MAXBUFLEN];
+ time_t mtime;
+
+ board = sover->board;
+ filename = sover->filename;
+ group = sover->group;
+ mtime = sover->mtime;
+ from = sover->from;
+ subject = sover->subject;
+ outgoingtype = sover->outgoingtype;
+ msgid = sover->msgid;
+ path = sover->path;
+ if (Verbose)
+ {
+ printf("<read_outgoing> %s:%s:%s\n", board, filename, group);
+ printf(" => %ld:%s\n", mtime, from);
+ printf(" => %s\n", subject);
+ printf(" => %s:%s\n", outgoingtype, msgid);
+ printf(" => %s\n", path);
+ }
+ if (NEWSFEED == LOCAL)
+ {
+ char *end = strrchr(filename, '.');
+
+ if (end)
+ *end = '\0';
+ strncpy(times, baseN(atol(filename + 2), 48, 6), sizeof times);
+ if (end)
+ *end = '.';
+ hash = hash_value(fileglue("%s.%s", filename, board));
+ sprintf(MSGID_BUF, "%s$%s@%s", times, hash, MYADDR);
+ }
+ else
+ {
+ strncpy(MSGID_BUF, msgid, sizeof MSGID_BUF);
+ }
+ sover->msgid = MSGID;
+ if (mtime == -1)
+ {
+ static char BODY_BUF[MAXBUFLEN];
+
+ strncpy(BODY_BUF, fileglue("%s\r\n", subject), sizeof BODY_BUF);
+ BODY = BODY_BUF;
+ sprintf(SUBJECT_BUF, "cmsg cancel <%s>", MSGID);
+ SUBJECT = SUBJECT_BUF;
+ sprintf(CONTROL_BUF, "cancel <%s>", MSGID);
+ CONTROL = CONTROL_BUF;
+ strncpy(MSGID_BUF, fileglue("%d.%s", getpid(), MSGID_BUF), sizeof MSGID_BUF);
+ sprintf(DATE_BUF, "%s", ascii_date(time(NULL)));
+ DATE = DATE_BUF;
+ sover->subject = SUBJECT;
+ sover->control = CONTROL;
+ sover->msgid = MSGID;
+ sover->date = DATE;
+ }
+ else
+ {
+ sover->control = CONTROL;
+ sover->date = DATE_BUF;
+ DATE = DATE_BUF;
+ *CONTROL = '\0';
+ sprintf(DATE, "%s", ascii_date((mtime)));
+ if (NEWSFEED == LOCAL && !NoAction)
+ {
+ SITE = MYSITE;
+ PATH = MYBBSID;
+ GROUPS = group;
+
+#ifndef MapleBBS
+ echomaillog();
+#endif
+ }
+ BODY = "";
+ FD = open(fileglue("%s/boards/%s/%s", BBSHOME, board, filename), O_RDONLY);
+ if (FD < 0)
+ {
+ if (Verbose)
+ printf(" !! can't open %s/boards/%s/%s\n", BBSHOME, board, filename);
+ else
+ fprintf(stderr, "can't open %s/boards/%s/%s\n", BBSHOME, board, filename);
+ return -1;
+ }
+
+ FD_SIZE = filesize(fileglue("%s/boards/%s/%s", BBSHOME, board, filename));
+ if (FD_BUF == NULL)
+ {
+ FD_BUF = (char *) mymalloc(FD_SIZE + 1 + strlen(COMMENT));
+ }
+ else
+ {
+ FD_BUF = (char *) myrealloc(FD_BUF, FD_SIZE + 1 + strlen(COMMENT));
+ }
+ FD_END = FD_BUF + FD_SIZE;
+ *FD_END = '\0';
+ read(FD, FD_BUF, FD_SIZE);
+ sprintf(FD_END, "%s", COMMENT);
+ FD_SIZE += strlen(COMMENT);
+ FD_END += strlen(COMMENT);
+ if (Verbose)
+ {
+ printf("<read in> %s/boards/%s/%s\n", BBSHOME, board, filename);
+ }
+
+ *ORGANIZATION = '\0';
+ *NEWSCONTROL = '\0';
+ *NEWSAPPROVED = '\0';
+ *NNTPHOST_BUF = '\0';
+ NNTPHOST = NULL;
+
+ for (buffer = FD_BUF, bufferp = strchr(buffer, '\n');
+ buffer && *buffer; bufferp = strchr(buffer, '\n'))
+ {
+ if (bufferp)
+ *bufferp = '\0';
+ if (*buffer == '\0')
+ {
+ break;
+ }
+ /* printf("get buffer %s\n", buffer); */
+ if (NEWSFEED == REMOTE)
+ {
+ if (strncmp(buffer, "Date: ", 11) == 0)
+ {
+ strcpy(DATE_BUF, buffer + 11);
+ DATE = DATE_BUF;
+ }
+ else if (strncmp(buffer, "µo«H¯¸: ", 8) == 0)
+ {
+ char *m, *n;
+
+ m = strchr(buffer, '(');
+ n = strrchr(buffer, ')');
+ if (m && n)
+ {
+ strncpy(DATE_BUF, m + 1, n - m - 1);
+ DATE_BUF[n - m - 1] = '\0';
+ DATE = DATE_BUF;
+ strncpy(ORGANIZATION, buffer + 8, m - 8 - buffer - 1);
+ ORGANIZATION[m - 8 - buffer - 1] = '\0';
+ }
+ }
+ else if (strncmp(buffer, "Control: ", 9) == 0)
+ {
+ strcpy(NEWSCONTROL, buffer + 9);
+ }
+ else if (strncmp(buffer, "Approved: ", 10) == 0)
+ {
+ strcpy(NEWSAPPROVED, buffer + 10);
+ }
+ else if (strncmp(buffer, "Origin: ", 8) == 0)
+ {
+ strcpy(NNTPHOST_BUF, buffer + 8);
+ NNTPHOST = NNTPHOST_BUF;
+ }
+ }
+ if (bufferp)
+ {
+ *bufferp = '\n';
+ buffer = bufferp + 1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (bufferp)
+ {
+ BODY = bufferp + 1;
+ }
+ else
+ BODY = "";
+ if (bufferp)
+ for (buffer = bufferp + 1, bufferp = strchr(buffer, '\n');
+ buffer && *buffer; bufferp = strchr(buffer, '\n'))
+ {
+ if (bufferp)
+ *bufferp = '\0';
+ /* printf("get line (%s)\n", buffer); */
+ /* if( strcmp(buffer,".")==0 ) { buffer[1]='.'; buffer[2]='\0'; } */
+ if (NEWSFEED == REMOTE &&
+ strncmp(NEWSCONTROL, "cancel", 5) == 0 &&
+ strncmp(buffer, "------------------", 18) == 0)
+ {
+ break;
+ }
+ else if (strncmp(buffer, "¡» From: ", 9) == 0)
+ {
+ strcpy(NNTPHOST_BUF, buffer + 9);
+ NNTPHOST = NNTPHOST_BUF;
+ }
+ /* $BODY[ @BODY ] = "$_\r\n"; */
+ if (bufferp)
+ {
+ *bufferp = '\n';
+ buffer = bufferp + 1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ /* # fprintf("BODY @BODY\n"; */
+ close(FD);
+ }
+ return 0;
+}
+
+#ifdef TEST
+#endif
+
+openfeed(node)
+ nodelist_t *node;
+{
+ if (node->feedfp == NULL)
+ {
+ node->feedfp = fopen(fileglue("%s/%s.link", INNDHOME, node->node), "a");
+ }
+}
+
+queuefeed(node, textline)
+ nodelist_t *node;
+ char *textline;
+{
+ openfeed(node);
+ if (node->feedfp != NULL)
+ {
+ flock(fileno(node->feedfp), LOCK_EX);
+ fprintf(node->feedfp, "%s", textline);
+ fflush(node->feedfp);
+ flock(fileno(node->feedfp), LOCK_UN);
+ }
+}
+
+post_article(node, site, sover, textline)
+ nodelist_t *node;
+ char *site;
+ soverview_t *sover;
+ char *textline;
+{
+ int status;
+ char *filename = sover->filename;
+ char *msgid = sover->msgid;
+ char *board = sover->board;
+ char *bodyp, *body;
+
+ if (Verbose)
+ fprintf(stdout, "<post_article> %s %s %s\n", site, filename, msgid);
+ if (NoAction && Verbose)
+ {
+ printf(" ==>%s\n", sover->path);
+ printf(" ==>%s:%s\n", sover->from, sover->group);
+ printf(" ==>%s:%s\n", sover->subject, sover->date);
+ body = BODY;
+ bodyp = strchr(body, '\n');
+ if (bodyp)
+ *bodyp = '\0';
+ printf(" ==>%s\n", body);
+ if (bodyp)
+ *bodyp = '\n';
+ if (bodyp)
+ {
+ body = bodyp + 1;
+ bodyp = strchr(body, '\n');
+ if (bodyp)
+ *bodyp = '\0';
+ printf(" ==>%s\n", body);
+ if (bodyp)
+ *bodyp = '\n';
+ }
+ }
+ if (NoAction)
+ return 1;
+ if (NEWSFEED == REMOTE)
+ {
+ fprintf(NNTPwfp, "Path: %s\r\n", sover->path);
+ fprintf(NNTPwfp, "From: %s\r\n", sover->from);
+ fprintf(NNTPwfp, "Newsgroups: %s\r\n", sover->group);
+ fprintf(NNTPwfp, "Subject: %s\r\n", sover->subject);
+ /* # fprintf( NNTPwfp,"Post with subject ($subject)\n"); */
+ fprintf(NNTPwfp, "Date: %s\r\n", sover->date);
+ if (*ORGANIZATION)
+ fprintf(NNTPwfp, "Organization: %s\r\n", ORGANIZATION);
+ fprintf(NNTPwfp, "Message-ID: <%s>\r\n", sover->msgid);
+ if (*NEWSCONTROL)
+ fprintf(NNTPwfp, "Control: %s\r\n", NEWSCONTROL);
+ if (*NEWSAPPROVED)
+ fprintf(NNTPwfp, "Approved: %s\r\n", NEWSAPPROVED);
+ }
+ else
+ {
+ fprintf(NNTPwfp, "Path: %s\r\n", MYBBSID);
+ fprintf(NNTPwfp, "From: %s\r\n", sover->from);
+ fprintf(NNTPwfp, "Newsgroups: %s\r\n", sover->group);
+ fprintf(NNTPwfp, "Subject: %s\r\n", sover->subject);
+ fprintf(NNTPwfp, "Date: %s\r\n", sover->date);
+ fprintf(NNTPwfp, "Organization: %s\r\n", MYSITE);
+ fprintf(NNTPwfp, "Message-ID: <%s>\r\n", sover->msgid);
+ fprintf(NNTPwfp, "X-Filename: %s/%s\r\n", sover->board, sover->filename);
+ }
+ if (NNTPHOST && *NNTPHOST && USEIHAVE)
+ fprintf(NNTPwfp, "NNTP-Posting-Host: %s\r\n", NNTPHOST);
+ else if (NNTPHOST && *NNTPHOST)
+ fprintf(NNTPwfp, "X-Auth-From: %s\r\n", NNTPHOST);
+ if (*CONTROL)
+ {
+ fprintf(NNTPwfp, "Control: %s\r\n", CONTROL);
+ }
+ fputs("\r\n", NNTPwfp);
+ for (body = BODY, bodyp = strchr(body, '\n');
+ body && *body; bodyp = strchr(body, '\n'))
+ {
+ if (bodyp)
+ *bodyp = '\0';
+
+ fputs(body, NNTPwfp);
+ if (body[0] == '.' && body[1] == '\0')
+ fputs(".", NNTPwfp);
+ fputs("\r\n", NNTPwfp);
+ if (bodyp)
+ {
+ *bodyp = '\n';
+ body = bodyp + 1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ /* print "send out @BODY\n"; */
+ status = tcpcommand(".");
+ /* 435 duplicated article 437 invalid header */
+
+ if (USEIHAVE)
+ {
+ if (status == 235)
+ {
+ if (NEWSFEED == LOCAL)
+ {
+ bbslog("Sendout <%s> from %s/%s\n", msgid, board, filename);
+ }
+ }
+ else if (status == 437 || status == 435)
+ {
+ bbslog("<bbslink> :Warn: %d %s <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Warn: %d %s <%s>\n", status, (char *) tcpmessage(), msgid);
+ return 0;
+ }
+ else
+ {
+ bbslog("<bbslink> :Err: %d %s of <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Err: %d %s of <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (!strstr(tcpmessage(), "Article not posted"))
+ queuefeed(node, textline);
+ return 0;
+ }
+ }
+ else if (USEPOST)
+ {
+ if (status == 240)
+ {
+ bbslog("Sendout <%s> from %s/%s\n", msgid, board, filename);
+ }
+ else if (status == 437 || status == 435)
+ {
+ bbslog("<bbslink> :Warn: %d %s <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Warn: %d %s <%s>\n", status, (char *) tcpmessage(), msgid);
+ return 0;
+ }
+ else
+ {
+ bbslog("<bbslink> :Err: %d %s of <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (!strstr(tcpmessage(), "Article not posted"))
+ queuefeed(node, textline);
+ return 0;
+ }
+ }
+ else
+ {
+ if (status == 250)
+ {
+ bbslog("<bbslink> DATA Sendout <%s> from %s/%s\n", msgid, board, filename);
+ if (Verbose)
+ printf("<DATA Sendout> <%s> from %s/%s\n", msgid, board, filename);
+ }
+ else
+ {
+ bbslog("<bbslink> :Err: %d %s of <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Err: %d %s of <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (!strstr(tcpmessage(), "Article not posted"))
+ queuefeed(node, textline);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+process_cancel(board, filename, userid, nickname, subject)
+ char *board, *filename, *userid, *nickname, *subject;
+{
+ time_t mtime;
+ soverview_t sover;
+
+ if (!userid || !*userid)
+ {
+ return;
+ }
+ mtime = -1;
+ strncpy(FROM_BUF, fileglue("%s.bbs@%s (%s)", userid, MYADDR, nickname), sizeof FROM_BUF);
+ FROM = FROM_BUF;
+ sover.from = FROM;
+ sover.board = board;
+ sover.subject = subject;
+ PATH = MYBBSID;
+ sover.path = MYBBSID;
+ /* save_outgoing(&sover, filename, userid, poster, -1); */
+ save_outgoing(&sover, filename, userid, userid, -1);
+}
+
+open_link(hostname, hostprot, hostport)
+ char *hostname, *hostprot, *hostport;
+{
+ USEIHAVE = 1;
+ USEPOST = 0;
+ USEDATA = 0;
+ FEEDTYPE = ' ';
+ if (Verbose)
+ printf("<OPEN_link> %s %s %s\n", hostname, hostprot, hostport);
+ if (strncasecmp(hostprot, "IHAVE", 5) != 0)
+ {
+ USEIHAVE = 0;
+ USEPOST = 1;
+ if (strncasecmp(hostprot, "POST", 4) == 0)
+ {
+ USEPOST = 1;
+ }
+ else if (strncasecmp(hostprot, "DATA", 4) == 0)
+ {
+ USEPOST = 0;
+ USEDATA = 1;
+ }
+ }
+
+ FEEDTYPE = hostname[0];
+ if (!USEDATA)
+ {
+ char *atsign;
+
+ if (FEEDTYPE == '-' || FEEDTYPE == '+')
+ {
+ hostname = hostname + 1;
+ }
+ atsign = strchr(hostname, '@');
+ if (atsign != NULL)
+ {
+ hostname = atsign + 1;
+ }
+ if (!NoAction)
+ {
+ if (Verbose)
+ printf("<inetclient> %s %s\n", hostname, hostport);
+ if ((NNTP = inetclient(hostname, hostport, "tcp")) < 0)
+ {
+ bbslog("<bbslink> :Err: server %s %s error: cant connect\n", hostname, hostport);
+ if (Verbose)
+ printf(":Err: server %s %s error: cant connect\n", hostname, hostport);
+ return 0;
+ /* exit( 0 ); */
+ /* return; */
+ }
+ NNTPrfp = fdopen(NNTP, "r");
+ NNTPwfp = fdopen(NNTP, "w");
+ fgets(NNTPbuffer, sizeof NNTPbuffer, NNTPrfp);
+ if (atoi(NNTPbuffer) != 200)
+ {
+ bbslog("<bbslink> :Err: server error: %s", NNTPbuffer);
+ if (Verbose)
+ printf(":Err: server error: %s", NNTPbuffer);
+ return 0;
+ /* exit( 0 ); */
+ }
+ }
+ else
+ {
+ if (Verbose)
+ printf("<inetclient> %s %s\n", hostname, hostport);
+ }
+ }
+ else
+ {
+ if (!NoAction)
+ {
+ if (Verbose)
+ printf("<inetclient> localhost %s\n", hostport);
+ if ((NNTP = inetclient("localhost", hostport, "tcp")) < 0)
+ {
+ bbslog("<bbslink> :Err: server %s port %s error: cant connect\n", hostname, hostport);
+ if (Verbose)
+ printf(":Err: server error: cant connect");
+ return 0;
+ /* exit( 0 ); */
+ /* return; */
+ }
+ NNTPrfp = fdopen(NNTP, "r");
+ NNTPwfp = fdopen(NNTP, "w");
+ fgets(NNTPbuffer, sizeof NNTPbuffer, NNTPrfp);
+ if (strncmp(NNTPbuffer, "220", 3) != 0)
+ {
+ bbslog("<bbslink> :Err: server error: %s", NNTPbuffer);
+ if (Verbose)
+ printf(":Err: server error: %s", NNTPbuffer);
+ return 0;
+ /* exit( 0 ); */
+ }
+ if (strncmp(NNTPbuffer, "220-", 4) == 0)
+ {
+ fgets(NNTPbuffer, sizeof NNTPbuffer, NNTPrfp);
+ }
+ }
+ else
+ {
+ if (Verbose)
+ printf("<inetclient> %s %s\n", hostname, hostport);
+ }
+ }
+ return 1;
+}
+
+send_outgoing(node, site, hostname, sover, textline)
+ nodelist_t *node;
+ soverview_t *sover;
+ char *hostname, *site;
+ char *textline;
+{
+ int status;
+ char *board, *filepath, *msgid;
+ int returnstatus = 0;
+
+ board = sover->board;
+ filepath = sover->filename;
+ msgid = sover->msgid;
+
+ if (Verbose)
+ printf("<send_outgoing> %s:%s:%s:%s\n", site, board, filepath, msgid);
+ if (BODY != NULL && !NoAction)
+ {
+ if (USEIHAVE)
+ {
+/* status = tcpcommand("IHAVE <%s>", msgid);*/
+ char buf[80];
+ sprintf(buf, "IHAVE <%s>", msgid);
+ status = tcpcommand(buf);
+ if (status == 335)
+ {
+ returnstatus = post_article(node, site, sover, textline);
+ }
+ else if (status == 435)
+ {
+ bbslog("<bbslink> :Warn: %d %s, IHAVE <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Warn: %d %s, IHAVE <%s>\n", status, (char *) tcpmessage(), msgid);
+ returnstatus = 0;
+ }
+ else
+ {
+ bbslog("<bbslink> :Err: %d %s, IHAVE <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Err: %d %s, IHAVE <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (!strstr(tcpmessage(), "Article not posted"))
+ queuefeed(node, textline);
+ returnstatus = 0;
+ }
+ }
+ else if (USEPOST)
+ {
+ tcpcommand("MODE READER");
+ status = tcpcommand("POST");
+ if (status == 340)
+ {
+ returnstatus = post_article(node, site, sover, textline);
+ }
+ else if (status == 441)
+ {
+ bbslog("<bbslink> :Warn: %d %s, POST <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Warn: %d %s, POST <%s>\n", status, (char *) tcpmessage(), msgid);
+ returnstatus = 0;
+ }
+ else
+ {
+ bbslog("<bbslink> :Err: %d %s, POST <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Err: %d %s, POST <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (!strstr(tcpmessage(), "Article not posted"))
+ queuefeed(node, textline);
+ returnstatus = 0;
+ }
+ }
+ else
+ {
+ tcpcommand("HELO");
+ tcpcommand("MAIL FROM: bbs");
+ tcpcommand("RCPT TO: %s", hostname);
+ status = tcpcommand("DATA");
+ if (status == 354)
+ {
+ returnstatus = post_article(node, site, sover, textline);
+ }
+ else
+ {
+ bbslog("<bbslink> :Err: %d %s, DATA <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Err: %d %s, DATA <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (!strstr(tcpmessage(), "Article not posted"))
+ queuefeed(node, textline);
+ returnstatus = 0;
+ }
+ }
+ }
+ else if (NoAction)
+ {
+ returnstatus = post_article(node, site, sover, textline);
+ }
+ return returnstatus;
+}
+
+save_nntplink(node, overview)
+ nodelist_t *node;
+ char *overview;
+{
+ FILE *POSTS;
+ char buffer[1024];
+
+ openfeed(node);
+ POSTS = fopen(overview, "r");
+ if (POSTS == NULL)
+ return 0;
+ openfeed(node);
+ /* if (node->feedfp == NULL) return 0; */
+ flock(fileno(node->feedfp), LOCK_EX);
+ while (fgets(buffer, sizeof buffer, POSTS) != NULL)
+ {
+ fputs(buffer, node->feedfp);
+ fflush(node->feedfp);
+ }
+ flock(fileno(node->feedfp), LOCK_UN);
+ fclose(POSTS);
+ if (Verbose)
+ printf("<Unlinking> %s\n", overview);
+ if (!NoAction)
+ unlink(overview);
+ return 1;
+}
+
+
+char *
+get_tmpfile(tmpfile)
+ char *tmpfile;
+{
+ FILE *FN;
+ static char result[256];
+
+ FN = fopen(tmpfile, "r");
+ fgets(result, sizeof result, FN);
+ fclose(FN);
+ unlink(tmpfile);
+ return (result);
+}
+
+/* cancel moderating posts */
+
+cancel_outgoing(board, filename, from, subject)
+ char *board, *filename, *from, *subject;
+{
+ char *base, filepath[MAXPATHLEN];
+ FILE *FN;
+ char *result;
+ char TMPFILE[MAXPATHLEN];
+
+ if (Verbose)
+ {
+ printf("<cancel_outgoing> %s %s %s %s\n", board, filename, from, subject);
+ }
+
+ sprintf(TMPFILE, "/tmp/cancel_outgoing.%d.%d", getuid(), getpid());
+
+ bbslog("<cancel_outgoing> Try to move moderated post from %s to deleted\n", board);
+ if (Verbose)
+ printf("Try to move moderated post from %s to deleted\n", board);
+ FN = popen(fileglue("%s/bbspost post %s/boards/deleted > %s",
+ INNDHOME, BBSHOME, TMPFILE), "w");
+ if (FN == NULL)
+ {
+ bbslog("<cancel_outgoing> can't run %s/bbspost\n", INNDHOME);
+ if (Verbose)
+ printf("<cancel_outgoing> can't run %s/bbspost\n", INNDHOME);
+ return 0;
+ }
+ fprintf(FN, "%s\n", from);
+ fprintf(FN, "%s\n", subject);
+ fprintf(FN, "µo«H¤H: %s, «H°Ï: %s\n", from, board);
+ fprintf(FN, "¼Ð ÃD: %s\n", subject);
+ fprintf(FN, "µo«H¯¸: %s (%s)\n", MYSITE, DATE);
+ fprintf(FN, "Âà«H¯¸: %s\n", MYBBSID);
+ fputs("\n", FN);
+ fputs(BODY, FN);
+ pclose(FN);
+ result = (char *) get_tmpfile(TMPFILE);
+ if (strncmp(result, "post to ", 8) == 0)
+ {
+ /* try to remove it */
+ strncpy(filepath, fileglue("%s/boards/%s/%s", BBSHOME, board, filename), sizeof filepath);
+ if (isfile(filepath))
+ {
+ Rename(filepath, fileglue("%s.cancel", filepath));
+ }
+ FN = fopen(filepath, "w");
+
+ fprintf(FN, "µo«H¤H: %s, «H°Ï: %s\n", from, board);
+ fprintf(FN, "¼Ð ÃD: <article cancelled and mailed to the moderator\n");
+ fprintf(FN, "µo«H¯¸: %s (%s)\n", MYSITE, DATE);
+ fprintf(FN, "Âà«H¯¸: %s\n", MYBBSID);
+ fprintf(FN, "\n");
+ fputs("\n", FN);
+ fprintf(FN, "§Aªº¤å³¹ \"%s\" ¤w¸g°e©¹¼f®Ö¤¤. ½Ðµ¥«Ý¦^ÂÐ.\n", subject);
+ fputs("\n", FN);
+ fputs("Your post has been sent to the moderator and move\n", FN);
+ fputs("into the deleted board. If the post accepted by the moderator,\n", FN);
+ fputs("it will be posted in this board again. Please wait.\n", FN);
+
+ }
+ else
+ {
+ bbslog("%s", result);
+ }
+
+ bbslog("%s/bbspost cancel %s %s %s moderate\n", INNDHOME, BBSHOME, board, filename);
+ if (Verbose)
+ printf("%s/bbspost cancel %s %s %s moderate\n", INNDHOME, BBSHOME, board, filename);
+ system(fileglue("%s/bbspost cancel %s %s %s moderate",
+ INNDHOME, BBSHOME, board, filename));
+ return 1;
+}
+
+/*
+ * send_nntplink open_link read_outgoing send_outgoing post_article
+ * cancel_outgoing
+ */
+send_nntplink(node, site, hostname, hostprot, hostport, overview, nlcount)
+ nodelist_t *node;
+ char *site, *hostname, *hostprot, *hostport, *overview;
+ int nlcount;
+{
+ FILE *POSTS;
+ char textline[1024];
+ char baktextline[1024];
+ char *filepath;
+ int status;
+
+ if (Verbose)
+ {
+ printf("<send nntplink> %s %s %s %s\n", site, hostname, hostprot, hostport);
+ printf(" ==> %s\n", overview);
+ }
+ if (!open_link(hostname, hostprot, hostport))
+ {
+ save_nntplink(node, overview);
+ return 0;
+ }
+ POSTS = fopen(overview, "r");
+ if (POSTS == NULL)
+ {
+ if (Verbose)
+ printf("open %s failed\n", overview);
+ return 0;
+ }
+ while (fgets(textline, sizeof textline, POSTS) != NULL)
+ {
+ char *linebreak = strchr(textline, '\n');
+ char *ptr;
+ char *board, *filename, *subject, *group, *mtime, *from;
+ char *outgoingtype;
+ char *msgid, *path;
+ soverview_t soverview;
+
+ strcpy(baktextline, textline);
+ if (linebreak)
+ *linebreak = '\0';
+
+ board = "", filename = "", mtime = "", group = "", from = "", subject = "";
+ outgoingtype = "", msgid = "", path = "";
+ /* get board field */
+ board = textline;
+ ptr = strchr(textline, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* filename field */
+ filename = ptr;
+
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+
+ *ptr++ = '\0';
+
+ /* group field */
+ group = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* mtime field */
+ mtime = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* from field */
+ from = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* subject */
+ subject = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ goto try_read_outgoing;
+ *ptr++ = '\0';
+
+ /* outgoing type field */
+ outgoingtype = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ goto try_read_outgoing;
+ *ptr++ = '\0';
+
+ /* msgid */
+ msgid = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ goto try_read_outgoing;
+ *ptr++ = '\0';
+
+ /* path */
+ path = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ goto try_read_outgoing;
+
+try_read_outgoing:
+
+ NEWSFEED = LOCAL;
+ if (outgoingtype && msgid && path && *outgoingtype && *msgid && *path)
+ {
+ char *left, *right;
+
+ NEWSFEED = REMOTE;
+ left = strchr(msgid, '<');
+ right = strrchr(msgid, '>');
+ if (left)
+ msgid = left + 1;
+ if (right)
+ *right = '\0';
+ }
+ soverview.board = board;
+ soverview.filename = filename;
+ soverview.group = group;
+ soverview.mtime = atol(mtime);
+ soverview.from = from;
+ soverview.subject = subject;
+ soverview.outgoingtype = outgoingtype;
+ soverview.msgid = msgid;
+ soverview.path = path;
+ if (read_outgoing(&soverview) == 0)
+ {
+ int sendresult = send_outgoing(node, site, hostname, &soverview, baktextline);
+ int sendfailed = 1 - sendresult;
+
+ if (NEWSFEED == REMOTE)
+ {
+ BBSLINK_STAT[nlcount].remotesendout += sendresult;
+ BBSLINK_STAT[nlcount].remotefailed += sendfailed;
+ }
+ else
+ {
+ BBSLINK_STAT[nlcount].localsendout += sendresult;
+ BBSLINK_STAT[nlcount].localfailed += sendfailed;
+ }
+ if (node->feedtype == '-')
+ {
+ if (!NoAction && sendresult)
+ cancel_outgoing(board, filename, from, subject);
+ }
+ }
+ }
+ fclose(POSTS);
+ close_link();
+ if (Verbose)
+ printf("<Unlinking> %s\n", overview);
+ if (!NoAction)
+ unlink(overview);
+}
+
+close_link()
+{
+ int status;
+
+ if (Verbose)
+ printf("<close_link>\n");
+ if (NoAction)
+ return;
+ status = tcpcommand("QUIT");
+ if (status != 205 && status != 221)
+ {
+ bbslog("<bbslink> :Err: Cannot quit message '%d %s'\n", status, (char *) tcpmessage());
+ if (Verbose)
+ printf(":Err: Cannot quit message '%d %s'\n", status, (char *) tcpmessage());
+ }
+ fclose(NNTPwfp);
+ fclose(NNTPrfp);
+ close(NNTP);
+}
+
+
+/*
+ * send_article() send_nntplink() read_outgoing()
+ *
+ */
+
+send_article()
+{
+ char *site, *addr, *protocol, *port, *op;
+ char *nntphost;
+ int nlcount;
+
+ chdir(INNDHOME);
+
+ for (nlcount = 0; nlcount < NLCOUNT; nlcount++)
+ {
+ nodelist_t *node;
+ char linkfile[MAXPATHLEN];
+ char sendfile[MAXPATHLEN];
+ char feedfile[MAXPATHLEN];
+ char feedingfile[MAXPATHLEN];
+ char protocol[MAXBUFLEN], port[MAXBUFLEN];
+
+ node = NODELIST + nlcount;
+ site = node->node;
+ nntphost = node->host;
+ op = node->protocol;
+
+ if (DefaultFeedSite && *DefaultFeedSite)
+ {
+ if (strcmp(node->node, DefaultFeedSite) != 0)
+ continue;
+ }
+
+ if (op && (strncasecmp(op, "ihave", 5) == 0 ||
+ strncasecmp(op, "post", 4) == 0 ||
+ strncasecmp(op, "data", 4) == 0))
+ {
+ char *left, *right;
+
+ left = strchr(op, '('), right = strrchr(op, ')');
+ if (left && right)
+ {
+ *left = '\0';
+ *right = '\0';
+ strncpy(protocol, op, sizeof protocol);
+ strncpy(port, left + 1, sizeof port);
+ *left = '(';
+ *right = ')';
+ }
+ else
+ {
+ strncpy(protocol, op, sizeof protocol);
+ strncpy(port, "nntp", sizeof port);
+ }
+ }
+ else
+ {
+ strcpy(protocol, "IHAVE");
+ strcpy(port, "nntp");
+ }
+ sprintf(linkfile, "%s.link", site);
+ sprintf(sendfile, "%s.sending", site);
+ sprintf(feedfile, "%s.feed", site);
+ sprintf(feedingfile, "%s.feeding", site);
+ if (isfile(sendfile) && !iszerofile(sendfile))
+ {
+ if (bbslink_get_lock(sendfile))
+ {
+ send_nntplink(node, site, nntphost, protocol, port, sendfile, nlcount);
+ bbslink_un_lock(sendfile);
+ }
+ }
+ if (isfile(linkfile) && !iszerofile(linkfile))
+ {
+ if (!NoAction)
+ {
+ if (bbslink_get_lock(sendfile) && bbslink_get_lock(linkfile) &&
+ bbslink_get_lock(feedingfile))
+ {
+ if (isfile(sendfile) && !iszerofile(sendfile))
+ {
+ save_nntplink(node, sendfile);
+ }
+ if (node->feedfp)
+ {
+ fclose(node->feedfp);
+ node->feedfp = NULL;
+ }
+ Rename(linkfile, sendfile);
+ send_nntplink(node, site, nntphost, protocol, port, sendfile, nlcount);
+ bbslink_un_lock(linkfile);
+ bbslink_un_lock(sendfile);
+ bbslink_un_lock(feedingfile);
+ }
+ }
+ else
+ {
+ send_nntplink(node, site, nntphost, protocol, port, linkfile, nlcount);
+ }
+ }
+ if (isfile(feedingfile) && !iszerofile(feedingfile))
+ {
+ if (bbslink_get_lock(feedingfile))
+ {
+ send_nntplink(node, site, nntphost, protocol, port, feedingfile, nlcount);
+ bbslink_un_lock(feedingfile);
+ }
+ }
+ if (isfile(feedfile) && !iszerofile(feedfile))
+ {
+ if (!NoAction)
+ {
+ if (bbslink_get_lock(feedfile) && bbslink_get_lock(feedingfile))
+ {
+ if (isfile(feedingfile) && !iszerofile(feedingfile))
+ {
+ save_nntplink(node, feedingfile);
+ if (node->feedfp)
+ {
+ fclose(node->feedfp);
+ node->feedfp = NULL;
+ }
+ }
+ Rename(feedfile, feedingfile);
+ system(fileglue("%s/ctlinnbbsd reload > /dev/null", INNDHOME));
+ send_nntplink(node, site, nntphost, protocol, port, feedingfile, nlcount);
+ bbslink_un_lock(feedfile);
+ bbslink_un_lock(feedingfile);
+ }
+ }
+ else
+ {
+ send_nntplink(node, site, nntphost, protocol, port, feedfile, nlcount);
+ }
+ }
+ }
+}
+
+/* bntplink() bbspost() process_article() process_cancel() send_article() */
+
+
+show_usage(argv)
+ char *argv;
+{
+ fprintf(stderr, "%s initialization failed or improper options !!\n", argv);
+ fprintf(stderr, "Usage: %s [options] bbs_home\n", argv);
+ fprintf(stderr, " -v (show transmission status)\n");
+ fprintf(stderr, " -n (dont send out articles and leave queue untouched)\n");
+ fprintf(stderr, " -s site (only process articles sent to site)\n");
+ fprintf(stderr, " -V (visit only: bbspost visit)\n");
+ fprintf(stderr, " -N (no visit, and only process batch queue)\n");
+ fprintf(stderr, " -k (kill the former bbslink process before started)\n\n");
+ fprintf(stderr, "¥»µ{¦¡­n¥¿±`°õ¦æ¥²¶·±N¥H¤UÀɮ׸m©ó %s/innd ¤U:\n", BBSHOME);
+ fprintf(stderr, "bbsname.bbs ³]©w¶Q¯¸ªº BBS ID (½Ð¾¨¶q²µu)\n");
+ fprintf(stderr, "nodelist.bbs ³]©wºô¸ô¦U BBS ¯¸ªº ID, Address ©M fullname\n");
+ fprintf(stderr, "newsfeeds.bbs ³]©wºô¸ô«H¥óªº newsgroup board nodelist ...\n");
+}
+
+
+bntplink(argc, argv)
+ int argc;
+ char **argv;
+{
+ static char *OUTING = ".outing";
+ nodelist_t *nl;
+ int linkport;
+ char result[4096];
+ char cancelfile[MAXPATHLEN], cancelpost[MAXPATHLEN];
+ char bbslink_lockfile[MAXPATHLEN];
+ FILE *NEWPOST;
+ char *left, *right;
+ int nlcount;
+
+// strcpy(BBSHOME, argv[0]);
+ if (initial_bbs("link") == 0)
+ {
+ return -1;
+ }
+
+ BBSLINK_STAT = (stat_t *) malloc(sizeof(stat_t) * (NLCOUNT + 1));
+ for (nlcount = 0; nlcount < NLCOUNT; nlcount++)
+ {
+ BBSLINK_STAT[nlcount].localsendout = 0;
+ BBSLINK_STAT[nlcount].remotesendout = 0;
+ BBSLINK_STAT[nlcount].localfailed = 0;
+ BBSLINK_STAT[nlcount].remotefailed = 0;
+ }
+
+ nl = (nodelist_t *) search_nodelist_bynode(MYBBSID);
+ if (nl == NULL)
+ {
+ *MYADDR = '\0';
+ *MYSITE = '\0';
+ *LINKPROTOCOL = '\0';
+ }
+ else
+ {
+ strncpy(MYADDR, nl->host, sizeof MYADDR);
+ strncpy(LINKPROTOCOL, nl->protocol, sizeof LINKPROTOCOL);
+ strncpy(MYSITE, nl->comments, sizeof MYSITE);
+ }
+ if (Verbose)
+ {
+ printf("MYADDR: %s\n", MYADDR);
+ printf("MYSITE: %s\n", MYSITE);
+ }
+ left = strchr(nl->protocol, '(');
+ right = strrchr(nl->protocol, ')');
+ if (left && right)
+ {
+ *right = '\0';
+ strncpy(LINKPROTOCOL, nl->protocol, sizeof LINKPROTOCOL);
+ LINKPORT = atoi(left + 1);
+ *right = ')';
+ }
+
+ if (!NoVisit)
+ {
+ sprintf(bbslink_lockfile, "%s/.bbslink.visit", INNDHOME);
+ if (!Rename(fileglue("%s/out.bntp", INNDHOME), OUTING) && bbslink_get_lock(bbslink_lockfile))
+ {
+ /* When try to visit new post, try to lock it */
+ NEWPOST = fopen(OUTING, "r");
+ if (NEWPOST == NULL)
+ {
+ bbslog("<bbslink> Err: can't open %s\n", OUTING);
+ bbslink_un_lock(bbslink_lockfile);
+ return -1;
+ }
+ while (fgets(result, sizeof result, NEWPOST))
+ {
+ /* chop( $_ ); */
+ char *board, *filename, *userid, *nickname, *subject;
+ char *ptr;
+
+ ptr = strchr(result, '\n');
+ if (ptr)
+ *ptr = '\0';
+
+ board = filename = userid = nickname = subject = NULL;
+ /* board field */
+ board = result;
+ ptr = strchr(result, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* filename field */
+ filename = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* userid field */
+ userid = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* nickname field */
+ nickname = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* subject field */
+ subject = ptr;
+ /* ptr = strchr(ptr, '\t'); if (ptr == NULL) continue; ptr++ = '\0'; */
+
+ if(bad_subject(subject)) continue;
+
+ if(outgo_post < MAX_OUTGO_POST){
+ out_bntp[outgo_post].board = board;
+ out_bntp[outgo_post].filename = filename;
+ out_bntp[outgo_post].userid = userid;
+ out_bntp[outgo_post].nickname = nickname;
+ out_bntp[outgo_post].subject = subject;
+ outgo_post++;
+ }
+
+ process_article(board, filename, userid, nickname, subject);
+ }
+ fclose(NEWPOST);
+ unlink(OUTING);
+ bbslink_un_lock(bbslink_lockfile);
+ } /* getlock */
+ } /* if NoVisit is false */
+
+ sprintf(cancelpost, "%s/cancel.bntp", INNDHOME);
+ if (isfile(cancelpost))
+ {
+ FILE *CANCELFILE;
+
+ if (bbslink_get_lock(cancelpost) && bbslink_get_lock(cancelfile))
+ {
+ sprintf(cancelfile, "%s.%d", cancelpost, getpid());
+ Rename(cancelpost, cancelfile);
+ CANCELFILE = fopen(cancelfile, "r");
+ while (fgets(result, sizeof result, CANCELFILE) != NULL)
+ {
+ /* chop( $_ ); */
+ char *board, *filename, *userid, *nickname, *subject;
+ char *ptr, **sptr;
+
+ ptr = strchr(result, '\n');
+ if (ptr)
+ *ptr = '\0';
+ board = filename = userid = nickname = subject = NULL;
+
+ /* board field */
+ board = result;
+ ptr = strchr(result, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* filename field */
+ filename = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* userid field */
+ userid = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* nickname field */
+ nickname = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* subject field */
+ subject = ptr;
+ /* ptr = strchr(ptr, '\t'); if (ptr == NULL) continue; ptr++ = '\0'; */
+ if(!is_outgo_post(board, filename, userid, nickname, subject))
+ process_cancel(board, filename, userid, nickname, subject);
+ }
+ fclose(CANCELFILE);
+ if (Verbose)
+ printf("Unlinking %s\n", cancelfile);
+ if (!NoAction)
+ unlink(cancelfile);
+ bbslink_un_lock(cancelfile);
+ bbslink_un_lock(cancelpost);
+ }
+ }
+
+ for (nlcount = 0; nlcount < NLCOUNT; nlcount++)
+ {
+ if (NODELIST[nlcount].feedfp != NULL)
+ {
+ fclose(NODELIST[nlcount].feedfp);
+ NODELIST[nlcount].feedfp = NULL;
+ }
+ }
+
+ send_article();
+ for (nlcount = 0; nlcount < NLCOUNT; nlcount++)
+ {
+ int localsendout, remotesendout, localfailed, remotefailed;
+
+ localsendout = BBSLINK_STAT[nlcount].localsendout;
+ remotesendout = BBSLINK_STAT[nlcount].remotesendout;
+ localfailed = BBSLINK_STAT[nlcount].localfailed;
+ remotefailed = BBSLINK_STAT[nlcount].remotefailed;
+ if (localsendout || remotesendout || localfailed || remotefailed)
+ bbslog("<bbslink> [%s]%s lsend:%d rsend:%d lfail:%d rfail:%d\n",
+ NODELIST[nlcount].node, NoAction ? "NoAction" : "", localsendout, remotesendout,
+ localfailed, remotefailed);
+ if (NODELIST[nlcount].feedfp != NULL)
+ {
+ fclose(NODELIST[nlcount].feedfp);
+ NODELIST[nlcount].feedfp = NULL;
+ }
+ }
+ if (BBSLINK_STAT);
+ free(BBSLINK_STAT);
+ return 0;
+}
+/*
+termbbslink(sig)
+ int sig;
+{
+ bbslog("kill signal received %d, terminated\n", sig);
+ if (Verbose)
+ printf("kill signal received %d, terminated\n", sig);
+ exit(0);
+}
+*/
+void
+termbbslink()
+{
+ bbslog("kill signal received ??, terminated\n");
+ if (Verbose)
+ printf("kill signal received ??, terminated\n");
+ exit(0);
+}
+
+char *REMOTEUSERNAME = "";
+char *REMOTEHOSTNAME = "";
+
+extern char *optarg;
+extern int opterr, optind;
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int c, errflag = 0;
+
+ CONTROL = CONTROL_BUF;
+ MSGID = MSGID_BUF;
+
+ /* For debug Only */
+#define DEBUGBBSLINK
+
+#ifdef DEBUGBBSLINK
+ NoAction = 0;
+ Verbose = 0;
+ VisitOnly = 0;
+ NoVisit = 0;
+ DefaultFeedSite = "";
+#endif
+
+ while ((c = getopt(argc, argv, "s:hnvVNk")) != -1)
+ switch (c)
+ {
+ case 's':
+ DefaultFeedSite = optarg;
+ break;
+ case 'n':
+ NoAction = 1;
+ break;
+ case 'v':
+ Verbose = 1;
+ break;
+ case 'V':
+ VisitOnly = 1;
+ break;
+ case 'N':
+ NoVisit = 1;
+ break;
+ case 'k':
+ KillFormerBBSLINK = 1;
+ break;
+ case 'h':
+ default:
+ errflag++;
+ break;
+ }
+ if (errflag > 0)
+ {
+ show_usage(argv[0]);
+ return (1);
+ }
+ if (argc - optind < 1)
+ {
+ show_usage(argv[0]);
+ exit(1);
+ }
+ signal(SIGTERM, termbbslink);
+ if (bntplink(argc - optind, argv + optind) != 0)
+ {
+ show_usage(argv[0]);
+ exit(1);
+ }
+ return 0;
+}
diff --git a/innbbsd/bbslink2.c b/innbbsd/bbslink2.c
new file mode 100644
index 00000000..d79c23a9
--- /dev/null
+++ b/innbbsd/bbslink2.c
@@ -0,0 +1,2017 @@
+#if defined( LINUX )
+# include "innbbsconf.h"
+# include "bbslib.h"
+# include <varargs.h>
+#else
+# include <varargs.h>
+# include "innbbsconf.h"
+# include "bbslib.h"
+#endif
+
+#include <sys/mman.h>
+
+#ifndef AIX
+# include <sys/fcntl.h>
+#endif
+
+#if defined(PalmBBS)
+#include <utime.h>
+#endif
+
+
+#include "daemon.h"
+#include "nntp.h"
+#include "externs.h"
+
+/*
+ * TODO 1. read newsfeeds.bbs, read nodelist.bbs, read bbsname.bbs 2. scan
+ * new posts and append to .link 3. rename .link to .send (must lock) 4.
+ * start to send .send out and append not sent to .link
+ *
+ * 5. node.LOCK (with pid) 6. log articles sent
+ */
+
+
+#ifndef MAXBUFLEN
+#define MAXBUFLEN 256
+#endif
+
+typedef struct Over_t
+{
+ time_t mtime;
+ char date[MAXBUFLEN];
+ char nickname[MAXBUFLEN];
+ char subject[MAXBUFLEN];
+ char from[MAXBUFLEN];
+ char msgid[MAXBUFLEN];
+ char site[MAXBUFLEN];
+ char board[MAXBUFLEN];
+} linkoverview_t;
+
+typedef struct SendOver_t
+{
+ char *board, *filename, *group, *from, *subject;
+ char *outgoingtype, *msgid, *path;
+ char *date, *control;
+ time_t mtime;
+} soverview_t;
+
+typedef struct Stat_t
+{
+ int localsendout;
+ int localfailed;
+ int remotesendout;
+ int remotefailed;
+} stat_t;
+
+static stat_t *BBSLINK_STAT;
+
+static int NoAction = 0;
+static int Verbose = 0;
+static int VisitOnly = 0;
+static int NoVisit = 0;
+static char *DefaultFeedSite = "";
+static int KillFormerBBSLINK = 0;
+
+extern char *SITE;
+extern char *GROUPS;
+
+char NICKNAME[MAXBUFLEN];
+
+char DATE_BUF[MAXBUFLEN];
+extern char *DATE;
+
+char FROM_BUF[MAXBUFLEN];
+extern char *FROM;
+
+#ifndef MapleBBS
+char POSTER_BUF[MAXBUFLEN];
+char *POSTER;
+#endif
+
+char MYADDR[MAXBUFLEN];
+char MYSITE[MAXBUFLEN];
+
+char SUBJECT_BUF[MAXBUFLEN];
+extern char *SUBJECT;
+
+char MSGID_BUF[MAXBUFLEN];
+extern char *MSGID;
+
+char LINKPROTOCOL[MAXBUFLEN];
+int LINKPORT;
+char ORGANIZATION[MAXBUFLEN];
+char NEWSCONTROL[MAXBUFLEN];
+char NEWSAPPROVED[MAXBUFLEN];
+char NNTPHOST_BUF[MAXBUFLEN];
+extern char *NNTPHOST;
+char PATH_BUF[MAXBUFLEN];
+extern char *PATH;
+
+char CONTROL_BUF[MAXBUFLEN];
+extern char *CONTROL;
+
+char *BODY, *HEAD;
+
+int USEIHAVE = 1;
+int USEPOST = 0;
+int USEDATA = 0;
+int FEEDTYPE = ' ';
+
+int NNTP = -1;
+FILE *NNTPrfp = NULL;
+FILE *NNTPwfp = NULL;
+char NNTPbuffer[1024];
+static char *NEWSFEED;
+static char *REMOTE = "REMOTE";
+static char *LOCAL = "LOCAL";
+
+static int FD, FD_SIZE;
+static char *FD_BUF;
+static char *FD_END;
+
+static char *COMMENT =
+"[Ptt °e¥X]\n";
+
+char *fileglue();
+
+/*
+woju
+Cross-fs rename()
+*/
+
+Rename(char* src, char* dst)
+{
+ char cmd[200];
+
+ if (rename(src, dst) == 0)
+ return 0;
+
+ sprintf(cmd, "/bin/mv %s %s", src, dst);
+ return system(cmd);
+
+}
+
+
+bbslink_un_lock(file)
+ char *file;
+{
+ char *lockfile = fileglue("%s.LOCK", file);
+
+ if (isfile(lockfile))
+ unlink(lockfile);
+}
+
+bbslink_get_lock(file)
+ char *file;
+{
+ int lockfd;
+ char LockFile[MAXPATHLEN];
+
+ strncpy(LockFile, (char *) fileglue("%s.LOCK", file), sizeof LockFile);
+ if ((lockfd = open(LockFile, O_RDONLY)) >= 0)
+ {
+ char buf[10];
+ int pid;
+
+ if (read(lockfd, buf, sizeof buf) > 0 &&
+ (pid = atoi(buf)) > 0 && kill(pid, 0) == 0)
+ {
+ if (KillFormerBBSLINK)
+ {
+ kill(pid, SIGTERM);
+ unlink(LockFile);
+ }
+ else
+ {
+ fprintf(stderr, "another process [%d] running\n", pid);
+ return 0;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "no process [%d] running, but lock file existed, unlinked\n", pid);
+ unlink(LockFile);
+ }
+ close(lockfd);
+ }
+
+ if ((lockfd = open(LockFile, O_RDWR | O_CREAT | O_EXCL, 0644)) < 0)
+ {
+ fprintf(stderr, "lock %s error: another bbslink process running\n", LockFile);
+ return 0;
+ }
+ else
+ {
+ char buf[10];
+ int pid;
+
+ sprintf(buf, "%-.8d\n", getpid());
+ write(lockfd, buf, strlen(buf));
+ close(lockfd);
+ return 1;
+ }
+}
+
+
+int
+tcpcommand(va_alist)
+va_dcl
+{
+ va_list ap;
+ register char *fmt;
+ char *ptr;
+
+ va_start(ap);
+ fmt = va_arg(ap, char *);
+ vfprintf(NNTPwfp, fmt, ap);
+ fprintf(NNTPwfp, "\r\n");
+ fflush(NNTPwfp);
+
+ fgets(NNTPbuffer, sizeof NNTPbuffer, NNTPrfp);
+ ptr = strchr(NNTPbuffer, '\r');
+ if (ptr)
+ *ptr = '\0';
+ ptr = strchr(NNTPbuffer, '\n');
+ if (ptr)
+ *ptr = '\0';
+ va_end(ap);
+ return atoi(NNTPbuffer);
+}
+
+char *
+tcpmessage()
+{
+ char *ptr;
+
+ ptr = strchr(NNTPbuffer, ' ');
+ if (ptr)
+ return ptr;
+ return NNTPbuffer;
+}
+
+read_article(lover, filename, userid)
+ linkoverview_t *lover;
+ char *filename, *userid;
+{
+ FILE *fp;
+ int fd;
+ struct stat st;
+ time_t mtime;
+ char *buffer;
+ char *artptr, *artend, *artback;
+
+ if (stat(filename, &st) != 0)
+ return 0;
+ lover->mtime = st.st_mtime;
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ {
+ bbslog("<bbslink> Err: can't open %s\n", filename);
+ return 0;
+ }
+
+ if (FD_BUF == NULL)
+ {
+ FD_BUF = mymalloc(st.st_size + 1 + strlen(COMMENT));
+ }
+ else
+ {
+ FD_BUF = myrealloc(FD_BUF, st.st_size + 1 + strlen(COMMENT));
+ }
+ FD_BUF[st.st_size] = '\0';
+ read(fd, FD_BUF, st.st_size);
+ sprintf(FD_BUF + st.st_size, "%s", COMMENT);
+ st.st_size += strlen(COMMENT);
+ FD_SIZE = st.st_size;
+ for (buffer = FD_BUF, artend = FD_BUF + st.st_size,
+ artback = strchr(buffer, '\n');
+ buffer && buffer < artend && *buffer;
+ artback = strchr(buffer, '\n')
+ )
+ {
+ /* while( fgets(buffer, sizeof buffer, fp) != NULL) { */
+ char *m, *n;
+ char *ptr;
+
+ if (artback != NULL)
+ *artback = '\0';
+ if (*buffer == '\0')
+ break;
+
+#ifndef MapleBBS
+ if (strstr(buffer, userid) != NULL)
+ {
+ m = strchr(buffer, '(');
+ n = strrchr(buffer, ')');
+ if (m != NULL && n != NULL)
+ {
+ strncpy(lover->nickname, m + 1, n - m - 1);
+ lover->nickname[n - m - 1] = '\0';
+ }
+ else
+ {
+ *lover->nickname = '\0';
+ }
+ }
+ else if (strncmp(buffer, "Date: ", 11) == 0)
+ {
+ strcpy(lover->date, buffer + 11);
+ }
+ else if (strncmp(buffer, "µo«H¯¸: ", 8) == 0)
+ {
+ m = strchr(buffer, '(');
+ n = strrchr(buffer, ')');
+ strncpy(lover->date, m + 1, n - m - 1);
+ lover->date[n - m - 1] = '\0';
+ }
+#endif
+
+ if (artback != NULL)
+ {
+ *artback = '\n';
+ buffer = artback + 1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (artback != NULL)
+ BODY = artback + 1;
+ else
+ BODY = "";
+ close(fd);
+ return 1;
+}
+
+save_outgoing(sover, filename, userid, poster, mtime)
+ soverview_t *sover, *filename, *userid, *poster;
+ time_t mtime;
+{
+ newsfeeds_t *nf;
+ char *group, *server, *serveraddr;
+ char *subject, *path;
+ char *board;
+ char *ptr1, *ptr2;
+
+ board = sover->board;
+
+ PATH = MYBBSID;
+ nf = (newsfeeds_t *) search_board(board);
+ if (nf == NULL)
+ {
+ bbslog("<bbslink> save_outgoing: No such board %s\n", board);
+ return;
+ }
+ else
+ {
+ group = nf->newsgroups;
+ server = nf->path;
+ }
+ if (!server || !*server)
+ {
+ sprintf(PATH_BUF, "%.*s (local)", sizeof PATH_BUF - 9, MYBBSID);
+ PATH = PATH_BUF;
+ serveraddr = "";
+ sover->path = PATH;
+ }
+ for (ptr1 = server; ptr1 && *ptr1;)
+ {
+ nodelist_t *nl;
+ char savech;
+
+ for (; *ptr1 && isspace(*ptr1); ptr1++);
+ if (!*ptr1)
+ break;
+ for (ptr2 = ptr1; *ptr2 && !isspace(*ptr2); ptr2++);
+ savech = *ptr2;
+ *ptr2 = '\0';
+ nl = (nodelist_t *) search_nodelist_bynode(ptr1);
+ *ptr2 = savech;
+ ptr1 = ptr2++;
+ if (nl == NULL)
+ continue;
+ /* if (nl->feedfp == NULL) continue; */
+
+ if (nl->host && *nl->host)
+ {
+ if (nl->feedfp == NULL)
+ {
+ nl->feedfp = fopen(fileglue("%s/%s.link", INNDHOME, nl->node), "a");
+ if (nl->feedfp == NULL)
+ {
+ bbslog("<save outgoing> append failed for %s/%s.link", INNDHOME, nl->node);
+ }
+ }
+ if (nl->feedfp != NULL)
+ {
+ flock(fileno(nl->feedfp), LOCK_EX);
+ fprintf(nl->feedfp, "%s\t%s\t%s\t%ld\t%s\t%s\n", sover->board, filename, group, mtime, FROM, sover->subject);
+ fflush(nl->feedfp);
+ flock(fileno(nl->feedfp), LOCK_UN);
+ }
+ }
+ if (savech == '\0')
+ break;
+ }
+}
+
+
+#ifndef MapleBBS
+save_article(board, filename, sover)
+ char *board, *filename;
+ soverview_t *sover;
+{
+ FILE *FN;
+
+ if (Verbose)
+ printf("<save_article> %s %s\n", board, filename);
+ FN = fopen(fileglue("%s/boards/%s/%s", BBSHOME, board, filename), "w");
+ if (FN == NULL)
+ {
+ bbslog("<save_article> err: %s %s\n", board, filename);
+ if (Verbose)
+ printf("<save_article> err: %s %s\n", board, filename);
+ return 0;
+ }
+ flock(fileno(FN), LOCK_EX);
+ fprintf(FN, "µo«H¤H: %s, «H°Ï: %s\n", POSTER, sover->board);
+ fprintf(FN, "¼Ð ÃD: %s\n", sover->subject);
+ fprintf(FN, "µo«H¯¸: %s (%s)\n", MYSITE, sover->date);
+ fprintf(FN, "Âà«H¯¸: %s\n", sover->path);
+ fprintf(FN, "\n");
+ fputs(BODY, FN);
+ flock(fileno(FN), LOCK_UN);
+ fclose(FN);
+
+#if defined(PalmBBS)
+ {
+ struct utimbuf times;
+
+ times.actime = sover->mtime;
+ times.modtime = sover->mtime;
+ utime(fileglue("%s/boards/%s/%s", BBSHOME, board, filename), &times);
+ utime(fileglue("%s/.bcache/%s", BBSHOME, board), NULL);
+ }
+#endif
+}
+#endif
+
+/* process_article() read_article() save_outgoing() save_article() */
+
+process_article(board, filename, userid, nickname, subject)
+ char *board, *filename, *userid, *nickname, *subject;
+{
+ char *n, *filepath;
+ char poster[MAXBUFLEN];
+ soverview_t sover;
+
+ if (!*userid)
+ {
+ return;
+ }
+ else if (!subject || !*subject)
+ {
+ subject = "µLÃD";
+ }
+ filepath = fileglue("%s/boards/%s/%s", BBSHOME, board, filename);
+ if (isfile(filepath))
+ {
+ linkoverview_t lover;
+
+ if (read_article(&lover, filepath, userid))
+ {
+
+#ifndef MapleBBS
+ strncpy(POSTER_BUF, fileglue("%s@%s (%s)", userid, MYBBSID, nickname), sizeof POSTER_BUF);
+ POSTER = POSTER_BUF;
+#endif
+
+ strncpy(FROM_BUF, fileglue("%s.bbs@%s (%s)", userid, MYADDR, nickname), sizeof FROM_BUF);
+ FROM = FROM_BUF;
+ sover.from = FROM;
+ sover.board = board;
+ sover.subject = subject;
+ PATH = MYBBSID;
+ sover.path = MYBBSID;
+ sover.date = lover.date;
+ sover.mtime = lover.mtime;
+ if (!VisitOnly)
+ {
+ save_outgoing(&sover, filename, userid, poster, lover.mtime);
+
+#ifndef MapleBBS
+ save_article(board, filename, &sover);
+#endif
+ }
+ }
+ }
+}
+
+
+char *
+baseN(val, base, len)
+ int val, base, len;
+{
+ int n, ans;
+ static char str[MAXBUFLEN];
+ char *pstr = str;
+ int index;
+
+ for (index = len - 1; index >= 0; index--)
+ {
+ n = val % base;
+ val /= base;
+ if (n < 10)
+ {
+ n += '0';
+ }
+ else if (n < 36)
+ {
+ n += 'A' - 10;
+ }
+ else if (n < 62)
+ {
+ n += 'a' - 36;
+ }
+ else
+ {
+ n = '_';
+ }
+ str[index] = n;
+ }
+ str[len] = '\0';
+ return str;
+}
+
+char *
+hash_value(str)
+ char *str;
+{
+ int val, n;
+ char *ptr;
+
+ if (*str)
+ ptr = str + strlen(str) - 1;
+ else
+ ptr = str;
+ val = 0;
+ while (ptr >= str)
+ {
+ n = *ptr;
+ val = (val + n * 0x100) ^ n;
+ ptr--;
+ }
+ return baseN(val, 64, 3);
+}
+
+/* process_cancel() save_outgoing() hash_value(); baseN(); ascii_date(); */
+
+
+read_outgoing(sover)
+ soverview_t *sover;
+{
+ char *board, *filename, *group, *from, *subject, *outgoingtype, *msgid, *path;
+ char *buffer, *bufferp;
+ FILE *ECHOMAIL, *FN;
+ char *hash;
+ char times[MAXBUFLEN];
+ time_t mtime;
+
+ board = sover->board;
+ filename = sover->filename;
+ group = sover->group;
+ mtime = sover->mtime;
+ from = sover->from;
+ subject = sover->subject;
+ outgoingtype = sover->outgoingtype;
+ msgid = sover->msgid;
+ path = sover->path;
+ if (Verbose)
+ {
+ printf("<read_outgoing> %s:%s:%s\n", board, filename, group);
+ printf(" => %ld:%s\n", mtime, from);
+ printf(" => %s\n", subject);
+ printf(" => %s:%s\n", outgoingtype, msgid);
+ printf(" => %s\n", path);
+ }
+ if (NEWSFEED == LOCAL)
+ {
+ char *end = strrchr(filename, '.');
+
+ if (end)
+ *end = '\0';
+ strncpy(times, baseN(atol(filename + 2), 48, 6), sizeof times);
+ if (end)
+ *end = '.';
+ hash = hash_value(fileglue("%s.%s", filename, board));
+ sprintf(MSGID_BUF, "%s$%s@%s", times, hash, MYADDR);
+ }
+ else
+ {
+ strncpy(MSGID_BUF, msgid, sizeof MSGID_BUF);
+ }
+ sover->msgid = MSGID;
+ if (mtime == -1)
+ {
+ static char BODY_BUF[MAXBUFLEN];
+
+ strncpy(BODY_BUF, fileglue("%s\r\n", subject), sizeof BODY_BUF);
+ BODY = BODY_BUF;
+ sprintf(SUBJECT_BUF, "cmsg cancel <%s>", MSGID);
+ SUBJECT = SUBJECT_BUF;
+ sprintf(CONTROL_BUF, "cancel <%s>", MSGID);
+ CONTROL = CONTROL_BUF;
+ strncpy(MSGID_BUF, fileglue("%d.%s", getpid(), MSGID_BUF), sizeof MSGID_BUF);
+ sprintf(DATE_BUF, "%s", ascii_date(time(NULL)));
+ DATE = DATE_BUF;
+ sover->subject = SUBJECT;
+ sover->control = CONTROL;
+ sover->msgid = MSGID;
+ sover->date = DATE;
+ }
+ else
+ {
+ sover->control = CONTROL;
+ sover->date = DATE_BUF;
+ DATE = DATE_BUF;
+ *CONTROL = '\0';
+ sprintf(DATE, "%s", ascii_date((mtime)));
+ if (NEWSFEED == LOCAL && !NoAction)
+ {
+ SITE = MYSITE;
+ PATH = MYBBSID;
+ GROUPS = group;
+
+#ifndef MapleBBS
+ echomaillog();
+#endif
+ }
+ BODY = "";
+ FD = open(fileglue("%s/boards/%s/%s", BBSHOME, board, filename), O_RDONLY);
+ if (FD < 0)
+ {
+ if (Verbose)
+ printf(" !! can't open %s/boards/%s/%s\n", BBSHOME, board, filename);
+ else
+ fprintf(stderr, "can't open %s/boards/%s/%s\n", BBSHOME, board, filename);
+ return -1;
+ }
+
+ FD_SIZE = filesize(fileglue("%s/boards/%s/%s", BBSHOME, board, filename));
+ if (FD_BUF == NULL)
+ {
+ FD_BUF = (char *) mymalloc(FD_SIZE + 1 + strlen(COMMENT));
+ }
+ else
+ {
+ FD_BUF = (char *) myrealloc(FD_BUF, FD_SIZE + 1 + strlen(COMMENT));
+ }
+ FD_END = FD_BUF + FD_SIZE;
+ *FD_END = '\0';
+ read(FD, FD_BUF, FD_SIZE);
+ sprintf(FD_END, "%s", COMMENT);
+ FD_SIZE += strlen(COMMENT);
+ FD_END += strlen(COMMENT);
+ if (Verbose)
+ {
+ printf("<read in> %s/boards/%s/%s\n", BBSHOME, board, filename);
+ }
+
+ *ORGANIZATION = '\0';
+ *NEWSCONTROL = '\0';
+ *NEWSAPPROVED = '\0';
+ *NNTPHOST_BUF = '\0';
+ NNTPHOST = NULL;
+
+ for (buffer = FD_BUF, bufferp = strchr(buffer, '\n');
+ buffer && *buffer; bufferp = strchr(buffer, '\n'))
+ {
+ if (bufferp)
+ *bufferp = '\0';
+ if (*buffer == '\0')
+ {
+ break;
+ }
+ /* printf("get buffer %s\n", buffer); */
+ if (NEWSFEED == REMOTE)
+ {
+ if (strncmp(buffer, "Date: ", 11) == 0)
+ {
+ strcpy(DATE_BUF, buffer + 11);
+ DATE = DATE_BUF;
+ }
+ else if (strncmp(buffer, "µo«H¯¸: ", 8) == 0)
+ {
+ char *m, *n;
+
+ m = strchr(buffer, '(');
+ n = strrchr(buffer, ')');
+ if (m && n)
+ {
+ strncpy(DATE_BUF, m + 1, n - m - 1);
+ DATE_BUF[n - m - 1] = '\0';
+ DATE = DATE_BUF;
+ strncpy(ORGANIZATION, buffer + 8, m - 8 - buffer - 1);
+ ORGANIZATION[m - 8 - buffer - 1] = '\0';
+ }
+ }
+ else if (strncmp(buffer, "Control: ", 9) == 0)
+ {
+ strcpy(NEWSCONTROL, buffer + 9);
+ }
+ else if (strncmp(buffer, "Approved: ", 10) == 0)
+ {
+ strcpy(NEWSAPPROVED, buffer + 10);
+ }
+ else if (strncmp(buffer, "Origin: ", 8) == 0)
+ {
+ strcpy(NNTPHOST_BUF, buffer + 8);
+ NNTPHOST = NNTPHOST_BUF;
+ }
+ }
+ if (bufferp)
+ {
+ *bufferp = '\n';
+ buffer = bufferp + 1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (bufferp)
+ {
+ BODY = bufferp + 1;
+ }
+ else
+ BODY = "";
+ if (bufferp)
+ for (buffer = bufferp + 1, bufferp = strchr(buffer, '\n');
+ buffer && *buffer; bufferp = strchr(buffer, '\n'))
+ {
+ if (bufferp)
+ *bufferp = '\0';
+ /* printf("get line (%s)\n", buffer); */
+ /* if( strcmp(buffer,".")==0 ) { buffer[1]='.'; buffer[2]='\0'; } */
+ if (NEWSFEED == REMOTE &&
+ strncmp(NEWSCONTROL, "cancel", 5) == 0 &&
+ strncmp(buffer, "------------------", 18) == 0)
+ {
+ break;
+ }
+ /* $BODY[ @BODY ] = "$_\r\n"; */
+ if (bufferp)
+ {
+ *bufferp = '\n';
+ buffer = bufferp + 1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ /* # fprintf("BODY @BODY\n"; */
+ close(FD);
+ }
+ return 0;
+}
+
+#ifdef TEST
+#endif
+
+openfeed(node)
+ nodelist_t *node;
+{
+ if (node->feedfp == NULL)
+ {
+ node->feedfp = fopen(fileglue("%s/%s.link", INNDHOME, node->node), "a");
+ }
+}
+
+queuefeed(node, textline)
+ nodelist_t *node;
+ char *textline;
+{
+ openfeed(node);
+ if (node->feedfp != NULL)
+ {
+ flock(fileno(node->feedfp), LOCK_EX);
+ fprintf(node->feedfp, "%s", textline);
+ fflush(node->feedfp);
+ flock(fileno(node->feedfp), LOCK_UN);
+ }
+}
+
+post_article(node, site, sover, textline)
+ nodelist_t *node;
+ char *site;
+ soverview_t *sover;
+ char *textline;
+{
+ int status;
+ char *filename = sover->filename;
+ char *msgid = sover->msgid;
+ char *board = sover->board;
+ char *bodyp, *body;
+
+ if (Verbose)
+ fprintf(stdout, "<post_article> %s %s %s\n", site, filename, msgid);
+ if (NoAction && Verbose)
+ {
+ printf(" ==>%s\n", sover->path);
+ printf(" ==>%s:%s\n", sover->from, sover->group);
+ printf(" ==>%s:%s\n", sover->subject, sover->date);
+ body = BODY;
+ bodyp = strchr(body, '\n');
+ if (bodyp)
+ *bodyp = '\0';
+ printf(" ==>%s\n", body);
+ if (bodyp)
+ *bodyp = '\n';
+ if (bodyp)
+ {
+ body = bodyp + 1;
+ bodyp = strchr(body, '\n');
+ if (bodyp)
+ *bodyp = '\0';
+ printf(" ==>%s\n", body);
+ if (bodyp)
+ *bodyp = '\n';
+ }
+ }
+ if (NoAction)
+ return 1;
+ if (NEWSFEED == REMOTE)
+ {
+ fprintf(NNTPwfp, "Path: %s\r\n", sover->path);
+ fprintf(NNTPwfp, "From: %s\r\n", sover->from);
+ fprintf(NNTPwfp, "Newsgroups: %s\r\n", sover->group);
+ fprintf(NNTPwfp, "Subject: %s\r\n", sover->subject);
+ /* # fprintf( NNTPwfp,"Post with subject ($subject)\n"); */
+ fprintf(NNTPwfp, "Date: %s\r\n", sover->date);
+ if (*ORGANIZATION)
+ fprintf(NNTPwfp, "Organization: %s\r\n", ORGANIZATION);
+ fprintf(NNTPwfp, "Message-ID: <%s>\r\n", sover->msgid);
+ if (*NEWSCONTROL)
+ fprintf(NNTPwfp, "Control: %s\r\n", NEWSCONTROL);
+ if (*NEWSAPPROVED)
+ fprintf(NNTPwfp, "Approved: %s\r\n", NEWSAPPROVED);
+ }
+ else
+ {
+ fprintf(NNTPwfp, "Path: %s\r\n", MYBBSID);
+ fprintf(NNTPwfp, "From: %s\r\n", sover->from);
+ fprintf(NNTPwfp, "Newsgroups: %s\r\n", sover->group);
+ fprintf(NNTPwfp, "Subject: %s\r\n", sover->subject);
+ fprintf(NNTPwfp, "Date: %s\r\n", sover->date);
+ fprintf(NNTPwfp, "Organization: %s\r\n", MYSITE);
+ fprintf(NNTPwfp, "Message-ID: <%s>\r\n", sover->msgid);
+ fprintf(NNTPwfp, "X-Filename: %s/%s\r\n", sover->board, sover->filename);
+ }
+ if (NNTPHOST && *NNTPHOST && USEIHAVE)
+ fprintf(NNTPwfp, "NNTP-Posting-Host: %s\r\n", NNTPHOST);
+ else if (NNTPHOST && *NNTPHOST)
+ fprintf(NNTPwfp, "X-Auth-From: %s\r\n", NNTPHOST);
+ if (*CONTROL)
+ {
+ fprintf(NNTPwfp, "Control: %s\r\n", CONTROL);
+ }
+ fputs("\r\n", NNTPwfp);
+ for (body = BODY, bodyp = strchr(body, '\n');
+ body && *body; bodyp = strchr(body, '\n'))
+ {
+ if (bodyp)
+ *bodyp = '\0';
+
+ fputs(body, NNTPwfp);
+ if (body[0] == '.' && body[1] == '\0')
+ fputs(".", NNTPwfp);
+ fputs("\r\n", NNTPwfp);
+ if (bodyp)
+ {
+ *bodyp = '\n';
+ body = bodyp + 1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ /* print "send out @BODY\n"; */
+ status = tcpcommand(".");
+ /* 435 duplicated article 437 invalid header */
+
+ if (USEIHAVE)
+ {
+ if (status == 235)
+ {
+ if (NEWSFEED == LOCAL)
+ {
+ bbslog("Sendout <%s> from %s/%s\n", msgid, board, filename);
+ }
+ }
+ else if (status == 437 || status == 435)
+ {
+ bbslog("<bbslink> :Warn: %d %s <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Warn: %d %s <%s>\n", status, (char *) tcpmessage(), msgid);
+ return 0;
+ }
+ else
+ {
+ bbslog("<bbslink> :Err: %d %s of <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Err: %d %s of <%s>\n", status, (char *) tcpmessage(), msgid);
+ queuefeed(node, textline);
+ return 0;
+ }
+ }
+ else if (USEPOST)
+ {
+ if (status == 240)
+ {
+ bbslog("Sendout <%s> from %s/%s\n", msgid, board, filename);
+ }
+ else
+ {
+ bbslog("<bbslink> :Err: %d %s of <%s>\n", status, (char *) tcpmessage(), msgid);
+ queuefeed(node, textline);
+ return 0;
+ }
+ }
+ else
+ {
+ if (status == 250)
+ {
+ bbslog("<bbslink> DATA Sendout <%s> from %s/%s\n", msgid, board, filename);
+ if (Verbose)
+ printf("<DATA Sendout> <%s> from %s/%s\n", msgid, board, filename);
+ }
+ else
+ {
+ bbslog("<bbslink> :Err: %d %s of <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Err: %d %s of <%s>\n", status, (char *) tcpmessage(), msgid);
+ queuefeed(node, textline);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+process_cancel(board, filename, userid, nickname, subject)
+ char *board, *filename, *userid, *nickname, *subject;
+{
+ time_t mtime;
+ soverview_t sover;
+
+ if (!userid || !*userid)
+ {
+ return;
+ }
+ mtime = -1;
+ strncpy(FROM_BUF, fileglue("%s.bbs@%s (%s)", userid, MYADDR, nickname), sizeof FROM_BUF);
+ FROM = FROM_BUF;
+ sover.from = FROM;
+ sover.board = board;
+ sover.subject = subject;
+ PATH = MYBBSID;
+ sover.path = MYBBSID;
+ /* save_outgoing(&sover, filename, userid, poster, -1); */
+ save_outgoing(&sover, filename, userid, userid, -1);
+}
+
+open_link(hostname, hostprot, hostport)
+ char *hostname, *hostprot, *hostport;
+{
+ USEIHAVE = 1;
+ USEPOST = 0;
+ USEDATA = 0;
+ FEEDTYPE = ' ';
+ if (Verbose)
+ printf("<OPEN_link> %s %s %s\n", hostname, hostprot, hostport);
+ if (strncasecmp(hostprot, "IHAVE", 5) != 0)
+ {
+ USEIHAVE = 0;
+ USEPOST = 1;
+ if (strncasecmp(hostprot, "POST", 4) == 0)
+ {
+ USEPOST = 1;
+ }
+ else if (strncasecmp(hostprot, "DATA", 4) == 0)
+ {
+ USEPOST = 0;
+ USEDATA = 1;
+ }
+ }
+
+ FEEDTYPE = hostname[0];
+ if (!USEDATA)
+ {
+ char *atsign;
+
+ if (FEEDTYPE == '-' || FEEDTYPE == '+')
+ {
+ hostname = hostname + 1;
+ }
+ atsign = strchr(hostname, '@');
+ if (atsign != NULL)
+ {
+ hostname = atsign + 1;
+ }
+ if (!NoAction)
+ {
+ if (Verbose)
+ printf("<inetclient> %s %s\n", hostname, hostport);
+ if ((NNTP = inetclient(hostname, hostport, "tcp")) < 0)
+ {
+ bbslog("<bbslink> :Err: server %s %s error: cant connect\n", hostname, hostport);
+ if (Verbose)
+ printf(":Err: server %s %s error: cant connect\n", hostname, hostport);
+ return 0;
+ /* exit( 0 ); */
+ /* return; */
+ }
+ NNTPrfp = fdopen(NNTP, "r");
+ NNTPwfp = fdopen(NNTP, "w");
+ fgets(NNTPbuffer, sizeof NNTPbuffer, NNTPrfp);
+ if (atoi(NNTPbuffer) != 200)
+ {
+ bbslog("<bbslink> :Err: server error: %s", NNTPbuffer);
+ if (Verbose)
+ printf(":Err: server error: %s", NNTPbuffer);
+ return 0;
+ /* exit( 0 ); */
+ }
+ }
+ else
+ {
+ if (Verbose)
+ printf("<inetclient> %s %s\n", hostname, hostport);
+ }
+ }
+ else
+ {
+ if (!NoAction)
+ {
+ if (Verbose)
+ printf("<inetclient> localhost %s\n", hostport);
+ if ((NNTP = inetclient("localhost", hostport, "tcp")) < 0)
+ {
+ bbslog("<bbslink> :Err: server %s port %s error: cant connect\n", hostname, hostport);
+ if (Verbose)
+ printf(":Err: server error: cant connect");
+ return 0;
+ /* exit( 0 ); */
+ /* return; */
+ }
+ NNTPrfp = fdopen(NNTP, "r");
+ NNTPwfp = fdopen(NNTP, "w");
+ fgets(NNTPbuffer, sizeof NNTPbuffer, NNTPrfp);
+ if (strncmp(NNTPbuffer, "220", 3) != 0)
+ {
+ bbslog("<bbslink> :Err: server error: %s", NNTPbuffer);
+ if (Verbose)
+ printf(":Err: server error: %s", NNTPbuffer);
+ return 0;
+ /* exit( 0 ); */
+ }
+ if (strncmp(NNTPbuffer, "220-", 4) == 0)
+ {
+ fgets(NNTPbuffer, sizeof NNTPbuffer, NNTPrfp);
+ }
+ }
+ else
+ {
+ if (Verbose)
+ printf("<inetclient> %s %s\n", hostname, hostport);
+ }
+ }
+ return 1;
+}
+
+send_outgoing(node, site, hostname, sover, textline)
+ nodelist_t *node;
+ soverview_t *sover;
+ char *hostname, *site;
+ char *textline;
+{
+ int status;
+ char *board, *filepath, *msgid;
+ int returnstatus = 0;
+
+ board = sover->board;
+ filepath = sover->filename;
+ msgid = sover->msgid;
+
+ if (Verbose)
+ printf("<send_outgoing> %s:%s:%s:%s\n", site, board, filepath, msgid);
+ if (BODY != NULL && !NoAction)
+ {
+ if (USEIHAVE)
+ {
+ status = tcpcommand("IHAVE <%s>", msgid);
+ if (status == 335)
+ {
+ returnstatus = post_article(node, site, sover, textline);
+ }
+ else if (status == 435)
+ {
+ bbslog("<bbslink> :Warn: %d %s, IHAVE <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Warn: %d %s, IHAVE <%s>\n", status, (char *) tcpmessage(), msgid);
+ returnstatus = 0;
+ }
+ else
+ {
+ bbslog("<bbslink> :Err: %d %s, IHAVE <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Err: %d %s, IHAVE <%s>\n", status, (char *) tcpmessage(), msgid);
+ queuefeed(node, textline);
+ returnstatus = 0;
+ }
+ }
+ else if (USEPOST)
+ {
+ tcpcommand("MODE READER");
+ status = tcpcommand("POST");
+ if (status == 340)
+ {
+ returnstatus = post_article(node, site, sover, textline);
+ }
+ else if (status == 441)
+ {
+ bbslog("<bbslink> :Warn: %d %s, POST <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Warn: %d %s, POST <%s>\n", status, (char *) tcpmessage(), msgid);
+ returnstatus = 0;
+ }
+ else
+ {
+ bbslog("<bbslink> :Err: %d %s, POST <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Err: %d %s, POST <%s>\n", status, (char *) tcpmessage(), msgid);
+ queuefeed(node, textline);
+ returnstatus = 0;
+ }
+ }
+ else
+ {
+ tcpcommand("HELO");
+ tcpcommand("MAIL FROM: bbs");
+ tcpcommand("RCPT TO: %s", hostname);
+ status = tcpcommand("DATA");
+ if (status == 354)
+ {
+ returnstatus = post_article(node, site, sover, textline);
+ }
+ else
+ {
+ bbslog("<bbslink> :Err: %d %s, DATA <%s>\n", status, (char *) tcpmessage(), msgid);
+ if (Verbose)
+ printf(":Err: %d %s, DATA <%s>\n", status, (char *) tcpmessage(), msgid);
+
+ queuefeed(node, textline);
+ returnstatus = 0;
+ }
+ }
+ }
+ else if (NoAction)
+ {
+ returnstatus = post_article(node, site, sover, textline);
+ }
+ return returnstatus;
+}
+
+save_nntplink(node, overview)
+ nodelist_t *node;
+ char *overview;
+{
+ FILE *POSTS;
+ char buffer[1024];
+
+ openfeed(node);
+ POSTS = fopen(overview, "r");
+ if (POSTS == NULL)
+ return 0;
+ openfeed(node);
+ /* if (node->feedfp == NULL) return 0; */
+ flock(fileno(node->feedfp), LOCK_EX);
+ while (fgets(buffer, sizeof buffer, POSTS) != NULL)
+ {
+ fputs(buffer, node->feedfp);
+ fflush(node->feedfp);
+ }
+ flock(fileno(node->feedfp), LOCK_UN);
+ fclose(POSTS);
+ if (Verbose)
+ printf("<Unlinking> %s\n", overview);
+ if (!NoAction)
+ unlink(overview);
+ return 1;
+}
+
+
+char *
+get_tmpfile(tmpfile)
+ char *tmpfile;
+{
+ FILE *FN;
+ static char result[256];
+
+ FN = fopen(tmpfile, "r");
+ fgets(result, sizeof result, FN);
+ fclose(FN);
+ unlink(tmpfile);
+ return (result);
+}
+
+/* cancel moderating posts */
+
+cancel_outgoing(board, filename, from, subject)
+ char *board, *filename, *from, *subject;
+{
+ char *base, filepath[MAXPATHLEN];
+ FILE *FN;
+ char *result;
+ char TMPFILE[MAXPATHLEN];
+
+ if (Verbose)
+ {
+ printf("<cancel_outgoing> %s %s %s %s\n", board, filename, from, subject);
+ }
+
+ sprintf(TMPFILE, "/tmp/cancel_outgoing.%d.%d", getuid(), getpid());
+
+ bbslog("<cancel_outgoing> Try to move moderated post from %s to deleted\n", board);
+ if (Verbose)
+ printf("Try to move moderated post from %s to deleted\n", board);
+ FN = popen(fileglue("%s/bbspost post %s/boards/deleted > %s",
+ INNDHOME, BBSHOME, TMPFILE), "w");
+ if (FN == NULL)
+ {
+ bbslog("<cancel_outgoing> can't run %s/bbspost\n", INNDHOME);
+ if (Verbose)
+ printf("<cancel_outgoing> can't run %s/bbspost\n", INNDHOME);
+ return 0;
+ }
+ fprintf(FN, "%s\n", from);
+ fprintf(FN, "%s\n", subject);
+ fprintf(FN, "µo«H¤H: %s, «H°Ï: %s\n", from, board);
+ fprintf(FN, "¼Ð ÃD: %s\n", subject);
+ fprintf(FN, "µo«H¯¸: %s (%s)\n", MYSITE, DATE);
+ fprintf(FN, "Âà«H¯¸: %s\n", MYBBSID);
+ fputs("\n", FN);
+ fputs(BODY, FN);
+ pclose(FN);
+ result = (char *) get_tmpfile(TMPFILE);
+ if (strncmp(result, "post to ", 8) == 0)
+ {
+ /* try to remove it */
+ strncpy(filepath, fileglue("%s/boards/%s/%s", BBSHOME, board, filename), sizeof filepath);
+ if (isfile(filepath))
+ {
+ Rename(filepath, fileglue("%s.cancel", filepath));
+ }
+ FN = fopen(filepath, "w");
+
+ fprintf(FN, "µo«H¤H: %s, «H°Ï: %s\n", from, board);
+ fprintf(FN, "¼Ð ÃD: <article cancelled and mailed to the moderator\n");
+ fprintf(FN, "µo«H¯¸: %s (%s)\n", MYSITE, DATE);
+ fprintf(FN, "Âà«H¯¸: %s\n", MYBBSID);
+ fprintf(FN, "\n");
+ fputs("\n", FN);
+ fprintf(FN, "§Aªº¤å³¹ \"%s\" ¤w¸g°e©¹¼f®Ö¤¤. ½Ðµ¥«Ý¦^ÂÐ.\n", subject);
+ fputs("\n", FN);
+ fputs("Your post has been sent to the moderator and move\n", FN);
+ fputs("into the deleted board. If the post accepted by the moderator,\n", FN);
+ fputs("it will be posted in this board again. Please wait.\n", FN);
+
+ }
+ else
+ {
+ bbslog("%s", result);
+ }
+
+ bbslog("%s/bbspost cancel %s %s %s moderate\n", INNDHOME, BBSHOME, board, filename);
+ if (Verbose)
+ printf("%s/bbspost cancel %s %s %s moderate\n", INNDHOME, BBSHOME, board, filename);
+ system(fileglue("%s/bbspost cancel %s %s %s moderate",
+ INNDHOME, BBSHOME, board, filename));
+ return 1;
+}
+
+/*
+ * send_nntplink open_link read_outgoing send_outgoing post_article
+ * cancel_outgoing
+ */
+send_nntplink(node, site, hostname, hostprot, hostport, overview, nlcount)
+ nodelist_t *node;
+ char *site, *hostname, *hostprot, *hostport, *overview;
+ int nlcount;
+{
+ FILE *POSTS;
+ char textline[1024];
+ char baktextline[1024];
+ char *filepath;
+ int status;
+
+ if (Verbose)
+ {
+ printf("<send nntplink> %s %s %s %s\n", site, hostname, hostprot, hostport);
+ printf(" ==> %s\n", overview);
+ }
+ if (!open_link(hostname, hostprot, hostport))
+ {
+ save_nntplink(node, overview);
+ return 0;
+ }
+ POSTS = fopen(overview, "r");
+ if (POSTS == NULL)
+ {
+ if (Verbose)
+ printf("open %s failed\n", overview);
+ return 0;
+ }
+ while (fgets(textline, sizeof textline, POSTS) != NULL)
+ {
+ char *linebreak = strchr(textline, '\n');
+ char *ptr;
+ char *board, *filename, *subject, *group, *mtime, *from;
+ char *outgoingtype;
+ char *msgid, *path;
+ soverview_t soverview;
+
+ strcpy(baktextline, textline);
+ if (linebreak)
+ *linebreak = '\0';
+
+ board = "", filename = "", mtime = "", group = "", from = "", subject = "";
+ outgoingtype = "", msgid = "", path = "";
+ /* get board field */
+ board = textline;
+ ptr = strchr(textline, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* filename field */
+ filename = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* group field */
+ group = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* mtime field */
+ mtime = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* from field */
+ from = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* subject */
+ subject = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ goto try_read_outgoing;
+ *ptr++ = '\0';
+
+ /* outgoing type field */
+ outgoingtype = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ goto try_read_outgoing;
+ *ptr++ = '\0';
+
+ /* msgid */
+ msgid = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ goto try_read_outgoing;
+ *ptr++ = '\0';
+
+ /* path */
+ path = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ goto try_read_outgoing;
+
+try_read_outgoing:
+
+ NEWSFEED = LOCAL;
+ if (outgoingtype && msgid && path && *outgoingtype && *msgid && *path)
+ {
+ char *left, *right;
+
+ NEWSFEED = REMOTE;
+ left = strchr(msgid, '<');
+ right = strrchr(msgid, '>');
+ if (left)
+ msgid = left + 1;
+ if (right)
+ *right = '\0';
+ }
+ soverview.board = board;
+ soverview.filename = filename;
+ soverview.group = group;
+ soverview.mtime = atol(mtime);
+ soverview.from = from;
+ soverview.subject = subject;
+ soverview.outgoingtype = outgoingtype;
+ soverview.msgid = msgid;
+ soverview.path = path;
+ if (read_outgoing(&soverview) == 0)
+ {
+ int sendresult = send_outgoing(node, site, hostname, &soverview, baktextline);
+ int sendfailed = 1 - sendresult;
+
+ if (NEWSFEED == REMOTE)
+ {
+ BBSLINK_STAT[nlcount].remotesendout += sendresult;
+ BBSLINK_STAT[nlcount].remotefailed += sendfailed;
+ }
+ else
+ {
+ BBSLINK_STAT[nlcount].localsendout += sendresult;
+ BBSLINK_STAT[nlcount].localfailed += sendfailed;
+ }
+ if (node->feedtype == '-')
+ {
+ if (!NoAction && sendresult)
+ cancel_outgoing(board, filename, from, subject);
+ }
+ }
+ }
+ fclose(POSTS);
+ close_link();
+ if (Verbose)
+ printf("<Unlinking> %s\n", overview);
+ if (!NoAction)
+ unlink(overview);
+}
+
+close_link()
+{
+ int status;
+
+ if (Verbose)
+ printf("<close_link>\n");
+ if (NoAction)
+ return;
+ status = tcpcommand("QUIT");
+ if (status != 205 && status != 221)
+ {
+ bbslog("<bbslink> :Err: Cannot quit message '%d %s'\n", status, (char *) tcpmessage());
+ if (Verbose)
+ printf(":Err: Cannot quit message '%d %s'\n", status, (char *) tcpmessage());
+ }
+ fclose(NNTPwfp);
+ fclose(NNTPrfp);
+ close(NNTP);
+}
+
+
+/*
+ * send_article() send_nntplink() read_outgoing()
+ *
+ */
+
+send_article()
+{
+ char *site, *addr, *protocol, *port, *op;
+ char *nntphost;
+ int nlcount;
+
+ chdir(INNDHOME);
+
+ for (nlcount = 0; nlcount < NLCOUNT; nlcount++)
+ {
+ nodelist_t *node;
+ char linkfile[MAXPATHLEN];
+ char sendfile[MAXPATHLEN];
+ char feedfile[MAXPATHLEN];
+ char feedingfile[MAXPATHLEN];
+ char protocol[MAXBUFLEN], port[MAXBUFLEN];
+
+ node = NODELIST + nlcount;
+ site = node->node;
+ nntphost = node->host;
+ op = node->protocol;
+
+ if (DefaultFeedSite && *DefaultFeedSite)
+ {
+ if (strcmp(node->node, DefaultFeedSite) != 0)
+ continue;
+ }
+
+ if (op && (strncasecmp(op, "ihave", 5) == 0 ||
+ strncasecmp(op, "post", 4) == 0 ||
+ strncasecmp(op, "data", 4) == 0))
+ {
+ char *left, *right;
+
+ left = strchr(op, '('), right = strrchr(op, ')');
+ if (left && right)
+ {
+ *left = '\0';
+ *right = '\0';
+ strncpy(protocol, op, sizeof protocol);
+ strncpy(port, left + 1, sizeof port);
+ *left = '(';
+ *right = ')';
+ }
+ else
+ {
+ strncpy(protocol, op, sizeof protocol);
+ strncpy(port, "nntp", sizeof port);
+ }
+ }
+ else
+ {
+ strcpy(protocol, "IHAVE");
+ strcpy(port, "nntp");
+ }
+ sprintf(linkfile, "%s.link", site);
+ sprintf(sendfile, "%s.sending", site);
+ sprintf(feedfile, "%s.feed", site);
+ sprintf(feedingfile, "%s.feeding", site);
+ if (isfile(sendfile) && !iszerofile(sendfile))
+ {
+ if (bbslink_get_lock(sendfile))
+ {
+ send_nntplink(node, site, nntphost, protocol, port, sendfile, nlcount);
+ bbslink_un_lock(sendfile);
+ }
+ }
+ if (isfile(linkfile) && !iszerofile(linkfile))
+ {
+ if (!NoAction)
+ {
+ if (bbslink_get_lock(sendfile) && bbslink_get_lock(linkfile) &&
+ bbslink_get_lock(feedingfile))
+ {
+ if (isfile(sendfile) && !iszerofile(sendfile))
+ {
+ save_nntplink(node, sendfile);
+ }
+ if (node->feedfp)
+ {
+ fclose(node->feedfp);
+ node->feedfp = NULL;
+ }
+ Rename(linkfile, sendfile);
+ send_nntplink(node, site, nntphost, protocol, port, sendfile, nlcount);
+ bbslink_un_lock(linkfile);
+ bbslink_un_lock(sendfile);
+ bbslink_un_lock(feedingfile);
+ }
+ }
+ else
+ {
+ send_nntplink(node, site, nntphost, protocol, port, linkfile, nlcount);
+ }
+ }
+ if (isfile(feedingfile) && !iszerofile(feedingfile))
+ {
+ if (bbslink_get_lock(feedingfile))
+ {
+ send_nntplink(node, site, nntphost, protocol, port, feedingfile, nlcount);
+ bbslink_un_lock(feedingfile);
+ }
+ }
+ if (isfile(feedfile) && !iszerofile(feedfile))
+ {
+ if (!NoAction)
+ {
+ if (bbslink_get_lock(feedfile) && bbslink_get_lock(feedingfile))
+ {
+ if (isfile(feedingfile) && !iszerofile(feedingfile))
+ {
+ save_nntplink(node, feedingfile);
+ if (node->feedfp)
+ {
+ fclose(node->feedfp);
+ node->feedfp = NULL;
+ }
+ }
+ Rename(feedfile, feedingfile);
+ system(fileglue("%s/ctlinnbbsd reload > /dev/null", INNDHOME));
+ send_nntplink(node, site, nntphost, protocol, port, feedingfile, nlcount);
+ bbslink_un_lock(feedfile);
+ bbslink_un_lock(feedingfile);
+ }
+ }
+ else
+ {
+ send_nntplink(node, site, nntphost, protocol, port, feedfile, nlcount);
+ }
+ }
+ }
+}
+
+/* bntplink() bbspost() process_article() process_cancel() send_article() */
+
+
+show_usage(argv)
+ char *argv;
+{
+ fprintf(stderr, "%s initialization failed or improper options !!\n", argv);
+/*
+woju
+*/
+ fprintf(stderr, "Usage: %s [options] bbs_home board\n", argv);
+ fprintf(stderr, " -v (show transmission status)\n");
+ fprintf(stderr, " -n (dont send out articles and leave queue untouched)\n");
+ fprintf(stderr, " -s site (only process articles sent to site)\n");
+ fprintf(stderr, " -V (visit only: bbspost visit)\n");
+ fprintf(stderr, " -N (no visit, and only process batch queue)\n");
+ fprintf(stderr, " -k (kill the former bbslink process before started)\n\n");
+ fprintf(stderr, "¥»µ{¦¡­n¥¿±`°õ¦æ¥²¶·±N¥H¤UÀɮ׸m©ó %s/innd ¤U:\n", BBSHOME);
+ fprintf(stderr, "bbsname.bbs ³]©w¶Q¯¸ªº BBS ID (½Ð¾¨¶q²µu)\n");
+ fprintf(stderr, "nodelist.bbs ³]©wºô¸ô¦U BBS ¯¸ªº ID, Address ©M fullname\n");
+ fprintf(stderr, "newsfeeds.bbs ³]©wºô¸ô«H¥óªº newsgroup board nodelist ...\n");
+}
+
+
+/*
+woju
+*/
+struct fileheader
+{
+ char filename[33]; /* M.9876543210.A */
+ char savemode; /* file save mode */
+ char owner[12 + 2]; /* uid[.] */
+ char date[6]; /* [02/02] or space(5) */
+ char title[72+ 1];
+ unsigned char filemode; /* must be last field @ boards.c */
+};
+typedef struct fileheader fileheader;
+
+
+bntplink(argc, argv)
+ int argc;
+ char **argv;
+{
+/*
+woju
+ static char *OUTING = ".outing";
+*/
+ static char OUTING[MAXPATHLEN];
+ fileheader fhdr;
+ char *fname, *s1, *s2;
+ char nick[100];
+ FILE* fp;
+
+ nodelist_t *nl;
+ int linkport;
+ char result[4096];
+ char cancelfile[MAXPATHLEN], cancelpost[MAXPATHLEN];
+ char bbslink_lockfile[MAXPATHLEN];
+ FILE *NEWPOST;
+ char *left, *right;
+ int nlcount;
+
+ strcpy(BBSHOME, argv[0]);
+/*
+woju
+*/
+ sprintf(OUTING, "%s/boards/%s/", BBSHOME, argv[1]);
+ fname = OUTING + strlen(OUTING);
+
+ if (initial_bbs("link") == 0)
+ {
+ return -1;
+ }
+
+ BBSLINK_STAT = (stat_t *) malloc(sizeof(stat_t) * (NLCOUNT + 1));
+ for (nlcount = 0; nlcount < NLCOUNT; nlcount++)
+ {
+ BBSLINK_STAT[nlcount].localsendout = 0;
+ BBSLINK_STAT[nlcount].remotesendout = 0;
+ BBSLINK_STAT[nlcount].localfailed = 0;
+ BBSLINK_STAT[nlcount].remotefailed = 0;
+ }
+
+ nl = (nodelist_t *) search_nodelist_bynode(MYBBSID);
+ if (nl == NULL)
+ {
+ *MYADDR = '\0';
+ *MYSITE = '\0';
+ *LINKPROTOCOL = '\0';
+ }
+ else
+ {
+ strncpy(MYADDR, nl->host, sizeof MYADDR);
+ strncpy(LINKPROTOCOL, nl->protocol, sizeof LINKPROTOCOL);
+ strncpy(MYSITE, nl->comments, sizeof MYSITE);
+ }
+ if (Verbose)
+ {
+ printf("MYADDR: %s\n", MYADDR);
+ printf("MYSITE: %s\n", MYSITE);
+ }
+ left = strchr(nl->protocol, '(');
+ right = strrchr(nl->protocol, ')');
+ if (left && right)
+ {
+ *right = '\0';
+ strncpy(LINKPROTOCOL, nl->protocol, sizeof LINKPROTOCOL);
+ LINKPORT = atoi(left + 1);
+ *right = ')';
+ }
+
+ if (!NoVisit)
+ {
+ sprintf(bbslink_lockfile, "%s/.bbslink.visit", INNDHOME);
+/*
+woju
+ if (!Rename(fileglue("%s/out.bntp", INNDHOME), OUTING) && bbslink_get_lock(bbslink_lockfile))
+*/
+ if (strcpy(fname, ".DIR"))
+ {
+ /* When try to visit new post, try to lock it */
+ NEWPOST = fopen(OUTING, "r");
+ if (NEWPOST == NULL)
+ {
+ bbslog("<bbslink> Err: can't open %s\n", OUTING);
+/*
+woju
+ bbslink_un_lock(bbslink_lockfile);
+*/
+ return -1;
+ }
+#ifdef 0
+woju
+ while (fgets(result, sizeof result, NEWPOST))
+ {
+ /* chop( $_ ); */
+ char *board, *filename, *userid, *nickname, *subject;
+ char *ptr;
+
+ ptr = strchr(result, '\n');
+ if (ptr)
+ *ptr = '\0';
+
+ board = filename = userid = nickname = subject = NULL;
+ /* board field */
+ board = result;
+ ptr = strchr(result, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* filename field */
+ filename = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* userid field */
+ userid = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* nickname field */
+ nickname = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* subject field */
+ subject = ptr;
+ /* ptr = strchr(ptr, '\t'); if (ptr == NULL) continue; ptr++ = '\0'; */
+
+ process_article(board, filename, userid, nickname, subject);
+ }
+#endif
+ while (fread(&fhdr, sizeof(fhdr), 1, NEWPOST) == 1) {
+ nick[1] = 0;
+ strcpy(fname, fhdr.filename);
+ if (fp = fopen(OUTING, "r")) {
+ fgets(nick, 100, fp);
+ if ((s1 = strchr(nick, '(')) && (s2 = strrchr(nick, ')')))
+ *s2 = 0;
+ else
+ s1 = nick;
+ fclose(fp);
+ }
+ printf("%s\n", fhdr.title);
+ process_article(argv[1], fhdr.filename, fhdr.owner, s1 + 1, fhdr.title);
+ }
+ fclose(NEWPOST);
+/*
+woju
+ unlink(OUTING);
+ bbslink_un_lock(bbslink_lockfile);
+*/
+ } /* getlock */
+ } /* if NoVisit is false */
+
+#if 0
+woju
+ sprintf(cancelpost, "%s/cancel.bntp", INNDHOME);
+ if (isfile(cancelpost))
+ {
+ FILE *CANCELFILE;
+
+ if (bbslink_get_lock(cancelpost) && bbslink_get_lock(cancelfile))
+ {
+ sprintf(cancelfile, "%s.%d", cancelpost, getpid());
+ Rename(cancelpost, cancelfile);
+ CANCELFILE = fopen(cancelfile, "r");
+ while (fgets(result, sizeof result, CANCELFILE) != NULL)
+ {
+ /* chop( $_ ); */
+ char *board, *filename, *userid, *nickname, *subject;
+ char *ptr, **sptr;
+
+ ptr = strchr(result, '\n');
+ if (ptr)
+ *ptr = '\0';
+ board = filename = userid = nickname = subject = NULL;
+
+ /* board field */
+ board = result;
+ ptr = strchr(result, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* filename field */
+ filename = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* userid field */
+ userid = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* nickname field */
+ nickname = ptr;
+ ptr = strchr(ptr, '\t');
+ if (ptr == NULL)
+ continue;
+ *ptr++ = '\0';
+
+ /* subject field */
+ subject = ptr;
+ /* ptr = strchr(ptr, '\t'); if (ptr == NULL) continue; ptr++ = '\0'; */
+ process_cancel(board, filename, userid, nickname, subject);
+ }
+ fclose(CANCELFILE);
+ if (Verbose)
+ printf("Unlinking %s\n", cancelfile);
+ if (!NoAction)
+ unlink(cancelfile);
+ bbslink_un_lock(cancelfile);
+ bbslink_un_lock(cancelpost);
+ }
+ }
+#endif
+
+ for (nlcount = 0; nlcount < NLCOUNT; nlcount++)
+ {
+ if (NODELIST[nlcount].feedfp != NULL)
+ {
+ fclose(NODELIST[nlcount].feedfp);
+ NODELIST[nlcount].feedfp = NULL;
+ }
+ }
+
+ send_article();
+ for (nlcount = 0; nlcount < NLCOUNT; nlcount++)
+ {
+ int localsendout, remotesendout, localfailed, remotefailed;
+
+ localsendout = BBSLINK_STAT[nlcount].localsendout;
+ remotesendout = BBSLINK_STAT[nlcount].remotesendout;
+ localfailed = BBSLINK_STAT[nlcount].localfailed;
+ remotefailed = BBSLINK_STAT[nlcount].remotefailed;
+ if (localsendout || remotesendout || localfailed || remotefailed)
+ bbslog("<bbslink> [%s]%s lsend:%d rsend:%d lfail:%d rfail:%d\n",
+ NODELIST[nlcount].node, NoAction ? "NoAction" : "", localsendout, remotesendout,
+ localfailed, remotefailed);
+ if (NODELIST[nlcount].feedfp != NULL)
+ {
+ fclose(NODELIST[nlcount].feedfp);
+ NODELIST[nlcount].feedfp = NULL;
+ }
+ }
+ if (BBSLINK_STAT);
+ free(BBSLINK_STAT);
+ return 0;
+}
+/*
+termbbslink(sig)
+ int sig;
+{
+ bbslog("kill signal received %d, terminated\n", sig);
+ if (Verbose)
+ printf("kill signal received %d, terminated\n", sig);
+ exit(0);
+}
+*/
+void
+termbbslink()
+{
+ bbslog("kill signal received ??, terminated\n");
+ if (Verbose)
+ printf("kill signal received ??, terminated\n");
+ exit(0);
+}
+
+char *REMOTEUSERNAME = "";
+char *REMOTEHOSTNAME = "";
+
+extern char *optarg;
+extern int opterr, optind;
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int c, errflag = 0;
+
+ CONTROL = CONTROL_BUF;
+ MSGID = MSGID_BUF;
+
+ /* For debug Only */
+#define DEBUGBBSLINK
+
+#ifdef DEBUGBBSLINK
+ NoAction = 0;
+ Verbose = 0;
+ VisitOnly = 0;
+ NoVisit = 0;
+ DefaultFeedSite = "";
+#endif
+
+ while ((c = getopt(argc, argv, "s:hnvVNk")) != -1)
+ switch (c)
+ {
+ case 's':
+ DefaultFeedSite = optarg;
+ break;
+ case 'n':
+ NoAction = 1;
+ break;
+ case 'v':
+ Verbose = 1;
+ break;
+ case 'V':
+ VisitOnly = 1;
+ break;
+ case 'N':
+ NoVisit = 1;
+ break;
+ case 'k':
+ KillFormerBBSLINK = 1;
+ break;
+ case 'h':
+ default:
+ errflag++;
+ break;
+ }
+ if (errflag > 0)
+ {
+ show_usage(argv[0]);
+ return (1);
+ }
+ if (argc - optind < 2)
+ {
+ show_usage(argv[0]);
+ exit(1);
+ }
+ signal(SIGTERM, termbbslink);
+ if (bntplink(argc - optind, argv + optind) != 0)
+ {
+ show_usage(argv[0]);
+ exit(1);
+ }
+ return 0;
+}
diff --git a/innbbsd/bbsnnrp.c b/innbbsd/bbsnnrp.c
new file mode 100644
index 00000000..11993629
--- /dev/null
+++ b/innbbsd/bbsnnrp.c
@@ -0,0 +1,1187 @@
+/*
+ Usage: bbsnnrp [options] nntpserver activefile
+ -h|? (help)
+ -v (verbose protocol transactions)
+ -c (reset active files only; don't receive articles)
+ -r remotehost(send articles to remotehost, default=local)
+ -p port|(send articles to remotehost at port, default=7777)
+ path(send articles to local at path, default=~bbs/innd/.innbbsd)
+ -n (don't ask innbbsd server and stat articles)
+ -w seconds (wait for seconds and run infinitely, default=once)
+ -a max_art (maximum number of articles received for a group each time)
+ -s max_stat(maximum number of articles stated for a group each time)
+ -t stdin|nntp (default=nntp)
+*/
+
+#include "innbbsconf.h"
+#include <sys/mman.h>
+#ifndef AIX
+# include <sys/fcntl.h>
+#endif
+#include "bbslib.h"
+#include "daemon.h"
+#include "nntp.h"
+
+#ifndef MAX_ARTS
+# define MAX_ARTS 100
+#endif
+#ifndef MAX_STATS
+# define MAX_STATS 1000
+#endif
+
+#if defined(__linux)
+#define NO_USE_MMAP
+#else
+#define USE_MMAP
+#endif
+
+int Max_Arts= MAX_ARTS;
+int Max_Stats = MAX_STATS;
+
+typedef struct NEWSRC_T {
+ char *nameptr, *lowptr, *highptr, *modeptr;
+ int namelen, lowlen, highlen;
+ ULONG low, high;
+ int mode, subscribe;
+} newsrc_t;
+
+typedef struct NNRP_T {
+ int nnrpfd;
+ int innbbsfd;
+ FILE *nnrpin, *nnrpout;
+ FILE *innbbsin, *innbbsout;
+ char activefile[MAXPATHLEN];
+ char rcfile[MAXPATHLEN];
+ newsrc_t *newsrc;
+ char *actpointer, *actend;
+ int actsize, actfd, actdirty;
+} nnrp_t;
+
+typedef struct XHDR_T {
+ char *header;
+ ULONG artno;
+} xhdr_t;
+
+xhdr_t XHDR[MAX_ARTS];
+char LockFile[1024];
+
+#define NNRPGroupOK NNTP_GROUPOK_VAL
+#define NNRPXhdrOK NNTP_HEAD_FOLLOWS_VAL
+#define NNRParticleOK NNTP_ARTICLE_FOLLOWS_VAL
+#define INNBBSstatOK NNTP_NOTHING_FOLLOWS_VAL
+#define INNBBSihaveOK NNTP_SENDIT_VAL
+#define NNRPconnectOK NNTP_POSTOK_VAL
+#define NNRPstatOK NNTP_NOTHING_FOLLOWS_VAL
+#define INNBBSconnectOK NNTP_POSTOK_VAL
+
+nnrp_t BBSNNRP;
+
+void doterm(s)
+int s;
+{
+ printf("bbsnnrp terminated. Signal %d\n", s);
+ writerc(&BBSNNRP);
+ if (isfile(LockFile))
+ unlink(LockFile);
+ exit(1);
+}
+
+extern char *optarg;
+extern int opterr, optind;
+
+#ifndef MIN_WAIT
+# define MIN_WAIT 60
+#endif
+
+int ResetActive = 0;
+int StatHistory = 1;
+int AskLocal = 1;
+int RunOnce = 1;
+
+int DefaultWait = MIN_WAIT;
+
+char *DefaultPort = DefaultINNBBSPort;
+char *DefaultPath = LOCALDAEMON;
+char *DefaultRemoteHost;
+
+#ifndef MAXBUFLEN
+#define MAXBUFLEN 256
+#endif
+char DefaultNewsgroups[MAXBUFLEN];
+char DefaultOrganization[MAXBUFLEN];
+char DefaultModerator[MAXBUFLEN];
+char DefaultTrustfrom[MAXBUFLEN];
+char DefaultTrustFrom[MAXBUFLEN];
+
+usage(arg)
+char *arg;
+{
+fprintf(stderr,"Usage: %s [options] nntpserver activefile\n", arg);
+fprintf(stderr," -h|? (help) \n");
+fprintf(stderr," -v (verbose protocol transactions)\n");
+fprintf(stderr," -c (reset active files only; don't receive articles)\n");
+fprintf(stderr," -r [proto:]remotehost\n");
+fprintf(stderr," (send articles to remotehost, default=ihave:local)\n");
+fprintf(stderr," -p port|(send articles to remotehost at port, default=%s)\n",DefaultINNBBSPort);
+fprintf(stderr," path(send articles to local at path, default=~bbs/innd/.innbbsd)\n");
+fprintf(stderr," -w seconds ( > 1 wait for seconds and run infinitely, default=once)\n");
+fprintf(stderr," -n (don't ask innbbsd server and stat articles)\n");
+fprintf(stderr," -a max_art(maximum number of articles received for a group each time)\n");
+fprintf(stderr," default=%d\n", MAX_ARTS);
+fprintf(stderr," -s max_stat(maximum number of articles stated for a group each time)\n");
+fprintf(stderr," default=%d\n", MAX_STATS);
+fprintf(stderr," -t stdin|nntp (default=nntp)\n");
+fprintf(stderr," -g newsgroups\n");
+fprintf(stderr," -m moderator\n");
+fprintf(stderr," -o organization\n");
+fprintf(stderr," -f trust_user (From: trust_user)\n");
+fprintf(stderr," -F trust_user (From trust_user)\n");
+fprintf(stderr," Please E-mail bug to skhuang@csie.nctu.edu.tw or\n");
+fprintf(stderr," post to tw.bbs.admin.installbbs\n");
+}
+
+static char *StdinInputType="stdin";
+static char *NntpInputType="nntp";
+static char *NntpIhaveProtocol="ihave";
+static char *NntpPostProtocol="post";
+static char *DefaultNntpProtocol ;
+main(argc, argv)
+int argc;
+char **argv;
+{
+ char *ptr, *server, *active;
+ int c, errflag=0;
+ int lockfd;
+ char *inputtype;
+
+ DefaultNntpProtocol = NntpIhaveProtocol;
+ *DefaultNewsgroups = '\0';
+ *DefaultModerator = '\0';
+ *DefaultOrganization = '\0';
+ *DefaultTrustFrom = '\0';
+ *DefaultTrustfrom = '\0';
+ inputtype = NntpInputType;
+ while ((c = getopt(argc,argv,"f:F:m:o:g:w:r:p:a:s:t:h?ncv"))!= -1)
+ switch (c) {
+ case 'v':
+ verboseon("bbsnnrp.log");
+ break;
+ case 'c':
+ ResetActive = 1;
+ break;
+ case 'g':
+ strncpy(DefaultNewsgroups, optarg, sizeof DefaultNewsgroups);
+ break;
+ case 'm':
+ strncpy(DefaultModerator, optarg, sizeof DefaultModerator);
+ break;
+ case 'o':
+ strncpy(DefaultOrganization, optarg, sizeof DefaultOrganization);
+ break;
+ case 'f':
+ strncpy(DefaultTrustfrom, optarg, sizeof DefaultTrustfrom);
+ break;
+ case 'F':
+ strncpy(DefaultTrustFrom, optarg, sizeof DefaultTrustFrom);
+ break;
+ case 'r': {
+ char *hostptr;
+ AskLocal = 0;
+ DefaultRemoteHost = optarg;
+ if ((hostptr = strchr(optarg,':')) != NULL) {
+ *hostptr = '\0';
+ DefaultRemoteHost = hostptr+1;
+ if (strcasecmp( optarg, "post" ) == 0)
+ DefaultNntpProtocol = NntpPostProtocol;
+ *hostptr = ':';
+ }
+ break;
+ }
+ case 'w':
+ RunOnce = 0;
+ DefaultWait = atoi(optarg);
+ if (DefaultWait < MIN_WAIT)
+ DefaultWait = MIN_WAIT;
+ break;
+ case 'p':
+ if (AskLocal == 0) {
+ DefaultPort = optarg;
+ } else {
+ DefaultPath = optarg;
+ }
+ break;
+ case 'n':
+ StatHistory = 0;
+ break;
+ case 'a':
+ Max_Arts = atol(optarg);
+ if (Max_Arts < 0) Max_Arts = 0;
+ break;
+ case 's':
+ Max_Stats = atol(optarg);
+ if (Max_Stats < 0) Max_Stats = 0;
+ break;
+ case 't':
+ if ( strcasecmp(optarg,StdinInputType) == 0) {
+ inputtype = StdinInputType;
+ }
+ break;
+ case 'h':
+ case '?':
+ default:
+ errflag ++;
+ }
+ if (errflag > 0) {
+ usage(argv[0]);
+ return(1);
+ }
+ if (inputtype == NntpInputType && argc - optind < 2) {
+ usage(argv[0]);
+ exit(1);
+ }
+ if (inputtype == NntpInputType) {
+ server = argv[optind];
+ active = argv[optind+1];
+ if ( isfile(active) ) {
+ strncpy(BBSNNRP.activefile, active, sizeof BBSNNRP.activefile);
+ } else if ( strchr(active,'/') == NULL) {
+ sprintf(BBSNNRP.activefile, "%s/innd/%.*s",BBSHOME, sizeof BBSNNRP.activefile - 7 - strlen(BBSHOME), active);
+ } else {
+ strncpy(BBSNNRP.activefile, active, sizeof BBSNNRP.activefile);
+ }
+
+ strncpy(LockFile , (char*)fileglue("%s.lock",active), sizeof LockFile);
+ if ((lockfd = open(LockFile, O_RDONLY)) >= 0) {
+ char buf[10];
+ int pid;
+
+ if (read(lockfd, buf, sizeof buf) > 0 && (pid = atoi(buf))>0 && kill(pid,0)==0) {
+ fprintf(stderr, "another process [%d] running\n", pid);
+ exit(1);
+ } else {
+ fprintf(stderr, "no process [%d] running, but lock file existed, unlinked\n", pid);
+ unlink(LockFile);
+ }
+ close(lockfd);
+ }
+ if ((lockfd = open(LockFile, O_RDWR|O_CREAT|O_EXCL,0644)) < 0) {
+ fprintf( stderr, "maybe another %s process running\n",argv[0]);
+ exit(1);
+ } else {
+ char buf[10];
+ int pid;
+ sprintf(buf,"%-.8d\n",getpid());
+ write(lockfd, buf, strlen(buf));
+ close(lockfd);
+ }
+ for (;;) {
+ if (!initial_bbs(NULL)) {
+ fprintf(stderr, "Initial BBS failed\n");
+ exit(1);
+ }
+ initsockets(server, &BBSNNRP, inputtype);
+ ptr = (char*)strrchr(active,'/');
+ if (ptr != NULL)
+ ptr++;
+ else
+ ptr = active;
+ sprintf(BBSNNRP.rcfile,"%s/.newsrc.%s.%s",INNDHOME, server, ptr);
+ initrcfiles(&BBSNNRP);
+
+ signal(SIGTERM, doterm);
+ signal(SIGKILL, doterm);
+ signal(SIGHUP, doterm);
+ signal(SIGPIPE, doterm);
+
+ readnews(&BBSNNRP);
+ writerc(&BBSNNRP);
+ closesockets();
+
+ if (RunOnce) break;
+ sleep(DefaultWait);
+ }
+ unlink(LockFile);
+ } /* NntpInputType */
+ else {
+ if (!initial_bbs(NULL)) {
+ fprintf(stderr, "Initial BBS failed\n");
+ exit(1);
+ }
+ initsockets(server, &BBSNNRP, inputtype);
+ signal(SIGTERM, doterm);
+ signal(SIGKILL, doterm);
+ signal(SIGHUP, doterm);
+ signal(SIGPIPE, doterm);
+
+ stdinreadnews(&BBSNNRP);
+ closesockets();
+ } /* stdin input type */
+ return 0;
+}
+
+headbegin(buffer)
+char *buffer;
+{
+ if (strncmp(buffer,"Path: ",6)==0 ) {
+ if (strchr(buffer+6,'!') != NULL)
+ return 1;
+ }
+ if (strncmp(buffer,"From ",5)== 0 ) {
+ if (strchr(buffer+5,':') != NULL)
+ return 1;
+ }
+ return 0;
+}
+
+stdinreadnews(bbsnnrp)
+nnrp_t *bbsnnrp;
+{
+ int i;
+ char buffer[4096];
+ ULONG low, high;
+ char tmpfilename[MAXPATHLEN];
+ FILE *tmpfp = NULL;
+ char mid[1024];
+ int pathagain;
+ int ngmet, submet, midmet, pathmet, orgmet, approvedmet;
+ int discard;
+ char sending_path[MAXPATHLEN];
+ int sending_path_len=0;
+
+ strncpy(tmpfilename,(char*)fileglue("/tmp/bbsnnrp-stdin-%d-%d",getuid(),getpid()),sizeof tmpfilename);
+ fgets(buffer, sizeof buffer, bbsnnrp->innbbsin);
+ verboselog("innbbsGet: %s", buffer);
+ if (atoi(buffer) != INNBBSconnectOK) {
+ fprintf(stderr, "INNBBS server not OK\n");
+ return;
+ }
+
+ if ( DefaultNntpProtocol == NntpPostProtocol ) {
+ fputs("MODE READER\r\n", bbsnnrp->innbbsout);
+ fflush(bbsnnrp->innbbsout);
+ verboselog("innbbsPut: MODE READER\n");
+ fgets(buffer, sizeof buffer, bbsnnrp->innbbsin);
+ verboselog("innbbsGet: %s",buffer);
+ }
+
+ if (StatHistory == 0) {
+ fputs("MIDCHECK OFF\r\n", bbsnnrp->innbbsout);
+ fflush(bbsnnrp->innbbsout);
+ verboselog("innbbsPut: MIDCHECK OFF\n");
+ fgets(buffer, sizeof buffer, bbsnnrp->innbbsin);
+ verboselog("innbbsGet: %s",buffer);
+ }
+ tmpfp = fopen(tmpfilename,"w");
+ if (tmpfp == NULL) return;
+ *mid = '\0';
+ for (;;) {
+ fprintf(stderr,"Try to read from stdin ...\n");
+ ngmet = 0, submet = 0, midmet = 0, pathmet = 0, orgmet = 0, approvedmet=0;
+ discard = 0;
+ while (fgets(buffer, sizeof buffer, stdin) != NULL) {
+ char *tmpptr;
+ tmpptr = strchr(buffer,'\n');
+ if (tmpptr != NULL) *tmpptr = '\0';
+ if (strncasecmp(buffer,"Message-ID: ",12)==0) {
+ strncpy(mid, buffer+12,sizeof mid);
+ midmet = 1;
+ } else if (strncmp(buffer,"Subject: ",9)==0) {
+ submet = 1;
+ } else if (strncmp(buffer,"Path: ",6)==0) {
+ pathmet = 1;
+ } else if (strncmp(buffer,"Organization: ",14)==0) {
+ orgmet = 1;
+ } else if (strncmp(buffer,"Approved: ",10) == 0) {
+ approvedmet = 1;
+ } else if (strncmp(buffer,"From: ",6)==0 && *DefaultTrustfrom ) {
+ if (strstr(buffer+6, DefaultTrustfrom)==NULL) {
+ discard = 1;
+ verboselog("Discard: %s for %s",buffer, DefaultTrustfrom);
+ }
+ } else if (strncmp(buffer,"From ",5)==0 && *DefaultTrustFrom ) {
+ if (strstr(buffer+5, DefaultTrustFrom)==NULL) {
+ discard = 1;
+ verboselog("Discard: %s for %s",buffer, DefaultTrustFrom);
+ }
+ } else if (strncmp(buffer,"Received: ",10)==0) {
+ char *rptr=buffer+10, *rrptr;
+ int savech, len;
+ if (strncmp(buffer+10,"from ",5)==0) {
+ rptr +=5;
+ rrptr = strchr(rptr,'(');
+ if (rrptr != NULL) rptr = rrptr + 1;
+ rrptr = strchr(rptr,' ');
+ savech = *rrptr;
+ if (rrptr != NULL) *rrptr = '\0';
+ } else if (strncmp(buffer+10,"(from ",6)==0) {
+ rptr +=6;
+ rrptr = strchr(rptr,')');
+ savech = *rrptr;
+ if (rrptr != NULL) *rrptr = '\0';
+ }
+ len = strlen(rptr) +1;
+ if (*rptr && sending_path_len + len < sizeof(sending_path)) {
+ if (*sending_path)
+ strcat(sending_path, "!");
+ strcat(sending_path, rptr);
+ sending_path_len += len ;
+ }
+ if (rrptr != NULL) *rrptr = savech;
+ }
+
+ if (strncmp(buffer,"Newsgroups: ",12)==0) {
+ if (*DefaultNewsgroups){
+ fprintf(tmpfp,"Newsgroups: %s\r\n",DefaultNewsgroups);
+ } else {
+ fprintf(tmpfp,"%s\r\n",buffer);
+ }
+ ngmet = 1;
+ } else {
+ if (buffer[0] == '\0') {
+ if (!ngmet && *DefaultNewsgroups) {
+ fprintf(tmpfp,"Newsgroups: %s\r\n",DefaultNewsgroups);
+ }
+ if (!submet) {
+ fprintf(tmpfp,"Subject: (no subject)\r\n");
+ }
+ if (!pathmet) {
+ fprintf(tmpfp,"Path: from-mail\r\n");
+ }
+ if (!midmet) {
+ static int seed;
+ time_t now;
+ time(&now);
+ fprintf(tmpfp,"Message-ID: <%d@%d.%d.%d>\r\n",now,getpid(), getuid(), seed);
+ sprintf(mid, "<%d@%d.%d.%d>", now, getpid(), getuid(), seed);
+ seed++;
+ }
+ if (!orgmet && *DefaultOrganization) {
+ fprintf(tmpfp,"Organization: %s\r\n", DefaultOrganization);
+ }
+ if (!approvedmet && *DefaultModerator) {
+ fprintf(tmpfp,"Approved: %s\r\n", DefaultModerator);
+ }
+ }
+ if (strncmp(buffer,"From ",5) != 0 && strncmp(buffer,"To: ",4) !=0) {
+ if (buffer[0] == '\0') {
+ if (*sending_path) {
+ fprintf(tmpfp,"X-Sending-Path: %s\r\n",sending_path);
+ }
+ }
+ fprintf(tmpfp,"%s\r\n",buffer);
+ }
+ }
+ if (buffer[0]=='\0') break;
+ }
+ fprintf(stderr,"Article Body begin ...\n");
+ pathagain = 0;
+ while (fgets(buffer, sizeof buffer, stdin) != NULL) {
+ char *tmpptr;
+ tmpptr = strchr(buffer,'\n');
+ if (tmpptr != NULL) *tmpptr = '\0';
+ if ( headbegin(buffer) ) {
+ FILE *oldfp = bbsnnrp->nnrpin;
+ pathagain = 1;
+ fputs(".\r\n",tmpfp);
+ fclose(tmpfp);
+ fprintf(stderr,"Try to post ...\n");
+ tmpfp = fopen(tmpfilename,"r");
+ bbsnnrp->nnrpin = tmpfp;
+ if (!discard)
+ if (INNBBSihave(bbsnnrp, -1, mid)== -1) {
+ fprintf(stderr,"post failed\n");
+ }
+ bbsnnrp->nnrpin = oldfp;
+ fclose(tmpfp);
+ *mid = '\0';
+ tmpfp = fopen(tmpfilename,"w");
+ fprintf(tmpfp,"%s\r\n",buffer);
+ break;
+ } else {
+ fprintf(tmpfp,"%s\r\n",buffer);
+ }
+ }
+ if (!pathagain) break;
+ }
+ if (!pathagain && tmpfp) {
+ FILE *oldfp = bbsnnrp->nnrpin;
+ fputs(".\r\n",tmpfp);
+ fclose(tmpfp);
+ fprintf(stderr,"Try to post ...\n");
+ tmpfp = fopen(tmpfilename,"r");
+ bbsnnrp->nnrpin = tmpfp;
+ if (!discard)
+ if (INNBBSihave(bbsnnrp, -1, mid)== -1) {
+ fprintf(stderr,"post failed\n");
+ }
+ bbsnnrp->nnrpin = oldfp;
+ fclose(tmpfp);
+ }
+ if (isfile(tmpfilename)) {
+ unlink(tmpfilename);
+ }
+}
+
+static char *ACT_BUF, *RC_BUF;
+int ACT_COUNT;
+
+initrcfiles(bbsnnrp)
+nnrp_t *bbsnnrp;
+{
+ FILE *actfp, *rcfp;
+ char buff[1024];
+ int actfd, i, count, actcount=0, rcount=0, maxcount;
+ struct stat st;
+ char *actlistptr, *ptr;
+
+ actfd = open(bbsnnrp->activefile, O_RDWR);
+ if (actfd < 0) {
+ fprintf( stderr, "can't read/write %s\n", bbsnnrp->activefile );
+ exit(1);
+ }
+ if (fstat(actfd, &st) != 0) {
+ fprintf( stderr, "can't stat %s\n", bbsnnrp->activefile );
+ exit(1);
+ }
+
+ bbsnnrp->actfd = actfd;
+ bbsnnrp->actsize = st.st_size;
+#ifdef USE_MMAP
+ bbsnnrp->actpointer = mmap(0, st.st_size, PROT_WRITE | PROT_READ,
+ MAP_SHARED, actfd, 0);
+ if (bbsnnrp->actpointer == (char*)-1) {
+ fprintf( stderr, "mmap error \n");
+ exit(1);
+ }
+#else
+ if (bbsnnrp->actpointer == NULL) {
+ bbsnnrp->actpointer = (char*)mymalloc(st.st_size);
+ } else {
+ bbsnnrp->actpointer = (char*)myrealloc(bbsnnrp->actpointer,st.st_size);
+ }
+ if (bbsnnrp->actpointer == NULL || read(actfd, bbsnnrp->actpointer, st.st_size) <= 0) {
+ fprintf( stderr, "read act error \n");
+ exit(1);
+ }
+#endif
+ bbsnnrp->actend = bbsnnrp->actpointer + st.st_size;
+ i = 0, count = 0;
+ for (ptr = bbsnnrp->actpointer; ptr < bbsnnrp->actend && (actlistptr = (char*)strchr(ptr,'\n')) != NULL; ptr = actlistptr +1, ACT_COUNT++) {
+ if (*ptr == '\n') continue;
+ if (*ptr == '#') continue;
+ count ++;
+ }
+ bbsnnrp->newsrc = (newsrc_t*) mymalloc( sizeof(newsrc_t) * count);
+ ACT_COUNT = 0;
+ for (ptr = bbsnnrp->actpointer; ptr < bbsnnrp->actend && (actlistptr = (char*)strchr(ptr,'\n')) != NULL; ptr = actlistptr +1 ) {
+ register newsrc_t *rcptr;
+ char *nptr;
+ /**actlistptr = '\0';*/
+ if (*ptr == '\n') continue;
+ if (*ptr == '#') continue;
+ rcptr = &bbsnnrp->newsrc[ACT_COUNT];
+ rcptr->nameptr = NULL;
+ rcptr->namelen = 0;
+ rcptr->lowptr = NULL;
+ rcptr->lowlen = 0;
+ rcptr->highptr = NULL;
+ rcptr->highlen = 0;
+ rcptr->modeptr = NULL;
+ rcptr->low = 0;
+ rcptr->high = 0;
+ rcptr->mode = 'y';
+ for (nptr= ptr ;*nptr && isspace(*nptr); ) nptr++;
+ if ( nptr == actlistptr ) continue;
+ rcptr->nameptr = nptr;
+ for (nptr++; *nptr && !isspace(*nptr); ) nptr++;
+ rcptr->namelen = (int)(nptr - rcptr->nameptr);
+ if ( nptr == actlistptr) continue;
+ for (nptr++ ;*nptr && isspace(*nptr); ) nptr++;
+ if ( nptr == actlistptr) continue;
+ rcptr->highptr = nptr;
+ rcptr->high = atol(nptr);
+ for (nptr++; *nptr && !isspace(*nptr); ) nptr++;
+ rcptr->highlen = (int)(nptr - rcptr->highptr);
+ if ( nptr == actlistptr) continue;
+ for (nptr++ ;*nptr && isspace(*nptr); ) nptr++;
+ if ( nptr == actlistptr) continue;
+ rcptr->lowptr = nptr;
+ rcptr->low = atol(nptr);
+ for (nptr++; *nptr && !isspace(*nptr); ) nptr++;
+ rcptr->lowlen = (int)(nptr - rcptr->lowptr);
+ if ( nptr == actlistptr) continue;
+ for (nptr++ ;*nptr && isspace(*nptr); ) nptr++;
+ if ( nptr == actlistptr) continue;
+ rcptr->mode = *nptr;
+ rcptr->modeptr = nptr;
+ ACT_COUNT ++;
+ }
+}
+
+initsockets(server, bbsnnrp, type)
+char *server;
+nnrp_t *bbsnnrp;
+char *type;
+{
+ int nnrpfd ;
+ int innbbsfd;
+ if (AskLocal) {
+ innbbsfd = unixclient(DefaultPath,"tcp");
+ if (innbbsfd < 0) {
+ fprintf(stderr, "Connect to %s error. You may not run innbbsd\n", LOCALDAEMON);
+ /* unix connect fail, may run by inetd, try to connect to local once */
+ innbbsfd = inetclient("localhost",DefaultPort,"tcp");
+ if (innbbsfd < 0) {
+ exit(2);
+ }
+ close(innbbsfd);
+ /* try again */
+ innbbsfd = unixclient(DefaultPath,"tcp");
+ if (innbbsfd < 0) {
+ exit(3);
+ }
+ }
+ verboselog("INNBBS connect to %s\n",DefaultPath);
+ } else {
+ innbbsfd = inetclient(DefaultRemoteHost,DefaultPort,"tcp");
+ if (innbbsfd < 0) {
+ fprintf(stderr, "Connect to %s at %s error. Remote Server not Ready\n", DefaultRemoteHost, DefaultPort);
+ exit(2);
+ }
+ verboselog("INNBBS connect to %s\n",DefaultRemoteHost);
+ }
+ if (type == StdinInputType) {
+ bbsnnrp->nnrpfd = 0;
+ bbsnnrp->innbbsfd = innbbsfd;
+ if ((bbsnnrp->nnrpin = fdopen(0,"r")) == NULL ||
+ (bbsnnrp->nnrpout= fdopen(1,"w")) == NULL ||
+ (bbsnnrp->innbbsin= fdopen(innbbsfd,"r")) == NULL ||
+ (bbsnnrp->innbbsout= fdopen(innbbsfd,"w"))== NULL ) {
+ fprintf( stderr, "fdopen error\n");
+ exit(3);
+ }
+ return;
+ }
+ nnrpfd = inetclient(server, "nntp","tcp");
+ if (nnrpfd < 0) {
+ fprintf(stderr, " connect to %s error \n", server);
+ exit(2);
+ }
+ verboselog("NNRP connect to %s\n", server);
+ bbsnnrp->nnrpfd = nnrpfd;
+ bbsnnrp->innbbsfd = innbbsfd;
+ if ((bbsnnrp->nnrpin = fdopen(nnrpfd,"r")) == NULL ||
+ (bbsnnrp->nnrpout= fdopen(nnrpfd,"w")) == NULL ||
+ (bbsnnrp->innbbsin= fdopen(innbbsfd,"r")) == NULL ||
+ (bbsnnrp->innbbsout= fdopen(innbbsfd,"w"))== NULL ) {
+ fprintf( stderr, "fdopen error\n");
+ exit(3);
+ }
+}
+
+closesockets()
+{
+ fclose(BBSNNRP.nnrpin);
+ fclose(BBSNNRP.nnrpout);
+ fclose(BBSNNRP.innbbsin);
+ fclose(BBSNNRP.innbbsout);
+ close(BBSNNRP.nnrpfd);
+ close(BBSNNRP.innbbsfd);
+}
+
+updaterc(actptr, len, value)
+char *actptr;
+int len;
+ULONG value;
+{
+ for (actptr += len -1; len -- >0; ) {
+ *actptr-- = value % 10 + '0';
+ value /= 10;
+ }
+}
+
+/*
+ if old file is empty, don't need to update
+ prevent from disk full
+*/
+int
+myrename(old,new)
+char *old, *new;
+{
+ struct stat st;
+ if (stat(old,&st) != 0) return -1;
+ if (st.st_size <= 0) return -1;
+ return rename(old,new);
+}
+
+flushrc(bbsnnrp)
+nnrp_t *bbsnnrp;
+{
+ int backfd;
+ char *bak1;
+ if (bbsnnrp->actdirty == 0) return;
+ bak1 = (char*)strdup((char*)fileglue("%s.BAK",bbsnnrp->activefile));
+ if (isfile(bak1)) {
+ myrename(bak1, (char*)fileglue("%s.BAK.OLD",bbsnnrp->activefile));
+ }
+#ifdef USE_MMAP
+ if ((backfd=open((char*)fileglue("%s.BAK",bbsnnrp->activefile),O_WRONLY | O_TRUNC | O_CREAT, 0664)) < 0 || write(backfd, bbsnnrp->actpointer, bbsnnrp->actsize) < bbsnnrp->actsize)
+#else
+ myrename(bbsnnrp->activefile, bak1);
+ if ((backfd=open(bbsnnrp->activefile,O_WRONLY | O_TRUNC | O_CREAT, 0664)) < 0 || write(backfd, bbsnnrp->actpointer, bbsnnrp->actsize) < bbsnnrp->actsize)
+#endif
+ {
+ char emergent[128];
+ sprintf(emergent,"/tmp/bbsnnrp.%d.active",getpid());
+ fprintf(stderr, "write to backup active fail. Maybe disk full\n");
+ fprintf(stderr, "try to write in %s\n",emergent);
+ if ((backfd = open(emergent,O_WRONLY | O_TRUNC | O_CREAT, 0644))<0 || write(backfd, bbsnnrp->actpointer, bbsnnrp->actsize) < bbsnnrp->actsize)
+ {
+ fprintf(stderr, "write to %sfail.\n", emergent);
+ } else {
+ close(backfd);
+ }
+ /* if write fail, should leave */
+ /*exit(1);*/
+ } else {
+ close(backfd);
+ }
+ free(bak1);
+ bbsnnrp->actdirty = 0;
+}
+
+writerc(bbsnnrp)
+nnrp_t *bbsnnrp;
+{
+ if (bbsnnrp->actpointer) {
+ flushrc(bbsnnrp);
+#ifdef USE_MMAP
+ if (munmap(bbsnnrp->actpointer, bbsnnrp->actsize) < 0)
+ fprintf(stderr, "can't unmap\n");
+ /*free(bbsnnrp->actpointer);*/
+ bbsnnrp->actpointer = NULL;
+#endif
+ if (close(bbsnnrp->actfd) < 0)
+ fprintf(stderr, "can't close actfd\n");
+ }
+}
+
+static FILE* Xhdrfp;
+static char NNRPbuffer[4096];
+static char INNBBSbuffer[4096];
+
+char *
+NNRPgets(string, len, fp)
+char *string;
+int len;
+FILE *fp;
+{
+ char* re = fgets(string, len, fp);
+ char *ptr;
+ if (re != NULL) {
+ if ((ptr = (char*)strchr(string,'\r'))!=NULL)
+ *ptr = '\0';
+ if ((ptr = (char*)strchr(string,'\n'))!=NULL)
+ *ptr = '\0';
+ }
+ return re;
+}
+
+int NNRPstat(bbsnnrp, artno, mid)
+nnrp_t *bbsnnrp;
+ ULONG artno;
+char **mid;
+{
+ char *ptr;
+ int code;
+
+ *mid = NULL;
+ fprintf(bbsnnrp->nnrpout,"STAT %d\r\n",artno);
+ fflush(bbsnnrp->nnrpout);
+ verboselog("nnrpPut: STAT %d\n",artno);
+ NNRPgets(NNRPbuffer, sizeof NNRPbuffer, bbsnnrp->nnrpin);
+ verboselog("nnrpGet: %s\n",NNRPbuffer);
+
+ ptr = (char*) strchr(NNRPbuffer, ' ');
+ if (ptr != NULL) *ptr++ = '\0';
+ code = atoi(NNRPbuffer);
+ ptr = (char*) strchr(ptr, ' ');
+ if (ptr != NULL) *ptr++ = '\0';
+ *mid = ptr;
+ ptr = (char*) strchr(ptr, ' ');
+ if (ptr != NULL) *ptr++ = '\0';
+ return code;
+}
+
+int
+NNRPxhdr(pattern, bbsnnrp, i, low, high)
+char *pattern;
+nnrp_t *bbsnnrp;
+int i;
+ULONG low, high;
+{
+ newsrc_t *rcptr = &bbsnnrp->newsrc[i];
+ int size, code;
+
+ Xhdrfp = bbsnnrp->nnrpin;
+ fprintf(bbsnnrp->nnrpout,"XHDR %s %d-%d\r\n",pattern,low, high );
+#ifdef BBSNNRPDEBUG
+ printf("XHDR %s %d-%d\r\n",pattern,low, high );
+#endif
+ fflush(bbsnnrp->nnrpout);
+ verboselog("nnrpPut: XHDR %s %d-%d\n",pattern,low, high );
+ NNRPgets(NNRPbuffer, sizeof NNRPbuffer, bbsnnrp->nnrpin);
+ verboselog("nnrpGet: %s\n", NNRPbuffer);
+ code = atoi(NNRPbuffer);
+ return code;
+}
+
+int NNRPxhdrget(artno, mid, iscontrol)
+int *artno;
+char **mid;
+int iscontrol;
+{
+ *mid = NULL;
+ *artno = 0;
+ if (NNRPgets(NNRPbuffer, sizeof NNRPbuffer, Xhdrfp) == NULL)
+ return 0;
+ else {
+ char *ptr, *s;
+ if (strcmp(NNRPbuffer,".")==0) return 0;
+ ptr = (char*)strchr(NNRPbuffer,' ');
+ if (!ptr) return 1;
+ *ptr++ = '\0';
+ *artno = atol(NNRPbuffer);
+ if (iscontrol) {
+ ptr = (char*)strchr(s=ptr,' ');
+ if (!ptr) return 1;
+ *ptr++ = '\0';
+ if (strcmp(s,"cancel") != 0) return 1;
+ }
+ *mid = ptr;
+ return 1;
+ }
+}
+
+int INNBBSstat(bbsnnrp, i, mid)
+nnrp_t *bbsnnrp;
+int i;
+char *mid;
+{
+ newsrc_t *rcptr = &bbsnnrp->newsrc[i];
+ int size, code;
+
+ fprintf(bbsnnrp->innbbsout,"STAT %s\r\n", mid);
+ fflush(bbsnnrp->innbbsout);
+ verboselog("innbbsPut: STAT %s\n", mid);
+ NNRPgets(INNBBSbuffer, sizeof INNBBSbuffer, bbsnnrp->innbbsin);
+ verboselog("innbbsGet: %s\n", INNBBSbuffer);
+ return atol(INNBBSbuffer);
+}
+
+int INNBBSihave(bbsnnrp, artno, mid)
+nnrp_t *bbsnnrp;
+ULONG artno;
+char *mid;
+{
+ int size, code;
+ int header=1;
+
+ if (DefaultNntpProtocol == NntpPostProtocol) {
+ fprintf(bbsnnrp->innbbsout,"POST\r\n");
+ fflush(bbsnnrp->innbbsout);
+ verboselog("innbbsPut: POST %s\n", mid);
+ } else {
+ fprintf(bbsnnrp->innbbsout,"IHAVE %s\r\n", mid);
+ fflush(bbsnnrp->innbbsout);
+ verboselog("innbbsPut: IHAVE %s\n", mid);
+ }
+ if (NNRPgets(INNBBSbuffer, sizeof INNBBSbuffer, bbsnnrp->innbbsin)==NULL){
+ return -1;
+ }
+ verboselog("innbbsGet: %s\n", INNBBSbuffer);
+#ifdef BBSNNRPDEBUG
+ printf("ihave got %s\n", INNBBSbuffer);
+#endif
+
+ if (DefaultNntpProtocol == NntpPostProtocol) {
+ if ((code=atol(INNBBSbuffer)) != NNTP_START_POST_VAL) {
+ if (code == NNTP_POSTFAIL_VAL)
+ return 0;
+ else
+ return -1;
+ }
+ } else {
+ if ((code=atol(INNBBSbuffer)) != INNBBSihaveOK) {
+ if (code == 435 || code == 437)
+ return 0;
+ else
+ return -1;
+ }
+ }
+ if (artno != -1) {
+ fprintf(bbsnnrp->nnrpout,"ARTICLE %d\r\n", artno);
+ verboselog("nnrpPut: ARTICLE %d\n", artno);
+#ifdef BBSNNRPDEBUG
+ printf("ARTICLE %d\r\n", artno);
+#endif
+ fflush(bbsnnrp->nnrpout);
+ if (NNRPgets(NNRPbuffer, sizeof NNRPbuffer, bbsnnrp->nnrpin)==NULL) {
+ return -1;
+ }
+ verboselog("nnrpGet: %s\n", NNRPbuffer);
+#ifdef BBSNNRPDEBUG
+ printf("article got %s\n", NNRPbuffer);
+#endif
+ if (atol(NNRPbuffer) != NNRParticleOK) {
+ fputs(".\r\n",bbsnnrp->innbbsout);
+ fflush(bbsnnrp->innbbsout);
+ NNRPgets(INNBBSbuffer, sizeof INNBBSbuffer, bbsnnrp->innbbsin);
+ verboselog("innbbsGet: %s\n",INNBBSbuffer);
+ return 0;
+ }
+ }
+ header = 1;
+ while ( fgets(NNRPbuffer, sizeof NNRPbuffer, bbsnnrp->nnrpin) != NULL)
+ {
+ if (strcmp(NNRPbuffer,"\r\n") == 0)
+ header = 0;
+ if (strcmp(NNRPbuffer,".\r\n")==0) {
+ verboselog("nnrpGet: .\n");
+ fputs(NNRPbuffer,bbsnnrp->innbbsout);
+ fflush(bbsnnrp->innbbsout);
+ verboselog("innbbsPut: .\n");
+ if (NNRPgets(INNBBSbuffer, sizeof INNBBSbuffer, bbsnnrp->innbbsin)==NULL)
+ return -1;
+ verboselog("innbbsGet: %s\n",INNBBSbuffer);
+#ifdef BBSNNRPDEBUG
+ printf("end ihave got %s\n", INNBBSbuffer);
+#endif
+ code = atol(INNBBSbuffer);
+ if (DefaultNntpProtocol == NntpPostProtocol) {
+ if (code == NNTP_POSTEDOK_VAL)
+ return 1;
+ if (code == NNTP_POSTFAIL_VAL)
+ return 0;
+ } else {
+ if (code == 235)
+ return 1;
+ if (code == 437 || code == 435)
+ return 0;
+ }
+ break;
+ }
+ if ( DefaultNntpProtocol == NntpPostProtocol &&
+ header && strncasecmp(NNRPbuffer,"NNTP-Posting-Host: ",19)==0) {
+ fprintf(bbsnnrp->innbbsout,"X-%s",NNRPbuffer);
+ } else {
+ fputs(NNRPbuffer,bbsnnrp->innbbsout);
+ }
+ }
+ fflush(bbsnnrp->innbbsout);
+ return -1;
+}
+
+int
+NNRPgroup(bbsnnrp, i, low, high)
+nnrp_t *bbsnnrp;
+int i;
+ULONG *low, *high;
+{
+ newsrc_t *rcptr = &bbsnnrp->newsrc[i];
+ int size, code;
+ ULONG tmp;
+
+ fprintf(bbsnnrp->nnrpout,"GROUP %-.*s\r\n",
+ rcptr->namelen, rcptr->nameptr );
+ printf("GROUP %-.*s\r\n", rcptr->namelen, rcptr->nameptr );
+ verboselog("nnrpPut: GROUP %-.*s\n", rcptr->namelen, rcptr->nameptr );
+ fflush(bbsnnrp->nnrpout);
+ NNRPgets(NNRPbuffer, sizeof NNRPbuffer, bbsnnrp->nnrpin);
+ verboselog("nnrpGet: %s\n",NNRPbuffer);
+ printf("%s\n",NNRPbuffer);
+ sscanf(NNRPbuffer, "%d %d %ld %ld", &code, &size, low, high);
+ if (*low > *high) {
+ tmp = *low;
+ *low = *high;
+ *high = tmp;
+ }
+ return code;
+}
+
+
+readnews(bbsnnrp)
+nnrp_t *bbsnnrp;
+{
+ int i;
+ char buffer[4096];
+ ULONG low, high;
+
+ fgets(buffer, sizeof buffer, bbsnnrp->innbbsin);
+ verboselog("innbbsGet: %s", buffer);
+ if (atoi(buffer) != INNBBSconnectOK) {
+ fprintf(stderr, "INNBBS server not OK\n");
+ return;
+ }
+#ifdef BBSNNRPDEBUG
+ printf("%s",buffer);
+#endif
+ fgets(buffer, sizeof buffer, bbsnnrp->nnrpin);
+ verboselog("nnrpGet: %s", buffer);
+ if (buffer[0] != '2') {
+ /*if (atoi(buffer) != NNRPconnectOK && atoi(buffer) != NNTP_NOPOSTOK_VAL) {*/
+ fprintf(stderr, "NNRP server not OK\n");
+ return;
+ }
+#ifdef BBSNNRPDEBUG
+ printf("%s",buffer);
+#endif
+ fputs("MODE READER\r\n", bbsnnrp->nnrpout);
+ fflush(bbsnnrp->nnrpout);
+ verboselog("nnrpPut: MODE READER\n");
+ fgets(buffer, sizeof buffer, bbsnnrp->nnrpin);
+ verboselog("nnrpGet: %s",buffer);
+
+ if ( DefaultNntpProtocol == NntpPostProtocol ) {
+ fputs("MODE READER\r\n", bbsnnrp->innbbsout);
+ fflush(bbsnnrp->innbbsout);
+ verboselog("innbbsPut: MODE READER\n");
+ fgets(buffer, sizeof buffer, bbsnnrp->innbbsin);
+ verboselog("innbbsGet: %s",buffer);
+ }
+
+#ifdef BBSNNRPDEBUG
+ printf("%s",buffer);
+#endif
+
+ if (StatHistory == 0) {
+ fputs("MIDCHECK OFF\r\n", bbsnnrp->innbbsout);
+ fflush(bbsnnrp->innbbsout);
+ verboselog("innbbsPut: MIDCHECK OFF\n");
+ fgets(buffer, sizeof buffer, bbsnnrp->innbbsin);
+ verboselog("innbbsGet: %s",buffer);
+ }
+ bbsnnrp->actdirty = 0;
+ for (i =0; i< ACT_COUNT; i++) {
+ int code = NNRPgroup(bbsnnrp, i, &low, &high);
+ newsrc_t *rcptr = &bbsnnrp->newsrc[i];
+ int j;
+ ULONG artno;
+ char *mid;
+ int artcount;
+
+#ifdef BBSNNRPDEBUG
+ printf("got reply %d %ld %ld\n",code, low, high);
+#endif
+ artcount = 0;
+ if (code == NNRPGroupOK) {
+ int xcount;
+ ULONG maxartno= rcptr->high;
+ int isCancelControl = (strncmp(rcptr->nameptr,"control",rcptr->namelen)==0)
+ ||
+ (strncmp(rcptr->nameptr,"control.cancel",rcptr->namelen)==0) ;
+
+/* less than or equal to high, for server renumber */
+ if (rcptr->low != low) {
+ bbsnnrp->actdirty = 1;
+ rcptr->low = low;
+ updaterc(rcptr->lowptr, rcptr->lowlen, rcptr->low);
+ }
+ if (ResetActive) {
+ if (rcptr->high != high) {
+ bbsnnrp->actdirty = 1;
+ rcptr->high = high;
+ updaterc(rcptr->highptr, rcptr->highlen, rcptr->high);
+ }
+ } else if (rcptr->high < high) {
+ int xhdrcode;
+ ULONG maxget=high;
+ int exception=0;
+ if (rcptr->high < low) {
+ bbsnnrp->actdirty = 1;
+ rcptr->high = low;
+ updaterc(rcptr->highptr, rcptr->highlen, low);
+ }
+ if (high > rcptr->high + Max_Stats) {
+ maxget = rcptr->high + Max_Stats;
+ }
+ if ( isCancelControl )
+ xhdrcode = NNRPxhdr("Control",bbsnnrp, i, rcptr->high+1, maxget);
+ else
+ xhdrcode = NNRPxhdr("Message-ID",bbsnnrp, i, rcptr->high+1, maxget);
+
+ maxartno = maxget;
+ if ( xhdrcode == NNRPXhdrOK) {
+ while (NNRPxhdrget(&artno, &mid, isCancelControl)) {
+/*#define DEBUG*/
+#ifdef DEBUG
+ printf("no %d id %s\n",artno, mid);
+#endif
+ if (artcount < Max_Arts) {
+ if (mid != NULL && !isCancelControl) {
+ if (!StatHistory || INNBBSstat(bbsnnrp,i,mid) != INNBBSstatOK) {
+ printf("** %d ** %d need it %s\n", artcount, artno,mid);
+ XHDR[artcount].artno = artno;
+ XHDR[artcount].header = restrdup(XHDR[artcount].header,mid);
+ /*INNBBSihave(bbsnnrp,i,artno,mid);*/
+ /* to get it */
+ artcount++;
+ }
+ } else if (mid != NULL) {
+ if (INNBBSstat(bbsnnrp,i,mid) == INNBBSstatOK) {
+ printf("** %d ** %d need cancel %s\n", artcount, artno,mid);
+ XHDR[artcount].artno = artno;
+ XHDR[artcount].header = restrdup(XHDR[artcount].header,mid);
+ artcount++;
+ }
+ }
+ maxartno = artno;
+ }
+ }
+ }/* while xhdr OK */
+ exception = 0;
+ for (xcount = 0; xcount < artcount; xcount++) {
+ ULONG artno;
+ char *mid;
+ artno = XHDR[xcount].artno;
+ mid = XHDR[xcount].header;
+ if (isCancelControl) {
+ if (NNRPstat(bbsnnrp,artno,&mid) == NNRPstatOK) {
+ }
+ }
+ printf("** %d ** %d i have it %s\n", xcount, artno, mid);
+ if (!ResetActive && mid != NULL)
+ exception = INNBBSihave(bbsnnrp,artno,mid);
+ if (exception == -1) break;
+ if (rcptr->high != artno) {
+ rcptr->high = artno;
+ updaterc(rcptr->highptr, rcptr->highlen, rcptr->high);
+ }
+ }
+ if (rcptr->high != maxartno && exception != -1) {
+ bbsnnrp->actdirty = 1;
+ rcptr->high = maxartno;
+ updaterc(rcptr->highptr, rcptr->highlen, maxartno);
+ }
+ }
+ }
+ /*
+ flushrc(bbsnnrp);
+ */
+ }
+ fprintf(bbsnnrp->innbbsout,"quit\r\n");
+ fprintf(bbsnnrp->nnrpout,"quit\r\n");
+ fflush(bbsnnrp->innbbsout);
+ fflush(bbsnnrp->nnrpout);
+ fgets(NNRPbuffer, sizeof NNRPbuffer, bbsnnrp->nnrpin);
+ fgets(INNBBSbuffer, sizeof INNBBSbuffer, bbsnnrp->innbbsin);
+
+/* bbsnnrp->newsrc[0].high = 1900;
+ updaterc(bbsnnrp->newsrc[0].highptr, bbsnnrp->newsrc[0].highlen,
+ bbsnnrp->newsrc[0].high);
+*/
+}
+
+INNBBSDhalt()
+{
+}
diff --git a/innbbsd/clibrary.h b/innbbsd/clibrary.h
new file mode 100644
index 00000000..92ec82e0
--- /dev/null
+++ b/innbbsd/clibrary.h
@@ -0,0 +1,131 @@
+/* $Revision: 1.1 $
+**
+** Here be declarations of routines and variables in the C library.
+** You must #include <sys/types.h> and <stdio.h> before this file.
+*/
+
+#if defined(DO_HAVE_UNISTD)
+#include <unistd.h>
+#endif /* defined(DO_HAVE_UNISTD) */
+
+#if defined(DO_HAVE_VFORK)
+#include <vfork.h>
+#endif /* defined(DO_HAVE_VFORK) */
+
+ /* Generic pointer, used by memcpy, malloc, etc. */
+ /* =()<typedef @<POINTER>@ *POINTER;>()= */
+typedef char *POINTER;
+ /* What is a file offset? Will not work unless long! */
+ /* =()<typedef @<OFFSET_T>@ OFFSET_T;>()= */
+typedef long OFFSET_T;
+ /* What is the type of an object size? */
+ /* =()<typedef @<SIZE_T>@ SIZE_T;>()= */
+typedef int SIZE_T;
+ /* What is the type of a passwd uid and gid, for use in chown(2)? */
+ /* =()<typedef @<UID_T>@ UID_T;>()= */
+typedef int UID_T;
+ /* =()<typedef @<GID_T>@ GID_T;>()= */
+typedef int GID_T;
+ /* =()<typedef @<PID_T>@ PID_T;>()= */
+typedef int PID_T;
+ /* What should a signal handler return? */
+ /* =()<#define SIGHANDLER @<SIGHANDLER>@>()= */
+#define SIGHANDLER void
+
+#if defined(SIG_DFL)
+ /* What types of variables can be modified in a signal handler? */
+ /* =()<typedef @<SIGVAR>@ SIGVAR;>()= */
+typedef int SIGVAR;
+#endif /* defined(SIG_DFL) */
+
+/* =()<#include @<STR_HEADER>@>()= */
+#include <string.h>
+/* =()<#include @<MEM_HEADER>@>()= */
+#include <memory.h>
+
+
+/*
+** It's a pity we have to go through these contortions, for broken
+** systems that have fd_set but not the FD_SET.
+*/
+#if defined(FD_SETSIZE)
+#define FDSET fd_set
+#else
+#include <sys/param.h>
+#if !defined(NOFILE)
+ error -- #define NOFILE to the number of files allowed on your machine!
+#endif /* !defined(NOFILE) */
+#if !defined(howmany)
+#define howmany(x, y) (((x) + ((y) - 1)) / (y))
+#endif /* !defined(howmany) */
+#define FD_SETSIZE NOFILE
+#define NFDBITS (sizeof (long) * 8)
+typedef struct _FDSET {
+ long fds_bits[howmany(FD_SETSIZE, NFDBITS)];
+} FDSET;
+#define FD_SET(n, p) (p)->fds_bits[(n) / NFDBITS] |= (1 << ((n) % NFDBITS))
+#define FD_CLR(n, p) (p)->fds_bits[(n) / NFDBITS] &= ~(1 << ((n) % NFDBITS))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n) / NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_ZERO(p) (void)memset((POINTER)(p), 0, sizeof *(p))
+#endif /* defined(FD_SETSIZE) */
+
+
+#if !defined(SEEK_SET)
+#define SEEK_SET 0
+#endif /* !defined(SEEK_SET) */
+#if !defined(SEEK_END)
+#define SEEK_END 2
+#endif /* !defined(SEEK_END) */
+
+/*
+** We must use #define to set FREEVAL, since "typedef void FREEVAL;" doesn't
+** work on some broken compilers, sigh.
+*/
+/* =()<#define FREEVAL @<FREEVAL>@>()= */
+#define FREEVAL int
+
+extern int optind;
+extern char *optarg;
+#if !defined(__STDC__)
+extern int errno;
+#endif /* !defined(__STDC__) */
+
+extern char *getenv();
+extern char *inet_ntoa();
+extern char *mktemp();
+#if !defined(strerror)
+extern char *strerror();
+#endif /* !defined(strerror) */
+extern long atol();
+extern time_t time();
+extern unsigned long inet_addr();
+extern FREEVAL free();
+extern POINTER malloc();
+extern POINTER realloc();
+#if defined(ACT_MMAP)
+extern char *mmap();
+#endif /* defined(ACT_MMAP) */
+
+/* Some backward systems need this. */
+extern FILE *popen();
+
+/* This is in <mystring.h>, but not in some system string headers,
+ * so we put it here just in case. */
+extern int strncasecmp();
+
+/* =()<extern @<ABORTVAL>@ abort();>()= */
+extern int abort();
+/* =()<extern @<ALARMVAL>@ alarm();>()= */
+extern int alarm();
+/* =()<extern @<EXITVAL>@ exit();>()= */
+extern void exit();
+/* =()<extern @<GETPIDVAL>@ getpid();>()= */
+extern int getpid();
+/* =()<extern @<LSEEKVAL>@ lseek();>()= */
+extern off_t lseek();
+/* =()<extern @<QSORTVAL>@ qsort();>()= */
+extern int qsort();
+/* =()<extern @<SLEEPVAL>@ sleep();>()= */
+extern int sleep();
+/* =()<extern @<_EXITVAL>@ _exit();>()= */
+extern int _exit();
diff --git a/innbbsd/closeonexec.c b/innbbsd/closeonexec.c
new file mode 100644
index 00000000..e005e51b
--- /dev/null
+++ b/innbbsd/closeonexec.c
@@ -0,0 +1,66 @@
+/* $Revision: 1.1 $
+**
+*/
+/*#include "configdata.h"*/
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include "clibrary.h"
+
+#ifndef CLX_IOCTL
+# define CLX_IOCTL
+#endif
+#ifndef CLX_FCNTL
+# define CLX_FCNTL
+#endif
+
+
+
+#if defined(CLX_IOCTL) && !defined(IRIX)
+#ifdef __linux
+# include <termios.h>
+#else
+# include <sgtty.h>
+#endif
+
+
+/*
+** Mark a file close-on-exec so that it doesn't get shared with our
+** children. Ignore any error codes.
+*/
+void
+closeOnExec(fd, flag)
+ int fd;
+ int flag;
+{
+ int oerrno;
+
+ oerrno = errno;
+ (void)ioctl(fd, flag ? FIOCLEX : FIONCLEX, (char *)NULL);
+ errno = oerrno;
+}
+#endif /* defined(CLX_IOCTL) */
+
+
+
+#if defined(CLX_FCNTL)
+#include <fcntl.h>
+
+
+/*
+** Mark a file close-on-exec so that it doesn't get shared with our
+** children. Ignore any error codes.
+*/
+void
+CloseOnExec(fd, flag)
+ int fd;
+ int flag;
+{
+ int oerrno;
+
+ oerrno = errno;
+ (void)fcntl(fd, F_SETFD, flag ? 1 : 0);
+ errno = oerrno;
+}
+#endif /* defined(CLX_FCNTL) */
diff --git a/innbbsd/connectsock.c b/innbbsd/connectsock.c
new file mode 100644
index 00000000..71203cfe
--- /dev/null
+++ b/innbbsd/connectsock.c
@@ -0,0 +1,452 @@
+#include "innbbsconf.h"
+#include "daemon.h"
+#include <signal.h>
+#include <setjmp.h>
+
+static jmp_buf timebuf;
+
+static void
+timeout(sig)
+ int sig;
+{
+ longjmp(timebuf, sig);
+}
+
+extern int errno;
+static void reapchild (s)
+int s;
+{
+ int state;
+ while (waitpid(-1,&state,WNOHANG|WUNTRACED)>0) {
+ /* printf("reaping child\n");*/
+ }
+}
+
+void dokill(s)
+int s;
+{
+ kill(0,SIGKILL);
+}
+
+static INETDstart = 0;
+int startfrominetd(flag)
+{
+ INETDstart = flag ;
+}
+
+
+int standalonesetup(fd)
+int fd;
+{
+ int on =1;
+ struct linger foobar;
+ if (setsockopt(fd,SOL_SOCKET, SO_REUSEADDR,(char *)&on,sizeof(on)) < 0)
+ syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
+ foobar.l_onoff = 0;
+ if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&foobar, sizeof (foobar))<0)
+ syslog(LOG_ERR, "setsockopt (SO_LINGER): %m");
+}
+
+static char *UNIX_SERVER_PATH;
+static int (*halt)();
+
+sethaltfunction(haltfunc)
+int (*haltfunc)();
+{
+ halt = haltfunc;
+}
+
+void docompletehalt(s)
+int s;
+{
+ /*printf("try to remove %s\n", UNIX_SERVER_PATH);
+ unlink(UNIX_SERVER_PATH);*/
+ exit(0);
+ /*dokill();*/
+}
+
+void doremove(s)
+int s;
+{
+ if (halt != NULL)
+ (*halt)(s);
+ else
+ docompletehalt(s);
+}
+
+
+initunixserver(path, protocol)
+char *path;
+char *protocol;
+{
+ struct sockaddr_un s_un;
+ /* unix endpoint address */
+ struct protoent *pe; /*protocol information entry*/
+ int s;
+ char *ptr;
+
+ bzero((char*)&s_un,sizeof(s_un));
+ s_un.sun_family= AF_UNIX;
+ strcpy(s_un.sun_path, path);
+ if (protocol==NULL)
+ protocol="tcp";
+ /* map protocol name to protocol number */
+ pe=getprotobyname(protocol);
+ if (pe==NULL) {
+ fprintf(stderr,"%s: Unknown protocol.\n",protocol);
+ return (-1);
+ }
+
+ /* Allocate a socket */
+ s = socket(PF_UNIX,strcmp(protocol,"tcp")?SOCK_DGRAM:SOCK_STREAM,0);
+ if (s<0) {
+ printf("protocol %d\n", pe->p_proto);
+ perror("socket");
+ return -1;
+ }
+ /*standalonesetup(s);*/
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGUSR1, SIG_IGN);
+ signal(SIGCHLD,reapchild);
+ UNIX_SERVER_PATH = path;
+ signal(SIGINT,doremove);
+ signal(SIGTERM,doremove);
+
+ chdir("/");
+ if (bind(s,(struct sockaddr*)&s_un,sizeof (struct sockaddr_un))<0){
+ perror("bind");
+ perror(path);
+ return -1;
+ }
+ listen(s,10);
+ return s;
+}
+
+initinetserver(service,protocol)
+char *service;
+char *protocol;
+{
+ struct servent *se; /*service information entry*/
+ struct hostent *he; /*host information entry*/
+ struct protoent *pe; /*protocol information entry*/
+ struct sockaddr_in sin;/*Internet endpoint address*/
+ int port,s;
+ int randomport=0;
+
+ bzero((char*)&sin,sizeof(sin));
+ sin.sin_family= AF_INET;
+ if (!strcmp("0",service)) {
+ randomport = 1;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ }
+
+ if (service==NULL)
+ service=DEFAULTPORT;
+ if (protocol==NULL)
+ protocol="tcp";
+ /* map service name to port number */
+ /* service ---> port */
+ se = getservbyname(service,protocol);
+ if (se==NULL) {
+ port = htons((u_short)atoi(service));
+ if (port==0 && !randomport) {
+ fprintf (stderr, "%s/%s: Unknown service.\n",service,protocol);
+ return (-1);
+ }
+ } else
+ port=se->s_port;
+ sin.sin_port = port;
+
+ /* map protocol name to protocol number */
+ pe=getprotobyname(protocol);
+ if (pe==NULL) {
+ fprintf(stderr,"%s: Unknown protocol.\n",protocol);
+ return (-1);
+ }
+
+ /* Allocate a socket */
+ s = socket(PF_INET,strcmp(protocol,"tcp")?SOCK_DGRAM:SOCK_STREAM,pe->p_proto);
+ if (s<0) {
+ perror("socket");
+ return -1;
+ }
+ standalonesetup(s);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGUSR1, SIG_IGN);
+ signal(SIGCHLD,reapchild);
+ signal(SIGINT,dokill);
+ signal(SIGTERM,dokill);
+
+ chdir("/");
+ if (bind(s,(struct sockaddr*)&sin,sizeof (struct sockaddr_in))<0){
+ perror("bind");
+ return -1;
+ }
+ listen(s,10);
+#ifdef DEBUG
+ { int length=sizeof(sin);
+ getsockname(s,&sin,&length);
+ printf("portnum alocalted %d\n",sin.sin_port);
+ }
+#endif
+ return s;
+}
+
+int open_unix_listen(path,protocol,initfunc)
+char *path;
+char *protocol;
+int (*initfunc) ARG((int));
+{
+ int s;
+ s = initunixserver(path,protocol);
+ if (s<0) {
+ return -1;
+ }
+ if (initfunc != NULL) {
+ printf("in inetsingleserver before initfunc s %d\n",s);
+ if ((*initfunc)(s)<0) {
+ perror("initfunc error");
+ return -1;
+ }
+ printf("end inetsingleserver before initfunc \n");
+ }
+ return s;
+}
+
+int open_listen(service,protocol,initfunc)
+char *service;
+char *protocol;
+int (*initfunc) ARG((int));
+{
+ int s;
+ if (! INETDstart)
+ s = initinetserver(service,protocol);
+ else
+ s = 0;
+ if (s<0) {
+ return -1;
+ }
+ if (initfunc != NULL) {
+ printf("in inetsingleserver before initfunc s %d\n",s);
+ if ((*initfunc)(s)<0) {
+ perror("initfunc error");
+ return -1;
+ }
+ printf("end inetsingleserver before initfunc \n");
+ }
+ return s;
+}
+
+int inetsingleserver(service,protocol,serverfunc,initfunc)
+char *service;
+char *protocol;
+int (*initfunc) ARG((int));
+int (*serverfunc) ARG((int));
+{
+ int s;
+ if (!INETDstart)
+ s = initinetserver(service,protocol);
+ else
+ s = 0;
+ if (s<0) {
+ return -1;
+ }
+ if (initfunc != NULL) {
+ printf("in inetsingleserver before initfunc s %d\n",s);
+ if ((*initfunc)(s)<0) {
+ perror("initfunc error");
+ return -1;
+ }
+ printf("end inetsingleserver before initfunc \n");
+ }
+ {
+ int ns=tryaccept(s);
+ int result=0;
+ if (ns < 0 && errno != EINTR){
+#ifdef DEBUGSERVER
+ perror("accept");
+#endif
+ }
+ close(s);
+ if (serverfunc != NULL)
+ result = (*serverfunc)(ns);
+ close(ns);
+ return(result);
+ }
+}
+
+
+int tryaccept(s)
+int s;
+{
+ int ns,fromlen;
+ struct sockaddr sockaddr;/*Internet endpoint address*/
+ fromlen=sizeof (struct sockaddr_in);
+
+#ifdef DEBUGSERVER
+ fputs("Listening again\n",stdout);
+#endif
+ do {
+ ns = accept(s,&sockaddr,&fromlen);
+ errno = 0;
+ } while ( ns < 0 && errno == EINTR );
+ return ns;
+}
+
+int inetserver(service,protocol,serverfunc)
+char *service;
+char *protocol;
+int (*serverfunc) ARG((int));
+{
+ int port,s;
+
+ if (!INETDstart)
+ s = initinetserver(service,protocol);
+ else
+ s = 0;
+ if (s<0) {
+ return -1;
+ }
+ for (;;) {
+ int ns=tryaccept(s);
+ int result=0;
+ int pid;
+ if (ns < 0 && errno != EINTR){
+#ifdef DEBUGSERVER
+ perror("accept");
+#endif
+ continue;
+ }
+#ifdef DEBUGSERVER
+ fputs("Accept OK\n",stdout);
+#endif
+ pid = fork();
+ if (pid==0) {
+ close(s);
+ if (serverfunc != NULL)
+ result = (*serverfunc)(ns);
+ close(ns);
+ exit(result);
+ } else if (pid < 0) {
+ perror("fork");
+ return -1;
+ }
+ close(ns);
+ }
+ return 0;
+}
+
+int inetclient(server,service,protocol)
+char *server;
+char *protocol;
+char *service;
+{
+ struct servent *se; /*service information entry*/
+ struct hostent *he; /*host information entry*/
+ struct protoent *pe; /*protocol information entry*/
+ struct sockaddr_in sin;/*Internet endpoint address*/
+ int port,s;
+
+ bzero((char*)&sin,sizeof(sin));
+ sin.sin_family= AF_INET;
+
+ if (service==NULL)
+ service=DEFAULTPORT;
+ if (protocol==NULL)
+ protocol="tcp";
+ if (server==NULL)
+ server=DEFAULTSERVER;
+ /* map service name to port number */
+ /* service ---> port */
+ se = getservbyname(service,protocol);
+ if (se==NULL) {
+ port = htons((u_short)atoi(service));
+ if (port==0) {
+ fprintf (stderr, "%s/%s: Unknown service.\n",service,protocol);
+ return (-1);
+ }
+ } else
+ port=se->s_port;
+ sin.sin_port = port;
+
+ /* map server hostname to IP address, allowing for dotted decimal */
+ he=gethostbyname(server);
+ if (he==NULL) {
+ sin.sin_addr.s_addr = inet_addr(server);
+ if (sin.sin_addr.s_addr==INADDR_NONE) {
+ fprintf (stderr, "%s: Unknown host.\n",server);
+ return (-1);
+ }
+ } else
+ bcopy(he->h_addr,(char*)&sin.sin_addr,he->h_length);
+
+ /* map protocol name to protocol number */
+ pe=getprotobyname(protocol);
+ if (pe==NULL) {
+ fprintf(stderr,"%s: Unknown protocol.\n",protocol);
+ return (-1);
+ }
+
+ /* Allocate a socket */
+ s = socket(PF_INET,strcmp(protocol,"tcp")?SOCK_DGRAM:SOCK_STREAM,pe->p_proto);
+ if (s<0) {
+ perror("socket");
+ return -1;
+ }
+
+ if (setjmp(timebuf) == 0)
+ {
+ signal(SIGALRM, timeout);
+ alarm(5);
+ if (connect(s,(struct sockaddr*)&sin,sizeof(sin))<0)
+ {
+ alarm(0);
+ return -1;
+ }
+ }
+ else
+ {
+ alarm(0);
+ return -1;
+ }
+ alarm(0);
+
+ return s;
+}
+
+int unixclient(path,protocol)
+char *path;
+char *protocol;
+{
+ struct protoent *pe; /*protocol information entry*/
+ struct sockaddr_un s_un;/*unix endpoint address*/
+ int s;
+
+ bzero((char*)&s_un,sizeof(s_un));
+ s_un.sun_family= AF_UNIX;
+
+ if (path==NULL)
+ path=DEFAULTPATH;
+ if (protocol==NULL)
+ protocol="tcp";
+ strcpy(s_un.sun_path , path);
+
+ /* map protocol name to protocol number */
+ pe=getprotobyname(protocol);
+ if (pe==NULL) {
+ fprintf(stderr,"%s: Unknown protocol.\n",protocol);
+ return (-1);
+ }
+ /* Allocate a socket */
+ s = socket(PF_UNIX,strcmp(protocol,"tcp")?SOCK_DGRAM:SOCK_STREAM,0);
+ if (s<0) {
+ perror("socket");
+ return -1;
+ }
+ /* Connect the socket to the server */
+ if (connect(s,(struct sockaddr*)&s_un,sizeof(s_un))<0) {
+ /*perror("connect");*/
+ return -1;
+ }
+ return s;
+}
diff --git a/innbbsd/ctlinnbbsd.c b/innbbsd/ctlinnbbsd.c
new file mode 100644
index 00000000..4ba77b52
--- /dev/null
+++ b/innbbsd/ctlinnbbsd.c
@@ -0,0 +1,160 @@
+#include "innbbsconf.h"
+#include "bbslib.h"
+
+extern char *optarg;
+extern int opterr, optind;
+
+usage(name)
+char *name;
+{
+ fprintf(stderr, "Usage: %s [-p path] commands\n",name);
+ fprintf(stderr, " where available commands:\n");
+ fprintf(stderr," ctlinnbbsd reload : reload datafiles for innbbsd\n");
+ fprintf(stderr," ctlinnbbsd shutdown : shutdown innbbsd gracefully\n");
+ fprintf(stderr," ctlinnbbsd mode : examine mode of innbbsd\n");
+ fprintf(stderr," ctlinnbbsd addhist <mid> path: add history\n");
+ fprintf(stderr," ctlinnbbsd grephist <mid>: query history\n");
+ fprintf(stderr," ctlinnbbsd verboselog on|off : verboselog on/off\n");
+ fprintf(stderr," ctlinnbbsd hismaint : maintain history\n");
+ fprintf(stderr," ctlinnbbsd listnodelist : list nodelist.bbs\n");
+ fprintf(stderr," ctlinnbbsd listnewsfeeds : list newsfeeds.bbs\n");
+#ifdef GETRUSAGE
+ fprintf(stderr," ctlinnbbsd getrusage: get resource usage\n");
+#endif
+#ifdef MALLOCMAP
+ fprintf(stderr," ctlinnbbsd mallocmap: get malloc map\n");
+#endif
+}
+
+
+char *DefaultPath = LOCALDAEMON;
+char INNBBSbuffer[4096];
+
+FILE *innbbsin, *innbbsout;
+int innbbsfd;
+
+ctlinnbbsd(argc, argv)
+int argc;
+char **argv;
+{
+ fgets(INNBBSbuffer, sizeof INNBBSbuffer, innbbsin);
+ printf("%s",INNBBSbuffer);
+ if (strcasecmp(argv[0], "shutdown")==0 ||
+ strcasecmp(argv[0], "reload")==0 ||
+ strcasecmp(argv[0], "hismaint")==0 ||
+#ifdef GETRUSAGE
+ strcasecmp(argv[0], "getrusage")==0 ||
+#endif
+#ifdef MALLOCMAP
+ strcasecmp(argv[0], "mallocmap")==0 ||
+#endif
+ strcasecmp(argv[0], "mode")==0 ||
+ strcasecmp(argv[0], "listnodelist")==0 ||
+ strcasecmp(argv[0], "listnewsfeeds")==0
+ ) {
+ fprintf( innbbsout, "%s\r\n", argv[0]);
+ fflush( innbbsout);
+ fgets(INNBBSbuffer, sizeof INNBBSbuffer, innbbsin);
+ printf("%s",INNBBSbuffer);
+ if (strcasecmp(argv[0], "mode") ==0
+#ifdef GETRUSAGE
+ ||
+ strcasecmp(argv[0], "getrusage") ==0
+ ||
+ strcasecmp(argv[0], "mallocmap") ==0
+#endif
+ ||
+ strcasecmp(argv[0], "listnodelist")==0
+ ||
+ strcasecmp(argv[0], "listnewsfeeds")==0
+ ) {
+ while (fgets(INNBBSbuffer, sizeof INNBBSbuffer, innbbsin) != NULL) {
+ if (strcmp(INNBBSbuffer,".\r\n")==0) {
+ break;
+ }
+ printf("%s",INNBBSbuffer);
+ }
+ }
+ } else if (strcasecmp(argv[0], "grephist")==0 ||
+ strcasecmp(argv[0], "verboselog")==0 ) {
+ if (argc < 2) {
+ usage("ctlinnbbsd");
+ } else {
+ fprintf( innbbsout, "%s %s\r\n", argv[0], argv[1]);
+ fflush( innbbsout);
+ fgets(INNBBSbuffer, sizeof INNBBSbuffer, innbbsin);
+ printf("%s\n",INNBBSbuffer);
+ }
+ } else if (strcasecmp(argv[0], "addhist")==0) {
+ if (argc < 3) {
+ usage("ctlinnbbsd");
+ } else {
+ fprintf( innbbsout, "%s %s %s\r\n", argv[0], argv[1], argv[2]);
+ fflush( innbbsout);
+ fgets(INNBBSbuffer, sizeof INNBBSbuffer, innbbsin);
+ printf("%s",INNBBSbuffer);
+ }
+ } else {
+ fprintf(stderr, "invalid command %s\n", argv[0]);
+ }
+ if (strcasecmp(argv[0],"shutdown") != 0) {
+ fprintf( innbbsout, "QUIT\r\n");
+ fflush(innbbsout);
+ fgets(INNBBSbuffer, sizeof INNBBSbuffer, innbbsin);
+ }
+}
+
+initsocket()
+{
+ innbbsfd = unixclient(DefaultPath,"tcp");
+ if (innbbsfd < 0) {
+ fprintf(stderr, "Connect to %s error. You may not run innbbsd\n", DefaultPath);
+ exit(2);
+ }
+ if ( (innbbsin= fdopen(innbbsfd,"r")) == NULL ||
+ (innbbsout= fdopen(innbbsfd,"w"))== NULL ) {
+ fprintf( stderr, "fdopen error\n");
+ exit(3);
+ }
+}
+
+closesocket()
+{
+ if (innbbsin != NULL)
+ fclose(innbbsin);
+ if (innbbsout != NULL)
+ fclose(innbbsout);
+ if (innbbsfd >= 0)
+ close(innbbsfd);
+}
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+ int c, errflag=0;
+
+ while ((c = getopt(argc,argv,"p:h?"))!= -1)
+ switch (c) {
+ case 'p':
+ DefaultPath = optarg;
+ break;
+ case 'h':
+ case '?':
+ default:
+ errflag ++;
+ break;
+ }
+ if (errflag > 0) {
+ usage(argv[0]);
+ return(1);
+ }
+ if (argc - optind < 1) {
+ usage(argv[0]);
+ exit(1);
+ }
+ initial_bbs(NULL);
+ initsocket();
+ ctlinnbbsd(argc-optind, argv+optind);
+ closesocket();
+}
diff --git a/innbbsd/daemon.c b/innbbsd/daemon.c
new file mode 100644
index 00000000..973a96c8
--- /dev/null
+++ b/innbbsd/daemon.c
@@ -0,0 +1,173 @@
+#include "daemon.h"
+/*
+typedef struct daemoncmd {
+ char *cmdname;
+ char *usage;
+ int argc;
+ int (*main) ARG((FILE*,FILE*,int,char**,char*));
+} daemoncmd_t;
+
+*/
+
+void deargify ARG((char ***));
+static daemoncmd_t *dcmdp=NULL;
+static char *startupmessage=NULL;
+static int startupcode=100;
+static FILE *DIN,*DOUT,*DIO;
+typedef int (*F)();
+
+void installdaemon(cmds,code,startupmsg)
+daemoncmd_t *cmds;
+int code;
+char *startupmsg;
+{
+ dcmdp = cmds;
+ startupcode = code;
+ startupmessage = startupmsg;
+}
+
+daemoncmd_t *searchcmd(cmd)
+char *cmd;
+{
+ daemoncmd_t *p;
+ for (p=dcmdp;p->name != NULL ; p++) {
+#ifdef DEBUGCMD
+ printf("searching name %s for cmd %s\n",p->name,cmd);
+#endif
+ if (!strncasecmp(p->name,cmd,1024))
+ return p;
+ }
+ return NULL;
+}
+
+#if 0
+int daemon(dfd)
+int dfd;
+{
+ static char BUF[1024];
+ /*hash_init();*/
+ if (dfd > 0) {
+ DIO = fdopen(dfd,"rw");
+ DIN = fdopen(dfd,"r");
+ DOUT = fdopen(dfd,"w");
+ if (DIO == NULL || DIN == NULL || DOUT == NULL) {
+ perror("fdopen");
+ return -1;
+ }
+ }
+ if (startupmessage) {
+ fprintf(DOUT,"%d %s\n",startupcode,startupmessage);
+ fflush(DOUT);
+ }
+ while (fgets(BUF,1024,DIN) != NULL) {
+ int i;
+ int (*Main)();
+ daemoncmd_t *dp;
+ argv_t Argv;
+
+ char *p=(char*)strchr(BUF,'\r');
+ if (p == NULL) p=(char*)strchr(BUF,'\n');
+ if (p == NULL) continue;
+ *p='\0';
+ if (p==BUF) continue;
+
+ Argv.argc = 0, Argv.argv = NULL, Argv.inputline=BUF;
+ Argv.in = DIN, Argv.out = DOUT;
+ printf("command entered: %s\n",BUF);
+#ifdef DEBUGSERVER
+ fprintf(DOUT,"BUF in client %s\n",BUF);
+ fprintf(stdout,"BUF in server %s\n",BUF);
+ fflush(DOUT);
+#endif
+ Argv.argc = argify(BUF,&Argv.argv);
+#ifdef DEBUGSERVER
+ fprintf(stdout,"argc %d argv ",Argv.argc);
+ for (i=0;i<Argv.argc;++i)
+ fprintf(stdout,"%s ",Argv.argv[i]);
+ fprintf(stdout,"\n");
+#endif
+ dp = searchcmd(Argv.argv[0]);
+ Argv.dc = dp;
+ if (dp) {
+#ifdef DEBUGSERVER
+ printf("find cmd %s by %s\n",dp->name,dp->usage);
+#endif
+ if (Argv.argc < dp->argc) {
+ fprintf(DOUT,"%d Usage: %s\n",dp->errorcode,dp->usage);
+ fflush(DOUT);
+ goto cont;
+ }
+ if (dp->argno != 0 && Argv.argc > dp->argno) {
+ fprintf(DOUT,"%d Usage: %s\n",dp->errorcode,dp->usage);
+ fflush(DOUT);
+ goto cont;
+ }
+ Main=dp->main;
+ if (Main) {
+ fflush(stdout);
+ (*Main)(&Argv);
+ }
+ }
+ else {
+ fprintf(DOUT,"99 command %s not available\n",Argv.argv[0]);
+ fflush(DOUT);
+ }
+cont:
+ deargify(&Argv.argv);
+ }
+ /*hash_reclaim();*/
+}
+#endif
+
+#define MAX_ARG 32
+#define MAX_ARG_SIZE 16384
+
+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++;
+ i=strlen(line);
+ /*p=(char*) mymalloc(i+1);*/
+ 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;
+}
+
+void deargify (argv)
+char ***argv;
+{
+ return;
+ /*if (*argv != NULL) {
+ if (*argv[0] != NULL){
+ free(*argv[0]);
+ *argv[0] = NULL;
+ }
+ free(*argv);
+ *argv = NULL;
+ }*/
+}
+
+int daemonprintf(format)
+char *format;
+{
+ fprintf(DOUT,format);
+ fflush(DOUT);
+}
+
+int daemonputs(output)
+char* output;
+{
+ fputs(output, DOUT);
+ fflush(DOUT);
+}
diff --git a/innbbsd/daemon.h b/innbbsd/daemon.h
new file mode 100644
index 00000000..d056051f
--- /dev/null
+++ b/innbbsd/daemon.h
@@ -0,0 +1,54 @@
+#ifndef DAEMON_H
+#define DAEMON_H
+
+#include <stdio.h>
+#include <time.h>
+
+#ifndef ARG
+# ifdef __STDC__
+# define ARG(x) x
+# else
+# define ARG(x) ()
+# endif
+#endif
+
+
+struct Argv_t {
+ FILE *in,*out;
+ int argc;
+ char **argv;
+ char *inputline;
+ struct Daemoncmd *dc;
+};
+
+typedef struct Argv_t argv_t;
+
+typedef struct Buffer_t {
+ char *data;
+ int used, left, lastread;
+} buffer_t;
+
+typedef struct ClientType {
+ char hostname[1024];
+ char username[32];
+ char buffer[4096];
+ int mode;
+ argv_t Argv;
+ int fd, access, lastread, midcheck;
+ buffer_t in,out;
+ int ihavecount, ihavesize, ihaveduplicate, ihavefail;
+ int statcount, statfail;
+ time_t begin;
+} ClientType;
+
+typedef struct Daemoncmd {
+ char *name;
+ char *usage;
+ int argc, argno, errorcode, normalcode;
+ int (*main) ARG(( ClientType*));
+} daemoncmd_t;
+
+extern void installdaemon ARG((daemoncmd_t *,int,char*));
+extern ClientType *Channel;
+
+#endif
diff --git a/innbbsd/dbz.c b/innbbsd/dbz.c
new file mode 100644
index 00000000..6fd15df8
--- /dev/null
+++ b/innbbsd/dbz.c
@@ -0,0 +1,1918 @@
+/*
+
+dbz.c V3.2
+
+Copyright 1988 Jon Zeeff (zeeff@b-tech.ann-arbor.mi.us)
+You can use this code in any manner, as long as you leave my name on it
+and don't hold me responsible for any problems with it.
+
+Hacked on by gdb@ninja.UUCP (David Butler); Sun Jun 5 00:27:08 CDT 1988
+
+Various improvments + INCORE by moraes@ai.toronto.edu (Mark Moraes)
+
+Major reworking by Henry Spencer as part of the C News project.
+
+Minor lint and CodeCenter (Saber) fluff removal by Rich $alz (March, 1991).
+Non-portable CloseOnExec() calls added by Rich $alz (September, 1991).
+Added "writethrough" and tagmask calculation code from
+<rob@violet.berkeley.edu> and <leres@ee.lbl.gov> by Rich $alz (December, 1992).
+Merged in MMAP code by David Robinson, formerly <david@elroy.jpl.nasa.gov>
+now <david.robinson@sun.com> (January, 1993).
+
+These routines replace dbm as used by the usenet news software
+(it's not a full dbm replacement by any means). It's fast and
+simple. It contains no AT&T code.
+
+In general, dbz's files are 1/20 the size of dbm's. Lookup performance
+is somewhat better, while file creation is spectacularly faster, especially
+if the incore facility is used.
+
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#ifndef __STDC__
+extern int errno;
+#endif
+#include <dbz.h>
+#include "clibrary.h"
+
+/*
+ * #ifdef index. "LIA" = "leave it alone unless you know what you're doing".
+ *
+ * FUNNYSEEKS SEEK_SET is not 0, get it from <unistd.h>
+ * INDEX_SIZE backward compatibility with old dbz; avoid using this
+ * NMEMORY number of days of memory for use in sizing new table (LIA)
+ * INCORE backward compatibility with old dbz; use dbzincore() instead
+ * DBZDEBUG enable debugging
+ * DEFSIZE default table size (not as critical as in old dbz)
+ * OLDBNEWS default case mapping as in old B News; set NOBUFFER
+ * BNEWS default case mapping as in current B News; set NOBUFFER
+ * DEFCASE default case-map algorithm selector
+ * NOTAGS fseek offsets are strange, do not do tagging (see below)
+ * NPAGBUF size of .pag buffer, in longs (LIA)
+ * SHISTBUF size of ASCII-file buffer, in bytes (LIA)
+ * MAXRUN length of run which shifts to next table (see below) (LIA)
+ * OVERFLOW long-int arithmetic overflow must be avoided, will trap
+ * NOBUFFER do not buffer hash-table i/o, B News locking is defective
+ * MMAP Use SunOS style mmap() for efficient incore
+ */
+/* SUPPRESS 530 *//* Empty body for statement */
+/* SUPPRESS 701 on free *//* Conflicting declaration */
+
+#ifdef FUNNYSEEKS
+#include <unistd.h>
+#else
+#define SEEK_SET 0
+#endif
+#ifdef OVERFLOW
+#include <limits.h>
+#endif
+
+static int dbzversion = 3; /* for validating .dir file format */
+
+/*
+ * The dbz database exploits the fact that when news stores a <key,value>
+ * tuple, the `value' part is a seek offset into a text file, pointing to
+ * a copy of the `key' part. This avoids the need to store a copy of
+ * the key in the dbz files. However, the text file *must* exist and be
+ * consistent with the dbz files, or things will fail.
+ *
+ * The basic format of the database is a simple hash table containing the
+ * values. A value is stored by indexing into the table using a hash value
+ * computed from the key; collisions are resolved by linear probing (just
+ * search forward for an empty slot, wrapping around to the beginning of
+ * the table if necessary). Linear probing is a performance disaster when
+ * the table starts to get full, so a complication is introduced. The
+ * database is actually one *or more* tables, stored sequentially in the
+ * .pag file, and the length of linear-probe sequences is limited. The
+ * search (for an existing item or an empty slot) always starts in the
+ * first table, and whenever MAXRUN probes have been done in table N,
+ * probing continues in table N+1. This behaves reasonably well even in
+ * cases of massive overflow. There are some other small complications
+ * added, see comments below.
+ *
+ * The table size is fixed for any particular database, but is determined
+ * dynamically when a database is rebuilt. The strategy is to try to pick
+ * the size so the first table will be no more than 2/3 full, that being
+ * slightly before the point where performance starts to degrade. (It is
+ * desirable to be a bit conservative because the overflow strategy tends
+ * to produce files with holes in them, which is a nuisance.)
+ */
+
+/*
+ * The following is for backward compatibility.
+ */
+#ifdef INDEX_SIZE
+#define DEFSIZE INDEX_SIZE
+#endif
+
+/*
+ * ANSI C says an offset into a file is a long, not an off_t, for some
+ * reason. This actually does simplify life a bit, but it's still nice
+ * to have a distinctive name for it. Beware, this is just for readability,
+ * don't try to change this.
+ */
+#define of_t long
+#define SOF (sizeof(of_t))
+
+/*
+ * We assume that unused areas of a binary file are zeros, and that the
+ * bit pattern of `(of_t)0' is all zeros. The alternative is rather
+ * painful file initialization. Note that okayvalue(), if OVERFLOW is
+ * defined, knows what value of an offset would cause overflow.
+ */
+#define VACANT ((of_t)0)
+#define BIAS(o) ((o)+1) /* make any valid of_t non-VACANT */
+#define UNBIAS(o) ((o)-1) /* reverse BIAS() effect */
+
+/*
+ * In a Unix implementation, or indeed any in which an of_t is a byte
+ * count, there are a bunch of high bits free in an of_t. There is a
+ * use for them. Checking a possible hit by looking it up in the base
+ * file is relatively expensive, and the cost can be dramatically reduced
+ * by using some of those high bits to tag the value with a few more bits
+ * of the key's hash. This detects most false hits without the overhead of
+ * seek+read+strcmp. We use the top bit to indicate whether the value is
+ * tagged or not, and don't tag a value which is using the tag bits itself.
+ * We're in trouble if the of_t representation wants to use the top bit.
+ * The actual bitmasks and offset come from the configuration stuff,
+ * which permits fiddling with them as necessary, and also suppressing
+ * them completely (by defining the masks to 0). We build pre-shifted
+ * versions of the masks for efficiency.
+ */
+static of_t tagbits; /* pre-shifted tag mask */
+static of_t taghere; /* pre-shifted tag-enable bit */
+static of_t tagboth; /* tagbits|taghere */
+#define HASTAG(o) ((o)&taghere)
+#define TAG(o) ((o)&tagbits)
+#define NOTAG(o) ((o)&~tagboth)
+#define CANTAG(o) (((o)&tagboth) == 0)
+#define MKTAG(v) (((v)<<conf.tagshift)&tagbits)
+
+/*
+ * A new, from-scratch database, not built as a rebuild of an old one,
+ * needs to know table size, casemap algorithm, and tagging. Normally
+ * the user supplies this info, but there have to be defaults.
+ */
+#ifndef DEFSIZE
+#define DEFSIZE 120011 /* 300007 might be better */
+#endif
+#ifdef OLDBNEWS
+#define DEFCASE '0' /* B2.10 -- no mapping */
+#define NOBUFFER /* B News locking is defective */
+#endif
+#ifdef BNEWS
+#define DEFCASE '=' /* B2.11 -- all mapped */
+#define NOBUFFER /* B News locking is defective */
+#endif
+#ifndef DEFCASE /* C News compatibility is the default */
+#define DEFCASE 'C' /* C News -- RFC822 mapping */
+#endif
+#ifndef NOTAGS
+#define TAGENB 0x80 /* tag enable is top bit, tag is next 7 */
+#define TAGMASK 0x7f
+#define TAGSHIFT 24
+#else
+#define TAGENB 0 /* no tags */
+#define TAGMASK 0
+#define TAGSHIFT 0
+#endif
+
+/*
+ * We read configuration info from the .dir file into this structure,
+ * so we can avoid wired-in assumptions for an existing database.
+ *
+ * Among the info is a record of recent peak usages, so that a new table
+ * size can be chosen intelligently when rebuilding. 10 is a good
+ * number of usages to keep, since news displays marked fluctuations
+ * in volume on a 7-day cycle.
+ */
+struct dbzconfig {
+ int olddbz; /* .dir file empty but .pag not? */
+ of_t tsize; /* table size */
+# ifndef NMEMORY
+# define NMEMORY 10 /* # days of use info to remember */
+# endif
+# define NUSEDS (1+NMEMORY)
+ of_t used[NUSEDS]; /* entries used today, yesterday, ... */
+ int valuesize; /* size of table values, == SOF */
+ int bytemap[SOF]; /* byte-order map */
+ char casemap; /* case-mapping algorithm (see cipoint()) */
+ char fieldsep; /* field separator in base file, if any */
+ of_t tagenb; /* unshifted tag-enable bit */
+ of_t tagmask; /* unshifted tag mask */
+ int tagshift; /* shift count for tagmask and tagenb */
+};
+static struct dbzconfig conf;
+static int getconf();
+static long getno();
+static int putconf();
+static void mybytemap();
+static of_t bytemap();
+
+/*
+ * Using mmap() is a more efficent way of keeping the .pag file incore. On
+ * average, it cuts the number of system calls and buffer copies in half.
+ * It also allows one copy to be shared among many processes without
+ * consuming any extra resources.
+ */
+#ifdef MMAP
+#include <sys/mman.h>
+#ifdef MAP_FILE
+#define MAP__ARG (MAP_FILE | MAP_SHARED)
+#else
+#define MAP__ARG (MAP_SHARED)
+#endif
+#ifndef INCORE
+#define INCORE
+#endif
+#endif
+
+/*
+ * For a program that makes many, many references to the database, it
+ * is a large performance win to keep the table in core, if it will fit.
+ * Note that this does hurt robustness in the event of crashes, and
+ * dbmclose() *must* be called to flush the in-core database to disk.
+ * The code is prepared to deal with the possibility that there isn't
+ * enough memory. There *is* an assumption that a size_t is big enough
+ * to hold the size (in bytes) of one table, so dbminit() tries to figure
+ * out whether this is possible first.
+ *
+ * The preferred way to ask for an in-core table is to do dbzincore(1)
+ * before dbminit(). The default is not to do it, although -DINCORE
+ * overrides this for backward compatibility with old dbz.
+ *
+ * We keep only the first table in core. This greatly simplifies the
+ * code, and bounds memory demand. Furthermore, doing this is a large
+ * performance win even in the event of massive overflow.
+ */
+#ifdef INCORE
+static int incore = 1;
+#else
+static int incore = 0;
+#endif
+
+/*
+ * Write to filesystem even if incore? This replaces a single multi-
+ * megabyte write when doing a dbzsync with a multi-byte write each
+ * time an article is added. On most systems, this will give an overall
+ * performance boost.
+ */
+static int writethrough = 0;
+
+/*
+ * Stdio buffer for .pag reads. Buffering more than about 16 does not help
+ * significantly at the densities we try to maintain, and the much larger
+ * buffers that most stdios default to are much more expensive to fill.
+ * With small buffers, stdio is performance-competitive with raw read(),
+ * and it's much more portable.
+ */
+#ifndef NPAGBUF
+#define NPAGBUF 16
+#endif
+#ifndef NOBUFFER
+#ifdef _IOFBF
+static of_t pagbuf[NPAGBUF]; /* only needed if !NOBUFFER && _IOFBF */
+#endif
+#endif
+
+/*
+ * Stdio buffer for base-file reads. Message-IDs (all news ever needs to
+ * read) are essentially never longer than 64 bytes, and the typical stdio
+ * buffer is so much larger that it is much more expensive to fill.
+ */
+#ifndef SHISTBUF
+#define SHISTBUF 64
+#endif
+#ifdef _IOFBF
+static char basebuf[SHISTBUF]; /* only needed if _IOFBF exists */
+#endif
+
+/*
+ * Data structure for recording info about searches.
+ */
+struct searcher {
+ of_t place; /* current location in file */
+ int tabno; /* which table we're in */
+ int run; /* how long we'll stay in this table */
+# ifndef MAXRUN
+# define MAXRUN 100
+# endif
+ long hash; /* the key's hash code (for optimization) */
+ of_t tag; /* tag we are looking for */
+ int seen; /* have we examined current location? */
+ int aborted; /* has i/o error aborted search? */
+};
+static void start();
+#define FRESH ((struct searcher *)NULL)
+static of_t search();
+#define NOTFOUND ((of_t)-1)
+static int okayvalue();
+static int set();
+
+/*
+ * Arguably the searcher struct for a given routine ought to be local to
+ * it, but a fetch() is very often immediately followed by a store(), and
+ * in some circumstances it is a useful performance win to remember where
+ * the fetch() completed. So we use a global struct and remember whether
+ * it is current.
+ */
+static struct searcher srch;
+static struct searcher *prevp; /* &srch or FRESH */
+
+/* byte-ordering stuff */
+static int mybmap[SOF]; /* my byte order (see mybytemap()) */
+static int bytesame; /* is database order same as mine? */
+#define MAPIN(o) ((bytesame) ? (o) : bytemap((o), conf.bytemap, mybmap))
+#define MAPOUT(o) ((bytesame) ? (o) : bytemap((o), mybmap, conf.bytemap))
+
+/*
+ * The double parentheses needed to make this work are ugly, but the
+ * alternative (under most compilers) is to pack around 2K of unused
+ * strings -- there's just no way to get rid of them.
+ */
+#ifdef DBZDEBUG
+static int debug; /* controlled by dbzdebug() */
+#define DEBUG(args) if (debug) { (void) printf args ; } else
+#else
+#define DEBUG(args) ;
+#endif
+
+/* externals used */
+#if 0
+extern char *memcpy();
+extern char *memchr();
+extern char *malloc();
+extern char *calloc();
+extern void free(); /* ANSI C; some old implementations say int */
+#endif /* 0 */
+extern int atoi();
+extern long atol();
+extern void CloseOnExec();
+
+/* misc. forwards */
+static long hash();
+static void crcinit();
+static char *cipoint();
+static char *mapcase();
+static int isprime();
+static FILE *latebase();
+
+/* file-naming stuff */
+static char dir[] = ".dir";
+static char pag[] = ".pag";
+static char *enstring();
+
+/* central data structures */
+static FILE *basef; /* descriptor for base file */
+static char *basefname; /* name for not-yet-opened base file */
+static FILE *dirf; /* descriptor for .dir file */
+static int dirronly; /* dirf open read-only? */
+static FILE *pagf = NULL; /* descriptor for .pag file */
+static of_t pagpos; /* posn in pagf; only search may set != -1 */
+static int pagronly; /* pagf open read-only? */
+static of_t *corepag; /* incore version of .pag file, if any */
+static FILE *bufpagf; /* well-buffered pagf, for incore rewrite */
+static of_t *getcore();
+#ifndef MMAP
+static int putcore();
+#endif
+static int written; /* has a store() been done? */
+
+/*
+ - dbzfresh - set up a new database, no historical info
+ */
+int /* 0 success, -1 failure */
+dbzfresh(name, size, fs, cmap, tagmask)
+char *name; /* base name; .dir and .pag must exist */
+long size; /* table size (0 means default) */
+int fs; /* field-separator character in base file */
+int cmap; /* case-map algorithm (0 means default) */
+of_t tagmask; /* 0 default, 1 no tags */
+{
+ register char *fn;
+ struct dbzconfig c;
+ register of_t m;
+ register FILE *f;
+
+ if (pagf != NULL) {
+ DEBUG(("dbzfresh: database already open\n"));
+ return(-1);
+ }
+ if (size != 0 && size < 2) {
+ DEBUG(("dbzfresh: preposterous size (%ld)\n", size));
+ return(-1);
+ }
+
+ /* get default configuration */
+ if (getconf((FILE *)NULL, (FILE *)NULL, &c) < 0)
+ return(-1); /* "can't happen" */
+
+ /* and mess with it as specified */
+ if (size != 0)
+ c.tsize = size;
+ c.fieldsep = fs;
+ switch (cmap) {
+ case 0:
+ case '0':
+ case 'B': /* 2.10 compat */
+ c.casemap = '0'; /* '\0' nicer, but '0' printable! */
+ break;
+ case '=':
+ case 'b': /* 2.11 compat */
+ c.casemap = '=';
+ break;
+ case 'C':
+ c.casemap = 'C';
+ break;
+ case '?':
+ c.casemap = DEFCASE;
+ break;
+ default:
+ DEBUG(("dbzfresh case map `%c' unknown\n", cmap));
+ return(-1);
+ }
+ switch ((int)tagmask) {
+ case 0: /* default */
+ break;
+ case 1: /* no tags */
+ c.tagshift = 0;
+ c.tagmask = 0;
+ c.tagenb = 0;
+ break;
+ default:
+ m = tagmask;
+ c.tagshift = 0;
+ while (!(m&01)) {
+ m >>= 1;
+ c.tagshift++;
+ }
+ c.tagmask = m;
+ c.tagenb = (m << 1) & ~m;
+ break;
+ }
+
+ /* write it out */
+ fn = enstring(name, dir);
+ if (fn == NULL)
+ return(-1);
+ f = fopen(fn, "w");
+ free((POINTER)fn);
+ if (f == NULL) {
+ DEBUG(("dbzfresh: unable to write config\n"));
+ return(-1);
+ }
+ if (putconf(f, &c) < 0) {
+ (void) fclose(f);
+ return(-1);
+ }
+ if (fclose(f) == EOF) {
+ DEBUG(("dbzfresh: fclose failure\n"));
+ return(-1);
+ }
+
+ /* create/truncate .pag */
+ fn = enstring(name, pag);
+ if (fn == NULL)
+ return(-1);
+ f = fopen(fn, "w");
+ free((POINTER)fn);
+ if (f == NULL) {
+ DEBUG(("dbzfresh: unable to create/truncate .pag file\n"));
+ return(-1);
+ } else
+ (void) fclose(f);
+
+ /* and punt to dbminit for the hard work */
+ return(dbminit(name));
+}
+
+/*
+ - dbzsize - what's a good table size to hold this many entries?
+ */
+long
+dbzsize(contents)
+long contents; /* 0 means what's the default */
+{
+ register long n;
+
+ if (contents <= 0) { /* foulup or default inquiry */
+ DEBUG(("dbzsize: preposterous input (%ld)\n", contents));
+ return(DEFSIZE);
+ }
+ n = (contents/2)*3; /* try to keep table at most 2/3 full */
+ if (!(n&01)) /* make it odd */
+ n++;
+ DEBUG(("dbzsize: tentative size %ld\n", n));
+ while (!isprime(n)) /* and look for a prime */
+ n += 2;
+ DEBUG(("dbzsize: final size %ld\n", n));
+
+ return(n);
+}
+
+/*
+ - isprime - is a number prime?
+ *
+ * This is not a terribly efficient approach.
+ */
+static int /* predicate */
+isprime(x)
+register long x;
+{
+ static int quick[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 0 };
+ register int *ip;
+ register long div;
+ register long stop;
+
+ /* hit the first few primes quickly to eliminate easy ones */
+ /* this incidentally prevents ridiculously small tables */
+ for (ip = quick; (div = *ip) != 0; ip++)
+ if (x%div == 0) {
+ DEBUG(("isprime: quick result on %ld\n", (long)x));
+ return(0);
+ }
+
+ /* approximate square root of x */
+ for (stop = x; x/stop < stop; stop >>= 1)
+ continue;
+ stop <<= 1;
+
+ /* try odd numbers up to stop */
+ for (div = *--ip; div < stop; div += 2)
+ if (x%div == 0)
+ return(0);
+
+ return(1);
+}
+
+/*
+ - dbzagain - set up a new database to be a rebuild of an old one
+ */
+int /* 0 success, -1 failure */
+dbzagain(name, oldname)
+char *name; /* base name; .dir and .pag must exist */
+char *oldname; /* base name; all must exist */
+{
+ register char *fn;
+ struct dbzconfig c;
+ register int i;
+ register long top;
+ register FILE *f;
+ register int newtable;
+ register of_t newsize;
+ struct stat sb;
+ register of_t m;
+
+ if (pagf != NULL) {
+ DEBUG(("dbzagain: database already open\n"));
+ return(-1);
+ }
+
+ /* pick up the old configuration */
+ fn = enstring(oldname, dir);
+ if (fn == NULL)
+ return(-1);
+ f = fopen(fn, "r");
+ free((POINTER)fn);
+ if (f == NULL) {
+ DEBUG(("dbzagain: cannot open old .dir file\n"));
+ return(-1);
+ }
+ i = getconf(f, (FILE *)NULL, &c);
+ (void) fclose(f);
+ if (i < 0) {
+ DEBUG(("dbzagain: getconf failed\n"));
+ return(-1);
+ }
+
+ /* calculate tagging from old file */
+ if (stat(oldname, &sb) != -1) {
+ for (m = 1, i = 0; m < sb.st_size; i++, m <<= 1)
+ continue;
+
+ /* if we had more tags than the default, use the new data */
+ if ((c.tagmask | c.tagenb) && m > (1 << TAGSHIFT)) {
+ c.tagshift = i;
+ c.tagmask = (~(unsigned long)0) >> (i + 1);
+ c.tagenb = (c.tagmask << 1) & ~c.tagmask;
+ }
+ }
+
+ /* tinker with it */
+ top = 0;
+ newtable = 0;
+ for (i = 0; i < NUSEDS; i++) {
+ if (top < c.used[i])
+ top = c.used[i];
+ if (c.used[i] == 0)
+ newtable = 1; /* hasn't got full usage history yet */
+ }
+ if (top == 0) {
+ DEBUG(("dbzagain: old table has no contents!\n"));
+ newtable = 1;
+ }
+ for (i = NUSEDS-1; i > 0; i--)
+ c.used[i] = c.used[i-1];
+ c.used[0] = 0;
+ newsize = dbzsize(top);
+ if (!newtable || newsize > c.tsize) /* don't shrink new table */
+ c.tsize = newsize;
+
+ /* write it out */
+ fn = enstring(name, dir);
+ if (fn == NULL)
+ return(-1);
+ f = fopen(fn, "w");
+ free((POINTER)fn);
+ if (f == NULL) {
+ DEBUG(("dbzagain: unable to write new .dir\n"));
+ return(-1);
+ }
+ i = putconf(f, &c);
+ (void) fclose(f);
+ if (i < 0) {
+ DEBUG(("dbzagain: putconf failed\n"));
+ return(-1);
+ }
+
+ /* create/truncate .pag */
+ fn = enstring(name, pag);
+ if (fn == NULL)
+ return(-1);
+ f = fopen(fn, "w");
+ free((POINTER)fn);
+ if (f == NULL) {
+ DEBUG(("dbzagain: unable to create/truncate .pag file\n"));
+ return(-1);
+ } else
+ (void) fclose(f);
+
+ /* and let dbminit do the work */
+ return(dbminit(name));
+}
+
+/*
+ - dbminit - open a database, creating it (using defaults) if necessary
+ *
+ * We try to leave errno set plausibly, to the extent that underlying
+ * functions permit this, since many people consult it if dbminit() fails.
+ */
+int /* 0 success, -1 failure */
+dbminit(name)
+char *name;
+{
+ register int i;
+ register size_t s;
+ register char *dirfname;
+ register char *pagfname;
+
+ if (pagf != NULL) {
+ DEBUG(("dbminit: dbminit already called once\n"));
+ errno = 0;
+ return(-1);
+ }
+
+ /* open the .dir file */
+ dirfname = enstring(name, dir);
+ if (dirfname == NULL)
+ return(-1);
+ dirf = fopen(dirfname, "r+");
+ if (dirf == NULL) {
+ dirf = fopen(dirfname, "r");
+ dirronly = 1;
+ } else
+ dirronly = 0;
+ free((POINTER)dirfname);
+ if (dirf == NULL) {
+ DEBUG(("dbminit: can't open .dir file\n"));
+ return(-1);
+ }
+ CloseOnExec((int)fileno(dirf), 1);
+
+ /* open the .pag file */
+ pagfname = enstring(name, pag);
+ if (pagfname == NULL) {
+ (void) fclose(dirf);
+ return(-1);
+ }
+ pagf = fopen(pagfname, "r+b");
+ if (pagf == NULL) {
+ pagf = fopen(pagfname, "rb");
+ if (pagf == NULL) {
+ DEBUG(("dbminit: .pag open failed\n"));
+ (void) fclose(dirf);
+ free((POINTER)pagfname);
+ return(-1);
+ }
+ pagronly = 1;
+ } else if (dirronly)
+ pagronly = 1;
+ else
+ pagronly = 0;
+ if (pagf != NULL)
+ CloseOnExec((int)fileno(pagf), 1);
+#ifdef NOBUFFER
+ /*
+ * B News does not do adequate locking on its database accesses.
+ * Why it doesn't get into trouble using dbm is a mystery. In any
+ * case, doing unbuffered i/o does not cure the problem, but does
+ * enormously reduce its incidence.
+ */
+ (void) setbuf(pagf, (char *)NULL);
+#else
+#ifdef _IOFBF
+ (void) setvbuf(pagf, (char *)pagbuf, _IOFBF, sizeof(pagbuf));
+#endif
+#endif
+ pagpos = -1;
+ /* don't free pagfname, need it below */
+
+ /* open the base file */
+ basef = fopen(name, "r");
+ if (basef == NULL) {
+ DEBUG(("dbminit: basefile open failed\n"));
+ basefname = enstring(name, "");
+ if (basefname == NULL) {
+ (void) fclose(pagf);
+ (void) fclose(dirf);
+ free((POINTER)pagfname);
+ pagf = NULL;
+ return(-1);
+ }
+ } else
+ basefname = NULL;
+ if (basef != NULL)
+ CloseOnExec((int)fileno(basef), 1);
+#ifdef _IOFBF
+ if (basef != NULL)
+ (void) setvbuf(basef, basebuf, _IOFBF, sizeof(basebuf));
+#endif
+
+ /* pick up configuration */
+ if (getconf(dirf, pagf, &conf) < 0) {
+ DEBUG(("dbminit: getconf failure\n"));
+ (void) fclose(basef);
+ (void) fclose(pagf);
+ (void) fclose(dirf);
+ free((POINTER)pagfname);
+ pagf = NULL;
+ errno = EDOM; /* kind of a kludge, but very portable */
+ return(-1);
+ }
+ tagbits = conf.tagmask << conf.tagshift;
+ taghere = conf.tagenb << conf.tagshift;
+ tagboth = tagbits | taghere;
+ mybytemap(mybmap);
+ bytesame = 1;
+ for (i = 0; i < SOF; i++)
+ if (mybmap[i] != conf.bytemap[i])
+ bytesame = 0;
+
+ /* get first table into core, if it looks desirable and feasible */
+ s = (size_t)conf.tsize * SOF;
+ if (incore && (of_t)(s/SOF) == conf.tsize) {
+ bufpagf = fopen(pagfname, (pagronly) ? "rb" : "r+b");
+ if (bufpagf != NULL) {
+ corepag = getcore(bufpagf);
+ CloseOnExec((int)fileno(bufpagf), 1);
+ }
+ } else {
+ bufpagf = NULL;
+ corepag = NULL;
+ }
+ free((POINTER)pagfname);
+
+ /* misc. setup */
+ crcinit();
+ written = 0;
+ prevp = FRESH;
+ DEBUG(("dbminit: succeeded\n"));
+ return(0);
+}
+
+/*
+ - enstring - concatenate two strings into a malloced area
+ */
+static char * /* NULL if malloc fails */
+enstring(s1, s2)
+char *s1;
+char *s2;
+{
+ register char *p;
+
+ p = malloc((size_t)strlen(s1) + (size_t)strlen(s2) + 1);
+ if (p != NULL) {
+ (void) strcpy(p, s1);
+ (void) strcat(p, s2);
+ } else {
+ DEBUG(("enstring(%s, %s) out of memory\n", s1, s2));
+ }
+ return(p);
+}
+
+/*
+ - dbmclose - close a database
+ */
+int
+dbmclose()
+{
+ register int ret = 0;
+
+ if (pagf == NULL) {
+ DEBUG(("dbmclose: not opened!\n"));
+ return(-1);
+ }
+
+ if (fclose(pagf) == EOF) {
+ DEBUG(("dbmclose: fclose(pagf) failed\n"));
+ ret = -1;
+ }
+ pagf = basef; /* ensure valid pointer; dbzsync checks it */
+ if (dbzsync() < 0)
+ ret = -1;
+ if (bufpagf != NULL && fclose(bufpagf) == EOF) {
+ DEBUG(("dbmclose: fclose(bufpagf) failed\n"));
+ ret = -1;
+ }
+ if (corepag != NULL)
+#ifdef MMAP
+ if (munmap((caddr_t)corepag, (int)conf.tsize * SOF) == -1) {
+ DEBUG(("dbmclose: munmap failed\n"));
+ ret = -1;
+ }
+#else
+ free((POINTER)corepag);
+#endif
+ corepag = NULL;
+ if (basef) {
+ if (fclose(basef) == EOF) {
+ DEBUG(("dbmclose: fclose(basef) failed\n"));
+ ret = -1;
+ }
+ }
+ if (basefname != NULL)
+ free((POINTER)basefname);
+ basef = NULL;
+ pagf = NULL;
+ if (fclose(dirf) == EOF) {
+ DEBUG(("dbmclose: fclose(dirf) failed\n"));
+ ret = -1;
+ }
+
+ DEBUG(("dbmclose: %s\n", (ret == 0) ? "succeeded" : "failed"));
+ return(ret);
+}
+
+/*
+ - dbzsync - push all in-core data out to disk
+ */
+int
+dbzsync()
+{
+ register int ret = 0;
+
+ if (pagf == NULL) {
+ DEBUG(("dbzsync: not opened!\n"));
+ return(-1);
+ }
+ if (!written)
+ return(0);
+
+#ifndef MMAP
+ if (corepag != NULL && !writethrough) {
+ if (putcore(corepag, bufpagf) < 0) {
+ DEBUG(("dbzsync: putcore failed\n"));
+ ret = -1;
+ }
+ }
+#endif
+ if (!conf.olddbz)
+ if (putconf(dirf, &conf) < 0)
+ ret = -1;
+
+ DEBUG(("dbzsync: %s\n", (ret == 0) ? "succeeded" : "failed"));
+ return(ret);
+}
+
+/*
+ - dbzcancel - cancel writing of in-core data
+ * Mostly for use from child processes.
+ * Note that we don't need to futz around with stdio buffers, because we
+ * always fflush them immediately anyway and so they never have stale data.
+ */
+int
+dbzcancel()
+{
+ if (pagf == NULL) {
+ DEBUG(("dbzcancel: not opened!\n"));
+ return(-1);
+ }
+
+ written = 0;
+ return(0);
+}
+
+/*
+ - dbzfetch - fetch() with case mapping built in
+ */
+datum
+dbzfetch(key)
+datum key;
+{
+ char buffer[DBZMAXKEY + 1];
+ datum mappedkey;
+ register size_t keysize;
+
+ DEBUG(("dbzfetch: (%s)\n", key.dptr));
+
+ /* Key is supposed to be less than DBZMAXKEY */
+ keysize = key.dsize;
+ if (keysize >= DBZMAXKEY) {
+ keysize = DBZMAXKEY;
+ DEBUG(("keysize is %d - truncated to %d\n", key.dsize, DBZMAXKEY));
+ }
+
+ mappedkey.dptr = mapcase(buffer, key.dptr, keysize);
+ buffer[keysize] = '\0'; /* just a debug aid */
+ mappedkey.dsize = keysize;
+
+ return(fetch(mappedkey));
+}
+
+/*
+ - fetch - get an entry from the database
+ *
+ * Disgusting fine point, in the name of backward compatibility: if the
+ * last character of "key" is a NUL, that character is (effectively) not
+ * part of the comparison against the stored keys.
+ */
+datum /* dptr NULL, dsize 0 means failure */
+fetch(key)
+datum key;
+{
+ char buffer[DBZMAXKEY + 1];
+ static of_t key_ptr; /* return value points here */
+ datum output;
+ register size_t keysize;
+ register size_t cmplen;
+ register char *sepp;
+
+ DEBUG(("fetch: (%s)\n", key.dptr));
+ output.dptr = NULL;
+ output.dsize = 0;
+ prevp = FRESH;
+
+ /* Key is supposed to be less than DBZMAXKEY */
+ keysize = key.dsize;
+ if (keysize >= DBZMAXKEY) {
+ keysize = DBZMAXKEY;
+ DEBUG(("keysize is %d - truncated to %d\n", key.dsize, DBZMAXKEY));
+ }
+
+ if (pagf == NULL) {
+ DEBUG(("fetch: database not open!\n"));
+ return(output);
+ } else if (basef == NULL) { /* basef didn't exist yet */
+ basef = latebase();
+ if (basef == NULL)
+ return(output);
+ }
+
+ cmplen = keysize;
+ sepp = &conf.fieldsep;
+ if (key.dptr[keysize-1] == '\0') {
+ cmplen--;
+ sepp = &buffer[keysize-1];
+ }
+ start(&srch, &key, FRESH);
+ while ((key_ptr = search(&srch)) != NOTFOUND) {
+ DEBUG(("got 0x%lx\n", key_ptr));
+
+ /* fetch the key */
+ if (fseek(basef, key_ptr, SEEK_SET) != 0) {
+ DEBUG(("fetch: seek failed\n"));
+ return(output);
+ }
+ if (fread((POINTER)buffer, 1, keysize, basef) != keysize) {
+ DEBUG(("fetch: read failed\n"));
+ return(output);
+ }
+
+ /* try it */
+ buffer[keysize] = '\0'; /* terminated for DEBUG */
+ (void) mapcase(buffer, buffer, keysize);
+ DEBUG(("fetch: buffer (%s) looking for (%s) size = %d\n",
+ buffer, key.dptr, keysize));
+ if (memcmp((POINTER)key.dptr, (POINTER)buffer, cmplen) == 0 &&
+ (*sepp == conf.fieldsep || *sepp == '\0')) {
+ /* we found it */
+ output.dptr = (char *)&key_ptr;
+ output.dsize = SOF;
+ DEBUG(("fetch: successful\n"));
+ return(output);
+ }
+ }
+
+ /* we didn't find it */
+ DEBUG(("fetch: failed\n"));
+ prevp = &srch; /* remember where we stopped */
+ return(output);
+}
+
+/*
+ - latebase - try to open a base file that wasn't there at the start
+ */
+static FILE *
+latebase()
+{
+ register FILE *it;
+
+ if (basefname == NULL) {
+ DEBUG(("latebase: name foulup\n"));
+ return(NULL);
+ }
+ it = fopen(basefname, "r");
+ if (it == NULL) {
+ DEBUG(("latebase: still can't open base\n"));
+ } else {
+ DEBUG(("latebase: late open succeeded\n"));
+ free((POINTER)basefname);
+ basefname = NULL;
+#ifdef _IOFBF
+ (void) setvbuf(it, basebuf, _IOFBF, sizeof(basebuf));
+#endif
+ }
+ if (it != NULL)
+ CloseOnExec((int)fileno(it), 1);
+ return(it);
+}
+
+/*
+ - dbzstore - store() with case mapping built in
+ */
+int
+dbzstore(key, data)
+datum key;
+datum data;
+{
+ char buffer[DBZMAXKEY + 1];
+ datum mappedkey;
+ register size_t keysize;
+
+ DEBUG(("dbzstore: (%s)\n", key.dptr));
+
+ /* Key is supposed to be less than DBZMAXKEY */
+ keysize = key.dsize;
+ if (keysize >= DBZMAXKEY) {
+ DEBUG(("dbzstore: key size too big (%d)\n", key.dsize));
+ return(-1);
+ }
+
+ mappedkey.dptr = mapcase(buffer, key.dptr, keysize);
+ buffer[keysize] = '\0'; /* just a debug aid */
+ mappedkey.dsize = keysize;
+
+ return(store(mappedkey, data));
+}
+
+/*
+ - store - add an entry to the database
+ */
+int /* 0 success, -1 failure */
+store(key, data)
+datum key;
+datum data;
+{
+ of_t value;
+
+ if (pagf == NULL) {
+ DEBUG(("store: database not open!\n"));
+ return(-1);
+ } else if (basef == NULL) { /* basef didn't exist yet */
+ basef = latebase();
+ if (basef == NULL)
+ return(-1);
+ }
+ if (pagronly) {
+ DEBUG(("store: database open read-only\n"));
+ return(-1);
+ }
+ if (data.dsize != SOF) {
+ DEBUG(("store: value size wrong (%d)\n", data.dsize));
+ return(-1);
+ }
+ if (key.dsize >= DBZMAXKEY) {
+ DEBUG(("store: key size too big (%d)\n", key.dsize));
+ return(-1);
+ }
+
+ /* copy the value in to ensure alignment */
+ (void) memcpy((POINTER)&value, (POINTER)data.dptr, SOF);
+ DEBUG(("store: (%s, %ld)\n", key.dptr, (long)value));
+ if (!okayvalue(value)) {
+ DEBUG(("store: reserved bit or overflow in 0x%lx\n", value));
+ return(-1);
+ }
+
+ /* find the place, exploiting previous search if possible */
+ start(&srch, &key, prevp);
+ while (search(&srch) != NOTFOUND)
+ continue;
+
+ prevp = FRESH;
+ conf.used[0]++;
+ DEBUG(("store: used count %ld\n", conf.used[0]));
+ written = 1;
+ return(set(&srch, value));
+}
+
+/*
+ - dbzincore - control attempts to keep .pag file in core
+ */
+int /* old setting */
+dbzincore(value)
+int value;
+{
+ register int old = incore;
+
+#ifndef MMAP
+ incore = value;
+#endif
+ return(old);
+}
+
+/*
+ - dbzwritethrough - write through the pag file in core
+ */
+int /* old setting */
+dbzwritethrough(value)
+int value;
+{
+ register int old = writethrough;
+
+ writethrough = value;
+ return(old);
+}
+
+/*
+ - dbztagmask - calculate the correct tagmask for the given base file size
+ */
+long
+dbztagmask(size)
+register long size;
+{
+ register long m;
+ register long tagmask;
+ register int i;
+
+ if (size <= 0)
+ return(0L); /* silly size */
+
+ for (m = 1, i = 0; m < size; i++, m <<= 1)
+ continue;
+
+ if (m < (1 << TAGSHIFT))
+ return(0L); /* not worth tagging */
+
+ tagmask = (~(unsigned long)0) >> (i + 1);
+ tagmask = tagmask << i;
+ return(tagmask);
+}
+
+/*
+ - getconf - get configuration from .dir file
+ */
+static int /* 0 success, -1 failure */
+getconf(df, pf, cp)
+register FILE *df; /* NULL means just give me the default */
+register FILE *pf; /* NULL means don't care about .pag */
+register struct dbzconfig *cp;
+{
+ register int c;
+ register int i;
+ int err = 0;
+
+ c = (df != NULL) ? getc(df) : EOF;
+ if (c == EOF) { /* empty file, no configuration known */
+ cp->olddbz = 0;
+ if (df != NULL && pf != NULL && getc(pf) != EOF)
+ cp->olddbz = 1;
+ cp->tsize = DEFSIZE;
+ cp->fieldsep = '\t';
+ for (i = 0; i < NUSEDS; i++)
+ cp->used[i] = 0;
+ cp->valuesize = SOF;
+ mybytemap(cp->bytemap);
+ cp->casemap = DEFCASE;
+ cp->tagenb = TAGENB;
+ cp->tagmask = TAGMASK;
+ cp->tagshift = TAGSHIFT;
+ DEBUG(("getconf: defaults (%ld, %c, (0x%lx/0x%lx<<%d))\n",
+ cp->tsize, cp->casemap, cp->tagenb,
+ cp->tagmask, cp->tagshift));
+ return(0);
+ }
+ (void) ungetc(c, df);
+
+ /* first line, the vital stuff */
+ if (getc(df) != 'd' || getc(df) != 'b' || getc(df) != 'z')
+ err = -1;
+ if (getno(df, &err) != dbzversion)
+ err = -1;
+ cp->tsize = getno(df, &err);
+ cp->fieldsep = (int)getno(df, &err);
+ while ((c = getc(df)) == ' ')
+ continue;
+ cp->casemap = c;
+ cp->tagenb = getno(df, &err);
+ cp->tagmask = getno(df, &err);
+ cp->tagshift = getno(df, &err);
+ cp->valuesize = getno(df, &err);
+ if (cp->valuesize != SOF) {
+ DEBUG(("getconf: wrong of_t size (%d)\n", cp->valuesize));
+ err = -1;
+ cp->valuesize = SOF; /* to protect the loops below */
+ }
+ for (i = 0; i < cp->valuesize; i++)
+ cp->bytemap[i] = getno(df, &err);
+ if (getc(df) != '\n')
+ err = -1;
+#ifdef DBZDEBUG
+ DEBUG(("size %ld, sep %d, cmap %c, tags 0x%lx/0x%lx<<%d, ", cp->tsize,
+ cp->fieldsep, cp->casemap, cp->tagenb, cp->tagmask,
+ cp->tagshift));
+ DEBUG(("bytemap (%d)", cp->valuesize));
+ for (i = 0; i < cp->valuesize; i++) {
+ DEBUG((" %d", cp->bytemap[i]));
+ }
+ DEBUG(("\n"));
+#endif
+
+ /* second line, the usages */
+ for (i = 0; i < NUSEDS; i++)
+ cp->used[i] = getno(df, &err);
+ if (getc(df) != '\n')
+ err = -1;
+ DEBUG(("used %ld %ld %ld...\n", cp->used[0], cp->used[1], cp->used[2]));
+
+ if (err < 0) {
+ DEBUG(("getconf error\n"));
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ - getno - get a long
+ */
+static long
+getno(f, ep)
+FILE *f;
+int *ep;
+{
+ register char *p;
+# define MAXN 50
+ char getbuf[MAXN];
+ register int c;
+
+ while ((c = getc(f)) == ' ')
+ continue;
+ if (c == EOF || c == '\n') {
+ DEBUG(("getno: missing number\n"));
+ *ep = -1;
+ return(0);
+ }
+ p = getbuf;
+ *p++ = c;
+ while ((c = getc(f)) != EOF && c != '\n' && c != ' ')
+ if (p < &getbuf[MAXN-1])
+ *p++ = c;
+ if (c == EOF) {
+ DEBUG(("getno: EOF\n"));
+ *ep = -1;
+ } else
+ (void) ungetc(c, f);
+ *p = '\0';
+
+ if (strspn(getbuf, "-1234567890") != strlen(getbuf)) {
+ DEBUG(("getno: `%s' non-numeric\n", getbuf));
+ *ep = -1;
+ }
+ return(atol(getbuf));
+}
+
+/*
+ - putconf - write configuration to .dir file
+ */
+static int /* 0 success, -1 failure */
+putconf(f, cp)
+register FILE *f;
+register struct dbzconfig *cp;
+{
+ register int i;
+ register int ret = 0;
+
+ if (fseek(f, (of_t)0, SEEK_SET) != 0) {
+ DEBUG(("fseek failure in putconf\n"));
+ ret = -1;
+ }
+ (void) fprintf(f, "dbz %d %ld %d %c %ld %ld %d %d", dbzversion, cp->tsize,
+ cp->fieldsep, cp->casemap, cp->tagenb,
+ cp->tagmask, cp->tagshift, cp->valuesize);
+ for (i = 0; i < cp->valuesize; i++)
+ (void) fprintf(f, " %d", cp->bytemap[i]);
+ (void) fprintf(f, "\n");
+ for (i = 0; i < NUSEDS; i++)
+ (void) fprintf(f, "%ld%c", cp->used[i], (i < NUSEDS-1) ? ' ' : '\n');
+
+ (void) fflush(f);
+ if (ferror(f))
+ ret = -1;
+
+ DEBUG(("putconf status %d\n", ret));
+ return(ret);
+}
+
+/*
+ - getcore - try to set up an in-core copy of .pag file
+ */
+static of_t * /* pointer to copy, or NULL */
+getcore(f)
+FILE *f;
+{
+ register of_t *p;
+ register size_t i;
+ register size_t nread;
+ register char *it;
+#ifdef MMAP
+ struct stat st;
+
+ if (fstat(fileno(f), &st) == -1) {
+ DEBUG(("getcore: fstat failed\n"));
+ return(NULL);
+ }
+ if (((size_t)conf.tsize * SOF) > st.st_size) {
+ /* file too small; extend it */
+ if (ftruncate((int)fileno(f), conf.tsize * SOF) == -1) {
+ DEBUG(("getcore: ftruncate failed\n"));
+ return(NULL);
+ }
+ }
+ it = mmap((caddr_t)0, (size_t)conf.tsize * SOF,
+ pagronly ? PROT_READ : PROT_WRITE | PROT_READ, MAP__ARG,
+ (int)fileno(f), (off_t)0);
+ if (it == (char *)-1) {
+ DEBUG(("getcore: mmap failed\n"));
+ return(NULL);
+ }
+#ifdef MC_ADVISE
+ /* not present in all versions of mmap() */
+ madvise(it, (size_t)conf.tsize * SOF, MADV_RANDOM);
+#endif
+#else
+ it = malloc((size_t)conf.tsize * SOF);
+ if (it == NULL) {
+ DEBUG(("getcore: malloc failed\n"));
+ return(NULL);
+ }
+
+ nread = fread((POINTER)it, SOF, (size_t)conf.tsize, f);
+ if (ferror(f)) {
+ DEBUG(("getcore: read failed\n"));
+ free((POINTER)it);
+ return(NULL);
+ }
+
+ /* NOSTRICT *//* Possible pointer alignment problem */
+ p = (of_t *)it + nread;
+ i = (size_t)conf.tsize - nread;
+ while (i-- > 0)
+ *p++ = VACANT;
+#endif
+ /* NOSTRICT *//* Possible pointer alignment problem */
+ return((of_t *)it);
+}
+
+#ifndef MMAP
+/*
+ - putcore - try to rewrite an in-core table
+ */
+static int /* 0 okay, -1 fail */
+putcore(tab, f)
+of_t *tab;
+FILE *f;
+{
+ if (fseek(f, (of_t)0, SEEK_SET) != 0) {
+ DEBUG(("fseek failure in putcore\n"));
+ return(-1);
+ }
+ (void) fwrite((POINTER)tab, SOF, (size_t)conf.tsize, f);
+ (void) fflush(f);
+ return((ferror(f)) ? -1 : 0);
+}
+#endif
+
+/*
+ - start - set up to start or restart a search
+ */
+static void
+start(sp, kp, osp)
+register struct searcher *sp;
+register datum *kp;
+register struct searcher *osp; /* may be FRESH, i.e. NULL */
+{
+ register long h;
+
+ h = hash(kp->dptr, kp->dsize);
+ if (osp != FRESH && osp->hash == h) {
+ if (sp != osp)
+ *sp = *osp;
+ DEBUG(("search restarted\n"));
+ } else {
+ sp->hash = h;
+ sp->tag = MKTAG(h / conf.tsize);
+ DEBUG(("tag 0x%lx\n", sp->tag));
+ sp->place = h % conf.tsize;
+ sp->tabno = 0;
+ sp->run = (conf.olddbz) ? conf.tsize : MAXRUN;
+ sp->aborted = 0;
+ }
+ sp->seen = 0;
+}
+
+/*
+ - search - conduct part of a search
+ */
+static of_t /* NOTFOUND if we hit VACANT or error */
+search(sp)
+register struct searcher *sp;
+{
+ register of_t dest;
+ register of_t value;
+ of_t val; /* buffer for value (can't fread register) */
+ register of_t place;
+
+ if (sp->aborted)
+ return(NOTFOUND);
+
+ for (;;) {
+ /* determine location to be examined */
+ place = sp->place;
+ if (sp->seen) {
+ /* go to next location */
+ if (--sp->run <= 0) {
+ sp->tabno++;
+ sp->run = MAXRUN;
+ }
+ place = (place+1)%conf.tsize + sp->tabno*conf.tsize;
+ sp->place = place;
+ } else
+ sp->seen = 1; /* now looking at current location */
+ DEBUG(("search @ %ld\n", place));
+
+ /* get the tagged value */
+ if (corepag != NULL && place < conf.tsize) {
+ DEBUG(("search: in core\n"));
+ value = MAPIN(corepag[place]);
+ } else {
+ /* seek, if necessary */
+ dest = place * SOF;
+ if (pagpos != dest) {
+ if (fseek(pagf, dest, SEEK_SET) != 0) {
+ DEBUG(("search: seek failed\n"));
+ pagpos = -1;
+ sp->aborted = 1;
+ return(NOTFOUND);
+ }
+ pagpos = dest;
+ }
+
+ /* read it */
+ if (fread((POINTER)&val, sizeof(val), 1, pagf) == 1)
+ value = MAPIN(val);
+ else if (ferror(pagf)) {
+ DEBUG(("search: read failed\n"));
+ pagpos = -1;
+ sp->aborted = 1;
+ return(NOTFOUND);
+ } else
+ value = VACANT;
+
+ /* and finish up */
+ pagpos += sizeof(val);
+ }
+
+ /* vacant slot is always cause to return */
+ if (value == VACANT) {
+ DEBUG(("search: empty slot\n"));
+ return(NOTFOUND);
+ };
+
+ /* check the tag */
+ value = UNBIAS(value);
+ DEBUG(("got 0x%lx\n", value));
+ if (!HASTAG(value)) {
+ DEBUG(("tagless\n"));
+ return(value);
+ } else if (TAG(value) == sp->tag) {
+ DEBUG(("match\n"));
+ return(NOTAG(value));
+ } else {
+ DEBUG(("mismatch 0x%lx\n", TAG(value)));
+ }
+ }
+ /* NOTREACHED */
+}
+
+/*
+ - okayvalue - check that a value can be stored
+ */
+static int /* predicate */
+okayvalue(value)
+of_t value;
+{
+ if (HASTAG(value))
+ return(0);
+#ifdef OVERFLOW
+ if (value == LONG_MAX) /* BIAS() and UNBIAS() will overflow */
+ return(0);
+#endif
+ return(1);
+}
+
+/*
+ - set - store a value into a location previously found by search
+ */
+static int /* 0 success, -1 failure */
+set(sp, value)
+register struct searcher *sp;
+of_t value;
+{
+ register of_t place = sp->place;
+ register of_t v = value;
+
+ if (sp->aborted)
+ return(-1);
+
+ if (CANTAG(v) && !conf.olddbz) {
+ v |= sp->tag | taghere;
+ if (v != UNBIAS(VACANT)) /* BIAS(v) won't look VACANT */
+#ifdef OVERFLOW
+ if (v != LONG_MAX) /* and it won't overflow */
+#endif
+ value = v;
+ }
+ DEBUG(("tagged value is 0x%lx\n", value));
+ value = BIAS(value);
+ value = MAPOUT(value);
+
+ /* If we have the index file in memory, use it */
+ if (corepag != NULL && place < conf.tsize) {
+ corepag[place] = value;
+ DEBUG(("set: incore\n"));
+#ifdef MMAP
+ return(0);
+#else
+ if (!writethrough)
+ return(0);
+#endif
+ }
+
+ /* seek to spot */
+ pagpos = -1; /* invalidate position memory */
+ if (fseek(pagf, (of_t)(place * SOF), SEEK_SET) != 0) {
+ DEBUG(("set: seek failed\n"));
+ sp->aborted = 1;
+ return(-1);
+ }
+
+ /* write in data */
+ if (fwrite((POINTER)&value, SOF, 1, pagf) != 1) {
+ DEBUG(("set: write failed\n"));
+ sp->aborted = 1;
+ return(-1);
+ }
+ /* fflush improves robustness, and buffer re-use is rare anyway */
+ if (fflush(pagf) == EOF) {
+ DEBUG(("set: fflush failed\n"));
+ sp->aborted = 1;
+ return(-1);
+ }
+
+ DEBUG(("set: succeeded\n"));
+ return(0);
+}
+
+/*
+ - mybytemap - determine this machine's byte map
+ *
+ * A byte map is an array of ints, sizeof(of_t) of them. The 0th int
+ * is the byte number of the high-order byte in my of_t, and so forth.
+ */
+static void
+mybytemap(map)
+int map[]; /* -> int[SOF] */
+{
+ union {
+ of_t o;
+ char c[SOF];
+ } u;
+ register int *mp = &map[SOF];
+ register int ntodo;
+ register int i;
+
+ u.o = 1;
+ for (ntodo = (int)SOF; ntodo > 0; ntodo--) {
+ for (i = 0; i < SOF; i++)
+ /* SUPPRESS 112 *//* Retrieving char where long is stored */
+ if (u.c[i] != 0)
+ break;
+ if (i == SOF) {
+ /* trouble -- set it to *something* consistent */
+ DEBUG(("mybytemap: nonexistent byte %d!!!\n", ntodo));
+ for (i = 0; i < SOF; i++)
+ map[i] = i;
+ return;
+ }
+ DEBUG(("mybytemap: byte %d\n", i));
+ *--mp = i;
+ /* SUPPRESS 112 *//* Retrieving char where long is stored */
+ while (u.c[i] != 0)
+ u.o <<= 1;
+ }
+}
+
+/*
+ - bytemap - transform an of_t from byte ordering map1 to map2
+ */
+static of_t /* transformed result */
+bytemap(ino, map1, map2)
+of_t ino;
+int *map1;
+int *map2;
+{
+ union oc {
+ of_t o;
+ char c[SOF];
+ };
+ union oc in;
+ union oc out;
+ register int i;
+
+ in.o = ino;
+ for (i = 0; i < SOF; i++)
+ out.c[map2[i]] = in.c[map1[i]];
+ return(out.o);
+}
+
+/*
+ * This is a simplified version of the pathalias hashing function.
+ * Thanks to Steve Belovin and Peter Honeyman
+ *
+ * hash a string into a long int. 31 bit crc (from andrew appel).
+ * the crc table is computed at run time by crcinit() -- we could
+ * precompute, but it takes 1 clock tick on a 750.
+ *
+ * This fast table calculation works only if POLY is a prime polynomial
+ * in the field of integers modulo 2. Since the coefficients of a
+ * 32-bit polynomial won't fit in a 32-bit word, the high-order bit is
+ * implicit. IT MUST ALSO BE THE CASE that the coefficients of orders
+ * 31 down to 25 are zero. Happily, we have candidates, from
+ * E. J. Watson, "Primitive Polynomials (Mod 2)", Math. Comp. 16 (1962):
+ * x^32 + x^7 + x^5 + x^3 + x^2 + x^1 + x^0
+ * x^31 + x^3 + x^0
+ *
+ * We reverse the bits to get:
+ * 111101010000000000000000000000001 but drop the last 1
+ * f 5 0 0 0 0 0 0
+ * 010010000000000000000000000000001 ditto, for 31-bit crc
+ * 4 8 0 0 0 0 0 0
+ */
+
+#define POLY 0x48000000L /* 31-bit polynomial (avoids sign problems) */
+
+static long CrcTable[128];
+
+/*
+ - crcinit - initialize tables for hash function
+ */
+static void
+crcinit()
+{
+ register int i, j;
+ register long sum;
+
+ for (i = 0; i < 128; ++i) {
+ sum = 0L;
+ for (j = 7 - 1; j >= 0; --j)
+ if (i & (1 << j))
+ sum ^= POLY >> j;
+ CrcTable[i] = sum;
+ }
+ DEBUG(("crcinit: done\n"));
+}
+
+/*
+ - hash - Honeyman's nice hashing function
+ */
+static long
+hash(name, size)
+register char *name;
+register int size;
+{
+ register long sum = 0L;
+
+ while (size--) {
+ sum = (sum >> 7) ^ CrcTable[(sum ^ (*name++)) & 0x7f];
+ }
+ DEBUG(("hash: returns (%ld)\n", sum));
+ return(sum);
+}
+
+/*
+ * case-mapping stuff
+ *
+ * Borrowed from C News, by permission of the authors. Somewhat modified.
+ *
+ * We exploit the fact that we are dealing only with headers here, and
+ * headers are limited to the ASCII characters by RFC822. It is barely
+ * possible that we might be dealing with a translation into another
+ * character set, but in particular it's very unlikely for a header
+ * character to be outside -128..255.
+ *
+ * Life would be a whole lot simpler if tolower() could safely and portably
+ * be applied to any char.
+ */
+
+#define OFFSET 128 /* avoid trouble with negative chars */
+
+/* must call casencmp before invoking TOLOW... */
+#define TOLOW(c) (cmap[(c)+OFFSET])
+
+/* ...but the use of it in CISTREQN is safe without the preliminary call (!) */
+/* CISTREQN is an optimised case-insensitive strncmp(a,b,n)==0; n > 0 */
+#define CISTREQN(a, b, n) \
+ (TOLOW((a)[0]) == TOLOW((b)[0]) && casencmp(a, b, n) == 0)
+
+#define MAPSIZE (256+OFFSET)
+static char cmap[MAPSIZE]; /* relies on init to '\0' */
+static int mprimed = 0; /* has cmap been set up? */
+
+/*
+ - mapprime - set up case-mapping stuff
+ */
+static void
+mapprime()
+{
+ register char *lp;
+ register char *up;
+ register int c;
+ register int i;
+ static char lower[] = "abcdefghijklmnopqrstuvwxyz";
+ static char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ for (lp = lower, up = upper; *lp != '\0'; lp++, up++) {
+ c = *lp;
+ cmap[c+OFFSET] = c;
+ cmap[*up+OFFSET] = c;
+ }
+ for (i = 0; i < MAPSIZE; i++)
+ if (cmap[i] == '\0')
+ cmap[i] = (char)(i-OFFSET);
+ mprimed = 1;
+}
+
+/*
+ - casencmp - case-independent strncmp
+ */
+static int /* < == > 0 */
+casencmp(s1, s2, len)
+char *s1;
+char *s2;
+int len;
+{
+ register char *p1;
+ register char *p2;
+ register int n;
+
+ if (!mprimed)
+ mapprime();
+
+ p1 = s1;
+ p2 = s2;
+ n = len;
+ while (--n >= 0 && *p1 != '\0' && TOLOW(*p1) == TOLOW(*p2)) {
+ p1++;
+ p2++;
+ }
+ if (n < 0)
+ return(0);
+
+ /*
+ * The following case analysis is necessary so that characters
+ * which look negative collate low against normal characters but
+ * high against the end-of-string NUL.
+ */
+ if (*p1 == '\0' && *p2 == '\0')
+ return(0);
+ else if (*p1 == '\0')
+ return(-1);
+ else if (*p2 == '\0')
+ return(1);
+ else
+ return(TOLOW(*p1) - TOLOW(*p2));
+}
+
+/*
+ - mapcase - do case-mapped copy
+ */
+static char * /* returns src or dst */
+mapcase(dst, src, siz)
+char *dst; /* destination, used only if mapping needed */
+char *src; /* source; src == dst is legal */
+size_t siz;
+{
+ register char *s;
+ register char *d;
+ register char *c; /* case break */
+ register char *e; /* end of source */
+
+
+ c = cipoint(src, siz);
+ if (c == NULL)
+ return(src);
+
+ if (!mprimed)
+ mapprime();
+ s = src;
+ e = s + siz;
+ d = dst;
+
+ while (s < c)
+ *d++ = *s++;
+ while (s < e)
+ *d++ = TOLOW(*s++);
+
+ return(dst);
+}
+
+/*
+ - cipoint - where in this message-ID does it become case-insensitive?
+ *
+ * The RFC822 code is not quite complete. Absolute, total, full RFC822
+ * compliance requires a horrible parsing job, because of the arcane
+ * quoting conventions -- abc"def"ghi is not equivalent to abc"DEF"ghi,
+ * for example. There are three or four things that might occur in the
+ * domain part of a message-id that are case-sensitive. They don't seem
+ * to ever occur in real news, thank Cthulhu. (What? You were expecting
+ * a merciful and forgiving deity to be invoked in connection with RFC822?
+ * Forget it; none of them would come near it.)
+ */
+static char * /* pointer into s, or NULL for "nowhere" */
+cipoint(s, siz)
+char *s;
+size_t siz;
+{
+ register char *p;
+ static char post[] = "postmaster";
+ static int plen = sizeof(post)-1;
+
+ switch (conf.casemap) {
+ case '0': /* unmapped, sensible */
+ return(NULL);
+ case 'C': /* C News, RFC 822 conformant (approx.) */
+ p = memchr((POINTER)s, '@', siz);
+ if (p == NULL) /* no local/domain split */
+ return(NULL); /* assume all local */
+ if (p - (s+1) == plen && CISTREQN(s+1, post, plen)) {
+ /* crazy -- "postmaster" is case-insensitive */
+ return(s);
+ }
+ return(p);
+ case '=': /* 2.11, neither sensible nor conformant */
+ return(s); /* all case-insensitive */
+ }
+
+ DEBUG(("cipoint: unknown case mapping `%c'\n", conf.casemap));
+ return(NULL); /* just leave it alone */
+}
+
+/*
+ - dbzdebug - control dbz debugging at run time
+ */
+#ifdef DBZDEBUG
+int /* old value */
+dbzdebug(value)
+int value;
+{
+ register int old = debug;
+
+ debug = value;
+ return(old);
+}
+#endif
diff --git a/innbbsd/dbz.h b/innbbsd/dbz.h
new file mode 100644
index 00000000..3d7e8ed7
--- /dev/null
+++ b/innbbsd/dbz.h
@@ -0,0 +1,32 @@
+/* for dbm and dbz */
+typedef struct {
+ char *dptr;
+ int dsize;
+} datum;
+
+/* standard dbm functions */
+extern int dbminit();
+extern datum fetch();
+extern int store();
+extern int delete(); /* not in dbz */
+extern datum firstkey(); /* not in dbz */
+extern datum nextkey(); /* not in dbz */
+extern int dbmclose(); /* in dbz, but not in old dbm */
+
+/* new stuff for dbz */
+extern int dbzfresh();
+extern int dbzagain();
+extern datum dbzfetch();
+extern int dbzstore();
+extern int dbzsync();
+extern long dbzsize();
+extern int dbzincore();
+extern int dbzcancel();
+extern int dbzdebug();
+
+/*
+ * In principle we could handle unlimited-length keys by operating a chunk
+ * at a time, but it's not worth it in practice. Setting a nice large
+ * bound on them simplifies the code and doesn't hurt anything.
+ */
+#define DBZMAXKEY 255
diff --git a/innbbsd/dbztool.c b/innbbsd/dbztool.c
new file mode 100644
index 00000000..5318721b
--- /dev/null
+++ b/innbbsd/dbztool.c
@@ -0,0 +1,88 @@
+#include <sys/file.h>
+#include "his.h"
+
+#define DEBUG 1
+#undef DEBUG
+
+static datum content, inputkey, inputvalue;
+static char dboutput[1025];
+static char dbinput[1025];
+static char valueinput[100];
+
+enum {SUBJECT, FROM, NAME};
+char *DBfetch(key)
+char *key;
+{
+ int i;
+ char *tail, *ptr;
+ if (key == NULL) return NULL;
+ sprintf(dbinput,"%.510s",key);
+ inputkey.dptr = dbinput;
+ inputkey.dsize = strlen(dbinput);
+ content.dptr = dboutput;
+ ptr = (char*)HISfilesfor(&inputkey,&content);
+ if (ptr == NULL) {
+ return NULL;
+ }
+ return ptr;
+}
+
+DBstore(key,paths)
+char *key;
+char *paths;
+{
+ int i;
+ char *tail;
+ time_t now;
+ time(&now);
+ if (key == NULL) return -1;
+ sprintf(dbinput,"%.510s",key);
+ inputkey.dptr = dbinput;
+ inputkey.dsize = strlen(dbinput);
+ if (HISwrite(&inputkey, now, paths ) == FALSE) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+int storeDB(mid,paths)
+char *mid;
+char *paths;
+{
+ char *key,*ptr;
+ int rel;
+ ptr = DBfetch(mid);
+ if (ptr != NULL) {
+ return 0;
+ } else {
+ return DBstore(mid , paths);
+ }
+}
+
+my_mkdir (idir,mode)
+char *idir;
+int mode;
+{
+ char buffer[LEN];
+ char *ptr, *dir = buffer;
+ struct stat st;
+ strncpy(dir, idir, LEN - 1);
+ for (;dir!=NULL && *dir;) {
+ ptr = (char*)strchr(dir,'/');
+ if (ptr != NULL) {
+ *ptr = '\0';
+ }
+ if (stat(dir,&st) != 0) {
+ if (mkdir(dir,mode) != 0 )
+ return -1;
+ }
+ chdir(dir);
+ if (ptr != NULL)
+ dir = ptr +1;
+ else
+ dir = ptr;
+ }
+ return 0;
+}
+
diff --git a/innbbsd/echobbslib.c b/innbbsd/echobbslib.c
new file mode 100644
index 00000000..84d77de6
--- /dev/null
+++ b/innbbsd/echobbslib.c
@@ -0,0 +1,713 @@
+#if defined( LINUX )
+# include "innbbsconf.h"
+# include "bbslib.h"
+# include <varargs.h>
+#else
+# include <varargs.h>
+# include "innbbsconf.h"
+# include "bbslib.h"
+#endif
+
+char INNBBSCONF[MAXPATHLEN];
+char INNDHOME[MAXPATHLEN];
+char HISTORY[MAXPATHLEN];
+char LOGFILE[MAXPATHLEN];
+char MYBBSID[MAXPATHLEN];
+char ECHOMAIL[MAXPATHLEN];
+char BBSFEEDS[MAXPATHLEN];
+char LOCALDAEMON[MAXPATHLEN];
+
+int His_Maint_Min= HIS_MAINT_MIN;
+int His_Maint_Hour= HIS_MAINT_HOUR;
+int Expiredays = EXPIREDAYS;
+
+nodelist_t *NODELIST=NULL, **NODELIST_BYNODE=NULL;
+newsfeeds_t *NEWSFEEDS=NULL, **NEWSFEEDS_BYBOARD=NULL;
+static char *NODELIST_BUF, *NEWSFEEDS_BUF;
+int NFCOUNT, NLCOUNT;
+int LOCALNODELIST=0, NONENEWSFEEDS=0;
+
+#ifndef _PATH_BBSHOME
+# define _PATH_BBSHOME "/u/staff/bbsroot/csie_util/bntpd/home"
+#endif
+
+static FILE *bbslogfp;
+
+static int
+verboseFlag=0;
+
+static char*
+verboseFilename=NULL;
+static char verbosename[MAXPATHLEN];
+
+verboseon(filename)
+char *filename;
+{
+ verboseFlag = 1;
+ if ( filename != NULL ) {
+ if (strchr(filename,'/') == NULL) {
+ sprintf(verbosename,"%s/innd/%s",BBSHOME,filename);
+ filename = verbosename;
+ }
+ }
+ verboseFilename = filename;
+}
+verboseoff()
+{
+ verboseFlag = 0;
+}
+
+setverboseon()
+{
+ verboseFlag = 1;
+}
+
+isverboselog()
+{
+ return verboseFlag;
+}
+
+setverboseoff()
+{
+ verboseoff();
+ if (bbslogfp != NULL) {
+ fclose(bbslogfp);
+ bbslogfp = NULL;
+ }
+}
+
+verboselog(va_alist)
+va_dcl
+{
+ va_list ap;
+ register char* fmt;
+ char datebuf[40];
+ time_t now;
+
+ if (verboseFlag == 0) return;
+
+ va_start(ap);
+
+ time(&now);
+ strftime(datebuf, sizeof(datebuf), "%b %d %X ", localtime(&now));
+
+ if (bbslogfp == NULL) {
+ if (verboseFilename != NULL)
+ bbslogfp = fopen(verboseFilename, "a");
+ else
+ bbslogfp = fdopen(1, "a");
+ }
+ if (bbslogfp == NULL) { va_end(ap); return; }
+ fmt = va_arg(ap, char *) ;
+ fprintf(bbslogfp,"%s[%d] ",datebuf, getpid());
+ vfprintf(bbslogfp, fmt, ap);
+ fflush(bbslogfp);
+ va_end(ap);
+}
+
+#ifdef PalmBBS
+xbbslog(va_alist)
+#else
+bbslog(va_alist)
+#endif
+va_dcl
+{
+ va_list ap;
+ register char* fmt;
+ char datebuf[40];
+ time_t now;
+
+ va_start(ap);
+
+ time(&now);
+ strftime(datebuf, sizeof(datebuf), "%b %d %X ", localtime(&now));
+
+ if (bbslogfp == NULL) {
+ bbslogfp = fopen(LOGFILE, "a");
+ }
+ if (bbslogfp == NULL) { va_end(ap); return; }
+ fmt = va_arg(ap, char *) ;
+ fprintf(bbslogfp,"%s[%d] ",datebuf,getpid());
+ vfprintf(bbslogfp, fmt, ap);
+ fflush(bbslogfp);
+ va_end(ap);
+}
+
+initial_bbs(outgoing)
+char *outgoing;
+{
+ FILE* FN;
+ struct stat st;
+ int fd, i;
+ char *bbsnameptr=NULL;
+
+/* reopen bbslog */
+ if (bbslogfp != NULL) {
+ fclose(bbslogfp);
+ bbslogfp = NULL;
+ }
+
+#ifdef WITH_ECHOMAIL
+ init_echomailfp();
+ init_bbsfeedsfp();
+#endif
+
+ LOCALNODELIST=0, NONENEWSFEEDS =0;
+ sprintf(INNDHOME,"%s/innd",BBSHOME);
+ sprintf(HISTORY, "%s/history",INNDHOME);
+ sprintf(LOGFILE, "%s/bbslog",INNDHOME);
+ sprintf(ECHOMAIL,"%s/echomail.log",BBSHOME);
+ sprintf(LOCALDAEMON,"%s/.innbbsd",INNDHOME);
+ sprintf(INNBBSCONF,"%s/innbbs.conf",INNDHOME);
+ sprintf(BBSFEEDS,"%s/bbsfeeds.log",INNDHOME);
+
+ if (isfile(INNBBSCONF)) {
+ FILE *conf;
+ char buffer[MAXPATHLEN];
+ conf = fopen(INNBBSCONF,"r");
+ if (conf != NULL) {
+ while (fgets( buffer, sizeof buffer, conf) != NULL) {
+ char *ptr, *front=NULL, *value=NULL, *value2=NULL, *value3=NULL;
+ if ( buffer[0] == '#' || buffer[0] == '\n') continue;
+ for ( front = buffer; *front && isspace(*front); front++);
+ for ( ptr = front; *ptr && !isspace(*ptr) ; ptr++) ;
+ if (*ptr == '\0') continue;
+ *ptr++ = '\0';
+ for ( ; *ptr && isspace(*ptr) ; ptr++) ;
+ if (*ptr == '\0') continue;
+ value = ptr++;
+ for ( ; *ptr && !isspace(*ptr) ; ptr++) ;
+ if (*ptr) {
+ *ptr++ = '\0';
+ for ( ; *ptr && isspace(*ptr) ; ptr++) ;
+ value2 = ptr++;
+ for ( ; *ptr && !isspace(*ptr) ; ptr++) ;
+ if (*ptr) {
+ *ptr++ = '\0';
+ for ( ; *ptr && isspace(*ptr) ; ptr++) ;
+ value3 = ptr++;
+ for ( ; *ptr && !isspace(*ptr) ; ptr++) ;
+ if (*ptr) {
+ *ptr++ = '\0';
+ }
+ }
+ }
+ if ( strcasecmp(front,"expiredays") == 0) {
+ Expiredays = atoi(value);
+ if (Expiredays < 0) {
+ Expiredays = EXPIREDAYS;
+ }
+ } else if ( strcasecmp(front,"expiretime") == 0) {
+ ptr = strchr(value,':');
+ if (ptr == NULL) {
+ fprintf(stderr, "Syntax error in innbbs.conf\n");
+ } else {
+ *ptr++ = '\0';
+ His_Maint_Hour = atoi(value);
+ His_Maint_Min = atoi(ptr);
+ if (His_Maint_Hour < 0)
+ His_Maint_Hour = HIS_MAINT_HOUR;
+ if (His_Maint_Min < 0)
+ His_Maint_Min = HIS_MAINT_MIN;
+ }
+ } else if ( strcasecmp(front,"newsfeeds") == 0) {
+ if (strcmp(value,"none")==0)
+ NONENEWSFEEDS = 1;
+ } else if ( strcasecmp(front,"nodelist") == 0) {
+ if (strcmp(value,"local")==0)
+ LOCALNODELIST = 1;
+ } /*else if ( strcasecmp(front,"newsfeeds") == 0) {
+ printf("newsfeeds %s\n", value);
+ } else if ( strcasecmp(front,"nodelist") == 0) {
+ printf("nodelist %s\n", value);
+ } else if ( strcasecmp(front,"bbsname") == 0) {
+ printf("bbsname %s\n", value);
+ } */
+ }
+ fclose(conf);
+ }
+ }
+
+#ifdef WITH_ECHOMAIL
+ bbsnameptr = (char*) fileglue("%s/bbsname.bbs",INNDHOME);
+ if ((FN = fopen( bbsnameptr ,"r" ))==NULL) {
+ fprintf(stderr,"can't open file %s\n", bbsnameptr);
+ return 0;
+ }
+ while ( fscanf(FN,"%s", MYBBSID) != EOF);
+ fclose(FN);
+ if( ! isdir(fileglue("%s/out.going",BBSHOME)) ) {
+ mkdir( (char*)fileglue("%s/out.going",BBSHOME), 0750 );
+ }
+ if (NONENEWSFEEDS == 0)
+ readnffile(INNDHOME);
+ if (LOCALNODELIST == 0) {
+ if (readnlfile(INNDHOME, outgoing) != 0) return 0;
+ }
+
+#endif
+ return 1;
+}
+
+static int
+nf_byboardcmp(a,b)
+newsfeeds_t **a, **b;
+{
+/*
+ if (!a || !*a || !(*a)->board) return -1;
+ if (!b || !*b || !(*b)->board) return 1;
+*/
+ return strcasecmp((*a)->board, (*b)->board);
+}
+
+static int
+nfcmp(a,b)
+newsfeeds_t *a, *b;
+{
+/*
+ if (!a || !a->newsgroups) return -1;
+ if (!b || !b->newsgroups) return 1;
+*/
+ return strcasecmp(a->newsgroups, b->newsgroups);
+}
+
+static int
+nlcmp(a,b)
+nodelist_t *a, *b;
+{
+/*
+ if (!a || !a->host) return -1;
+ if (!b || !b->host) return 1;
+*/
+ return strcasecmp(a->host, b->host);
+}
+
+static int
+nl_bynodecmp(a,b)
+nodelist_t **a, **b;
+{
+/*
+ if (!a || !*a || !(*a)->node) return -1;
+ if (!b || !*b || !(*b)->node) return 1;
+*/
+ return strcasecmp((*a)->node, (*b)->node);
+}
+
+/* read in newsfeeds.bbs and nodelist.bbs */
+readnlfile(inndhome, outgoing)
+char *inndhome;
+char *outgoing;
+{
+ FILE *fp;
+ char buff[1024];
+ struct stat st;
+ int i, count, j;
+ char *ptr, *nodelistptr;
+ static lastcount=0;
+
+ sprintf(buff,"%s/nodelist.bbs", inndhome);
+ fp = fopen(buff,"r");
+ if (fp == NULL) {
+ fprintf(stderr,"open fail %s",buff);
+ return -1;
+ }
+ if (fstat(fileno(fp),&st) != 0) {
+ fprintf(stderr,"stat fail %s", buff);
+ return -1;
+ }
+ if (NODELIST_BUF == NULL) {
+ NODELIST_BUF = (char*) mymalloc( st.st_size +1);
+ } else {
+ NODELIST_BUF = (char*) myrealloc( NODELIST_BUF, st.st_size +1);
+ }
+ i = 0, count =0;
+ while (fgets(buff, sizeof buff, fp) != NULL) {
+ if (buff[0] == '#') continue;
+ if (buff[0] == '\n') continue;
+ strcpy(NODELIST_BUF+i, buff);
+ i += strlen(buff);
+ count ++;
+ }
+ fclose(fp);
+ if (NODELIST == NULL) {
+ NODELIST = (nodelist_t*) mymalloc(sizeof(nodelist_t) * (count+1));
+ NODELIST_BYNODE = (nodelist_t**) mymalloc(sizeof(nodelist_t*) * (count+1));
+ } else {
+ NODELIST = (nodelist_t*) myrealloc(NODELIST, sizeof(nodelist_t) * (count+1));
+ NODELIST_BYNODE = (nodelist_t**) myrealloc(NODELIST_BYNODE, sizeof(nodelist_t*) * (count+1));
+ }
+ for (i=lastcount; i< count; i++) {
+ NODELIST[i].feedfp = NULL;
+ }
+ lastcount = count;
+ NLCOUNT = 0;
+ for (ptr = NODELIST_BUF; (nodelistptr = (char*)strchr(ptr,'\n')) != NULL; ptr = nodelistptr +1, NLCOUNT++) {
+ char *nptr , *bptr, *pptr, *tptr;
+ *nodelistptr = '\0';
+ NODELIST[NLCOUNT].host = "";
+ NODELIST[NLCOUNT].exclusion = "";
+ NODELIST[NLCOUNT].node = "";
+ NODELIST[NLCOUNT].protocol = "IHAVE(119)";
+ NODELIST[NLCOUNT].comments = "";
+ NODELIST_BYNODE[NLCOUNT] = NODELIST+NLCOUNT;
+ for (nptr= ptr ;*nptr && isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') {
+ bbslog("nodelist.bbs %d entry read error\n", NLCOUNT);
+ return -1;
+ }
+ /*NODELIST[NLCOUNT].id = nptr;*/
+ NODELIST[NLCOUNT].node = nptr;
+ for (nptr++; *nptr && !isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') {
+ bbslog("nodelist.bbs node %d entry read error\n", NLCOUNT);
+ return -1;
+ }
+ *nptr = '\0';
+ if ((tptr = strchr(NODELIST[NLCOUNT].node,'/'))) {
+ *tptr = '\0';
+ NODELIST[NLCOUNT].exclusion = tptr + 1;
+ } else {
+ NODELIST[NLCOUNT].exclusion = "";
+ }
+ for (nptr++ ;*nptr && isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ if (*nptr=='+' || *nptr=='-') {
+ NODELIST[NLCOUNT].feedtype = *nptr;
+ if (NODELIST[NLCOUNT].feedfp != NULL) {
+ fclose(NODELIST[NLCOUNT].feedfp);
+ }
+ if ( NODELIST[NLCOUNT].feedtype == '+')
+ if (outgoing != NULL) {
+ NODELIST[NLCOUNT].feedfp = fopen((char*)fileglue("%s/out.going/%s.%s",BBSHOME, NODELIST[NLCOUNT].node, outgoing),"a");
+ }
+ nptr++;
+ } else {
+ NODELIST[NLCOUNT].feedtype = ' ';
+ }
+ NODELIST[NLCOUNT].host = nptr;
+ for (nptr++; *nptr && !isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') {
+ continue;
+ }
+ *nptr = '\0';
+ for (nptr++;*nptr && isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ NODELIST[NLCOUNT].protocol = nptr;
+ for (nptr++; *nptr && !isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ *nptr = '\0';
+ for (nptr++;*nptr && strchr(" \t\r\n",*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ NODELIST[NLCOUNT].comments = nptr;
+ }
+ qsort(NODELIST, NLCOUNT, sizeof(nodelist_t), nlcmp);
+ qsort(NODELIST_BYNODE, NLCOUNT, sizeof(nodelist_t*), nl_bynodecmp);
+ return 0;
+}
+
+readnffile(inndhome)
+char *inndhome;
+{
+ FILE *fp;
+ char buff[1024];
+ struct stat st;
+ int i, count;
+ char *ptr, *newsfeedsptr;
+
+ sprintf(buff,"%s/newsfeeds.bbs", inndhome);
+ fp = fopen(buff,"r");
+ if (fp == NULL) {
+ fprintf(stderr,"open fail %s",buff);
+ return -1;
+ }
+ if (fstat(fileno(fp),&st) != 0) {
+ fprintf(stderr,"stat fail %s", buff);
+ return -1;
+ }
+ if (NEWSFEEDS_BUF == NULL) {
+ NEWSFEEDS_BUF = (char*) mymalloc( st.st_size +1);
+ } else {
+ NEWSFEEDS_BUF = (char*) myrealloc( NEWSFEEDS_BUF, st.st_size +1);
+ }
+ i = 0, count =0;
+ while (fgets(buff, sizeof buff, fp) != NULL) {
+ if (buff[0] == '#') continue;
+ if (buff[0] == '\n') continue;
+ strcpy(NEWSFEEDS_BUF+i, buff);
+ i += strlen(buff);
+ count ++;
+ }
+ fclose(fp);
+ if (NEWSFEEDS == NULL) {
+ NEWSFEEDS = (newsfeeds_t*) mymalloc(sizeof(newsfeeds_t) * (count+1));
+ NEWSFEEDS_BYBOARD = (newsfeeds_t**) mymalloc(sizeof(newsfeeds_t*) * (count+1));
+ } else {
+ NEWSFEEDS = (newsfeeds_t*) myrealloc(NEWSFEEDS, sizeof(newsfeeds_t) * (count+1));
+ NEWSFEEDS_BYBOARD = (newsfeeds_t**) myrealloc(NEWSFEEDS_BYBOARD, sizeof(newsfeeds_t*) * (count+1));
+ }
+ NFCOUNT = 0;
+ for (ptr = NEWSFEEDS_BUF; (newsfeedsptr = (char*)strchr(ptr,'\n')) != NULL; ptr = newsfeedsptr +1, NFCOUNT++) {
+ char *nptr , *bptr, *pptr;
+ *newsfeedsptr = '\0';
+ NEWSFEEDS[NFCOUNT].newsgroups = "";
+ NEWSFEEDS[NFCOUNT].board = "";
+ NEWSFEEDS[NFCOUNT].path = NULL;
+ NEWSFEEDS_BYBOARD[NFCOUNT] = NEWSFEEDS+NFCOUNT;
+ for (nptr= ptr ;*nptr && isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ NEWSFEEDS[NFCOUNT].newsgroups = nptr;
+ for (nptr++; *nptr && !isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ *nptr = '\0';
+ for (nptr++ ;*nptr && isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ NEWSFEEDS[NFCOUNT].board = nptr;
+ for (nptr++; *nptr && !isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ *nptr = '\0';
+ for (nptr++;*nptr && isspace(*nptr); ) nptr++;
+ if (*nptr == '\0') continue;
+ NEWSFEEDS[NFCOUNT].path = nptr;
+ for (nptr++; *nptr && !strchr("\r\n",*nptr); ) nptr++;
+ /*if (*nptr == '\0') continue;*/
+ *nptr = '\0';
+ }
+ qsort(NEWSFEEDS, NFCOUNT, sizeof(newsfeeds_t), nfcmp);
+ qsort(NEWSFEEDS_BYBOARD, NFCOUNT, sizeof(newsfeeds_t*), nf_byboardcmp);
+}
+
+newsfeeds_t *search_board(board)
+char *board;
+{
+ newsfeeds_t nft, *nftptr, **find;
+ if (NONENEWSFEEDS) return NULL;
+ nft.board = board;
+ nftptr = &nft;
+ find = (newsfeeds_t**)bsearch((char*)&nftptr, NEWSFEEDS_BYBOARD, NFCOUNT, sizeof(newsfeeds_t*), nf_byboardcmp);
+ if (find != NULL) return *find;
+ return NULL;
+}
+
+nodelist_t *search_nodelist_bynode(node)
+char *node;
+{
+ nodelist_t nlt, *nltptr, **find;
+ if (LOCALNODELIST) return NULL;
+ nlt.node = node;
+ nltptr = &nlt;
+ find = (nodelist_t**)bsearch((char*)&nltptr, NODELIST_BYNODE, NLCOUNT, sizeof(nodelist_t*), nl_bynodecmp);
+ if (find != NULL) return *find;
+ return NULL;
+}
+
+
+nodelist_t *search_nodelist(site, identuser)
+char *site;
+char *identuser;
+{
+ nodelist_t nlt, *find;
+ char buffer[1024];
+ if (LOCALNODELIST) return NULL;
+ nlt.host = site;
+ find = (nodelist_t*)bsearch((char*)&nlt, NODELIST, NLCOUNT, sizeof(nodelist_t), nlcmp);
+ if (find == NULL && identuser != NULL) {
+ sprintf(buffer,"%s@%s", identuser, site);
+ nlt.host = buffer;
+ find = (nodelist_t*)bsearch((char*)&nlt, NODELIST, NLCOUNT, sizeof(nodelist_t), nlcmp);
+ }
+ return find;
+}
+
+newsfeeds_t *search_group(newsgroup)
+char *newsgroup;
+{
+ newsfeeds_t nft, *find;
+ if (NONENEWSFEEDS) return NULL;
+ nft.newsgroups = newsgroup;
+ find = (newsfeeds_t*)bsearch((char*)&nft, NEWSFEEDS, NFCOUNT, sizeof(newsfeeds_t), nfcmp);
+ return find;
+}
+
+char *ascii_date(now)
+time_t now;
+{
+ static char datebuf[40];
+ /*time_t now;
+ time(&now);*/
+ strftime(datebuf, sizeof(datebuf), "%d %b %Y %X GMT", gmtime(&now));
+ return datebuf;
+}
+
+char *
+restrdup(ptr, string)
+char *ptr;
+char *string;
+{
+ int len ;
+ if (string == NULL) {
+ if (ptr != NULL) *ptr = '\0';
+ return ptr;
+ }
+ len = strlen(string) + 1;
+ if (ptr != NULL) {
+ ptr = (char*)myrealloc(ptr, len);
+ } else
+ ptr = (char*)mymalloc(len);
+ strcpy(ptr, string);
+ return ptr;
+}
+
+
+
+void *
+mymalloc(size)
+int size;
+{
+ char *ptr = (char*)malloc(size);
+ if (ptr == NULL) {
+ fprintf(stderr, "cant allocate memory\n");
+ syslog(LOG_ERR, "cant allocate memory %m");
+ exit(1);
+ }
+ return ptr;
+}
+
+void *
+myrealloc(optr, size)
+void *optr;
+int size;
+{
+ char *ptr = (char*)realloc(optr, size);
+ if (ptr == NULL) {
+ fprintf(stderr, "cant allocate memory\n");
+ syslog(LOG_ERR, "cant allocate memory %m");
+ exit(1);
+ }
+ return ptr;
+}
+
+testandmkdir(dir)
+char *dir;
+{
+ if (!isdir(dir)) {
+ char path[MAXPATHLEN+12];
+ sprintf(path,"mkdir -p %s",dir);
+ system(path);
+ }
+}
+
+static char splitbuf[2048];
+static char joinbuf[1024];
+#define MAXTOK 50
+static char* Splitptr[MAXTOK];
+char **split(line,pat)
+char *line,*pat;
+{
+ char *p;
+ int i;
+
+ for (i=0;i<MAXTOK;++i) Splitptr[i] = NULL;
+ strncpy(splitbuf,line,sizeof splitbuf - 1 );
+ /*printf("%d %d\n",strlen(line),strlen(splitbuf));*/
+ splitbuf[sizeof splitbuf - 1] = '\0';
+ for (i=0,p=splitbuf;*p && i< MAXTOK -1 ;){
+ for (Splitptr[i++]=p;*p && !strchr(pat,*p);p++);
+ if (*p=='\0') break;
+ for (*p++='\0'; *p && strchr(pat,*p);p++);
+ }
+ return Splitptr;
+}
+
+char **BNGsplit(line)
+char *line;
+{
+ char **ptr = split(line,",");
+ newsfeeds_t *nf1, *nf2;
+ char *n11, *n12, *n21, *n22;
+ int i,j;
+ for (i=0; ptr[i] != NULL; i++) {
+ nf1 = (newsfeeds_t*)search_group(ptr[i]);
+ for (j=i+1; ptr[j] != NULL; j++) {
+ if (strcmp(ptr[i],ptr[j])==0) {
+ *ptr[j] = '\0';
+ continue;
+ }
+ nf2 = (newsfeeds_t*)search_group(ptr[j]);
+ if (nf1 && nf2) {
+ if (strcmp(nf1->board,nf2->board)==0) {
+ *ptr[j] = '\0';
+ continue;
+ }
+ for (n11 = nf1->board, n12 = (char*)strchr(n11,',');
+ n11 && *n11 ; n12 = (char*) strchr(n11,',')) {
+ if (n12) *n12 = '\0';
+ for (n21 = nf2->board, n22 = (char*)strchr(n21,',');
+ n21 && *n21 ; n22 = (char*) strchr(n21,',')) {
+ if (n22) *n22 = '\0';
+ if (strcmp(n11,n21)==0) {
+ *n21 = '\t';
+ }
+ if (n22) {
+ *n22 = ',';
+ n21 = n22 + 1;
+ } else
+ break;
+ }
+ if (n12) {
+ *n12 = ',';
+ n11 = n12 +1;
+ } else
+ break;
+ }
+ }
+ }
+ }
+ return ptr;
+}
+
+char **ssplit(line,pat)
+char *line,*pat;
+{
+ char *p;
+ int i;
+ for (i=0;i<MAXTOK;++i) Splitptr[i] = NULL;
+ strncpy(splitbuf,line,1024);
+ for (i=0,p=splitbuf;*p && i< MAXTOK;){
+ for (Splitptr[i++]=p;*p && !strchr(pat,*p);p++);
+ if (*p=='\0') break;
+ *p=0;p++;
+/* for (*p='\0'; strchr(pat,*p);p++);*/
+ }
+ return Splitptr;
+}
+
+char *join(lineptr,pat,num)
+char **lineptr,*pat;
+int num;
+{
+ int i;
+ joinbuf[0] = '\0';
+ if (lineptr[0] != NULL)
+ strncpy(joinbuf,lineptr[0],1024);
+ else {
+ joinbuf[0]='\0';
+ return joinbuf;
+ }
+ for (i=1;i<num;i++) {
+ strcat(joinbuf,pat);
+ if (lineptr[i] != NULL)
+ strcat(joinbuf,lineptr[i]);
+ else
+ break;
+ }
+ return joinbuf;
+}
+
+#ifdef BBSLIB
+main()
+{
+ initial_bbs("feed");
+ printf("%s\n",ascii_date());
+}
+#endif
+
diff --git a/innbbsd/externs.h b/innbbsd/externs.h
new file mode 100644
index 00000000..2cde1141
--- /dev/null
+++ b/innbbsd/externs.h
@@ -0,0 +1,16 @@
+#ifndef EXTERNS_H
+#define EXTERNS_H
+
+# ifndef ARG
+# ifdef __STDC__
+# define ARG(x) x
+# else
+# define ARG(x) ()
+# endif
+# endif
+
+char *fileglue ARG((char *, ...));
+char *ascii_date ARG(());
+char **split ARG((char *, char *));
+
+#endif
diff --git a/innbbsd/file.c b/innbbsd/file.c
new file mode 100644
index 00000000..d4df15b2
--- /dev/null
+++ b/innbbsd/file.c
@@ -0,0 +1,185 @@
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <varargs.h>
+#define MAXARGS 100
+
+/* isfile is called by
+ * isfile(filenamecomp1, filecomp2, filecomp3, ..., (char *)0);
+ * extern "C" int isfile(const char *, const char *[]) ;
+*/
+
+
+char FILEBUF[4096];
+
+
+static char DOLLAR_[8192];
+char *getstream(fp)
+FILE *fp;
+{
+ return fgets(DOLLAR_, sizeof(DOLLAR_) -1 , fp);
+}
+
+/*
+ The same as sprintf, but return the new string
+ fileglue("%s/%s",home,".newsrc");
+*/
+
+char *fileglue(va_alist)
+va_dcl
+{
+ va_list ap;
+ register char* fmt;
+ static char *newstring;
+ static char gluebuffer[8192];
+
+ va_start(ap);
+ fmt = va_arg(ap, char *) ;
+ vsprintf(gluebuffer, fmt, ap);
+ newstring = gluebuffer;
+ va_end(ap);
+ return newstring;
+}
+
+long
+filesize(filename)
+char* filename;
+{
+ struct stat st;
+
+ if (stat(filename,&st)) return 0;
+ return st.st_size;
+}
+
+int iszerofile(filename)
+char* filename;
+{
+ struct stat st;
+
+ if (stat(filename,&st)) return 0;
+ if (st.st_size == 0) return 1;
+ return 0;
+}
+
+int isfile(filename)
+char* filename;
+{
+ struct stat st;
+
+ if (stat(filename,&st)) return 0;
+ if (!S_ISREG(st.st_mode)) return 0;
+ return 1;
+}
+
+int isfilev(va_alist)
+va_dcl
+{
+ va_list ap;
+ struct stat st;
+ char *p;
+ va_start(ap);
+
+ FILEBUF[0]='\0';
+ while ((p = va_arg(ap, char *)) != (char *)0) {
+ strcat(FILEBUF,p);
+ }
+ printf("file %s\n",FILEBUF);
+
+ va_end(ap);
+ return isfile(FILEBUF);
+}
+
+
+int isdir(filename)
+char* filename;
+{
+ struct stat st;
+
+ if (stat(filename,&st)) return 0;
+ if (!S_ISDIR(st.st_mode)) return 0;
+ return 1;
+}
+
+int isdirv(va_alist)
+va_dcl
+{
+ va_list ap;
+ struct stat st;
+ char *p;
+ va_start(ap);
+
+ FILEBUF[0]='\0';
+ while ((p = va_arg(ap, char *)) != (char *)0) {
+ strcat(FILEBUF,p);
+ }
+
+ va_end(ap);
+ return isdir(FILEBUF);
+}
+
+unsigned long mtime(filename)
+char* filename;
+{
+ struct stat st;
+ if (stat(filename,&st)) return 0;
+ return st.st_mtime;
+}
+
+unsigned long mtimev(va_alist)
+va_dcl
+{
+ va_list ap;
+ struct stat st;
+ char *p;
+ va_start(ap);
+
+ FILEBUF[0]='\0';
+ while ((p = va_arg(ap, char *)) != (char *)0) {
+ strcat(FILEBUF,p);
+ }
+
+ va_end(ap);
+ return mtime(FILEBUF);
+}
+
+unsigned long atime(filename)
+char *filename;
+{
+ struct stat st;
+ if (stat(filename,&st)) return 0;
+ return st.st_atime;
+}
+
+unsigned long atimev(va_alist)
+va_dcl
+{
+ va_list ap;
+ struct stat st;
+ char *p;
+ va_start(ap);
+
+ FILEBUF[0]='\0';
+ while ((p = va_arg(ap, char *)) != (char *)0) {
+ strcat(FILEBUF,p);
+ }
+
+ va_end(ap);
+ return atime(FILEBUF);
+}
+
+/*#undef TEST*/
+#ifdef TEST
+main(argc,argv)
+int argc;
+char **argv;
+{
+ int i;
+ if (argc > 3) {
+ if (isfilev(argv[1],argv[2],(char*)0)) printf("%s %s %s is file\n",argv[1],argv[2],argv[3]);
+ if (isdirv(argv[1],argv[2],(char*)0)) printf("%s %s %s is dir\n",argv[1],argv[2],argv[3]);
+ printf("mtime %d\n",mtimev(argv[1],argv[2],(char*)0));
+ printf("atime %d\n",atimev(argv[1],argv[2],(char*)0));
+ }
+ printf("fileglue %s\n", fileglue("%s/%s","home",".test"));
+}
+#endif
diff --git a/innbbsd/his.c b/innbbsd/his.c
new file mode 100644
index 00000000..7fe48dc3
--- /dev/null
+++ b/innbbsd/his.c
@@ -0,0 +1,474 @@
+/* $Revision: 1.1 $
+**
+** History file routines.
+*/
+#include "innbbsconf.h"
+#include "bbslib.h"
+#include "his.h"
+
+#define STATIC static
+/*STATIC char HIShistpath[] = _PATH_HISTORY;*/
+STATIC FILE *HISwritefp;
+STATIC int HISreadfd;
+STATIC int HISdirty;
+STATIC int HISincore = XINDEX_DBZINCORE;
+STATIC char *LogName = "xindexchan";
+
+#ifndef EXPIREDAYS
+# define EXPIREDAYS 4
+#endif
+
+#ifndef DEFAULT_HIST_SIZE
+# define DEFAULT_HIST_SIZE 100000
+#endif
+
+hisincore(flag)
+int flag;
+{
+ HISincore = flag;
+}
+
+makedbz(histpath, entry)
+char *histpath;
+long entry;
+{
+ long size;
+ size = dbzsize(entry);
+ dbzfresh(histpath,size,'\t',0, 1);
+ dbmclose();
+}
+
+void HISsetup();
+void HISclose();
+
+void
+mkhistory(srchist)
+char *srchist;
+{
+ FILE *hismaint ;
+ time_t lasthist, now;
+ char maintbuff[256];
+ char *ptr;
+ hismaint= fopen(srchist, "r");
+ if (hismaint == NULL) {
+ return;
+ }
+ {
+ char newhistpath[1024];
+ char newhistdirpath[1024];
+ char newhistpagpath[1024];
+ sprintf(newhistpath,"%s.n",srchist);
+ sprintf(newhistdirpath,"%s.n.dir",srchist);
+ sprintf(newhistpagpath,"%s.n.pag",srchist);
+ if (!isfile(newhistdirpath) || !isfile(newhistpagpath)) {
+ makedbz(newhistpath, DEFAULT_HIST_SIZE);
+ }
+ myHISsetup(newhistpath);
+ while ( fgets(maintbuff, sizeof(maintbuff), hismaint) != NULL) {
+ datum key;
+ ptr = (char*) strchr(maintbuff,'\t');
+ if (ptr != NULL) { *ptr = '\0'; ptr++;}
+ key.dptr = maintbuff;
+ key.dsize = strlen(maintbuff);
+ myHISwrite(&key, ptr);
+ }
+ (void) HISclose();
+ /*rename(newhistpath, srchist);
+ rename(newhistdirpath, fileglue("%s.dir", srchist));
+ rename(newhistpagpath, fileglue("%s.pag", srchist));*/
+ }
+ fclose(hismaint);
+}
+
+time_t
+gethisinfo()
+{
+ FILE *hismaint ;
+ time_t lasthist, now;
+ char maintbuff[4096];
+ char *ptr;
+ hismaint= fopen(HISTORY, "r");
+ if (hismaint == NULL) {
+ return 0;
+ }
+ fgets(maintbuff,sizeof(maintbuff), hismaint);
+ fclose(hismaint);
+ ptr = (char*)strchr(maintbuff,'\t');
+ if (ptr != NULL) {
+ ptr++;
+ lasthist = atol(ptr);
+ return lasthist;
+ }
+ return 0;
+}
+
+void
+HISmaint()
+{
+ FILE *hismaint ;
+ time_t lasthist, now;
+ char maintbuff[4096];
+ char *ptr;
+
+ if (!isfile(HISTORY)) {
+ makedbz(HISTORY, DEFAULT_HIST_SIZE);
+ }
+ hismaint= fopen(HISTORY, "r");
+ if (hismaint == NULL) {
+ return;
+ }
+ fgets(maintbuff,sizeof(maintbuff), hismaint);
+ ptr = (char*)strchr(maintbuff,'\t');
+ if (ptr != NULL) {
+ ptr++;
+ lasthist = atol(ptr);
+ time(&now);
+ if ( lasthist + 86400 * Expiredays * 2 < now ) {
+ char newhistpath[1024];
+ char newhistdirpath[1024];
+ char newhistpagpath[1024];
+ (void) HISclose();
+ sprintf(newhistpath,"%s.n",HISTORY);
+ sprintf(newhistdirpath,"%s.n.dir",HISTORY);
+ sprintf(newhistpagpath,"%s.n.pag",HISTORY);
+ if (!isfile(newhistdirpath)) {
+ makedbz(newhistpath, DEFAULT_HIST_SIZE);
+ }
+ myHISsetup(newhistpath);
+ while ( fgets(maintbuff, sizeof(maintbuff), hismaint) != NULL) {
+ datum key;
+ ptr = (char*) strchr(maintbuff,'\t');
+ if (ptr != NULL) {
+ *ptr = '\0'; ptr++;
+ lasthist = atol(ptr);
+ } else {
+ continue ;
+ }
+ if ( lasthist + 99600 * Expiredays < now ) continue;
+ key.dptr = maintbuff;
+ key.dsize = strlen(maintbuff);
+ myHISwrite(&key, ptr);
+ }
+ (void) HISclose();
+ rename(HISTORY, (char*)fileglue("%s.o",HISTORY));
+ rename(newhistpath, HISTORY);
+ rename(newhistdirpath, (char*)fileglue("%s.dir", HISTORY));
+ rename(newhistpagpath, (char*)fileglue("%s.pag", HISTORY));
+ (void) HISsetup();
+ }
+ }
+ fclose(hismaint);
+}
+
+
+/*
+** Set up the history files.
+*/
+void
+HISsetup()
+{
+ myHISsetup(HISTORY);
+}
+
+int
+myHISsetup(histpath)
+char *histpath;
+{
+ if (HISwritefp == NULL) {
+ /* Open the history file for appending formatted I/O. */
+ if ((HISwritefp = fopen(histpath, "a")) == NULL) {
+ syslog(LOG_CRIT, "%s cant fopen %s %m", LogName, histpath);
+ exit(1);
+ }
+ CloseOnExec((int)fileno(HISwritefp), TRUE);
+
+ /* Open the history file for reading. */
+ if ((HISreadfd = open(histpath, O_RDONLY)) < 0) {
+ syslog(LOG_CRIT, "%s cant open %s %m", LogName, histpath);
+ exit(1);
+ }
+ CloseOnExec(HISreadfd, TRUE);
+
+ /* Open the DBZ file. */
+ /*(void)dbzincore(HISincore);*/
+ (void)dbzincore(HISincore);
+ (void)dbzwritethrough(1);
+ if (dbminit(histpath) < 0) {
+ syslog(LOG_CRIT, "%s cant dbminit %s %m", histpath, LogName);
+ exit(1);
+ }
+ }
+}
+
+
+/*
+** Synchronize the in-core history file (flush it).
+*/
+void
+HISsync()
+{
+ if (HISdirty) {
+ if (dbzsync()) {
+ syslog(LOG_CRIT, "%s cant dbzsync %m", LogName);
+ exit(1);
+ }
+ HISdirty = 0;
+ }
+}
+
+
+/*
+** Close the history files.
+*/
+void
+HISclose()
+{
+ if (HISwritefp != NULL) {
+ /* Since dbmclose calls dbzsync we could replace this line with
+ * "HISdirty = 0;". Oh well, it keeps the abstraction clean. */
+ HISsync();
+ if (dbmclose() < 0)
+ syslog(LOG_ERR, "%s cant dbmclose %m", LogName);
+ if (fclose(HISwritefp) == EOF)
+ syslog(LOG_ERR, "%s cant fclose history %m", LogName);
+ HISwritefp = NULL;
+ if (close(HISreadfd) < 0)
+ syslog(LOG_ERR, "%s cant close history %m", LogName);
+ HISreadfd = -1;
+ }
+}
+
+
+#ifdef HISset
+/*
+** File in the DBZ datum for a Message-ID, making sure not to copy any
+** illegal characters.
+*/
+STATIC void
+HISsetkey(p, keyp)
+ register char *p;
+ datum *keyp;
+{
+ static BUFFER MessageID;
+ register char *dest;
+ register int i;
+
+ /* Get space to hold the ID. */
+ i = strlen(p);
+ if (MessageID.Data == NULL) {
+ MessageID.Data = NEW(char, i + 1);
+ MessageID.Size = i;
+ }
+ else if (MessageID.Size < i) {
+ RENEW(MessageID.Data, char, i + 1);
+ MessageID.Size = i;
+ }
+
+ for (keyp->dptr = dest = MessageID.Data; *p; p++)
+ if (*p == HIS_FIELDSEP || *p == '\n')
+ *dest++ = HIS_BADCHAR;
+ else
+ *dest++ = *p;
+ *dest = '\0';
+
+ keyp->dsize = dest - MessageID.Data + 1;
+}
+
+#endif
+/*
+** Get the list of files under which a Message-ID is stored.
+*/
+char *
+HISfilesfor(key,output)
+ datum *key;
+ datum *output;
+{
+ char *dest;
+ datum val;
+ long offset;
+ register char *p;
+ register int i;
+ int Used;
+
+ /* Get the seek value into the history file. */
+ val = dbzfetch(*key);
+ if (val.dptr == NULL || val.dsize != sizeof offset){
+ /*printf("fail here val.dptr %d\n",val.dptr);*/
+ return NULL;
+ }
+
+ /* Get space. */
+ if (output->dptr == NULL) {
+ printf("fail here output->dptr null\n");
+ return NULL;
+ }
+
+ /* Copy the value to an aligned spot. */
+ for (p = val.dptr, dest = (char *)&offset, i = sizeof offset; --i >= 0; )
+ *dest++ = *p++;
+ if (lseek(HISreadfd, offset, SEEK_SET) == -1) {
+ printf("fail here lseek %d\n",offset);
+ return NULL;
+ }
+
+ /* Read the text until \n or EOF. */
+ for (output->dsize = 0,Used=0; ; ) {
+ i = read(HISreadfd,
+ &output->dptr[output->dsize], LEN - 1);
+ if (i <= 0) {
+ printf("fail here i %d\n",i);
+ return NULL;
+ }
+ Used += i;
+ output->dptr[Used] = '\0';
+ if ((p = (char*)strchr(output->dptr, '\n')) != NULL) {
+ *p = '\0';
+ break;
+ }
+ }
+
+ /* Move past the first two fields -- Message-ID and date info. */
+ if ((p = (char*)strchr(output->dptr, HIS_FIELDSEP)) == NULL) {
+ printf("fail here no HIS_FILE\n");
+ return NULL;
+ }
+ return p+1;
+ /*if ((p = (char*)strchr(p + 1, HIS_FIELDSEP)) == NULL)
+ return NULL;*/
+
+ /* Translate newsgroup separators to slashes, return the fieldstart. */
+}
+
+/*
+** Have we already seen an article?
+*/
+#ifdef HISh
+BOOL
+HIShavearticle(MessageID)
+ char *MessageID;
+{
+ datum key;
+ datum val;
+
+ HISsetkey(MessageID, &key);
+ val = dbzfetch(key);
+ return val.dptr != NULL;
+}
+#endif
+
+
+/*
+** Turn a history filename entry from slashes to dots. It's a pity
+** we have to do this.
+*/
+STATIC void
+HISslashify(p)
+ register char *p;
+{
+ register char *last;
+
+ for (last = NULL; *p; p++) {
+ if (*p == '/') {
+ *p = '.';
+ last = p;
+ }
+ else if (*p == ' ' && last != NULL)
+ *last = '/';
+ }
+ if (last)
+ *last = '/';
+}
+
+
+IOError(error)
+char *error;
+{
+ fprintf(stderr,"%s\n",error);
+}
+
+/*BOOL*/
+myHISwrite(key, remain)
+ datum *key;
+ char *remain;
+{
+ static char NOPATHS[] = "";
+ long offset;
+ datum val;
+ int i;
+
+ val = dbzfetch(*key);
+ if (val.dptr != NULL){
+ return FALSE;
+ }
+
+ flock(fileno(HISwritefp),LOCK_EX);
+ offset = ftell(HISwritefp);
+ i = fprintf(HISwritefp, "%s%c%s",
+ key->dptr, HIS_FIELDSEP, remain);
+ if (i == EOF || fflush(HISwritefp) == EOF) {
+ /* The history line is now an orphan... */
+ IOError("history");
+ syslog(LOG_ERR, "%s cant write history %m", LogName);
+ flock(fileno(HISwritefp),LOCK_UN);
+ return FALSE;
+ }
+
+ /* Set up the database values and write them. */
+ val.dptr = (char *)&offset;
+ val.dsize = sizeof offset;
+ if (dbzstore(*key, val) < 0) {
+ IOError("my history database");
+ syslog(LOG_ERR, "%s cant dbzstore %m", LogName);
+ flock(fileno(HISwritefp),LOCK_UN);
+ return FALSE;
+ }
+
+ if (++HISdirty >= ICD_SYNC_COUNT)
+ HISsync();
+ flock(fileno(HISwritefp),LOCK_UN);
+ return TRUE;
+}
+
+
+/*
+** Write a history entry.
+*/
+BOOL
+HISwrite(key, date, paths)
+ datum *key;
+ char *paths;
+ long date;
+{
+ static char NOPATHS[] = "";
+ long offset;
+ datum val;
+ int i;
+
+ flock(fileno(HISwritefp),LOCK_EX);
+ offset = ftell(HISwritefp);
+ i = fprintf(HISwritefp, "%s%c%ld%c%s\n",
+ key->dptr, HIS_FIELDSEP, (long)date, HIS_FIELDSEP,
+ paths);
+ if (i == EOF || fflush(HISwritefp) == EOF) {
+ /* The history line is now an orphan... */
+ IOError("history");
+ syslog(LOG_ERR, "%s cant write history %m", LogName);
+ flock(fileno(HISwritefp),LOCK_UN);
+ return FALSE;
+ }
+
+ /* Set up the database values and write them. */
+ val.dptr = (char *)&offset;
+ val.dsize = sizeof offset;
+ if (dbzstore(*key, val) < 0) {
+ IOError("history database");
+ syslog(LOG_ERR, "%s cant dbzstore %m", LogName);
+ flock(fileno(HISwritefp),LOCK_UN);
+ return FALSE;
+ }
+
+ if (++HISdirty >= ICD_SYNC_COUNT)
+ HISsync();
+ flock(fileno(HISwritefp),LOCK_UN);
+ return TRUE;
+}
diff --git a/innbbsd/his.h b/innbbsd/his.h
new file mode 100644
index 00000000..f54efc01
--- /dev/null
+++ b/innbbsd/his.h
@@ -0,0 +1,80 @@
+#ifndef HIS_H
+#define HIS_H
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#ifndef SEEK_SET
+#include <unistd.h>
+#endif
+#include "dbz.h"
+
+#ifndef XINDEXDIR
+# define XINDEXDIR "/homec/xindex"
+#endif
+#ifndef _PATH_HISTORY
+# define _PATH_HISTORY "/u/staff/bbsroot/csie_util/bntpd/history"
+#endif
+
+#ifndef _PATH_COVERVIEW
+# define _PATH_COVERVIEW ".coverview"
+#endif
+
+#ifndef _PATH_COVERVIEWDIR
+# define _PATH_COVERVIEWDIR "/homec/xindex"
+#endif
+
+#ifndef XINDEX_DBZINCORE
+# define XINDEX_DBZINCORE 1
+#endif
+#ifndef XINDEXNAME
+# define XINDEXNAME ".index"
+#endif
+#ifndef XINDEXDBM
+# define XINDEXDBM ".dbm"
+#endif
+#ifndef XINDEXINFO
+# define XINDEXINFO ".info"
+#endif
+
+#define LEN 1024
+struct t_article {
+ long artnum;
+ char subject[LEN]; /* Subject: line from mail header */
+ char from[LEN]; /* From: line from mail header (address)
+ */
+ char name[LEN]; /* From: line from mail header (full nam
+e) */
+ long date; /* Date: line from header in seconds */
+ char xref[LEN]; /* Xref: cross posted article reference
+line */
+ int lines; /* Lines: number of lines in article */
+ char *archive; /* Archive-name: line from mail header */
+ char *part; /* part no. of archive */
+ char *patch; /* patch no. of archive */
+};
+
+typedef struct t_article art_t;
+
+#define HIS_BADCHAR '_'
+#define HIS_FIELDSEP '\t'
+#define HIS_NOEXP "-"
+#define HIS_SUBFIELDSEP '~'
+/*#define HIS_FIELDSEP2 '\034'*/
+#define HIS_FIELDSEP2 'I'
+
+#ifndef TRUE
+# define TRUE 1
+# define FALSE 0
+#endif
+
+#ifndef BOOL
+typedef unsigned char BOOL;
+#endif
+
+#ifndef ICD_SYNC_COUNT
+# define ICD_SYNC_COUNT 1
+#endif
+
+#endif
diff --git a/innbbsd/innbbsconf.h b/innbbsd/innbbsconf.h
new file mode 100644
index 00000000..6521dde6
--- /dev/null
+++ b/innbbsd/innbbsconf.h
@@ -0,0 +1,192 @@
+#ifndef INNBBSCONF_H
+#define INNBBSCONF_H
+#include <stdio.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/un.h>
+#include <sys/param.h>
+#include <sys/wait.h>
+
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <time.h>
+#ifndef BSD44
+# include <malloc.h>
+#endif
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+
+/*#include "bbs.h"*/
+#if defined(AIX)
+# include <sys/select.h>
+#endif
+
+/*
+ BBS home directory
+ It has been overridden in Makefile
+*/
+#ifndef _PATH_BBSHOME
+# define _PATH_BBSHOME "/u/staff/bbsroot/csie_util/bntpd/home"
+/*# define _PATH_BBSHOME "/home/bbs"*/
+#endif
+
+#ifndef EXPIREDAYS
+# define EXPIREDAYS 7
+#endif
+
+#ifndef DEFAULT_HIST_SIZE
+# define DEFAULT_HIST_SIZE 100000
+#endif
+
+/*
+ Maximum number of connections accepted by innbbsd
+*/
+#ifndef MAXCLIENT
+# define MAXCLIENT 500
+#endif
+
+/*
+ Maximum number of articles received for a newsgroup by bbsnnrp each time
+*/
+#ifndef MAX_ARTS
+# define MAX_ARTS 100
+#endif
+
+/*
+ Maximum size of articles received
+*/
+#ifndef MAX_ART_SIZE
+# define MAX_ART_SIZE 1000000L
+#endif
+
+
+/*
+ Maximum number of articles stated for a newsgroup by bbsnnrp each time
+*/
+#ifndef MAX_STATS
+# define MAX_STATS 1000
+#endif
+
+/*
+ Mininum wait interval for bbsnnrp
+*/
+#ifndef MIN_WAIT
+# define MIN_WAIT 60
+#endif
+
+
+#ifndef DefaultINNBBSPort
+# define DefaultINNBBSPort "7777"
+#endif
+
+/*
+ time to maintain history database
+*/
+#ifndef HIS_MAINT
+# define HIS_MAINT
+# define HIS_MAINT_HOUR 4
+# define HIS_MAINT_MIN 30
+#endif
+
+#ifndef ChannelSize
+# define ChannelSize 4096
+#endif
+
+#ifndef ReadSize
+# define ReadSize 1024
+#endif
+
+#ifndef MAXPATHLEN
+# define MAXPATHLEN 1024
+#endif
+
+#ifndef CLX_IOCTL
+# define CLX_IOCTL
+#endif
+
+#define DEFAULTSERVER "your.favorite.news.server"
+#define DEFAULTPORT "nntp"
+#define DEFAULTPROTOCOL "tcp"
+#define DEFAULTPATH ".innbbsd"
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+/*
+# ifndef ARG
+# ifdef __STDC__
+# define ARG(x) (x)
+# else
+# define ARG(x) ()
+# endif
+# endif
+*/
+/* machine dependend */
+#if defined(__linux)
+# ifndef LINUX
+# define LINUX
+# endif
+#endif
+
+#if !defined(__svr4__) || defined(sun)
+# define WITH_TM_GMTOFF
+#endif
+#if (defined(__svr4__) && defined(sun)) || defined(SOLARIS)
+# ifndef SOLARIS
+# define SOLARIS
+# endif
+# define NO_getdtablesize
+# define NO_bcopy
+# define NO_bzero
+# define NO_flock
+# define WITH_lockf
+#endif
+
+#if defined(AIX)
+# define NO_flock
+# define WITH_lockf
+#endif
+
+#if defined(HPUX)
+# define NO_getdtablesize
+# define NO_flock
+# define WITH_lockf
+#endif
+
+#ifdef NO_bcopy
+# ifndef bcopy
+# define bcopy(a,b,c) memcpy(b,a,c)
+# endif
+#endif
+
+#ifdef NO_bzero
+# ifndef bzero
+# define bzero(mem, size) memset(mem,'\0',size)
+# endif
+#endif
+
+#ifndef LOCK_EX
+# define LOCK_EX 2 /* exclusive lock */
+# define LOCK_UN 8 /* unlock */
+#endif
+
+#ifdef DEC_ALPHA
+# define ULONG unsigned int
+#else
+# define ULONG unsigned long
+#endif
+
+#ifdef PalmBBS
+#undef WITH_RECORD_O
+#endif
+
+#endif
diff --git a/innbbsd/innbbsd.c b/innbbsd/innbbsd.c
new file mode 100644
index 00000000..f35c1cfb
--- /dev/null
+++ b/innbbsd/innbbsd.c
@@ -0,0 +1,775 @@
+#include "innbbsconf.h"
+#include "daemon.h"
+#include "innbbsd.h"
+#include <dirent.h>
+#include "bbslib.h"
+#include "inntobbs.h"
+#include "nntp.h"
+
+#ifdef GETRUSAGE
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+
+#ifdef STDC
+# ifndef ARG
+# define ARG(x) (x)
+# else
+# define ARG(x) ()
+# endif
+#endif
+
+/*< add <mid> <recno> ...
+> 200 OK
+< quit
+ 500 BYE
+
+> 300 DBZ Server ...
+< query <mid>
+> 250 <recno> ...
+> 450 NOT FOUND!
+*/
+
+static int CMDhelp ARG((ClientType*));
+static int CMDquit ARG((ClientType*));
+static int CMDihave ARG((ClientType*));
+static int CMDstat ARG((ClientType*));
+static int CMDaddhist ARG((ClientType*));
+static int CMDgrephist ARG((ClientType*));
+static int CMDmidcheck ARG((ClientType*));
+static int CMDshutdown ARG((ClientType*));
+static int CMDmode ARG((ClientType*));
+static int CMDreload ARG((ClientType*));
+static int CMDhismaint ARG((ClientType*));
+static int CMDverboselog ARG((ClientType*));
+static int CMDlistnodelist ARG((ClientType*));
+static int CMDlistnewsfeeds ARG((ClientType*));
+
+#ifdef GETRUSAGE
+static int CMDgetrusage ARG((ClientType*));
+static int CMDmallocmap ARG((ClientType*));
+#endif
+
+static daemoncmd_t cmds[]=
+/* cmd-name, cmd-usage, min-argc, max-argc, errorcode, normalcode, cmd-func */
+{ {"help","help [cmd]",1,2,99,100,CMDhelp},
+ {"quit","quit",1,0,99,100,CMDquit},
+#ifndef DBZSERVER
+ {"ihave","ihave mid",2,2,435,335,CMDihave},
+#endif
+ {"stat","stat mid",2,2,223,430,CMDstat},
+ {"addhist","addhist <mid> <path>",3,3, NNTP_ADDHIST_BAD, NNTP_ADDHIST_OK,CMDaddhist},
+ {"grephist","grephist <mid>",2,2, NNTP_GREPHIST_BAD, NNTP_GREPHIST_OK, CMDgrephist},
+ {"midcheck","midcheck [on|off]",1,2, NNTP_MIDCHECK_BAD, NNTP_MIDCHECK_OK, CMDmidcheck},
+ {"shutdown","shutdown (local)",1,1, NNTP_SHUTDOWN_BAD, NNTP_SHUTDOWN_OK, CMDshutdown},
+ {"mode","mode (local)",1,1, NNTP_MODE_BAD, NNTP_MODE_OK, CMDmode},
+ {"listnodelist","listnodelist (local)",1,1, NNTP_MODE_BAD, NNTP_MODE_OK, CMDlistnodelist},
+ {"listnewsfeeds","listnewsfeeds (local)",1,1, NNTP_MODE_BAD, NNTP_MODE_OK, CMDlistnewsfeeds},
+ {"reload","reload (local)",1,1, NNTP_RELOAD_BAD, NNTP_RELOAD_OK, CMDreload},
+ {"hismaint","hismaint (local)",1,1, NNTP_RELOAD_BAD, NNTP_RELOAD_OK, CMDhismaint},
+ {"verboselog","verboselog [on|off](local)",1,2, NNTP_VERBOSELOG_BAD, NNTP_VERBOSELOG_OK, CMDverboselog},
+#ifdef GETRUSAGE
+ {"getrusage","getrusage (local)",1,1, NNTP_MODE_BAD, NNTP_MODE_OK, CMDgetrusage},
+#endif
+#ifdef MALLOCMAP
+ {"mallocmap","mallocmap (local)",1,1, NNTP_MODE_BAD, NNTP_MODE_OK, CMDmallocmap},
+#endif
+ {NULL,NULL,0,0,99,100,NULL}
+};
+
+installinnbbsd()
+{
+ installdaemon(cmds,100,NULL);
+}
+
+#ifdef OLDLIBINBBSINND
+testandmkdir(dir)
+char *dir;
+{
+ if (!isdir(dir)) {
+ char path[MAXPATHLEN+12];
+ sprintf(path,"mkdir -p %s",dir);
+ system(path);
+ }
+}
+
+static char splitbuf[2048];
+static char joinbuf[1024];
+#define MAXTOK 50
+static char* Splitptr[MAXTOK];
+char **split(line,pat)
+char *line,*pat;
+{
+ char *p;
+ int i;
+
+ for (i=0;i<MAXTOK;++i) Splitptr[i] = NULL;
+ strncpy(splitbuf,line,sizeof splitbuf - 1 );
+ /*printf("%d %d\n",strlen(line),strlen(splitbuf));*/
+ splitbuf[sizeof splitbuf - 1] = '\0';
+ for (i=0,p=splitbuf;*p && i< MAXTOK -1 ;){
+ for (Splitptr[i++]=p;*p && !strchr(pat,*p);p++);
+ if (*p=='\0') break;
+ for (*p++='\0'; *p && strchr(pat,*p);p++);
+ }
+ return Splitptr;
+}
+
+char **BNGsplit(line)
+char *line;
+{
+ char **ptr = split(line,",");
+ newsfeeds_t *nf1, *nf2;
+ char *n11, *n12, *n21, *n22;
+ int i,j;
+ for (i=0; ptr[i] != NULL; i++) {
+ nf1 = (newsfeeds_t*)search_group(ptr[i]);
+ for (j=i+1; ptr[j] != NULL; j++) {
+ if (strcmp(ptr[i],ptr[j])==0) {
+ *ptr[j] = '\0';
+ continue;
+ }
+ nf2 = (newsfeeds_t*)search_group(ptr[j]);
+ if (nf1 && nf2) {
+ if (strcmp(nf1->board,nf2->board)==0) {
+ *ptr[j] = '\0';
+ continue;
+ }
+ for (n11 = nf1->board, n12 = (char*)strchr(n11,',');
+ n11 && *n11 ; n12 = (char*) strchr(n11,',')) {
+ if (n12) *n12 = '\0';
+ for (n21 = nf2->board, n22 = (char*)strchr(n21,',');
+ n21 && *n21 ; n22 = (char*) strchr(n21,',')) {
+ if (n22) *n22 = '\0';
+ if (strcmp(n11,n21)==0) {
+ *n21 = '\t';
+ }
+ if (n22) {
+ *n22 = ',';
+ n21 = n22 + 1;
+ } else
+ break;
+ }
+ if (n12) {
+ *n12 = ',';
+ n11 = n12 +1;
+ } else
+ break;
+ }
+ }
+ }
+ }
+ return ptr;
+}
+
+char **ssplit(line,pat)
+char *line,*pat;
+{
+ char *p;
+ int i;
+ for (i=0;i<MAXTOK;++i) Splitptr[i] = NULL;
+ strncpy(splitbuf,line,1024);
+ for (i=0,p=splitbuf;*p && i< MAXTOK;){
+ for (Splitptr[i++]=p;*p && !strchr(pat,*p);p++);
+ if (*p=='\0') break;
+ *p=0;p++;
+/* for (*p='\0'; strchr(pat,*p);p++);*/
+ }
+ return Splitptr;
+}
+
+char *join(lineptr,pat,num)
+char **lineptr,*pat;
+int num;
+{
+ int i;
+ joinbuf[0] = '\0';
+ if (lineptr[0] != NULL)
+ strncpy(joinbuf,lineptr[0],1024);
+ else {
+ joinbuf[0]='\0';
+ return joinbuf;
+ }
+ for (i=1;i<num;i++) {
+ strcat(joinbuf,pat);
+ if (lineptr[i] != NULL)
+ strcat(joinbuf,lineptr[i]);
+ else
+ break;
+ }
+ return joinbuf;
+}
+
+#endif
+
+static int CMDtnrpd(client)
+ClientType *client;
+{
+ argv_t *argv = &client->Argv;
+ fprintf(argv->out,"%d %s\n",argv->dc->usage);
+ return 0;
+}
+
+islocalconnect(client)
+ClientType *client;
+{
+ if (strcmp(client->username,"localuser") != 0 ||
+ strcmp(client->hostname,"localhost") != 0)
+ return 0;
+ return 1;
+}
+
+static shutdownflag = 0;
+INNBBSDhalt()
+{
+ shutdownflag = 1;
+}
+
+int INNBBSDshutdown()
+{
+ return shutdownflag;
+}
+
+static int CMDshutdown(client)
+ClientType *client;
+{
+ argv_t *argv = &client->Argv;
+ buffer_t *in = &client->in;
+ daemoncmd_t *p = argv->dc;
+ if (!islocalconnect(client)) {
+ fprintf(argv->out,"%d shutdown access denied\r\n", p->errorcode);
+ fflush(argv->out);
+ verboselog("Shutdown Put: %d shutdown access denied\n", p->errorcode);
+ return 1;
+ }
+ shutdownflag = 1;
+ fprintf(argv->out,"%d shutdown starting\r\n", p->normalcode);
+ fflush(argv->out);
+ verboselog("Shutdown Put: %d shutdown starting\n", p->normalcode);
+ return 1;
+}
+
+static int CMDmode(client)
+ClientType *client;
+{
+ /*char cwdpath[MAXPATHLEN+1];*/
+ argv_t *argv = &client->Argv;
+ extern ClientType INNBBSD_STAT;
+ buffer_t *in = &client->in;
+ daemoncmd_t *p = argv->dc;
+ time_t uptime, now;
+ int i,j;
+ time_t lasthist;
+ ClientType *client1 = &INNBBSD_STAT;
+
+ if (!islocalconnect(client)) {
+ fprintf(argv->out,"%d mode access denied\r\n", p->errorcode);
+ fflush(argv->out);
+ verboselog("Mode Put: %d mode access denied\n", p->errorcode);
+ return 1;
+ }
+ fprintf(argv->out,"%d mode\r\n", p->normalcode);
+ fflush(argv->out);
+ verboselog("Mode Put: %d mode\n", p->normalcode);
+ uptime = innbbsdstartup();
+ time(&now);
+ fprintf(argv->out,"up since %salive %.2f days\r\n", ctime(&uptime), (double)(now - innbbsdstartup())/86400);
+ fprintf(argv->out,"BBSHOME %s\r\n", BBSHOME);
+ fprintf(argv->out,"MYBBSID %s\r\n", MYBBSID);
+ fprintf(argv->out,"ECHOMAIL %s\r\n", ECHOMAIL);
+ fprintf(argv->out,"INNDHOME %s\r\n", INNDHOME);
+ fprintf(argv->out,"HISTORY %s\r\n", HISTORY);
+ fprintf(argv->out,"LOGFILE %s\r\n", LOGFILE);
+ fprintf(argv->out,"INNBBSCONF %s\r\n", INNBBSCONF);
+ fprintf(argv->out,"BBSFEEDS %s\r\n", BBSFEEDS);
+ fprintf(argv->out,"Verbose log: %s\r\n", isverboselog() ?"ON":"OFF");
+ fprintf(argv->out,"History Expire Days %d\r\n", Expiredays);
+ fprintf(argv->out,"History Expire Time %d:%d\r\n", His_Maint_Hour, His_Maint_Min);
+ lasthist = gethisinfo();
+ if (lasthist > 0) {
+ time_t keep = lasthist, keep1;
+ time(&now);
+ fprintf(argv->out,"Oldest history entry created: %s",(char*)ctime(&keep));
+ keep = Expiredays * 86400 * 2 + lasthist;
+ keep1 = keep - now ;
+ fprintf(argv->out,"Next time to maintain history: (%.2f days later) %s",(double)keep1/86400, (char*)ctime(&keep));
+ }
+ fprintf(argv->out,"PID is %d\r\n", getpid());
+ fprintf(argv->out,"LOCAL ONLY %d\r\n", LOCALNODELIST);
+ fprintf(argv->out,"NONE NEWSFEEDS %d\r\n", NONENEWSFEEDS);
+ fprintf(argv->out,"Max connections %d\r\n", Maxclient);
+#ifdef DEBUGCWD
+ getwd(cwdpath);
+ fprintf(argv->out,"Working directory %s\r\n", cwdpath);
+#endif
+ if (Channel)
+ for (i=0, j=0; i< Maxclient; ++i) {
+ if (Channel[i].fd == -1) continue;
+ if (Channel+i == client) continue;
+ j++;
+ fprintf(argv->out," %d) in->used %d, in->left %d %s@%s\r\n",i,
+ Channel[i].in.used, Channel[i].in.left,
+ Channel[i].username,Channel[i].hostname);
+ }
+ fprintf(argv->out,"Total connections %d\r\n", j);
+ fprintf(argv->out,"Total rec: %d dup: %d fail: %d size: %d, stat rec: %d fail: %d\n", client1->ihavecount, client1->ihaveduplicate, client1->ihavefail, client1->ihavesize, client1->statcount, client1->statfail);
+ fprintf(argv->out,".\r\n");
+ fflush(argv->out);
+ return 1;
+}
+
+static int
+CMDlistnodelist(client)
+ClientType *client;
+{
+ int nlcount;
+ argv_t *argv = &client->Argv;
+ buffer_t *in = &client->in;
+ daemoncmd_t *p = argv->dc;
+ if (!islocalconnect(client)) {
+ fprintf(argv->out,"%d listnodelist access denied\r\n", p->errorcode);
+ fflush(argv->out);
+ verboselog("Mallocmap Put: %d listnodelist access denied\n", p->errorcode);
+ return 1;
+ }
+ fprintf(argv->out,"%d listnodelist\r\n", p->normalcode);
+ for (nlcount =0; nlcount < NLCOUNT; nlcount++) {
+ nodelist_t *nl = NODELIST+nlcount;
+ fprintf(argv->out,"%2d %s /\\/\\ %s\r\n", nlcount+1, nl->node==NULL?"":nl->node, nl->exclusion==NULL?"":nl->exclusion);
+ fprintf(argv->out," %s:%s:%s\r\n",nl->host==NULL?"":nl->host, nl->protocol==NULL?"":nl->protocol, nl->comments == NULL ? "": nl->comments);
+ }
+ fprintf(argv->out,".\r\n");
+ fflush(argv->out);
+ verboselog("Listnodelist Put: %d listnodelist complete\n", p->normalcode);
+ return 1;
+}
+
+static int
+CMDlistnewsfeeds(client)
+ClientType *client;
+{
+ argv_t *argv = &client->Argv;
+ buffer_t *in = &client->in;
+ daemoncmd_t *p = argv->dc;
+ int nfcount;
+ if (!islocalconnect(client)) {
+ fprintf(argv->out,"%d listnewsfeeds access denied\r\n", p->errorcode);
+ fflush(argv->out);
+ verboselog("Mallocmap Put: %d listnewsfeeds access denied\n", p->errorcode);
+ return 1;
+ }
+ fprintf(argv->out,"%d listnewsfeeds\r\n", p->normalcode);
+ for (nfcount =0; nfcount < NFCOUNT; nfcount++) {
+ newsfeeds_t *nf = NEWSFEEDS + nfcount;
+ fprintf(argv->out,"%3d %s<=>%s\r\n",nfcount+1, nf->newsgroups, nf->board);
+ fprintf(argv->out," %s\r\n",nf->path==NULL?"(Null)":nf->path);
+ }
+ fprintf(argv->out,".\r\n");
+ fflush(argv->out);
+ verboselog("Listnewsfeeds Put: %d listnewsfeeds complete\n", p->normalcode);
+ return 1;
+}
+
+#ifdef MALLOCMAP
+static int CMDmallocmap(client)
+ClientType *client;
+{
+ argv_t *argv = &client->Argv;
+ buffer_t *in = &client->in;
+ daemoncmd_t *p = argv->dc;
+ struct rusage ru;
+ int savefd ;
+ if (!islocalconnect(client)) {
+ fprintf(argv->out,"%d mallocmap access denied\r\n", p->errorcode);
+ fflush(argv->out);
+ verboselog("Mallocmap Put: %d mallocmap access denied\n", p->errorcode);
+ return 1;
+ }
+ fprintf(argv->out,"%d mallocmap\r\n", p->normalcode);
+ savefd = dup(1);
+ dup2(client->fd, 1);
+ mallocmap();
+ dup2(savefd, 1);
+ close(savefd);
+ fprintf(argv->out,".\r\n");
+ fflush(argv->out);
+ verboselog("Mallocmap Put: %d mallocmap complete\n", p->normalcode);
+ return 1;
+}
+#endif
+
+#ifdef GETRUSAGE
+static int CMDgetrusage(client)
+ClientType *client;
+{
+ argv_t *argv = &client->Argv;
+ buffer_t *in = &client->in;
+ daemoncmd_t *p = argv->dc;
+ struct rusage ru;
+ if (!islocalconnect(client)) {
+ fprintf(argv->out,"%d getrusage access denied\r\n", p->errorcode);
+ fflush(argv->out);
+ verboselog("Getrusage Put: %d getrusage access denied\n", p->errorcode);
+ return 1;
+ }
+ fprintf(argv->out,"%d getrusage\r\n", p->normalcode);
+ if (getrusage(RUSAGE_SELF,&ru) == 0) {
+ fprintf(argv->out,"user time used: %.6f\r\n",(double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec/1000000.0);
+ fprintf(argv->out,"system time used: %.6f\r\n",(double)ru.ru_stime.tv_sec + (double)ru.ru_stime.tv_usec/1000000.0);
+ fprintf(argv->out,"maximum resident set size: %lu\r\n",ru.ru_maxrss * getpagesize());
+ fprintf(argv->out,"integral resident set size: %lu\r\n",ru.ru_idrss * getpagesize());
+ fprintf(argv->out,"page faults not requiring physical I/O: %d\r\n",ru.ru_minflt);
+ fprintf(argv->out,"page faults requiring physical I/O: %d\r\n",ru.ru_majflt);
+ fprintf(argv->out,"swaps: %d\r\n",ru.ru_nswap);
+ fprintf(argv->out,"block input operations: %d\r\n",ru.ru_inblock);
+ fprintf(argv->out,"block output operations: %d\r\n",ru.ru_oublock);
+ fprintf(argv->out,"messages sent: %d\r\n",ru.ru_msgsnd);
+ fprintf(argv->out,"messages received: %d\r\n",ru.ru_msgrcv);
+ fprintf(argv->out,"signals received: %d\r\n",ru.ru_nsignals);
+ fprintf(argv->out,"voluntary context switches: %d\r\n",ru.ru_nvcsw);
+ fprintf(argv->out,"involuntary context switches: %d\r\n",ru.ru_nivcsw);
+ }
+ fprintf(argv->out,".\r\n");
+ fflush(argv->out);
+ verboselog("Getrusage Put: %d getrusage complete\n", p->normalcode);
+ return 1;
+}
+
+#endif
+
+static int CMDhismaint(client)
+ClientType *client;
+{
+ argv_t *argv = &client->Argv;
+ buffer_t *in = &client->in;
+ daemoncmd_t *p = argv->dc;
+ if (!islocalconnect(client)) {
+ fprintf(argv->out,"%d hismaint access denied\r\n", p->errorcode);
+ fflush(argv->out);
+ verboselog("Hismaint Put: %d hismaint access denied\n", p->errorcode);
+ return 1;
+ }
+ verboselog("Hismaint Put: %d hismaint start\n", p->normalcode);
+ HISmaint();
+ fprintf(argv->out,"%d hismaint complete\r\n", p->normalcode);
+ fflush(argv->out);
+ verboselog("Hismaint Put: %d hismaint complete\n", p->normalcode);
+ return 1;
+}
+
+static int CMDreload(client)
+ClientType *client;
+{
+ argv_t *argv = &client->Argv;
+ buffer_t *in = &client->in;
+ daemoncmd_t *p = argv->dc;
+ if (!islocalconnect(client)) {
+ fprintf(argv->out,"%d reload access denied\r\n", p->errorcode);
+ fflush(argv->out);
+ verboselog("Reload Put: %d reload access denied\n", p->errorcode);
+ return 1;
+ }
+ initial_bbs("feed");
+ fprintf(argv->out,"%d reload complete\r\n", p->normalcode);
+ fflush(argv->out);
+ verboselog("Reload Put: %d reload complete\n", p->normalcode);
+ return 1;
+}
+
+static int CMDverboselog(client)
+ClientType *client;
+{
+ argv_t *argv = &client->Argv;
+ buffer_t *in = &client->in;
+ daemoncmd_t *p = argv->dc;
+ if (!islocalconnect(client)) {
+ fprintf(argv->out,"%d verboselog access denied\r\n", p->errorcode);
+ fflush(argv->out);
+ verboselog("Reload Put: %d verboselog access denied\n", p->errorcode);
+ return 1;
+ }
+ if (client->mode == 0) {
+ if (argv->argc > 1) {
+ if (strcasecmp(argv->argv[1],"off")==0) {
+ setverboseoff();
+ } else {
+ setverboseon();
+ }
+ }
+ }
+ fprintf(argv->out,"%d verboselog %s\r\n",p->normalcode,
+ isverboselog() ?"ON":"OFF");
+ fflush(argv->out);
+ verboselog("%d verboselog %s\r\n",p->normalcode,
+ isverboselog()?"ON":"OFF");
+}
+
+static int CMDmidcheck(client)
+ClientType *client;
+{
+ argv_t *argv = &client->Argv;
+ buffer_t *in = &client->in;
+ daemoncmd_t *p = argv->dc;
+ if (client->mode == 0) {
+ if (argv->argc > 1) {
+ if (strcasecmp(argv->argv[1],"off")==0) {
+ client->midcheck = 0;
+ } else {
+ client->midcheck = 1;
+ }
+ }
+ }
+ fprintf(argv->out,"%d mid check %s\r\n",p->normalcode,
+ client->midcheck == 1?"ON":"OFF");
+ fflush(argv->out);
+ verboselog("%d mid check %s\r\n",p->normalcode,
+ client->midcheck == 1?"ON":"OFF");
+}
+
+static int CMDgrephist(client)
+ClientType *client;
+{
+ argv_t *argv = &client->Argv;
+ buffer_t *in = &client->in;
+ daemoncmd_t *p = argv->dc;
+ if (client->mode == 0) {
+ if (argv->argc > 1) {
+ char *ptr;
+ ptr = (char*)DBfetch(argv->argv[1]);
+ if (ptr != NULL) {
+ fprintf(argv->out,"%d %s OK\r\n", p->normalcode, ptr);
+ fflush(argv->out);
+ verboselog("Addhist Put: %d %s OK\n", p->normalcode, ptr);
+ return 0;
+ } else {
+ fprintf(argv->out,"%d %s not found\r\n", p->errorcode,argv->argv[1]);
+ fflush(argv->out);
+ verboselog("Addhist Put: %d %s not found\n", p->errorcode, argv->argv[1]);
+ return 1;
+ }
+ }
+ }
+ fprintf(argv->out,"%d grephist error\r\n", p->errorcode);
+ fflush(argv->out);
+ verboselog("Addhist Put: %d grephist error\n", p->errorcode);
+ return 1;
+}
+
+
+static int CMDaddhist(client)
+ClientType *client;
+{
+ argv_t *argv = &client->Argv;
+ buffer_t *in = &client->in;
+ daemoncmd_t *p = argv->dc;
+ /*
+ if (strcmp(client->username,"localuser") != 0 ||
+ strcmp(client->hostname,"localhost") != 0) {
+ fprintf(argv->out,"%d add hist access denied\r\n", p->errorcode);
+ fflush(argv->out);
+ verboselog("Addhist Put: %d add hist access denied\n", p->errorcode);
+ return 1;
+ }
+ */
+ if (client->mode == 0) {
+ if (argv->argc > 2) {
+ char *ptr;
+ ptr = (char*)DBfetch(argv->argv[1]);
+ if (ptr == NULL) {
+ if (storeDB(argv->argv[1], argv->argv[2]) < 0) {
+ fprintf(argv->out,"%d add hist store DB error\r\n", p->errorcode);
+ fflush(argv->out);
+ verboselog("Addhist Put: %d add hist store DB error\n", p->errorcode);
+ return 1;
+ } else {
+ fprintf(argv->out,"%d add hist OK\r\n", p->normalcode);
+ fflush(argv->out);
+ verboselog("Addhist Put: %d add hist OK\n", p->normalcode);
+ return 0;
+ }
+ } else {
+ fprintf(argv->out,"%d add hist duplicate error\r\n", p->errorcode);
+ fflush(argv->out);
+ verboselog("Addhist Put: %d add hist duplicate error\n", p->errorcode);
+ return 1;
+ }
+ }
+ }
+ fprintf(argv->out,"%d add hist error\r\n", p->errorcode);
+ fflush(argv->out);
+ verboselog("Addhist Put: %d add hist error\n", p->errorcode);
+ return 1;
+}
+
+static int CMDstat(client)
+ClientType *client;
+{
+ argv_t *argv = &client->Argv;
+ char *ptr, *frontptr;
+ buffer_t *in = &client->in;
+ daemoncmd_t *p;
+ if (client->mode == 0) {
+ client->statcount++;
+ if (argv->argc > 1) {
+ if (argv->argv[1][0] != '<') {
+ fprintf(argv->out,"430 No such article\r\n");
+ fflush(argv->out);
+ verboselog("Stat Put: 430 No such article\n");
+ client->statfail++;
+ return 0;
+ }
+ ptr = (char*)DBfetch(argv->argv[1]);
+ if (ptr != NULL) {
+ fprintf(argv->out,"223 0 status %s\r\n",argv->argv[1]);
+ fflush(argv->out);
+ client->mode = 0;
+ verboselog("Stat Put: 223 0 status %s\n",argv->argv[1]);
+ return 1;
+ } else {
+ fprintf(argv->out,"430 No such article\r\n");
+ fflush(argv->out);
+ verboselog("Stat Put: 430 No such article\n");
+ client->mode = 0;
+ client->statfail++;
+ }
+ }
+ }
+}
+
+#ifndef DBZSERVER
+static int CMDihave(client)
+ClientType *client;
+{
+ argv_t *argv = &client->Argv;
+ char *ptr=NULL, *frontptr;
+ buffer_t *in = &client->in;
+ daemoncmd_t *p;
+ if (client->mode == 0) {
+ client->ihavecount++;
+ if (argv->argc > 1) {
+ if (argv->argv[1][0] != '<') {
+ fprintf(argv->out,"435 Bad Message-ID\r\n");
+ fflush(argv->out);
+ verboselog("Ihave Put: 435 Bad Message-ID\n");
+ client->ihavefail++;
+ return 0;
+ }
+ if (client->midcheck == 1)
+ ptr = (char*)DBfetch(argv->argv[1]);
+ if (ptr != NULL && client->midcheck == 1) {
+ fprintf(argv->out,"435 Duplicate\r\n");
+ fflush(argv->out);
+ client->mode = 0;
+ verboselog("Ihave Put: 435 Duplicate\n");
+ client->ihaveduplicate++;
+ client->ihavefail++;
+ return 1;
+ } else {
+ fprintf(argv->out,"335\r\n");
+ fflush(argv->out);
+ client->mode = 1;
+ verboselog("Ihave Put: 335\n");
+ }
+ }
+ } else {
+ client->mode = 0;
+ readlines(client);
+ if (HEADER[SUBJECT_H] && HEADER[FROM_H] && HEADER[DATE_H] &&
+ HEADER[MID_H] && HEADER[NEWSGROUPS_H] ) {
+ char *path1, *path2;
+ int rel ;
+ rel = 0;
+ path1 = (char*)mymalloc(strlen(HEADER[PATH_H]) + 3);
+ path2 = (char*)mymalloc(strlen(MYBBSID) + 3);
+ sprintf(path1, "!%s!",HEADER[PATH_H]);
+ sprintf(path2, "!%s!",MYBBSID);
+ if (HEADER[CONTROL_H]) {
+ bbslog( "Control: %s\n", HEADER[CONTROL_H] );
+ if (strncasecmp(HEADER[CONTROL_H],"cancel ",7)==0) {
+ rel = cancel_article_front(HEADER[CONTROL_H]+7);
+ } else {
+ rel = receive_control();
+ }
+ } else if ( (char*)strstr(path1, path2) != NULL) {
+ bbslog( ":Warn: Loop back article: %s!%s\n",MYBBSID,HEADER[PATH_H] );
+ } else {
+ rel = receive_article();
+ }
+ free(path1);
+ free(path2);
+ if (rel == -1) {
+ fprintf(argv->out,"400 server side failed\r\n");
+ fflush(argv->out);
+ verboselog("Ihave Put: 400\n");
+ clearfdset(client->fd);
+ fclose(client->Argv.in);
+ fclose(client->Argv.out);
+ close(client->fd);
+ client->fd = -1;
+ client->mode = 0;
+ client->ihavefail++;
+ return;
+ } else {
+ fprintf(argv->out,"235\r\n");
+ verboselog("Ihave Put: 235\n");
+ }
+ fflush(argv->out);
+ } else if (!HEADER[PATH_H]) {
+ fprintf(argv->out,"437 No Path in \"ihave %s\" header\r\n",HEADER[MID_H]);
+ fflush(argv->out);
+ verboselog("Put: 437 No Path in \"ihave %s\" header\n",HEADER[MID_H]);
+ client->ihavefail++;
+ } else {
+ fprintf(argv->out,"437 No colon-space in \"ihave %s\" header\r\n",HEADER[MID_H]);
+ fflush(argv->out);
+ verboselog("Ihave Put: 437 No colon-space in \"ihave %s\" header\n",HEADER[MID_H]);
+ client->ihavefail++;
+ }
+#ifdef DEBUG
+ printf("subject is %s\n",HEADER[SUBJECT_H]);
+ printf("from is %s\n",HEADER[FROM_H]);
+ printf("Date is %s\n",HEADER[DATE_H]);
+ printf("Newsgroups is %s\n",HEADER[NEWSGROUPS_H]);
+ printf("mid is %s\n",HEADER[MID_H]);
+ printf("path is %s\n",HEADER[PATH_H]);
+#endif
+ }
+ fflush(argv->out);
+ return 0;
+}
+#endif
+
+static int CMDhelp(client)
+ClientType *client;
+{
+ argv_t *argv = &client->Argv;
+ daemoncmd_t *p;
+ if (argv->argc>=1) {
+ fprintf(argv->out,"%d Available Commands\r\n",argv->dc->normalcode);
+ for (p=cmds;p->name !=NULL;p++) {
+ fprintf(argv->out," %s\r\n",p->usage);
+ }
+ fprintf(argv->out,"Report problems to %s\r\n",ADMINUSER);
+ }
+ fputs(".\r\n",argv->out);
+ fflush(argv->out);
+ client->mode = 0;
+ return 0;
+}
+
+static int CMDquit(client)
+ClientType *client;
+{
+ argv_t *argv = &client->Argv;
+ fprintf(argv->out,"205 quit\r\n");
+ fflush(argv->out);
+ verboselog("Quit Put: 205 quit\n");
+ clearfdset(client->fd);
+ fclose(client->Argv.in);
+ fclose(client->Argv.out);
+ close(client->fd);
+ client->fd = -1;
+ client->mode = 0;
+ channeldestroy(client);
+ /*exit(0);*/
+}
diff --git a/innbbsd/innbbsd.h b/innbbsd/innbbsd.h
new file mode 100644
index 00000000..ba667ee6
--- /dev/null
+++ b/innbbsd/innbbsd.h
@@ -0,0 +1,9 @@
+#ifndef INNBBSD_H
+#define INNBBSD_H
+#include "daemon.h"
+
+#ifndef ADMINUSER
+# define ADMINUSER "usenet@csie.nctu.edu.tw"
+#endif
+
+#endif
diff --git a/innbbsd/inndchannel.c b/innbbsd/inndchannel.c
new file mode 100644
index 00000000..439b2af0
--- /dev/null
+++ b/innbbsd/inndchannel.c
@@ -0,0 +1,657 @@
+#include "innbbsconf.h"
+#include "daemon.h"
+#include "bbslib.h"
+#include "config.h"
+
+#define DEBUG
+#undef DEBUG
+
+#ifndef MAXCLIENT
+#define MAXCLIENT 500
+#endif
+
+#ifndef ChannelSize
+#define ChannelSize 4096
+#endif
+
+#ifndef ReadSize
+#define ReadSize 1024
+#endif
+
+#ifndef DefaultINNBBSPort
+# define DefaultINNBBSPort "7777"
+#endif
+
+#ifndef HIS_MAINT
+# define HIS_MAINT
+# define HIS_MAINT_HOUR 5
+# define HIS_MAINT_MIN 30
+#endif
+
+int Maxclient=MAXCLIENT;
+ClientType *Channel=NULL;
+ClientType INNBBSD_STAT;
+
+int Max_Art_Size = MAX_ART_SIZE;
+
+int inetdstart = 0;
+
+int Junkhistory = 0;
+
+char *REMOTEUSERNAME, *REMOTEHOSTNAME;
+
+static fd_set rfd,wfd,efd,orfd,owfd,oefd;
+
+clearfdset(fd)
+int fd;
+{
+ FD_CLR(fd,&rfd);
+}
+
+static
+channelcreate(client)
+ClientType *client;
+{
+ buffer_t *in, *out;
+ in = &client->in;
+ out = &client->out;
+ if (in->data != NULL)
+ free(in->data);
+ in->data = (char*)mymalloc( ChannelSize );
+ in->left = ChannelSize;
+ in->used = 0;
+ if (out->data != NULL)
+ free(out->data);
+ out->data = (char*)mymalloc( ChannelSize );
+ out->used = 0;
+ out->left = ChannelSize;
+ client->ihavecount = 0;
+ client->ihaveduplicate = 0;
+ client->ihavefail = 0;
+ client->ihavesize = 0;
+ client->statcount = 0;
+ client->statfail = 0;
+ client->begin = time(NULL);
+}
+
+channeldestroy(client)
+ClientType *client;
+{
+ 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;
+ }
+#if !defined(PowerBBS) && !defined(DBZSERVER)
+ if (client->ihavecount >0 || client->statcount >0) {
+ bbslog("%s@%s rec: %d dup: %d fail: %d size: %d, stat rec: %d fail: %d, time sec: %d\n",
+ client->username, client->hostname, client->ihavecount,
+ client->ihaveduplicate, client->ihavefail, client->ihavesize,
+ client->statcount, client->statfail, time(NULL) - client->begin);
+ INNBBSD_STAT.ihavecount += client->ihavecount;
+ INNBBSD_STAT.ihaveduplicate += client->ihaveduplicate;
+ INNBBSD_STAT.ihavefail += client->ihavefail;
+ INNBBSD_STAT.ihavesize += client->ihavesize;
+ INNBBSD_STAT.statcount += client->statcount;
+ INNBBSD_STAT.statfail += client->statfail;
+ }
+#endif
+}
+
+inndchannel(port, path)
+char *port, *path;
+{
+ time_t tvec;
+ int i;
+ int bbsinnd ;
+ int localbbsinnd;
+ char obuf[4096];
+ struct timeval tout;
+ ClientType *client = (ClientType *)mymalloc( sizeof(ClientType) * Maxclient);
+ int localdaemonready = 0;
+ Channel = client;
+
+ bbsinnd = pmain(port);
+ if (bbsinnd < 0) {
+ perror("pmain, existing");
+ docompletehalt();
+ return(-1);
+ }
+
+ FD_ZERO(&rfd); FD_ZERO(&wfd); FD_ZERO(&efd);
+
+ localbbsinnd = p_unix_main(path);
+ if (localbbsinnd < 0) {
+ perror("local pmain, existing");
+/* Kaede
+ if (!inetdstart)
+ fprintf(stderr, "if no other innbbsd running, try to remove %s\n",path);
+*/
+ close(bbsinnd);
+ return(-1);
+ } else {
+ FD_SET(localbbsinnd,&rfd);
+ localdaemonready = 1;
+ }
+
+ FD_SET(bbsinnd,&rfd);
+ tvec = time((time_t *)0);
+ for (i=0;i< Maxclient ;++i) {
+ client[i].fd = -1;
+ client[i].access=0;
+ client[i].buffer[0] = '\0';
+ client[i].mode = 0;
+ client[i].in.left = 0;
+ client[i].in.used = 0;
+ client[i].in.data = NULL;
+ client[i].out.left = 0;
+ client[i].out.used = 0;
+ client[i].out.data = NULL;
+ client[i].midcheck = 1;
+ }
+ for (;;) {
+ int nsel,i;
+
+/*
+ When to maintain history files.
+*/
+ time_t now;
+ static int maint = 0;
+ struct tm *local;
+
+ if (INNBBSDshutdown()) {
+ HISclose();
+ bbslog(" Shutdown Complete \n");
+ docompletehalt();
+ exit(0);
+ }
+
+ time(&now);
+ local = localtime(&now);
+ if (local != NULL & local->tm_hour == His_Maint_Hour &&
+ local->tm_min >= His_Maint_Min ) {
+ if (!maint) {
+ bbslog(":Maint: start (%d:%d).\n",local->tm_hour,local->tm_min);
+ HISmaint();
+ time(&now);
+ local = localtime(&now);
+ if (local != NULL)
+ bbslog(":Maint: end (%d:%d).\n",local->tm_hour,local->tm_min);
+ maint = 1;
+ }
+ } else {
+ maint = 0;
+ }
+/*
+*/
+/*
+ in order to maintain history, timeout every 60 seconds in case
+ no connections
+*/
+ tout.tv_sec = 60;
+ tout.tv_usec = 0;
+ orfd = rfd;
+ if ((nsel=select(FD_SETSIZE,&orfd, NULL , NULL , &tout))<0){
+ continue;
+ }
+ if (localdaemonready && FD_ISSET(localbbsinnd,&orfd)) {
+ int ns,length;
+ int cc;
+ ns=tryaccept(localbbsinnd);
+ if (ns < 0) continue;
+ for (i=0;i< Maxclient ;++i) {
+ if (client[i].fd==-1) break;
+ }
+ if (i== Maxclient) {
+ static char msg[]="502 no free descriptors\r\n";
+ printf("%s",msg);
+ write(ns, msg, sizeof(msg));
+ close(ns);
+ continue;
+ }
+ client[i].fd=ns;
+ client[i].buffer[0] = '\0';
+ client[i].mode = 0;
+ client[i].midcheck = 1;
+ channelcreate(&client[i]);
+ FD_SET(ns,&rfd); /*FD_SET(ns,&wfd);*/
+ {
+ strncpy(client[i].username,"localuser",20);
+ strncpy(client[i].hostname,"localhost",128);
+ client[i].Argv.in = fdopen( ns,"r");
+ client[i].Argv.out = fdopen( ns,"w");
+#if !defined(PowerBBS) && !defined(DBZSERVER)
+ bbslog("connected from (%s@%s).\n",client[i].username, client[i].hostname);
+#endif
+#ifdef INNBBSDEBUG
+ printf("connected from (%s@%s).\n",client[i].username, client[i].hostname);
+#endif
+#ifdef DBZSERVER
+ fprintf(client[i].Argv.out,"200 %s InterNetNews DBZSERVER server %s (%s@%s).\r\n",MYBBSID, VERSION, client[i].username, client[i].hostname);
+#else
+ fprintf(client[i].Argv.out,"200 %s InterNetNews INNBBSD server %s (%s@%s).\r\n", MYBBSID, VERSION, client[i].username, client[i].hostname );
+#endif
+ fflush(client[i].Argv.out);
+ verboselog("UNIX Connect from %s@%s\n",client[i].username, client[i].hostname);
+ }
+ }
+
+ if (FD_ISSET(bbsinnd,&orfd)) {
+ int ns=tryaccept(bbsinnd), length;
+ struct sockaddr_in there;
+ char *name;
+ struct hostent *hp;
+ int cc;
+ if (ns < 0) continue;
+ for (i=0;i< Maxclient ;++i) {
+ if (client[i].fd==-1) break;
+ }
+ if (i== Maxclient) {
+ static char msg[]="502 no free descriptors\r\n";
+ printf("%s",msg);
+ write(ns, msg, sizeof(msg));
+ close(ns);
+ continue;
+ }
+ client[i].fd=ns;
+ client[i].buffer[0] = '\0';
+ client[i].mode = 0;
+ client[i].midcheck = 1;
+ channelcreate(&client[i]);
+ FD_SET(ns,&rfd); /*FD_SET(ns,&wfd);*/
+ length = sizeof(there);
+ if (getpeername(ns,(struct sockaddr *)&there,&length)>=0){
+ time_t now=time((time_t *)0);
+ name=(char*)my_rfc931_name(ns,&there);
+ strncpy(client[i].username,name,20);
+ hp = (struct hostent*)gethostbyaddr((char*)&there.sin_addr, sizeof (struct in_addr), there.sin_family);
+ if (hp)
+ strncpy(client[i].hostname,hp->h_name,128);
+ else
+ strncpy(client[i].hostname,(char*)inet_ntoa(there.sin_addr),128);
+
+ client[i].Argv.in = fdopen( ns,"r");
+ client[i].Argv.out = fdopen( ns,"w");
+ if ((char*)search_nodelist(client[i].hostname,client[i].username) == NULL) {
+ bbslog(":Err: invalid connection (%s@%s).\n",client[i].username, client[i].hostname);
+ fprintf(client[i].Argv.out,"502 You are not in my access file. (%s@%s)\r\n", client[i].username, client[i].hostname);
+ fflush(client[i].Argv.out);
+ fclose(client[i].Argv.in);
+ fclose(client[i].Argv.out);
+ close(client[i].fd);
+ FD_CLR(client[i].fd,&rfd);
+ client[i].fd = -1;
+ continue;
+ }
+ bbslog("connected from (%s@%s).\n",client[i].username, client[i].hostname);
+#ifdef INNBBSDEBUG
+ printf("connected from (%s@%s).\n",client[i].username, client[i].hostname);
+#endif
+#ifdef DBZSERVER
+ fprintf(client[i].Argv.out,"200 %s InterNetNews DBZSERVER server %s (%s@%s).\r\n",MYBBSID, VERSION, client[i].username, client[i].hostname );
+#else
+ fprintf(client[i].Argv.out,"200 %s InterNetNews INNBBSD server %s (%s@%s).\r\n",MYBBSID, VERSION, client[i].username, client[i].hostname );
+#endif
+ fflush(client[i].Argv.out);
+ verboselog("INET Connect from %s@%s\n",client[i].username, client[i].hostname);
+ } else {
+ }
+
+ }
+ for (i=0;i< Maxclient ;++i) {
+ int fd=client[i].fd;
+ if (fd < 0) {
+ continue;
+ }
+ if (FD_ISSET(fd,&orfd)) {
+ int nr;
+#ifdef DEBUG
+ printf("before read i %d in.used %d in.left %d\n",i,client[i].in.used, client[i].in.left);
+#endif
+ nr=channelreader(client+i);
+#ifdef DEBUG
+ printf("after read i %d in.used %d in.left %d\n",i,client[i].in.used, client[i].in.left);
+#endif
+ /*int nr=read(fd,client[i].buffer,1024);*/
+ if (nr <= 0) {
+ FD_CLR(fd,&rfd);
+ fclose(client[i].Argv.in);
+ fclose(client[i].Argv.out);
+ close(fd);
+ client[i].fd = -1;
+ channeldestroy(client+i);
+ continue;
+ }
+#ifdef DEBUG
+ printf("nr %d %.*s", nr, nr, client[i].buffer);
+#endif
+ if (client[i].access==0) {
+ continue;
+ }
+ }
+ }
+ }
+}
+
+int channelreader(client)
+ClientType *client;
+{
+ int len, clientlen;
+ char buffer1[8192], buffer2[4096];
+ char *ptr;
+ buffer_t *in = &client->in;
+
+ if (in->left < ReadSize+3) {
+ int need = in->used + in->left + ReadSize + 3;
+ need += need/5 ;
+ in->data = (char*)myrealloc(in->data, need);
+ in->left = need - in->used;
+ verboselog("channelreader realloc %d\n",need);
+ }
+ len = read(client->fd, in->data+in->used, ReadSize);
+
+ if (len <=0) return len;
+
+ in->data[len+in->used] = '\0';
+ in->lastread = len;
+#ifdef DEBUG
+ printf("after read lastread %d\n", in->lastread);
+ printf("len %d client %d\n", len, strlen(in->data+in->used));
+#endif
+
+ REMOTEHOSTNAME = client->hostname;
+ REMOTEUSERNAME = client->username;
+ if (client->mode == 0) {
+ if ( (ptr=(char*)strchr(in->data,'\n')) != NULL) {
+ if (in->data[0] != '\r')
+ commandparse(client);
+ }
+ } else {
+ commandparse(client);
+ }
+ return len;
+}
+
+commandparse(client)
+ClientType *client;
+{
+ char *ptr, *lastend;
+ argv_t *Argv = &client->Argv;
+ int (*Main)();
+ char *buffer = client->in.data;
+ int fd = client->fd;
+ buffer_t *in = &client->in;
+ int dataused;
+ int dataleft;
+
+#ifdef DEBUG
+ printf("%s %s buffer %s",client->username, client->hostname, buffer);
+#endif
+ ptr= (char*) strchr(in->data+in->used,'\n');
+ if (client->mode == 0) {
+ if (ptr == NULL) {
+ in->used += in->lastread;
+ in->left -= in->lastread;
+ return;
+ } else {
+ dataused = ptr - (in->data + in->used) + 1;
+ dataleft = in->lastread - dataused;
+ lastend = ptr + 1;
+ }
+ } else {
+ if (in->used >= 5) {
+ ptr = (char*) strstr(in->data+in->used-5,"\r\n.\r\n");
+ } else if (strncmp(in->data,".\r\n",3)==0) {
+ ptr = in->data;
+ } else {
+ ptr = (char*) strstr(in->data+in->used,"\r\n.\r\n");
+ }
+ if (ptr == NULL) {
+ in->used += in->lastread;
+ in->left -= in->lastread;
+ return;
+ } else {
+ ptr[2]='\0';
+ if ( strncmp(in->data,".\r\n",3)==0)
+ dataused = 3;
+ else
+ dataused = ptr - (in->data + in->used) + 5;
+ dataleft = in->lastread - dataused;
+ lastend = ptr + 5;
+ verboselog("Get: %s@%s end of data . size %d\n", client->username, client->hostname, in->used + dataused);
+ client->ihavesize += in->used + dataused;
+ }
+ }
+ if (client->mode == 0) {
+ struct Daemoncmd * dp;
+ Argv->argc = 0, Argv->argv = NULL,
+ Argv->inputline= buffer;
+ if ( ptr != NULL) *ptr = '\0';
+ verboselog("Get: %s\n",Argv->inputline);
+ Argv->argc = argify( in->data + in->used,&Argv->argv);
+ if ( ptr != NULL) *ptr = '\n';
+ dp = (struct Daemoncmd *) searchcmd(Argv->argv[0]);
+ Argv->dc = dp;
+ if (Argv->dc) {
+#ifdef DEBUG
+ printf("enter command %s\n",Argv->argv[0]);
+#endif
+ if (Argv->argc < dp->argc) {
+ fprintf(Argv->out,"%d Usage: %s\r\n",dp->errorcode,dp->usage);
+ fflush(Argv->out);
+ verboselog("Put: %d Usage: %s\n",dp->errorcode,dp->usage);
+ } else if (dp->argno != 0 && Argv->argc > dp->argno) {
+ fprintf(Argv->out,"%d Usage: %s\r\n",dp->errorcode,dp->usage);
+ fflush(Argv->out);
+ verboselog("Put: %d Usage: %s\n",dp->errorcode,dp->usage);
+ } else {
+ Main=Argv->dc->main;
+ if (Main) {
+ fflush(stdout);
+ (*Main)(client);
+ }
+ }
+ } else {
+ fprintf(Argv->out,"500 Syntax error or bad command\r\n");
+ fflush(Argv->out);
+ verboselog("Put: 500 Syntax error or bad command\r\n");
+ }
+ deargify(&Argv->argv);
+ } else {
+ if (Argv->dc) {
+#ifdef DEBUG
+ printf("enter data mode\n");
+#endif
+ Main=Argv->dc->main;
+ if (Main) {
+ fflush(stdout);
+ (*Main)(client);
+ }
+ }
+ }
+ if (client->mode == 0) {
+ if (dataleft > 0) {
+ strncpy(in->data, lastend, dataleft);
+#ifdef INNBBSDEBUG
+ printf("***** try to copy %x %x %d bytes\n",in->data, lastend, dataleft);
+#endif
+ } else {
+ dataleft = 0;
+ }
+ in->left += in->used - dataleft;
+ in->used = dataleft;
+ }
+}
+
+do_command()
+{
+}
+
+void dopipesig(s)
+int s;
+{
+ printf("catch sigpipe\n");
+ signal(SIGPIPE, dopipesig);
+}
+
+int standaloneinit(port)
+char *port ;
+{
+ int ndescriptors;
+ FILE *pf;
+ char pidfile[24];
+ ndescriptors = getdtablesize();
+/*#ifndef NOFORK*/
+ if (!inetdstart)
+ if (fork())
+ exit(0);
+/*#endif*/
+
+ sprintf(pidfile,"/tmp/innbbsd-%s.pid",port);
+/* Kaede
+ if (!inetdstart)
+ fprintf(stderr, "PID file is in %s\n", pidfile);
+*/
+ { int s;
+ for (s = 3; s < ndescriptors; s++)
+ (void) close(s);
+ }
+ pf=fopen(pidfile,"w");
+ if (pf != NULL) {
+ fprintf(pf,"%d\n",getpid());
+ fclose(pf);
+ }
+}
+
+extern char *optarg;
+extern int opterr, optind;
+
+innbbsusage(name)
+char *name;
+{
+ fprintf(stderr,"Usage: %s [options] [port [path]]\n",name);
+ fprintf(stderr," -v (verbose log)\n");
+ fprintf(stderr," -h|? (help)\n");
+ fprintf(stderr," -n (not to use in core dbz)\n");
+ fprintf(stderr," -i (start from inetd with wait option)\n");
+ fprintf(stderr," -c connections (maximum number of connections accepted)\n");
+ fprintf(stderr," default=%d\n",Maxclient);
+ fprintf(stderr," -j (keep history of junk article, default=none)\n");
+}
+
+
+#ifdef DEBUGNGSPLIT
+main()
+{
+ char **ngptr ;
+ char buf[1024];
+ gets(buf);
+ ngptr = (char**)BNGsplit(buf);
+ printf("line %s\n",buf);
+ while ( *ngptr != NULL) {
+ printf("%s\n",*ngptr);
+ ngptr++;
+ }
+}
+#endif
+
+static time_t INNBBSDstartup;
+innbbsdstartup()
+{
+ return INNBBSDstartup;
+}
+
+main(argc,argv)
+int argc;
+char **argv;
+{
+
+ char *port, *path;
+ int c, errflag=0;
+ extern INNBBSDhalt();
+/*
+woju
+*/
+ setgid(BBSGID);
+ setuid(BBSUID);
+ chdir(BBSHOME);
+ resolve_boards();
+
+ port = DefaultINNBBSPort;
+ path = LOCALDAEMON;
+ Junkhistory = 0;
+
+ time(&INNBBSDstartup);
+ openlog("innbbsd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
+ while ((c = getopt(argc,argv,"c:f:s:vhidn?j"))!= -1)
+ switch (c) {
+ case 'j':
+ Junkhistory = 1;
+ break;
+ case 'v':
+ verboseon("innbbsd.log");
+ break;
+ case 'n':
+ hisincore(0);
+ break;
+ case 'c':
+ Maxclient = atoi(optarg);
+ if (Maxclient < 0) Maxclient = 0;
+ break;
+ case 'i': {
+ struct sockaddr_in there;
+ int len = sizeof(there);
+ int rel;
+ if ((rel=getsockname(0,(struct sockaddr *)&there,&len))< 0){
+ fprintf(stdout,"You must run -i from inetd with inetd.conf line: \n");
+ fprintf(stdout,"service-port stream tcp wait bbs /home/bbs/innbbsd innbbsd -i port\n");
+ fflush(stdout);
+ exit(5);
+ }
+ inetdstart = 1;
+ startfrominetd(1);
+ }
+ break;
+ case 'd':
+ dbzdebug(1);
+ break;
+ case 's':
+ Max_Art_Size = atol(optarg);
+ if (Max_Art_Size < 0) Max_Art_Size = 0;
+ break;
+ case 'h':
+ case '?':
+ default:
+ errflag ++;
+ }
+ if (errflag > 0) {
+ innbbsusage(argv[0]);
+ return(1);
+ }
+ if (argc - optind >= 1) {
+ port = argv[optind];
+ }
+ if (argc - optind >= 2) {
+ path = argv[optind+1];
+ }
+
+ standaloneinit(port);
+
+ initial_bbs("feed");
+
+/* Kaede
+ if (!inetdstart)
+ fprintf(stderr, "Try to listen in port %s and path %s\n", port, path);
+*/
+ HISmaint();
+ HISsetup();
+ installinnbbsd();
+ sethaltfunction(INNBBSDhalt);
+
+ signal(SIGPIPE, dopipesig);
+ inndchannel(port, path);
+ HISclose();
+}
diff --git a/innbbsd/inntobbs.c b/innbbsd/inntobbs.c
new file mode 100644
index 00000000..b57d8bb1
--- /dev/null
+++ b/innbbsd/inntobbs.c
@@ -0,0 +1,323 @@
+#include <stdio.h>
+#include "daemon.h"
+#include "bbslib.h"
+#include <time.h>
+
+#define INNTOBBS
+#include "inntobbs.h"
+
+typedef struct Header {
+ char *name;
+ int id;
+} header_t;
+
+/*enum HeaderValue {
+SUBJECT_H, FROM_H, DATE_H, MID_H, NEWSGROUPS_H,
+NNTPPOSTINGHOST_H, NNTPHOST_H, CONTROL_H, PATH_H,
+ORGANIZATION_H, LASTHEADER,
+};
+*/
+
+char *strchr ARG((char*,int));
+char *strrchr ARG((char*,int));
+char *strstr ARG((char*,char*));
+
+header_t headertable[] = {
+"Subject" ,SUBJECT_H,
+"From" ,FROM_H,
+"Date" ,DATE_H,
+"Message-ID",MID_H,
+"Newsgroups",NEWSGROUPS_H,
+"NNTP-Posting-Host",NNTPPOSTINGHOST_H,
+"NNTP-Host", NNTPHOST_H,
+"Control", CONTROL_H,
+"Path", PATH_H,
+"Organization", ORGANIZATION_H,
+"X-Auth-From", X_Auth_From_H,
+"Approved", APPROVED_H,
+"Distribution", DISTRIBUTION_H,
+"Keywords", KEYWORDS_H,
+"Summary", SUMMARY_H,
+"References",REFERENCES_H,
+};
+
+char *HEADER[LASTHEADER];
+char *BODY;
+char *FROM, *SUBJECT, *SITE, *DATE, *POSTHOST,
+ *NNTPHOST, *PATH, *GROUPS, *MSGID, *CONTROL;
+
+#ifdef PalmBBS
+char **XHEADER;
+char *XPATH;
+#endif
+
+
+int
+isexcluded(path1, nl)
+char *path1;
+nodelist_t *nl;
+{
+ char path2[1024];
+ /*path2 = (char*)mymalloc(strlen(nl->node) + 3);*/
+ sprintf(path2, "!%.*s!",sizeof path2 - 3, nl->node);
+ if (strstr(path1, path2) != NULL) return 1;
+ if (nl->exclusion && *nl->exclusion) {
+ char *exclude, *ptr;
+ for (exclude = nl->exclusion, ptr = strchr(exclude,',');
+ exclude && *exclude; ptr = strchr(exclude,',')) {
+ if (ptr) *ptr = '\0';
+ sprintf(path2, "!%.*s!",sizeof path2 - 3, exclude);
+ if (strstr(path1, path2) != NULL) return 1;
+ if (ptr) {
+ *ptr = ',';
+ exclude = ptr+1;
+ } else {
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+feedfplog(nf, filepath, type)
+newsfeeds_t *nf;
+char *filepath;
+int type;
+{
+ char *path1, *path2, *hostptr;
+ nodelist_t *nl;
+ if (nf == NULL) return;
+ if( nf->path != NULL ) {
+ char *ptr1, *ptr2;
+ char savech;
+ path1 = (char*)mymalloc(strlen(HEADER[PATH_H]) + 3);
+ sprintf(path1, "!%s!",HEADER[PATH_H]);
+ for (ptr1 = nf->path; ptr1 && *ptr1;) {
+ for (; *ptr1 && isspace(*ptr1); ptr1++);
+ if (!*ptr1) break;
+ for (ptr2 = ptr1; *ptr2 && !isspace(*ptr2); ptr2++);
+ savech = *ptr2;
+ *ptr2 = '\0';
+ /*
+ bbslog("search node %s\n",ptr1);
+ */
+ nl = (nodelist_t*) search_nodelist_bynode(ptr1);
+ /*
+ bbslog("search node node %s, host %s fp %d\n",nl->node, nl->host, nl->feedfp);
+ */
+ *ptr2 = savech;
+ ptr1 = ptr2++;
+ if (nl == NULL) continue;
+ if (nl->feedfp == NULL) continue;
+ if (isexcluded(path1,nl)) continue;
+ /*path2 = (char*)mymalloc(strlen(nl->node) + 3);
+ sprintf(path2, "!%s!",nl->node);
+ free(path2);
+ */
+ /*
+ bbslog("path1 %s path2 %s\n",path1, path2);
+ */
+ /*if (strstr(path1, path2) != NULL) return;*/
+ /* to conform to the bntplink batch file */
+ {
+ char *slash = strrchr(filepath,'/');
+ if (slash != NULL) *slash = '\t';
+ fprintf(nl->feedfp,"%s\t%s\t\t%s\t%s\t%c\t%s\t%s!%s\n",
+ filepath == NULL ? "": filepath,
+ GROUPS, FROM, SUBJECT, type, MSGID, MYBBSID, HEADER[PATH_H]);
+ if (slash != NULL) *slash = '/';
+ }
+ fflush(nl->feedfp);
+ if (savech == '\0') break;
+ }
+ free(path1);
+ }
+}
+
+static FILE* bbsfeedsfp = NULL;
+static bbsfeedson = -1;
+
+init_bbsfeedsfp()
+{
+ if (bbsfeedsfp != NULL) {
+ fclose(bbsfeedsfp);
+ bbsfeedsfp = NULL;
+ }
+ bbsfeedson = -1;
+}
+
+bbsfeedslog(filepath, type)
+char *filepath;
+int type;
+{
+
+ char datebuf[40];
+ time_t now;
+
+ if (bbsfeedson ==0) return;
+ if (bbsfeedson == -1) {
+ if (!isfile(BBSFEEDS)) {
+ bbsfeedson = 0;
+ return;
+ }
+ bbsfeedson = 1;
+ }
+
+ if (bbsfeedsfp == NULL) {
+ bbsfeedsfp = fopen(BBSFEEDS,"a");
+ }
+ time(&now);
+ strftime(datebuf, sizeof(datebuf), "%b %d %X ", localtime(&now));
+
+ if( bbsfeedsfp != NULL ) {
+ fprintf(bbsfeedsfp,"%s %c %s %s %s %s!%s %s\n", datebuf, type,
+ REMOTEHOSTNAME, GROUPS, MSGID, MYBBSID, HEADER[PATH_H], filepath==NULL? "": filepath);
+ fflush(bbsfeedsfp);
+ }
+}
+
+static FILE* echomailfp = NULL;
+static echomaillogon = -1;
+
+init_echomailfp()
+{
+ if (echomailfp != NULL) {
+ fclose(echomailfp);
+ echomailfp = NULL;
+ }
+ echomaillogon = -1;
+}
+
+echomaillog()
+{
+
+ if (echomaillogon ==0) return;
+ if (echomaillogon == -1) {
+ if (!isfile(ECHOMAIL)) {
+ echomaillogon = 0;
+ return;
+ }
+ echomaillogon = 1;
+ }
+
+ if (echomailfp == NULL) {
+ echomailfp = fopen(ECHOMAIL,"a");
+ }
+
+ if( echomailfp != NULL ) {
+ fprintf(echomailfp,"\n");
+ fprintf(echomailfp,"µo«H¤H: %s, «H°Ï: %s\n", FROM, GROUPS);
+ fprintf(echomailfp,"¼Ð ÃD: %s\n", SUBJECT);
+ fprintf(echomailfp,"µo«H¯¸: %s (%s)\n", SITE, DATE);
+ fprintf(echomailfp,"Âà«H¯¸: %s (%s)\n", PATH, REMOTEHOSTNAME);
+ fflush(echomailfp);
+ }
+}
+
+int headercmp(a,b)
+header_t *a, *b;
+{
+ return strcasecmp(a->name, b->name);
+}
+
+int readlines(client)
+ClientType *client;
+{
+ int fd = client->fd;
+ char *buffer = client->buffer;
+ buffer_t *in = &client->in;
+ char *front = in->data, *ptr, *hptr;
+ int i;
+
+ for (i=0; i < LASTHEADER; i++ )
+ HEADER[i] = NULL;
+ for (ptr = (char*)strchr(in->data,'\n'); ptr != NULL && *ptr != '\0' ; front = ptr+1, ptr = (char*)strchr(front,'\n')) {
+ *ptr = '\0';
+ if (front[0] == '\r' || front[1] == '\n') {
+ BODY = front+2;
+ break;
+ }
+ hptr = (char*)strchr(front,':');
+ if (hptr != NULL && hptr[1] == ' ') {
+ int value;
+ *hptr = '\0';
+ value = headervalue(front);
+ if (value != -1) {
+ char *tp;
+ HEADER[value] = hptr + 2;
+ if ((tp = (char*)strchr(HEADER[value],'\r'))!=NULL)
+ *tp = '\0';
+ }
+ *hptr = ':';
+ }
+ /**ptr = '\n';*/
+ }
+ NNTPHOST = HEADER[NNTPHOST_H];
+ PATH = HEADER[PATH_H];
+ FROM = HEADER[FROM_H];
+ GROUPS = HEADER[NEWSGROUPS_H];
+ SUBJECT = HEADER[SUBJECT_H];
+ DATE = HEADER[DATE_H];
+ SITE = HEADER[ORGANIZATION_H];
+ MSGID = HEADER[MID_H];
+ CONTROL = HEADER[CONTROL_H];
+ POSTHOST = HEADER[NNTPPOSTINGHOST_H];
+ if (POSTHOST == NULL) {
+ if (HEADER[X_Auth_From_H] != NULL) {
+ POSTHOST = HEADER[X_Auth_From_H];
+ HEADER[NNTPPOSTINGHOST_H] = POSTHOST;
+ }
+ }
+#ifdef PalmBBS
+ XPATH = PATH;
+ XHEADER = HEADER;
+#endif
+}
+
+int headervalue(inputheader)
+char *inputheader;
+{
+ header_t key, *findkey;
+ static int hasinit=0;
+
+ if (hasinit == 0) {
+ article_init();
+ hasinit = 1;
+ }
+
+ key.name = inputheader;
+ findkey = ( header_t *)bsearch (
+ (char *) &key, (char *) headertable,
+ sizeof(headertable)/ sizeof(header_t), sizeof (key),
+ headercmp);
+ if (findkey != NULL) return findkey->id;
+ return -1;
+}
+
+article_init()
+{
+ int i;
+ static int article_inited = 0;
+
+ if (article_inited) return;
+ article_inited = 1;
+
+ qsort(headertable, sizeof(headertable)/ sizeof(header_t), sizeof(header_t),
+ headercmp);
+ for (i=0; i < LASTHEADER; i++ )
+ HEADER[i] = NULL;
+}
+
+#ifdef INNTOBBS_MAIN
+main()
+{
+ int i,j,k,l,m,n,o,p,q;
+ article_init();
+ i = headervalue("Subject");
+ j = headervalue("From");
+ k = headervalue("Date");
+ l = headervalue("NNTP-Posting-Host");
+ m = headervalue("Newsgroups");
+ n = headervalue("Message-ID");
+}
+#endif
diff --git a/innbbsd/inntobbs.h b/innbbsd/inntobbs.h
new file mode 100644
index 00000000..1026e6d7
--- /dev/null
+++ b/innbbsd/inntobbs.h
@@ -0,0 +1,39 @@
+#ifndef INNTOBBS_H
+#define INNTOBBS_H
+
+enum HeaderValue {
+SUBJECT_H, FROM_H, DATE_H, MID_H, NEWSGROUPS_H,
+NNTPPOSTINGHOST_H, NNTPHOST_H, CONTROL_H, PATH_H,
+ORGANIZATION_H, X_Auth_From_H, APPROVED_H, DISTRIBUTION_H,
+REFERENCES_H, KEYWORDS_H, SUMMARY_H,
+LASTHEADER,
+};
+
+#if !defined(PalmBBS)
+extern char *HEADER[];
+extern char *BODY;
+extern char *FROM, *SUBJECT, *SITE, *DATE, *POSTHOST,
+ *NNTPHOST, *PATH, *GROUPS, *MSGID, *CONTROL;
+extern char *REMOTEHOSTNAME, *REMOTEUSERNAME;
+#else
+extern char **XHEADER;
+extern char *BODY;
+extern char *FROM, *SUBJECT, *SITE, *DATE, *POSTHOST,
+ *NNTPHOST, *XPATH, *GROUPS, *MSGID, *CONTROL;
+extern char *REMOTEHOSTNAME, *REMOTEUSERNAME;
+#endif
+
+int receive_article();
+
+#if defined(PalmBBS)
+#ifndef INNTOBBS
+#ifndef PATH
+# define PATH XPATH
+#endif
+#ifndef HEADER
+# define HEADER XHEADER
+#endif
+#endif
+#endif
+
+#endif
diff --git a/innbbsd/mkhistory.c b/innbbsd/mkhistory.c
new file mode 100644
index 00000000..4be980ea
--- /dev/null
+++ b/innbbsd/mkhistory.c
@@ -0,0 +1,14 @@
+#include "innbbsconf.h"
+#include "bbslib.h"
+
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ if (argc < 2) {
+ fprintf(stderr,"Usage: %s history-file\n",argv[0]);
+ exit(1);
+ }
+ initial_bbs(NULL);
+ mkhistory(argv[1]);
+}
diff --git a/innbbsd/nntp.h b/innbbsd/nntp.h
new file mode 100644
index 00000000..489f3502
--- /dev/null
+++ b/innbbsd/nntp.h
@@ -0,0 +1,145 @@
+/* $Revision: 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/pmain.c b/innbbsd/pmain.c
new file mode 100644
index 00000000..39ddba22
--- /dev/null
+++ b/innbbsd/pmain.c
@@ -0,0 +1,62 @@
+#include "innbbsconf.h"
+#include "daemon.h"
+
+/*char *AccessFile=ACCESSFILE;*/
+#define INNBBSDPORT1 "1904"
+#define INNBBSDPORT2 "1234"
+#define INNBBSDPATH1 ".innbbsd1"
+#define INNBBSDPATH2 ".innbbsd2"
+
+pmain(port)
+char *port;
+{
+ if (port == NULL) {
+ int rel;
+/* installbbstalkd(); */
+ fprintf(stderr,"Trying to listen in port %s\n",INNBBSDPORT1);
+ rel = open_listen(INNBBSDPORT1,"tcp",NULL);
+#ifdef DEBUG
+ printf("port fd %d allocated\n",rel);
+#endif
+ if (rel<0) {
+ fprintf(stderr,"Trying to listen in port %s\n",INNBBSDPORT2);
+ return open_listen(INNBBSDPORT2,"tcp",NULL);
+ }
+ return rel;
+ } else {
+#ifdef DEBUG
+ printf("start to allocate port\n");
+#endif
+ return open_listen(port,"tcp",NULL);
+ }
+}
+
+p_unix_main(path)
+char *path;
+{
+ if (path == NULL) {
+ int rel;
+/* installbbstalkd(); */
+ fprintf(stderr,"Trying to listen in port %s\n",INNBBSDPATH1);
+ rel = open_unix_listen(INNBBSDPATH1,"tcp",NULL);
+#ifdef DEBUG
+ printf("port fd %d allocated\n",rel);
+#endif
+ if (rel<0) {
+ fprintf(stderr,"Trying to listen in port %s\n",INNBBSDPATH2);
+ return open_listen(INNBBSDPATH2,"tcp",NULL);
+ }
+ return rel;
+ } else {
+#ifdef DEBUG
+ printf("start to allocate path %s\n", path);
+#endif
+ int fd = unixclient(path,"tcp");
+ if (fd < 0)
+ unlink(path);
+ else
+ close(fd);
+ return open_unix_listen(path,"tcp",NULL);
+ }
+}
+
diff --git a/innbbsd/port.c b/innbbsd/port.c
new file mode 100644
index 00000000..65e91fa4
--- /dev/null
+++ b/innbbsd/port.c
@@ -0,0 +1,28 @@
+#include "innbbsconf.h"
+
+#ifdef NO_getdtablesize
+#include <sys/time.h>
+#include <sys/resource.h>
+getdtablesize()
+{
+ struct rlimit limit;
+ if (getrlimit(RLIMIT_NOFILE, &limit) >= 0){
+ return limit.rlim_cur;
+ }
+ return -1;
+}
+#endif
+
+#if defined(SYSV) && !defined(WITH_RECORD_O)
+#include <fcntl.h>
+flock(fd, op)
+int fd,op;
+{
+ switch (op) {
+ case LOCK_EX: op = F_LOCK; break;
+ case LOCK_UN: op = F_ULOCK; break;
+ default: return -1;
+ }
+ return lockf(fd, op, 0L);
+}
+#endif
diff --git a/innbbsd/receive_article.c b/innbbsd/receive_article.c
new file mode 100644
index 00000000..40f2609c
--- /dev/null
+++ b/innbbsd/receive_article.c
@@ -0,0 +1,1204 @@
+/*
+ * BBS implementation dependendent part
+ *
+ * The only two interfaces you must provide
+ *
+ * #include "inntobbs.h" int receive_article(); 0 success not 0 fail
+ *
+ * if (storeDB(HEADER[MID_H], hispaths) < 0) { .... fail }
+ *
+ * int cancel_article_front( char *msgid ); 0 success not 0 fail
+ *
+ * char *ptr = (char*)DBfetch(msgid);
+ *
+ * ¦¬¨ì¤§¤å³¹¤º®e (body)¦b char *BODY, ÀÉÀY (header)¦b char *HEADER[] SUBJECT_H,
+ * FROM_H, DATE_H, MID_H, NEWSGROUPS_H, NNTPPOSTINGHOST_H, NNTPHOST_H,
+ * CONTROL_H, PATH_H, ORGANIZATION_H
+ */
+
+/*
+ * Sample Implementation
+ *
+ * receive_article() --> post_article() --> bbspost_write_post();
+ * cacnel_article_front(mid) --> cancel_article() --> bbspost_write_cancel();
+ */
+
+
+#ifndef PowerBBS
+#include "innbbsconf.h"
+#include "daemon.h"
+#include "bbslib.h"
+#include "inntobbs.h"
+#include "antisplam.h"
+
+extern int Junkhistory;
+
+char *post_article ARG((char *, char *, char *, int (*) (), char *, char *));
+int cancel_article ARG((char *, char *, char *));
+
+
+#ifdef MapleBBS
+#include "config.h"
+#include "pttstruct.h"
+#define _BBS_UTIL_C_
+#else
+report()
+{
+ /* Function called from record.o */
+ /* Please leave this function empty */
+}
+#endif
+
+
+#if defined(PalmBBS)
+
+#ifndef PATH
+# define PATH XPATH
+#endif
+
+#ifndef HEADER
+# define HEADER XHEADER
+#endif
+
+#endif
+
+/* process post write */
+bbspost_write_post(fh, board, filename)
+ int fh;
+ char *board;
+ char *filename;
+{
+ char *fptr, *ptr;
+ FILE *fhfd = fdopen(fh, "w");
+
+ if (fhfd == NULL)
+ {
+ bbslog("can't fdopen, maybe disk full\n");
+ return -1;
+ }
+
+ fprintf(fhfd, "µo«H¤H: %.60s, ¬ÝªO: %s\n", FROM, board);
+ fprintf(fhfd, "¼Ð ÃD: %.70s\n", SUBJECT);
+ fprintf(fhfd, "µo«H¯¸: %.43s (%s)\n", SITE, DATE);
+ fprintf(fhfd, "Âà«H¯¸: %.70s\n", PATH);
+
+#ifndef MapleBBS
+ if (POSTHOST != NULL)
+ {
+ fprintf(fhfd, "Origin: %.70s\n", POSTHOST);
+ }
+#endif
+
+ fprintf(fhfd, "\n");
+ for (fptr = BODY, ptr = strchr(fptr, '\r'); ptr != NULL && *ptr != '\0'; fptr = ptr + 1, ptr = strchr(fptr, '\r'))
+ {
+ int ch = *ptr;
+ *ptr = '\0';
+ fputs(fptr, fhfd);
+ *ptr = ch;
+ }
+ fputs(fptr, fhfd);
+
+ fflush(fhfd);
+ fclose(fhfd);
+ return 0;
+}
+
+#ifdef KEEP_NETWORK_CANCEL
+/* process cancel write */
+bbspost_write_cancel(fh, board, filename)
+ int fh;
+ char *board, *filename;
+{
+ char *fptr, *ptr;
+ FILE *fhfd = fdopen(fh, "w"), *fp;
+ char buffer[256];
+
+ if (fhfd == NULL)
+ {
+ bbslog("can't fdopen, maybe disk full\n");
+ return -1;
+ }
+
+ fprintf(fhfd, "µo«H¤H: %s, «H°Ï: %s\n", FROM, board);
+ fprintf(fhfd, "¼Ð ÃD: %s\n", SUBJECT);
+ fprintf(fhfd, "µo«H¯¸: %.43s (%s)\n", SITE, DATE);
+ fprintf(fhfd, "Âà«H¯¸: %.70s\n", PATH);
+ if (HEADER[CONTROL_H] != NULL)
+ {
+ fprintf(fhfd, "Control: %s\n", HEADER[CONTROL_H]);
+ }
+ if (POSTHOST != NULL)
+ {
+ fprintf(fhfd, "Origin: %s\n", POSTHOST);
+ }
+ fprintf(fhfd, "\n");
+ for (fptr = BODY, ptr = strchr(fptr, '\r'); ptr != NULL && *ptr != '\0'; fptr = ptr + 1, ptr = strchr(fptr, '\r'))
+ {
+ int ch = *ptr;
+ *ptr = '\0';
+ fputs(fptr, fhfd);
+ *ptr = ch;
+ }
+ fputs(fptr, fhfd);
+ if (POSTHOST != NULL)
+ {
+ fprintf(fhfd, "\n * Origin: ¡´ %.26s ¡´ From: %.40s\n", SITE, POSTHOST);
+ }
+ fprintf(fhfd, "\n---------------------\n");
+ fp = fopen(filename, "r");
+ if (fp == NULL)
+ {
+ bbslog("can't open %s\n", filename);
+ return -1;
+ }
+ while (fgets(buffer, sizeof buffer, fp) != NULL)
+ {
+ fputs(buffer, fhfd);
+ }
+ fclose(fp);
+ fflush(fhfd);
+ fclose(fhfd);
+
+ {
+ fp = fopen(filename, "w");
+ if (fp == NULL)
+ {
+ bbslog("can't write %s\n", filename);
+ return -1;
+ }
+ fprintf(fp, "µo«H¤H: %s, «H°Ï: %s\n", FROM, board);
+ fprintf(fp, "¼Ð ÃD: %.70s\n", SUBJECT);
+ fprintf(fp, "µo«H¯¸: %.43s (%s)\n", SITE, DATE);
+ fprintf(fp, "Âà«H¯¸: %.70s\n", PATH);
+ if (POSTHOST != NULL)
+ {
+ fprintf(fhfd, "Origin: %s\n", POSTHOST);
+ }
+ if (HEADER[CONTROL_H] != NULL)
+ {
+ fprintf(fhfd, "Control: %s\n", HEADER[CONTROL_H]);
+ }
+ fprintf(fp, "\n");
+ for (fptr = BODY, ptr = strchr(fptr, '\r'); ptr != NULL && *ptr != '\0'; fptr = ptr + 1, ptr = strchr(fptr, '\r'))
+ {
+ *ptr = '\0';
+ fputs(fptr, fp);
+ }
+ fputs(fptr, fp);
+ if (POSTHOST != NULL)
+ {
+ fprintf(fp, "\n * Origin: ¡´ %.26s ¡´ From: %.40s\n", SITE, POSTHOST);
+ }
+ fclose(fp);
+ }
+ return 0;
+}
+#endif
+
+
+bbspost_write_control(fh, board, filename)
+ int fh;
+ char *board;
+ char *filename;
+{
+ char *fptr, *ptr;
+ FILE *fhfd = fdopen(fh, "w");
+
+ if (fhfd == NULL)
+ {
+ bbslog("can't fdopen, maybe disk full\n");
+ return -1;
+ }
+
+ fprintf(fhfd, "Path: %s!%s\n", MYBBSID, HEADER[PATH_H]);
+ fprintf(fhfd, "From: %s\n", FROM);
+ fprintf(fhfd, "Newsgroups: %s\n", GROUPS);
+ fprintf(fhfd, "Subject: %s\n", SUBJECT);
+ fprintf(fhfd, "Date: %s\n", DATE);
+ fprintf(fhfd, "Organization: %s\n", SITE);
+ if (POSTHOST != NULL)
+ {
+ fprintf(fhfd, "NNTP-Posting-Host: %.70s\n", POSTHOST);
+ }
+ if (HEADER[CONTROL_H] != NULL)
+ {
+ fprintf(fhfd, "Control: %s\n", HEADER[CONTROL_H]);
+ }
+ if (HEADER[APPROVED_H] != NULL)
+ {
+ fprintf(fhfd, "Approved: %s\n", HEADER[APPROVED_H]);
+ }
+ if (HEADER[DISTRIBUTION_H] != NULL)
+ {
+ fprintf(fhfd, "Distribution: %s\n", HEADER[DISTRIBUTION_H]);
+ }
+ fprintf(fhfd, "\n");
+ for (fptr = BODY, ptr = strchr(fptr, '\r'); ptr != NULL && *ptr != '\0'; fptr = ptr + 1, ptr = strchr(fptr, '\r'))
+ {
+ int ch = *ptr;
+ *ptr = '\0';
+ fputs(fptr, fhfd);
+ *ptr = ch;
+ }
+ fputs(fptr, fhfd);
+
+
+ fflush(fhfd);
+ fclose(fhfd);
+ return 0;
+}
+
+
+time_t datevalue;
+
+
+/* process cancel write */
+receive_article()
+{
+ int i;
+ char *user, *userptr;
+ char *ngptr, *nngptr, *pathptr;
+ char **splitptr;
+ static char userid[32];
+ static char xdate[32];
+ static char xpath[180];
+ newsfeeds_t *nf;
+ char *boardhome;
+ char hispaths[4096];
+ char firstpath[MAXPATHLEN], *firstpathbase;
+ char *lesssym, *nameptrleft, *nameptrright;
+ static char sitebuf[80];
+
+#ifdef HMM_USE_ANTI_SPAM
+ char *notitle[] =
+ {"¦æ¾P", "·~°È¥Nªí", "¼x", "¸ê°T", "§K¶O", "¤jÃØ°e", "¶Ç¾P", "¥¼º¡",
+ "¦~¶O", "¶Ç©I", "»ù", "¾Þ§A¶ý", "¥¼¦¨¦~", "°¨ÁɧJ", "«H¥Î", "ÁÈ¿ú",
+ "=?", "!!!",
+ "¾Þ§A", "¾Þ§A", "·F©p", "¾Þ©p","**","¡¹¡¹","¡¯¡¯","¢C¢C","ªwÄÑ", NULL},
+ *nofrom[] =
+ {"TaipeiNet.Net", "hotmail.com", "mt.touc.edu.tw", "ms11.hinet.net", NULL},
+ *nocont[] =
+ {"¦WÃB¦³­­", "Àu´f»ù", "°Ê§@­n§Ö", "­qÁÊ", "¯S»ù", "±M½æ", "BBC",
+ "·F§A", "¾Þ§A", "·F©p", "¾Þ©p","¨C¤ù","³Ì·s¥Ø¿ý", "http://", "¦¬¿ú",
+ "³Ð·~", "¥I´Ú", "¼s§i«H", "¥u½æ", "¥«»ù", "NCg", "ICAg", NULL};
+#endif
+
+ if (FROM == NULL)
+ {
+ bbslog(":Err: article without usrid %s\n", MSGID);
+ return 0;
+ }
+ else
+ {
+#ifdef HMM_USE_ANTI_SPAM
+ for(i=0; nofrom[i]; i++)
+ if(strstr(FROM, nofrom[i]))
+ {
+ morelog_to(INNBBSD_SPAM, "spam from [%s]: %s\n", nofrom[i], FROM);
+ morelog_to(INNBBSD_SPAM, " %s %s %s %s\n", FROM, PATH, GROUPS, SUBJECT);
+ bbslog(":Ptt: spam from [%s]: %s\n", nofrom[i], FROM);
+ return 0;
+ }
+#endif
+ }
+
+ if(!BODY)
+ {
+ bbslog(":Err: article without body %s\n", MSGID);
+ return 0;
+ }
+ else
+ {
+#ifdef HMM_USE_ANTI_SPAM
+ for(i=0; nocont[i]; i++)
+ if(strstr(BODY, nocont[i]))
+ {
+ morelog_to(INNBBSD_SPAM, "spam body [%s]: %s\n", nocont[i]);
+ morelog_to(INNBBSD_SPAM, " %s %s %s %s\n", FROM, PATH, GROUPS, SUBJECT);
+ bbslog(":Ptt: spam body [%s]: %s\n", nocont[i]);
+ return 0;
+ }
+#endif
+ }
+
+ if(!SUBJECT)
+ {
+ bbslog(":Err: article without subject %s\n", MSGID);
+ return 0;
+ }
+ else
+ {
+#ifdef HMM_USE_ANTI_SPAM
+ for(i=0; notitle[i]; i++)
+ if(strstr(SUBJECT, notitle[i]))
+ {
+ morelog_to(INNBBSD_SPAM, "spam title [%s]: %s\n", notitle[i], SUBJECT);
+ morelog_to(INNBBSD_SPAM, " %s %s %s %s\n", FROM, PATH, GROUPS, SUBJECT);
+ bbslog(":Ptt: spam title [%s]: %s\n", notitle[i], SUBJECT);
+ return 0;
+ }
+#endif
+ }
+
+
+ user = (char *) strchr(FROM, '@');
+ lesssym = (char *) strchr(FROM, '<');
+ nameptrleft = NULL, nameptrright = NULL;
+ if (lesssym == NULL || lesssym >= user)
+ {
+ lesssym = FROM;
+ nameptrleft = strchr(FROM, '(');
+ if (nameptrleft != NULL)
+ nameptrleft++;
+ nameptrright = strrchr(FROM, ')');
+ }
+ else
+ {
+ nameptrleft = FROM;
+ nameptrright = strrchr(FROM, '<');
+ lesssym++;
+ }
+ if (user != NULL)
+ {
+ *user = '\0';
+ userptr = (char *) strchr(FROM, '.');
+ if (userptr != NULL)
+ {
+ *userptr = '\0';
+ strncpy(userid, lesssym, sizeof userid);
+ *userptr = '.';
+ }
+ else
+ {
+ strncpy(userid, lesssym, sizeof userid);
+ }
+ *user = '@';
+ }
+ else
+ {
+ strncpy(userid, lesssym, sizeof userid);
+ }
+ strcat(userid, ".");
+
+ {
+ struct tm tmbuf;
+
+ strptime(DATE, "%d %b %Y %X GMT", &tmbuf);
+ datevalue = timegm(&tmbuf);
+ }
+
+ if (datevalue > 0)
+ {
+ char *p;
+ strncpy(xdate, ctime(&datevalue), sizeof(xdate));
+ p = (char *) strchr(xdate, '\n');
+ if (p != NULL)
+ *p = '\0';
+ DATE = xdate;
+ }
+
+#ifndef MapleBBS
+ if (SITE == NULL || *SITE == '\0')
+ {
+ if (nameptrleft != NULL && nameptrright != NULL)
+ {
+ char savech = *nameptrright;
+ *nameptrright = '\0';
+ strncpy(sitebuf, nameptrleft, sizeof sitebuf);
+ *nameptrright = savech;
+ SITE = sitebuf;
+ }
+ else
+ /* SITE = "(Unknown)"; */
+ SITE = "";
+ }
+ if (strlen(MYBBSID) > 70)
+ {
+ bbslog(" :Err: your bbsid %s too long\n", MYBBSID);
+ return 0;
+ }
+#endif
+
+ sprintf(xpath, "%s!%.*s", MYBBSID, sizeof(xpath) - strlen(MYBBSID) - 2, PATH);
+ PATH = xpath;
+ for (pathptr = PATH; pathptr != NULL && (pathptr = strstr(pathptr, ".edu.tw")) != NULL;)
+ {
+ if (pathptr != NULL)
+ {
+ strcpy(pathptr, pathptr + 7);
+ }
+ }
+ xpath[71] = '\0';
+
+#ifndef MapleBBS
+ echomaillog();
+#endif
+
+ *hispaths = '\0';
+ splitptr = (char **) BNGsplit(GROUPS);
+ firstpath[0] = '\0';
+ firstpathbase = firstpath;
+
+ for (ngptr = *splitptr; ngptr != NULL; ngptr = *(++splitptr))
+ {
+ char *boardptr, *nboardptr;
+
+ if (*ngptr == '\0')
+ continue;
+ nf = (newsfeeds_t *) search_group(ngptr);
+ if (nf == NULL)
+ {
+ bbslog("unwanted \'%s\'\n", ngptr);
+ continue;
+ }
+ if (nf->board == NULL || !*nf->board)
+ continue;
+ if (nf->path == NULL || !*nf->path)
+ continue;
+ for (boardptr = nf->board, nboardptr = (char *) strchr(boardptr, ','); boardptr != NULL && *boardptr != '\0'; nboardptr = (char *) strchr(boardptr, ','))
+ {
+ if (nboardptr != NULL)
+ {
+ *nboardptr = '\0';
+ }
+ if (*boardptr == '\t')
+ {
+ goto boardcont;
+ }
+ boardhome = (char *) fileglue("%s/boards/%s", BBSHOME, boardptr);
+ if (!isdir(boardhome))
+ {
+ bbslog(":Err: unable to write %s\n", boardhome);
+ }
+ else
+ {
+ char *fname;
+ /*
+ * if ( !isdir( boardhome )) { bbslog( ":Err: unable to write
+ * %s\n",boardhome); testandmkdir(boardhome); }
+ */
+ fname = (char *) post_article(boardhome, userid, boardptr,
+ bbspost_write_post, NULL, firstpath);
+ if (fname != NULL)
+ {
+ fname = (char *) fileglue("%s/%s", boardptr, fname);
+ if (firstpath[0] == '\0')
+ {
+ sprintf(firstpath, "%s/boards/%s", BBSHOME, fname);
+ firstpathbase = firstpath + strlen(BBSHOME) + strlen("/boards/");
+ }
+ if (strlen(fname) + strlen(hispaths) + 1 < sizeof(hispaths))
+ {
+ strcat(hispaths, fname);
+ strcat(hispaths, " ");
+ }
+ }
+ else
+ {
+ bbslog("fname is null %s\n", boardhome);
+ return -1;
+ }
+ }
+
+ boardcont:
+ if (nboardptr != NULL)
+ {
+ *nboardptr = ',';
+ boardptr = nboardptr + 1;
+ }
+ else
+ break;
+
+ } /* for board1,board2,... */
+ /*
+ * if (nngptr != NULL) ngptr = nngptr + 1; else break;
+ */
+ if (*firstpathbase)
+ feedfplog(nf, firstpathbase, 'P');
+ }
+ if (*hispaths)
+ bbsfeedslog(hispaths, 'P');
+
+ if (Junkhistory || *hispaths)
+ {
+ if (storeDB(HEADER[MID_H], hispaths) < 0)
+ {
+ bbslog("store DB fail\n");
+ /* I suspect here will introduce duplicated articles */
+ /* return -1; */
+ }
+ }
+ return 0;
+}
+
+receive_control()
+{
+ char *boardhome, *fname;
+ char firstpath[MAXPATHLEN], *firstpathbase;
+ char **splitptr, *ngptr;
+ newsfeeds_t *nf;
+
+ bbslog("control post %s\n", HEADER[CONTROL_H]);
+ boardhome = (char *) fileglue("%s/boards/control", BBSHOME);
+ testandmkdir(boardhome);
+ *firstpath = '\0';
+ if (isdir(boardhome))
+ {
+ fname = (char *) post_article(boardhome, FROM, "control", bbspost_write_control, NULL, firstpath);
+ if (fname != NULL)
+ {
+ if (firstpath[0] == '\0')
+ sprintf(firstpath, "%s/boards/control/%s", BBSHOME, fname);
+ if (storeDB(HEADER[MID_H], (char *) fileglue("control/%s", fname)) < 0)
+ {
+ }
+ bbsfeedslog(fileglue("control/%s", fname), 'C');
+ firstpathbase = firstpath + strlen(BBSHOME) + strlen("/boards/");
+ splitptr = (char **) BNGsplit(GROUPS);
+ for (ngptr = *splitptr; ngptr != NULL; ngptr = *(++splitptr))
+ {
+ if (*ngptr == '\0')
+ continue;
+ nf = (newsfeeds_t *) search_group(ngptr);
+ if (nf == NULL)
+ continue;
+ if (nf->board == NULL)
+ continue;
+ if (nf->path == NULL)
+ continue;
+ feedfplog(nf, firstpathbase, 'C');
+ }
+ }
+ }
+ return 0;
+}
+
+cancel_article_front(msgid)
+ char *msgid;
+{
+ char *ptr = (char *) DBfetch(msgid);
+ char *filelist, filename[2048];
+ char histent[4096];
+ char firstpath[MAXPATHLEN], *firstpathbase;
+ if (ptr == NULL)
+ {
+ bbslog("cancel failed(DBfetch): %s\n", msgid);
+ return 0;
+ }
+ strncpy(histent, ptr, sizeof histent);
+ ptr = histent;
+
+#ifdef DEBUG
+ printf("**** try to cancel %s *****\n", ptr);
+#endif
+
+ filelist = strchr(ptr, '\t');
+ if (filelist != NULL)
+ {
+ filelist++;
+ }
+ *firstpath = '\0';
+ for (ptr = filelist; ptr && *ptr;)
+ {
+ char *file;
+ for (; *ptr && isspace(*ptr); ptr++);
+ if (*ptr == '\0')
+ break;
+ file = ptr;
+ for (ptr++; *ptr && !isspace(*ptr); ptr++);
+ if (*ptr != '\0')
+ {
+ *ptr++ = '\0';
+ }
+ sprintf(filename, "%s/boards/%s", BBSHOME, file);
+ bbslog("cancel post %s\n", filename);
+ if (isfile(filename))
+ {
+ FILE *fp = fopen(filename, "r");
+ char buffer[1024];
+ char xfrom0[100], xfrom[100], xpath[1024], *boardhome;
+
+ if (fp == NULL)
+ continue;
+ strncpy(xfrom0, HEADER[FROM_H], 99);
+ xfrom0[99] = 0;
+ strtok(xfrom0, ", ");
+ while (fgets(buffer, sizeof buffer, fp) != NULL)
+ {
+ char *hptr;
+ if (buffer[0] == '\n')
+ break;
+ hptr = strchr(buffer, '\n');
+ if (hptr != NULL)
+ *hptr = '\0';
+ if (strncmp(buffer, "µo«H¤H: ", 8) == 0)
+ {
+ strncpy(xfrom, buffer + 8, 99);
+ xfrom[99] = 0;
+ strtok(xfrom, ", ");
+ }
+ else if (strncmp(buffer, "Âà«H¯¸: ", 8) == 0)
+ {
+ strcpy(xpath, buffer + 8);
+ }
+ }
+ fclose(fp);
+ if (strcmp(xfrom0, xfrom))
+ {
+ bbslog("Invalid cancel %s, path: %s!%s, [`%s` != `%s`]\n",
+ FROM, MYBBSID, PATH, xfrom0, xfrom);
+ return 0;
+ }
+
+#ifdef KEEP_NETWORK_CANCEL
+ bbslog("cancel post %s\n", filename);
+ boardhome = (char *) fileglue("%s/boards/deleted", BBSHOME);
+ testandmkdir(boardhome);
+ if (isdir(boardhome))
+ {
+ char subject[1024];
+ char *fname;
+ if (POSTHOST)
+ {
+ sprintf(subject, "cancel by: %.1000s", POSTHOST);
+ }
+ else
+ {
+ char *body, *body2;
+ body = strchr(BODY, '\r');
+ if (body != NULL)
+ *body = '\0';
+ body2 = strchr(BODY, '\n');
+ if (body2 != NULL)
+ *body = '\0';
+ sprintf(subject, "%.1000s", BODY);
+ if (body != NULL)
+ *body = '\r';
+ if (body2 != NULL)
+ *body = '\n';
+ }
+ if (*subject)
+ SUBJECT = subject;
+ fname = (char *) post_article(boardhome, FROM, "deleted", bbspost_write_cancel, filename, firstpath);
+ if (fname != NULL)
+ {
+ if (firstpath[0] == '\0')
+ {
+ sprintf(firstpath, "%s/boards/deleted/%s", BBSHOME, fname);
+ firstpathbase = firstpath + strlen(BBSHOME) + strlen("/boards/");
+ }
+ if (storeDB(HEADER[MID_H], (char *) fileglue("deleted/%s", fname)) < 0)
+ {
+ /* should do something */
+ bbslog("store DB fail\n");
+ /* return -1; */
+ }
+ bbsfeedslog(fileglue("deleted/%s", fname), 'D');
+
+#ifdef OLDDISPATCH
+ {
+ char board[256];
+ newsfeeds_t *nf;
+ char *filebase = filename + strlen(BBSHOME) + strlen("/boards/");
+ char *filetail = strrchr(filename, '/');
+ if (filetail != NULL)
+ {
+ strncpy(board, filebase, filetail - filebase);
+ nf = (newsfeeds_t *) search_board(board);
+ if (nf != NULL && nf->board && nf->path)
+ {
+ feedfplog(nf, firstpathbase, 'D');
+ }
+ }
+ }
+#endif
+ }
+ else
+ {
+ bbslog(" fname is null %s %s\n", boardhome, filename);
+ return -1;
+ }
+ }
+#else
+ /* bbslog("**** %s should be removed\n", filename); */
+/*
+ unlink(filename);
+*/
+#endif
+
+ {
+ char *fp = strrchr(file, '/');
+ if (fp != NULL)
+ {
+ *fp = '\0';
+ cancel_article(BBSHOME, file, fp + 1);
+ *fp = '/';
+ }
+ }
+ }
+ }
+ if (*firstpath)
+ {
+ char **splitptr, *ngptr;
+ newsfeeds_t *nf;
+ splitptr = (char **) BNGsplit(GROUPS);
+ for (ngptr = *splitptr; ngptr != NULL; ngptr = *(++splitptr))
+ {
+ if (*ngptr == '\0')
+ continue;
+ nf = (newsfeeds_t *) search_group(ngptr);
+ if (nf == NULL)
+ continue;
+ if (nf->board == NULL)
+ continue;
+ if (nf->path == NULL)
+ continue;
+ feedfplog(nf, firstpathbase, 'D');
+ }
+ }
+ return 0;
+}
+
+
+#if defined(PhoenixBBS) || defined(SecretBBS) || defined(PivotBBS) || defined(MapleBBS)
+/* for PhoenixBBS's post article and cancel article */
+#include "config.h"
+
+
+char *
+post_article(homepath, userid, board, writebody, pathname, firstpath)
+ char *homepath;
+ char *userid, *board;
+ int (*writebody) ();
+char *pathname, *firstpath;
+{
+ struct userec_t record;
+ struct fileheader_t header;
+ char *subject = SUBJECT;
+ char index[MAXPATHLEN];
+ static char name[MAXPATHLEN];
+ char article[MAXPATHLEN];
+ char buf[MAXPATHLEN], *ptr;
+ FILE *fidx;
+ int fh, bid;
+ time_t now;
+ int linkflag;
+/* Ptt
+ if(bad_subject(subject)) return NULL;
+*/
+ sprintf(index, "%s/.DIR", homepath);
+ if ((fidx = fopen(index, "r")) == NULL)
+ {
+ if ((fidx = fopen(index, "w")) == NULL)
+ {
+ bbslog(":Err: Unable to post in %s.\n", homepath);
+ return NULL;
+ }
+ }
+ fclose(fidx);
+
+ now = time(NULL);
+ while (1)
+ {
+ sprintf(name, "M.%d.A", ++now);
+ sprintf(article, "%s/%s", homepath, name);
+ fh = open(article, O_CREAT | O_EXCL | O_WRONLY, 0644);
+ if (fh >= 0)
+ break;
+ if (errno != EEXIST)
+ {
+ bbslog(" Err: can't writable or other errors\n");
+ return NULL;
+ }
+ }
+
+#ifdef DEBUG
+ printf("post to %s\n", article);
+#endif
+
+ linkflag = 1;
+ if (firstpath && *firstpath)
+ {
+ close(fh);
+ unlink(article);
+
+#ifdef DEBUGLINK
+ bbslog("try to link %s to %s", firstpath, article);
+#endif
+
+ linkflag = link(firstpath, article);
+ if (linkflag)
+ {
+ fh = open(article, O_CREAT | O_EXCL | O_WRONLY, 0644);
+ }
+ }
+ if (linkflag)
+ {
+ if (writebody)
+ {
+ if ((*writebody) (fh, board, pathname) < 0)
+ return NULL;
+ }
+ else
+ {
+ if (bbspost_write_post(fh, board, pathname) < 0)
+ return NULL;
+ }
+ close(fh);
+ }
+
+ bzero((void *) &header, sizeof(header));
+
+#ifndef MapleBBS
+ strcpy(header.filename, name);
+ strncpy(header.owner, userid, IDLEN);
+ strncpy(header.title, subject, STRLEN);
+ header.filename[STRLEN - 1] = 'M';
+#else
+
+ strcpy(header.filename, name);
+ if (userid[IDLEN])
+ strcpy(&userid[IDLEN], ".");
+ strcpy(header.owner, userid);
+ strncpy(header.title, subject, TTLEN);
+ header.savemode = 'M';
+ {
+ struct tm *ptime;
+ ptime = localtime(&datevalue);
+ sprintf(header.date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday);
+ }
+#endif
+
+ append_record(index, &header, sizeof(header));
+
+ if((bid = getbnum(board)) > 0)
+ touchbtotal(bid);
+ return name;
+}
+
+/*
+woju
+Cross-fs rename()
+*/
+
+Rename(char* src, char* dst)
+{
+ char cmd[200];
+
+ bbslog("Rename: %s -> %s\n", src, dst);
+ if (rename(src, dst) == 0)
+ return 0;
+
+ sprintf(cmd, "/bin/mv %s %s", src, dst);
+ return system(cmd);
+}
+
+
+cancelpost(fileheader_t *fhdr, char* boardname)
+{
+ int fd;
+ char fpath[MAXPATHLEN];
+
+ sprintf(fpath, BBSHOME "/boards/%s/%s", boardname, fhdr->filename);
+ if ((fd = open(fpath, O_RDONLY)) >= 0) {
+ fileheader_t postfile;
+ char fn2[MAXPATHLEN] = BBSHOME "/boards/deleted", *junkdir;
+
+ stampfile(fn2, &postfile);
+ memcpy(postfile.owner, fhdr->owner, IDLEN + TTLEN + 10);
+ postfile.savemode = 'D';
+ close(fd);
+ Rename(fpath, fn2);
+ strcpy(strrchr(fn2, '/') + 1, ".DIR");
+ append_record(fn2, &postfile, sizeof(postfile));
+ }
+ else
+ bbslog("cancelpost: %s opened error\n", fpath);
+}
+
+
+/* ---------------------------- */
+/* new/old/lock file processing */
+/* ---------------------------- */
+
+typedef struct
+{
+ char newfn[MAXPATHLEN];
+ char oldfn[MAXPATHLEN];
+ char lockfn[MAXPATHLEN];
+} nol;
+
+
+static void
+nolfilename(n, fpath)
+ nol *n;
+ char *fpath;
+{
+ sprintf(n->newfn, "%s.new", fpath);
+ sprintf(n->oldfn, "%s.old", fpath);
+ sprintf(n->lockfn, "%s.lock", fpath);
+}
+
+
+
+int
+delete_record(char *fpath, int size, int id)
+{
+ nol my;
+ char abuf[512];
+ int fdr, fdw, fd;
+ int count;
+ fileheader_t fhdr;
+
+ nolfilename(&my, fpath);
+
+ if ((fd = open(my.lockfn, O_RDWR | O_CREAT | O_APPEND, 0644)) == -1)
+ return -1;
+ flock(fd, LOCK_EX);
+
+ if ((fdr = open(fpath, O_RDONLY, 0)) == -1)
+ {
+
+#ifdef HAVE_REPORT
+ report("delete_record failed!!! (open)");
+#endif
+
+ flock(fd, LOCK_UN);
+ close(fd);
+ return -1;
+ }
+ if ((fdw = open(my.newfn, O_WRONLY | O_CREAT | O_EXCL, 0644)) == -1)
+ {
+ flock(fd, LOCK_UN);
+
+#ifdef HAVE_REPORT
+ report("delete_record failed!!! (open tmpfile)");
+#endif
+
+ close(fd);
+ close(fdr);
+ return -1;
+ }
+ count = 1;
+ while (read(fdr, abuf, size) == size)
+ {
+ if (id == count) {
+ memcpy(&fhdr, abuf, sizeof(fhdr));
+ bbslog("delete_record: %d, %s, %s\n", count, fhdr.owner, fhdr.title);
+ }
+ if (id != count++ && (write(fdw, abuf, size) == -1))
+ {
+
+ bbslog("delete_record: %s failed!!! (write)\n", fpath);
+#ifdef HAVE_REPORT
+ report("delete_record failed!!! (write)");
+#endif
+
+ unlink(my.newfn);
+ close(fdr);
+ close(fdw);
+ flock(fd, LOCK_UN);
+ close(fd);
+ return -1;
+ }
+ }
+ close(fdr);
+ close(fdw);
+ if (Rename(fpath, my.oldfn) == -1 || Rename(my.newfn, fpath) == -1)
+ {
+
+#ifdef HAVE_REPORT
+ report("delete_record failed!!! (Rename)");
+#endif
+
+ flock(fd, LOCK_UN);
+ close(fd);
+ return -1;
+ }
+ flock(fd, LOCK_UN);
+ close(fd);
+ return 0;
+}
+
+cancel_article(homepath, board, file)
+ char *homepath;
+ char *board, *file;
+{
+ struct fileheader_t header;
+ struct stat state;
+ char dirname[MAXPATHLEN];
+ char buf[MAXPATHLEN];
+ long numents, size, time, now;
+ int fd, lower, ent;
+
+
+ if (file == NULL || file[0] != 'M' || file[1] != '.' ||
+ (time = atoi(file + 2)) <= 0) {
+ bbslog("cancel_article: invalid filename `%s`\n", file);
+ return 0;
+ }
+ size = sizeof(header);
+ sprintf(dirname, "%s/boards/%s/.DIR", homepath, board);
+ if ((fd = open(dirname, O_RDONLY)) == -1) {
+ bbslog("cancel_article: open `%s` error\n", dirname);
+ return 0;
+ }
+ fstat(fd, &state);
+ ent = ((long) state.st_size) / size;
+ lower = 0;
+ while (1)
+ {
+ ent -= 8;
+ if (ent <= 0 || lower >= 2)
+ break;
+ lseek(fd, size * ent, SEEK_SET);
+ if (read(fd, &header, size) != size)
+ {
+ ent = 0;
+ break;
+ }
+ now = atoi(header.filename + 2);
+ lower = (now < time) ? lower + 1 : 0;
+ }
+ if (ent < 0)
+ ent = 0;
+ while (read(fd, &header, size) == size)
+ {
+ if (strcmp(file, header.filename) == 0)
+ {
+ if ((header.filemode & FILE_MARKED)
+ || (header.filemode & FILE_DIGEST) || (header.owner[0] == '-'))
+ break;
+ delete_record(dirname, sizeof(fileheader_t), lseek(fd, 0, SEEK_CUR) / size);
+ cancelpost(&header, board);
+ break;
+ }
+ now = atoi(header.filename + 2);
+ if (now > time)
+ break;
+ }
+ close(fd);
+ return 0;
+}
+
+#elif defined(PalmBBS)
+# undef PATH XPATH
+# undef HEADER XHEADER
+#include "server.h"
+
+char *
+post_article(homepath, userid, board, writebody, pathname, firstpath)
+ char *homepath;
+ char *userid, *board;
+ int (*writebody) ();
+char *pathname, *firstpath;
+{
+ PATH msgdir, msgfile;
+ static PATH name;
+
+ READINFO readinfo;
+ SHORT fileid;
+ char buf[MAXPATHLEN];
+ struct stat stbuf;
+ int fh;
+
+ strcpy(msgdir, homepath);
+ if (stat(msgdir, &stbuf) == -1 || !S_ISDIR(stbuf.st_mode))
+ {
+ /* A directory is missing! */
+ bbslog(":Err: Unable to post in %s.\n", msgdir);
+ return NULL;
+ }
+ get_filelist_ids(msgdir, &readinfo);
+
+ for (fileid = 1; fileid <= BBS_MAX_FILES; fileid++)
+ {
+ int oumask;
+ if (test_readbit(&readinfo, fileid))
+ continue;
+ fileid_to_fname(msgdir, fileid, msgfile);
+ sprintf(name, "%04x", fileid);
+
+#ifdef DEBUG
+ printf("post to %s\n", msgfile);
+#endif
+
+ if (firstpath && *firstpath)
+ {
+
+#ifdef DEBUGLINK
+ bbslog("try to link %s to %s", firstpath, msgfile);
+#endif
+
+ if (link(firstpath, msgfile) == 0)
+ break;
+ }
+ oumask = umask(0);
+ fh = open(msgfile, O_CREAT | O_EXCL | O_WRONLY, 0664);
+ umask(oumask);
+ if (writebody)
+ {
+ if ((*writebody) (fh, board, pathname) < 0)
+ return NULL;
+ }
+ else
+ {
+ if (bbspost_write_post(fh, board, pathname) < 0)
+ return NULL;
+ }
+ close(fh);
+ break;
+ }
+
+#ifdef CACHED_OPENBOARD
+ {
+ char *bname;
+ bname = strrchr(msgdir, '/');
+ if (bname)
+ notify_new_post(++bname, 1, fileid, stbuf.st_mtime);
+ }
+#endif
+
+ return name;
+}
+
+cancel_article(homepath, board, file)
+ char *homepath;
+ char *board, *file;
+{
+ PATH fname;
+
+#ifdef CACHED_OPENBOARD
+ PATH bdir;
+ struct stat stbuf;
+
+ sprintf(bdir, "%s/boards/%s", homepath, board);
+ stat(bdir, &stbuf);
+#endif
+
+ sprintf(fname, "%s/boards/%s/%s", homepath, board, file);
+ unlink(fname);
+ /* kill it now! the function is far small then original.. :) */
+ /* because it won't make system load heavy like before */
+
+#ifdef CACHED_OPENBOARD
+ notify_new_post(board, -1, hex2SHORT(file), stbuf.st_mtime);
+#endif
+}
+
+#else
+error("You should choose one of the systems: PhoenixBBS, PowerBBS, or PalmBBS")
+#endif
+
+#else
+
+receive_article()
+{
+}
+
+cancel_article_front(msgid)
+ char *msgid;
+{
+}
+#endif
diff --git a/innbbsd/rfc931.c b/innbbsd/rfc931.c
new file mode 100644
index 00000000..0d59d771
--- /dev/null
+++ b/innbbsd/rfc931.c
@@ -0,0 +1,144 @@
+ /*
+ * rfc931_user() speaks a common subset of the RFC 931, AUTH, TAP and IDENT
+ * protocols. It consults an RFC 931 etc. compatible daemon on the client
+ * host to look up the remote user name. The information should not be used
+ * for authentication purposes.
+ *
+ * Diagnostics are reported through syslog(3).
+ *
+ * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
+ *
+ * Inspired by the authutil package (comp.sources.unix volume 22) by Dan
+ * Bernstein (brnstnd@kramden.acf.nyu.edu).
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#) rfc931.c 1.4 93/03/07 22:47:52";
+#endif
+
+#include <stdio.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <signal.h>
+
+/*#include "log_tcp.h"*/
+
+#define RFC931_PORT 113 /* Semi-well-known port */
+
+#ifndef RFC931_TIMEOUT
+#define RFC931_TIMEOUT 30 /* wait for at most 30 seconds */
+#endif
+
+extern char *strchr();
+extern char *inet_ntoa();
+
+static jmp_buf timebuf;
+
+/* timeout - handle timeouts */
+
+static void timeout(sig)
+int sig;
+{
+ longjmp(timebuf, sig);
+}
+
+/* rfc931_name - return remote user name */
+
+char *my_rfc931_name(herefd,there)
+int herefd;
+struct sockaddr_in *there; /* remote link information */
+{
+ struct sockaddr_in here; /* local link information */
+ struct sockaddr_in sin; /* for talking to RFC931 daemon */
+ int length;
+ int s;
+ unsigned remote;
+ unsigned local;
+ static char user[256]; /* XXX */
+ char buffer[512]; /* YYY */
+ FILE *fp;
+ char *cp;
+ char *result = "unknown";
+
+ /* Find out local address and port number of stdin. */
+
+ length = sizeof(here);
+ if (getsockname(herefd, (struct sockaddr *) & here, &length) == -1) {
+ syslog(LOG_ERR, "getsockname: %m");
+ return (result);
+ }
+
+ /*
+ * The socket that will be used for user name lookups should be bound to
+ * the same local IP address as stdin. This will automagically happen on
+ * hosts that have only one IP network address. When the local host has
+ * more than one IP network address, we must do an explicit bind() call.
+ */
+
+ if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ return (result);
+
+ sin = here;
+ sin.sin_port = 0;
+ if (bind(s, (struct sockaddr *) & sin, sizeof sin) < 0) {
+ syslog(LOG_ERR, "bind: %s: %m", inet_ntoa(here.sin_addr));
+ return (result);
+ }
+ /* Set up timer so we won't get stuck. */
+
+ signal(SIGALRM, timeout);
+ if (setjmp(timebuf)) {
+ close(s); /* not: fclose(fp) */
+ return (result);
+ }
+ alarm(RFC931_TIMEOUT);
+
+ /* Connect to the RFC931 daemon. */
+
+ sin = *there;
+ sin.sin_port = htons(RFC931_PORT);
+ if (connect(s, (struct sockaddr *) & sin, sizeof(sin)) == -1
+ || (fp = fdopen(s, "w+")) == 0) {
+ close(s);
+ alarm(0);
+ return (result);
+ }
+
+ /*
+ * Use unbuffered I/O or we may read back our own query. setbuf() must be
+ * called before doing any I/O on the stream. Thanks for the reminder,
+ * Paul Kranenburg <pk@cs.few.eur.nl>!
+ */
+
+ setbuf(fp, (char *) 0);
+
+ /* Query the RFC 931 server. Would 13-byte writes ever be broken up? */
+
+ fprintf(fp, "%u,%u\r\n", ntohs(there->sin_port), ntohs(here.sin_port));
+ fflush(fp);
+
+ /*
+ * Read response from server. Use fgets()/sscanf() instead of fscanf()
+ * because there is no buffer for pushback. Thanks, Chris Turbeville
+ * <turbo@cse.uta.edu>.
+ */
+
+ if (fgets(buffer, sizeof(buffer), fp) != 0
+ && ferror(fp) == 0 && feof(fp) == 0
+ && sscanf(buffer, "%u , %u : USERID :%*[^:]:%255s",
+ &remote, &local, user) == 3
+ && ntohs(there->sin_port) == remote
+ && ntohs(here.sin_port) == local) {
+ /* Strip trailing carriage return. */
+
+ if (cp = strchr(user, '\r'))
+ *cp = 0;
+ result = user;
+ }
+ alarm(0);
+ fclose(fp);
+ return (result);
+}
diff --git a/mbbsd/.cvsignore b/mbbsd/.cvsignore
new file mode 100644
index 00000000..35f9f2d1
--- /dev/null
+++ b/mbbsd/.cvsignore
@@ -0,0 +1,2 @@
+*.o
+mbbsd
diff --git a/mbbsd/Makefile b/mbbsd/Makefile
new file mode 100644
index 00000000..886944f3
--- /dev/null
+++ b/mbbsd/Makefile
@@ -0,0 +1,45 @@
+# $Id: Makefile,v 1.1 2002/03/07 15:13:48 in2 Exp $
+
+BBSHOME?=$(HOME)
+OSTYPE=FreeBSD
+
+# FreeBSD
+CFLAGS_FreeBSD= -pipe -Wall -g -O3 -DHAVE_SETPROCTITLE -DBBSHOME='"$(BBSHOME)"' -DFreeBSD -I../include
+LDFLAGS_FreeBSD=-pipe -Wall -g -O3
+LIBS_FreeBSD= -lutil -lkvm
+
+# Linux
+CFLAGS_linux= -pipe -Wall -g -O3 -DHAVE_DES_CRYPT -DBBSHOME='"$(BBSHOME)"' -DLinux -I../include -s
+LDFLAGS_linux= -pipe -Wall -g -O3
+LIBS_linux= -lcrypt
+
+CFLAGS= $(CFLAGS_$(OSTYPE))
+LDFLAGS=$(LDFLAGS_$(OSTYPE))
+LIBS= $(LIBS_$(OSTYPE))
+
+CC= gcc
+PROG= mbbsd
+OBJS= admin.o announce.o args.o bbcall.o bbs.o board.o cache.o cal.o card.o\
+ chat.o chc_draw.o chc_net.o chc_play.o chc_rule.o chicken.o dark.o\
+ dice.o edit.o friend.o gamble.o gomo.o gomo1.o guess.o indict.o io.o\
+ kaede.o lovepaper.o mail.o mbbsd.o menu.o more.o name.o osdep.o\
+ othello.o page.o read.o record.o register.o screen.o stuff.o\
+ talk.o term.o topsong.o user.o vice.o vote.o xyz.o\
+ voteboard.o syspost.o var.o descrypt.o toolkit.o passwd.o\
+ calendar.o
+
+.SUFFIXES: .c .o
+.c.o:
+ $(CC) $(CFLAGS) -c $*.c
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(CC) $(LDFLAGS) -o $(PROG) $(OBJS) $(LIBS)
+
+install: $(PROG)
+ install -d $(BBSHOME)/bin/
+ install -c -m 755 $(PROG) $(BBSHOME)/bin/
+
+clean:
+ rm -f $(OBJS) $(PROG)
diff --git a/mbbsd/admin.c b/mbbsd/admin.c
new file mode 100644
index 00000000..14bc9721
--- /dev/null
+++ b/mbbsd/admin.c
@@ -0,0 +1,1105 @@
+/* $Id: admin.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "perm.h"
+#include "modes.h"
+#include "proto.h"
+
+extern char *msg_uid;
+extern userec_t xuser;
+extern char *err_uid;
+extern boardheader_t *bcache;
+
+/* ¨Ï¥ÎªÌºÞ²z */
+int m_user() {
+ userec_t muser;
+ int id;
+ char genbuf[200];
+
+ stand_title("¨Ï¥ÎªÌ³]©w");
+ usercomplete(msg_uid, genbuf);
+ if(*genbuf) {
+ move(2, 0);
+ if((id = getuser(genbuf))) {
+ memcpy(&muser, &xuser, sizeof(muser));
+ user_display(&muser, 1);
+ uinfo_query(&muser, 1, id);
+ } else {
+ outs(err_uid);
+ clrtoeol();
+ pressanykey();
+ }
+ }
+ return 0;
+}
+
+extern int b_lines;
+
+static int search_key_user(char *passwdfile, int mode) {
+ userec_t user;
+ int ch;
+ int coun = 0;
+ FILE *fp1 = fopen(passwdfile, "r");
+ char buf[128], key[22], genbuf[8];
+
+ clear();
+ getdata(0, 0, mode ? "½Ð¿é¤J¨Ï¥ÎªÌÃöÁä¦r[¹q¸Ü|¦a§}|©m¦W|¤W¯¸¦aÂI|"
+ "email|¤pÂûid] :" : "½Ð¿é¤Jid :", key, 21, DOECHO);
+ while((fread(&user, sizeof(user), 1, fp1)) > 0 && coun < MAX_USERS) {
+ if(!(++coun & 15)) {
+ move(1, 0);
+ sprintf(buf, "²Ä [%d] µ§¸ê®Æ\n", coun);
+ outs(buf);
+ refresh();
+ }
+ if(!strcasecmp(user.userid, key) ||
+ (mode && (
+ strstr(user.realname, key) || strstr(user.username, key) ||
+ strstr(user.lasthost, key) || strstr(user.email, key) ||
+ strstr(user.address, key) || strstr(user.justify, key) ||
+ strstr(user.mychicken.name, key)))) {
+ move(1, 0);
+ sprintf(buf, "²Ä [%d] µ§¸ê®Æ\n", coun);
+ outs(buf);
+ refresh();
+
+ user_display(&user, 1);
+ uinfo_query(&user, 1, coun);
+ outs("\033[44m ªÅ¥ÕÁä\033[37m:·j´M¤U¤@­Ó"
+ " \033[33m Q\033[37m: Â÷¶}");
+ outs(mode ? " \033[m " :
+ " S: ¨ú¥Î³Æ¥÷¸ê®Æ \033[m ");
+ while(1) {
+ while((ch = igetch()) == 0);
+ if(ch == ' ')
+ break;
+ if(ch == 'q' || ch == 'Q')
+ return 0;
+ if(ch == 's' && !mode) {
+ if((ch = searchuser(user.userid))) {
+ setumoney(ch,user.money);
+ passwd_update(ch, &user);
+ return 0;
+ } else {
+ move(b_lines - 1, 0);
+ genbuf[0] = 'n';
+ getdata(0, 0,
+ "¥Ø«eªº PASSWD ÀɨS¦³¦¹ ID¡A·s¼W¶Ü¡H[y/N]",
+ genbuf, 3, LCECHO);
+ if(genbuf[0] == 'n') {
+ outs("¥Ø«eªºPASSWDSÀɨS¦³¦¹id "
+ "½Ð¥ýnew¤@­Ó³o­Óidªº±b¸¹");
+ } else {
+ int allocid = getnewuserid();
+
+ if(allocid > MAX_USERS || allocid <= 0) {
+ fprintf(stderr, "¥»¯¸¤H¤f¤w¹F¹¡©M¡I\n");
+ exit(1);
+ }
+
+ if(passwd_update(allocid, &user) == -1) {
+ fprintf(stderr, "«Èº¡¤F¡A¦A¨£¡I\n");
+ exit(1);
+ }
+ setuserid(allocid, user.userid);
+ if(!searchuser(user.userid)) {
+ fprintf(stderr, "µLªk«Ø¥ß±b¸¹\n");
+ exit(1);
+ }
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ fclose(fp1);
+ return 0;
+}
+
+/* ¥H¥ô·N key ´M§ä¨Ï¥ÎªÌ */
+int search_user_bypwd() {
+ search_key_user(FN_PASSWD, 1);
+ return 0;
+}
+
+/* ´M§ä³Æ¥÷ªº¨Ï¥ÎªÌ¸ê®Æ */
+int search_user_bybakpwd() {
+ char *choice[] = {
+ "PASSWDS.NEW1", "PASSWDS.NEW2", "PASSWDS.NEW3",
+ "PASSWDS.NEW4", "PASSWDS.NEW5", "PASSWDS.NEW6",
+ "PASSWDS.BAK"
+ };
+ int ch;
+
+ clear();
+ move(1, 1);
+ outs("½Ð¿é¤J§A­n¥Î¨Ó´M§ä³Æ¥÷ªºÀÉ®× ©Î«ö 'q' Â÷¶}\n");
+ outs(" [\033[1;31m1\033[m]¤@¤Ñ«e, [\033[1;31m2\033[m]¨â¤Ñ«e, "
+ "[\033[1;31m3\033[m]¤T¤Ñ«e\n");
+ outs(" [\033[1;31m4\033[m]¥|¤Ñ«e, [\033[1;31m5\033[m]¤­¤Ñ«e, "
+ "[\033[1;31m6\033[m]¤»¤Ñ«e\n");
+ outs(" [7]³Æ¥÷ªº\n");
+ do {
+ move(5, 1);
+ outs("¿ï¾Ü => ");
+ ch = igetch();
+ if(ch == 'q' || ch == 'Q')
+ return 0;
+ } while (ch < '1' || ch > '8');
+ ch -= '1';
+ search_key_user(choice[ch], 0);
+ return 0;
+}
+
+static void bperm_msg(boardheader_t *board) {
+ prints("\n³]©w [%s] ¬ÝªO¤§(%s)Åv­­¡G", board->brdname,
+ board->brdattr & BRD_POSTMASK ? "µoªí" : "¾\\Ū");
+}
+
+extern char* str_permboard[];
+
+unsigned int setperms(unsigned int pbits, char *pstring[]) {
+ register int i;
+ char choice[4];
+
+ move(4, 0);
+ for(i = 0; i < NUMPERMS / 2; i++) {
+ prints("%c. %-20s %-15s %c. %-20s %s\n",
+ 'A' + i, pstring[i],
+ ((pbits >> i) & 1 ? "£¾" : "¢æ"),
+ i < 10 ? 'Q' + i : '0' + i - 10,
+ pstring[i + 16],
+ ((pbits >> (i + 16)) & 1 ? "£¾" : "¢æ"));
+ }
+ clrtobot();
+ while(getdata(b_lines - 1, 0, "½Ð«ö [A-5] ¤Á´«³]©w¡A«ö [Return] µ²§ô¡G",
+ choice, 3, LCECHO)) {
+ i = choice[0] - 'a';
+ if(i < 0)
+ i = choice[0] - '0' + 26;
+ if(i >= NUMPERMS)
+ bell();
+ else {
+ pbits ^= (1 << i);
+ move(i % 16 + 4, i <= 15 ? 24 : 64);
+ prints((pbits >> i) & 1 ? "£¾" : "¢æ");
+ }
+ }
+ return pbits;
+}
+
+/* ¦Û°Ê³]¥ßºëµØ°Ï */
+void setup_man(boardheader_t * board) {
+ char genbuf[200];
+
+ setapath(genbuf, board->brdname);
+ mkdir(genbuf, 0755);
+}
+
+extern char *fn_board;
+extern char *err_bid;
+extern userec_t cuser;
+extern char *msg_sure_ny;
+extern char* str_permid[];
+
+int m_mod_board(char *bname) {
+ boardheader_t bh, newbh;
+ int bid;
+ char genbuf[256], ans[4];
+
+ bid = getbnum(bname);
+ if(!bid || !bname[0] || get_record(fn_board, &bh, sizeof(bh), bid) == -1) {
+ outs(err_bid);
+ pressanykey();
+ return -1;
+ }
+
+ prints("¬ÝªO¦WºÙ¡G%s\n¬ÝªO»¡©ú¡G%s\n¬ÝªObid¡G%d\n¬ÝªOGID¡G%d\n"
+ "ªO¥D¦W³æ¡G%s", bh.brdname, bh.title, bid, bh.gid, bh.BM);
+ bperm_msg(&bh);
+
+ /* Ptt ³oÃäÂ_¦æ·|Àɨì¤U­± */
+ move(9, 0);
+ sprintf(genbuf, "¬ÝªO (E)³]©w (V)¹Hªk/¸Ñ°£ %s (D)§R°£ [Q]¨ú®ø¡H",
+ HAS_PERM(PERM_SYSOP) ?
+ " (B)BVote (S)±Ï¦^¤å³¹" : "");
+ getdata(10, 0, genbuf, ans, 3, LCECHO);
+
+ switch(*ans) {
+ case 's':
+ if(HAS_PERM(PERM_SYSOP) ) {
+ char actionbuf[512];
+
+ sprintf(actionbuf, BBSHOME "/bin/buildir boards/%s &",
+ bh.brdname);
+ system(actionbuf);
+ }
+ break;
+ case 'b':
+ if(HAS_PERM(PERM_SYSOP)) {
+ char bvotebuf[10];
+
+ memcpy(&newbh, &bh, sizeof(bh));
+ sprintf(bvotebuf, "%d", newbh.bvote);
+ move(20, 0);
+ prints("¬Ýª© %s ­ì¨Óªº BVote¡G%d", bh.brdname, bh.bvote);
+ getdata_str(21, 0, "·sªº Bvote¡G", genbuf, 5, LCECHO, bvotebuf);
+ newbh.bvote = atoi(genbuf);
+ substitute_record(fn_board, &newbh, sizeof(newbh), bid);
+ reset_board(bid);
+ log_usies("SetBoardBvote", newbh.brdname);
+ break;
+ } else
+ break;
+ case 'v':
+ memcpy(&newbh, &bh, sizeof(bh));
+ outs("¬Ýª©¥Ø«e¬°");
+ outs((bh.brdattr & BRD_BAD) ? "¹Hªk" : "¥¿±`");
+ getdata(21, 0, "½T©w§ó§ï¡H", genbuf, 5, LCECHO);
+ if(genbuf[0] == 'y') {
+ if(newbh.brdattr & BRD_BAD)
+ newbh.brdattr = newbh.brdattr & (!BRD_BAD);
+ else
+ newbh.brdattr = newbh.brdattr | BRD_BAD;
+ substitute_record(fn_board, &newbh, sizeof(newbh), bid);
+ reset_board(bid);
+ log_usies("ViolateLawSet", newbh.brdname);
+ }
+ break;
+ case 'd':
+ getdata_str(9, 0, msg_sure_ny, genbuf, 3, LCECHO, "N");
+ if(genbuf[0] != 'y' || !bname[0])
+ outs(MSG_DEL_CANCEL);
+ else {
+ strcpy(bname, bh.brdname);
+ sprintf(genbuf,
+ "/bin/tar zcvf tmp/board_%s.tgz boards/%s man/%s >/dev/null 2>&1;"
+ "/bin/rm -fr boards/%s man/%s",
+ bname, bname, bname, bname, bname);
+ system(genbuf);
+ memset(&bh, 0, sizeof(bh));
+ sprintf(bh.title, "%s ¬ÝªO %s §R°£", bname, cuser.userid);
+ post_msg("Security", bh.title,"½Ðª`·N§R°£ªº¦Xªk©Ê","[¨t²Î¦w¥þ§½]");
+ substitute_record(fn_board, &bh, sizeof(bh), bid);
+ reset_board(bid);
+ log_usies("DelBoard", bh.title);
+ outs("§RªO§¹²¦");
+ }
+ break;
+ case 'e':
+ move(8, 0);
+ outs("ª½±µ«ö [Return] ¤£­×§ï¸Ó¶µ³]©w");
+ memcpy(&newbh, &bh, sizeof(bh));
+
+ while(getdata(9, 0, "·s¬ÝªO¦WºÙ¡G", genbuf, IDLEN + 1, DOECHO)) {
+ if(getbnum(genbuf)) {
+ move(3, 0);
+ outs("¿ù»~! ªO¦W¹p¦P");
+ } else if(!invalid_brdname(genbuf)) {
+ strcpy(newbh.brdname, genbuf);
+ break;
+ }
+ }
+
+ do {
+ getdata_str(12, 0, "¬ÝªOÃþ§O¡G", genbuf, 5, DOECHO, bh.title);
+ if(strlen(genbuf) == 4)
+ break;
+ } while (1);
+
+ if(strlen(genbuf) >= 4)
+ strncpy(newbh.title, genbuf, 4);
+
+ newbh.title[4] = ' ';
+
+ getdata_str(14, 0, "¬ÝªO¥DÃD¡G", genbuf, BTLEN + 1, DOECHO,
+ bh.title + 7);
+ if(genbuf[0])
+ strcpy(newbh.title + 7, genbuf);
+ if(getdata_str(15, 0, "·sªO¥D¦W³æ¡G", genbuf, IDLEN * 3 + 3, DOECHO,
+ bh.BM)) {
+ trim(genbuf);
+ strcpy(newbh.BM, genbuf);
+ }
+
+ if(HAS_PERM(PERM_SYSOP)) {
+ move(1, 0);
+ clrtobot();
+ newbh.brdattr = setperms(newbh.brdattr, str_permboard);
+ move(1, 0);
+ clrtobot();
+ }
+
+ if(newbh.brdattr & BRD_GROUPBOARD)
+ strncpy(newbh.title + 5, "£U", 2);
+ else if(newbh.brdattr & BRD_NOTRAN)
+ strncpy(newbh.title + 5, "¡·", 2);
+ else
+ strncpy(newbh.title + 5, "¡´", 2);
+
+ if(HAS_PERM(PERM_SYSOP) && !(newbh.brdattr & BRD_HIDE)) {
+ getdata_str(14, 0, "³]©wŪ¼gÅv­­(Y/N)¡H", ans, 4, LCECHO, "N");
+ if(*ans == 'y') {
+ getdata_str(15, 0, "­­¨î [R]¾\\Ū (P)µoªí¡H", ans, 4, LCECHO,
+ "R");
+ if(*ans == 'p')
+ newbh.brdattr |= BRD_POSTMASK;
+ else
+ newbh.brdattr &= ~BRD_POSTMASK;
+
+ move(1, 0);
+ clrtobot();
+ bperm_msg(&newbh);
+ newbh.level = setperms(newbh.level, str_permid);
+ clear();
+ }
+ }
+
+ getdata_str(b_lines - 1, 0, msg_sure_ny, genbuf, 4, LCECHO, "Y");
+
+ if((*genbuf == 'y') && memcmp(&newbh, &bh, sizeof(bh))) {
+ if(strcmp(bh.brdname, newbh.brdname)) {
+ char src[60], tar[60];
+
+ setbpath(src, bh.brdname);
+ setbpath(tar, newbh.brdname);
+ Rename(src, tar);
+
+ setapath(src, bh.brdname);
+ setapath(tar, newbh.brdname);
+ Rename(src, tar);
+ }
+ setup_man(&newbh);
+ substitute_record(fn_board, &newbh, sizeof(newbh), bid);
+ reset_board(bid);
+ log_usies("SetBoard", newbh.brdname);
+ }
+ }
+ return 0;
+}
+
+extern char *msg_bid;
+
+/* ³]©w¬Ýª© */
+int m_board() {
+ char bname[32];
+
+ stand_title("¬ÝªO³]©w");
+ make_blist();
+ namecomplete(msg_bid, bname);
+ if(!*bname)
+ return 0;
+ m_mod_board(bname);
+ return 0;
+}
+
+/* ³]©w¨t²ÎÀÉ®× */
+int x_file() {
+ int aborted;
+ char ans[4], *fpath;
+
+ move(b_lines - 4, 0);
+ /* Ptt */
+ outs("³]©w (1)¨­¥÷½T»{«H (4)postª`·N¨Æ¶µ (5)¿ù»~µn¤J°T®§ (6)µù¥U½d¨Ò (7)³q¹L½T»{³qª¾\n");
+ outs(" (8)email post³qª¾ (9)¨t²Î¥\\¯àºëÆF (A)¯ù¼Ó (B)¯¸ªø¦W³æ (C)email³q¹L½T»{\n");
+ outs(" (D)·s¨Ï¥ÎªÌ»Ýª¾ (E)¨­¥÷½T»{¤èªk (F)Åwªïµe­± (G)¶i¯¸µe­± "
+#ifdef MULTI_WELCOME_LOGIN
+"(X)§R°£¶i¯¸µe­±"
+#endif
+"\n");
+ getdata(b_lines - 1, 0, " (H)¬ÝªO´Á­­ (I)¬G¶m (J)¥X¯¸µe­± (K)¥Í¤é¥d (L)¸`¤é [Q]¨ú®ø¡H", ans, 3, LCECHO);
+
+ switch(ans[0]) {
+ case '1':
+ fpath = "etc/confirm";
+ break;
+ case '4':
+ fpath = "etc/post.note";
+ break;
+ case '5':
+ fpath = "etc/goodbye";
+ break;
+ case '6':
+ fpath = "etc/register";
+ break;
+ case '7':
+ fpath = "etc/registered";
+ break;
+ case '8':
+ fpath = "etc/emailpost";
+ break;
+ case '9':
+ fpath = "etc/hint";
+ break;
+ case 'a':
+ fpath = "etc/teashop";
+ break;
+ case 'b':
+ fpath = "etc/sysop";
+ break;
+ case 'c':
+ fpath = "etc/bademail";
+ break;
+ case 'd':
+ fpath = "etc/newuser";
+ break;
+ case 'e':
+ fpath = "etc/justify";
+ break;
+ case 'f':
+ fpath = "etc/Welcome";
+ break;
+ case 'g':
+#ifdef MULTI_WELCOME_LOGIN
+ getdata(b_lines - 1, 0, "²Ä´X­Ó¶i¯¸µe­±[0-4]", ans, 3, LCECHO);
+ if( ans[0] == '1' ) { fpath = "etc/Welcome_login.1"; }
+ else if( ans[0] == '2' ){ fpath = "etc/Welcome_login.2"; }
+ else if( ans[0] == '3' ){ fpath = "etc/Welcome_login.3"; }
+ else if( ans[0] == '4' ){ fpath = "etc/Welcome_login.4"; }
+ else { fpath = "etc/Welcome_login.0"; }
+#else
+ fpath = "etc/Welcome_login";
+#endif
+ break;
+
+#ifdef MULTI_WELCOME_LOGIN
+ case 'x':
+ getdata(b_lines - 1, 0, "²Ä´X­Ó¶i¯¸µe­±[1-4]", ans, 3, LCECHO);
+ if( ans[0] == '1' ) { unlink("etc/Welcome_login.1"); outs("ok"); }
+ else if( ans[0] == '2' ){ unlink("etc/Welcome_login.2"); outs("ok"); }
+ else if( ans[0] == '3' ){ unlink("etc/Welcome_login.3"); outs("ok"); }
+ else if( ans[0] == '4' ){ unlink("etc/Welcome_login.4"); outs("ok"); }
+ else {outs("©Ò«ü©wªº¶i¯¸µe­±µLªk§R°£"); }
+ pressanykey();
+ return FULLUPDATE;
+
+#endif
+
+ case 'h':
+ fpath = "etc/expire.conf";
+ break;
+ case 'i':
+ fpath = "etc/domain_name_query";
+ break;
+ case 'j':
+ fpath = "etc/Logout";
+ break;
+ case 'k':
+ fpath = "etc/Welcome_birth";
+ break;
+ case 'l':
+ fpath = "etc/feast";
+ break;
+ default:
+ return FULLUPDATE;
+ }
+ aborted = vedit(fpath, NA, NULL);
+ prints("\n\n¨t²ÎÀÉ®×[%s]¡G%s", fpath,
+ (aborted == -1) ? "¥¼§ïÅÜ" : "§ó·s§¹²¦");
+ pressanykey();
+ return FULLUPDATE;
+}
+
+extern int numboards;
+extern int class_bid;
+
+int m_newbrd(int recover) {
+ boardheader_t newboard;
+ char ans[4];
+ int bid;
+ char genbuf[200];
+
+ stand_title("«Ø¥ß·sªO");
+ memset(&newboard, 0, sizeof(newboard));
+
+ newboard.gid = class_bid;
+ if (newboard.gid == 0) {
+ move(6, 0);
+ outs("½Ð¥ý¿ï¾Ü¤@­ÓÃþ§O¦A¶}ªO!");
+ pressanykey();
+ return -1;
+ }
+
+ do {
+ if(!getdata(3, 0, msg_bid, newboard.brdname, IDLEN + 1, DOECHO))
+ return -1;
+ } while(invalid_brdname(newboard.brdname));
+
+ do {
+ getdata(6, 0, "¬ÝªOÃþ§O¡G", genbuf, 5, DOECHO);
+ if(strlen(genbuf) == 4)
+ break;
+ } while (1);
+
+ if(strlen(genbuf) >= 4)
+ strncpy(newboard.title, genbuf, 4);
+
+ newboard.title[4] = ' ';
+
+ getdata(8, 0, "¬ÝªO¥DÃD¡G", genbuf, BTLEN + 1, DOECHO);
+ if(genbuf[0])
+ strcpy(newboard.title + 7, genbuf);
+ setbpath(genbuf, newboard.brdname);
+
+ if(recover) {
+ struct stat sb;
+
+ if(stat(genbuf, &sb) == -1 || !(sb.st_mode & S_IFDIR)) {
+ outs("¦¹¬ÝªO¤w¸g¦s¦b! ½Ð¨ú¤£¦P­^¤åªO¦W");
+ pressanykey();
+ return -1;
+ }
+ } else if(getbnum(newboard.brdname) > 0 || mkdir(genbuf, 0755) == -1) {
+ outs("¦¹¬ÝªO¤w¸g¦s¦b! ½Ð¨ú¤£¦P­^¤åªO¦W");
+ pressanykey();
+ return -1;
+ }
+
+ newboard.brdattr = BRD_NOTRAN;
+
+ if(HAS_PERM(PERM_SYSOP)) {
+ move(1, 0);
+ clrtobot();
+ newboard.brdattr = setperms(newboard.brdattr, str_permboard);
+ move(1, 0);
+ clrtobot();
+ }
+ getdata(9, 0, "¬O¬ÝªO? (N:¥Ø¿ý) (Y/n)¡G", genbuf, 3, LCECHO);
+ if(genbuf[0]=='n')
+ newboard.brdattr |= BRD_GROUPBOARD;
+
+ if(newboard.brdattr & BRD_GROUPBOARD)
+ strncpy(newboard.title + 5, "£U", 2);
+ else if(newboard.brdattr & BRD_NOTRAN)
+ strncpy(newboard.title + 5, "¡·", 2);
+ else
+ strncpy(newboard.title + 5, "¡´", 2);
+
+ newboard.level = 0;
+ getdata(11, 0, "ªO¥D¦W³æ¡G", newboard.BM, IDLEN * 3 + 3, DOECHO);
+
+ if(HAS_PERM(PERM_SYSOP) && !(newboard.brdattr & BRD_HIDE)) {
+ getdata_str(14, 0, "³]©wŪ¼gÅv­­(Y/N)¡H", ans, 3, LCECHO, "N");
+ if(*ans == 'y') {
+ getdata_str(15, 0, "­­¨î [R]¾\\Ū (P)µoªí¡H", ans, 4, LCECHO, "R");
+ if(*ans == 'p')
+ newboard.brdattr |= BRD_POSTMASK;
+ else
+ newboard.brdattr &= (~BRD_POSTMASK);
+
+ move(1, 0);
+ clrtobot();
+ bperm_msg(&newboard);
+ newboard.level = setperms(newboard.level, str_permid);
+ clear();
+ }
+ }
+
+ if((bid = getbnum("")) > 0)
+ {
+ substitute_record(fn_board, &newboard, sizeof(newboard), bid);
+ reset_board(bid);
+ }
+ else if(append_record(fn_board, (fileheader_t *) & newboard,
+ sizeof(newboard)) == -1) {
+ pressanykey();
+ return -1;
+ }
+ else
+ {
+ addbrd_touchcache();
+ }
+ setup_man(&newboard);
+
+ outs("\n·sªO¦¨¥ß");
+ post_newboard(newboard.title, newboard.brdname, newboard.BM);
+ log_usies("NewBoard", newboard.title);
+ pressanykey();
+ return 0;
+}
+
+static int auto_scan(char fdata[][STRLEN], char ans[]) {
+ int good = 0;
+ int count = 0;
+ int i;
+ char temp[10];
+
+ if(!strncmp(fdata[2], "¤p", 2) || strstr(fdata[2], "¤X")
+ || strstr(fdata[2], "½Ö") || strstr(fdata[2], "¤£")) {
+ ans[0] = '0';
+ return 1;
+ }
+
+ strncpy(temp, fdata[2], 2);
+ temp[2] = '\0';
+
+ /* Å|¦r */
+ if(!strncmp(temp, &(fdata[2][2]), 2)) {
+ ans[0] = '0';
+ return 1;
+ }
+
+ if(strlen(fdata[2]) >= 6) {
+ if(strstr(fdata[2], "³¯¤ô«ó")) {
+ ans[0] = '0';
+ return 1;
+ }
+
+ if(strstr("»¯¿ú®]§õ©P§d¾G¤ý", temp))
+ good++;
+ else if(strstr("§ùÃC¶ÀªL³¯©x§E¨¯¼B", temp))
+ good++;
+ else if(strstr("Ĭ¤è§d§f§õªò±i¹ùÀ³Ä¬", temp))
+ good++;
+ else if(strstr("®}ÁÂ¥Û¿c¬IÀ¹¯Î­ð", temp))
+ good++;
+ }
+
+ if(!good)
+ return 0;
+
+ if(!strcmp(fdata[3], fdata[4]) ||
+ !strcmp(fdata[3], fdata[5]) ||
+ !strcmp(fdata[4], fdata[5])) {
+ ans[0] = '4';
+ return 5;
+ }
+
+ if(strstr(fdata[3], "¤j")) {
+ if (strstr(fdata[3], "¥x") || strstr(fdata[3], "²H") ||
+ strstr(fdata[3], "¥æ") || strstr(fdata[3], "¬F") ||
+ strstr(fdata[3], "²M") || strstr(fdata[3], "ĵ") ||
+ strstr(fdata[3], "®v") || strstr(fdata[3], "»Ê¶Ç") ||
+ strstr(fdata[3], "¤¤¥¡") || strstr(fdata[3], "¦¨") ||
+ strstr(fdata[3], "»²") || strstr(fdata[3], "ªF§d"))
+ good++;
+ } else if(strstr(fdata[3], "¤k¤¤"))
+ good++;
+
+ if(strstr(fdata[4], "¦a²y") || strstr(fdata[4], "¦t©z") ||
+ strstr(fdata[4], "«H½c")) {
+ ans[0] = '2';
+ return 3;
+ }
+
+ if(strstr(fdata[4], "¥«") || strstr(fdata[4], "¿¤")) {
+ if(strstr(fdata[4], "¸ô") || strstr(fdata[4], "µó")) {
+ if(strstr(fdata[4], "¸¹"))
+ good++;
+ }
+ }
+
+ for(i = 0; fdata[5][i]; i++) {
+ if(isdigit(fdata[5][i]))
+ count++;
+ }
+
+ if(count <= 4) {
+ ans[0] = '3';
+ return 4;
+ } else if(count >= 7)
+ good++;
+
+ if(good >= 3) {
+ ans[0] = 'y';
+ return -1;
+ } else
+ return 0;
+}
+
+/* ³B²z Register Form */
+int scan_register_form(char *regfile, int automode, int neednum) {
+ char genbuf[200];
+ static char *logfile = "register.log";
+ static char *field[] = {
+ "uid", "ident", "name", "career", "addr", "phone", "email", NULL
+ };
+ static char *finfo[] = {
+ "±b¸¹", "¨­¤ÀÃÒ¸¹", "¯u¹ê©m¦W", "ªA°È³æ¦ì", "¥Ø«e¦í§}",
+ "³sµ¸¹q¸Ü", "¹q¤l¶l¥ó«H½c", NULL
+ };
+ static char *reason[] = {
+ "¿é¤J¯u¹ê©m¦W", "¸Ô¶ñ¾Ç®Õ¬ì¨t»P¦~¯Å", "¶ñ¼g§¹¾ãªº¦í§}¸ê®Æ",
+ "¸Ô¶ñ³sµ¸¹q¸Ü", "½T¹ê¶ñ¼gµù¥U¥Ó½Ðªí", "¥Î¤¤¤å¶ñ¼g¥Ó½Ð³æ", NULL
+ };
+ static char *autoid = "AutoScan";
+ userec_t muser;
+ FILE *fn, *fout, *freg;
+ char fdata[7][STRLEN];
+ char fname[STRLEN], buf[STRLEN];
+ char ans[4], *ptr, *uid;
+ int n, unum;
+ int nSelf = 0, nAuto = 0;
+
+ uid = cuser.userid;
+ sprintf(fname, "%s.tmp", regfile);
+ move(2, 0);
+ if(dashf(fname)) {
+ if(neednum == 0) { /* ¦Û¤v¶i Admin ¨Ó¼fªº */
+ outs("¨ä¥L SYSOP ¤]¦b¼f®Öµù¥U¥Ó½Ð³æ");
+ pressanykey();
+ }
+ return -1;
+ }
+ Rename(regfile, fname);
+ if((fn = fopen(fname, "r")) == NULL) {
+ prints("¨t²Î¿ù»~¡AµLªkŪ¨úµù¥U¸ê®ÆÀÉ: %s", fname);
+ pressanykey();
+ return -1;
+ }
+ if(neednum) { /* ³Q±j­¢¼fªº */
+ move(1, 0);
+ clrtobot();
+ prints("¦U¦ì¨ã¦³¯¸ªøÅv­­ªº¤H¡Aµù¥U³æ²Ö¿n¶W¹L¤@¦Ê¥÷¤F¡A³Â·Ð±zÀ°¦£¼f %d ¥÷\n", neednum);
+ prints("¤]´N¬O¤j·§¤G¤Q¤À¤§¤@ªº¼Æ¶q¡A·íµM¡A±z¤]¥i¥H¦h¼f\n¨S¼f§¹¤§«e¡A¨t²Î¤£·|Åý§A¸õ¥X³é¡IÁÂÁÂ");
+ pressanykey();
+ }
+ memset(fdata, 0, sizeof(fdata));
+ while(fgets(genbuf, STRLEN, fn)) {
+ if ((ptr = (char *) strstr(genbuf, ": "))) {
+ *ptr = '\0';
+ for(n = 0; field[n]; n++) {
+ if(strcmp(genbuf, field[n]) == 0) {
+ strcpy(fdata[n], ptr + 2);
+ if((ptr = (char *) strchr(fdata[n], '\n')))
+ *ptr = '\0';
+ }
+ }
+ } else if ((unum = getuser(fdata[0])) == 0) {
+ move(2, 0);
+ clrtobot();
+ outs("¨t²Î¿ù»~¡A¬dµL¦¹¤H\n\n");
+ for (n = 0; field[n]; n++)
+ prints("%s : %s\n", finfo[n], fdata[n]);
+ pressanykey();
+ neednum--;
+ } else {
+ neednum--;
+ memcpy(&muser, &xuser, sizeof(muser));
+ if(automode)
+ uid = autoid;
+
+ if(!automode || !auto_scan(fdata, ans)) {
+ uid = cuser.userid;
+
+ move(1, 0);
+ prints("±b¸¹¦ì¸m ¡G%d\n", unum);
+ user_display(&muser, 1);
+ move(14, 0);
+ prints("\033[1;32m------------- ½Ð¯¸ªøÄY®æ¼f®Ö¨Ï¥ÎªÌ¸ê®Æ¡A±zÁÙ¦³ %d ¥÷---------------\033[m\n", neednum);
+ for(n = 0; field[n]; n++) {
+ if(n >= 2 && n <= 5)
+ prints("%d.", n - 2);
+ else
+ prints(" ");
+ prints("%-12s¡G%s\n", finfo[n], fdata[n]);
+ }
+ if(muser.userlevel & PERM_LOGINOK) {
+ getdata(b_lines - 1, 0, "\033[1;32m¦¹±b¸¹¤w¸g§¹¦¨µù¥U, "
+ "§ó·s(Y/N/Skip)¡H\033[m[N] ", ans, 3, LCECHO);
+ if(ans[0] != 'y' && ans[0] != 's')
+ ans[0] = 'd';
+ } else {
+ getdata(b_lines - 1, 0,
+ "¬O§_±µ¨ü¦¹¸ê®Æ(Y/N/Q/Del/Skip)¡H[Y] ",
+ ans, 3, LCECHO);
+ }
+ nSelf++;
+ } else
+ nAuto++;
+ if(neednum > 0 && ans[0] == 'q') {
+ move(2, 0);
+ clrtobot();
+ prints("¨S¼f§¹¤£¯à°h¥X");
+ pressanykey();
+ ans[0] = 's';
+ }
+
+ switch(ans[0]) {
+ case 'q':
+ if((freg = fopen(regfile, "a"))) {
+ for(n = 0; field[n]; n++)
+ fprintf(freg, "%s: %s\n", field[n], fdata[n]);
+ fprintf(freg, "----\n");
+ while(fgets(genbuf, STRLEN, fn))
+ fputs(genbuf, freg);
+ fclose(freg);
+ }
+ case 'd':
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case 'n':
+ if(ans[0] == 'n') {
+ for(n = 0; field[n]; n++)
+ prints("%s: %s\n", finfo[n], fdata[n]);
+ move(9, 0);
+ prints("½Ð´£¥X°h¦^¥Ó½Ðªí­ì¦]¡A«ö <enter> ¨ú®ø\n");
+ for (n = 0; reason[n]; n++)
+ prints("%d) ½Ð%s\n", n, reason[n]);
+ } else
+ buf[0] = ans[0];
+ if(ans[0] != 'n' ||
+ getdata(10 + n, 0, "°h¦^­ì¦]¡G", buf, 60, DOECHO))
+ if((buf[0] - '0') >= 0 && (buf[0] - '0') < n) {
+ int i;
+ fileheader_t mhdr;
+ char title[128], buf1[80];
+ FILE *fp;
+
+ i = buf[0] - '0';
+ strcpy(buf, reason[i]);
+ sprintf(genbuf, "[°h¦^­ì¦]] ½Ð%s", buf);
+
+ sethomepath(buf1, muser.userid);
+ stampfile(buf1, &mhdr);
+ strcpy(mhdr.owner, cuser.userid);
+ strncpy(mhdr.title, "[µù¥U¥¢±Ñ]", TTLEN);
+ mhdr.savemode = 0;
+ mhdr.filemode = 0;
+ sethomedir(title, muser.userid);
+ if(append_record(title, &mhdr, sizeof(mhdr)) != -1) {
+ fp = fopen(buf1, "w");
+ fprintf(fp, "%s\n", genbuf);
+ fclose(fp);
+ }
+ if((fout = fopen(logfile, "a"))) {
+ for(n = 0; field[n]; n++)
+ fprintf(fout, "%s: %s\n", field[n], fdata[n]);
+ n = time(NULL);
+ fprintf(fout, "Date: %s\n", Cdate((time_t *) & n));
+ fprintf(fout, "Rejected: %s [%s]\n----\n",
+ uid, buf);
+ fclose(fout);
+ }
+ break;
+ }
+ move(10, 0);
+ clrtobot();
+ prints("¨ú®ø°h¦^¦¹µù¥U¥Ó½Ðªí");
+ case 's':
+ if((freg = fopen(regfile, "a"))) {
+ for(n = 0; field[n]; n++)
+ fprintf(freg, "%s: %s\n", field[n], fdata[n]);
+ fprintf(freg, "----\n");
+ fclose(freg);
+ }
+ break;
+ default:
+ prints("¥H¤U¨Ï¥ÎªÌ¸ê®Æ¤w¸g§ó·s:\n");
+ mail_muser(muser, "[µù¥U¦¨¥\\Åo]", "etc/registered");
+ muser.userlevel |= (PERM_LOGINOK | PERM_POST);
+ strcpy(muser.realname, fdata[2]);
+ strcpy(muser.address, fdata[4]);
+ strcpy(muser.email, fdata[6]);
+ sprintf(genbuf, "%s:%s:%s", fdata[5], fdata[3], uid);
+ strncpy(muser.justify, genbuf, REGLEN);
+ sethomefile(buf, muser.userid, "justify");
+ log_file(buf, genbuf);
+ passwd_update(unum, &muser);
+
+ if((fout = fopen(logfile, "a"))) {
+ for(n = 0; field[n]; n++)
+ fprintf(fout, "%s: %s\n", field[n], fdata[n]);
+ n = time(NULL);
+ fprintf(fout, "Date: %s\n", Cdate((time_t *) & n));
+ fprintf(fout, "Approved: %s\n", uid);
+ fprintf(fout, "----\n");
+ fclose(fout);
+ }
+ break;
+ }
+ }
+ }
+ fclose(fn);
+ unlink(fname);
+
+ move(0, 0);
+ clrtobot();
+
+ move(5, 0);
+ prints("±z¼f¤F %d ¥÷µù¥U³æ¡AAutoScan ¼f¤F %d ¥÷", nSelf, nAuto);
+
+/** DickG: ±N¼f¤F´X¥÷ªº¬ÛÃö¸ê®Æ post ¨ì Security ªO¤W ***********/
+/* DickG: ¦]À³·sªº¯¸ªø¤W¯¸»Ý¼f®Ö¤è®×¡A¬O¬G¨S¦³¥²­n¯d¤U record ¦ÓÃö±¼
+ strftime(buf, 200, "%Y/%m/%d/%H:%M", pt);
+
+ strcpy(xboard, "Security");
+ setbpath(xfpath, xboard);
+ stampfile(xfpath, &xfile);
+ strcpy(xfile.owner, "¨t²Î");
+ strcpy(xfile.title, "[³ø§i] ¼f®Ö°O¿ý");
+ xfile.savemode = 'S';
+ xptr = fopen(xfpath, "w");
+ fprintf(xptr, "\n®É¶¡¡G%s
+ %s ¼f¤F %d ¥÷µù¥U³æ\n
+ AutoScan ¼f¤F %d ¥÷µù¥U³æ\n
+ ¦@­p %d ¥÷¡C",
+ buf, cuser.userid, nSelf, nAuto, nSelf+nAuto);
+ fclose(xptr);
+ setbdir(fname, xboard);
+ append_record(fname, &xfile, sizeof(xfile));
+ outgo_post(&xfile, xboard);
+ touchbtotal(getbnum(xboard));
+ cuser.numposts++;
+*/
+/*********************************************/
+ pressanykey();
+ return (0);
+}
+
+extern char* fn_register;
+extern int t_lines;
+
+int m_register() {
+ FILE *fn;
+ int x, y, wid, len;
+ char ans[4];
+ char genbuf[200];
+
+ if((fn = fopen(fn_register, "r")) == NULL) {
+ outs("¥Ø«e¨ÃµL·sµù¥U¸ê®Æ");
+ return XEASY;
+ }
+
+ stand_title("¼f®Ö¨Ï¥ÎªÌµù¥U¸ê®Æ");
+ y = 2;
+ x = wid = 0;
+
+ while(fgets(genbuf, STRLEN, fn) && x < 65) {
+ if(strncmp(genbuf, "uid: ", 5) == 0) {
+ move(y++, x);
+ outs(genbuf + 5);
+ len = strlen(genbuf + 5);
+ if(len > wid)
+ wid = len;
+ if(y >= t_lines - 3) {
+ y = 2;
+ x += wid + 2;
+ }
+ }
+ }
+ fclose(fn);
+ getdata(b_lines - 1, 0, "¶}©l¼f®Ö¶Ü(Auto/Yes/No)¡H[N] ", ans, 3, LCECHO);
+ if(ans[0] == 'a')
+ scan_register_form(fn_register, 1, 0);
+ else if(ans[0] == 'y')
+ scan_register_form(fn_register, 0, 0);
+
+ return 0;
+}
+
+int cat_register() {
+ if(system("cat register.new.tmp >> register.new") == 0 &&
+ system("rm -f register.new.tmp") == 0)
+ mprints(22, 0, "OK ÂP~~ Ä~Äò¥h¾Ä°«§a!! ");
+ else
+ mprints(22, 0, "¨S¿ìªkCAT¹L¥h©O ¥hÀˬd¤@¤U¨t²Î§a!! ");
+ pressanykey();
+ return 0;
+}
+
+static void give_id_money(char *user_id, int money, FILE *log_fp, char *mail_title, time_t t) {
+ char tt[TTLEN + 1] = {0};
+
+ if(deumoney(searchuser(user_id), money) < 0) {
+ move(12, 0);
+ clrtoeol();
+ prints("id:%s money:%d ¤£¹ï§a!!", user_id, money);
+ pressanykey();
+ } else {
+ fprintf(log_fp, "%ld %s %d", t, user_id, money);
+ sprintf(tt, "%s : %d ptt ¹ô", mail_title, money);
+ mail_id(user_id, tt, "~bbs/etc/givemoney.why", "[PTT »È¦æ]");
+ }
+}
+
+int give_money() {
+ FILE *fp, *fp2;
+ char *ptr, *id, *mn;
+ char buf[200] = {0}, tt[TTLEN + 1] = {0};
+ time_t t = time(NULL);
+ struct tm *pt = localtime(&t);
+ int to_all = 0, money = 0;
+
+ getdata(0, 0, "«ü©w¨Ï¥ÎªÌ(S) ¥þ¯¸¨Ï¥ÎªÌ(A) ¨ú®ø(Q)¡H[S]", buf, 3, LCECHO);
+ if(buf[0] == 'q')
+ return 1;
+ else if( buf[0] == 'a') {
+ to_all = 1;
+ getdata(1, 0, "µo¦h¤Ö¿ú©O?", buf, 20, DOECHO);
+ money = atoi(buf);
+ if(money <= 0) {
+ move(2, 0);
+ prints("¿é¤J¿ù»~!!");
+ pressanykey();
+ return 1;
+ }
+ } else {
+ if(vedit("etc/givemoney.txt", NA, NULL) < 0)
+ return 1;
+ }
+
+ clear();
+ getdata(0, 0, "­nµo¿ú¤F¶Ü(Y/N)[N]", buf, 3, LCECHO);
+ if(buf[0] != 'y')
+ return 1;
+
+ if(!(fp2 = fopen("etc/givemoney.log", "a")))
+ return 1;
+ strftime(buf, 200, "%Y/%m/%d/%H:%M", pt);
+ fprintf(fp2, "%s\n", buf);
+
+ getdata(1, 0, "¬õ¥]³U¼ÐÃD ¡G", tt, TTLEN, DOECHO);
+ move(2, 0);
+
+ prints("½s¬õ¥]³U¤º®e");
+ pressanykey();
+ if(vedit("etc/givemoney.why", NA, NULL) < 0)
+ return 1;
+
+ stand_title("µo¿ú¤¤...");
+ if(to_all) {
+ extern struct uhash_t *uhash;
+ int i, unum;
+ for(unum = uhash->number, i=0; i<unum; i++) {
+ if(bad_user_id(uhash->userid[i]))
+ continue;
+ id = uhash->userid[i];
+ give_id_money(id, money, fp2, tt, t);
+ }
+ } else {
+ if(!(fp = fopen("etc/givemoney.txt", "r+"))) {
+ fclose(fp2);
+ return 1;
+ }
+ while(fgets(buf, 255, fp)) {
+// clear();
+ if (!(ptr = strchr(buf, ':')))
+ continue;
+ *ptr = '\0';
+ id = buf;
+ mn = ptr + 1;
+ give_id_money(id, atoi(mn), fp2, tt, t);
+ }
+ fclose(fp);
+ }
+
+ fclose(fp2);
+ pressanykey();
+ return FULLUPDATE;
+}
diff --git a/mbbsd/announce.c b/mbbsd/announce.c
new file mode 100644
index 00000000..960a45aa
--- /dev/null
+++ b/mbbsd/announce.c
@@ -0,0 +1,1590 @@
+/* $Id: announce.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "perm.h"
+#include "common.h"
+#include "modes.h"
+#include "proto.h"
+
+extern int b_lines;
+extern int p_lines;
+extern int TagNum;
+extern int currbid;
+static void g_showmenu(gmenu_t *pm) {
+ static char *mytype = "½s ¿ï µ·¸ô¤§®È";
+ char *title, ch;
+ int n, max;
+ item_t *item;
+
+ showtitle("ºëµØ¤å³¹", pm->mtitle);
+ prints(" \033[1;36m½s¸¹ ¼Ð ÃD%56s\033[m", mytype);
+
+ if(pm->num) {
+ n = pm->page;
+ max = n + p_lines;
+ if(max > pm->num)
+ max = pm->num;
+ while(n < max) {
+ item = pm->item[n++];
+ title = item->title;
+ ch = title[1];
+ prints("\n%5d. %-72.71s", n, title);
+ }
+ } else
+ outs("\n ¡mºëµØ°Ï¡n©|¦b§l¨ú¤Ñ¦a¶¡ªº¤éºë¤ëµØ :)");
+
+ move(b_lines, 1);
+ outs(pm->level ?
+ "\033[34;46m ¡iªO ¥D¡j \033[31;47m (h)\033[30m»¡©ú "
+ "\033[31m(q/¡ö)\033[30mÂ÷¶} \033[31m(n)\033[30m·s¼W¤å³¹ "
+ "\033[31m(g)\033[30m·s¼W¥Ø¿ý \033[31m(e)\033[30m½s¿èÀÉ®× \033[m" :
+ "\033[34;46m ¡i¥\\¯àÁä¡j \033[31;47m (h)\033[30m»¡©ú "
+ "\033[31m(q/¡ö)\033[30mÂ÷¶} \033[31m(k¡ôj¡õ)\033[30m²¾°Ê´å¼Ð "
+ "\033[31m(enter/¡÷)\033[30mŪ¨ú¸ê®Æ \033[m");
+}
+
+static FILE *go_cmd(item_t *node, int *sock) {
+ struct sockaddr_in sin;
+ struct hostent *host;
+ char *site;
+ FILE *fp;
+
+ *sock = socket(AF_INET, SOCK_STREAM, 0);
+
+ if(*sock < 0) {
+ syslog(LOG_ERR, "socket(): %m");
+ return NULL;
+ }
+ memset((char *)&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(node->X.G.port);
+
+ host = gethostbyname(site = node->X.G.server);
+ if(host == NULL)
+ sin.sin_addr.s_addr = inet_addr(site);
+ else
+ memcpy(&sin.sin_addr.s_addr, host->h_addr, host->h_length);
+
+ if(connect(*sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ syslog(LOG_ERR, "connect(): %m");
+ return NULL;
+ }
+ fp = fdopen(*sock, "r+");
+ if(fp != NULL) {
+ setbuf(fp, (char *) 0);
+ fprintf(fp, "%s\r\n", node->X.G.path);
+ fflush(fp);
+ } else
+ close(*sock);
+ return fp;
+}
+
+static char *nextfield(char *data, char *field) {
+ register int ch;
+
+ while((ch = *data)) {
+ data++;
+ if((ch == '\t') || (ch == '\r' && *data == '\n'))
+ break;
+ *field++ = ch;
+ }
+ *field = '\0';
+ return data;
+}
+
+extern char *str_author1;
+
+static FILE* my_open(char* path) {
+ FILE* ans = 0;
+ char buf[80];
+ struct stat st;
+ time_t now = time(0);
+
+ if(stat(path, &st) == 0 && st.st_mtime < now - 3600 * 24 * 7) {
+ return fopen(path, "w");
+ }
+
+ if((ans = fopen(path, "r+"))) {
+ fclose(ans);
+ return 0;
+ /*
+ return directly due to currutmp->pager > 1 mode (real copy)
+ */
+ fgets(buf, 80, ans);
+ if(!strncmp(buf, str_author1, strlen(str_author1)) ||
+ *buf == '0' || *buf == '1') {
+ fclose(ans);
+ return 0;
+ }
+
+ rewind(ans);
+ } else
+ ans = fopen(path, "w");
+ return ans;
+}
+
+static jmp_buf jbuf;
+
+static void isig(int sig) {
+ longjmp(jbuf, 1);
+}
+
+#define PROXY_HOME "proxy/"
+extern userec_t cuser;
+extern userinfo_t *currutmp;
+
+static void go_proxy(char* fpath, item_t *node, int update) {
+ char *ptr, *str, *server;
+ int ch;
+ static FILE *fo;
+
+ strcpy(fpath, PROXY_HOME);
+ ptr = fpath + sizeof(PROXY_HOME) - 1;
+ str = server = node->X.G.server;
+ while((ch = *str)) {
+ str++;
+ if(ch == '.') {
+ if(!strcmp(str, "edu.tw"))
+ break;
+ } else if(ch >= 'A' && ch <= 'Z') {
+ ch |= 0x20;
+ }
+ *ptr++ = ch;
+ }
+ *ptr = '\0';
+ mkdir(fpath, 0755);
+
+ *ptr++ = '/';
+ str = node->X.G.path;
+ while((ch = *str)) {
+ str++;
+ if(ch == '/') {
+ ch = '.';
+ }
+ *ptr++ = ch;
+ }
+ *ptr = '\0';
+
+ /* expire proxy data */
+
+ if((fo = update ? fopen(fpath, "w") : my_open(fpath))) {
+ FILE *fp;
+ char buf[512];
+ int sock;
+
+ if(fo == NULL)
+ return;
+
+ outmsg("¡¹ «Ø¥ß proxy ¸ê®Æ³s½u¤¤ ... ");
+ refresh();
+
+ sock = -1;
+ if(setjmp(jbuf)) {
+ if(sock != -1)
+ close(sock);
+ fseek(fo, 0, SEEK_SET);
+ fwrite("", 0, 0, fo);
+ fclose(fo);
+ alarm(0);
+ return;
+ }
+
+ signal(SIGALRM, isig);
+ alarm(5);
+ fp = go_cmd(node, &sock);
+ alarm(0);
+
+ str = node->title;
+ ch = str[1];
+ if(ch == (char) 0xbc &&
+ !(HAS_PERM(PERM_SYSOP) && currutmp->pager > 1)) {
+ time_t now;
+
+ time(&now);
+ fprintf(fo, "§@ªÌ: %s (³s½uºëµØ°Ï)\n¼ÐÃD: %s\n®É¶¡: %s\n",
+ server, str + 3, ctime(&now)
+ );
+ }
+
+ while(fgets(buf, 511, fp)) {
+ if(!strcmp(buf, ".\r\n"))
+ break;
+ if((ptr = strstr(buf, "\r\n")))
+ strcpy(ptr, "\n");
+ fputs(buf, fo);
+ }
+ fclose(fo);
+ fclose(fp);
+ }
+}
+
+static void g_additem(gmenu_t *pm, item_t *myitem) {
+ if(pm->num < MAX_ITEMS) {
+ item_t *newitem = (item_t *)malloc(sizeof(item_t));
+
+ memcpy(newitem, myitem, sizeof(item_t));
+ pm->item[(pm->num)++] = newitem;
+ }
+}
+
+static void go_menu(gmenu_t *pm, item_t *node, int update) {
+ FILE *fp;
+ char buf[512], *ptr, *title;
+ item_t item;
+ int ch;
+
+ go_proxy(buf, node, update);
+ pm->num = 0;
+ if((fp = fopen(buf, "r"))) {
+ title = item.title;
+ while(fgets(buf, 511, fp)) {
+ ptr = buf;
+ ch = *ptr++;
+ if(ch != '0' && ch != '1')
+ continue;
+
+ strcpy(title, "¡¼ ");
+ if(ch == '1')
+ title[1] = (char) 0xbd;
+
+ ptr = nextfield(ptr, title + 3);
+ if(!*ptr)
+ continue;
+ title[sizeof(item.title) - 1] = '\0';
+
+ ptr = nextfield(ptr, item.X.G.path);
+ if(!*ptr)
+ continue;
+
+ ptr = nextfield(ptr, item.X.G.server);
+ if(!*ptr)
+ continue;
+
+ nextfield(ptr, buf);
+ item.X.G.port = atoi(buf);
+
+ g_additem(pm, &item);
+ }
+ fclose(fp);
+ }
+}
+
+static int g_searchtitle(gmenu_t* pm, int rev) {
+ static char search_str[30] = "";
+ int pos;
+
+ if(getdata(b_lines - 1, 1,"[·j´M]ÃöÁä¦r:", search_str, 40, DOECHO))
+ if(!*search_str)
+ return pm->now;
+
+ str_lower(search_str, search_str);
+
+ rev = rev ? -1 : 1;
+ pos = pm->now;
+ do {
+ pos += rev;
+ if(pos == pm->num)
+ pos = 0;
+ else if(pos < 0)
+ pos = pm->num - 1;
+ if(strstr_lower(pm->item[pos]->title, search_str))
+ return pos;
+ } while(pos != pm->now);
+ return pm->now;
+}
+
+static void g_showhelp() {
+ clear();
+ outs("\033[36m¡i " BBSNAME "³s½uºëµØ°Ï¨Ï¥Î»¡©ú ¡j\033[m\n\n"
+ "[¡ö][q] Â÷¶}¨ì¤W¤@¼h¥Ø¿ý\n"
+ "[¡ô][k] ¤W¤@­Ó¿ï¶µ\n"
+ "[¡õ][j] ¤U¤@­Ó¿ï¶µ\n"
+ "[¡÷][r][enter] ¶i¤J¥Ø¿ý¡þŪ¨ú¤å³¹\n"
+ "[b][PgUp] ¤W­¶¿ï³æ\n"
+ "[^F][PgDn][Spc] ¤U­¶¿ï³æ\n"
+ "[##] ²¾¨ì¸Ó¿ï¶µ\n"
+ "[^S] ±N¤å³¹¦s¨ì«H½c\n"
+ "[R] §ó·s¸ê®Æ\n"
+ "[N] ¬d¸ßÀɦW\n"
+ "[c][C][^C] «þ¨©¤å³¹/¨Ã¸õ¦Ü¤W¦¸¶K¤å³¹ªº¦a¤è/"
+ "ª½±µ¶K¨ì¤W¦¸¶Kªº¦a¤è\n");
+ pressanykey();
+}
+
+#define PATHLEN 256
+
+static char paste_fname[200];
+extern time_t paste_time;
+extern char paste_path[];
+extern char paste_title[];
+extern int paste_level;
+
+static void load_paste() {
+ struct stat st;
+ FILE *fp;
+
+ if(!*paste_fname)
+ setuserfile(paste_fname, "paste_path");
+ if(stat(paste_fname, &st) == 0 && st.st_mtime > paste_time &&
+ (fp = fopen(paste_fname, "r"))) {
+ int i;
+ fgets(paste_path, PATHLEN, fp);
+ i = strlen(paste_path) - 1;
+ if(paste_path[i] == '\n')
+ paste_path[i] = 0;
+ fgets(paste_title, STRLEN, fp);
+ i = strlen(paste_title) - 1;
+ if(paste_title[i] == '\n')
+ paste_title[i] = 0;
+ fscanf(fp, "%d", &paste_level);
+ paste_time = st.st_mtime;
+ fclose(fp);
+ }
+}
+
+static char copyfile[PATHLEN];
+static char copytitle[TTLEN+1];
+static char copyowner[IDLEN + 2];
+
+void a_copyitem(char* fpath, char* title, char* owner, int mode) {
+ strcpy(copyfile, fpath);
+ strcpy(copytitle, title);
+ if(owner)
+ strcpy(copyowner, owner);
+ else
+ *copyowner = 0;
+ if(mode) {
+ outmsg("Àɮ׼аO§¹¦¨¡C[ª`·N] «þ¨©«á¤~¯à§R°£­ì¤å!");
+ igetch();
+ }
+}
+
+#define FHSZ sizeof(fileheader_t)
+
+static void a_loadname(menu_t *pm) {
+ char buf[PATHLEN];
+ int len;
+
+ setadir(buf, pm->path);
+ len = get_records(buf, pm->header, FHSZ, pm->page+1, p_lines);
+ if(len < p_lines)
+ bzero(&pm->header[len], FHSZ*(p_lines-len));
+}
+
+static void a_timestamp(char *buf, time_t *time) {
+ struct tm *pt = localtime(time);
+
+ sprintf(buf, "%02d/%02d/%02d", pt->tm_mon + 1, pt->tm_mday, (pt->tm_year + 1900) % 100);
+}
+
+static void a_showmenu(menu_t *pm) {
+ char *title, *editor;
+ int n;
+ fileheader_t *item;
+ char buf[PATHLEN];
+ time_t dtime;
+
+ showtitle("ºëµØ¤å³¹", pm->mtitle);
+ prints(" \033[1;36m½s¸¹ ¼Ð ÃD%56s\033[0m",
+ "½s ¿ï ¤é ´Á");
+
+ if(pm->num) {
+ setadir(buf, pm->path);
+ a_loadname(pm);
+ for(n = 0; n < p_lines && pm->page + n < pm->num; n++) {
+ item = &pm->header[n];
+ title = item->title;
+ editor = item->owner;
+ /* Ptt §â®É¶¡§ï¬°¨úÀɮ׮ɶ¡
+ dtime = atoi(&item->filename[2]);
+ */
+ sprintf(buf,"%s/%s",pm->path,item->filename);
+ dtime = dasht(buf);
+ a_timestamp(buf, &dtime);
+ prints("\n%6d%c %-47.46s%-13s[%s]", pm->page+n+1,
+ (item->filemode & FILE_BM) ?'X':
+ (item->filemode & FILE_HIDE) ?')':'.',
+ title, editor,
+ buf);
+ }
+ } else
+ outs("\n ¡mºëµØ°Ï¡n©|¦b§l¨ú¤Ñ¦a¶¡ªº¤é¤ëºëµØ¤¤... :)");
+
+ move(b_lines, 1);
+ outs(pm->level ?
+ "\033[34;46m ¡iªO ¥D¡j \033[31;47m (h)\033[30m»¡©ú "
+ "\033[31m(q/¡ö)\033[30mÂ÷¶} \033[31m(n)\033[30m·s¼W¤å³¹ "
+ "\033[31m(g)\033[30m·s¼W¥Ø¿ý \033[31m(e)\033[30m½s¿èÀÉ®× \033[m" :
+ "\033[34;46m ¡i¥\\¯àÁä¡j \033[31;47m (h)\033[30m»¡©ú "
+ "\033[31m(q/¡ö)\033[30mÂ÷¶} \033[31m(k¡ôj¡õ)\033[30m²¾°Ê´å¼Ð "
+ "\033[31m(enter/¡÷)\033[30mŪ¨ú¸ê®Æ \033[m");
+}
+
+static int a_searchtitle(menu_t *pm, int rev) {
+ static char search_str[40] = "";
+ int pos;
+
+ getdata(b_lines - 1, 1, "[·j´M]ÃöÁä¦r:", search_str, 40, DOECHO);
+
+ if(!*search_str)
+ return pm->now;
+
+ str_lower(search_str, search_str);
+
+ rev = rev ? -1 : 1;
+ pos = pm->now;
+ do {
+ pos += rev;
+ if(pos == pm->num)
+ pos = 0;
+ else if(pos < 0)
+ pos = pm->num - 1;
+ if(pos < pm->page || pos >= pm->page + p_lines) {
+ pm->page = pos - pos % p_lines;
+ a_loadname(pm);
+ }
+ if(strstr_lower(pm->header[pos - pm->page].title, search_str))
+ return pos;
+ } while(pos != pm->now);
+ return pm->now;
+}
+
+enum {NOBODY, MANAGER, SYSOP};
+
+static void a_showhelp(int level) {
+ clear();
+ outs("\033[36m¡i " BBSNAME "¤½§GÄæ¨Ï¥Î»¡©ú ¡j\033[m\n\n"
+ "[¡ö][q] Â÷¶}¨ì¤W¤@¼h¥Ø¿ý\n"
+ "[¡ô][k] ¤W¤@­Ó¿ï¶µ\n"
+ "[¡õ][j] ¤U¤@­Ó¿ï¶µ\n"
+ "[¡÷][r][enter] ¶i¤J¥Ø¿ý¡þŪ¨ú¤å³¹\n"
+ "[^B][PgUp] ¤W­¶¿ï³æ\n"
+ "[^F][PgDn][Spc] ¤U­¶¿ï³æ\n"
+ "[##] ²¾¨ì¸Ó¿ï¶µ\n"
+ "[F][U] ±N¤å³¹±H¦^ Internet ¶l½c/"
+ "±N¤å³¹ uuencode «á±H¦^¶l½c\n");
+ if(level >= MANAGER) {
+ outs("\n\033[36m¡i ªO¥D±M¥ÎÁä ¡j\033[m\n"
+ "[H] ¤Á´«¬° ¤½¶}/·|­û/ª©¥D ¤~¯à¾\\Ū\n"
+ "[n/g/G] ¦¬¿ýºëµØ¤å³¹/¶}ÅP¥Ø¿ý/«Ø¥ß³s½u\n"
+ "[m/d/D] ²¾°Ê/§R°£¤å³¹/§R°£¤@­Ó½d³òªº¤å³¹\n"
+ "[f/T/e] ½s¿è¼ÐÃD²Å¸¹/­×§ï¤å³¹¼ÐÃD/¤º®e\n"
+ "[c/p/a] «þ¨©/Ö߶K/ªþ¥[¤å³¹\n"
+ "[^P/^A] Ö߶K/ªþ¥[¤w¥Î't'¼Ð°O¤å³¹\n");
+ }
+
+ if(level >= SYSOP) {
+ outs("\n\033[36m¡i ¯¸ªø±M¥ÎÁä ¡j\033[m\n"
+ "[l] «Ø symbolic link\n"
+ "[N] ¬d¸ßÀɦW\n");
+ }
+ pressanykey();
+}
+
+static int AnnounceSelect() {
+ static char xboard[20];
+ char buf[20];
+ char fpath[256];
+ boardheader_t *bp;
+
+ move(2, 0);
+ clrtoeol();
+ move(3, 0);
+ clrtoeol();
+ move(1, 0);
+ make_blist();
+ namecomplete("¿ï¾ÜºëµØ°Ï¬ÝªO¡G", buf);
+ if(*buf)
+ strcpy(xboard, buf);
+ if(*xboard && (bp = getbcache(getbnum(xboard)))) {
+ setapath(fpath, xboard);
+ setutmpmode(ANNOUNCE);
+ a_menu(xboard, fpath,
+ (HAS_PERM(PERM_ALLBOARD) ||
+ (HAS_PERM(PERM_BM) && is_BM(bp->BM))) ? 1 : 0);
+ }
+ return FULLUPDATE;
+}
+
+extern char vetitle[];
+
+void gem(char* maintitle, item_t* path, int update) {
+ gmenu_t me;
+ int ch;
+ char fname[PATHLEN];
+
+ strncpy(me.mtitle, maintitle, 40);
+ me.mtitle[40] = 0;
+ go_menu(&me, path, update);
+
+ /* ºëµØ°Ï-tree ¤¤³¡¥÷µ²ºcÄÝ©ó cuser ==> BM */
+
+ me.level = 0;
+ me.page = 9999;
+ me.now = 0;
+ for(;;) {
+ if(me.now >= me.num && me.num > 0)
+ me.now = me.num - 1;
+ else if(me.now < 0)
+ me.now = 0;
+
+ if(me.now < me.page || me.now >= me.page + p_lines) {
+ me.page = me.now - (me.now % p_lines);
+ g_showmenu(&me);
+ }
+ ch = cursor_key(2 + me.now - me.page, 0);
+ if(ch == 'q' || ch == 'Q' || ch == KEY_LEFT)
+ break;
+
+ if(ch >= '0' && ch <= '9') {
+ if((ch = search_num(ch, me.num)) != -1)
+ me.now = ch;
+ me.page = 9999;
+ continue;
+ }
+
+ switch(ch) {
+ case KEY_UP:
+ case 'k':
+ if(--me.now < 0)
+ me.now = me.num - 1;
+ break;
+ case KEY_DOWN:
+ case 'j':
+ if(++me.now >= me.num)
+ me.now = 0;
+ break;
+ case KEY_PGUP:
+ case 'b':
+ if(me.now >= p_lines)
+ me.now -= p_lines;
+ else if(me.now > 0)
+ me.now = 0;
+ else
+ me.now = me.num - 1;
+ break;
+ case ' ':
+ case KEY_PGDN:
+ case Ctrl('F'):
+ if(me.now < me.num - p_lines)
+ me.now += p_lines;
+ else if(me.now < me.num - 1)
+ me.now = me.num - 1;
+ else
+ me.now = 0;
+ break;
+ case 'h':
+ g_showhelp();
+ me.page = 9999;
+ break;
+ case '?':
+ case '/':
+ me.now = g_searchtitle(&me, ch == '?');
+ me.page = 9999;
+ break;
+ case 'N':
+ if(HAS_PERM(PERM_SYSOP)) {
+ go_proxy(fname, me.item[me.now], 0);
+ move(b_lines - 1, 0);
+ outs(fname);
+ pressanykey();
+ me.page = 9999;
+ }
+ break;
+ case 'c':
+ case 'C':
+ case Ctrl('C'):
+ if(me.now < me.num) {
+ item_t *node = me.item[me.now];
+ char *title = node->title;
+ int mode = title[1];
+
+ load_paste();
+ if(mode == (char) 0xbc || ch == Ctrl('C')) {
+ if(mode == (char) 0xbc)
+ go_proxy(fname, node, 0);
+ if(ch == Ctrl('C') && *paste_path && paste_level) {
+ char newpath[PATHLEN];
+ fileheader_t item;
+
+ strcpy(newpath, paste_path);
+ if(mode == (char) 0xbc) {
+ stampfile(newpath, &item);
+ unlink(newpath);
+ Link(fname, newpath);
+ } else
+ stampdir(newpath, &item);
+ strcpy(item.owner, cuser.userid);
+ sprintf(item.title, "%s%.72s",
+ (currutmp->pager > 1) ? "" :
+ (mode == (char) 0xbc) ? "¡º " : "¡» ",
+ title + 3);
+ strcpy(strrchr(newpath, '/') + 1, ".DIR");
+ append_record(newpath, &item, FHSZ);
+ if(++me.now >= me.num)
+ me.now = 0;
+ break;
+ }
+ if(mode == (char) 0xbc) {
+ a_copyitem(fname,
+ title + ((currutmp->pager > 1) ? 3 : 0),
+ 0, 1);
+ if(ch == 'C' && *paste_path) {
+ setutmpmode(ANNOUNCE);
+ a_menu(paste_title, paste_path, paste_level);
+ }
+ me.page = 9999;
+ } else
+ bell();
+ }
+ }
+ break;
+ case Ctrl('B'):
+ m_read();
+ me.page = 9999;
+ break;
+ case Ctrl('I'):
+ t_idle();
+ me.page = 9999;
+ break;
+ case 's':
+ AnnounceSelect();
+ me.page = 9999;
+ break;
+ case '\n':
+ case '\r':
+ case KEY_RIGHT:
+ case 'r':
+ case 'R':
+ if(me.now < me.num) {
+ item_t *node = me.item[me.now];
+ char *title = node->title;
+ int mode = title[1];
+ int update = (ch == 'R') ? 1 : 0;
+
+ title += 3;
+
+ if(mode == (char) 0xbc) {
+ int more_result;
+
+ go_proxy(fname, node, update);
+ strcpy(vetitle, title);
+ while((more_result = more(fname, YEA))) {
+ if(more_result == 1) {
+ if(--me.now < 0) {
+ me.now = 0;
+ break;
+ }
+ } else if(more_result == 3) {
+ if(++me.now >= me.num) {
+ me.now = me.num - 1;
+ break;
+ }
+ } else
+ break;
+ node = me.item[me.now];
+ if(node->title[1] != (char) 0xbc)
+ break;
+ go_proxy(fname, node, update);
+ strcpy(vetitle, title);
+ }
+ } else if(mode == (char) 0xbd) {
+ gem(title, node, update);
+ }
+ me.page = 9999;
+ }
+ break;
+ }
+ }
+ for(ch = 0; ch < me.num; ch++)
+ free(me.item[ch]);
+}
+
+extern char *msg_fwd_ok;
+extern char *msg_fwd_err1;
+extern char *msg_fwd_err2;
+
+static void a_forward(char *path, fileheader_t *pitem, int mode) {
+ fileheader_t fhdr;
+
+ strcpy(fhdr.filename, pitem->filename);
+ strcpy(fhdr.title, pitem->title);
+ switch(doforward(path, &fhdr, mode)) {
+ case 0:
+ outmsg(msg_fwd_ok);
+ break;
+ case -1:
+ outmsg(msg_fwd_err1);
+ break;
+ case -2:
+ outmsg(msg_fwd_err2);
+ break;
+ }
+}
+
+static void a_additem(menu_t *pm, fileheader_t *myheader) {
+ char buf[PATHLEN];
+
+ setadir(buf, pm->path);
+ if(append_record(buf, myheader, FHSZ) == -1)
+ return;
+ pm->now = pm->num++;
+
+ if(pm->now >= pm->page + p_lines) {
+ pm->page = pm->now - ((pm->page == 10000 && pm->now > p_lines / 2) ?
+ (p_lines / 2) : (pm->now % p_lines));
+ }
+
+ /*Ptt*/
+ strcpy(pm->header[pm->now - pm->page].filename, myheader->filename);
+}
+
+#define ADDITEM 0
+#define ADDGROUP 1
+#define ADDGOPHER 2
+#define ADDLINK 3
+extern char currboard[];
+
+static void a_newitem(menu_t *pm, int mode) {
+ static char *mesg[4] = {
+ "[·s¼W¤å³¹] ½Ð¿é¤J¼ÐÃD¡G", /* ADDITEM */
+ "[·s¼W¥Ø¿ý] ½Ð¿é¤J¼ÐÃD¡G", /* ADDGROUP */
+ "[·s¼W³s½u] ½Ð¿é¤J¼ÐÃD¡G", /* ADDGOPHER */
+ "½Ð¿é¤J¼ÐÃD¡G" /* ADDLINK */
+ };
+
+ char fpath[PATHLEN], buf[PATHLEN], lpath[PATHLEN];
+ fileheader_t item;
+ int d;
+
+ strcpy(fpath, pm->path);
+
+ switch(mode) {
+ case ADDITEM:
+ stampfile(fpath, &item);
+ strcpy(item.title, "¡º "); /* A1BA */
+ break;
+
+ case ADDGROUP:
+ stampdir(fpath, &item);
+ strcpy(item.title, "¡» "); /* A1BB */
+ break;
+ case ADDGOPHER:
+ bzero(&item, sizeof(item));
+ strcpy(item.title, "¡ó "); /* A1BB */
+ if(!getdata(b_lines - 2, 1, "¿é¤JURL¦ì§}¡G",
+ item.filename+2,61, DOECHO))
+ return;
+ break;
+ case ADDLINK:
+ stamplink(fpath, &item);
+ if (!getdata(b_lines - 2, 1, "·s¼W³s½u¡G", buf, 61, DOECHO))
+ return;
+ if(invalid_pname(buf)) {
+ unlink(fpath);
+ outs("¥Øªº¦a¸ô®|¤£¦Xªk¡I");
+ igetch();
+ return;
+ }
+
+ item.title[0] = 0;
+ for(d = 0; d <= 3; d++) {
+ switch(d) {
+ case 0:
+ sprintf(lpath, "%s%s%s/%s",
+ BBSHOME, "/man/boards/",currboard , buf);
+ break;
+ case 1:
+ sprintf(lpath, "%s%s%s",
+ BBSHOME, "/man/boards/" , buf);
+ break;
+ case 2:
+ sprintf(lpath, "%s%s%s",
+ BBSHOME, "/" , buf);
+ break;
+ case 3:
+ sprintf(lpath, "%s%s%s",
+ BBSHOME, "/etc/" , buf);
+ break;
+ }
+ if(dashf(lpath)) {
+ strcpy(item.title, "¡¸ "); /* A1B3 */
+ break;
+ } else if (dashd(lpath)) {
+ strcpy(item.title, "¡¹ "); /* A1B4 */
+ break;
+ }
+ if(!HAS_PERM(PERM_BBSADM) && d==1)
+ break;
+ }
+
+ if(!item.title[0]) {
+ unlink(fpath);
+ outs("¥Øªº¦a¸ô®|¤£¦Xªk¡I");
+ igetch();
+ return;
+ }
+ }
+
+ if(!getdata(b_lines - 1, 1, mesg[mode], &item.title[3], 55, DOECHO)) {
+ if(mode == ADDGROUP)
+ rmdir(fpath);
+ else if(mode != ADDGOPHER)
+ unlink(fpath);
+ return;
+ }
+
+ switch(mode) {
+ case ADDITEM:
+ if(vedit(fpath, 0, NULL) == -1) {
+ unlink(fpath);
+ pressanykey();
+ return;
+ }
+ break;
+ case ADDLINK:
+ unlink(fpath);
+ if(symlink(lpath, fpath) == -1) {
+ outs("µLªk«Ø¥ß symbolic link");
+ igetch();
+ return;
+ }
+ break;
+ case ADDGOPHER:
+ strcpy(item.date, "70");
+ strncpy(item.filename, "H.",2);
+ break;
+ }
+
+ strcpy(item.owner, cuser.userid);
+ a_additem(pm, &item);
+}
+
+static void a_pasteitem(menu_t *pm, int mode) {
+ char newpath[PATHLEN];
+ char buf[PATHLEN];
+ char ans[2];
+ int i;
+ fileheader_t item;
+
+ move(b_lines - 1, 1);
+ if(copyfile[0]) {
+ if(dashd(copyfile)) {
+ for(i = 0; copyfile[i] && copyfile[i] == pm->path[i]; i++);
+ if(!copyfile[i]) {
+ outs("±N¥Ø¿ý«þ¶i¦Û¤vªº¤l¥Ø¿ý¤¤¡A·|³y¦¨µL½a°j°é¡I");
+ igetch();
+ return;
+ }
+ }
+ if(mode) {
+ sprintf(buf, "½T©w­n«þ¨©[%s]¶Ü(Y/N)¡H[N] ", copytitle);
+ getdata(b_lines - 1, 1, buf, ans, 3, LCECHO);
+ } else
+ ans[0]='y';
+ if(ans[0] == 'y') {
+ strcpy(newpath, pm->path);
+
+ if(*copyowner) {
+ char* fname = strrchr(copyfile, '/');
+
+ if(fname)
+ strcat(newpath, fname);
+ else
+ return;
+ if(access(pm->path, X_OK | R_OK | W_OK))
+ mkdir(pm->path, 0755);
+ memset(&item, 0, sizeof(fileheader_t));
+ strcpy(item.filename, fname + 1);
+ memcpy(copytitle, "¡·", 2);
+ if(HAS_PERM(PERM_BBSADM))
+ Link(copyfile, newpath);
+ else {
+ sprintf(buf, "/bin/cp %s %s", copyfile, newpath);
+ system(buf);
+ }
+ } else if(dashf(copyfile)) {
+ stampfile(newpath, &item);
+ memcpy(copytitle, "¡º", 2);
+ sprintf(buf, "/bin/cp %s %s", copyfile, newpath);
+ } else if(dashd(copyfile)) {
+ stampdir(newpath, &item);
+ memcpy(copytitle, "¡»", 2);
+ sprintf(buf, "/bin/cp -r %s/* %s/.D* %s", copyfile, copyfile,
+ newpath);
+ } else {
+ outs("µLªk«þ¨©¡I");
+ igetch();
+ return;
+ }
+ strcpy(item.owner, *copyowner ? copyowner : cuser.userid);
+ strcpy(item.title, copytitle);
+ if(!*copyowner)
+ system(buf);
+ a_additem(pm, &item);
+ copyfile[0] = '\0';
+ }
+ } else {
+ outs("½Ð¥ý°õ¦æ copy ©R¥O«á¦A paste");
+ igetch();
+ }
+}
+
+static void a_appenditem(menu_t *pm, int isask) {
+ char fname[PATHLEN];
+ char buf[ANSILINELEN];
+ char ans[2] = "y";
+ FILE *fp, *fin;
+
+ move(b_lines - 1, 1);
+ if(copyfile[0]) {
+ if(dashf(copyfile)) {
+ sprintf(fname, "%s/%s", pm->path,
+ pm->header[pm->now-pm->page].filename);
+ if(dashf(fname)) {
+ if(isask) {
+ sprintf(buf, "½T©w­n±N[%s]ªþ¥[©ó¦¹¶Ü(Y/N)¡H[N] ",
+ copytitle);
+ getdata(b_lines - 2, 1, buf, ans, 3, LCECHO);
+ }
+ if(ans[0] == 'y') {
+ if((fp = fopen(fname, "a+"))) {
+ if((fin = fopen(copyfile, "r"))) {
+ memset(buf, '-', 74);
+ buf[74] = '\0';
+ fprintf(fp, "\n> %s <\n\n", buf);
+ if(isask)
+ getdata(b_lines - 1, 1,
+ "¬O§_¦¬¿ýñ¦WÀɳ¡¥÷(Y/N)¡H[Y] ",
+ ans, 3, LCECHO);
+ while(fgets(buf, sizeof(buf), fin)) {
+ if((ans[0] == 'n' ) &&
+ !strcmp(buf, "--\n"))
+ break;
+ fputs(buf, fp);
+ }
+ fclose(fin);
+ copyfile[0] = '\0';
+ }
+ fclose(fp);
+ }
+ }
+ } else {
+ outs("Àɮפ£±oªþ¥[©ó¦¹¡I");
+ igetch();
+ }
+ } else {
+ outs("¤£±oªþ¥[¾ã­Ó¥Ø¿ý©óÀɮ׫á¡I");
+ igetch();
+ }
+ } else {
+ outs("½Ð¥ý°õ¦æ copy ©R¥O«á¦A append");
+ igetch();
+ }
+}
+
+static int a_pastetagpost(menu_t *pm, int mode) {
+ extern int TagNum;
+ extern void EnumTagFhdr();
+ extern void UnTagger(int locus);
+ fileheader_t fhdr;
+ int ans = 0, ent=0, tagnum;
+ char title[TTLEN + 1]= "¡º ";
+ char dirname[200],buf[200];
+
+ setbdir(dirname, currboard);
+ tagnum = TagNum;
+
+ if (!tagnum) return ans;
+
+ while (tagnum--)
+ {
+ EnumTagFhdr (&fhdr, dirname, ent++);
+ setbfile (buf, currboard, fhdr.filename);
+
+ if (dashf (buf))
+ {
+ strncpy(title+3, fhdr.title, TTLEN-3);
+ title[TTLEN] = '\0';
+ a_copyitem(buf, title, 0, 0);
+ if(mode)
+ {
+ mode--;
+ a_pasteitem(pm,0);
+ }
+ else a_appenditem(pm, 0);
+ ++ans;
+ UnTagger (tagnum);
+ }
+
+ };
+
+ return ans;
+}
+
+static void a_moveitem(menu_t *pm) {
+ fileheader_t *tmp;
+ char newnum[4];
+ int num, max, min;
+ char buf[PATHLEN];
+ int fail;
+
+ sprintf(buf, "½Ð¿é¤J²Ä %d ¿ï¶µªº·s¦¸§Ç¡G", pm->now + 1);
+ if(!getdata(b_lines - 1, 1, buf, newnum, 6, DOECHO))
+ return;
+ num = (newnum[0] == '$') ? 9999 : atoi(newnum) - 1;
+ if(num >= pm->num)
+ num = pm->num - 1;
+ else if(num < 0)
+ num = 0;
+ setadir(buf, pm->path);
+ min = num < pm->now ? num : pm->now;
+ max = num > pm->now ? num : pm->now;
+ tmp = (fileheader_t *) calloc(max + 1, FHSZ);
+
+ fail = 0;
+ if(get_records(buf, tmp, FHSZ, 1, min) != min)
+ fail = 1;
+ if(num > pm->now) {
+ if(get_records(buf, &tmp[min], FHSZ, pm->now+2, max-min) != max-min)
+ fail = 1;
+ if(get_records(buf, &tmp[max], FHSZ, pm->now+1, 1) != 1)
+ fail = 1;
+ } else {
+ if(get_records(buf, &tmp[min], FHSZ, pm->now+1, 1) != 1)
+ fail = 1;
+ if(get_records(buf, &tmp[min+1], FHSZ, num+1, max-min) != max-min)
+ fail = 1;
+ }
+ if(!fail)
+ substitute_record(buf, tmp, FHSZ * (max + 1), 1);
+ pm->now = num;
+ free(tmp);
+}
+
+static void a_delrange(menu_t *pm) {
+ char fname[256];
+
+ sprintf(fname,"%s/.DIR",pm->path);
+ del_range(0, NULL, fname);
+ pm->num = get_num_records(fname, FHSZ);
+}
+
+static void a_delete(menu_t *pm) {
+ char fpath[PATHLEN], buf[PATHLEN], cmd[PATHLEN];
+ char ans[4];
+ fileheader_t backup;
+
+ sprintf(fpath, "%s/%s", pm->path, pm->header[pm->now - pm->page].filename);
+ setadir(buf, pm->path);
+
+ if(pm->header[pm->now - pm->page].filename[0] == 'H' &&
+ pm->header[pm->now - pm->page].filename[1] == '.') {
+ getdata(b_lines - 1, 1, "±z½T©w­n§R°£¦¹ºëµØ°Ï³s½u¶Ü(Y/N)¡H[N] ",
+ ans, 3, LCECHO);
+ if(ans[0] != 'y')
+ return;
+ if(delete_record(buf, FHSZ, pm->now + 1) == -1)
+ return;
+ } else if (dashl(fpath)) {
+ getdata(b_lines - 1, 1, "±z½T©w­n§R°£¦¹ symbolic link ¶Ü(Y/N)¡H[N] ",
+ ans, 3, LCECHO);
+ if(ans[0] != 'y')
+ return;
+ if(delete_record(buf, FHSZ, pm->now + 1) == -1)
+ return;
+ unlink(fpath);
+ } else if(dashf(fpath)) {
+ getdata(b_lines - 1, 1, "±z½T©w­n§R°£¦¹Àɮ׶Ü(Y/N)¡H[N] ", ans, 3,
+ LCECHO);
+ if(ans[0] != 'y')
+ return;
+ if(delete_record(buf, FHSZ, pm->now + 1) == -1)
+ return;
+
+ setbpath(buf, "deleted");
+ stampfile(buf, &backup);
+ strcpy(backup.owner, cuser.userid);
+ strcpy(backup.title,pm->header[pm->now - pm->page].title + 2);
+ backup.savemode = 'D';
+
+ sprintf(cmd, "mv -f %s %s", fpath,buf);
+ system(cmd);
+ setbdir(buf, "deleted");
+ append_record(buf, &backup, sizeof(backup));
+ } else if (dashd(fpath)) {
+ getdata(b_lines - 1, 1, "±z½T©w­n§R°£¾ã­Ó¥Ø¿ý¶Ü(Y/N)¡H[N] ", ans, 3,
+ LCECHO);
+ if(ans[0] != 'y')
+ return;
+ if(delete_record(buf, FHSZ, pm->now + 1) == -1)
+ return;
+
+ setapath(buf, "deleted");
+ stampdir(buf, &backup);
+
+ sprintf(cmd, "rm -rf %s;/bin/mv -f %s %s",buf,fpath,buf);
+ system(cmd);
+
+ strcpy(backup.owner, cuser.userid);
+ strcpy(backup.title,pm->header[pm->now - pm->page].title +2);
+ setapath(buf, "deleted");
+ setadir(buf,buf);
+ append_record(buf, &backup, sizeof(backup));
+ } else { /* Ptt ·l·´ªº¶µ¥Ø */
+ getdata(b_lines - 1, 1, "±z½T©w­n§R°£¦¹·l·´ªº¶µ¥Ø¶Ü(Y/N)¡H[N] ",
+ ans, 3, LCECHO);
+ if(ans[0] != 'y')
+ return;
+ if(delete_record(buf, FHSZ, pm->now + 1) == -1)
+ return;
+ }
+ pm->num--;
+}
+
+static void a_newtitle(menu_t *pm) {
+ char buf[PATHLEN];
+ fileheader_t item;
+
+ memcpy(&item, &pm->header[pm->now - pm->page], FHSZ);
+ strcpy(buf,item.title + 3);
+ if(getdata_buf(b_lines - 1, 1, "·s¼ÐÃD¡G", buf, 60, DOECHO)) {
+ strcpy(item.title + 3, buf);
+ setadir(buf, pm->path);
+ substitute_record(buf, &item, FHSZ, pm->now + 1);
+ }
+}
+static void a_hideitem(menu_t *pm) {
+ fileheader_t *item=&pm->header[pm->now - pm->page];
+ char buf[PATHLEN];
+ if(item->filemode&FILE_BM)
+ {
+ item->filemode &= ~FILE_BM;
+ item->filemode &= ~FILE_HIDE;
+ }
+ else if(item->filemode&FILE_HIDE)
+ item->filemode |= FILE_BM;
+ else item->filemode |= FILE_HIDE;
+ setadir(buf, pm->path);
+ substitute_record(buf, item, FHSZ, pm->now + 1);
+}
+static void a_editsign(menu_t *pm) {
+ char buf[PATHLEN];
+ fileheader_t item;
+
+ memcpy(&item, &pm->header[pm->now - pm->page], FHSZ);
+ sprintf(buf, "%c%c", item.title[0], item.title[1]);
+ if(getdata_buf(b_lines - 1, 1, "²Å¸¹", buf, 5, DOECHO)) {
+ item.title[0] = buf[0] ? buf[0] : ' ';
+ item.title[1] = buf[1] ? buf[1] : ' ';
+ item.title[2] = buf[2] ? buf[2] : ' ';
+ setadir(buf, pm->path);
+ substitute_record(buf, &item, FHSZ, pm->now + 1);
+ }
+}
+
+static void a_showname(menu_t *pm) {
+ char buf[PATHLEN];
+ int len;
+ int i;
+ int sym;
+
+ move(b_lines - 1, 1);
+ sprintf(buf, "%s/%s", pm->path, pm->header[pm->now - pm->page].filename);
+ if(dashl(buf)) {
+ prints("¦¹ symbolic link ¦WºÙ¬° %s\n",
+ pm->header[pm->now - pm->page].filename);
+ if((len = readlink(buf, buf, PATHLEN-1)) >= 0) {
+ buf[len] = '\0';
+ for(i = 0; BBSHOME[i] && buf[i] == BBSHOME[i]; i++);
+ if(!BBSHOME[i] && buf[i] == '/') {
+ if(HAS_PERM(PERM_BBSADM))
+ sym = 1;
+ else {
+ sym = 0;
+ for(i++; BBSHOME "/man"[i] && buf[i] == BBSHOME "/man"[i];
+ i++);
+ if(!BBSHOME "/man"[i] && buf[i] == '/')
+ sym = 1;
+ }
+ if(sym) {
+ pressanykey();
+ move(b_lines - 1, 1);
+ prints("¦¹ symbolic link «ü¦V %s\n", &buf[i+1]);
+ }
+ }
+ }
+ } else if(dashf(buf))
+ prints("¦¹¤å³¹¦WºÙ¬° %s", pm->header[pm->now - pm->page].filename);
+ else if(dashd(buf))
+ prints("¦¹¥Ø¿ý¦WºÙ¬° %s", pm->header[pm->now - pm->page].filename);
+ else
+ outs("¦¹¶µ¥Ø¤w·l·´, «Øij±N¨ä§R°£¡I");
+ pressanykey();
+}
+
+static char *a_title;
+
+static void atitle() {
+ showtitle("ºëµØ¤å³¹", a_title);
+ outs("[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]µoªí¤å³¹ [b]³Æ§Ñ¿ý [d]§R°£ [q]ºëµØ°Ï "
+ "[TAB]¤åºK [h]elp\n\033[7m ½s¸¹ ¤é ´Á §@ ªÌ "
+ "¤å ³¹ ¼Ð ÃD\033[m");
+}
+
+extern char currtitle[];
+
+char trans_buffer[256];
+extern char quote_file[];
+extern unsigned int currstat;
+
+static int isvisible_man(menu_t *me)
+{
+ fileheader_t *fhdr = &me->header[me->now-me->page];
+ if( me->level<MANAGER && ((fhdr->filemode & FILE_BM) ||
+ ((fhdr->filemode & FILE_HIDE) &&
+ hbflcheck(currbid, currutmp->uid))))
+ return 0;
+ return 1;
+}
+int a_menu(char *maintitle, char *path, int lastlevel) {
+ static char Fexit;
+ menu_t me;
+ char fname[PATHLEN];
+ int ch, returnvalue = FULLUPDATE;
+
+ trans_buffer[0] = 0;
+
+ Fexit = 0;
+ me.header = (fileheader_t *)calloc(p_lines, FHSZ);
+ me.path = path;
+ strcpy(me.mtitle, maintitle);
+ setadir(fname, me.path);
+ me.num = get_num_records(fname, FHSZ);
+
+ /* ºëµØ°Ï-tree ¤¤³¡¥÷µ²ºcÄÝ©ó cuser ==> BM */
+
+ if(!(me.level = lastlevel)) {
+ char *ptr;
+
+ if((ptr = strrchr(me.mtitle, '[')))
+ me.level = is_BM(ptr + 1);
+ }
+
+ me.page = 9999;
+ me.now = 0;
+ for(;;) {
+ if(me.now >= me.num)
+ me.now = me.num - 1;
+ if(me.now < 0)
+ me.now = 0;
+
+ if(me.now < me.page || me.now >= me.page + p_lines) {
+ me.page = me.now - ((me.page == 10000 && me.now > p_lines / 2) ?
+ (p_lines / 2) : (me.now % p_lines));
+ a_showmenu(&me);
+ }
+
+ ch = cursor_key(2 + me.now - me.page, 0);
+
+ if(ch == 'q' || ch == 'Q' || ch == KEY_LEFT)
+ break;
+
+ if(ch >= '1' && ch <= '9') {
+ if((ch = search_num(ch, me.num)) != -1)
+ me.now = ch;
+ me.page = 10000;
+ continue;
+ }
+
+ switch(ch) {
+ case KEY_UP:
+ case 'k':
+ if(--me.now < 0)
+ me.now = me.num - 1;
+ break;
+
+ case KEY_DOWN:
+ case 'j':
+ if(++me.now >= me.num)
+ me.now = 0;
+ break;
+
+ case KEY_PGUP:
+ case Ctrl('B'):
+ if(me.now >= p_lines)
+ me.now -= p_lines;
+ else if (me.now > 0)
+ me.now = 0;
+ else
+ me.now = me.num - 1;
+ break;
+
+ case ' ':
+ case KEY_PGDN:
+ case Ctrl('F'):
+ if(me.now < me.num - p_lines)
+ me.now += p_lines;
+ else if(me.now < me.num - 1)
+ me.now = me.num - 1;
+ else
+ me.now = 0;
+ break;
+
+ case '0':
+ me.now = 0;
+ break;
+ case '?':
+ case '/':
+ me.now = a_searchtitle(&me, ch == '?');
+ me.page = 9999;
+ break;
+ case '$':
+ me.now = me.num -1;
+ break;
+ case 'h':
+ a_showhelp(me.level);
+ me.page = 9999;
+ break;
+ case Ctrl('C'):
+ cal();
+ me.page = 9999;
+ break;
+
+ case Ctrl('I'):
+ t_idle();
+ me.page = 9999;
+ break;
+
+ case 's':
+ AnnounceSelect();
+ me.page = 9999;
+ break;
+
+ case 'e':
+ case 'E':
+ sprintf(fname, "%s/%s", path, me.header[me.now-me.page].filename);
+ if(dashf(fname) && me.level >= MANAGER) {
+ *quote_file = 0;
+ if(vedit(fname, NA, NULL) != -1) {
+ char fpath[200];
+ fileheader_t fhdr;
+
+ strcpy(fpath, path);
+ stampfile(fpath, &fhdr);
+ unlink(fpath);
+ Rename(fname, fpath);
+ strcpy(me.header[me.now-me.page].filename, fhdr.filename);
+ strcpy(me.header[me.now-me.page].owner, cuser.userid);
+ setadir(fpath, path);
+ substitute_record(fpath, me.header+me.now-me.page,
+ sizeof(fhdr), me.now + 1);
+ }
+ me.page = 9999;
+ }
+ break;
+
+ case 'c':
+ if(me.now < me.num) {
+ if(!isvisible_man(&me)) break;
+ sprintf(fname, "%s/%s", path,
+ me.header[me.now-me.page].filename);
+ a_copyitem(fname, me.header[me.now-me.page].title, 0, 1);
+ me.page = 9999;
+ break;
+ }
+
+ case '\n':
+ case '\r':
+ case KEY_RIGHT:
+ case 'r':
+ if(me.now < me.num) {
+ fileheader_t *fhdr = &me.header[me.now-me.page];
+ if(!isvisible_man(&me)) break;
+ sprintf(fname, "%s/%s", path, fhdr->filename);
+ if(*fhdr->filename == 'H' && fhdr->filename[1] == '.') {
+ item_t item;
+ strcpy(item.X.G.server, fhdr->filename + 2);
+ strcpy(item.X.G.path, "1/");
+ item.X.G.port = 70;
+ gem(fhdr->title, &item, (ch == 'R') ? 1 : 0);
+ } else if (dashf(fname)) {
+ int more_result;
+
+ while((more_result = more(fname, YEA))) {
+ /* Ptt ½d¥»ºëÆF plugin */
+ if(currstat == EDITEXP || currstat == OSONG) {
+ char ans[4];
+
+ move(22, 0);
+ clrtoeol();
+ getdata(22, 1,
+ currstat == EDITEXP ?
+ "­n§â½d¨Ò Plugin ¨ì¤å³¹¶Ü?[y/N]":
+ "½T©w­nÂI³o­ººq¶Ü?[y/N]",
+ ans, 3, LCECHO);
+ if(ans[0]=='y') {
+ strcpy(trans_buffer,fname);
+ Fexit = 1;
+ free(me.header);
+ if(currstat == OSONG){
+ log_file(FN_USSONG,fhdr->title);
+ }
+ return FULLUPDATE;
+ }
+ }
+ if(more_result == 1) {
+ if(--me.now < 0) {
+ me.now = 0;
+ break;
+ }
+ } else if(more_result == 3) {
+ if(++me.now >= me.num) {
+ me.now = me.num - 1;
+ break;
+ }
+ } else
+ break;
+ if(!isvisible_man(&me)) break;
+ sprintf(fname, "%s/%s", path,
+ me.header[me.now-me.page].filename);
+ if(!dashf(fname))
+ break;
+ }
+ } else if(dashd(fname)) {
+ a_menu(me.header[me.now-me.page].title, fname, me.level);
+ /* Ptt ±j¤O¸õ¥Xrecursive */
+ if(Fexit) {
+ free(me.header);
+ return FULLUPDATE;
+ }
+ }
+ me.page = 9999;
+ }
+ break;
+
+ case 'F':
+ case 'U':
+ sprintf(fname, "%s/%s", path, me.header[me.now-me.page].filename);
+ if(me.now < me.num && HAS_PERM(PERM_BASIC) && dashf(fname)) {
+ a_forward(path, &me.header[me.now-me.page], ch /*== 'U'*/);
+ /*By CharlieL*/
+ } else
+ outmsg("µLªkÂà±H¦¹¶µ¥Ø");
+
+ me.page = 9999;
+ refresh();
+ sleep(1);
+ break;
+ }
+
+ if(me.level >= MANAGER) {
+ int page0 = me.page;
+
+ switch(ch) {
+ case 'n':
+ a_newitem(&me, ADDITEM);
+ me.page = 9999;
+ break;
+ case 'g':
+ a_newitem(&me, ADDGROUP);
+ me.page = 9999;
+ break;
+ case 'G':
+ a_newitem(&me, ADDGOPHER);
+ me.page = 9999;
+ break;
+ case 'p':
+ a_pasteitem(&me,1);
+ me.page = 9999;
+ break;
+ case 'f':
+ a_editsign(&me);
+ me.page = 9999;
+ break;
+ case Ctrl('P'):
+ a_pastetagpost(&me, -1);
+ returnvalue = DIRCHANGED;
+ me.page = 9999;
+ break;
+ case Ctrl('A'):
+ a_pastetagpost(&me, 1);
+ returnvalue = DIRCHANGED;
+ me.page = 9999;
+ break;
+ case 'a':
+ a_appenditem(&me, 1);
+ me.page = 9999;
+ break;
+ default:
+ me.page = page0;
+ break;
+ }
+
+ if(me.num)
+ switch(ch) {
+ case 'm':
+ a_moveitem(&me);
+ me.page = 9999;
+ break;
+
+ case 'D':
+ /* Ptt me.page = -1;*/
+ a_delrange(&me);
+ me.page = 9999;
+ break;
+ case 'd':
+ a_delete(&me);
+ me.page = 9999;
+ break;
+ case 'H':
+ a_hideitem(&me);
+ me.page = 9999;
+ break;
+ case 'T':
+ a_newtitle(&me);
+ me.page = 9999;
+ break;
+ }
+ }
+
+ if(me.level == SYSOP) {
+ switch(ch) {
+ case 'l':
+ a_newitem(&me, ADDLINK);
+ me.page = 9999;
+ break;
+ case 'N':
+ a_showname(&me);
+ me.page = 9999;
+ break;
+ }
+ }
+ }
+ free(me.header);
+ return returnvalue;
+}
+
+static char *mytitle = BBSNAME "§G§iÄæ";
+
+int Announce() {
+ setutmpmode(ANNOUNCE);
+ a_menu(mytitle, "man",
+ ((HAS_PERM(PERM_SYSOP) || HAS_PERM(PERM_ANNOUNCE)) ? SYSOP :
+ NOBODY));
+ return 0;
+}
diff --git a/mbbsd/args.c b/mbbsd/args.c
new file mode 100644
index 00000000..4d1d6ceb
--- /dev/null
+++ b/mbbsd/args.c
@@ -0,0 +1,62 @@
+/* $Id: args.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#ifdef HAVE_SETPROCTITLE
+
+void initsetproctitle(int argc, char **argv, char **envp) {
+}
+
+#else
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+char **Argv = NULL; /* pointer to argument vector */
+char *LastArgv = NULL; /* end of argv */
+extern char **environ;
+
+void initsetproctitle(int argc, char **argv, char **envp) {
+ register int i;
+
+ /* Move the environment so setproctitle can use the space at
+ the top of memory. */
+ for(i = 0; envp[i]; i++);
+ environ = malloc(sizeof(char *) * (i + 1));
+ for(i = 0; envp[i]; i++)
+ environ[i] = strdup(envp[i]);
+ environ[i] = NULL;
+
+ /* Save start and extent of argv for setproctitle. */
+ Argv = argv;
+ if(i > 0)
+ LastArgv = envp[i - 1] + strlen(envp[i - 1]);
+ else
+ LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
+}
+
+static void do_setproctitle(const char *cmdline) {
+ char buf[256], *p;
+ int i;
+
+ strncpy(buf, cmdline, 256);
+ buf[255] = '\0';
+ i = strlen(buf);
+ if(i > LastArgv - Argv[0] - 2) {
+ i = LastArgv - Argv[0] - 2;
+ }
+ strcpy(Argv[0], buf);
+ p = &Argv[0][i];
+ while(p < LastArgv)
+ *p++='\0';
+ Argv[1] = NULL;
+}
+
+void setproctitle(const char* format, ...) {
+ char buf[256];
+ va_list args;
+ va_start(args, format);
+ vsprintf(buf, format,args);
+ do_setproctitle(buf);
+ va_end(args);
+}
+#endif
diff --git a/mbbsd/bbcall.c b/mbbsd/bbcall.c
new file mode 100644
index 00000000..d7b2d33b
--- /dev/null
+++ b/mbbsd/bbcall.c
@@ -0,0 +1,268 @@
+/* $Id: bbcall.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "proto.h"
+
+#define SERVER_0941 "www.chips.com.tw"
+#define SERVER_0943 "www.pager.com.tw"
+#define SERVER_0948 "www.fitel.net.tw"
+#define SERVER_0947 "www.hoyard.com.tw"
+#define SERVER_0945 "203.73.181.254"
+
+#define CGI_0948 "/cgi-bin/Webpage.dll"
+#define CGI_0941 "/cgi-bin/paging1.pl"
+#define CGI_0947 "/scripts/fp_page1.dll"
+#define CGI_0945 "/Scripts/fiss/PageForm.exe"
+#define CGI_0943 "/tpn/tpnasp/dowebcall.asp"
+
+#define CGI_RAILWAY "http://www.railway.gov.tw/cgi-bin/timetk.cgi"
+
+#define REFER_0943 "http://www.pager.com.tw/tpn/webcall/webcall.asp"
+#define REFER_0948 "http://www.fitel.net.tw/html/svc03.htm"
+#define REFER_0941 "http://www.chips.com.tw:9100/WEB2P/page_1.htm"
+#define REFER_0947 "http://web1.hoyard.com.tw/freeway/freewayi.html"
+#define REFER_0945 "http://203.73.181.254/call.HTM"
+
+static void pager_msg_encode(char *field, char *buf) {
+ char *cc = field;
+ unsigned char *p;
+
+ for(p = (unsigned char *)buf; *p; p++) {
+ if((*p >= '0' && *p <= '9') ||
+ (*p >= 'A' && *p <= 'Z') ||
+ (*p >= 'a' && *p <= 'z') ||
+ *p == ' ')
+ *cc++ = *p == ' ' ? '+' : (char)*p;
+ else {
+ sprintf(cc, "%%%02X", (int)*p);
+ cc += 3;
+ }
+ }
+ *cc = 0;
+}
+
+static void gettime(int flag, int *Year, int *Month, int *Day, int *Hour,
+ int *Minute) {
+ char ans[5];
+
+ do {
+ getdata(10, 0, "¦~[20-]:", ans, 3, LCECHO);
+ *Year = atoi(ans);
+ } while(*Year < 00 || *Year > 02);
+ do {
+ getdata(10, 15, "¤ë[1-12]:", ans, 3, LCECHO);
+ } while(!IsSNum(ans) || (*Month = atoi(ans)) > 12 || *Month < 1);
+ do {
+ getdata(10,30, "¤é[1-31]:", ans, 3, LCECHO);
+ } while(!IsSNum(ans) || (*Day = atoi(ans)) > 31 || *Day < 1);
+ do {
+ getdata(10,45, "®É[0-23]:", ans, 3, LCECHO);
+ } while(!IsSNum(ans) || (*Hour = atoi(ans)) > 23 || *Hour < 0);
+ do {
+ getdata(10,60, "¤À[0-59]:", ans, 3, LCECHO);
+ } while(!IsSNum(ans) || (*Minute=atoi(ans))>59 || *Minute<0);
+ if(flag == 1)
+ *Year-=11;
+}
+
+#define hpressanykey(a) {move(22, 0); prints(a); pressanykey();}
+
+static int Connect(char *s, char *server) {
+ FILE *fp = fopen(BBSHOME "/log/bbcall.log", "a");
+ int sockfd;
+ char result[2048];
+ struct sockaddr_in serv_addr;
+ struct hostent *hp;
+
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ if(sockfd < 0)
+ return 0;
+
+ memset((char *)&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+
+ if((hp = gethostbyname(server)) == NULL)
+ return 0;
+
+ memcpy(&serv_addr.sin_addr, hp->h_addr, hp->h_length);
+
+ if(!strcmp(server, SERVER_0941))
+ serv_addr.sin_port = htons(9100);
+ else
+ serv_addr.sin_port = htons(80);
+
+ if(connect(sockfd, (struct sockaddr *) &serv_addr, sizeof serv_addr)) {
+ hpressanykey("µLªk»P¦øªA¾¹¨ú±o³sµ²¡A¶Ç©I¥¢±Ñ");
+ return 0;
+ } else {
+ mprints(20, 0, "\033[1;33m¦øªA¾¹¤w¸g³s±µ¤W¡A½Ðµy«á"
+ ".....................\033[m");
+ refresh();
+ }
+
+ write(sockfd, s, strlen(s));
+ shutdown(sockfd, 1);
+
+ while(read(sockfd, result, sizeof(result)) > 0) {
+ fprintf(fp, "%s\n", result);
+ fflush(fp);
+ if(strstr(result, "¥¿½T") ||
+ strstr(result,"µ¥«Ý") ||
+ strstr(result,"¦A«×") ||
+ strstr(result,"§¹ ¦¨ ¦^ À³") ||
+ strstr(result, "¹w¬ù¤¤") ||
+ strstr(result,"¶Ç°e¤¤")) {
+ close(sockfd);
+ hpressanykey("¶¶§Q°e¥X¶Ç©I");
+ return 0;
+ }
+ memset(result, 0, sizeof(result));
+ }
+ fclose(fp);
+ close(sockfd);
+ hpressanykey("µLªk¶¶§Q°e¥X¶Ç©I");
+ return 0;
+}
+
+#define PARA \
+"Connection: Keep-Alive\r\n"\
+"User-Agent: Lynx/2.6 libwww-FM/2.14\r\n"\
+"Content-type: application/x-www-form-urlencoded\r\n"\
+"Accept: text/html, text/plain, application/x-wais-source, "\
+"application/html, */*;q=0.001\r\n"\
+"Accept-Encoding: gzip\r\n"\
+"Accept-Language: en\r\n"\
+"Accept-Charset: iso-8859-1,*,utf-8\r\n"
+
+static void halpha0943(char* CoId) {
+ char tmpbuf[64],ans[2];
+ char ID[8];
+ char Msg[64], atrn[512], sendform[1024];
+ int Year = 99, Month = 1, Day = 15, Hour = 13, Minute = 8;
+
+ sprintf(tmpbuf, "\033[1;37m½Ð¿é¤J±z­n¶Ç©Iªº¸¹½X\033[m : %s-", CoId);
+ if(!getdata(7,0, tmpbuf, ID, 7, LCECHO) ||
+ !getdata(8,0, "\033[1;37m½Ð¿é¤J¶Ç©I°T®§\033[m¡G", tmpbuf, 63, LCECHO)) {
+ hpressanykey("©ñ±ó¶Ç©I");
+ return;
+ }
+ pager_msg_encode(Msg,tmpbuf);
+ getdata(9, 0, "\033[1;37m¦pªG§A­n°¨¤W°e½Ð«ö '1' "
+ "¦pªG­n©w®É°e½Ð«ö '2': \033[m", ans, 2, LCECHO);
+
+ if(ans[0] != '1')
+ gettime(0, &Year, &Month, &Day, &Hour, &Minute);
+
+ sprintf(atrn, "CoId=%s&ID=%s&Year=19%02d&Month=%02d&Day=%02d"
+ "&Hour=%02d&Minute=%02d&Msg=%s",
+ CoId, ID,Year,Month,Day,Hour,Minute,Msg);
+ sprintf(sendform, "POST %s HTTP/1.0\nReferer: "
+ "%s\n%sContent-length:%d\n\n%s",
+ CGI_0943, REFER_0943, PARA, strlen(atrn), atrn);
+ Connect(sendform, SERVER_0943);
+ return ;
+}
+
+static void hcall0941() {
+ char ans[2];
+ char PAGER_NO[8], TRAN_MSG[18], TIME[8];
+ char trn[512], sendform[512];
+ int year = 98, month = 12, day = 4, hour = 13, min = 8;
+
+ if(!getdata(7, 0, "\033[1;37 ½Ð±z¿é¤J±z­n¶Ç©Iªº¸¹½X : 0941- \033[m",
+ PAGER_NO, 7, LCECHO) ||
+ !getdata(8, 0, "\033[1;37m½Ð¿é¤J¶Ç©I°T®§\033[m¡G", trn, 17, LCECHO)) {
+ hpressanykey("©ñ±ó¶Ç©I");
+ return;
+ }
+ pager_msg_encode(TRAN_MSG,trn);
+ getdata(9,0, "\033[1;37m¦pªG§A­n°¨¤W°e½Ð«ö '1' "
+ "¦pªG­n©w®É°e½Ð«ö '2': \033[m", ans, 2, LCECHO);
+ if(ans[0] != '1') {
+ strcpy(TIME,"DELAY");
+ gettime(0, &year, &month, &day, &hour, &min);
+ } else
+ strcpy(TIME,"NOW");
+ sprintf(trn,"PAGER_NO=%s&TRAN_MSG=%s&MSG_TYPE=NUMERIC&%s=1"
+ "&year=19%02d&month=%02d&day=%02d&hour=%02d&min=%02d",
+ PAGER_NO, TRAN_MSG, TIME,year,month,day,hour,min);
+
+ sprintf(sendform, "POST %s HTTP/1.0\nReferer: %s\n%s"
+ "Content-length:%d\n\n%s",
+ CGI_0941, REFER_0941, PARA, strlen(trn), trn);
+
+ Connect(sendform, SERVER_0941);
+ return ;
+}
+
+static void hcall0948() {
+ int year = 87, month = 12, day = 19, hour = 12, min = 0, ya = 0;
+ char svc_no[8], message[64], trn[256], sendform[512], ans[3];
+
+ move(7,0);
+ clrtoeol();
+
+ if(!getdata(7, 0, "\033[1;37m½Ð¿é¤J±z­n¶Ç©Iªº¸¹½X\033[m¡G0948-",
+ svc_no, 7, LCECHO) ||
+ !getdata(8, 0, "\033[1;37m½Ð¿é¤J¶Ç©I°T®§\033[m¡G", trn, 61, LCECHO)) {
+ hpressanykey("©ñ±ó¶Ç©I");
+ return;
+ }
+ pager_msg_encode(message, trn);
+ getdata(9, 0, "\033[1;37m¦pªG§A­n°¨¤W°e½Ð«ö '1' "
+ "¦pªG­n©w®É°e½Ð«ö '2'\033[m: ", ans, 2, LCECHO);
+ if(ans[0] != '1') {
+ gettime(1, &year, &month, &day, &hour, &min);
+ ya = 1;
+ }
+
+ sprintf(trn, "MfcISAPICommand=SinglePage&svc_no=%s&reminder=%d"
+ "&year=%02d&month=%02d&day=%02d&hour=%02d&min=%02d&message=%s",
+ svc_no, ya, year, month, day, hour, min, message);
+
+ sprintf(sendform, "GET %s?%s Http/1.0\n\n", CGI_0948, trn);
+
+ Connect(sendform, SERVER_0948);
+ return;
+}
+
+int main_bbcall() {
+ char ch[2];
+
+ clear();
+ move(0, 30);
+ prints("\033[1;37;45m ¹G¹Gáà¾÷ \033[m");
+ move(3, 0);
+ prints("\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¢{\033[m\n");
+ prints("\033[1;33m (1)0941 (2)0943 (3)0946 "
+ " (4)0948 \033[m\n");
+ prints("\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¢}\033[m\n");
+ getdata(7, 8, "\033[1;37m§Aªº¿ï¾Ü? [1-4]\033[m", ch, 2, LCECHO);
+
+ switch(ch[0]) {
+ case '1':
+ hcall0941();
+ break;
+ case '2':
+ halpha0943("0943");
+ break;
+ case '3':
+ halpha0943("0946");
+ break;
+ case '4':
+ hcall0948();
+ break;
+ }
+ return 0;
+}
diff --git a/mbbsd/bbs.c b/mbbsd/bbs.c
new file mode 100644
index 00000000..15db1c91
--- /dev/null
+++ b/mbbsd/bbs.c
@@ -0,0 +1,1904 @@
+/* $Id: bbs.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "perm.h"
+#include "modes.h"
+#include "common.h"
+#include "proto.h"
+
+static int g_board_names(boardheader_t *fhdr) {
+ AddNameList(fhdr->brdname);
+ return 0;
+}
+
+extern userec_t cuser;
+extern void touchdircache(int bid);
+extern int TagNum;
+
+static void mail_by_link(char* owner, char* title, char* path) {
+ char genbuf[200];
+ fileheader_t mymail;
+
+ sprintf(genbuf,BBSHOME"/home/%c/%s", cuser.userid[0], cuser.userid);
+ stampfile(genbuf, &mymail);
+ strcpy(mymail.owner, owner);
+ sprintf(mymail.title, title);
+ mymail.savemode = 0;
+ unlink(genbuf);
+ Link(path, genbuf);
+ sprintf(genbuf,BBSHOME"/home/%c/%s/.DIR",cuser.userid[0],cuser.userid);
+
+ append_record(genbuf, &mymail, sizeof(mymail));
+}
+
+extern int usernum;
+
+void anticrosspost() {
+ char buf[200];
+ time_t now = time(NULL);
+
+ sprintf(buf,
+ "\033[1;33;46m%s \033[37;45mcross post ¤å³¹ \033[37m %s\033[m",
+ cuser.userid, ctime(&now));
+ log_file("etc/illegal_money", buf);
+
+ post_violatelaw(cuser.userid, "Ptt¨t²Îĵ¹î", "Cross-post", "»@³æ³B¥÷");
+ cuser.userlevel |= PERM_VIOLATELAW;
+ cuser.vl_count ++;
+ mail_by_link("Pttĵ¹î³¡¶¤", "Cross-Post»@³æ",
+ BBSHOME "/etc/crosspost.txt");
+ passwd_update(usernum, &cuser);
+ exit(0);
+}
+
+/* Heat CharlieL*/
+int save_violatelaw() {
+ char buf[128], ok[3];
+
+ setutmpmode(VIOLATELAW);
+ clear();
+ stand_title("ú»@³æ¤¤¤ß");
+
+ if(!(cuser.userlevel & PERM_VIOLATELAW)) {
+ mprints(22, 0, "\033[1;31m§AµL²á°Ú? §A¤S¨S¦³³Q¶}»@³æ~~\033[m");
+ pressanykey();
+ return 0;
+ }
+
+ reload_money();
+ if(cuser.money < (int)cuser.vl_count*1000) {
+ sprintf(buf, "\033[1;31m³o¬O§A²Ä %d ¦¸¹H¤Ï¥»¯¸ªk³W"
+ "¥²¶·Ãº¥X %d $Ptt ,§A¥u¦³ %d ¤¸, ¿ú¤£°÷°Õ!!\033[m",
+ (int)cuser.vl_count, (int)cuser.vl_count * 1000, cuser.money);
+ mprints(22, 0, buf);
+ pressanykey();
+ return 0;
+ }
+
+ move(5,0);
+ prints("\033[1;37m§Aª¾¹D¶Ü? ¦]¬°§Aªº¹Hªk "
+ "¤w¸g³y¦¨«Ü¦h¤Hªº¤£«K\033[m\n");
+ prints("\033[1;37m§A¬O§_½T©w¥H«á¤£·|¦A¥Ç¤F¡H\033[m\n");
+
+ if(!getdata(10,0,"½T©w¶Ü¡H[y/n]:", ok, 2, LCECHO) ||
+ ok[0] == 'n' || ok[0] == 'N') {
+ mprints(22,0,"\033[1;31mµ¥§A·Q³q¤F¦A¨Ó§a!! "
+ "§Ú¬Û«H§A¤£·|ª¾¿ù¤£§ïªº~~~\033[m");
+ pressanykey();
+ return 0;
+ }
+
+ sprintf(buf, "³o¬O§A²Ä %d ¦¸¹Hªk ¥²¶·Ãº¥X %d $Ptt",
+ cuser.vl_count, cuser.vl_count*1000);
+ mprints(11,0,buf);
+
+ if(!getdata(10, 0, "­n¥I¿ú[y/n]:", ok, 2, LCECHO) ||
+ ok[0] == 'N' || ok[0] == 'n') {
+
+ mprints(22,0, "\033[1;31m ¶â ¦s°÷¿ú ¦A¨Ó§a!!!\033[m");
+ pressanykey();
+ return 0;
+ }
+
+ demoney(-1000*cuser.vl_count);
+ cuser.userlevel &= (~PERM_VIOLATELAW);
+ passwd_update(usernum, &cuser);
+ return 0;
+}
+
+void make_blist() {
+ CreateNameList();
+ apply_boards(g_board_names);
+}
+
+extern int currbid;
+extern char currBM[];
+extern int currmode;
+extern char currboard[];
+static time_t board_note_time;
+static char *brd_title;
+
+void set_board() {
+ boardheader_t *bp;
+
+ bp = getbcache(currbid);
+ board_note_time = bp->bupdate;
+ brd_title = bp->BM;
+ if(brd_title[0] <= ' ')
+ brd_title = "¼x¨D¤¤";
+ sprintf(currBM, "ªO¥D¡G%s", brd_title);
+ brd_title = ((bp->bvote != 2 && bp->bvote) ? "¥»¬ÝªO¶i¦æ§ë²¼¤¤" :
+ bp->title + 7);
+ currmode = (currmode & (MODE_DIRTY | MODE_MENU)) | MODE_STARTED ;
+
+ if (HAS_PERM(PERM_ALLBOARD) || is_BM(bp->BM))
+ currmode = currmode | MODE_BOARD | MODE_POST;
+ else if(haspostperm(currboard))
+ currmode |= MODE_POST;
+}
+
+static void readtitle() {
+ showtitle(currBM, brd_title);
+ outs("[¡ö]Â÷¶} [¡÷]¾\\Ū [^P]µoªí¤å³¹ [b]³Æ§Ñ¿ý [d]§R°£ [z]ºëµØ°Ï "
+ "[TAB]¤åºK [h]elp\n\033[7m ½s¸¹ ¤é ´Á §@ ªÌ ¤å ³¹ ¼Ð ÃD"
+ " \033[m");
+}
+
+extern int brc_num;
+extern int brc_list[];
+extern char currtitle[];
+
+extern int Tagger();
+
+static void readdoent(int num, fileheader_t *ent) {
+ int type;
+ char *mark, *title, color;
+
+ type = brc_unread(ent->filename,brc_num,brc_list) ? '+' : ' ';
+
+ if((currmode & MODE_BOARD) && (ent->filemode & FILE_DIGEST))
+ type = (type == ' ') ? '*' : '#';
+ else if(currmode & MODE_BOARD || HAS_PERM(PERM_LOGINOK)) {
+ if(ent->filemode & FILE_MARKED)
+ type = (type == ' ') ? 'm' : 'M';
+
+ else if (TagNum && !Tagger(atoi(ent->filename + 2), 0, TAG_NIN))
+ type = 'D';
+
+ else if (ent->filemode & FILE_SOLVED)
+ type = 's';
+ }
+
+ title = subject(mark = ent->title);
+ if(title == mark)
+ color = '1', mark = "¡¼";
+ else
+ color = '3', mark = "R:";
+
+ if(title[47])
+ strcpy(title + 44, " ¡K"); /* §â¦h¾lªº string ¬å±¼ */
+
+ if(strncmp(currtitle, title, 40))
+ prints("%6d %c %-7s%-13.12s%s %s\n", num, type,
+ ent->date, ent->owner, mark, title);
+ else
+ prints("%6d %c %-7s%-13.12s\033[1;3%cm%s %s\033[m\n", num, type,
+ ent->date, ent->owner, color, mark, title);
+}
+
+extern char currfile[];
+
+int cmpfilename(fileheader_t *fhdr) {
+ return (!strcmp(fhdr->filename, currfile));
+}
+
+extern unsigned char currfmode;
+
+int cmpfmode(fileheader_t *fhdr) {
+ return (fhdr->filemode & currfmode);
+}
+
+extern char currowner[];
+
+int cmpfowner(fileheader_t *fhdr) {
+ return !strcasecmp(fhdr->owner, currowner);
+}
+
+extern char *err_bid;
+extern userinfo_t *currutmp;
+
+int whereami(int ent, fileheader_t *fhdr, char *direct) {
+ boardheader_t *bh, *p[32], *root;
+ int i,j;
+
+ if(!currutmp->brc_id) return 0;
+
+ move(1,0);
+ clrtobot();
+ bh=getbcache(currutmp->brc_id);
+ root=getbcache(1);
+ p[0]=bh;
+ for(i=0;i<31 && p[i]->parent!=root && p[i]->parent;i++)
+ p[i+1]=p[i]->parent;
+ j=i;
+ prints("§Ú¦b­þ?\n%-40.40s %.13s\n", p[j]->title+7, p[j]->BM);
+ for(j--;j>=0;j--)
+ prints("%*s %-13.13s %-37.37s %.13s\n", (i-j)*2, "",
+ p[j]->brdname, p[j]->title,
+ p[j]->BM);
+
+ pressanykey();
+ return FULLUPDATE;
+}
+static int do_select(int ent, fileheader_t *fhdr, char *direct) {
+ char bname[20];
+ char bpath[60];
+ boardheader_t *bh;
+ struct stat st;
+ int i;
+
+ move(0, 0);
+ clrtoeol();
+ make_blist();
+ namecomplete(MSG_SELECT_BOARD, bname);
+ if(bname[0]=='\0' || !(i = getbnum(bname)))
+ return FULLUPDATE;
+ bh = getbcache(i);
+ if(!Ben_Perm(bh)) return FULLUPDATE;
+ strcpy(bname, bh->brdname);
+ currbid=i;
+
+ setbpath(bpath, bname);
+ if((*bname == '\0') || (stat(bpath, &st) == -1)) {
+ move(2, 0);
+ clrtoeol();
+ outs(err_bid);
+ return FULLUPDATE;
+ }
+
+ currutmp->brc_id = currbid;
+
+ brc_initial(bname);
+ set_board();
+ setbdir(direct, currboard);
+
+ move(1, 0);
+ clrtoeol();
+ return NEWDIRECT;
+}
+
+/* ----------------------------------------------------- */
+/* §ï¨} innbbsd Âà¥X«H¥ó¡B³s½u¬å«H¤§³B²zµ{§Ç */
+/* ----------------------------------------------------- */
+void outgo_post(fileheader_t *fh, char *board) {
+ FILE *foo;
+
+ if((foo = fopen("innd/out.bntp", "a"))) {
+ fprintf(foo, "%s\t%s\t%s\t%s\t%s\n", board,
+ fh->filename, cuser.userid, cuser.username, fh->title);
+ fclose(foo);
+ }
+}
+
+extern char *str_author1;
+extern char *str_author2;
+
+static void cancelpost(fileheader_t *fh, int by_BM) {
+ FILE *fin, *fout;
+ char *ptr, *brd;
+ fileheader_t postfile;
+ char genbuf[200];
+ char nick[STRLEN], fn1[STRLEN], fn2[STRLEN];
+
+ setbfile(fn1, currboard, fh->filename);
+ if((fin = fopen(fn1, "r"))) {
+ brd = by_BM ? "deleted" : "junk";
+
+ setbpath(fn2, brd);
+ stampfile(fn2, &postfile);
+ memcpy(postfile.owner, fh->owner, IDLEN + TTLEN + 10);
+ postfile.savemode = 'D';
+
+ if(fh->savemode == 'S') {
+ nick[0] = '\0';
+ while(fgets(genbuf, sizeof(genbuf), fin)) {
+ if (!strncmp(genbuf, str_author1, LEN_AUTHOR1) ||
+ !strncmp(genbuf, str_author2, LEN_AUTHOR2)) {
+ if((ptr = strrchr(genbuf, ')')))
+ *ptr = '\0';
+ if((ptr = (char *)strchr(genbuf, '(')))
+ strcpy(nick, ptr + 1);
+ break;
+ }
+ }
+
+ if((fout = fopen("innd/cancel.bntp", "a"))) {
+ fprintf(fout, "%s\t%s\t%s\t%s\t%s\n", currboard, fh->filename,
+ cuser.userid, nick, fh->title);
+ fclose(fout);
+ }
+ }
+
+ fclose(fin);
+ Rename(fn1, fn2);
+ setbdir(genbuf, brd);
+ append_record(genbuf, &postfile, sizeof(postfile));
+ }
+}
+
+extern char *str_reply;
+extern char save_title[];
+
+/* ----------------------------------------------------- */
+/* µoªí¡B¦^À³¡B½s¿è¡BÂà¿ý¤å³¹ */
+/* ----------------------------------------------------- */
+void do_reply_title(int row, char *title) {
+ char genbuf[200];
+ char genbuf2[4];
+
+ if(strncasecmp(title, str_reply, 4))
+ sprintf(save_title, "Re: %s", title);
+ else
+ strcpy(save_title, title);
+ save_title[TTLEN - 1] = '\0';
+ sprintf(genbuf, "±Ä¥Î­ì¼ÐÃD¡m%.60s¡n¶Ü?[Y] ", save_title);
+ getdata(row, 0, genbuf, genbuf2, 4, LCECHO);
+ if(genbuf2[0] == 'n' || genbuf2[0] == 'N')
+ getdata(++row, 0, "¼ÐÃD¡G", save_title, TTLEN, DOECHO);
+}
+
+static void do_unanonymous_post(char* fpath) {
+ fileheader_t mhdr;
+ char title[128];
+ char genbuf[200];
+
+ setbpath(genbuf, "UnAnonymous");
+ if(dashd(genbuf)) {
+ stampfile(genbuf, &mhdr);
+ unlink(genbuf);
+ Link(fpath, genbuf);
+ strcpy(mhdr.owner, cuser.userid);
+ strcpy(mhdr.title, save_title);
+ mhdr.savemode = 0;
+ mhdr.filemode = 0;
+ setbdir(title, "UnAnonymous");
+ append_record(title, &mhdr, sizeof(mhdr));
+ }
+}
+
+extern char quote_file[];
+extern char quote_user[];
+extern int curredit;
+extern unsigned int currbrdattr;
+extern char currdirect[];
+extern char *err_uid;
+
+#ifdef NO_WATER_POST
+static time_t last_post_time = 0;
+static time_t water_counts = 0;
+#endif
+int local_article;
+char real_name[20];
+
+static int do_general() {
+ fileheader_t postfile;
+ char fpath[80], buf[80];
+ int aborted, defanony, ifuseanony;
+ char genbuf[200],*owner;
+ boardheader_t *bp;
+ int islocal;
+
+ ifuseanony = 0;
+ bp = getbcache(currbid);
+
+ clear();
+ if(!(currmode & MODE_POST)) {
+ move(5, 10);
+ outs("¹ï¤£°_¡A±z¥Ø«eµLªk¦b¦¹µoªí¤å³¹¡I");
+ pressanykey();
+ return FULLUPDATE;
+ }
+
+#ifdef NO_WATER_POST
+ /* ¤T¤ÀÄÁ¤º³Ì¦hµoªí¤­½g¤å³¹ */
+ if(currutmp->lastact - last_post_time < 60 * 3) {
+ if(water_counts >= 5) {
+ move(5, 10);
+ outs("¹ï¤£°_¡A±zªº¤å³¹¤Ó¤ôÅo¡A¦h«ä¦Ò¤@¤U¡A«Ý·|¦Apost§a¡I");
+ pressanykey();
+ return FULLUPDATE;
+ }
+ } else {
+ last_post_time = currutmp->lastact;
+ water_counts = 0;
+ }
+#endif
+
+ setbfile(genbuf, currboard, FN_POST_NOTE );
+
+ if(more(genbuf,NA) == -1)
+ more("etc/"FN_POST_NOTE , NA);
+
+ move(19,0);
+ prints("µoªí¤å³¹©ó¡i\033[33m %s\033[m ¡j \033[32m%s\033[m ¬ÝªO\n\n",
+ currboard, bp->title + 7);
+
+ if(quote_file[0])
+ do_reply_title(20, currtitle);
+ else {
+ getdata(21, 0, "¼ÐÃD¡G", save_title, TTLEN, DOECHO);
+ strip_ansi(save_title,save_title,0);
+ }
+ if(save_title[0] == '\0')
+ return FULLUPDATE;
+
+ curredit &= ~EDIT_MAIL;
+ curredit &= ~EDIT_ITEM;
+ setutmpmode(POSTING);
+
+ /* ¥¼¨ã³Æ Internet Åv­­ªÌ¡A¥u¯à¦b¯¸¤ºµoªí¤å³¹ */
+ if(HAS_PERM(PERM_INTERNET))
+ local_article = 0;
+ else
+ local_article = 1;
+
+ /* build filename */
+ setbpath(fpath, currboard);
+ stampfile(fpath, &postfile);
+
+ aborted = vedit(fpath, YEA, &islocal);
+ if(aborted == -1) {
+ unlink(fpath);
+ pressanykey();
+ return FULLUPDATE;
+ }
+ water_counts++; /* po¦¨¥\ */
+
+ /* set owner to Anonymous , for Anonymous board */
+
+#ifdef HAVE_ANONYMOUS
+ /* Ptt and Jaky */
+ defanony=currbrdattr & BRD_DEFAULTANONYMOUS;
+ if((currbrdattr & BRD_ANONYMOUS) &&
+ ((strcmp(real_name,"r") && defanony) || (real_name[0] && !defanony))
+ ) {
+ strcat(real_name,".");
+ owner = real_name;
+ ifuseanony=1;
+ } else
+ owner = cuser.userid;
+#else
+ owner = cuser.userid;
+#endif
+ /* ¿ú */
+ aborted = (aborted > MAX_POST_MONEY * 2) ? MAX_POST_MONEY : aborted / 2;
+ postfile.money = aborted;
+ strcpy(postfile.owner, owner);
+ strcpy(postfile.title, save_title);
+ if(islocal) { /* local save */
+ postfile.savemode = 'L';
+ postfile.filemode = FILE_LOCAL;
+ } else
+ postfile.savemode = 'S';
+
+ setbdir(buf, currboard);
+ if(append_record(buf, &postfile, sizeof(postfile)) != -1) {
+ setbtotal(currbid);
+
+ if(currmode & MODE_SELECT)
+ append_record(currdirect,&postfile,sizeof(postfile));
+ if(!islocal && !(bp->brdattr & BRD_NOTRAN))
+ outgo_post(&postfile, currboard);
+ brc_addlist(postfile.filename);
+
+ if(!(currbrdattr & BRD_HIDE) &&
+ (!bp->level || (currbrdattr & BRD_POSTMASK))) {
+ setbpath(genbuf, ALLPOST);
+ stampfile(genbuf, &postfile);
+ unlink(genbuf);
+
+ /* jochang: boards may spread across many disk */
+ /* link doesn't work across device,
+ Link doesn't work if we have same-time-across-device posts,
+ we try symlink now */
+ {
+ /* we need absolute path for symlink */
+ char abspath[256]=BBSHOME"/";
+ strcat(abspath,fpath);
+ symlink(abspath,genbuf);
+ }
+ strcpy(postfile.owner, owner);
+ strcpy(postfile.title, save_title);
+ postfile.savemode = 'L';
+ setbdir(genbuf, ALLPOST);
+ if(append_record(genbuf, &postfile, sizeof(postfile)) != -1) {
+ setbtotal(getbnum(ALLPOST));
+ }
+ }
+
+ outs("¶¶§Q¶K¥X§G§i¡A");
+
+#ifdef MAX_POST_MONEY
+ aborted = (aborted > MAX_POST_MONEY) ? MAX_POST_MONEY : aborted;
+#endif
+ if(strcmp(currboard, "Test") && !ifuseanony) {
+ prints("³o¬O±zªº²Ä %d ½g¤å³¹¡C ½Z¹S %d »È¡C",
+ ++cuser.numposts, aborted );
+ demoney(aborted);
+ passwd_update(usernum, &cuser); /* post ¼Æ */
+ } else
+ outs("´ú¸Õ«H¥ó¤£¦C¤J¬ö¿ý¡A·q½Ð¥]²[¡C");
+
+ /* ¦^À³¨ì­ì§@ªÌ«H½c */
+
+ if(curredit & EDIT_BOTH) {
+ char *str, *msg = "¦^À³¦Ü§@ªÌ«H½c";
+
+ if((str = strchr(quote_user, '.'))) {
+ if(
+#ifndef USE_BSMTP
+ bbs_sendmail(fpath, save_title, str + 1)
+#else
+ bsmtp(fpath, save_title, str + 1 ,0)
+#endif
+ < 0)
+ msg = "§@ªÌµLªk¦¬«H";
+ } else {
+ sethomepath(genbuf, quote_user);
+ stampfile(genbuf, &postfile);
+ unlink(genbuf);
+ Link(fpath, genbuf);
+
+ strcpy(postfile.owner, cuser.userid);
+ strcpy(postfile.title, save_title);
+ postfile.savemode = 'B';/* both-reply flag */
+ sethomedir(genbuf, quote_user);
+ if(append_record(genbuf, &postfile, sizeof(postfile)) == -1)
+ msg = err_uid;
+ }
+ outs(msg);
+ curredit ^= EDIT_BOTH;
+ }
+ if(currbrdattr & BRD_ANONYMOUS)
+ do_unanonymous_post(fpath);
+ }
+ pressanykey();
+ return FULLUPDATE;
+}
+
+int do_post() {
+ boardheader_t *bp;
+ bp = getbcache(currbid);
+ if(bp->brdattr & BRD_VOTEBOARD)
+ return do_voteboard();
+ else if(!(bp->brdattr & BRD_GROUPBOARD))
+ return do_general();
+ touchdircache(currbid);
+ return 0;
+}
+
+extern int b_lines;
+extern int curredit;
+
+static void do_generalboardreply(fileheader_t *fhdr){
+ char genbuf[200];
+ getdata(b_lines - 1, 0,
+ "¡¶ ¦^À³¦Ü (F)¬ÝªO (M)§@ªÌ«H½c (B)¤GªÌ¬Ò¬O (Q)¨ú®ø¡H[F] ",
+ genbuf, 3, LCECHO);
+ switch(genbuf[0]) {
+ case 'm':
+ mail_reply(0, fhdr, 0);
+ case 'q':
+ break;
+
+ case 'b':
+ curredit = EDIT_BOTH;
+ default:
+ strcpy(currtitle, fhdr->title);
+ strcpy(quote_user, fhdr->owner);
+ quote_file[79] = fhdr->savemode;
+ do_post();
+ }
+ *quote_file = 0;
+}
+
+int getindex(char *fpath, char *fname, int size) {
+ int fd, now=0;
+ fileheader_t fhdr;
+
+ if((fd = open(fpath, O_RDONLY, 0)) != -1) {
+ while((read(fd, &fhdr, size) == size)) {
+ now++;
+ if(!strcmp(fhdr.filename,fname)) {
+ close(fd);
+ return now;
+ }
+ }
+ close(fd);
+ }
+ return 0;
+}
+
+int invalid_brdname(char *brd) {
+ register char ch;
+
+ ch = *brd++;
+ if(not_alnum(ch))
+ return 1;
+ while((ch = *brd++)) {
+ if(not_alnum(ch) && ch != '_' && ch != '-' && ch != '.')
+ return 1;
+ }
+ return 0;
+}
+
+static void do_reply(fileheader_t *fhdr) {
+ boardheader_t *bp;
+ bp = getbcache(currbid);
+ if (bp->brdattr & BRD_VOTEBOARD)
+ do_voteboardreply(fhdr);
+ else
+ do_generalboardreply(fhdr);
+}
+
+static int reply_post(int ent, fileheader_t *fhdr, char *direct) {
+ if(!(currmode & MODE_POST))
+ return DONOTHING;
+
+ setdirpath(quote_file, direct, fhdr->filename);
+ do_reply(fhdr);
+ *quote_file = 0;
+ return FULLUPDATE;
+}
+
+static int edit_post(int ent, fileheader_t *fhdr, char *direct) {
+ char fpath[80], fpath0[80];
+ char genbuf[200];
+ fileheader_t postfile;
+ boardheader_t *bp;
+ bp = getbcache(currbid);
+ if (!HAS_PERM(PERM_SYSOP) && (bp->brdattr & BRD_VOTEBOARD))
+ return DONOTHING;
+
+ if ((!HAS_PERM(PERM_SYSOP)) &&
+ strcmp(fhdr->owner, cuser.userid))
+ return DONOTHING;
+ setutmpmode(REEDIT);
+ setdirpath(genbuf, direct, fhdr->filename);
+ local_article = fhdr->filemode & FILE_LOCAL;
+ strcpy(save_title, fhdr->title);
+
+/* rocker.011018: ³o¸Ì¬O¤£¬O¸ÓÀˬd¤@¤U­×§ï¤å³¹«áªºmoney©M­ì¦³ªº¤ñ¸û? */
+ if(vedit(genbuf, 0, NULL) != -1) {
+ setbpath(fpath, currboard);
+ stampfile(fpath, &postfile);
+ unlink(fpath);
+ setbfile(fpath0, currboard, fhdr->filename);
+
+ Rename(fpath0, fpath);
+
+/* rocker.011018: fix ¦ê±µ¼Ò¦¡§ï¤å³¹«á¤å³¹´N¤£¨£ªºbug */
+ if ((currmode & MODE_SELECT) && (fhdr->money & FHR_REFERENCE))
+ {
+ fileheader_t hdr;
+ int num;
+
+ num = fhdr->money & ~FHR_REFERENCE;
+ setbdir(fpath0, currboard);
+ get_record(fpath0, &hdr, sizeof (hdr), num);
+
+ /* ¦A³o¸Ì­ncheck¤@¤U­ì¨Óªºdir¸Ì­±¬O¤£¬O¦³³Q¤H°Ê¹L... */
+ if (!strcmp (hdr.filename, fhdr->filename))
+ {
+ strcpy(hdr.filename, postfile.filename);
+ strcpy(hdr.title, save_title);
+ substitute_record(fpath0, &hdr, sizeof(hdr), num);
+ }
+ }
+
+ strcpy(fhdr->filename, postfile.filename);
+ strcpy(fhdr->title, save_title);
+ brc_addlist(postfile.filename);
+ substitute_record(direct, fhdr, sizeof(*fhdr), ent);
+/* rocker.011018: ¶¶«K§ó·s¤@¤Ucache */
+ touchdircache(currbid);
+ }
+ return FULLUPDATE;
+}
+
+extern crosspost_t postrecord;
+#define UPDATE_USEREC (currmode |= MODE_DIRTY)
+
+static int cross_post(int ent, fileheader_t *fhdr, char *direct) {
+ char xboard[20], fname[80], xfpath[80], xtitle[80], inputbuf[10];
+ fileheader_t xfile;
+ FILE *xptr;
+ int author = 0;
+ char genbuf[200];
+ char genbuf2[4];
+ boardheader_t *bp;
+ make_blist();
+ move(2, 0);
+ clrtoeol();
+ move(3, 0);
+ clrtoeol();
+ move(1, 0);
+ bp = getbcache(currbid);
+ if (bp && (bp->brdattr & BRD_VOTEBOARD))
+ return FULLUPDATE;
+ namecomplete("Âà¿ý¥»¤å³¹©ó¬ÝªO¡G", xboard);
+ if(*xboard == '\0' || !haspostperm(xboard))
+ return FULLUPDATE;
+
+ if((ent = str_checksum(fhdr->title)) != 0 &&
+ ent == postrecord.checksum[0]) {
+ /* Àˬd cross post ¦¸¼Æ */
+ if(postrecord.times++ > MAX_CROSSNUM)
+ anticrosspost();
+ } else {
+ postrecord.times = 0;
+ postrecord.checksum[0] = ent;
+ }
+
+ ent = 1;
+ if(HAS_PERM(PERM_SYSOP) || !strcmp(fhdr->owner, cuser.userid)) {
+ getdata(2, 0, "(1)­ì¤åÂà¸ü (2)ÂÂÂà¿ý®æ¦¡¡H[1] ",
+ genbuf, 3, DOECHO);
+ if(genbuf[0] != '2') {
+ ent = 0;
+ getdata(2, 0, "«O¯d­ì§@ªÌ¦WºÙ¶Ü?[Y] ", inputbuf, 3, DOECHO);
+ if (inputbuf[0] != 'n' && inputbuf[0] != 'N') author = 1;
+ }
+ }
+
+ if(ent)
+ sprintf(xtitle, "[Âà¿ý]%.66s", fhdr->title);
+ else
+ strcpy(xtitle, fhdr->title);
+
+ sprintf(genbuf, "±Ä¥Î­ì¼ÐÃD¡m%.60s¡n¶Ü?[Y] ", xtitle);
+ getdata(2, 0, genbuf, genbuf2, 4, LCECHO);
+ if(genbuf2[0] == 'n' || genbuf2[0] == 'N') {
+ if(getdata_str(2, 0, "¼ÐÃD¡G", genbuf, TTLEN, DOECHO,xtitle))
+ strcpy(xtitle, genbuf);
+ }
+
+ getdata(2, 0, "(S)¦sÀÉ (L)¯¸¤º (Q)¨ú®ø¡H[Q] ", genbuf, 3, LCECHO);
+ if(genbuf[0] == 'l' || genbuf[0] == 's') {
+ int currmode0 = currmode;
+
+ currmode = 0;
+ setbpath(xfpath, xboard);
+ stampfile(xfpath, &xfile);
+ if(author)
+ strcpy(xfile.owner, fhdr->owner);
+ else
+ strcpy(xfile.owner, cuser.userid);
+ strcpy(xfile.title, xtitle);
+ if(genbuf[0] == 'l') {
+ xfile.savemode = 'L';
+ xfile.filemode = FILE_LOCAL;
+ } else
+ xfile.savemode = 'S';
+
+ setbfile(fname, currboard, fhdr->filename);
+// if(ent) {
+ xptr = fopen(xfpath, "w");
+
+ strcpy(save_title, xfile.title);
+ strcpy(xfpath, currboard);
+ strcpy(currboard, xboard);
+ write_header(xptr);
+ strcpy(currboard, xfpath);
+
+ fprintf(xptr, "¡° [¥»¤åÂà¿ý¦Û %s ¬ÝªO]\n\n", currboard);
+
+ b_suckinfile(xptr, fname);
+ addsignature(xptr,0);
+ fclose(xptr);
+/* Cross fs¦³°ÝÃD
+ } else {
+ unlink(xfpath);
+ link(fname, xfpath);
+ }
+*/
+ setbdir(fname, xboard);
+ append_record(fname, &xfile, sizeof(xfile));
+ bp = getbcache(getbnum(xboard));
+ if(!xfile.filemode && !(bp->brdattr && BRD_NOTRAN))
+ outgo_post(&xfile, xboard);
+ setbtotal(getbnum(xboard));
+ cuser.numposts++;
+ UPDATE_USEREC;
+ outs("¤å³¹Âà¿ý§¹¦¨");
+ pressanykey();
+ currmode = currmode0;
+ }
+ return FULLUPDATE;
+}
+
+static int read_post(int ent, fileheader_t *fhdr, char *direct) {
+ char genbuf[200];
+ int more_result;
+
+ if(fhdr->owner[0] == '-')
+ return DONOTHING;
+
+ setdirpath(genbuf, direct, fhdr->filename);
+
+ if((more_result = more(genbuf, YEA)) == -1)
+ return DONOTHING;
+
+ brc_addlist(fhdr->filename);
+ strncpy(currtitle, subject(fhdr->title), 40);
+ strncpy(currowner, subject(fhdr->owner), IDLEN + 2);
+
+ switch (more_result) {
+ case 1:
+ return READ_PREV;
+ case 2:
+ return RELATE_PREV;
+ case 3:
+ return READ_NEXT;
+ case 4:
+ return RELATE_NEXT;
+ case 5:
+ return RELATE_FIRST;
+ case 6:
+ return FULLUPDATE;
+ case 7:
+ case 8:
+ if((currmode & MODE_POST)) {
+ strcpy(quote_file, genbuf);
+ do_reply(fhdr);
+ *quote_file = 0;
+ }
+ return FULLUPDATE;
+ case 9:
+ return 'A';
+ case 10:
+ return 'a';
+ case 11:
+ return '/';
+ case 12:
+ return '?';
+ }
+
+
+ outmsg("\033[34;46m ¾\\Ū¤å³¹ \033[31;47m (R/Y)\033[30m¦^«H \033[31m"
+ "(=[]<>)\033[30m¬ÛÃö¥DÃD \033[31m(¡ô¡õ)\033[30m¤W¤U«Ê \033[31m(¡ö)"
+ "\033[30mÂ÷¶} \033[m");
+
+ switch(egetch()) {
+ case 'q':
+ case 'Q':
+ case KEY_LEFT:
+ break;
+
+ case ' ':
+ case KEY_RIGHT:
+ case KEY_DOWN:
+ case KEY_PGDN:
+ case 'n':
+ case Ctrl('N'):
+ return READ_NEXT;
+
+ case KEY_UP:
+ case 'p':
+ case Ctrl('P'):
+ case KEY_PGUP:
+ return READ_PREV;
+
+ case '=':
+ return RELATE_FIRST;
+
+ case ']':
+ case 't':
+ return RELATE_NEXT;
+
+ case '[':
+ return RELATE_PREV;
+
+ case '.':
+ case '>':
+ return THREAD_NEXT;
+
+ case ',':
+ case '<':
+ return THREAD_PREV;
+
+ case Ctrl('C'):
+ cal();
+ return FULLUPDATE;
+ break;
+
+ case Ctrl('I'):
+ t_idle();
+ return FULLUPDATE;
+ case 'y':
+ case 'r':
+ case 'R':
+ case 'Y':
+ if((currmode & MODE_POST)) {
+ strcpy(quote_file, genbuf);
+ do_reply(fhdr);
+ *quote_file = 0;
+ }
+ }
+ return FULLUPDATE;
+}
+
+/* ----------------------------------------------------- */
+/* ±Ä¶°ºëµØ°Ï */
+/* ----------------------------------------------------- */
+static int b_man() {
+ char buf[64];
+
+ setapath(buf, currboard);
+ if( (currmode & MODE_BOARD) || HAS_PERM(PERM_SYSOP) ){
+ char genbuf[128];
+ int fd;
+ sprintf(genbuf, "%s/.rebuild", buf);
+ if( (fd = open(genbuf, O_CREAT, 0640)) > 0 )
+ close(fd);
+ }
+ return a_menu(currboard, buf, HAS_PERM(PERM_ALLBOARD) ? 2 :
+ (currmode & MODE_BOARD ? 1 : 0));
+}
+
+#ifndef NO_GAMBLE
+static int join_gamble(int ent, fileheader_t *fhdr, char *direct) {
+ ticket(currbid);
+ return FULLUPDATE;
+}
+static int hold_gamble(int ent, fileheader_t *fhdr, char *direct) {
+ char fn_ticket[128],fn_ticket_end[128],genbuf[128],
+ msg[256]="",yn[10]="";
+ int i;
+ FILE *fp=NULL;
+
+ if(!(currmode & MODE_BOARD)) return 0;
+ setbfile(fn_ticket, currboard, FN_TICKET);
+ setbfile(fn_ticket_end, currboard, FN_TICKET_END);
+ if(dashf(fn_ticket))
+ {
+ getdata(b_lines - 1, 0, "¤w¸g¦³Á|¿ì½ä½L, "
+ "¬O§_­n [°±¤î¤Uª`]?(N/y)¡G", yn, 3, LCECHO);
+ if(yn[0]!='y') return FULLUPDATE;
+ rename(fn_ticket, fn_ticket_end);
+ return FULLUPDATE;
+ }
+
+ if(dashf(fn_ticket_end))
+ {
+ getdata(b_lines - 1, 0, "¤w¸g¦³Á|¿ì½ä½L, "
+ "¬O§_­n [¶}¼ú]?(N/y)¡G", yn, 3, LCECHO);
+ if(yn[0]!='y') return FULLUPDATE;
+ openticket(currbid);
+ return FULLUPDATE;
+ }
+ getdata(b_lines - 2, 0, "­nÁ|¿ì½ä½L (N/y):", yn, 3, LCECHO);
+ if(yn[0]!='y') return FULLUPDATE;
+ getdata(b_lines - 1, 0, "½ä¤°»ò? ½Ð¿é¤J¥DÃD (¿é¤J«á½s¿è¤º®e):",
+ msg, 20, DOECHO);
+ if(msg[0]==0 ||
+ vedit(fn_ticket_end, NA, NULL)<0)
+ return FULLUPDATE;
+
+ clear();
+ showtitle("Á|¿ì½ä½L",BBSNAME);
+ setbfile(genbuf, currboard, FN_TICKET_ITEMS);
+
+// sprintf(genbuf, "%s/"FN_TICKET_ITEMS, direct);
+
+ if(!(fp=fopen(genbuf,"w"))) return FULLUPDATE;
+ do
+ {
+ getdata(2, 0, "¿é¤J±m²¼»ù®æ (»ù®æ:10-10000):",yn,6, LCECHO);
+ i=atoi(yn);
+ } while( i<10 || i>10000);
+ fprintf(fp,"%d\n",i);
+ move(3,0);
+ sprintf(genbuf,"½Ð¨ì %s ª© «ö'f'°Ñ»P½ä³Õ!\n\n¤@±i %d Ptt¹ô, ³o¬O%sªº½ä³Õ\n",
+ currboard,
+ i, i<100 ? "¤p½ä¦¡" : i<500 ? "¥­¥Á¯Å":
+ i<1000 ?"¶Q±Ú¯Å" : i<5000 ?"´I»¨¯Å" : "¶É®a¿º²£");
+ strcat(msg, genbuf);
+ prints("½Ð¨Ì¦¸¿é¤J±m²¼¦WºÙ, »Ý´£¨Ñ2~8¶µ. (¥¼º¡¤K¶µ, ¿é¤Jª½±µ«öenter)\n");
+ for(i=0; i<8; i++)
+ {
+ sprintf(yn, " %d)",i+1);
+ getdata(6+i, 0, yn, genbuf, 9, DOECHO);
+ if(!genbuf[0] && i>1)
+ break;
+ fprintf(fp,"%s\n",genbuf);
+ }
+ fclose(fp);
+ move(8+i,0);
+ prints("½ä½L³]©w§¹¦¨");
+ sprintf(genbuf,"[¤½§i] %s ª© ¶}©l½ä³Õ!", currboard);
+ post_msg(currboard, genbuf, msg, cuser.userid);
+ post_msg("Record", genbuf+7, msg, "[°¨¸ô±´¤l]");
+ /* Tim ±±¨îCS, ¥H§K¥¿¦bª±ªºuser§â¸ê®Æ¤w¸g¼g¶i¨Ó */
+ rename(fn_ticket_end, fn_ticket); // ³]©w§¹¤~§âÀɦW§ï¹L¨Ó
+
+ return FULLUPDATE;
+}
+#endif
+
+static int cite_post(int ent, fileheader_t *fhdr, char *direct) {
+ char fpath[256];
+ char title[TTLEN + 1];
+
+ setbfile(fpath, currboard, fhdr->filename);
+ strcpy(title, "¡º ");
+ strncpy(title+3, fhdr->title, TTLEN-3);
+ title[TTLEN] = '\0';
+ a_copyitem(fpath, title, 0, 1);
+ b_man();
+ return FULLUPDATE;
+}
+
+int edit_title(int ent, fileheader_t *fhdr, char *direct) {
+ char genbuf[200];
+ fileheader_t tmpfhdr = *fhdr;
+ int dirty = 0;
+
+ if(currmode & MODE_BOARD || !strcmp(cuser.userid,fhdr->owner)) {
+ if(getdata(b_lines - 1, 0, "¼ÐÃD¡G", genbuf, TTLEN, DOECHO)) {
+ strcpy(tmpfhdr.title, genbuf);
+ dirty++;
+ }
+ }
+
+ if(HAS_PERM(PERM_SYSOP)) {
+ if(getdata(b_lines - 1, 0, "§@ªÌ¡G", genbuf, IDLEN + 2, DOECHO)) {
+ strcpy(tmpfhdr.owner, genbuf);
+ dirty++;
+ }
+
+ if(getdata(b_lines - 1, 0, "¤é´Á¡G", genbuf, 6, DOECHO)) {
+ sprintf(tmpfhdr.date, "%.5s", genbuf);
+ dirty++;
+ }
+ }
+
+ if(currmode & MODE_BOARD || !strcmp(cuser.userid,fhdr->owner)) {
+ getdata(b_lines-1, 0, "½T©w(Y/N)?[n] ", genbuf, 3, DOECHO);
+ if((genbuf[0] == 'y' || genbuf[0] == 'Y') && dirty) {
+ *fhdr = tmpfhdr;
+ substitute_record(direct, fhdr, sizeof(*fhdr), ent);
+/* rocker.011018: ³o¸ÌÀ³¸Ó§ï¦¨¥Îreferenceªº¤è¦¡¨ú±o­ì¨ÓªºÀÉ®× */
+#if 0
+ if((currmode & MODE_SELECT)) {
+ int now;
+
+ setbdir(genbuf, currboard);
+ now = getindex(genbuf, fhdr->filename, sizeof(fileheader_t));
+ substitute_record(genbuf, fhdr, sizeof(*fhdr), now);
+ }
+#else
+ if ((currmode & MODE_SELECT) && (fhdr->money & FHR_REFERENCE))
+ {
+ fileheader_t hdr;
+ int num;
+
+ num = fhdr->money & ~FHR_REFERENCE;
+ setbdir(genbuf, currboard);
+ get_record(genbuf, &hdr, sizeof (hdr), num);
+
+ /* ¦A³o¸Ì­ncheck¤@¤U­ì¨Óªºdir¸Ì­±¬O¤£¬O¦³³Q¤H°Ê¹L... */
+ if (strcmp (hdr.filename, fhdr->filename))
+ num = getindex(genbuf, fhdr->filename, sizeof(fileheader_t));
+
+ substitute_record(genbuf, fhdr, sizeof(*fhdr), num);
+ }
+#endif
+ touchdircache(currbid);
+ }
+ return FULLUPDATE;
+ }
+ return DONOTHING;
+}
+
+extern unsigned int currstat;
+
+static int solve_post(int ent, fileheader_t * fhdr, char *direct){
+ if (HAS_PERM(PERM_SYSOP)) {
+ fhdr->filemode ^= FILE_SOLVED;
+ substitute_record(direct, fhdr, sizeof(*fhdr), ent);
+ touchdircache(currbid);
+ return PART_REDRAW;
+ }
+ return DONOTHING;
+}
+
+static int mark_post(int ent, fileheader_t *fhdr, char *direct) {
+
+ if(!(currmode & MODE_BOARD)) return DONOTHING;
+
+ fhdr->filemode ^= FILE_MARKED;
+ substitute_record(direct, fhdr, sizeof(*fhdr), ent);
+
+ /* rocker.011018: ¦ê±µ¼Ò¦¡¥Îreference¼W¶i®Ä²v */
+ if ((currmode & MODE_SELECT) && (fhdr->money & FHR_REFERENCE))
+ {
+ fileheader_t hdr;
+ char genbuf[100];
+ int num;
+
+ num = fhdr->money & ~FHR_REFERENCE;
+ setbdir(genbuf, currboard);
+ get_record(genbuf, &hdr, sizeof (hdr), num);
+
+ /* ¦A³o¸Ì­ncheck¤@¤U­ì¨Óªºdir¸Ì­±¬O¤£¬O¦³³Q¤H°Ê¹L... */
+ if (strcmp (hdr.filename, fhdr->filename))
+ num = getindex(genbuf, fhdr->filename, sizeof(fileheader_t));
+
+ substitute_record(genbuf, fhdr, sizeof(*fhdr), num);
+ }
+ touchdircache(currbid);
+ return PART_REDRAW;
+}
+
+extern char *msg_sure_ny;
+
+int del_range(int ent, fileheader_t *fhdr, char *direct) {
+ char num1[8], num2[8];
+ int inum1, inum2;
+
+/* rocker.011018: ¦ê±µ¼Ò¦¡¤UÁÙ¬O¤£¤¹³\§R°£¤ñ¸û¦n */
+ if(currmode & MODE_SELECT) {
+ outmsg("½Ð¥ý¦^¨ì¥¿±`¼Ò¦¡«á¦A¶i¦æ§R°£...");
+ refresh();
+ /*safe_sleep(1);*/
+ return FULLUPDATE;
+ }
+
+ if((currstat != READING) || (currmode & MODE_BOARD)) {
+ getdata(1, 0, "[³]©w§R°£½d³ò] °_ÂI¡G", num1, 5, DOECHO);
+ inum1 = atoi(num1);
+ if(inum1 <= 0) {
+ outmsg("°_ÂI¦³»~");
+ refresh();
+ /*safe_sleep(1);*/
+ return FULLUPDATE;
+ }
+ getdata(1, 28, "²×ÂI¡G", num2, 5, DOECHO);
+ inum2 = atoi(num2);
+ if(inum2 < inum1) {
+ outmsg("²×ÂI¦³»~");
+ refresh();
+ /*safe_sleep(1);*/
+ return FULLUPDATE;
+ }
+ getdata(1, 48, msg_sure_ny, num1, 3, LCECHO);
+ if(*num1 == 'y') {
+ outmsg("³B²z¤¤,½Ðµy«á...");
+ refresh();
+ if(currmode & MODE_SELECT) {
+ int fd,size = sizeof(fileheader_t);
+ char genbuf[100];
+ fileheader_t rsfh;
+ int i = inum1,now;
+ if(currstat == RMAIL)
+ sethomedir(genbuf, cuser.userid);
+ else
+ setbdir(genbuf,currboard);
+ if((fd = (open(direct, O_RDONLY, 0))) != -1) {
+ if(lseek(fd, (off_t)(size * (inum1 - 1)), SEEK_SET) !=
+ -1) {
+ while(read(fd,&rsfh,size) == size) {
+ if(i > inum2)
+ break;
+ now = getindex(genbuf, rsfh.filename, size);
+ strcpy(currfile, rsfh.filename);
+ delete_file(genbuf, sizeof(fileheader_t), now,
+ cmpfilename);
+ i++;
+ }
+ }
+ close(fd);
+ }
+ }
+
+ delete_range(direct, inum1, inum2);
+ fixkeep(direct, inum1);
+
+ if(currmode & MODE_BOARD)
+ setbtotal(currbid);
+
+ return DIRCHANGED;
+ }
+ return FULLUPDATE;
+ }
+ return DONOTHING;
+}
+
+extern char *msg_del_ny;
+extern char *msg_del_ok;
+
+static int del_post(int ent, fileheader_t *fhdr, char *direct) {
+ char genbuf[100];
+ int not_owned;
+ boardheader_t *bp;
+
+ bp = getbcache(currbid);
+
+ if((fhdr->filemode & FILE_MARKED) || (fhdr->filemode & FILE_DIGEST) ||
+ (fhdr->owner[0] == '-'))
+ return DONOTHING;
+
+ not_owned = strcmp(fhdr->owner, cuser.userid);
+ if((!(currmode & MODE_BOARD) && not_owned) ||
+ ((bp->brdattr & BRD_VOTEBOARD) && !HAS_PERM(PERM_SYSOP)) ||
+ !strcmp(cuser.userid, STR_GUEST))
+ return DONOTHING;
+
+ getdata(1, 0, msg_del_ny, genbuf, 3, LCECHO);
+ if(genbuf[0] == 'y' || genbuf[0] == 'Y') {
+ strcpy(currfile, fhdr->filename);
+
+ setbfile(genbuf,currboard,fhdr->filename);
+ if(!delete_file (direct, sizeof(fileheader_t), ent, cmpfilename)) {
+
+ if(currmode & MODE_SELECT)
+ {
+ /* rocker.011018: §Q¥Îreference´î§Cloading */
+ fileheader_t hdr;
+ int num;
+
+ num = fhdr->money & ~FHR_REFERENCE;
+ setbdir(genbuf, currboard);
+ get_record(genbuf, &hdr, sizeof (hdr), num);
+
+ /* ¦A³o¸Ì­ncheck¤@¤U­ì¨Óªºdir¸Ì­±¬O¤£¬O¦³³Q¤H°Ê¹L... */
+ if (strcmp (hdr.filename, fhdr->filename))
+ {
+ num=getindex(genbuf,fhdr->filename,sizeof(fileheader_t));
+ get_record(genbuf, &hdr, sizeof (hdr), num);
+ }
+
+ /* rocker.011018: ³o¸Ì­nÁÙ­ì³Q¯}Ãaªºmoney */
+ fhdr->money = hdr.money;
+ delete_file (genbuf, sizeof(fileheader_t), num, cmpfilename);
+ }
+
+#if 0
+ {
+ setbdir(genbuf,currboard);
+ now=getindex(genbuf,fhdr->filename,sizeof(fileheader_t));
+ delete_file (genbuf, sizeof(fileheader_t),now,cmpfilename);
+ }
+#endif
+ cancelpost(fhdr, not_owned);
+
+ setbtotal(currbid);
+ if (fhdr->money < 0)
+ fhdr->money = 0;
+ if (not_owned && strcmp(currboard, "Test")){
+ deumoney(searchuser(fhdr->owner), -fhdr->money);
+ }
+ if(!not_owned && strcmp(currboard, "Test")) {
+ if(cuser.numposts)
+ cuser.numposts--;
+ move(b_lines - 1, 0);
+ clrtoeol();
+ demoney(-fhdr->money);
+ passwd_update(usernum, &cuser); /* post ¼Æ */
+ prints("%s¡A±zªº¤å³¹´î¬° %d ½g¡A¤ä¥I²M¼ä¶O %d »È", msg_del_ok,
+ cuser.numposts,fhdr->money);
+ refresh();
+ pressanykey();
+ }
+ return DIRCHANGED;
+ }
+ }
+ return FULLUPDATE;
+}
+
+static int view_postmoney(int ent, fileheader_t *fhdr, char *direct) {
+ move(b_lines - 1, 0);
+ clrtoeol();
+ prints("³o¤@½g¤å³¹­È %d »È", fhdr->money);
+ refresh();
+ pressanykey();
+ return FULLUPDATE;
+}
+
+#ifdef OUTJOBSPOOL
+/* ¬Ýª©³Æ¥÷ */
+static int tar_addqueue(int ent, fileheader_t *fhdr, char *direct) {
+ char email[60], qfn[80], ans[2];
+ FILE *fp;
+ char bakboard, bakman;
+ clear();
+ showtitle("¬Ýª©³Æ¥÷", BBSNAME);
+ move(2, 0);
+ if( !((currmode & MODE_BOARD) || HAS_PERM(PERM_SYSOP)) ) {
+ move(5, 10);
+ outs("©p­n¬Oª©¥D©Î¬O¯¸ªø¤~¯àÂæÂæ°Ú -.-\"\"");
+ pressanykey();
+ return FULLUPDATE;
+ }
+
+ sprintf(qfn, BBSHOME "/jobspool/tarqueue.%s", currboard);
+ if( access(qfn, 0) == 0 ){
+ outs("¤w¸g±Æ©w¦æµ{, µy«á·|¶i¦æ³Æ¥÷");
+ pressanykey();
+ return FULLUPDATE;
+ }
+ if( !getdata(4, 0, "½Ð¿é¤J¥Øªº«H½c¡G", email, sizeof(email), DOECHO) )
+ return FULLUPDATE;
+
+ /* check email -.-"" */
+ if( strstr(email, "@") == NULL || strstr(email, ".bbs@") != NULL ){
+ move(6, 0);
+ outs("±z«ü©wªº«H½c¤£¥¿½T! ");
+ pressanykey();
+ return FULLUPDATE;
+ }
+
+ getdata(6, 0, "­n³Æ¥÷¬Ýª©¤º®e¶Ü(Y/N)?[Y]", ans, 2, LCECHO);
+ bakboard = (ans[0] == 'n' || ans[0] =='N') ? 0 : 1;
+ getdata(7, 0, "­n³Æ¥÷ºëµØ°Ï¤º®e¶Ü(Y/N)?[N]", ans, 2, LCECHO);
+ bakman = (ans[0] == 'y' || ans[0] =='Y') ? 1 : 0;
+ if( !bakboard && !bakman ){
+ move(8, 0);
+ outs("¥i¬O§Ú­Ì¥u¯à³Æ¥÷¬Ýª©©ÎºëµØ°Ïªº­C ^^\"\"\"");
+ pressanykey();
+ return FULLUPDATE;
+ }
+
+ fp = fopen(qfn, "w");
+ fprintf(fp, "%s\n", cuser.userid);
+ fprintf(fp, "%s\n", email);
+ fprintf(fp, "%d,%d\n", bakboard, bakman);
+ fclose(fp);
+
+ move(10, 0);
+ outs("¨t²Î¤w¸g±N±zªº³Æ¥÷±Æ¤J¦æµ{, \n");
+ outs("µy«á±N·|¦b¨t²Î­t²ü¸û§Cªº®É­Ô±N¸ê®Æ±Hµ¹±z~ :) ");
+ pressanykey();
+ return FULLUPDATE;
+}
+#endif
+
+static int sequent_ent;
+static int continue_flag;
+
+/* ----------------------------------------------------- */
+/* ¨Ì§ÇŪ·s¤å³¹ */
+/* ----------------------------------------------------- */
+static int sequent_messages(fileheader_t *fptr) {
+ static int idc;
+ char genbuf[200];
+
+ if(fptr == NULL)
+ return (idc = 0);
+
+ if(++idc < sequent_ent)
+ return 0;
+
+ if(!brc_unread(fptr->filename,brc_num,brc_list))
+ return 0;
+
+ if(continue_flag)
+ genbuf[0] = 'y';
+ else {
+ prints("Ū¨ú¤å³¹©ó¡G[%s] §@ªÌ¡G[%s]\n¼ÐÃD¡G[%s]",
+ currboard, fptr->owner, fptr->title);
+ getdata(3, 0, "(Y/N/Quit) [Y]: ", genbuf, 3, LCECHO);
+ }
+
+ if(genbuf[0] != 'y' && genbuf[0]) {
+ clear();
+ return (genbuf[0] == 'q' ? QUIT : 0);
+ }
+
+ setbfile(genbuf, currboard, fptr->filename);
+ brc_addlist(fptr->filename);
+
+ if(more(genbuf, YEA) == 0)
+ outmsg("\033[31;47m \033[31m(R)\033[30m¦^«H \033[31m(¡õ,n)"
+ "\033[30m¤U¤@«Ê \033[31m(¡ö,q)\033[30mÂ÷¶} \033[m");
+ continue_flag = 0;
+
+ switch(egetch()) {
+ case KEY_LEFT:
+ case 'e':
+ case 'q':
+ case 'Q':
+ break;
+
+ case 'y':
+ case 'r':
+ case 'Y':
+ case 'R':
+ if(currmode & MODE_POST) {
+ strcpy(quote_file, genbuf);
+ do_reply(fptr);
+ *quote_file = 0;
+ }
+ break;
+
+ case ' ':
+ case KEY_DOWN:
+ case '\n':
+ case 'n':
+ continue_flag = 1;
+ }
+
+ clear();
+ return 0;
+}
+
+static int sequential_read(int ent, fileheader_t *fhdr, char *direct) {
+ char buf[40];
+
+ clear();
+ sequent_messages((fileheader_t *) NULL);
+ sequent_ent = ent;
+ continue_flag = 0;
+ setbdir(buf, currboard);
+ apply_record(buf, sequent_messages, sizeof(fileheader_t));
+ return FULLUPDATE;
+}
+
+extern char *fn_notes;
+extern char *msg_cancel;
+extern char *fn_board;
+
+/* ----------------------------------------------------- */
+/* ¬ÝªO³Æ§Ñ¿ý¡B¤åºK¡BºëµØ°Ï */
+/* ----------------------------------------------------- */
+int b_note_edit_bname(int bid) {
+ char buf[64];
+ int aborted;
+ boardheader_t *fh=getbcache(bid);
+
+ setbfile(buf, fh->brdname, fn_notes);
+ aborted = vedit(buf, NA, NULL);
+ if(aborted == -1) {
+ clear();
+ outs(msg_cancel);
+ pressanykey();
+ } else {
+ aborted = (fh->bupdate - time(0)) / 86400 + 1;
+ sprintf(buf,"%d", aborted > 0 ? aborted : 0);
+ getdata_buf(3, 0, "½Ð³]©w¦³®Ä´Á­­(0 - 9999)¤Ñ¡H", buf, 5, DOECHO);
+ aborted = atoi(buf);
+ fh->bupdate = aborted ? time(0) + aborted * 86400 : 0;
+ substitute_record(fn_board, fh, sizeof(boardheader_t), bid);
+ }
+ return 0;
+}
+
+static int b_notes_edit() {
+ if(currmode & MODE_BOARD) {
+ b_note_edit_bname(currbid);
+ return FULLUPDATE;
+ }
+ return 0;
+}
+
+static int b_water_edit() {
+ if(currmode & MODE_BOARD) {
+ friend_edit(BOARD_WATER);
+ return FULLUPDATE;
+ }
+ return 0;
+}
+
+static int visable_list_edit() {
+ if(currmode & MODE_BOARD) {
+ friend_edit(BOARD_VISABLE);
+ hbflreload(currbid);
+ return FULLUPDATE;
+ }
+ return 0;
+}
+
+static int b_post_note() {
+ char buf[200], yn[3];
+
+ if(currmode & MODE_BOARD) {
+ setbfile(buf, currboard, FN_POST_NOTE );
+ if(more(buf,NA) == -1) more("etc/"FN_POST_NOTE , NA);
+ getdata(b_lines - 2, 0, "¬O§_­n¥Î¦Û­qpostª`·N¨Æ¶µ?", yn, 3, LCECHO);
+ if(yn[0] == 'y')
+ vedit(buf, NA, NULL);
+ else
+ unlink(buf);
+ return FULLUPDATE;
+ }
+ return 0;
+}
+
+static int b_application() {
+ char buf[200];
+
+ if(currmode & MODE_BOARD) {
+ setbfile(buf, currboard, FN_APPLICATION);
+ vedit(buf, NA, NULL);
+ return FULLUPDATE;
+ }
+ return 0;
+}
+
+static int can_vote_edit() {
+ if(currmode & MODE_BOARD) {
+ friend_edit(FRIEND_CANVOTE);
+ return FULLUPDATE;
+ }
+ return 0;
+}
+
+static int bh_title_edit() {
+ boardheader_t *bp;
+
+ if(currmode & MODE_BOARD) {
+ char genbuf[BTLEN];
+
+ bp = getbcache(currbid);
+ move(1,0);
+ clrtoeol();
+ getdata_str(1,0,"½Ð¿é¤J¬ÝªO·s¤¤¤å±Ô­z:", genbuf,BTLEN -
+ 16,DOECHO, bp->title + 7);
+
+ if(!genbuf[0])
+ return 0;
+ strip_ansi( genbuf,genbuf,0);
+ strcpy(bp->title + 7,genbuf);
+ substitute_record(fn_board, bp, sizeof(boardheader_t), currbid);
+ log_usies("SetBoard", currboard);
+ return FULLUPDATE;
+ }
+ return 0;
+}
+
+static int b_notes() {
+ char buf[64];
+
+ setbfile(buf, currboard, fn_notes);
+ if(more(buf, NA) == -1) {
+ clear();
+ move(4, 20);
+ outs("¥»¬ÝªO©|µL¡u³Æ§Ñ¿ý¡v¡C");
+ }
+ pressanykey();
+ return FULLUPDATE;
+}
+
+int board_select() {
+ char fpath[80];
+ char genbuf[100];
+
+ currmode &= ~MODE_SELECT;
+ sprintf(fpath, "SR.%s", cuser.userid);
+ setbfile(genbuf, currboard, fpath);
+ unlink(genbuf);
+ if(currstat == RMAIL)
+ sethomedir(currdirect, cuser.userid);
+ else
+ setbdir(currdirect, currboard);
+ return NEWDIRECT;
+}
+
+int board_digest() {
+ if(currmode & MODE_SELECT)
+ board_select();
+ currmode ^= MODE_DIGEST;
+ if(currmode & MODE_DIGEST)
+ currmode &= ~MODE_POST;
+ else if (haspostperm(currboard))
+ currmode |= MODE_POST;
+
+ setbdir(currdirect, currboard);
+ return NEWDIRECT;
+}
+
+int board_etc() {
+ if(!HAS_PERM(PERM_SYSOP))
+ return DONOTHING;
+ currmode ^= MODE_ETC;
+ if(currmode & MODE_ETC)
+ currmode &= ~MODE_POST;
+ else if(haspostperm(currboard))
+ currmode |= MODE_POST;
+
+ setbdir(currdirect, currboard);
+ return NEWDIRECT;
+}
+
+extern char *fn_mandex;
+
+static int good_post(int ent, fileheader_t *fhdr, char *direct) {
+ char genbuf[200];
+ char genbuf2[200];
+ int delta = 0;
+
+ if((currmode & MODE_DIGEST) || !(currmode & MODE_BOARD))
+ return DONOTHING;
+
+ if(fhdr->filemode & FILE_DIGEST) {
+ fhdr->filemode = (fhdr->filemode & ~FILE_DIGEST);
+ if(!strcmp(currboard,"Note") || !strcmp(currboard,"PttBug") ||
+ !strcmp(currboard,"Artdsn") || !strcmp(currboard, "PttLaw")) {
+ deumoney(searchuser(fhdr->owner),-1000);
+ if(!(currmode & MODE_SELECT))
+ fhdr->money -= 1000;
+ else
+ delta = -1000;
+ }
+ } else {
+ fileheader_t digest;
+ char *ptr, buf[64];
+
+ memcpy(&digest, fhdr, sizeof(digest));
+ digest.filename[0] = 'G';
+ strcpy(buf, direct);
+ ptr = strrchr(buf, '/') + 1;
+ ptr[0] = '\0';
+ sprintf(genbuf, "%s%s", buf, digest.filename);
+
+ if(dashf(genbuf)) unlink (genbuf);
+
+ digest.savemode = digest.filemode = 0;
+ sprintf(genbuf2, "%s%s", buf, fhdr->filename);
+ Link(genbuf2, genbuf);
+ strcpy(ptr, fn_mandex);
+ append_record(buf, &digest, sizeof(digest));
+
+ fhdr->filemode = (fhdr->filemode & ~FILE_MARKED) | FILE_DIGEST;
+ if(!strcmp(currboard, "Note") || !strcmp(currboard, "PttBug") ||
+ !strcmp(currboard,"Artdsn") || !strcmp(currboard, "PttLaw")) {
+ deumoney(searchuser(fhdr->owner), 1000);
+ if(!(currmode & MODE_SELECT)) fhdr->money += 1000;
+ else delta = 1000;
+ }
+ }
+ substitute_record(direct, fhdr, sizeof(*fhdr), ent);
+ touchdircache(currbid);
+/* rocker.011018: ¦ê±µ¼Ò¦¡¥Îreference¼W¶i®Ä²v */
+ if ((currmode & MODE_SELECT) && (fhdr->money & FHR_REFERENCE))
+ {
+ fileheader_t hdr;
+ char genbuf[100];
+ int num;
+
+ num = fhdr->money & ~FHR_REFERENCE;
+ setbdir(genbuf, currboard);
+ get_record(genbuf, &hdr, sizeof (hdr), num);
+
+ /* ¦A³o¸Ì­ncheck¤@¤U­ì¨Óªºdir¸Ì­±¬O¤£¬O¦³³Q¤H°Ê¹L... */
+ if (strcmp (hdr.filename, fhdr->filename))
+ {
+ num = getindex(genbuf, fhdr->filename, sizeof(fileheader_t));
+ get_record(genbuf, &hdr, sizeof (hdr), num);
+ }
+ fhdr->money = hdr.money + delta;
+
+ substitute_record(genbuf, fhdr, sizeof(*fhdr), num);
+ }
+#if 0
+ if(currmode & MODE_SELECT) {
+ int now;
+ char genbuf[100];
+
+ setbdir(genbuf, currboard);
+ now=getindex(genbuf, fhdr->filename, sizeof(fileheader_t));
+ substitute_record(genbuf, fhdr, sizeof(*fhdr), now);
+ }
+#endif
+ return PART_REDRAW;
+}
+
+/* help for board reading */
+static char *board_help[] = {
+ "\0¥þ¥\\¯à¬ÝªO¾Þ§@»¡©ú",
+ "\01°ò¥»©R¥O",
+ "(p)(¡ô) ¤W²¾¤@½g¤å³¹ (^P) µoªí¤å³¹",
+ "(n)(¡õ) ¤U²¾¤@½g¤å³¹ (d) §R°£¤å³¹",
+ "(P)(PgUp) ¤W²¾¤@­¶ (S) ¦ê³s¬ÛÃö¤å³¹",
+ "(N)(PgDn) ¤U²¾¤@­¶ (##) ¸õ¨ì ## ¸¹¤å³¹",
+ "(r)(¡÷) ¾\\Ū¦¹½g¤å³¹ ($) ¸õ¨ì³Ì«á¤@½g¤å³¹",
+ "\01¶i¶¥©R¥O",
+ "(tab)/z ¤åºK¼Ò¦¡/ºëµØ°Ï (a)(A) §ä´M§@ªÌ",
+ "(b/f) ®iŪ³Æ§Ñ¿ý/°Ñ»P½ä½L (?)(/) §ä´M¼ÐÃD",
+ "(V/R) §ë²¼/¬d¸ß§ë²¼µ²ªG (^W) §Ú¦b­þ¸Ì¥i¬Ý¨ì¬ÝªOªº¤ÀÃþ",
+ "(x) Âà¿ý¤å³¹¨ì¨ä¥L¬ÝªO (=)/([]<>-+) §ä´M­º½g¤å³¹/¥DÃD¦¡¾\\Ū",
+#ifdef INTERNET_EMAIL
+ "(F) ¤å³¹±H¦^Internet¶l½c (U) ±N¤å³¹ uuencode «á±H¦^¶l½c",
+#endif
+ "(E) ­«½s¤å³¹ (^H) ¦C¥X©Ò¦³ªº New Post(s)",
+ "\01ªO¥D©R¥O",
+ "(G) Á|¿ì½ä½L/°±¤î¤Uª`/¶}¼ú(W/w/v) ½s¿è³Æ§Ñ¿ý/¤ô±í¦W³æ/¥i¬Ý¨£¦W³æ",
+ "(M/o) Á|¦æ§ë²¼/½s¨p§ë²¼¦W³æ (m/c/g) «O¯d¤å³¹/¿ï¿ýºëµØ/¤åºK",
+ "(D) §R°£¤@¬q½d³òªº¤å³¹ (T/B) ­«½s¤å³¹¼ÐÃD/­«½s¬Ýª©¼ÐÃD",
+ "(i) ½s¿è¥Ó½Ð¤J·|ªí®æ (t/^D) ¼Ð°O¤å³¹/¬å°£¼Ð°Oªº¤å³¹",
+ "(O) ½s¿èPostª`·N¨Æ¶µ (H) ¬ÝªOÁôÂÃ/²{¨­",
+ NULL
+};
+
+static int b_help() {
+ show_help(board_help);
+ return FULLUPDATE;
+}
+
+/* ----------------------------------------------------- */
+/* ªO¥D³]©wÁô§Î/ ¸ÑÁô§Î */
+/* ----------------------------------------------------- */
+char board_hidden_status;
+#ifdef BMCHS
+extern char *fn_board;
+static int change_hidden(int ent, fileheader_t *fhdr, char *direct)
+{
+ boardheader_t bh;
+ int bid;
+ char ans[4];
+
+ if( !((currmode & MODE_BOARD) || HAS_PERM(PERM_SYSOP)) ||
+ currboard[0] == 0 ||
+ (bid = getbnum(currboard)) < 0 ||
+ get_record(fn_board, &bh, sizeof(bh), bid) == -1 )
+ return DONOTHING;
+
+ if( ((bh.brdattr & BRD_HIDE) && (bh.brdattr & BRD_POSTMASK)) ){
+ getdata(1, 0, "¥Ø«eªO¦bÁô§Îª¬ºA, ­n¸ÑÁô§Î¹À(Y/N)?[N]", ans, 2, LCECHO);
+ if( ans[0] != 'y' && ans[0] != 'Y' )
+ return FULLUPDATE;
+ getdata(2, 0, "¦A½T»{¤@¦¸, ¯uªº­n§âªOªO¤½¶}¹À @____@(Y/N)?[N]",
+ ans, 2, LCECHO);
+ if( ans[0] != 'y' && ans[0] != 'Y' )
+ return FULLUPDATE;
+ if( bh.brdattr & BRD_HIDE ) bh.brdattr -= BRD_HIDE;
+ if( bh.brdattr & BRD_POSTMASK ) bh.brdattr -= BRD_POSTMASK;
+ log_usies("OpenBoard", bh.brdname);
+ outs("§g¤ß¤µ¶Ç²³¤H¡AµL³B¤£»D©¶ºq¡C\n");
+ board_hidden_status = 0;
+ hbflreload(bid);
+ }
+ else{
+ getdata(1, 0, "¥Ø«eªO¦b²{§Îª¬ºA, ­nÁô§Î¹À(Y/N)?[N]", ans, 2, LCECHO);
+ if( ans[0] != 'y' && ans[0] != 'Y' )
+ return FULLUPDATE;
+ bh.brdattr |= BRD_HIDE;
+ bh.brdattr |= BRD_POSTMASK;
+ log_usies("CloseBoard", bh.brdname);
+ outs("§g¤ß¤µ¤w±»§í¡A±©¬ßµ½¦Û¬Ã­«¡C\n");
+ board_hidden_status = 1;
+ }
+ setup_man(&bh);
+ substitute_record(fn_board, &bh, sizeof(bh), bid);
+ reset_board(bid);
+ log_usies("SetBoard", bh.brdname);
+ pressanykey();
+ return FULLUPDATE;
+}
+#endif
+
+/* ----------------------------------------------------- */
+/* ¬ÝªO¥\¯àªí */
+/* ----------------------------------------------------- */
+struct onekey_t read_comms[] = {
+ {KEY_TAB, board_digest},
+ {'C', board_etc},
+ {'b', b_notes},
+ {'c', cite_post},
+ {'r', read_post},
+ {'z', b_man},
+ {'D', del_range},
+ {'S', sequential_read},
+ {'E', edit_post},
+ {'T', edit_title},
+ {'s', do_select},
+ {'R', b_results},
+ {'V', b_vote},
+ {'M', b_vote_maintain},
+ {'B', bh_title_edit},
+ {'W', b_notes_edit},
+ {'O', b_post_note},
+ {'w', b_water_edit},
+ {'v', visable_list_edit},
+ {'i', b_application},
+ {'o', can_vote_edit},
+ {'x', cross_post},
+ {'h', b_help},
+#ifndef NO_GAMBLE
+ {'f', join_gamble},
+ {'G', hold_gamble},
+#endif
+ {'g', good_post},
+ {'y', reply_post},
+ {'d', del_post},
+ {'m', mark_post},
+ {'L', solve_post},
+ {Ctrl('P'), do_post},
+ {Ctrl('W'), whereami},
+ {'Q', view_postmoney},
+#ifdef OUTJOBSPOOL
+ {'u', tar_addqueue},
+#endif
+#ifdef BMCHS
+ {'H', change_hidden},
+#endif
+ {'\0', NULL}
+};
+
+time_t board_visit_time;
+
+int Read() {
+ int mode0 = currutmp->mode;
+ int stat0 = currstat, tmpbid=currutmp->brc_id;
+ char buf[40];
+#ifdef LOG_BOARD
+ time_t usetime = time(0);
+#endif
+
+ setutmpmode(READING);
+ set_board();
+
+ if(board_visit_time < board_note_time) {
+ setbfile(buf, currboard, fn_notes);
+ more(buf, NA);
+ pressanykey();
+ }
+ currutmp->brc_id = currbid;
+ setbdir(buf, currboard);
+ curredit &= ~EDIT_MAIL;
+ i_read(READING, buf, readtitle, readdoent, read_comms,
+ currbid);
+#ifdef LOG_BOARD
+ log_board(currboard, time(0) - usetime);
+#endif
+ brc_update();
+
+ currutmp->brc_id =tmpbid;
+ currutmp->mode = mode0;
+ currstat = stat0;
+ return 0;
+}
+
+void ReadSelect() {
+ int mode0 = currutmp->mode;
+ int stat0 = currstat;
+ char genbuf[200];
+
+ currstat = XMODE;
+ if(do_select(0, 0, genbuf) == NEWDIRECT)
+ Read();
+ currutmp->brc_id=0;
+ currutmp->mode = mode0;
+ currstat = stat0;
+}
+
+#ifdef LOG_BOARD
+static void log_board(char *mode, time_t usetime) {
+ time_t now;
+ char buf[ 256 ];
+
+ if(usetime > 30) {
+ now = time(0);
+ sprintf(buf, "USE %-20.20s Stay: %5ld (%s) %s",
+ mode, usetime ,cuser.userid ,ctime(&now));
+ log_file(FN_USEBOARD,buf);
+ }
+}
+#endif
+
+int Select() {
+ char genbuf[200];
+
+ setutmpmode(SELECT);
+ do_select(0, NULL, genbuf);
+ return 0;
+}
diff --git a/mbbsd/board.c b/mbbsd/board.c
new file mode 100644
index 00000000..44b4b842
--- /dev/null
+++ b/mbbsd/board.c
@@ -0,0 +1,1098 @@
+/* $Id: board.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "perm.h"
+#include "modes.h"
+#include "common.h"
+#include "proto.h"
+
+#define BRC_STRLEN 15 /* Length of board name */
+#define BRC_MAXSIZE 24576
+#define BRC_ITEMSIZE (BRC_STRLEN + 1 + BRC_MAXNUM * sizeof( int ))
+#define BRC_MAXNUM 80
+
+extern userinfo_t *currutmp;
+static char *brc_getrecord(char *ptr, char *name, int *pnum, int *list) {
+ int num;
+ char *tmp;
+
+ strncpy(name, ptr, BRC_STRLEN);
+ ptr += BRC_STRLEN;
+ num = (*ptr++) & 0xff;
+ tmp = ptr + num * sizeof(int);
+ if (num > BRC_MAXNUM)
+ num = BRC_MAXNUM;
+ *pnum = num;
+ memcpy(list, ptr, num * sizeof(int));
+ return tmp;
+}
+
+static time_t brc_expire_time;
+
+static char *brc_putrecord(char *ptr, char *name, int num, int *list) {
+ if(num > 0 && list[0] > brc_expire_time) {
+ if (num > BRC_MAXNUM)
+ num = BRC_MAXNUM;
+
+ while(num > 1 && list[num - 1] < brc_expire_time)
+ num--;
+
+ strncpy(ptr, name, BRC_STRLEN);
+ ptr += BRC_STRLEN;
+ *ptr++ = num;
+ memcpy(ptr, list, num * sizeof(int));
+ ptr += num * sizeof(int);
+ }
+ return ptr;
+}
+
+extern userec_t cuser;
+extern char currboard[]; /* name of currently selected board */
+static int brc_changed = 0;
+static char brc_buf[BRC_MAXSIZE];
+int brc_num;
+static char brc_name[BRC_STRLEN];
+int brc_list[BRC_MAXNUM];
+static char *fn_boardrc = ".boardrc";
+static int brc_size;
+
+void brc_update() {
+ if(brc_changed && cuser.userlevel) {
+ char dirfile[STRLEN], *ptr;
+ char tmp_buf[BRC_MAXSIZE - BRC_ITEMSIZE], *tmp;
+ char tmp_name[BRC_STRLEN];
+ int tmp_list[BRC_MAXNUM], tmp_num;
+ int fd, tmp_size;
+
+ ptr = brc_buf;
+ if(brc_num > 0)
+ ptr = brc_putrecord(ptr, brc_name, brc_num, brc_list);
+
+ setuserfile(dirfile, fn_boardrc);
+ if((fd = open(dirfile, O_RDONLY)) != -1) {
+ tmp_size = read(fd, tmp_buf, sizeof(tmp_buf));
+ close(fd);
+ } else {
+ tmp_size = 0;
+ }
+
+ tmp = tmp_buf;
+ while(tmp < &tmp_buf[tmp_size] && (*tmp >= ' ' && *tmp <= 'z')) {
+ tmp = brc_getrecord(tmp, tmp_name, &tmp_num, tmp_list);
+ if(strncmp(tmp_name, currboard, BRC_STRLEN))
+ ptr = brc_putrecord(ptr, tmp_name, tmp_num, tmp_list);
+ }
+ brc_size = (int)(ptr - brc_buf);
+
+ if((fd = open(dirfile, O_WRONLY | O_CREAT, 0644)) != -1) {
+ ftruncate(fd, 0);
+ write(fd, brc_buf, brc_size);
+ close(fd);
+ }
+ brc_changed = 0;
+ }
+}
+
+static void read_brc_buf() {
+ char dirfile[STRLEN];
+ int fd;
+
+ if(brc_buf[0] == '\0') {
+ setuserfile(dirfile, fn_boardrc);
+ if((fd = open(dirfile, O_RDONLY)) != -1) {
+ brc_size = read(fd, brc_buf, sizeof(brc_buf));
+ close(fd);
+ } else {
+ brc_size = 0;
+ }
+ }
+}
+
+extern int currbid;
+extern unsigned int currbrdattr;
+extern boardheader_t *bcache;
+
+int brc_initial(char *boardname) {
+ char *ptr;
+ if(strcmp(currboard, boardname) == 0) {
+ return brc_num;
+ }
+ brc_update();
+ strcpy(currboard, boardname);
+ currbid = getbnum(currboard);
+ currbrdattr = bcache[currbid - 1].brdattr;
+ read_brc_buf();
+
+ ptr = brc_buf;
+ while(ptr < &brc_buf[brc_size] && (*ptr >= ' ' && *ptr <= 'z')) {
+ ptr = brc_getrecord(ptr, brc_name, &brc_num, brc_list);
+ if (strncmp(brc_name, currboard, BRC_STRLEN) == 0)
+ return brc_num;
+ }
+ strncpy(brc_name, boardname, BRC_STRLEN);
+ brc_num = brc_list[0] = 1;
+ return 0;
+}
+
+void brc_addlist(char *fname) {
+ int ftime, n, i;
+
+ if(!cuser.userlevel)
+ return;
+
+ ftime = atoi(&fname[2]);
+ if(ftime <= brc_expire_time
+ /* || fname[0] != 'M' || fname[1] != '.' */ ) {
+ return;
+ }
+ if(brc_num <= 0) {
+ brc_list[brc_num++] = ftime;
+ brc_changed = 1;
+ return;
+ }
+ if((brc_num == 1) && (ftime < brc_list[0]))
+ return;
+ for(n = 0; n < brc_num; n++) {
+ if(ftime == brc_list[n]) {
+ return;
+ } else if(ftime > brc_list[n]) {
+ if(brc_num < BRC_MAXNUM)
+ brc_num++;
+ for(i = brc_num - 1; --i >= n; brc_list[i + 1] = brc_list[i]);
+ brc_list[n] = ftime;
+ brc_changed = 1;
+ return;
+ }
+ }
+ if(brc_num < BRC_MAXNUM) {
+ brc_list[brc_num++] = ftime;
+ brc_changed = 1;
+ }
+}
+
+static int brc_unread_time(time_t ftime, int bnum, int *blist) {
+ int n;
+
+ if(ftime <= brc_expire_time )
+ return 0;
+
+ if(brc_num <= 0)
+ return 1;
+ for(n = 0; n < bnum; n++) {
+ if(ftime > blist[n])
+ return 1;
+ else if(ftime == blist[n])
+ return 0;
+ }
+ return 0;
+}
+
+int brc_unread(char *fname, int bnum, int *blist) {
+ int ftime, n;
+
+ ftime = atoi(&fname[2]);
+
+ if(ftime <= brc_expire_time )
+ return 0;
+
+ if(brc_num <= 0)
+ return 1;
+ for(n = 0; n < bnum; n++) {
+ if(ftime > blist[n])
+ return 1;
+ else if(ftime == blist[n])
+ return 0;
+ }
+ return 0;
+}
+
+#define BRD_UNREAD 1
+#define BRD_FAV 2
+#define BRD_ZAP 4
+#define BRD_TAG 8
+
+typedef struct {
+ int bid, *total;
+ time_t *lastposttime;
+ boardheader_t *bh;
+ unsigned int myattr;
+} boardstat_t;
+
+extern time_t login_start_time;
+extern int numboards;
+static int *zapbuf=NULL,*favbuf;
+static boardstat_t *nbrd;
+
+#define STR_BBSRC ".bbsrc"
+#define STR_FAV ".fav"
+
+void init_brdbuf() {
+ register int n, size;
+ char fname[60];
+
+ /* MAXBOARDS ==> ¦Ü¦h¬Ý±o¨£ 4 ­Ó·sªO */
+ n = numboards + 4;
+ size = n * sizeof(int);
+ zapbuf = (int *) malloc(size);
+ favbuf = (int *) malloc(size);
+
+ memset(favbuf,0,size);
+
+ while(n)
+ zapbuf[--n] = login_start_time;
+ setuserfile(fname, STR_BBSRC);
+ if((n = open(fname, O_RDONLY, 0600)) != -1) {
+ read(n, zapbuf, size);
+ close(n);
+ }
+ setuserfile(fname, STR_FAV);
+ if((n = open(fname, O_RDONLY, 0600)) != -1) {
+ read(n, favbuf, size);
+ close(n);
+ }
+
+ if(!nbrd)
+ nbrd = (boardstat_t *)malloc(MAX_BOARD * sizeof(boardstat_t));
+ brc_expire_time = login_start_time - 365 * 86400;
+}
+
+void save_brdbuf() {
+ int fd, size;
+ char fname[60];
+
+ if(!zapbuf) return;
+ setuserfile(fname, STR_BBSRC);
+ if((fd = open(fname, O_WRONLY | O_CREAT, 0600)) != -1) {
+ size = numboards * sizeof(int);
+ write(fd, zapbuf, size);
+ close(fd);
+ }
+ setuserfile(fname, STR_FAV);
+ if((fd = open(fname, O_WRONLY | O_CREAT, 0600)) != -1) {
+ size = numboards * sizeof(int);
+ write(fd, favbuf, size);
+ close(fd);
+ }
+}
+
+extern char *fn_visable;
+
+int Ben_Perm(boardheader_t *bptr) {
+ register int level,brdattr;
+ register char *ptr;
+
+ level = bptr->level;
+ brdattr = bptr->brdattr;
+
+ if(HAS_PERM(PERM_SYSOP))
+ return 1;
+
+ ptr = bptr->BM;
+ if(is_BM(ptr))
+ return 1;
+
+ /* ¯¦±K¬ÝªO¡G®Ö¹ï­º®uªO¥Dªº¦n¤Í¦W³æ */
+
+ if(brdattr & BRD_HIDE) { /* ÁôÂÃ */
+ if( hbflcheck((int)(bptr-bcache) + 1, currutmp->uid) ){
+ if(brdattr & BRD_POSTMASK)
+ return 0;
+ else
+ return 2;
+ } else
+ return 1;
+ }
+ /* ­­¨î¾\ŪÅv­­ */
+ if(level && !(brdattr & BRD_POSTMASK) && !HAS_PERM(level))
+ return 0;
+
+ return 1;
+}
+
+extern char currauthor[];
+extern int b_lines;
+extern char currowner[];
+
+static int have_author(char* brdname) {
+ char dirname[100];
+
+ sprintf(dirname, "¥¿¦b·j´M§@ªÌ%s ¬ÝªO:%s.....",
+ currauthor,brdname);
+ move(b_lines, 0);
+ clrtoeol();
+ outs(dirname);
+ refresh();
+
+ setbdir(dirname, brdname);
+ str_lower(currowner, currauthor);
+
+ return search_rec(dirname, cmpfowner);
+}
+
+static int check_newpost(boardstat_t *ptr) { /* Ptt §ï */
+ int tbrc_list[BRC_MAXNUM], tbrc_num;
+ char bname[BRC_STRLEN];
+ char *po;
+ time_t ftime;
+
+ ptr->myattr &= ~BRD_UNREAD;
+ if(ptr->bh->brdattr & BRD_GROUPBOARD)
+ return 0;
+
+ if(*(ptr->total) == 0)
+ setbtotal(ptr->bid);
+ if(*(ptr->total) == 0) return 0;
+ ftime = *(ptr->lastposttime);
+ read_brc_buf();
+ po = brc_buf;
+ while(po < &brc_buf[brc_size] && (*po >= ' ' && *po <= 'z')) {
+ po = brc_getrecord(po, bname, &tbrc_num, tbrc_list);
+ if(strncmp(bname, ptr->bh->brdname, BRC_STRLEN) == 0) {
+ if(brc_unread_time(ftime,tbrc_num,tbrc_list)) {
+ ptr->myattr |= BRD_UNREAD;
+ }
+ return 1;
+ }
+ }
+
+ ptr->myattr |= BRD_UNREAD;
+ return 1;
+}
+
+extern int currmode;
+extern struct bcache_t *brdshm;
+static int brdnum;
+int class_bid = 0;
+static int yank_flag = 1;
+static void load_uidofgid(const int gid, const int type){
+ boardheader_t *bptr,*currbptr;
+ int n;
+ currbptr = &bcache[gid-1];
+ for(n=0;n<numboards;n++)
+ {
+ bptr = brdshm->sorted[type][n];
+ if(bptr->brdname[0]=='\0') continue;
+ if(bptr->gid == gid)
+ {
+ if(currbptr == &bcache[gid-1])
+ currbptr->firstchild[type]=bptr;
+ else
+ {
+ currbptr->next[type]=bptr;
+ currbptr->parent=&bcache[gid-1];
+ }
+ currbptr=bptr;
+ }
+ }
+ if(currbptr == &bcache[gid-1])
+ currbptr->firstchild[type]=(boardheader_t *) ~0;
+ else
+ currbptr->next[type]=(boardheader_t *) ~0;
+}
+static boardstat_t * addnewbrdstat(int n, int state)
+{
+ boardstat_t *ptr=&nbrd[brdnum++];
+ boardheader_t *bptr = &bcache[n];
+ ptr->total = &(brdshm->total[n]);
+ ptr->lastposttime = &(brdshm->lastposttime[n]);
+ ptr->bid = n+1;
+ ptr->myattr=0;
+ ptr->myattr=(favbuf[n]&~BRD_ZAP);
+ if(zapbuf[n] == 0)
+ ptr->myattr|=BRD_ZAP;
+ ptr->bh = bptr;
+ if((bptr->brdattr & BRD_HIDE) && state == 1)
+ bptr->brdattr |= BRD_POSTMASK;
+ check_newpost(ptr);
+ return ptr;
+}
+
+static void load_boards(char *key) {
+ boardheader_t *bptr = NULL;
+ int type=cuser.uflag & BRDSORT_FLAG?1:0;
+ register int i,n;
+ register int state ;
+
+ if(class_bid>0)
+ {
+ bptr = &bcache[class_bid-1];
+ if(bptr->firstchild[type]==NULL)
+ load_uidofgid(class_bid,type);
+ }
+ brdnum = 0;
+ if(class_bid==0)
+ for(i=0 ; i < numboards; i++)
+ {
+
+ if( (bptr = brdshm->sorted[type][i]) == NULL )
+ continue;
+ n = (int)( bptr - bcache);
+ if(!bptr->brdname[0] || bptr->brdattr & BRD_GROUPBOARD ||
+ !((state = Ben_Perm(bptr)) || (currmode & MODE_MENU)) ||
+ (yank_flag == 0 && !(favbuf[n]&BRD_FAV)) ||
+ (yank_flag == 1 && !zapbuf[n]) ||
+ (key[0] && !strcasestr(bptr->title, key))
+ ) continue;
+ addnewbrdstat(n, state);
+ }
+ else
+ for(bptr=bptr->firstchild[type]; bptr!=(boardheader_t *)~0;
+ bptr=bptr->next[type])
+ {
+ n = (int)( bptr - bcache);
+ if(!((state = Ben_Perm(bptr)) || (currmode & MODE_MENU))
+ ||(yank_flag == 0 && !(favbuf[n]&BRD_FAV))
+ ||(yank_flag == 1 && !zapbuf[n]) ||
+ (key[0] && !strcasestr(bptr->title, key))) continue;
+ addnewbrdstat(n, state);
+ }
+}
+
+static int search_board() {
+ int num;
+ char genbuf[IDLEN + 2];
+ move(0, 0);
+ clrtoeol();
+ CreateNameList();
+ for(num = 0; num < brdnum; num++)
+ AddNameList(nbrd[num].bh->brdname);
+ namecomplete(MSG_SELECT_BOARD, genbuf);
+
+ for (num = 0; num < brdnum; num++)
+ if (!strcasecmp(nbrd[num].bh->brdname, genbuf))
+ return num;
+ return -1;
+}
+
+static int unread_position(char *dirfile, boardstat_t *ptr) {
+ fileheader_t fh;
+ char fname[FNLEN];
+ register int num, fd, step, total;
+
+ total = *(ptr->total);
+ num = total + 1;
+ if((ptr->myattr&BRD_UNREAD) &&(fd = open(dirfile, O_RDWR)) > 0) {
+ if(!brc_initial(ptr->bh->brdname)) {
+ num = 1;
+ } else {
+ num = total - 1;
+ step = 4;
+ while(num > 0) {
+ lseek(fd, (off_t)(num * sizeof(fh)), SEEK_SET);
+ if(read(fd, fname, FNLEN) <= 0 ||
+ !brc_unread(fname,brc_num,brc_list))
+ break;
+ num -= step;
+ if(step < 32)
+ step += step >> 1;
+ }
+ if(num < 0)
+ num = 0;
+ while(num < total) {
+ lseek(fd, (off_t)(num * sizeof(fh)), SEEK_SET);
+ if(read(fd, fname, FNLEN) <= 0 ||
+ brc_unread(fname,brc_num,brc_list))
+ break;
+ num++;
+ }
+ }
+ close(fd);
+ }
+ if(num < 0)
+ num = 0;
+ return num;
+}
+
+static void brdlist_foot() {
+ prints("\033[34;46m ¿ï¾Ü¬ÝªO \033[31;47m (c)\033[30m·s¤å³¹¼Ò¦¡ "
+ "\033[31m(v/V)\033[30m¼Ð°O¤wŪ/¥¼Åª \033[31m(y)\033[30m¿z¿ï%s"
+ " \033[31m(z)\033[30m¤Á´«¿ï¾Ü \033[m",
+ yank_flag==0 ? "³Ì·R" : yank_flag==1 ? "³¡¥÷" : "¥þ³¡");
+}
+
+extern unsigned int currstat;
+extern char *BBSName;
+
+static void show_brdlist(int head, int clsflag, int newflag) {
+ int myrow = 2;
+ if(class_bid == 1) {
+ currstat = CLASS;
+ myrow = 6;
+ showtitle("¤ÀÃþ¬ÝªO", BBSName);
+ movie(0);
+ move(1, 0);
+ prints(
+ " "
+ "¢© ¢~¡X\033[33m¡´\n"
+ " ùá¡X \033[m "
+ "¢¨¢i\033[47m¡ó\033[40m¢i¢i¢©ùç\n");
+ prints(
+ " \033[44m ¡s¡s¡s¡s¡s¡s¡s¡s "
+ "\033[33mùø\033[m\033[44m ¢©¢¨¢i¢i¢i¡¿¡¿¡¿ùø \033[m\n"
+ " \033[44m "
+ "\033[33m \033[m\033[44m ¢«¢ª¢i¢i¢i¡¶¡¶¡¶ ùø\033[m\n"
+ " ¡s¡s¡s¡s¡s¡s¡s¡s \033[33m"
+ "¢x\033[m ¢ª¢i¢i¢i¢i¢« ùø\n"
+ " \033[33mùó"
+ "¡X¡X\033[m ¢« ¡X¡Ï\033[m");
+ } else if (clsflag) {
+ showtitle("¬ÝªO¦Cªí", BBSName);
+ prints("[¡ö]¥D¿ï³æ [¡÷]¾\\Ū [¡ô¡õ]¿ï¾Ü [y]¸ü¤J [S]±Æ§Ç [/]·j´M "
+ "[TAB]¤åºK¡E¬ÝªO [h]¨D§U\n"
+ "\033[7m%-20s Ãþ§O Âà«H%-31s§ë²¼ ªO ¥D \033[m",
+ newflag ? "Á`¼Æ ¥¼Åª ¬Ý ªO" : " ½s¸¹ ¬Ý ªO",
+ " ¤¤ ¤å ±Ô ­z");
+ move(b_lines, 0);
+ brdlist_foot();
+ }
+
+ if(brdnum > 0) {
+ boardstat_t *ptr;
+ static char *color[8]={"","\033[32m",
+ "\033[33m","\033[36m","\033[34m","\033[1m",
+ "\033[1;32m","\033[1;33m"};
+ static char *unread[2]={"\33[37m \033[m","\033[1;31m£¾\033[m"};
+
+ while(++myrow < b_lines) {
+ move(myrow, 0);
+ clrtoeol();
+ if(head < brdnum) {
+ ptr = &nbrd[head++];
+ if(class_bid == 1)
+ prints(" ");
+ if(!newflag) {
+ prints("%5d%c%s", head,
+ !(ptr->bh->brdattr & BRD_HIDE) ? ' ':
+ (ptr->bh->brdattr & BRD_POSTMASK) ? ')' : '-',
+ (ptr->myattr & BRD_TAG) ? "D " :
+ (ptr->myattr & BRD_ZAP) ? "- " :
+ (ptr->bh->brdattr & BRD_GROUPBOARD) ? " " :
+ unread[ptr->myattr&BRD_UNREAD]);
+ } else if(ptr->myattr&BRD_ZAP) {
+ ptr->myattr &= ~BRD_UNREAD;
+ prints(" ¡ß ¡ß");
+ } else {
+ if(newflag) {
+ if((ptr->bh->brdattr & BRD_GROUPBOARD))
+ prints(" ");
+ else
+ prints("%6d%s", (int)(*(ptr->total)),
+ unread[ptr->myattr&BRD_UNREAD]);
+ }
+ }
+ if(class_bid != 1) {
+ prints("%s%-13s\033[m%s%5.5s\033[0;37m%2.2s\033[m"
+ "%-35.35s%c %.13s",
+ (ptr->myattr & BRD_FAV)?"\033[1;36m":"",
+ ptr->bh->brdname,
+ color[(unsigned int)
+ (ptr->bh->title[1] + ptr->bh->title[2] +
+ ptr->bh->title[3] + ptr->bh->title[0]) & 07],
+ ptr->bh->title, ptr->bh->title+5, ptr->bh->title+7,
+ (ptr->bh->brdattr & BRD_BAD) ? 'X' :
+ " ARBCDEFGHI"[ptr->bh->bvote],
+ ptr->bh->BM);
+ refresh();
+ } else {
+ prints("%-40.40s %.13s", ptr->bh->title + 7, ptr->bh->BM);
+ }
+ }
+ clrtoeol();
+ }
+ }
+}
+
+static char *choosebrdhelp[] = {
+ "\0¬ÝªO¿ï³æ»²§U»¡©ú",
+ "\01°ò¥»«ü¥O",
+ "(p)(¡ô)/(n)(¡õ)¤W¤@­Ó¬ÝªO / ¤U¤@­Ó¬ÝªO",
+ "(P)(^B)(PgUp) ¤W¤@­¶¬ÝªO",
+ "(N)(^F)(PgDn) ¤U¤@­¶¬ÝªO",
+ "($)/(s)/(/) ³Ì«á¤@­Ó¬ÝªO / ·j´M¬ÝªO / ¥H¤¤¤å·j´M¬ÝªOÃöÁä¦r",
+ "(¼Æ¦r) ¸õ¦Ü¸Ó¶µ¥Ø",
+ "\01¶i¶¥«ü¥O",
+ "(^W) °g¸ô¤F §Ú¦b­þ¸Ì",
+ "(r)(¡÷)(Rtn) ¶i¤J¦h¥\\¯à¾\\Ū¿ï³æ",
+ "(q)(¡ö) ¦^¨ì¥D¿ï³æ",
+ "(z)(Z) ­q¾\\/¤Ï­q¾\\¬ÝªO ­q¾\\/¤Ï­q¾\\©Ò¦³¬ÝªO",
+ "(y) §Úªº³Ì·R/­q¾\\¬ÝªO/¥X©Ò¦³¬ÝªO",
+ "(v/V) ³q³q¬Ý§¹/¥þ³¡¥¼Åª",
+ "(S) «ö·Ó¦r¥À/¤ÀÃþ±Æ§Ç",
+ "(t/^T/^A/^D) ¼Ð°O¬ÝªO/¨ú®ø©Ò¦³¼Ð°O/¤w¼Ð°Oªº¥[¤J§Úªº³Ì·R/¨ú®ø§Úªº³Ì·R",
+ "(m) §â¬ÝªO¥[¤J§Úªº³Ì·R",
+ "\01¤p²Õªø«ü¥O",
+ "(E/W/B) ³]©w¬ÝªO/³]©w¤p²Õ³Æ§Ñ/¶}·s¬ÝªO",
+ "(^P) ²¾°Ê¤w¼Ð°O¬ÝªO¨ì¦¹¤ÀÃþ",
+ NULL
+};
+
+
+static void set_menu_BM(char *BM) {
+ if(HAS_PERM(PERM_ALLBOARD) || is_BM(BM)) {
+ currmode |= MODE_MENU;
+ cuser.userlevel |= PERM_SYSSUBOP;
+ }
+}
+
+extern int p_lines; /* a Page of Screen line numbers: tlines-4 */
+extern int t_lines;
+extern char *fn_notes;
+static char *privateboard =
+"\n\n\n\n ¹ï¤£°_ ¦¹ªO¥Ø«e¥u­ã¬ÝªO¦n¤Í¶i¤J ½Ð¥ý¦VªO¥D¥Ó½Ð¤J¹Ò³\\¥i";
+static void dozap(int num){
+ boardstat_t *ptr;
+ ptr = &nbrd[num];
+ ptr->myattr ^= BRD_ZAP;
+ if(ptr->bh->brdattr & BRD_NOZAP) ptr->myattr &= ~BRD_ZAP;
+ if(!(ptr->myattr & BRD_ZAP) ) check_newpost(ptr);
+ zapbuf[ptr->bid-1] = (ptr->myattr&BRD_ZAP?0:login_start_time);
+}
+static void choose_board(int newflag) {
+ static int num = 0;
+ boardstat_t *ptr;
+ int head = -1, ch = 0, currmodetmp, tmp,tmp1, bidtmp;
+ char keyword[13]="";
+#if HAVE_SEARCH_ALL
+ char genbuf[200];
+#endif
+ extern time_t board_visit_time;
+
+ setutmpmode(newflag ? READNEW : READBRD);
+ brdnum = 0;
+ if(!cuser.userlevel) /* guest yank all boards */
+ yank_flag = 2;
+
+ do {
+ if(brdnum <= 0) {
+ load_boards(keyword);
+ if(brdnum <= 0) {
+ if(keyword[0]!=0)
+ {
+ mprints(b_lines-1,0,"¨S¦³¥ô¦ó¬ÝªO¼ÐÃD¦³¦¹ÃöÁä¦r "
+ "(ª©¥DÀ³ª`·N¬ÝªO¼ÐÃD©R¦W)");
+ pressanykey();
+ keyword[0]=0;
+ brdnum = -1;
+ continue;
+ }
+ if(yank_flag<2)
+ {
+ brdnum = -1;
+ yank_flag++;
+ continue;
+ }
+ if(HAS_PERM(PERM_SYSOP) || (currmode & MODE_MENU)) {
+ if(m_newbrd(0) == -1)
+ break;
+ brdnum = -1;
+ continue;
+ } else
+ break;
+ }
+ head = -1;
+ }
+
+ if(num < 0)
+ num = 0;
+ else if(num >= brdnum)
+ num = brdnum - 1;
+
+ if(head < 0) {
+ if(newflag) {
+ tmp = num;
+ while(num < brdnum) {
+ ptr = &nbrd[num];
+ if(ptr->myattr&BRD_UNREAD)
+ break;
+ num++;
+ }
+ if(num >= brdnum)
+ num = tmp;
+ }
+ head = (num / p_lines) * p_lines;
+ show_brdlist(head, 1, newflag);
+ } else if(num < head || num >= head + p_lines) {
+ head = (num / p_lines) * p_lines;
+ show_brdlist(head, 0, newflag);
+ }
+ if(class_bid == 1)
+ ch = cursor_key(7 + num - head, 10);
+ else
+ ch = cursor_key(3 + num - head, 0);
+
+ switch(ch) {
+ case Ctrl('W'):
+ whereami(0,NULL,NULL);
+ head=-1;
+ break;
+ case 'e':
+ case KEY_LEFT:
+ case EOF:
+ ch = 'q';
+ case 'q':
+ if(keyword[0])
+ {
+ keyword[0]=0;
+ brdnum=-1;
+ ch=' ';
+ }
+ break;
+ case 'c':
+ show_brdlist(head, 1, newflag ^= 1);
+ break;
+ case KEY_PGUP:
+ case 'P':
+ case 'b':
+ case Ctrl('B'):
+ if(num) {
+ num -= p_lines;
+ break;
+ }
+ case KEY_END:
+ case '$':
+ num = brdnum - 1;
+ break;
+ case ' ':
+ case KEY_PGDN:
+ case 'N':
+ case Ctrl('F'):
+ if(num == brdnum - 1)
+ num = 0;
+ else
+ num += p_lines;
+ break;
+ case Ctrl('C'):
+ cal();
+ show_brdlist(head, 1, newflag);
+ break;
+ case Ctrl('I'):
+ t_idle();
+ show_brdlist(head, 1, newflag);
+ break;
+ case KEY_UP:
+ case 'p':
+ case 'k':
+ if (num-- <= 0)
+ num = brdnum - 1;
+ break;
+ case 't':
+ ptr = &nbrd[num];
+ ptr->myattr ^= BRD_TAG;
+ favbuf[ptr->bid-1]=ptr->myattr;
+ head = 9999;
+ case KEY_DOWN:
+ case 'n':
+ case 'j':
+ if (++num < brdnum)
+ break;
+ case '0':
+ case KEY_HOME:
+ num = 0;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if((tmp = search_num(ch, brdnum)) >= 0)
+ num = tmp;
+ brdlist_foot();
+ break;
+ case 'F':
+ case 'f':
+ if(class_bid && HAS_PERM(PERM_SYSOP))
+ {
+ bcache[class_bid-1].firstchild[cuser.uflag&BRDSORT_FLAG?1:0]
+ =NULL;
+ brdnum = -1;
+ }
+ break;
+ case 'h':
+ show_help(choosebrdhelp);
+ show_brdlist(head, 1, newflag);
+ break;
+ case '/':
+ getdata_buf(b_lines-1,0,"½Ð¿é¤J¬ÝªO¤¤¤åÃöÁä¦r:",keyword, 12, DOECHO);
+ brdnum=-1;
+ break;
+ case 'S':
+ cuser.uflag ^= BRDSORT_FLAG;
+ brdnum = -1;
+ break;
+ case 'y':
+ if(class_bid==0)
+ yank_flag = (yank_flag+1)%3;
+ else
+ yank_flag = yank_flag%2+1;
+ brdnum = -1;
+ break;
+ case Ctrl('D'):
+ for(tmp = 0; tmp < numboards; tmp++)
+ {
+ if(favbuf[tmp] & BRD_TAG)
+ {
+ favbuf[tmp] &= ~BRD_FAV;
+ favbuf[tmp] &= ~BRD_TAG;
+ }
+ }
+ brdnum = -1;
+ break;
+ case Ctrl('A'):
+ for(tmp = 0; tmp < numboards; tmp++)
+ {
+ if(favbuf[tmp] & BRD_TAG)
+ {
+ favbuf[tmp] |= BRD_FAV;
+ favbuf[tmp] &= ~BRD_TAG;
+ }
+ }
+ brdnum = -1;
+ break;
+ case Ctrl('T'):
+ for(tmp = 0; tmp < numboards; tmp++)
+ favbuf[tmp] &= ~BRD_TAG;
+ brdnum = -1;
+ break;
+ case Ctrl('P'):
+ if(class_bid!=0 &&
+ (HAS_PERM(PERM_SYSOP) || (currmode & MODE_MENU))) {
+ for(tmp = 0; tmp < numboards; tmp++) {
+ boardheader_t *bh=&bcache[tmp];
+ if(!(favbuf[tmp]&BRD_TAG) || bh->gid==class_bid)
+ continue;
+ favbuf[tmp] &= ~BRD_TAG;
+ if(bh->gid != class_bid)
+ {
+ bh->gid = class_bid;
+ substitute_record(FN_BOARD, bh,
+ sizeof(boardheader_t), tmp+1);
+ reset_board(tmp+1);
+ log_usies("SetBoardGID", bh->brdname);
+ }
+ }
+ brdnum = -1;
+ }
+ break;
+ case 'm':
+ if(HAS_PERM(PERM_BASIC)) {
+ ptr = &nbrd[num];
+ ptr->myattr ^= BRD_FAV;
+ favbuf[ptr->bid-1]=ptr->myattr;
+ head = 9999;
+ }
+ break;
+ case 'z':
+ if(HAS_PERM(PERM_BASIC)) {
+ dozap(num);
+ head = 9999;
+ }
+ break;
+ case 'Z': /* Ptt */
+ if(HAS_PERM(PERM_BASIC)) {
+ for(tmp = 0; tmp < brdnum; tmp++) {
+ dozap(tmp);
+ }
+ head = 9999;
+ }
+ break;
+ case 'v':
+ case 'V':
+ ptr = &nbrd[num];
+ brc_initial(ptr->bh->brdname);
+ if(ch == 'v') {
+ ptr->myattr &= ~BRD_UNREAD;
+ zapbuf[ptr->bid-1] = time((time_t *) &brc_list[0]);
+ } else
+ {
+ zapbuf[ptr->bid-1] = brc_list[0] = 1;
+ ptr->myattr |= BRD_UNREAD;
+ }
+ brc_num = brc_changed = 1;
+ brc_update();
+ show_brdlist(head, 0, newflag);
+ break;
+ case 's':
+ if((tmp = search_board()) == -1) {
+ show_brdlist(head, 1, newflag);
+ break;
+ }
+ num = tmp;
+ case 'E':
+ if(HAS_PERM(PERM_SYSOP) || (currmode & MODE_MENU)) {
+ ptr = &nbrd[num];
+ move(1,1);
+ clrtobot();
+ m_mod_board(ptr->bh->brdname);
+ brdnum = -1;
+ }
+ break;
+ case 'R':
+ if(HAS_PERM(PERM_SYSOP) || (currmode & MODE_MENU)) {
+ m_newbrd(1);
+ brdnum = -1;
+ }
+ break;
+ case 'B':
+ if(HAS_PERM(PERM_SYSOP) || (currmode & MODE_MENU)) {
+ m_newbrd(0);
+ brdnum = -1;
+ }
+ break;
+ case 'W':
+ if(class_bid > 0 &&
+ (HAS_PERM(PERM_SYSOP) || (currmode & MODE_MENU))) {
+ b_note_edit_bname(class_bid);
+ brdnum = -1;
+ }
+ break;
+ case KEY_RIGHT:
+ case '\n':
+ case '\r':
+ case 'r':
+ {
+ char buf[STRLEN];
+
+ ptr = &nbrd[num];
+
+ if(!(ptr->bh->brdattr & BRD_GROUPBOARD)) { /* «Dsub class */
+ if(!(ptr->bh->brdattr & BRD_HIDE) ||
+ (ptr->bh->brdattr & BRD_POSTMASK)) {
+ brc_initial(ptr->bh->brdname);
+
+ if(newflag) {
+ setbdir(buf, currboard);
+ tmp = unread_position(buf, ptr);
+ head = tmp - t_lines / 2;
+ getkeep(buf, head > 1 ? head : 1, tmp + 1);
+ }
+ board_visit_time = zapbuf[ptr->bid-1];
+ if(!(ptr->myattr&BRD_ZAP))
+ time((time_t *) &zapbuf[ptr->bid-1]);
+ Read();
+ check_newpost(ptr);
+ head = -1;
+ setutmpmode(newflag ? READNEW : READBRD);
+ } else {
+ setbfile(buf, ptr->bh->brdname, FN_APPLICATION);
+ if(more(buf,YEA)==-1) {
+ move(1,0);
+ clrtobot();
+ outs(privateboard);
+ pressanykey();
+ }
+ head = -1;
+ }
+ } else { /* sub class */
+ move(12,1);
+ bidtmp = class_bid;
+ currmodetmp =currmode;
+ tmp1=num;
+ num=0;
+ class_bid = ptr->bid;
+ if (!(currmode & MODE_MENU))/*¦pªGÁÙ¨S¦³¤p²ÕªøÅv­­ */
+ set_menu_BM(ptr->bh->BM);
+
+ if(time(NULL) < ptr->bh->bupdate) {
+ setbfile(buf, ptr->bh->brdname, fn_notes);
+ if(more(buf, NA) != -1)
+ pressanykey();
+ }
+ tmp=currutmp->brc_id;
+ currutmp->brc_id=ptr->bid;
+ choose_board(0);
+ currmode = currmodetmp; /* Â÷¶}ª©ª©«á´N§âÅv­­®³±¼³á */
+ num=tmp1;
+ class_bid = bidtmp;
+ currutmp->brc_id=tmp;
+ brdnum = -1;
+ }
+ }
+ }
+ } while(ch != 'q');
+ save_brdbuf();
+}
+
+int root_board() {
+ class_bid = 1;
+ yank_flag = 1;
+ choose_board(0);
+ return 0;
+}
+
+int Boards() {
+ class_bid = 0;
+ yank_flag = 0;
+ choose_board(0);
+ return 0;
+}
+
+
+int New() {
+ int mode0 = currutmp->mode;
+ int stat0 = currstat;
+
+ class_bid = 0;
+ choose_board(1);
+ currutmp->mode = mode0;
+ currstat = stat0;
+ return 0;
+}
+
+/*
+int v_favorite(){
+ char fname[256];
+ char inbuf[2048];
+ FILE* fp;
+ int nGroup;
+ char* strtmp;
+
+ setuserfile(fname,str_favorite);
+
+ if (!(fp=fopen(fname,"r")))
+ return -1;
+ move(0,0);
+ clrtobot();
+ fgets(inbuf,sizeof(inbuf),fp);
+ nGroup=atoi(inbuf);
+
+ currutmp->nGroup=0;
+ currutmp->ninRoot=0;
+
+ while(nGroup!=currutmp->nGroup+1){
+ fgets(inbuf,sizeof(inbuf),fp);
+ prints("%s\n",strtmp=strtok(inbuf," \n"));
+ strcpy(currutmp->gfavorite[currutmp->nGroup++],strtmp);
+ while((strtmp=strtok(NULL, " \n"))){
+ prints(" %s %d\n",strtmp,getbnum(strtmp));
+ }
+ currutmp->nGroup++;
+ }
+ prints("+++%d+++\n",currutmp->nGroup);
+
+ fgets(inbuf,sizeof(inbuf),fp);
+
+ for(strtmp=strtok(inbuf, " \n");strtmp;strtmp=strtok(NULL, " \n")){
+ if (strtmp[0]!='#')
+ prints("*** %s %d\n",strtmp, getbnum(strtmp));
+ else
+ prints("*** %s %d\n",strtmp+1, -1);
+ currutmp->ninRoot++;
+ }
+
+ fclose(fp);
+ pressanykey();
+ return 0;
+}
+*/
diff --git a/mbbsd/cache.c b/mbbsd/cache.c
new file mode 100644
index 00000000..73f8ac5b
--- /dev/null
+++ b/mbbsd/cache.c
@@ -0,0 +1,1053 @@
+/* $Id: cache.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+
+#ifdef __FreeBSD__
+#include <machine/param.h>
+#endif
+
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "perm.h"
+#include "modes.h"
+#include "proto.h"
+
+#ifndef __FreeBSD__
+union semun {
+ int val; /* value for SETVAL */
+ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
+ unsigned short int *array; /* array for GETALL, SETALL */
+ struct seminfo *__buf; /* buffer for IPC_INFO */
+};
+#endif
+
+int fcache_semid;
+
+/* the reason for "safe_sleep" is that we may call sleep during
+ SIGALRM handler routine, while SIGALRM is blocked.
+ if we use the original sleep, we'll never wake up. */
+unsigned int safe_sleep(unsigned int seconds) {
+ /* jochang sleep¦³°ÝÃD®É¥Î*/
+ sigset_t set,oldset;
+
+ sigemptyset(&set);
+ sigprocmask(SIG_BLOCK, &set, &oldset);
+ if(sigismember(&oldset, SIGALRM)) {
+ unsigned long retv;
+#if !defined(_BBS_UTIL_C_)
+ log_usies("SAFE_SLEEP ", "avoid hang");
+#endif
+ sigemptyset(&set);
+ sigaddset(&set,SIGALRM);
+ sigprocmask(SIG_UNBLOCK,&set,NULL);
+ retv=sleep(seconds);
+ sigprocmask(SIG_BLOCK,&set,NULL);
+ return retv;
+ }
+ return sleep(seconds);
+}
+
+#if defined(_BBS_UTIL_C_)
+static void setapath(char *buf, char *boardname) {
+ sprintf(buf, "man/boards/%s", boardname);
+}
+
+static char *str_dotdir = ".DIR";
+
+static void setadir(char *buf, char *path) {
+ sprintf(buf, "%s/%s", path, str_dotdir);
+}
+#endif
+
+static void attach_err(int shmkey, char *name) {
+ fprintf(stderr, "[%s error] key = %x\n", name, shmkey);
+ fprintf(stderr, "errno = %d: %s\n", errno, strerror(errno));
+ exit(1);
+}
+
+static void *attach_shm(int shmkey, int shmsize) {
+ void *shmptr;
+ int shmid;
+
+ char *empty_addr;
+ /* set up one page in-accessible -- jochang */
+ {
+ int fd = open("/dev/zero",O_RDONLY);
+ int size = ((shmsize + 4095) / 4096) * 4096;
+
+ munmap(
+ (empty_addr=mmap(0,4096+size,PROT_NONE,MAP_PRIVATE,fd,0))+4096
+ ,size);
+
+ close(fd);
+ }
+
+ shmid = shmget(shmkey, shmsize, 0);
+ if(shmid < 0) {
+ shmid = shmget(shmkey, shmsize, IPC_CREAT | 0600);
+ if(shmid < 0)
+ attach_err(shmkey, "shmget");
+ shmptr = (void *)shmat(shmid, NULL, 0);
+ if(shmptr == (void *)-1)
+ attach_err(shmkey, "shmat");
+ } else {
+ shmptr = (void *)shmat(shmid, NULL, 0);
+ if(shmptr == (void *)-1)
+ attach_err(shmkey, "shmat");
+ }
+
+ /* unmap the page -- jochang */
+ {
+ munmap(empty_addr,4096);
+ }
+ return shmptr;
+}
+
+
+#define SEM_FLG 0600 /* semaphore mode */
+
+/* ----------------------------------------------------- */
+/* semaphore : for critical section */
+/* ----------------------------------------------------- */
+void sem_init(int semkey,int *semid) {
+ union semun s;
+
+ s.val=1;
+ *semid = semget(semkey, 1, 0);
+ if(*semid == -1) {
+ *semid = semget(semkey, 1, IPC_CREAT | SEM_FLG);
+ if(*semid == -1)
+ attach_err(semkey, "semget");
+ semctl(*semid, 0, SETVAL, s);
+ }
+}
+
+void sem_lock(int op,int semid) {
+ struct sembuf sops;
+
+ sops.sem_num = 0;
+ sops.sem_flg = SEM_UNDO;
+ sops.sem_op = op;
+ semop(semid, &sops, 1);
+}
+
+/* uhash *******************************************/
+/* the design is this:
+ we use another stand-alone program to create and load data into the hash.
+ (that program could be run in rc-scripts or something like that)
+ after loading completes, the stand-alone program sets loaded to 1 and exits.
+
+ the bbs exits if it can't attach to the shared memory or
+ the hash is not loaded yet.
+*/
+uhash_t *uhash;
+
+/* attach_uhash should be called before using uhash */
+void attach_uhash() {
+ uhash = attach_shm(UHASH_KEY, sizeof(*uhash));
+ if(!uhash->loaded) /* assume fresh shared memory is zeroed */
+ exit(1);
+}
+
+void add_to_uhash(int n, char *id) {
+ int *p, h = StringHash(id);
+ strcpy(uhash->userid[n], id);
+
+ p = &(uhash->hash_head[h]);
+
+ while(*p != -1)
+ p = &(uhash->next_in_hash[*p]);
+
+ uhash->next_in_hash[*p = n] = -1;
+}
+
+/* note: after remove_from_uhash(), you should add_to_uhash()
+ (likely with a different name) */
+void remove_from_uhash(int n) {
+ int h = StringHash(uhash->userid[n]);
+ int *p = &(uhash->hash_head[h]);
+
+ while(*p != -1 && *p != n)
+ p = &(uhash->next_in_hash[*p]);
+ if(*p == n)
+ *p = uhash->next_in_hash[n];
+}
+
+int setumoney(int uid, int money) {
+ uhash->money[uid-1]=money;
+ passwd_update_money(uid);
+ return uhash->money[uid-1];
+}
+
+int deumoney(int uid, int money) {
+ if(money<0 && uhash->money[uid-1]<-money)
+ return setumoney(uid,0);
+ else
+ return setumoney(uid,uhash->money[uid-1]+money);
+}
+int demoney(int money) {
+ extern int usernum;
+ return deumoney(usernum,money);
+}
+int moneyof(int uid){ /* ptt §ï¶iª÷¿ú³B²z®Ä²v */
+ return uhash->money[uid-1];
+}
+int searchuser(char *userid) {
+ int h,p;
+
+ h = StringHash(userid);
+ p = uhash->hash_head[h];
+
+ while(p != -1) {
+ if(strcasecmp(uhash->userid[p],userid) == 0) {
+ strcpy(userid,uhash->userid[p]);
+ return p + 1;
+ }
+ p = uhash->next_in_hash[p];
+ }
+ return 0;
+}
+
+#if !defined(_BBS_UTIL_C_)
+extern userec_t xuser;
+
+int getuser(char *userid) {
+ int uid;
+
+ if((uid = searchuser(userid)))
+ passwd_query(uid, &xuser);
+ return uid;
+}
+
+char *getuserid(int num) {
+ if(--num >= 0 && num < MAX_USERS)
+ return ((char *) uhash->userid[num]);
+ return NULL;
+}
+
+void setuserid(int num, char *userid) {
+ if(num > 0 && num <= MAX_USERS) {
+ if(num > uhash->number)
+ uhash->number = num;
+ else
+ remove_from_uhash(num-1);
+ add_to_uhash(num-1,userid);
+ }
+}
+
+/* 0 ==> §ä¹L´Á±b¸¹ */
+/* 1 ==> «Ø¥ß·s±b¸¹ */
+/* should do it by searching "" in the hash */
+int searchnewuser(int mode) {
+ register int i, num;
+
+ num = uhash->number;
+ i = 0;
+
+ /* ¬°¤°»ò³oÃ䤣¥Î hash table ¥h§ä¦Ó­n¥Î linear search? */
+ while(i < num) {
+ if(!uhash->userid[i++][0])
+ return i;
+ }
+ if(mode && (num < MAX_USERS))
+ return num + 1;
+ return 0;
+}
+
+char *u_namearray(char buf[][IDLEN + 1], int *pnum, char *tag) {
+ register struct uhash_t *reg_ushm = uhash;
+ register char *ptr, tmp;
+ register int n, total;
+ char tagbuf[STRLEN];
+ int ch, ch2, num;
+
+ if(*tag == '\0') {
+ *pnum = reg_ushm->number;
+ return reg_ushm->userid[0];
+ }
+ for(n = 0; tag[n]; n++)
+ tagbuf[n] = chartoupper(tag[n]);
+ tagbuf[n] = '\0';
+ ch = tagbuf[0];
+ ch2 = ch - 'A' + 'a';
+ total = reg_ushm->number;
+ for(n = num = 0; n < total; n++) {
+ ptr = reg_ushm->userid[n];
+ tmp = *ptr;
+ if(tmp == ch || tmp == ch2) {
+ if(chkstr(tag, tagbuf, ptr))
+ strcpy(buf[num++], ptr);
+ }
+ }
+ *pnum = num;
+ return buf[0];
+}
+#endif
+
+/*-------------------------------------------------------*/
+/* .UTMP cache */
+/*-------------------------------------------------------*/
+struct utmpfile_t *utmpshm=NULL;
+
+void resolve_utmp() {
+ if(utmpshm == NULL) {
+ utmpshm = attach_shm(UTMPSHM_KEY, sizeof(*utmpshm));
+ }
+}
+
+userinfo_t *currutmp = NULL;
+
+#if !defined(_BBS_UTIL_C_)
+extern unsigned int currstat;
+extern userec_t cuser;
+
+void setutmpmode(int mode) {
+ if(currstat != mode)
+ currutmp->mode = currstat = mode;
+
+ /* °lÂÜ¨Ï¥ÎªÌ */
+ if(HAS_PERM(PERM_LOGUSER)) {
+ time_t now = time(NULL);
+ char msg[200];
+ sprintf(msg, "%s setutmpmode to %s(%d) at %s",
+ cuser.userid, modestring(currutmp, 0), mode, Cdate(&now));
+ log_user(msg);
+ }
+}
+#endif
+/*
+static int cmputmpuserid(userinfo_t ** i, userinfo_t ** j) {
+ return strcasecmp((*i)->userid, (*j)->userid);
+}
+
+static int cmputmpmode(userinfo_t ** i, userinfo_t ** j) {
+ return (*i)->mode-(*j)->mode;
+}
+
+static int cmputmpidle(userinfo_t ** i, userinfo_t ** j) {
+ return (*i)->lastact-(*j)->lastact;
+}
+
+static int cmputmpfrom(userinfo_t ** i, userinfo_t ** j) {
+ return strcasecmp((*i)->from, (*j)->from);
+}
+
+static int cmputmpfive(userinfo_t ** i, userinfo_t ** j) {
+ int type;
+ if((type=(*j)->five_win - (*i)->five_win))
+ return type;
+ if((type=(*i)->five_lose - (*j)->five_lose))
+ return type;
+ return (*i)->five_tie-(*j)->five_tie;
+}
+static int cmputmpsex(userinfo_t ** i, userinfo_t ** j) {
+ static int ladyfirst[]={1,0,1,0,1,0,3,3};
+ return ladyfirst[(*i)->sex]-ladyfirst[(*j)->sex];
+}
+static int cmputmppid(userinfo_t ** i, userinfo_t ** j) {
+ return (*i)->pid-(*j)->pid;
+}
+static int cmputmpuid(userinfo_t ** i, userinfo_t ** j) {
+ return (*i)->uid-(*j)->uid;
+}
+*/
+static int cmputmpuserid(const void *i, const void *j){
+ return strcasecmp((*((userinfo_t**)i))->userid, (*((userinfo_t**)j))->userid);
+}
+
+static int cmputmpmode(const void *i, const void *j){
+ return (*((userinfo_t**)i))->mode-(*((userinfo_t**)j))->mode;
+}
+
+static int cmputmpidle(const void *i, const void *j){
+ return (*((userinfo_t**)i))->lastact-(*((userinfo_t**)j))->lastact;
+}
+
+static int cmputmpfrom(const void *i, const void *j){
+ return strcasecmp((*((userinfo_t**)i))->from, (*((userinfo_t**)j))->from);
+}
+
+static int cmputmpfive(const void *i, const void *j){
+ int type;
+ if((type=(*((userinfo_t**)j))->five_win - (*((userinfo_t**)i))->five_win))
+ return type;
+ if((type=(*((userinfo_t**)i))->five_lose - (*((userinfo_t**)j))->five_lose))
+ return type;
+ return (*((userinfo_t**)i))->five_tie-(*((userinfo_t**)j))->five_tie;
+}
+
+static int cmputmpsex(const void *i, const void *j){
+ static int ladyfirst[]={1,0,1,0,1,0,3,3};
+ return ladyfirst[(*((userinfo_t**)i))->sex]-ladyfirst[(*((userinfo_t**)j))->sex];
+}
+static int cmputmppid(const void *i, const void *j){
+ return (*((userinfo_t**)i))->pid-(*((userinfo_t**)j))->pid;
+}
+static int cmputmpuid(const void *i, const void *j){
+ return (*((userinfo_t**)i))->uid-(*((userinfo_t**)j))->uid;
+}
+void sort_utmp()
+{
+ time_t now=time(NULL);
+ int count, i, ns;
+ userinfo_t *uentp;
+
+ if(now-utmpshm->uptime<60 && (now==utmpshm->uptime || utmpshm->busystate))
+ return; /* lazy sort */
+ utmpshm->busystate=1;
+ utmpshm->uptime = now;
+ ns=(utmpshm->currsorted?0:1);
+
+ for(uentp = &utmpshm->uinfo[0], count=0, i=0;
+ i< USHM_SIZE; i++,uentp = &utmpshm->uinfo[i])
+ if(uentp->pid)
+ {
+ utmpshm->sorted[ns][0][count++]= uentp;
+ }
+ utmpshm->number = count;
+ qsort(utmpshm->sorted[ns][0],count,sizeof(userinfo_t*),cmputmpuserid);
+ memcpy(utmpshm->sorted[ns][1],utmpshm->sorted[ns][0],
+ sizeof(userinfo_t *)*count);
+ memcpy(utmpshm->sorted[ns][2],utmpshm->sorted[ns][0],
+ sizeof(userinfo_t *)*count);
+ memcpy(utmpshm->sorted[ns][3],utmpshm->sorted[ns][0],
+ sizeof(userinfo_t *)*count);
+ memcpy(utmpshm->sorted[ns][4],utmpshm->sorted[ns][0],
+ sizeof(userinfo_t *)*count);
+ memcpy(utmpshm->sorted[ns][5],utmpshm->sorted[ns][0],
+ sizeof(userinfo_t *)*count);
+ memcpy(utmpshm->sorted[ns][6],utmpshm->sorted[ns][0],
+ sizeof(userinfo_t *)*count);
+ memcpy(utmpshm->sorted[ns][7],utmpshm->sorted[ns][0],
+ sizeof(userinfo_t *)*count);
+ qsort(utmpshm->sorted[ns][1], count, sizeof(userinfo_t *), cmputmpmode );
+ qsort(utmpshm->sorted[ns][2], count, sizeof(userinfo_t *), cmputmpidle );
+ qsort(utmpshm->sorted[ns][3], count, sizeof(userinfo_t *), cmputmpfrom );
+ qsort(utmpshm->sorted[ns][4], count, sizeof(userinfo_t *), cmputmpfive );
+ qsort(utmpshm->sorted[ns][5], count, sizeof(userinfo_t *), cmputmpsex );
+ qsort(utmpshm->sorted[ns][6], count, sizeof(userinfo_t *), cmputmpuid );
+ qsort(utmpshm->sorted[ns][7], count, sizeof(userinfo_t *), cmputmppid );
+ utmpshm->currsorted=ns;
+ utmpshm->busystate=0;
+}
+// Ptt:³oÃä¥[¤JhashÆ[©À §äªÅªºutmp
+void getnewutmpent(userinfo_t *up) {
+ extern int errno;
+ register int i, p ;
+ register userinfo_t *uentp;
+ for(i = 0, p=StringHash(up->userid)%USHM_SIZE; i < USHM_SIZE; i++, p++) {
+ if(p==USHM_SIZE) p=0;
+ uentp = &(utmpshm->uinfo[p]);
+ if(!(uentp->pid)) {
+ memcpy(uentp, up, sizeof(userinfo_t));
+ currutmp = uentp;
+ sort_utmp();
+ return;
+ }
+ }
+ exit(1);
+}
+
+int apply_ulist(int (*fptr)(userinfo_t *)) {
+ register userinfo_t *uentp;
+ register int i, state;
+
+ for(i = 0; i < USHM_SIZE; i++) {
+ uentp = &(utmpshm->uinfo[i]);
+ if(uentp->pid && (PERM_HIDE(currutmp) || !PERM_HIDE(uentp)))
+ if((state = (*fptr) (uentp)))
+ return state;
+ }
+ return 0;
+}
+
+userinfo_t *search_ulist(int uid) {
+ return search_ulistn(uid,1);
+}
+
+#if !defined(_BBS_UTIL_C_)
+extern int usernum;
+
+userinfo_t *search_ulist_pid(int pid) {
+ register int i=0, j, start = 0, end = utmpshm->number - 1;
+ register userinfo_t **ulist;
+ ulist=utmpshm->sorted[utmpshm->currsorted][7];
+ for(i=((start+end)/2); ;i=(start+end)/2)
+ {
+ j=pid-ulist[i]->pid;
+ if(!j)
+ {
+ return (userinfo_t *) (ulist[i]);
+ }
+ if(end==start)
+ {
+ break;
+ }
+ else if(i==start)
+ {
+ i=end;
+ start=end;
+ }
+ else if(j>0) start = i;
+ else end = i;
+ }
+ return 0;
+}
+userinfo_t *search_ulistn(int uid, int unum) {
+ register int i=0, j, start = 0, end = utmpshm->number - 1;
+ register userinfo_t **ulist;
+ ulist=utmpshm->sorted[utmpshm->currsorted][6];
+ for(i=((start+end)/2); ;i=(start+end)/2)
+ {
+ j= uid - ulist[i]->uid;
+ if(!j)
+ {
+ for(;i>0 && uid==ulist[i-1]->uid;i--);/* «ü¨ì²Ä¤@µ§ */
+ if(uid==ulist[i+unum-1]->uid)
+ return (userinfo_t *) (ulist[i+unum-1]);
+ break; /* ¶W¹L½d³ò */
+ }
+ if(end==start)
+ {
+ break;
+ }
+ else if(i==start)
+ {
+ i=end;
+ start=end;
+ }
+ else if(j>0) start = i;
+ else end = i;
+ }
+ return 0;
+}
+
+int count_logins(int uid, int show) {
+ register int i=0, j, start = 0, end = utmpshm->number - 1, count;
+ register userinfo_t **ulist;
+ ulist=utmpshm->sorted[utmpshm->currsorted][6];
+ for(i=((start+end)/2); ;i=(start+end)/2)
+ {
+ j = uid-ulist[i]->uid;
+ if(!j)
+ {
+ for(;i>0 && uid==ulist[i-1]->uid;i--);/* «ü¨ì²Ä¤@µ§ */
+ for(count=0;uid==ulist[i+count]->uid;count++)
+ {
+ if(show)
+ prints("(%d) ¥Ø«eª¬ºA¬°: %-17.16s(¨Ó¦Û %s)\n",
+ count+1, modestring(ulist[i+count], 0),
+ ulist[i+count]->from);
+ }
+ return count;
+ }
+ if(end==start)
+ {
+ break;
+ }
+ else if(i==start)
+ {
+ i=end;
+ start=end;
+ }
+ else if(j>0) start = i;
+ else end = i;
+ }
+ return 0;
+}
+
+
+void purge_utmp(userinfo_t *uentp) {
+ logout_friend_online();
+ memset(uentp, 0, sizeof(userinfo_t));
+}
+
+#endif
+
+/*-------------------------------------------------------*/
+/* .BOARDS cache */
+/*-------------------------------------------------------*/
+extern char *fn_board;
+extern int currbid;
+bcache_t *brdshm;
+boardheader_t *bcache;
+
+void touchdircache(int bid)
+{
+ int *i= (int *)&brdshm->dircache[bid - 1][0].filename[0];
+ *i=0;
+}
+
+void load_fileheader_cache(int bid, char *direct)
+{
+ int num=getbtotal(bid);
+ int n = num-DIRCACHESIZE+1;
+ if (brdshm->busystate!=1)
+ {
+ brdshm->busystate = 1;
+ get_records(direct, brdshm->dircache[bid - 1] ,
+ sizeof(fileheader_t),n<1?1:n, DIRCACHESIZE);
+ brdshm->cachetotal[bid-1]=num; // cachetotal¥ý³] ¥H«á¦A§ï¤£¥Î¥þ³¡load
+ brdshm->busystate = 0;
+ }
+ else
+ {safe_sleep(1);}
+}
+
+int get_fileheader_cache(int bid, char *direct, fileheader_t *headers,
+ int recbase, int nlines)
+{
+ int ret, n,num;
+
+ num=getbtotal(bid);
+
+ ret = num-recbase+1,
+ n = (num - DIRCACHESIZE+1);
+
+
+ if(brdshm->dircache[bid - 1][0].filename[0]=='\0')
+ load_fileheader_cache(bid, direct);
+ if (n<1)
+ n=recbase-1;
+ else
+ n=recbase-n;
+ if(n<0) n=0;
+ if (ret>nlines) ret=nlines;
+ memcpy(headers, &(brdshm->dircache[bid - 1][n]),sizeof(fileheader_t)*ret);
+ return ret;
+}
+static int cmpboardname(boardheader_t **brd, boardheader_t **tmp) {
+ return strcasecmp((*brd)->brdname, (*tmp)->brdname);
+}
+static int cmpboardclass(boardheader_t **brd, boardheader_t **tmp) {
+ return (strncmp((*brd)->title, (*tmp)->title, 4)<<8)+
+ strcasecmp((*brd)->brdname, (*tmp)->brdname);
+}
+static void sort_bcache(){
+ int i;/*critical section ¤£¯à³æ¿W©I¥s ©I¥sreload_bcache or reset_board */
+ for(i=0;i<brdshm->number;i++)
+ {
+ brdshm->sorted[1][i]=brdshm->sorted[0][i]=&bcache[i];
+ }
+ qsort(brdshm->sorted[0], brdshm->number, sizeof(boardheader_t *),
+ (QCAST)cmpboardname);
+ qsort(brdshm->sorted[1], brdshm->number, sizeof(boardheader_t *),
+ (QCAST)cmpboardclass);
+}
+static void reload_bcache() {
+ if(brdshm->busystate) {
+ safe_sleep(1);
+ }
+#if !defined(_BBS_UTIL_C_)
+ else {
+ int fd,i;
+
+ brdshm->busystate = 1;
+ if((fd = open(fn_board, O_RDONLY)) > 0) {
+ brdshm->number =
+ read(fd, bcache, MAX_BOARD * sizeof(boardheader_t)) /
+ sizeof(boardheader_t);
+ close(fd);
+ }
+ memset(brdshm->lastposttime, 0, MAX_BOARD * sizeof(time_t));
+ /* µ¥©Ò¦³ boards ¸ê®Æ§ó·s«á¦A³]©w uptime */
+ brdshm->uptime = brdshm->touchtime;
+ log_usies("CACHE", "reload bcache");
+ sort_bcache();
+ for(i=0;i<brdshm->number;i++)
+ {
+ bcache[i].firstchild[0]=NULL;
+ bcache[i].firstchild[1]=NULL;
+ }
+ brdshm->busystate = 0;
+ }
+#endif
+}
+
+int numboards = -1;
+
+void resolve_boards() {
+ if(brdshm == NULL) {
+ brdshm = attach_shm(BRDSHM_KEY, sizeof(*brdshm));
+ if(brdshm->touchtime == 0)
+ brdshm->touchtime = 1;
+ bcache = brdshm->bcache;
+ }
+
+ while(brdshm->uptime < brdshm->touchtime)
+ {reload_bcache();}
+ numboards = brdshm->number;
+}
+
+void touch_boards() {
+ time(&(brdshm->touchtime));
+ numboards = -1;
+ resolve_boards();
+}
+void addbrd_touchcache()
+{
+ brdshm->number++;
+ numboards=brdshm->number;
+ reset_board(numboards);
+}
+#if !defined(_BBS_UTIL_C_)
+void reset_board(int bid) { /* Ptt: ³o¼Ë´N¤£¥Î¦Ñ¬Otouch board¤F */
+ int fd,i;
+ boardheader_t *bhdr;
+
+ if(--bid < 0)
+ return;
+ if(brdshm->busystate) {
+ safe_sleep(1);
+ } else {
+ brdshm->busystate = 1;
+ bhdr = bcache;
+ bhdr += bid;
+ if((fd = open(fn_board, O_RDONLY)) > 0) {
+ lseek(fd, (off_t)(bid * sizeof(boardheader_t)), SEEK_SET);
+ read(fd, bhdr, sizeof(boardheader_t));
+ close(fd);
+ }
+ sort_bcache();
+ for(i=0;i<brdshm->number;i++)
+ {
+ bcache[i].firstchild[0]=NULL;
+ bcache[i].firstchild[1]=NULL;
+ }
+ brdshm->busystate = 0;
+ }
+}
+
+int apply_boards(int (*func)(boardheader_t *)) {
+ register int i;
+ register boardheader_t *bhdr;
+
+ for(i = 0, bhdr = bcache; i < numboards; i++, bhdr++) {
+ if(!(bhdr->brdattr & BRD_GROUPBOARD) && Ben_Perm(bhdr) &&
+ (*func)(bhdr) == QUIT)
+ return QUIT;
+ }
+ return 0;
+}
+#endif
+
+boardheader_t *getbcache(int bid) { /* Ptt§ï¼g */
+ return bcache + bid - 1;
+}
+int getbtotal(int bid)
+{
+ return brdshm->total[bid - 1];
+}
+void setbtotal(int bid) {
+ boardheader_t *bh = getbcache(bid);
+ struct stat st;
+ char genbuf[256];
+ int num,fd;
+
+ sprintf(genbuf, "boards/%s/.DIR", bh->brdname);
+
+ if((fd = open(genbuf, O_RDWR)) < 0)
+ return; /* .DIR±¾¤F */
+ fstat(fd, &st);
+ num = st.st_size / sizeof(fileheader_t);
+ brdshm->total[bid - 1] = num;
+
+ if(num>0)
+ {
+ lseek(fd, (off_t) (num - 1) * sizeof(fileheader_t), SEEK_SET);
+ if(read(fd, genbuf, FNLEN)>=0)
+ {
+ brdshm->lastposttime[bid - 1]=(time_t) atoi(&genbuf[2]);
+ }
+ }
+ else
+ brdshm->lastposttime[bid - 1] = 0;
+ close(fd);
+ if(num)
+ touchdircache(bid);
+}
+
+void
+touchbpostnum(int bid, int delta) {
+ int *total = &brdshm->total[bid - 1];
+ if (*total) *total += delta;
+}
+
+
+int getbnum(char *bname) {
+ register int i=0, j, start = 0, end = brdshm->number - 1;
+ register boardheader_t **bhdr;
+ bhdr=brdshm->sorted[0];
+ for(i=((start+end)/2); ;i=(start+end)/2)
+ {
+ if(! (j=strcasecmp(bname,bhdr[i]->brdname)))
+ return (int) (bhdr[i] - bcache +1);
+ if(end==start)
+ {
+ break;
+ }
+ else if(i==start)
+ {
+ i=end;
+ start=end;
+ }
+ else if(j>0) start = i;
+ else end = i;
+ }
+ return 0;
+}
+
+#if !defined(_BBS_UTIL_C_)
+extern char *fn_water;
+extern char *str_sysop;
+
+int haspostperm(char *bname) {
+ register int i;
+ char buf[200];
+
+ setbfile(buf, bname, fn_water);
+ if(belong(buf, cuser.userid))
+ return 0;
+
+ if(!strcasecmp(bname, DEFAULT_BOARD))
+ return 1;
+
+ if (!strcasecmp(bname, "PttLaw"))
+ return 1;
+
+ if(!HAS_PERM(PERM_POST))
+ return 0;
+
+ if(!(i = getbnum(bname)))
+ return 0;
+
+ /* ¯µ±K¬ÝªO¯S§O³B²z */
+ if(bcache[i - 1].brdattr & BRD_HIDE)
+ return 1;
+
+ i = bcache[i - 1].level;
+
+ if (HAS_PERM(PERM_VIOLATELAW) && (i & PERM_VIOLATELAW))
+ return 1;
+ else if (HAS_PERM(PERM_VIOLATELAW))
+ return 0;
+
+ return HAS_PERM(i & ~PERM_POST);
+}
+#endif
+
+/*-------------------------------------------------------*/
+/* PTT cache */
+/*-------------------------------------------------------*/
+/* cachefor °ÊºA¬Ýª© */
+struct pttcache_t *ptt;
+
+static void reload_pttcache() {
+ if(ptt->busystate)
+ safe_sleep(1);
+ else { /* jochang: temporary workaround */
+ fileheader_t item, subitem;
+ char pbuf[256], buf[256], *chr;
+ FILE *fp, *fp1, *fp2;
+ int id, section = 0;
+
+ ptt->busystate = 1;
+ ptt->max_film = 0;
+ bzero(ptt->notes, sizeof ptt->notes);
+ setapath(pbuf, "Note");
+ setadir(buf, pbuf);
+ id = 0;
+ if((fp = fopen(buf, "r"))) {
+ while(fread(&item, sizeof(item), 1, fp)) {
+ if(item.title[3]=='<' && item.title[8]=='>') {
+ sprintf(buf,"%s/%s", pbuf, item.filename);
+ setadir(buf, buf);
+ if(!(fp1 = fopen(buf, "r")))
+ continue;
+ ptt->next_refresh[section] = ptt->n_notes[section] = id;
+ section ++;
+ while(fread(&subitem, sizeof(subitem), 1, fp1)) {
+ sprintf(buf,"%s/%s/%s", pbuf, item.filename ,
+ subitem.filename);
+ if(!(fp2=fopen(buf,"r")))
+ continue;
+ fread(ptt->notes[id],sizeof(char), 200*11, fp2);
+ ptt->notes[id][200*11 - 1]=0;
+ id++;
+ fclose(fp2);
+ if(id >= MAX_MOVIE)
+ break;
+ }
+ fclose(fp1);
+ if(id >= MAX_MOVIE || section >= MAX_MOVIE_SECTION)
+ break;
+ }
+ }
+ fclose(fp);
+ }
+ ptt->next_refresh[section] = -1;
+ ptt->n_notes[section] = ptt->max_film = id-1;
+ ptt->max_history = ptt->max_film - 2;
+ if(ptt->max_history > MAX_HISTORY - 1)
+ ptt->max_history = MAX_HISTORY - 1;
+ if(ptt->max_history <0) ptt->max_history=0;
+
+ fp = fopen("etc/today_is","r");
+ if(fp) {
+ fgets(ptt->today_is,15,fp);
+ if((chr = strchr(ptt->today_is,'\n')))
+ *chr = 0;
+ ptt->today_is[15] = 0;
+ fclose(fp);
+ }
+
+ /* µ¥©Ò¦³¸ê®Æ§ó·s«á¦A³]©w uptime */
+
+ ptt->uptime = ptt->touchtime ;
+#if !defined(_BBS_UTIL_C_)
+ log_usies("CACHE", "reload pttcache");
+#endif
+ ptt->busystate = 0;
+ }
+}
+
+void resolve_garbage() {
+ int count=0;
+
+ if(ptt == NULL) {
+ ptt = attach_shm(PTTSHM_KEY, sizeof(*ptt));
+ if(ptt->touchtime == 0)
+ ptt->touchtime = 1;
+ }
+ while(ptt->uptime < ptt->touchtime) { /* ¤£¥Îwhileµ¥ */
+ reload_pttcache();
+ if(count ++ > 10 && ptt->busystate) {
+/* Ptt: ³oÃä·|¦³°ÝÃD load¶W¹L10 ¬í·|©Ò¦³¶iloopªºprocess³£Åý busystate = 0
+ ³o¼Ë·|©Ò¦³prcosee³£·|¦bload °ÊºA¬ÝªO ·|³y¦¨load¤j¼W
+ ¦ý¨S¦³¥Î³o­Ófunctionªº¸Ü ¸U¤@load passwdÀɪºprocess¦º¤F ¤S¨S¦³¤H§â¥L
+ ¸Ñ¶} ¦P¼Ëªº°ÝÃDµo¥Í¦breload passwd
+*/
+ ptt->busystate = 0;
+#ifndef _BBS_UTIL_C_
+ log_usies("CACHE", "refork Ptt dead lock");
+#endif
+ }
+ }
+}
+
+/*-------------------------------------------------------*/
+/* PTT's cache */
+/*-------------------------------------------------------*/
+/* cachefor from host »P³Ì¦h¤W½u¤H¼Æ */
+struct fromcache_t *fcache;
+
+static void reload_fcache() {
+ if(fcache->busystate)
+ safe_sleep(1);
+ else {
+ FILE *fp;
+
+ fcache->busystate = 1;
+ bzero(fcache->domain, sizeof fcache->domain);
+ if((fp = fopen("etc/domain_name_query","r"))) {
+ char buf[256],*po;
+
+ fcache->top=0;
+ while(fgets(buf, sizeof(buf),fp)) {
+ if(buf[0] && buf[0] != '#' && buf[0] != ' ' &&
+ buf[0] != '\n') {
+ sscanf(buf,"%s",fcache->domain[fcache->top]);
+ po = buf + strlen(fcache->domain[fcache->top]);
+ while(*po == ' ')
+ po++;
+ strncpy(fcache->replace[fcache->top],po,49);
+ fcache->replace[fcache->top]
+ [strlen(fcache->replace[fcache->top])-1] = 0;
+ (fcache->top)++;
+ if(fcache->top == MAX_FROM)
+ break;
+ }
+ }
+ }
+
+ fcache->max_user=0;
+
+ /* µ¥©Ò¦³¸ê®Æ§ó·s«á¦A³]©w uptime */
+ fcache->uptime = fcache->touchtime;
+#if !defined(_BBS_UTIL_C_)
+ log_usies("CACHE", "reload fcache");
+#endif
+ fcache->busystate = 0;
+ }
+}
+
+void resolve_fcache() {
+ if(fcache == NULL) {
+ fcache = attach_shm(FROMSHM_KEY, sizeof(*fcache));
+ if(fcache->touchtime == 0)
+ fcache->touchtime = 1;
+ }
+ while(fcache->uptime < fcache->touchtime)
+ reload_fcache();
+}
+
+extern time_t login_start_time;
+extern char *fn_visable;
+FILE *DEBUG = NULL;
+
+void hbflreload(int bid)
+{
+ int hbfl[MAX_FRIEND + 1], i, num, uid;
+ char buf[128];
+ FILE *fp;
+
+ memset(hbfl, 0, sizeof(hbfl));
+ setbfile(buf, bcache[bid-1].brdname, fn_visable);
+ if( (fp = fopen(buf, "r")) != NULL ){
+ for( num = 1 ; num <= MAX_FRIEND ; ++num ){
+ if( fgets(buf, sizeof(buf), fp) == NULL )
+ break;
+ for( i = 0 ; buf[i] != 0 ; ++i )
+ if( buf[i] == ' ' ){
+ buf[i] = 0;
+ break;
+ }
+ if( strcasecmp("guest", buf) == 0 ||
+ (uid = searchuser(buf)) == 0 ) {
+ --num;
+ continue;
+ }
+ hbfl[num] = uid;
+ }
+ fclose(fp);
+ }
+ hbfl[0] = time(NULL);
+ memcpy(uhash->hbfl[bid], hbfl, sizeof(hbfl));
+}
+
+int hbflcheck(int bid, int uid)
+{
+ int i;
+
+ if( uhash->hbfl[bid][0] < login_start_time - HBFLexpire )
+ hbflreload(bid);
+ for( i = 1 ; uhash->hbfl[bid][i] != 0 && i <= MAX_FRIEND ; ++i ){
+ if( uhash->hbfl[bid][i] == uid )
+ return 0;
+ }
+ return 1;
+}
diff --git a/mbbsd/cal.c b/mbbsd/cal.c
new file mode 100644
index 00000000..680ee9d6
--- /dev/null
+++ b/mbbsd/cal.c
@@ -0,0 +1,512 @@
+/* $Id: cal.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "modes.h"
+#include "perm.h"
+#include "proto.h"
+
+extern struct utmpfile_t *utmpshm;
+extern int usernum;
+
+/* ¨¾°ô Multi play */
+static int count_multiplay(int unmode) {
+ register int i, j;
+ register userinfo_t *uentp;
+ extern struct utmpfile_t *utmpshm;
+
+ for(i = j = 0; i < USHM_SIZE; i++) {
+ uentp = &(utmpshm->uinfo[i]);
+ if(uentp->uid == usernum)
+ if(uentp->lockmode == unmode)
+ j++;
+ }
+ return j;
+}
+
+extern userinfo_t *currutmp;
+extern char *ModeTypeTable[];
+
+int lockutmpmode(int unmode, int state) {
+ int errorno = 0;
+
+ if(currutmp->lockmode)
+ errorno = 1;
+ else if(count_multiplay(unmode))
+ errorno = 2;
+
+ if(errorno && !(state == LOCK_THIS && errorno == LOCK_MULTI)) {
+ clear();
+ move(10,20);
+ if(errorno == 1)
+ prints("½Ð¥ýÂ÷¶} %s ¤~¯à¦A %s ",
+ ModeTypeTable[currutmp->lockmode],
+ ModeTypeTable[unmode]);
+ else
+ prints("©êºp! ±z¤w¦³¨ä¥L½u¬Û¦PªºID¥¿¦b%s",
+ ModeTypeTable[unmode]);
+ pressanykey();
+ return errorno;
+ }
+
+ setutmpmode(unmode);
+ currutmp->lockmode = unmode;
+ return 0;
+}
+
+int unlockutmpmode() {
+ currutmp->lockmode = 0;
+ return 0;
+}
+
+extern userec_t cuser;
+extern userec_t xuser;
+
+/* ¨Ï¥Î¿úªº¨ç¼Æ */
+#define VICE_NEW "vice.new"
+
+/* Heat:µo²¼ */
+int vice(int money, char* item) {
+ char buf[128];
+ unsigned int viceserial=(currutmp->lastact%1000000)*100+rand()%100;
+ FILE *fp;
+ demoney(-money);
+ sprintf(buf, BBSHOME"/home/%c/%s/%s",
+ cuser.userid[0], cuser.userid, VICE_NEW);
+ fp = fopen(buf, "a");
+ if(!fp )
+ {return 0;}
+
+ fprintf(fp, "%08d\n", viceserial);
+ fclose(fp);
+ sprintf(buf, "%s ªá¤F%d$ ½s¸¹[%08d]",item, money, viceserial);
+ mail_id(cuser.userid, buf, "etc/vice.txt", "Ptt¸gÀÙ³¡");
+ return 0;
+}
+
+#define lockreturn(unmode, state) if(lockutmpmode(unmode, state)) return
+#define lockreturn0(unmode, state) if(lockutmpmode(unmode, state)) return 0
+#define lockbreak(unmode, state) if(lockutmpmode(unmode, state)) break
+#define SONGBOOK "etc/SONGBOOK"
+#define OSONGPATH "etc/SONGO"
+extern char trans_buffer[];
+extern char save_title[];
+
+static int osong(char *defaultid) {
+ char destid[IDLEN + 1],buf[200],genbuf[200],filename[256],say[51];
+ char receiver[60],ano[2];
+ FILE *fp,*fp1;// *fp2;
+ fileheader_t mail;
+ time_t now;
+ int nsongs;
+
+ now = time(NULL);
+ strcpy(buf, Cdatedate(&now));
+
+ lockreturn0(OSONG, LOCK_MULTI);
+
+ /* Jaky ¤@¤H¤@¤ÑÂI¤@­º */
+ if(!strcmp(buf, Cdatedate(&cuser.lastsong)) && !HAS_PERM(PERM_SYSOP)) {
+ move(22,0);
+ outs("§A¤µ¤Ñ¤w¸gÂI¹LÅo¡A©ú¤Ñ¦AÂI§a....");
+ refresh();
+ pressanykey();
+
+ unlockutmpmode();
+ return 0;
+ }
+
+ if(cuser.money < 200) {
+ move(22, 0);
+ outs("ÂIºq­n200»È­ò!....");
+ refresh();
+ pressanykey();
+ unlockutmpmode();
+ return 0;
+ }
+ move(12, 0);
+ clrtobot();
+ sprintf(buf, "¿Ë·Rªº %s Åwªï¨Ó¨ì¼Ú®á¦Û°ÊÂIºq¨t²Î\n", cuser.userid);
+ outs(buf);
+ trans_buffer[0] = 0;
+ if(!defaultid){
+ getdata(13, 0, "­nÂIµ¹½Ö©O:[¥iª½±µ«ö Enter ¥ý¿ïºq]", destid, IDLEN + 1, DOECHO);
+ while (!destid[0]){
+ a_menu("ÂIºqºq¥»", SONGBOOK,0 );
+ clear();
+ getdata(13, 0, "­nÂIµ¹½Ö©O:[¥i«ö Enter ­«·s¿ïºq]", destid, IDLEN + 1, DOECHO);
+ }
+ }
+ else
+ strcpy(destid,defaultid);
+
+ /* Heat:ÂIºqªÌ°Î¦W¥\¯à */
+ getdata(14,0, "­n°Î¦W¶Ü?[y/n]:", ano, 2, DOECHO);
+
+ if(!destid[0]) {
+ unlockutmpmode();
+ return 0;
+ }
+
+ getdata_str(14, 0, "·Q­n­n¹ï¥L(¦o)»¡..:", say, 51, DOECHO, "§Ú·R©p..");
+ sprintf(save_title, "%s:%s", (ano[0]=='y')?"°Î¦WªÌ":cuser.userid, say);
+ getdata_str(16, 0, "±H¨ì½Öªº«H½c(¥i¥ÎE-mail)?", receiver, 45,
+ LCECHO, destid);
+
+
+
+ if (!trans_buffer[0]){
+ outs("\n±µµÛ­n¿ïºqÅo..¶i¤Jºq¥»¦n¦nªº¿ï¤@­ººq§a..^o^");
+ pressanykey();
+ a_menu("ÂIºqºq¥»", SONGBOOK,0 );
+ }
+ if(!trans_buffer[0] || strstr(trans_buffer, "home") ||
+ strstr(trans_buffer, "boards") || !(fp = fopen(trans_buffer, "r"))) {
+ unlockutmpmode();
+ return 0;
+ }
+
+ strcpy(filename, OSONGPATH);
+
+ stampfile(filename, &mail);
+
+ unlink(filename);
+
+ if(!(fp1 = fopen(filename, "w"))) {
+ fclose(fp);
+ unlockutmpmode();
+ return 0;
+ }
+
+ strcpy(mail.owner, "ÂIºq¾÷");
+ sprintf(mail.title, "¡º %s ÂIµ¹ %s ", (ano[0]=='y')?"°Î¦WªÌ":cuser.userid, destid);
+ mail.savemode = 0;
+
+ while(fgets(buf, 200, fp)) {
+ char *po;
+ if(!strncmp(buf, "¼ÐÃD: ", 6)) {
+ clear();
+ move(10,10);prints("%s", buf);
+ pressanykey();
+ fclose(fp);
+ unlockutmpmode();
+ return 0;
+ }
+ while((po = strstr(buf, "<~Src~>"))) {
+ po[0] = 0;
+ sprintf(genbuf,"%s%s%s",buf,(ano[0]=='y')?"°Î¦WªÌ":cuser.userid,po+7);
+ strcpy(buf,genbuf);
+ }
+ while((po = strstr(buf, "<~Des~>"))) {
+ po[0] = 0;
+ sprintf(genbuf,"%s%s%s",buf,destid,po+7);
+ strcpy(buf,genbuf);
+ }
+ while((po = strstr(buf, "<~Say~>"))) {
+ po[0] = 0;
+ sprintf(genbuf,"%s%s%s",buf,say,po+7);
+ strcpy(buf,genbuf);
+ }
+ fputs(buf,fp1);
+ }
+ fclose(fp1);
+ fclose(fp);
+
+// do_append(OSONGMAIL "/.DIR", &mail2, sizeof(mail2));
+
+ if(do_append(OSONGPATH "/.DIR", &mail, sizeof(mail)) != -1) {
+ cuser.lastsong = time(NULL);
+ /* Jaky ¶W¹L 500 ­ººq´N¶}©l¬å */
+ nsongs=get_num_records(OSONGPATH "/.DIR", sizeof(mail));
+ if (nsongs > 500){
+ delete_range(OSONGPATH "/.DIR", 1, nsongs-500);
+ }
+ /* §â²Ä¤@­º®³±¼ */
+ vice(200, "ÂIºq");
+ }
+ sprintf(save_title, "%s:%s", (ano[0]=='y')?"°Î¦WªÌ":cuser.userid, say);
+ hold_mail(filename, destid);
+
+ if(receiver[0]) {
+#ifndef USE_BSMTP
+ bbs_sendmail(filename, save_title, receiver);
+#else
+ bsmtp(filename, save_title, receiver,0);
+#endif
+ }
+ clear();
+ outs(
+ "\n\n ®¥³ß±zÂIºq§¹¦¨Åo..\n"
+ " ¤@¤p®É¤º°ÊºA¬ÝªO·|¦Û°Ê­«·s§ó·s\n"
+ " ¤j®a´N¥i¥H¬Ý¨ì±zÂIªººqÅo\n\n"
+ " ÂIºq¦³¥ô¦ó°ÝÃD¥i¥H¨ìNoteªOªººëµØ°Ï§äµª®×\n"
+ " ¤]¥i¦bNoteªOºëµØ°Ï¬Ý¨ì¦Û¤vªºÂIºq°O¿ý\n"
+ " ¦³¥ô¦ó«O¶Qªº·N¨£¤]Åwªï¨ìNoteªO¯d¸Ü\n"
+ " Åý¿Ë¤ÁªºªO¥D¬°±zªA°È\n");
+ pressanykey();
+ sortsong();
+ topsong();
+
+ unlockutmpmode();
+ return 1;
+}
+
+int ordersong() {
+ osong(NULL);
+ return 0;
+}
+
+static int inmailbox(int m) {
+ passwd_query(usernum, &xuser);
+ cuser.exmailbox = xuser.exmailbox + m;
+ passwd_update(usernum, &cuser);
+ return cuser.exmailbox;
+}
+
+
+extern int b_lines;
+
+#if !HAVE_FREECLOAK
+/* ªá¿ú¿ï³æ */
+int p_cloak() {
+ char buf[4];
+ getdata(b_lines-1, 0,
+ currutmp->invisible ? "½T©w­n²{¨­?[y/N]" : "½T©w­nÁô¨­?[y/N]",
+ buf, 3, LCECHO);
+ if(buf[0] != 'y')
+ return 0;
+ if(cuser.money >= 19) {
+ vice(19, "cloak");
+ currutmp->invisible %= 2;
+ outs((currutmp->invisible ^= 1) ? MSG_CLOAKED : MSG_UNCLOAK);
+ refresh();
+ safe_sleep(1);
+ }
+ return 0;
+}
+#endif
+
+int p_from() {
+ char ans[4];
+
+ getdata(b_lines-2, 0, "½T©w­n§ï¬G¶m?[y/N]", ans, 3, LCECHO);
+ if(ans[0] != 'y')
+ return 0;
+ reload_money();
+ if(cuser.money < 49)
+ return 0;
+ if(getdata_buf(b_lines-1, 0, "½Ð¿é¤J·s¬G¶m:",
+ currutmp->from, 17, DOECHO)) {
+ vice(49,"home");
+ currutmp->from_alias=0;
+ }
+ return 0;
+}
+
+int p_exmail() {
+ char ans[4],buf[200];
+ int n;
+
+ if(cuser.exmailbox >= MAX_EXKEEPMAIL) {
+ sprintf(buf,"®e¶q³Ì¦h¼W¥[ %d «Ê¡A¤£¯à¦A¶R¤F¡C", MAX_EXKEEPMAIL);
+ outs(buf);
+ refresh();
+ return 0;
+ }
+ sprintf(buf,"±z´¿¼WÁÊ %d «Ê®e¶q¡AÁÙ­n¦A¶R¦h¤Ö?",
+ cuser.exmailbox);
+
+ getdata_str(b_lines-2, 0, buf, ans, 3, LCECHO, "10");
+
+ n = atoi(ans);
+ if(!ans[0] || !n)
+ return 0;
+ if(n + cuser.exmailbox > MAX_EXKEEPMAIL)
+ n = MAX_EXKEEPMAIL - cuser.exmailbox;
+ reload_money();
+ if(cuser.money < n * 1000)
+ return 0;
+ vice(n * 1000, "mail");
+ inmailbox(n);
+ return 0;
+}
+
+void mail_redenvelop(char* from, char* to, int money, char mode){
+ char genbuf[200];
+ fileheader_t fhdr;
+ time_t now;
+ FILE* fp;
+ sprintf(genbuf, "home/%c/%s", to[0], to);
+ stampfile(genbuf, &fhdr);
+ if (!(fp = fopen(genbuf, "w")))
+ return;
+ now = time(NULL);
+ fprintf(fp, "§@ªÌ: %s\n"
+ "¼ÐÃD: ©Û°]¶iÄ_\n"
+ "®É¶¡: %s\n"
+ "\033[1;33m¿Ë·Rªº %s ¡G\n\n\033[m"
+ "\033[1;31m §Ú¥]µ¹§A¤@­Ó %d ¤¸ªº¤j¬õ¥]³á ^_^\n\n"
+ " §»´±¡·N­«¡A½Ð¯º¯Ç...... ^_^\033[m\n"
+ , from, ctime(&now), to, money);
+ fclose(fp);
+ sprintf(fhdr.title, "©Û°]¶iÄ_");
+ strcpy(fhdr.owner, from);
+
+ if (mode == 'y')
+ vedit(genbuf, NA, NULL);
+ sprintf(genbuf, "home/%c/%s/.DIR", to[0], to);
+ append_record(genbuf, &fhdr, sizeof(fhdr));
+}
+
+int p_give() {
+ int money;
+ char id[IDLEN + 1], genbuf[90];
+ time_t now = time(0);
+
+ move(1,0);
+ usercomplete("³o¦ì©¯¹B¨àªºid:", id);
+ if(!id[0] || !strcmp(cuser.userid,id) ||
+ !getdata(2, 0, "­nµ¹¦h¤Ö¿ú:", genbuf, 7, LCECHO))
+ return 0;
+ money = atoi(genbuf);
+ reload_money();
+ if(money > 0 && cuser.money >= money ) {
+ deumoney(searchuser(id), money);
+ demoney(-money);
+ now = time(NULL);
+ sprintf(genbuf,"%s\tµ¹%s\t%d\t%s", cuser.userid, id, money,
+ ctime(&now));
+ log_file(FN_MONEY, genbuf);
+ genbuf[0] = 'n';
+ getdata(3, 0, "­n¦Û¦æ®Ñ¼g¬õ¥]³U¶Ü¡H[y/N]", genbuf, 2, LCECHO);
+ mail_redenvelop(cuser.userid, id, money, genbuf[0]);
+ }
+ return 0;
+}
+
+int p_sysinfo() {
+ char buf[100];
+ long int total,used;
+ float p;
+
+ move(b_lines-1,0);
+ clrtoeol();
+ cpuload(buf);
+ outs("CPU ­t²ü : ");
+ outs(buf);
+
+ p = swapused(&total,&used);
+ sprintf(buf, " µêÀÀ°O¾ÐÅé: %.1f%%(¥þ³¡:%ldMB ¥Î±¼:%ldMB)\n",
+ p*100, total >> 20, used >> 20);
+ outs(buf);
+ pressanykey();
+ return 0;
+}
+
+/* ¤p­pºâ¾÷ */
+static void ccount(float *a, float b, int cmode) {
+ switch(cmode) {
+ case 0:
+ case 1:
+ case 2:
+ *a += b;
+ break;
+ case 3:
+ *a -= b;
+ break;
+ case 4:
+ *a *= b;
+ break;
+ case 5:
+ *a /= b;
+ break;
+ }
+}
+
+int cal() {
+ float a = 0;
+ char flo = 0, ch = 0;
+ char mode[6] = {' ','=','+','-','*','/'} , cmode = 0;
+ char buf[100] = "[ 0] [ ] ", b[20] = "0";
+
+ move(b_lines - 1, 0);
+ clrtoeol();
+ outs(buf);
+ move(b_lines, 0);
+ clrtoeol();
+ outs("\033[44m ¤p­pºâ¾÷ \033[31;47m (0123456789+-*/=) "
+ "\033[30m¿é¤J \033[31m "
+ "(Q)\033[30m Â÷¶} \033[m");
+ while(1) {
+ ch = igetch();
+ switch(ch) {
+ case '\r':
+ ch = '=';
+ case '=':
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ ccount(&a, atof(b), cmode);
+ flo = 0;
+ b[0] = '0';
+ b[1] = 0;
+ move(b_lines - 1, 0);
+ sprintf(buf, "[%13.2f] [%c] ", a, ch);
+ outs(buf);
+ break;
+ case '.':
+ if(!flo)
+ flo = 1;
+ else
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '0':
+ if(strlen(b) > 13)
+ break;
+ if(flo || b[0] != '0')
+ sprintf(b,"%s%c",b,ch);
+ else
+ b[0]=ch;
+ move(b_lines - 1, 0);
+ sprintf(buf, "[%13s] [%c]", b, mode[(int)cmode]);
+ outs(buf);
+ break;
+ case 'q':
+ return 0;
+ }
+
+ switch(ch) {
+ case '=':
+ a = 0;
+ cmode = 0;
+ break;
+ case '+':
+ cmode = 2;
+ break;
+ case '-':
+ cmode = 3;
+ break;
+ case '*':
+ cmode = 4;
+ break;
+ case '/':
+ cmode = 5;
+ break;
+ }
+ }
+}
diff --git a/mbbsd/calendar.c b/mbbsd/calendar.c
new file mode 100644
index 00000000..78ca46cf
--- /dev/null
+++ b/mbbsd/calendar.c
@@ -0,0 +1,284 @@
+/* $Id: calendar.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "proto.h"
+#include "modes.h"
+
+typedef struct event_t {
+ int year, month, day, days;
+ int color;
+ char *content;
+ struct event_t *next;
+} event_t;
+
+static int MonthDay(int m, int leap) {
+ static int day[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+ return leap && m == 2 ? 29 : day[m - 1];
+}
+
+static int IsLeap(int y) {
+ if(y % 400 == 0 || (y % 4 == 0 && y % 100 != 0))
+ return 1;
+ else
+ return 0;
+}
+
+static int Days(int y, int m, int d) {
+ int i, w;
+
+ w = 1 + 365 * (y - 1)
+ + ((y - 1) / 4) - ((y - 1) / 100) + ((y - 1) / 400)
+ + d - 1;
+ for(i = 1; i < m; i++)
+ w += MonthDay(i, IsLeap(y));
+ return w;
+}
+
+static int ParseDate(char *date, event_t *t) {
+ char *y, *m, *d;
+
+ y = strtok(date, "/");
+ m = strtok(NULL, "/");
+ d = strtok(NULL, "");
+ if(!y || !m || !d)
+ return 1;
+
+ t->year = atoi(y);
+ t->month = atoi(m);
+ t->day = atoi(d);
+ if(t->year < 1 || t->month < 1 || t->month > 12 ||
+ t->day < 1 || t->day > 31)
+ return 1;
+ t->days = Days(t->year, t->month, t->day);
+ return 0;
+}
+
+static int ParseColor(char *color) {
+ struct {
+ char *str;
+ int val;
+ } c[] = {
+ {"black", 0},
+ {"red", 1},
+ {"green", 2},
+ {"yellow", 3},
+ {"blue", 4},
+ {"magenta", 5},
+ {"cyan", 6},
+ {"white", 7}
+ };
+ int i;
+
+ for(i = 0; i < sizeof(c) / sizeof(c[0]); i++)
+ if(strcasecmp(color, c[i].str) == 0)
+ return c[i].val;
+ return 7;
+}
+
+static void InsertEvent(event_t *head, event_t *t) {
+ event_t *p;
+
+ for(p = head; p->next && p->next->days < t->days; p = p->next);
+ t->next = p->next;
+ p->next = t;
+}
+
+static void FreeEvent(event_t *e) {
+ event_t *n;
+
+ while(e) {
+ n = e->next;
+ free(e);
+ e = n;
+ }
+}
+
+extern userec_t cuser;
+
+static event_t *ReadEvent(int today) {
+ FILE *fp;
+ char buf[256];
+ static event_t head;
+
+ head.next = NULL;
+ setcalfile(buf, cuser.userid);
+ fp = fopen(buf, "r");
+ if(fp) {
+ while(fgets(buf, sizeof(buf), fp)) {
+ char *date, *color, *content;
+ event_t *t;
+
+ if(buf[0] == '#')
+ continue;
+
+ date = strtok(buf, " \t\n");
+ color = strtok(NULL, " \t\n");
+ content = strtok(NULL, "\n");
+ if(!date || !color || !content)
+ continue;
+
+ t = malloc(sizeof(event_t));
+ if(ParseDate(date, t) || t->days < today) {
+ free(t);
+ continue;
+ }
+ t->color = ParseColor(color) + 30;
+ for(; *content == ' ' || *content == '\t'; content++);
+ t->content = strdup(content);
+ InsertEvent(&head, t);
+ }
+ fclose(fp);
+ }
+ return head.next;
+}
+
+static char **AllocCalBuffer(int line, int len) {
+ int i;
+ char **p;
+
+ p = malloc(sizeof(char *) * line);
+ p[0] = malloc(sizeof(char) * line * len);
+ for(i = 1; i < line; i++)
+ p[i] = p[i - 1] + len;
+ return p;
+}
+
+static void FreeCalBuffer(char **buf) {
+ free(buf[0]);
+ free(buf);
+}
+
+#define CALENDAR_COLOR "\33[0;30;47m"
+#define HEADER_COLOR "\33[1;44m"
+#define HEADER_SUNDAY_COLOR "\33[31m"
+#define HEADER_DAY_COLOR "\33[33m"
+
+static int GenerateCalendar(char **buf, int y, int m, int today, event_t *e) {
+ static char *week_str[7] = {"¤é", "¤@", "¤G", "¤T", "¥|", "¤­", "¤»"};
+ static char *month_color[12] = {
+ "\33[1;32m", "\33[1;33m", "\33[1;35m", "\33[1;36m",
+ "\33[1;32m", "\33[1;33m", "\33[1;35m", "\33[1;36m",
+ "\33[1;32m", "\33[1;33m", "\33[1;35m", "\33[1;36m"
+ };
+ static char *month_str[12] = {
+ "¤@¤ë ", "¤G¤ë ", "¤T¤ë ", "¥|¤ë ", "¤­¤ë ", "¤»¤ë ",
+ "¤C¤ë ", "¤K¤ë ", "¤E¤ë ", "¤Q¤ë ", "¤Q¤@¤ë", "¤Q¤G¤ë"
+ };
+
+ char *p, attr1[16], *attr2;
+ int i, d, w, line = 0, first_day = Days(y, m, 1);
+
+
+ /* week day banner */
+ p = buf[line];
+ p += sprintf(p, " %s%s%s%s", HEADER_COLOR, HEADER_SUNDAY_COLOR,
+ week_str[0], HEADER_DAY_COLOR);
+ for(i = 1; i < 7; i++)
+ p += sprintf(p, " %s", week_str[i]);
+ p += sprintf(p, "\33[m");
+
+ /* indent for first line */
+ p = buf[++line];
+ p += sprintf(p, " %s", CALENDAR_COLOR);
+ for(i = 0, w = first_day % 7; i < w; i++)
+ p += sprintf(p, " ");
+
+ /* initial event */
+ for(; e && e->days < first_day; e = e->next);
+
+ d = MonthDay(m, IsLeap(y));
+ for(i = 1; i <= d; i++, w = (w + 1) % 7) {
+ attr1[0] = 0;
+ attr2 = "";
+ while(e && e->days == first_day + i - 1) {
+ sprintf(attr1, "\33[1;%dm", e->color);
+ attr2 = CALENDAR_COLOR;
+ e = e->next;
+ }
+ if(today == first_day + i - 1) {
+ strcpy(attr1, "\33[1;37;42m");
+ attr2 = CALENDAR_COLOR;
+ }
+ p += sprintf(p, "%s%2d%s", attr1, i, attr2);
+
+ if(w == 6) {
+ p += sprintf(p, "\33[m");
+ p = buf[++line];
+ /* show month */
+ if(line >= 2 && line <= 4)
+ p += sprintf(p, "%s%2.2s\33[m %s", month_color[m - 1],
+ month_str[m - 1] + (line - 2) * 2,
+ CALENDAR_COLOR);
+ else if(i < d)
+ p += sprintf(p, " %s", CALENDAR_COLOR);
+ } else
+ *p++ = ' ';
+ }
+
+ /* fill up the last line */
+ if(w) {
+ for(w = 7 - w; w; w--)
+ p += sprintf(p, w == 1 ? " " : " ");
+ p += sprintf(p, "\33[m");
+ }
+ return line + 1;
+}
+
+int calendar() {
+ char **buf;
+ time_t t;
+ struct tm now;
+ int i, y, m, today, lines = 0;
+ event_t *head = NULL, *e = NULL;
+
+ /* initialize date */
+ time(&t);
+ memcpy(&now, localtime(&t), sizeof(struct tm));
+ today = Days(now.tm_year + 1900, now.tm_mon + 1, now.tm_mday);
+ y = now.tm_year + 1900, m = now.tm_mon + 1;
+
+ /* read event */
+ head = e = ReadEvent(today);
+
+ /* generate calendar */
+ buf = AllocCalBuffer(22, 256);
+ for(i = 0; i < 22; i++)
+ sprintf(buf[i], "%24s", "");
+ for(i = 0; i < 3; i++) {
+ lines += GenerateCalendar(buf + lines, y, m, today, e) + 1;
+ if(m == 12)
+ y++, m = 1;
+ else
+ m++;
+ }
+
+ /* output */
+ clear();
+ outc('\n');
+ for(i = 0; i < 22; i++) {
+ outs(buf[i]);
+ if(i == 0) {
+ prints("\t\33[1;37m²{¦b¬O %d.%02d.%02d %2d:%02d:%02d%cm\33[m",
+ now.tm_year + 1900, now.tm_mon + 1, now.tm_mday,
+ (now.tm_hour == 0 || now.tm_hour == 12) ?
+ 12 : now.tm_hour % 12, now.tm_min, now.tm_sec,
+ now.tm_hour >= 12 ? 'p' : 'a');
+ } else if(i >= 2 && e) {
+ prints("\t\33[1;37m(\33[%dm%3d\33[37m)\33[m %02d/%02d %s",
+ e->color, e->days - today,
+ e->month, e->day, e->content);
+ e = e->next;
+ }
+ outc('\n');
+ }
+ FreeEvent(head);
+ FreeCalBuffer(buf);
+ pressanykey();
+ return 0;
+}
diff --git a/mbbsd/card.c b/mbbsd/card.c
new file mode 100644
index 00000000..cfa10b0c
--- /dev/null
+++ b/mbbsd/card.c
@@ -0,0 +1,625 @@
+/* $Id: card.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "modes.h"
+#include "proto.h"
+extern int usernum;
+
+static int card_remain(int cards[]) {
+ int i, temp = 0;
+
+ for(i = 0; i < 52; i++)
+ temp += cards[i];
+ if(temp == 52)
+ return 1;
+ return 0;
+}
+
+/* 0 Spare , 1 heart , ...3 dimon */
+static int card_flower(int card) {
+ return (card / 13);
+}
+
+/* 1...13 */
+static int card_number(int card) {
+ return (card % 13 + 1);
+}
+
+static int card_select(int *now) {
+ char *cc[2] = {"\033[44m \033[m",
+ "\033[1;33;41m ¡µ \033[m"};
+
+ while(1) {
+ move(20, 0);
+ clrtoeol();
+ prints("%s%s%s%s%s", (*now == 0) ? cc[1] : cc[0],
+ (*now == 1) ? cc[1] : cc[0],
+ (*now == 2) ? cc[1] : cc[0],
+ (*now == 3) ? cc[1] : cc[0],
+ (*now == 4) ? cc[1] : cc[0]);
+ switch(egetch()) {
+ case 'Q':
+ case 'q':
+ return 0;
+ case '+':
+ case ',':
+ return 1;
+ case '\r':
+ return -1;
+ case KEY_LEFT:
+ *now = (*now + 4) % 5;
+ break;
+ case KEY_RIGHT:
+ *now = (*now + 1) % 5;
+ break;
+ case '1':
+ *now = 0;
+ break;
+ case '2':
+ *now = 1;
+ break;
+ case '3':
+ *now = 2;
+ break;
+ case '4':
+ *now = 3;
+ break;
+ case '5':
+ *now = 4;
+ break;
+ }
+ }
+}
+
+static void card_display(int cline, int number, int flower, int show) {
+ int color = 31;
+ char *cn[13] = {"¢Ï", "¢±", "¢²", "¢³", "¢´", "¢µ",
+ "¢¶", "¢·", "¢¸", "10", "¢Ø", "¢ß", "¢Ù"};
+ if(flower == 0 || flower == 3)
+ color = 36;
+ if((show < 0) && (cline > 1 && cline < 8))
+ prints("¢x\033[1;33;42m¡°¡°¡°¡°\033[m¢x");
+ else
+ switch(cline) {
+ case 1:
+ prints("¢~¢w¢w¢w¢w¢¡");
+ break;
+ case 2:
+ prints("¢x\033[1;%dm%s\033[m ¢x", color, cn[number - 1]);
+ break;
+ case 3:
+ if(flower == 1)
+ prints("¢x\033[1;%dm¢¨¢©¢¨¢©\033[m¢x", color);
+ else
+ prints("¢x\033[1;%dm ¢¨¢© \033[m¢x", color);
+ break;
+ case 4:
+ if(flower == 1)
+ prints("¢x\033[1;%dm¢i¢i¢i¢i\033[m¢x", color);
+ else if (flower == 3)
+ prints("¢x\033[1;%dm¢©¢i¢i¢¨\033[m¢x", color);
+ else
+ prints("¢x\033[1;%dm¢¨¢i¢i¢©\033[m¢x", color);
+ break;
+ case 5:
+ if(flower == 0)
+ prints("¢x\033[1;%dm¢i¢i¢i¢i\033[m¢x", color);
+ else if (flower == 3)
+ prints("¢x\033[1;%dm¢i¢ª¢«¢i\033[m¢x", color);
+ else
+ prints("¢x\033[1;%dm¢ª¢i¢i¢«\033[m¢x", color);
+ break;
+ case 6:
+ if(flower == 0)
+ prints("¢x\033[1;%dm ¢¨¢© \033[m¢x", color);
+ else if (flower == 3)
+ prints("¢x\033[1;%dm¢ª¢¨¢©¢«\033[m¢x", color);
+ else
+ prints("¢x\033[1;%dm ¢ª¢« \033[m¢x", color);
+ break;
+ case 7:
+ prints("¢x \033[1;%dm%s\033[m¢x", color, cn[number - 1]);
+ break;
+ case 8:
+ prints("¢¢¢w¢w¢w¢w¢£");
+ break;
+ }
+}
+
+static void card_show(int cpu[], int c[], int me[], int m[]) {
+ int i, j;
+
+ for(j = 0; j < 8; j++) {
+ move(2 + j, 0);
+ clrtoeol();
+ for(i = 0; i < 5 && cpu[i] >= 0; i++)
+ card_display(j + 1, card_number(cpu[i]),
+ card_flower(cpu[i]), c[i]);
+ }
+
+ for(j = 0; j < 8; j++) {
+ move(11 + j, 0);
+ clrtoeol();
+ for(i = 0; i < 5 && me[i] >= 0; i++)
+ card_display(j + 1, card_number(me[i]), card_flower(me[i]), m[i]);
+ }
+}
+static void card_new(int cards[]) {
+ memset(cards, 0, sizeof(int)*52);
+}
+
+static int card_give(int cards[]) {
+ int i, error;
+ for(error=0, i=rand()%52; cards[i] == 1 && error<52; error++, i=rand()%52);
+ if(error==52) card_new(cards); // Ptt:³oÃ䦳dead lock°ÝÃD
+ cards[i] = 1;
+ return i;
+}
+
+static void card_start(char name[]) {
+ clear();
+ stand_title(name);
+ move(1, 0);
+ prints(" \033[1;33;41m ¹q ¸£ \033[m");
+ move(10, 0);
+ prints("\033[1;34;44m¡»¡ã¡»¡ã¡»¡ã¡»¡ã¡»¡ã¡»¡ã¡»¡ã¡»¡ã¡»¡ã¡»¡ã¡»¡ã¡»¡ã"
+ "¡»¡ã¡»¡ã¡»¡ã¡»¡ã¡»¡ã¡»¡ã¡»¡ã¡»\033[m");
+ move(19, 0);
+ prints(" \033[1;37;42m ¦Û ¤v \033[m");
+}
+
+static int card_99_add(int i, int aom, int count) {
+ if (i == 4 || i == 5 || i == 11)
+ return count;
+ else if(i == 12)
+ return count + 20 * aom;
+ else if(i == 10)
+ return count + 10 * aom;
+ else if(i == 13)
+ return 99;
+ else
+ return count + i;
+}
+
+static int card_99_cpu(int cpu[], int *count) {
+ int stop = -1;
+ int twenty = -1;
+ int ten = -1;
+ int kill = -1;
+ int temp, num[10];
+ int other = -1;
+ int think = 99-(*count);
+ int i, j;
+
+ for(i = 0; i < 10; i++)
+ num[i] = -1;
+ for(i = 0; i < 5; i++) {
+ temp = card_number(cpu[i]);
+ if(temp == 4 || temp == 5 || temp == 11)
+ stop = i;
+ else if(temp == 12)
+ twenty = i;
+ else if (temp == 10)
+ ten = i;
+ else if (temp == 13)
+ kill = i;
+ else {
+ other = i;
+ num[temp] = i;
+ }
+ }
+ for(j = 9; j > 0; j--)
+ if(num[j] >= 0 && j != 4 && j != 5 && think >= j) {
+ (*count) += j;
+ return num[j];
+ }
+ if((think >= 20) && (twenty >= 0)) {
+ (*count) += 20;
+ return twenty;
+ } else if((think >= 10) && (ten >= 0)) {
+ (*count) += 10;
+ return ten;
+ } else if(stop >= 0)
+ return stop;
+ else if (kill >= 0) {
+ (*count) = 99;
+ return kill;
+ } else if(ten >= 0) {
+ (*count) -= 10;
+ return ten;
+ } else if(twenty >= 0) {
+ (*count) -= 20;
+ return twenty;
+ } else {
+ (*count) += card_number(cpu[0]);
+ return 0;
+ }
+}
+
+int card_99() {
+ int i, j, turn;
+ int cpu[5], c[5], me[5], m[5];
+ int cards[52];
+ int count = 0;
+ char *ff[4] = {"\033[1;36m¶Â®ç", "\033[1;31m¬õ¤ß",
+ "\033[1;31m¤è¶ô", "\033[1;36m¶Âªá"};
+ char *cn[13] = {"¢Ï", "¢±", "¢²", "¢³", "¢´", "¢µ",
+ "¢¶", "¢·", "¢¸", "10", "¢Ø", "¢ß", "¢Ù"};
+ for(i = 0; i < 5; i++)
+ cpu[i] = c[i] = me[i] = m[i] = -1;
+ setutmpmode(CARD_99);
+ card_start("¤Ñªø¦a¤[");
+ card_new(cards);
+ for(i = 0; i < 5; i++) {
+ cpu[i] = card_give(cards);
+ me[i] = card_give(cards);
+ m[i] = 1;
+ }
+ card_show(cpu, c, me, m);
+ j = 0;
+ turn = 1;
+ move(21, 0);
+ clrtoeol();
+ prints("[0]¥Ø«e %d , ´Ý %d ÂI\n", count, 99 - count);
+ prints("¥ª¥kÁä²¾°Ê´å¼Ð, [Enter]½T©w, [ + ]ªí¥[¤G¤Q(¥[¤Q), [Q/q]©ñ±ó¹CÀ¸");
+ while(1) {
+ i = card_select(&j);
+ if(i == 0) /*©ñ±ó¹CÀ¸*/
+ return 0;
+ count = card_99_add(card_number(me[j]), i, count);
+ move(21 + (turn / 2) % 2, 0);
+ clrtoeol();
+ prints("[%d]±z¥X %s%s\033[m ¥Ø«e \033[1;31m%d/\033[34m%d\033[m ÂI",
+ turn, ff[card_flower(me[j])],
+ cn[card_number(me[j]) - 1], count, 99 - count);
+ me[j] = card_give(cards);
+ turn++;
+ if(count < 0)
+ count = 0;
+ card_show(cpu, c, me, m);
+ pressanykey();
+ if(count > 99) {
+ move(22, 0);
+ clrtoeol();
+ prints("[%d]µ²ªG..YOU LOSS..¥Ø«e \033[1;31m%d/\033[34m%d\033[m ÂI",
+ turn, count, 99 - count);
+ pressanykey();
+ return 0;
+ }
+ i = card_99_cpu(cpu, &count);
+ move(21 + (turn / 2 + 1) % 2, 40);
+ prints("[%d]¹q¸£¥X %s%s\033[m ¥Ø«e \033[1;31m%d/\033[34m%d\033[m ÂI",
+ turn, ff[card_flower(cpu[i])],
+ cn[card_number(cpu[i]) - 1], count, 99 - count);
+ cpu[i] = card_give(cards);
+ turn++;
+ if(count < 0)
+ count = 0;
+ if(count > 99) {
+ move(22, 0);
+ clrtoeol();
+ prints("[%d]µ²ªG..YOU WIN!..¥Ø«e \033[1;31m%d/\033[34m%d\033[m ÂI",
+ turn, count, 99 - count);
+ pressanykey();
+ return 0;
+ }
+ if(!card_remain(cards)) {
+ card_new(cards);
+ for(i = 0; i < 5; i++) {
+ cards[me[i]] = 1;
+ cards[cpu[i]] = 1;
+ }
+ }
+ }
+}
+
+#define PMONEY (10)
+#define TEN_HALF (5) /*¤QÂI¥bªºTicket*/
+#define JACK (10) /*¶Â³Ç§JªºTicket*/
+#define NINE99 (99) /*99 ªºTicket*/
+
+extern userec_t cuser;
+
+static int game_log(int type, int money) {
+ FILE *fp;
+
+ if(money > 0)
+ demoney(money);
+
+ switch(type) {
+ case JACK:
+ fp = fopen(BBSHOME "/etc/card/jack.log", "a");
+ if(!fp)
+ return 0;
+ fprintf(fp, "%s win:%d\n", cuser.userid, money);
+ fclose(fp);
+ break;
+ case TEN_HALF:
+ fp = fopen(BBSHOME "/etc/card/tenhalf.log", "a");
+ if(!fp)
+ return 0;
+ fprintf(fp, "%s win:%d\n", cuser.userid, money);
+ fclose(fp);
+ break;
+ }
+ return 0;
+}
+
+static int card_double_ask() {
+ char buf[100], buf2[3];
+
+ sprintf(buf, "[ %s ]±z²{¦b¦@¦³ %d P¹ô, ²{¦b­n¤À²Õ(¥[¦¬ %d ¤¸)¶Ü? [y/N]",
+ cuser.userid, cuser.money, JACK);
+ reload_money();
+ if(cuser.money < JACK)
+ return 0;
+ getdata(20, 0, buf, buf2, 2, LCECHO);
+ if(buf2[0] == 'y' || buf2[0] == 'Y')
+ return 1;
+ return 0;
+}
+
+static int card_ask() {
+ char buf[100], buf2[3];
+
+ sprintf(buf, "[ %s ]±z²{¦b¦@¦³ %d P¹ô, ÁÙ­n¥[µP¶Ü? [y/N]",
+ cuser.userid, cuser.money);
+ getdata(20, 0 , buf, buf2, 2, LCECHO);
+ if(buf2[0] == 'y' || buf2[0] == 'Y')
+ return 1;
+ return 0;
+}
+
+static int card_alls_lower(int all[]) {
+ int i, count = 0;
+ for (i = 0; i < 5 && all[i] >= 0; i++)
+ if(card_number(all[i]) <= 10)
+ count += card_number(all[i]);
+ else
+ count += 10;
+ return count;
+}
+
+static int card_alls_upper(int all[]) {
+ int i, count;
+
+ count = card_alls_lower(all);
+ for (i = 0; i < 5 && all[i] >= 0 && count <= 11; i++)
+ if (card_number(all[i]) == 1)
+ count += 10;
+ return count;
+}
+
+extern int b_lines;
+
+static int card_jack(int *db) {
+ int i, j;
+ int cpu[5], c[5], me[5], m[5];
+ int cards[52];
+
+ for(i = 0;i<5;i++)
+ cpu[i] = c[i] = me[i] = m[i] = -1;
+
+ if((*db)<0) {
+ card_new(cards);
+ card_start("¶Â³Ç§J");
+ for(i = 0; i < 2; i++) {
+ cpu[i] = card_give(cards);
+ me[i] = card_give(cards);
+ }
+ } else {
+ card_start("¶Â³Ç§JDOUBLE°l¥[§½");
+ cpu[0] = card_give(cards);
+ cpu[1] = card_give(cards);
+ me[0] = *db;
+ me[1] = card_give(cards);
+ }
+ c[1] = m[0] = m[1] = 1;
+ card_show(cpu, c, me, m);
+ if((card_number(me[0]) == 0 && card_number(me[1]) == 12) ||
+ (card_number(me[1]) == 0 && card_number(me[0]) == 12)) {
+ if(card_flower(me[0]) == 0 && card_flower(me[1]) == 0) {
+ move(b_lines - 1, 0);
+ prints("«D±`¤£¿ù­ò! (¶W¯Å¶Â³Ç§J!! ¥[ %d ¤¸)", JACK * 10);
+ game_log(JACK, JACK * 10);
+ pressanykey();
+ return 0;
+ } else {
+ move(b_lines - 1, 0);
+ prints("«Ü¤£¿ù­ò! (¶Â³Ç§J!! ¥[ %d ¤¸)", JACK * 5);
+ game_log(JACK, JACK * 5);
+ pressanykey();
+ return 0;
+ }
+ }
+ if((card_number(cpu[0]) == 0 && card_number(cpu[1]) == 12) ||
+ (card_number(cpu[1]) == 0 && card_number(cpu[0]) == 12)) {
+ c[0] = 1;
+ card_show(cpu, c, me, m);
+ move(b_lines - 1, 0);
+ prints("¼K¼K...¤£¦n·N«ä....¶Â³Ç§J!!");
+ game_log(JACK, 0);
+ pressanykey();
+ return 0;
+ }
+ if((*db < 0)&& (card_number(me[0]) == card_number(me[1])) &&
+ (card_double_ask())) {
+ *db = me[1];
+ me[1] = card_give(cards);
+ card_show(cpu, c, me, m);
+ }
+ i = 2;
+ while(i < 5 && card_ask()) {
+ me[i] = card_give(cards);
+ m[i] = 1;
+ card_show(cpu, c, me, m);
+ if(card_alls_lower(me) > 21) {
+ move(b_lines - 1, 0);
+ prints("¶ã¶ã...Ãz±¼¤F!");
+ game_log(JACK, 0);
+ pressanykey();
+ return 0;
+ }
+ i++;
+ if((i == 3) && (card_number(me[0]) == 7) &&
+ (card_number(me[1]) == 7) && (card_number(me[2]) == 7)) {
+ move(b_lines - 1, 0);
+ prints("«Ü¤£¿ù­ò! (©¯¹B¤C¸¹!! ¥[ %d ¤¸)", JACK * 7);
+ game_log(JACK, JACK * 7);
+ pressanykey();
+ return 0;
+ }
+ }
+ if(i == 5) {/*¹L¤­Ãö*/
+ move(b_lines - 1, 0);
+ prints("¦n¼F®`­ò! ¹L¤­Ãö¹Æ! ¥[P¹ô %d ¤¸!", 5 * JACK);
+ game_log(JACK, JACK * 5);
+ pressanykey();
+ return 0;
+ }
+ j = 2;
+ c[0] = 1;
+ while((card_alls_upper(cpu) < card_alls_upper(me))||
+ ((card_alls_upper(cpu) == card_alls_upper(me) && j < i ) && j < 5)) {
+ cpu[j] = card_give(cards);
+ c[j] = 1;
+ if(card_alls_lower(cpu) > 21) {
+ card_show(cpu, c, me, m);
+ move(b_lines - 1, 0);
+ prints("¨þ¨þ...¹q¸£Ãz±¼¤F! §AŤF! ¥i±oP¹ô %d ¤¸", JACK * 2);
+ game_log(JACK, JACK * 2);
+ pressanykey();
+ return 0;
+ }
+ j++;
+ }
+ card_show(cpu, c, me, m);
+ move(b_lines - 1, 0);
+ prints("«z«z...¹q¸£Ä¹¤F!");
+ game_log(JACK, 0);
+ pressanykey();
+ return 0;
+}
+
+int g_card_jack() {
+ int db;
+ char buf[3];
+
+ setutmpmode(JACK_CARD);
+ while(1) {
+ reload_money();
+ if(cuser.money < JACK) {
+ outs("±zªº¿ú¤£°÷­ò!¥h¦hµoªí¨Ç¦³·N¸qªº¤å³¹¦A¨Ó~~~");
+ return 0;
+ }
+ getdata(b_lines - 1, 0, "½T©w­nª±¶Â³Ç§J¶Ü ¤@¦¸¤Q¤¸­ò?(Y/N)?[N]",
+ buf, 3, LCECHO);
+ if((*buf != 'y') && (*buf != 'Y'))
+ break;
+ else {
+ db = -1;
+ vice(PMONEY, "¶Â³Ç§J");
+ card_jack(&db);
+ if(db >= 0)
+ card_jack(&db);
+ }
+ }
+ return 0;
+}
+
+static int card_all(int all[]) {
+ int i, count = 0;
+
+ for (i = 0; i < 5 && all[i] >= 0; i++)
+ if(card_number(all[i]) <= 10)
+ count += 2 * card_number(all[i]);
+ else
+ count += 1;
+ return count;
+}
+
+static int ten_helf() {
+ int i, j;
+ int cpu[5], c[5], me[5], m[5];
+ int cards[52];
+
+ card_start("¤QÂI¥b");
+ card_new(cards);
+ for (i = 0; i < 5; i++)
+ cpu[i] = c[i] = me[i] = m[i] = -1;
+
+ cpu[0] = card_give(cards);
+ me[0] = card_give(cards);
+ m[0] = 1;
+ card_show(cpu, c, me, m);
+ i = 1;
+ while(i < 5 && card_ask()) {
+ me[i] = card_give(cards);
+ m[i] = 1;
+ card_show(cpu, c, me, m);
+ if(card_all(me) > 21) {
+ move(b_lines - 1, 0);
+ prints("¶ã¶ã...Ãz±¼¤F!");
+ game_log(TEN_HALF, 0);
+ pressanykey();
+ return 0;
+ }
+ i++;
+ }
+ if(i == 5) {/*¹L¤­Ãö*/
+ move(b_lines - 1, 0);
+ prints("¦n¼F®`­ò! ¹L¤­Ãö¹Æ! ¥[P¹ô %d ¤¸!", 5 * PMONEY);
+ game_log(TEN_HALF, PMONEY * 5);
+ pressanykey();
+ return 0;
+ }
+ j = 1;
+ c[0] = 1;
+ while( j<5 && ((card_all(cpu) < card_all(me)) ||
+ (card_all(cpu) == card_all(me) && j < i))) {
+ cpu[j] = card_give(cards);
+ c[j] = 1;
+ if(card_all(cpu) > 21) {
+ card_show(cpu, c, me, m);
+ move(b_lines - 1, 0);
+ prints("¨þ¨þ...¹q¸£Ãz±¼¤F! §AŤF! ¥i±oP¹ô %d ¤¸", PMONEY * 2);
+ game_log(TEN_HALF, PMONEY * 2);
+ pressanykey();
+ return 0;
+ }
+ j++;
+ }
+ card_show(cpu, c, me, m);
+ move(b_lines - 1, 0);
+ prints("«z«z...¹q¸£Ä¹¤F!");
+ game_log(TEN_HALF, 0);
+ pressanykey();
+ return 0;
+}
+
+int g_ten_helf() {
+ char buf[3];
+
+ setutmpmode(TENHALF);
+ while(1) {
+ reload_money();
+ if(cuser.money < TEN_HALF) {
+ outs("±zªº¿ú¤£°÷­ò!¥h¦hµoªí¨Ç¦³·N¸qªº¤å³¹¦A¨Ó~~~");
+ return 0;
+ }
+ getdata(b_lines - 1, 0,
+ "\033[1;37m½T©w­nª±¤QÂI¥b¶Ü ¤@¦¸¤Q¤¸­ò?(Y/N)?[N]\033[m",
+ buf, 3, LCECHO);
+ if(buf[0] != 'y' && buf[0] != 'Y')
+ return 0;
+ else {
+ vice(PMONEY, "¤QÂI¥b");
+ ten_helf();
+ }
+ }
+ return 0;
+}
diff --git a/mbbsd/chat.c b/mbbsd/chat.c
new file mode 100644
index 00000000..f75383a8
--- /dev/null
+++ b/mbbsd/chat.c
@@ -0,0 +1,623 @@
+/* $Id: chat.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "perm.h"
+#include "common.h"
+#include "modes.h"
+#include "proto.h"
+
+extern userinfo_t *currutmp;
+static int chatline;
+static int stop_line; /* next line of bottom of message window area */
+static FILE *flog;
+
+static void printchatline(char *str) {
+ move(chatline, 0);
+ if(*str == '>' && !PERM_HIDE(currutmp))
+ return;
+ else if(chatline < stop_line - 1)
+ chatline++;
+ else {
+ region_scroll_up(2, stop_line - 2);
+ move(stop_line - 2, 0);
+ }
+ outs(str);
+ outc('\n');
+ outs("¡÷");
+
+ if(flog)
+ fprintf(flog, "%s\n", str);
+}
+
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+
+static void chat_clear() {
+ for(chatline = 2; chatline < stop_line; chatline++) {
+ move(chatline, 0);
+ clrtoeol();
+ }
+ move(b_lines, 0);
+ clrtoeol();
+ move(chatline = 2, 0);
+ outs("¡÷");
+}
+
+static void print_chatid(char *chatid) {
+ move(b_lines - 1, 0);
+ clrtoeol();
+ outs(chatid);
+ outc(':');
+}
+
+static int chat_send(int fd, char *buf) {
+ int len;
+ char genbuf[200];
+
+ sprintf(genbuf, "%s\n", buf);
+ len = strlen(genbuf);
+ return (send(fd, genbuf, len, 0) == len);
+}
+
+static char chatroom[IDLEN]; /* Chat-Room Name */
+
+static int chat_recv(int fd, char *chatid) {
+ static char buf[512];
+ static int bufstart = 0;
+ char genbuf[200];
+ int c, len;
+ char *bptr;
+
+ len = sizeof(buf) - bufstart - 1;
+ if((c = recv(fd, buf + bufstart, len, 0)) <= 0)
+ return -1;
+ c += bufstart;
+
+ bptr = buf;
+ while(c > 0) {
+ len = strlen(bptr) + 1;
+ if(len > c && len < (sizeof buf / 2))
+ break;
+
+ if(*bptr == '/') {
+ switch(bptr[1]) {
+ case 'c':
+ chat_clear();
+ break;
+ case 'n':
+ strncpy(chatid, bptr + 2, 8);
+ print_chatid(chatid);
+ clrtoeol();
+ break;
+ case 'r':
+ strncpy(chatroom, bptr + 2, IDLEN - 1);
+ break;
+ case 't':
+ move(0, 0);
+ clrtoeol();
+ sprintf(genbuf, "½Í¤Ñ«Ç [%s]", chatroom);
+ prints("\033[1;37;46m %-21s \033[45m ¸ÜÃD¡G%-48s\033[m",
+ genbuf, bptr + 2);
+ }
+ } else
+ printchatline(bptr);
+
+ c -= len;
+ bptr += len;
+ }
+
+ if(c > 0) {
+ strcpy(genbuf, bptr);
+ strcpy(buf, genbuf);
+ bufstart = len - 1;
+ } else
+ bufstart = 0;
+ return 0;
+}
+
+extern userec_t cuser;
+
+static int printuserent(userinfo_t *uentp) {
+ static char uline[80];
+ static int cnt;
+ char pline[30];
+
+ if(!uentp) {
+ if(cnt)
+ printchatline(uline);
+ bzero(uline, 80);
+ cnt = 0;
+ return 0;
+ }
+ if(!HAS_PERM(PERM_SYSOP) && !HAS_PERM(PERM_SEECLOAK) && uentp->invisible)
+ return 0;
+
+ sprintf(pline, "%-13s%c%-10s ", uentp->userid,
+ uentp->invisible ? '#' : ' ',
+ modestring(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 chathelp(char *cmd, char *desc) {
+ char buf[STRLEN];
+
+ sprintf(buf, " %-20s- %s", cmd, desc);
+ printchatline(buf);
+}
+
+static void chat_help(char *arg) {
+ if(strstr(arg, " op")) {
+ printchatline("½Í¤Ñ«ÇºÞ²z­û±M¥Î«ü¥O");
+ chathelp("[/f]lag [+-][ls]", "³]©wÂê©w¡B¯µ±Kª¬ºA");
+ chathelp("[/i]nvite <id>", "ÁܽР<id> ¥[¤J½Í¤Ñ«Ç");
+ chathelp("[/k]ick <id>", "±N <id> ½ð¥X½Í¤Ñ«Ç");
+ chathelp("[/o]p <id>", "±N Op ªºÅv¤OÂಾµ¹ <id>");
+ chathelp("[/t]opic <text>", "´«­Ó¸ÜÃD");
+ chathelp("[/w]all", "¼s¼½ (¯¸ªø±M¥Î)");
+ } else {
+ chathelp("[//]help", "MUD-like ªÀ¥æ°Êµü");
+ chathelp("[/.]help", "chicken °«Âû¥Î«ü¥O");
+ chathelp("[/h]elp op", "½Í¤Ñ«ÇºÞ²z­û±M¥Î«ü¥O");
+ chathelp("[/a]ct <msg>", "°µ¤@­Ó°Ê§@");
+ chathelp("[/b]ye [msg]", "¹D§O");
+ chathelp("[/c]lear", "²M°£¿Ã¹õ");
+ chathelp("[/j]oin <room>", "«Ø¥ß©Î¥[¤J½Í¤Ñ«Ç");
+ chathelp("[/l]ist [room]", "¦C¥X½Í¤Ñ«Ç¨Ï¥ÎªÌ");
+ chathelp("[/m]sg <id> <msg>", "¸ò <id> »¡®¨®¨¸Ü");
+ chathelp("[/n]ick <id>", "±N½Í¤Ñ¥N¸¹´«¦¨ <id>");
+ chathelp("[/p]ager", "¤Á´«©I¥s¾¹");
+ chathelp("[/q]uery", "¬d¸ßºô¤Í");
+ chathelp("[/r]oom", "¦C¥X¤@¯ë½Í¤Ñ«Ç");
+ chathelp("[/u]sers", "¦C¥X¯¸¤W¨Ï¥ÎªÌ");
+ chathelp("[/w]ho", "¦C¥X¥»½Í¤Ñ«Ç¨Ï¥ÎªÌ");
+ chathelp("[/w]hoin <room>", "¦C¥X½Í¤Ñ«Ç<room> ªº¨Ï¥ÎªÌ");
+ }
+}
+
+static void chat_date() {
+ time_t thetime;
+ char genbuf[200];
+
+ time(&thetime);
+ sprintf(genbuf, "¡» " BBSNAME "¼Ð·Ç®É¶¡: %s", Cdate(&thetime));
+ printchatline(genbuf);
+}
+
+static void chat_pager() {
+ char genbuf[200];
+
+ char *msgs[] = {"Ãö³¬", "¥´¶}", "©Þ±¼", "¨¾¤ô","¦n¤Í"};
+ sprintf(genbuf, "¡» ±zªº©I¥s¾¹:[%s]",
+ msgs[currutmp->pager = (currutmp->pager+1)%5]);
+ printchatline(genbuf);
+}
+
+extern char *str_space;
+extern userec_t xuser;
+extern char *fn_plans;
+extern char *err_uid;
+
+static void chat_query(char *arg) {
+ char *uid;
+ int tuid;
+
+ printchatline("");
+ strtok(arg, str_space);
+ if((uid = strtok(NULL, str_space)) && (tuid = getuser(uid))) {
+ char buf[128], *ptr;
+ FILE *fp;
+
+ sprintf(buf, "%s(%s) ¦@¤W¯¸ %d ¦¸¡Aµoªí¹L %d ½g¤å³¹",
+ xuser.userid, xuser.username, xuser.numlogins, xuser.numposts);
+ printchatline(buf);
+
+ sprintf(buf, "³Ìªñ(%s)±q[%s]¤W¯¸", Cdate(&xuser.lastlogin),
+ (xuser.lasthost[0] ? xuser.lasthost : "(¤£¸Ô)"));
+ printchatline(buf);
+
+ sethomefile(buf, xuser.userid, fn_plans);
+ if((fp = fopen(buf, "r"))) {
+ tuid = 0;
+ while(tuid++ < MAX_QUERYLINES && fgets(buf, 128, fp)) {
+ if((ptr = strchr(buf, '\n')))
+ ptr[0] = '\0';
+ printchatline(buf);
+ }
+ fclose(fp);
+ }
+ } else
+ printchatline(err_uid);
+}
+
+extern char *msg_shortulist;
+
+static void chat_users() {
+ printchatline("");
+ printchatline("¡i " BBSNAME "ªº¹C«È¦Cªí ¡j");
+ printchatline(msg_shortulist);
+
+ if(apply_ulist(printuserent) == -1)
+ printchatline("ªÅµL¤@¤H");
+ printuserent(NULL);
+}
+
+typedef struct chat_command_t {
+ char *cmdname; /* Chatroom command length */
+ void (*cmdfunc) (); /* Pointer to function */
+} chat_command_t;
+
+static chat_command_t chat_cmdtbl[] = {
+ {"help", chat_help},
+ {"clear", chat_clear},
+ {"date", chat_date},
+ {"pager", chat_pager},
+ {"query", chat_query},
+ {"users", chat_users},
+ {NULL, NULL}
+};
+
+static int chat_cmd_match(char *buf, char *str) {
+ while(*str && *buf && !isspace(*buf))
+ if(tolower(*buf++) != *str++)
+ return 0;
+ return 1;
+}
+
+static int chat_cmd(char *buf, int fd) {
+ int i;
+
+ if(*buf++ != '/')
+ return 0;
+
+ for(i = 0; chat_cmdtbl[i].cmdname; i++) {
+ if(chat_cmd_match(buf, chat_cmdtbl[i].cmdname)) {
+ chat_cmdtbl[i].cmdfunc(buf);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+extern char trans_buffer[256]; /* ¤@¯ë¶Ç»¼ÅÜ¼Æ add by Ptt */
+
+#if 0
+static char *select_address() {
+ int c;
+ FILE *fp;
+ char nametab[25][90];
+ char iptab[25][18], buf[80];
+
+ move(1, 0);
+ clrtobot();
+ outs("\n \033[36m¡i§ä­Ó¦a¤è©ï©ïºb§a!¡j\033[m "
+ "¡· ¡i¥H¤U¬°¥»¯¸µn°O¦³®×ªº¯ù¼Ó¡j \n");
+ trans_buffer[0]=0;
+ if((fp = fopen("etc/teashop", "r"))) {
+ for(c = 0; fscanf(fp, "%s%s", iptab[c], nametab[c]) != EOF; c++) {
+ sprintf(buf,"\n (\033[36m%d\033[0m) %-30s [%s]",
+ c + 1, nametab[c], iptab[c]);
+ outs(buf);
+ }
+ getdata(20, 10, "¡¹\033[32m ½Ð¿ï¾Ü¡A[0]Â÷¶}¡G\033[0m", buf, 3,
+ LCECHO);
+ if(buf[1])
+ buf[0] = (buf[0] + 1) * 10 + (buf[1] - '1');
+ else
+ buf[0] -= '1';
+ if(buf[0] >= 0 && buf[0] < c)
+ strcpy(trans_buffer,iptab[(int)buf[0]]);
+ } else {
+ outs("¥»¯¸¨S¦³µn°O¥ô¦ó¦X®æ¯ù¼Ó");
+ pressanykey();
+ }
+ return trans_buffer;
+}
+#endif
+
+extern int usernum;
+extern int t_lines;
+extern char *msg_seperator;
+#define MAXLASTCMD 6
+static int chatid_len = 10;
+
+int t_chat() {
+ char inbuf[80], chatid[20], lastcmd[MAXLASTCMD][80], *ptr = "";
+ struct sockaddr_in sin;
+ struct hostent *h;
+ int cfd, cmdpos, ch;
+ int currchar;
+ int newmail;
+ int chatting = YEA;
+ char fpath[80];
+ char genbuf[200];
+ char roomtype;
+
+ if(inbuf[0] == 0)
+ return -1;
+
+ outs(" ÅX¨®«e©¹ ½Ð±é­Ô........ ");
+ if(!(h = gethostbyname("localhost"))) {
+ perror("gethostbyname");
+ return -1;
+ }
+ memset(&sin, 0, sizeof sin);
+#ifdef FreeBSD
+ sin.sin_len = sizeof(sin);
+#endif
+ sin.sin_family = PF_INET;
+ memcpy(&sin.sin_addr, h->h_addr, h->h_length);
+ sin.sin_port = htons(NEW_CHATPORT);
+ cfd = socket(sin.sin_family, SOCK_STREAM, 0);
+ if(!(connect(cfd, (struct sockaddr *) & sin, sizeof sin)))
+ roomtype = 1;
+ else {
+ sin.sin_port = CHATPORT;
+ cfd = socket(sin.sin_family, SOCK_STREAM, 0);
+ if(!(connect(cfd, (struct sockaddr *) & sin, sizeof sin)))
+ roomtype = 2;
+ else {
+ outs("\n "
+ "«z! ¨S¤H¦b¨ºÃä­C...­n¦³¨º¦a¤èªº¤H¥ý¥h¶}ªù°Õ!...");
+ system("bin/xchatd");
+ pressanykey();
+ return -1;
+ }
+ }
+
+ while(1) {
+ getdata(b_lines - 1, 0, "½Ð¿é¤J²á¤Ñ¥N¸¹¡G", inbuf, 9, DOECHO);
+ sprintf(chatid, "%s", (inbuf[0] ? inbuf : cuser.userid));
+ chatid[8] = '\0';
+/*
+ ®榡: /! ¨Ï¥ÎªÌ½s¸¹ ¨Ï¥ÎªÌµ¥¯Å UserID ChatID
+ ·s®æ¦¡: /! UserID ChatID Password
+*/
+ if(roomtype == 1)
+ sprintf(inbuf, "/! %s %s %s",
+ cuser.userid, chatid, cuser.passwd);
+ else
+ sprintf(inbuf, "/! %d %d %s %s",
+ usernum, cuser.userlevel, cuser.userid, chatid);
+ chat_send(cfd, inbuf);
+ if(recv(cfd, inbuf, 3, 0) != 3)
+ return 0;
+ if(!strcmp(inbuf, CHAT_LOGIN_OK))
+ break;
+ else if(!strcmp(inbuf, CHAT_LOGIN_EXISTS))
+ ptr = "³o­Ó¥N¸¹¤w¸g¦³¤H¥Î¤F";
+ else if(!strcmp(inbuf, CHAT_LOGIN_INVALID))
+ ptr = "³o­Ó¥N¸¹¬O¿ù»~ªº";
+ else if(!strcmp(inbuf, CHAT_LOGIN_BOGUS))
+ ptr = "½Ð¤Å¬£»º¤À¨­¶i¤J²á¤Ñ«Ç !!";
+
+ move(b_lines - 2, 0);
+ outs(ptr);
+ clrtoeol();
+ bell();
+ }
+
+ add_io(cfd, 0);
+
+ newmail = currchar = 0;
+ cmdpos = -1;
+ memset(lastcmd, 0, MAXLASTCMD * 80);
+
+ setutmpmode(CHATING);
+ currutmp->in_chat = YEA;
+ strcpy(currutmp->chatid, chatid);
+
+ clear();
+ chatline = 2;
+ strcpy(inbuf, chatid);
+ stop_line = t_lines - 3;
+
+ move(stop_line, 0);
+ outs(msg_seperator);
+ move(1, 0);
+ outs(msg_seperator);
+ print_chatid(chatid);
+ memset(inbuf, 0, 80);
+
+ sethomepath(fpath, cuser.userid);
+ strcpy(fpath, tempnam(fpath, "chat_"));
+ flog = fopen(fpath, "w");
+
+ while(chatting) {
+ move(b_lines - 1, currchar + chatid_len);
+ ch = igetkey();
+
+ switch(ch) {
+ case KEY_DOWN:
+ cmdpos += MAXLASTCMD - 2;
+ case KEY_UP:
+ cmdpos++;
+ cmdpos %= MAXLASTCMD;
+ strcpy(inbuf, lastcmd[cmdpos]);
+ move(b_lines - 1, chatid_len);
+ clrtoeol();
+ outs(inbuf);
+ currchar = strlen(inbuf);
+ continue;
+ case KEY_LEFT:
+ if(currchar)
+ --currchar;
+ continue;
+ case KEY_RIGHT:
+ if(inbuf[currchar])
+ ++currchar;
+ continue;
+ }
+
+ if(!newmail && currutmp->mailalert ) {
+ newmail = 1;
+ printchatline("¡» ¾´¡I¶l®t¤S¨Ó¤F...");
+ }
+
+ if(ch == I_OTHERDATA) { /* incoming */
+ if(chat_recv(cfd, chatid) == -1) {
+ chatting = chat_send(cfd, "/b");
+ break;
+ }
+ continue;
+ }
+ if(isprint2(ch)) {
+ if(currchar < 68) {
+ if(inbuf[currchar]) { /* insert */
+ int i;
+
+ for(i = currchar; inbuf[i] && i < 68; i++);
+ inbuf[i + 1 ] = '\0';
+ for(; i > currchar; i--)
+ inbuf[i] = inbuf[i - 1];
+ } else /* append */
+ inbuf[currchar + 1] = '\0';
+ inbuf[currchar] = ch;
+ move(b_lines - 1, currchar + chatid_len);
+ outs(&inbuf[currchar++]);
+ }
+ continue;
+ }
+
+ if(ch == '\n' || ch == '\r') {
+ if(*inbuf) {
+ chatting = chat_cmd(inbuf, cfd);
+ if(chatting == 0)
+ chatting = chat_send(cfd, inbuf);
+ if(!strncmp(inbuf, "/b", 2))
+ break;
+
+ for(cmdpos = MAXLASTCMD - 1; cmdpos; cmdpos--)
+ strcpy(lastcmd[cmdpos], lastcmd[cmdpos - 1]);
+ strcpy(lastcmd[0], inbuf);
+
+ inbuf[0] = '\0';
+ currchar = 0;
+ cmdpos = -1;
+ }
+ print_chatid(chatid);
+ move(b_lines - 1, chatid_len);
+ continue;
+ }
+
+ if(ch == Ctrl('H') || ch == '\177') {
+ if(currchar) {
+ currchar--;
+ inbuf[69] = '\0';
+ memcpy(&inbuf[currchar], &inbuf[currchar + 1], 69 - currchar);
+ move(b_lines - 1, currchar + chatid_len);
+ clrtoeol();
+ outs(&inbuf[currchar]);
+ }
+ continue;
+ }
+ if(ch == Ctrl('Z') || ch == Ctrl('Y')) {
+ inbuf[0] = '\0';
+ currchar = 0;
+ print_chatid(chatid);
+ move(b_lines - 1, chatid_len);
+ continue;
+ }
+
+ if(ch == Ctrl('C')) {
+ chat_send(cfd, "/b");
+ break;
+ }
+ if(ch == Ctrl('D')) {
+ if(currchar < strlen(inbuf)) {
+ inbuf[69] = '\0';
+ memcpy(&inbuf[currchar], &inbuf[currchar + 1], 69 - currchar);
+ move(b_lines - 1, currchar + chatid_len);
+ clrtoeol();
+ outs(&inbuf[currchar]);
+ }
+ continue;
+ }
+ if(ch == Ctrl('K')) {
+ inbuf[currchar] = 0;
+ move(b_lines - 1, currchar + chatid_len);
+ clrtoeol();
+ continue;
+ }
+ if(ch == Ctrl('A')) {
+ currchar = 0;
+ continue;
+ }
+ if(ch == Ctrl('E')) {
+ currchar = strlen(inbuf);
+ continue;
+ }
+ if(ch == Ctrl('I')) {
+ extern screenline_t *big_picture;
+ screenline_t *screen0 = calloc(t_lines, sizeof(screenline_t));
+
+ memcpy(screen0, big_picture, t_lines * sizeof(screenline_t));
+ add_io(0, 0);
+ t_idle();
+ memcpy(big_picture, screen0, t_lines * sizeof(screenline_t));
+ free(screen0);
+ redoscr();
+ add_io(cfd, 0);
+ continue;
+ }
+ if(ch == Ctrl('Q')) {
+ print_chatid(chatid);
+ move(b_lines - 1, chatid_len);
+ outs(inbuf);
+ continue;
+ }
+ }
+
+ close(cfd);
+ add_io(0, 0);
+ currutmp->in_chat = currutmp->chatid[0] = 0;
+
+ if(flog) {
+ char ans[4];
+
+ fclose(flog);
+ more(fpath, NA);
+ getdata(b_lines - 1, 0, "²M°£(C) ²¾¦Ü³Æ§Ñ¿ý(M) (C/M)?[C]",
+ ans, 4, LCECHO);
+ if (*ans == 'm') {
+ fileheader_t mymail;
+ char title[128];
+
+ sethomepath(genbuf, cuser.userid);
+ stampfile(genbuf, &mymail);
+ mymail.savemode = 'H'; /* hold-mail flag */
+ mymail.filemode = FILE_READ;
+ strcpy(mymail.owner, "[³Æ.§Ñ.¿ý]");
+ strcpy(mymail.title, "·|ij\033[1;33m°O¿ý\033[m");
+ sethomedir(title, cuser.userid);
+ append_record(title, &mymail, sizeof(mymail));
+ Rename(fpath, genbuf);
+ } else
+ unlink(fpath);
+ }
+
+ return 0;
+}
+/* -------------------------------------------------- */
+#if 0
+
+extern char page_requestor[];
+extern userinfo_t *currutmp;
+
+#endif
diff --git a/mbbsd/chc_draw.c b/mbbsd/chc_draw.c
new file mode 100644
index 00000000..b3bd216f
--- /dev/null
+++ b/mbbsd/chc_draw.c
@@ -0,0 +1,187 @@
+/* $Id: chc_draw.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "proto.h"
+
+#define SIDE_ROW 10
+#define TURN_ROW 11
+#define STEP_ROW 12
+#define TIME_ROW 13
+#define WARN_ROW 15
+#define MYWIN_ROW 17
+#define HISWIN_ROW 18
+
+extern char chc_warnmsg[64], *chc_mateid;
+extern rc_t chc_from, chc_to, chc_select;
+extern int chc_selected, chc_my, chc_turn, chc_firststep;
+extern int chc_lefttime;
+extern int chc_hiswin, chc_hislose, chc_histie;
+
+static char *turn_str[2] = {"¶Âªº", "¬õªº"};
+
+static char *num_str[10] = {
+ "", "¤@", "¤G", "¤T", "¥|", "¤­", "¤»", "¤C", "¤K", "¤E"
+};
+
+static char *chess_str[2][8] = {
+ /* 0 1 2 3 4 5 6 7 */
+ {" ", "±N", "¤h", "¶H", "¨®", "°¨", "¥]", "¨ò"},
+ {" ", "«Ó", "¥K", "¬Û", "¨®", "ØX", "¬¶", "§L"}
+};
+
+static char *chess_brd[BRD_ROW * 2 - 1] = {
+ /*0 1 2 3 4 5 6 7 8*/
+ "¢z¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢{", /* 0 */
+ "¢x ¢x ¢x ¢x¢@¢x¡þ¢x ¢x ¢x ¢x",
+ "¢u¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t", /* 1 */
+ "¢x ¢x ¢x ¢x¡þ¢x¢@¢x ¢x ¢x ¢x",
+ "¢u¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t", /* 2 */
+ "¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x",
+ "¢u¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t", /* 3 */
+ "¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x",
+ "¢u¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢t", /* 4 */
+ "¢x ·¡ ªe º~ ¬É ¢x",
+ "¢u¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢t", /* 5 */
+ "¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x",
+ "¢u¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t", /* 6 */
+ "¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x",
+ "¢u¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t", /* 7 */
+ "¢x ¢x ¢x ¢x¢@¢x¡þ¢x ¢x ¢x ¢x",
+ "¢u¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t", /* 8 */
+ "¢x ¢x ¢x ¢x¡þ¢x¢@¢x ¢x ¢x ¢x",
+ "¢|¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢}" /* 9 */
+};
+
+static char *hint_str[] = {
+ " q »{¿éÂ÷¶}",
+ " p ­n¨D©M´Ñ",
+ "¤è¦VÁä ²¾°Ê¹C¼Ð",
+ "Enter ¿ï¾Ü/²¾°Ê"
+};
+
+void chc_movecur(int r, int c) {
+ move(r * 2 + 3, c * 4 + 4);
+}
+
+#define BLACK_COLOR "\033[1;36m"
+#define RED_COLOR "\033[1;31m"
+#define BLACK_REVERSE "\033[1;37;46m"
+#define RED_REVERSE "\033[1;37;41m"
+#define TURN_COLOR "\033[1;33m"
+
+static void showstep(board_t board) {
+ int turn, fc, tc, eatten;
+ char *dir;
+
+ turn = CHE_O(board[chc_from.r][chc_from.c]);
+ fc = (turn == (chc_my ^ 1) ? chc_from.c + 1 : 9 - chc_from.c);
+ tc = (turn == (chc_my ^ 1) ? chc_to.c + 1 : 9 - chc_to.c);
+ if(chc_from.r == chc_to.r)
+ dir = "¥­";
+ else {
+ if(chc_from.c == chc_to.c)
+ tc = chc_from.r - chc_to.r;
+ if(tc < 0) tc = -tc;
+
+ if((turn == (chc_my ^ 1) && chc_to.r > chc_from.r) ||
+ (turn == chc_my && chc_to.r < chc_from.r))
+ dir = "¶i";
+ else
+ dir = "°h";
+ }
+ prints("%s%s%s%s%s",
+ turn == 0 ? BLACK_COLOR : RED_COLOR,
+ chess_str[turn][CHE_P(board[chc_from.r][chc_from.c])],
+ num_str[fc], dir, num_str[tc]);
+ eatten = board[chc_to.r][chc_to.c];
+ if(eatten)
+ prints("¡G %s%s",
+ CHE_O(eatten) == 0 ? BLACK_COLOR : RED_COLOR,
+ chess_str[CHE_O(eatten)][CHE_P(eatten)]);
+ prints("\033[m");
+}
+
+extern userec_t cuser;
+
+void chc_drawline(board_t board, int line) {
+ int i, j;
+
+ move(line, 0);
+ clrtoeol();
+ if(line == 0) {
+ prints("\033[1;46m ¶H´Ñ¹ï¾Ô \033[45m%30s VS %-30s\033[m",
+ cuser.userid, chc_mateid);
+ } else if(line >= 3 && line <= 21) {
+ outs(" ");
+ for(i = 0; i < 9; i++) {
+ j = board[RTL(line)][i];
+ if((line & 1) == 1 && j) {
+ if(chc_selected &&
+ chc_select.r == RTL(line) && chc_select.c == i)
+ prints("%s%s\033[m",
+ CHE_O(j) == 0 ? BLACK_REVERSE : RED_REVERSE,
+ chess_str[CHE_O(j)][CHE_P(j)]);
+ else
+ prints("%s%s\033[m",
+ CHE_O(j) == 0 ? BLACK_COLOR : RED_COLOR,
+ chess_str[CHE_O(j)][CHE_P(j)]);
+ } else
+ prints("%c%c", chess_brd[line - 3][i * 4],
+ chess_brd[line - 3][i * 4 + 1]);
+ if(i != 8)
+ prints("%c%c", chess_brd[line - 3][i * 4 + 2],
+ chess_brd[line - 3][i * 4 + 3]);
+ }
+ outs(" ");
+
+ if(line >= 3 && line < 3 + dim(hint_str)) {
+ outs(hint_str[line - 3]);
+ } else if(line == SIDE_ROW) {
+ prints("\033[1m§A¬O%s%s\033[m",
+ chc_my == 0 ? BLACK_COLOR : RED_COLOR,
+ turn_str[chc_my]);
+ } else if(line == TURN_ROW) {
+ prints("%s%s\033[m",
+ TURN_COLOR,
+ chc_my == chc_turn ? "½ü¨ì§A¤U´Ñ¤F" : "µ¥«Ý¹ï¤è¤U´Ñ");
+ } else if(line == STEP_ROW && !chc_firststep) {
+ showstep(board);
+ } else if(line == TIME_ROW) {
+ prints("³Ñ¾l®É¶¡ %d:%02d", chc_lefttime / 60, chc_lefttime % 60);
+ } else if(line == WARN_ROW) {
+ outs(chc_warnmsg);
+ } else if(line == MYWIN_ROW) {
+ prints("\033[1;33m%12.12s "
+ "\033[1;31m%2d\033[37m³Ó "
+ "\033[34m%2d\033[37m±Ñ "
+ "\033[36m%2d\033[37m©M\033[m",
+ cuser.userid,
+ cuser.chc_win, cuser.chc_lose - 1, cuser.chc_tie);
+ } else if(line == HISWIN_ROW) {
+ prints("\033[1;33m%12.12s "
+ "\033[1;31m%2d\033[37m³Ó "
+ "\033[34m%2d\033[37m±Ñ "
+ "\033[36m%2d\033[37m©M\033[m",
+ chc_mateid,
+ chc_hiswin, chc_hislose - 1, chc_histie);
+ }
+ } else if(line == 2 || line == 22) {
+ outs(" ");
+ if(line == 2)
+ for(i = 1; i <= 9; i++)
+ prints("%s ", num_str[i]);
+ else
+ for(i = 9; i >= 1; i--)
+ prints("%s ", num_str[i]);
+ }
+}
+
+void chc_redraw(board_t board) {
+ int i;
+
+ for(i = 0; i <= 22; i++)
+ chc_drawline(board, i);
+}
diff --git a/mbbsd/chc_net.c b/mbbsd/chc_net.c
new file mode 100644
index 00000000..d094d5f2
--- /dev/null
+++ b/mbbsd/chc_net.c
@@ -0,0 +1,28 @@
+/* $Id: chc_net.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "config.h"
+#include "pttstruct.h"
+
+extern rc_t chc_from, chc_to;
+
+typedef struct drc_t {
+ rc_t from, to;
+} drc_t;
+
+int chc_recvmove(int s) {
+ drc_t buf;
+
+ if(read(s, &buf, sizeof(buf)) != sizeof(buf))
+ return 1;
+ chc_from = buf.from, chc_to = buf.to;
+ return 0;
+}
+
+void chc_sendmove(int s) {
+ drc_t buf;
+
+ buf.from = chc_from, buf.to = chc_to;
+ write(s, &buf, sizeof(buf));
+}
diff --git a/mbbsd/chc_play.c b/mbbsd/chc_play.c
new file mode 100644
index 00000000..86c17fbc
--- /dev/null
+++ b/mbbsd/chc_play.c
@@ -0,0 +1,277 @@
+/* $Id: chc_play.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <string.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "modes.h"
+#include "proto.h"
+
+extern userinfo_t *currutmp;
+extern int usernum;
+
+typedef int (*play_func_t)(int, board_t, board_t);
+
+static int chc_ipass = 0, chc_hepass = 0;
+int chc_lefttime;
+int chc_my, chc_turn, chc_selected, chc_firststep;
+char chc_warnmsg[64], *chc_mateid;
+rc_t chc_from, chc_to, chc_select, chc_cursor;
+int chc_hiswin, chc_hislose, chc_histie;
+
+#define CHC_TIMEOUT 300
+#define SIDE_ROW 10
+#define TURN_ROW 11
+#define STEP_ROW 12
+#define TIME_ROW 13
+#define WARN_ROW 15
+#define MYWIN_ROW 17
+#define HISWIN_ROW 18
+
+static int hisplay(int s, board_t board, board_t tmpbrd) {
+ int start_time;
+ int endgame = 0, endturn = 0;
+
+ start_time = time(NULL);
+ while(!endturn) {
+ chc_lefttime = CHC_TIMEOUT - (time(NULL) - start_time);
+ if(chc_lefttime < 0) {
+ chc_lefttime = 0;
+
+ /* to make him break out igetkey() */
+ chc_from.r = -2;
+ chc_sendmove(s);
+ }
+ chc_drawline(board, TIME_ROW);
+ move(1, 0);
+ oflush();
+ switch(igetkey()) {
+ case 'q':
+ endgame = 2;
+ endturn = 1;
+ break;
+ case 'p':
+ if(chc_hepass) {
+ chc_from.r = -1;
+ chc_sendmove(s);
+ endgame = 3;
+ endturn = 1;
+ }
+ break;
+ case I_OTHERDATA:
+ if(chc_recvmove(s)) { /* disconnect */
+ endturn = 1;
+ endgame = 1;
+ } else {
+ if(chc_from.r == -1) {
+ chc_hepass = 1;
+ strcpy(chc_warnmsg, "\033[1;33m­n¨D©M§½!\033[m");
+ chc_drawline(board, WARN_ROW);
+ } else {
+ chc_from.r = 9 - chc_from.r, chc_from.c = 8 - chc_from.c;
+ chc_to.r = 9 - chc_to.r, chc_to.c = 8 - chc_to.c;
+ chc_cursor = chc_to;
+ if(CHE_P(board[chc_to.r][chc_to.c]) == 1)
+ endgame = 2;
+ endturn = 1;
+ chc_hepass = 0;
+ chc_drawline(board, STEP_ROW);
+ chc_movechess(board);
+ chc_drawline(board, LTR(chc_from.r));
+ chc_drawline(board, LTR(chc_to.r));
+ }
+ }
+ break;
+ }
+ }
+ return endgame;
+}
+
+static int myplay(int s, board_t board, board_t tmpbrd) {
+ int ch, start_time;
+ int endgame = 0, endturn = 0;
+
+ chc_ipass = 0, chc_selected = 0;
+ start_time = time(NULL);
+ chc_lefttime = CHC_TIMEOUT - (time(NULL) - start_time);
+ bell();
+ while(!endturn) {
+ chc_drawline(board, TIME_ROW);
+ chc_movecur(chc_cursor.r, chc_cursor.c);
+ oflush();
+ ch = igetkey();
+ chc_lefttime = CHC_TIMEOUT - (time(NULL) - start_time);
+ if(chc_lefttime < 0)
+ ch = 'q';
+ switch(ch) {
+ case I_OTHERDATA:
+ if(chc_recvmove(s)) { /* disconnect */
+ endgame = 1;
+ endturn = 1;
+ } else if(chc_from.r == -1 && chc_ipass) {
+ endgame = 3;
+ endturn = 1;
+ }
+ break;
+ case KEY_UP:
+ chc_cursor.r--;
+ if(chc_cursor.r < 0)
+ chc_cursor.r = BRD_ROW - 1;
+ break;
+ case KEY_DOWN:
+ chc_cursor.r++;
+ if(chc_cursor.r >= BRD_ROW)
+ chc_cursor.r = 0;
+ break;
+ case KEY_LEFT:
+ chc_cursor.c--;
+ if(chc_cursor.c < 0)
+ chc_cursor.c = BRD_COL - 1;
+ break;
+ case KEY_RIGHT:
+ chc_cursor.c++;
+ if(chc_cursor.c >= BRD_COL)
+ chc_cursor.c = 0;
+ break;
+ case 'q':
+ endgame = 2;
+ endturn = 1;
+ break;
+ case 'p':
+ chc_ipass = 1;
+ chc_from.r = -1;
+ chc_sendmove(s);
+ strcpy(chc_warnmsg, "\033[1;33m­n¨D©M´Ñ!\033[m");
+ chc_drawline(board, WARN_ROW);
+ bell();
+ break;
+ case '\r':
+ case '\n':
+ case ' ':
+ if(chc_selected) {
+ if(chc_cursor.r == chc_select.r &&
+ chc_cursor.c == chc_select.c) {
+ chc_selected = 0;
+ chc_drawline(board, LTR(chc_cursor.r));
+ } else if(chc_canmove(board, chc_select, chc_cursor)) {
+ if(CHE_P(board[chc_cursor.r][chc_cursor.c]) == 1)
+ endgame = 1;
+ chc_from = chc_select;
+ chc_to = chc_cursor;
+ if(!endgame) {
+ memcpy(tmpbrd, board, sizeof(board_t));
+ chc_movechess(tmpbrd);
+ }
+ if(endgame || !chc_iskfk(tmpbrd)) {
+ chc_drawline(board, STEP_ROW);
+ chc_movechess(board);
+ chc_sendmove(s);
+ chc_selected = 0;
+ chc_drawline(board, LTR(chc_from.r));
+ chc_drawline(board, LTR(chc_to.r));
+ endturn = 1;
+ } else {
+ strcpy(chc_warnmsg, "\033[1;33m¤£¥i¥H¤ý¨£¤ý\033[m");
+ bell();
+ chc_drawline(board, WARN_ROW);
+ }
+ }
+ } else if(board[chc_cursor.r][chc_cursor.c] &&
+ CHE_O(board[chc_cursor.r][chc_cursor.c]) == chc_turn) {
+ chc_selected = 1;
+ chc_select = chc_cursor;
+ chc_drawline(board, LTR(chc_cursor.r));
+ }
+ break;
+ }
+ }
+ return endgame;
+}
+
+extern userec_t cuser;
+
+static void mainloop(int s, board_t board) {
+ int endgame;
+ board_t tmpbrd;
+ play_func_t play_func[2];
+
+ play_func[chc_my] = myplay;
+ play_func[chc_my ^ 1] = hisplay;
+ for(chc_turn = 1, endgame = 0; !endgame; chc_turn ^= 1) {
+ chc_firststep = 0;
+ chc_drawline(board, TURN_ROW);
+ if(chc_ischeck(board, chc_turn)) {
+ strcpy(chc_warnmsg, "\033[1;31m±N­x!\033[m");
+ bell();
+ } else
+ chc_warnmsg[0] = 0;
+ chc_drawline(board, WARN_ROW);
+ endgame = play_func[chc_turn](s, board, tmpbrd);
+ }
+
+ if(endgame == 1) {
+ strcpy(chc_warnmsg, "¹ï¤è»{¿é¤F!");
+ cuser.chc_win++;
+ } else if(endgame == 2) {
+ strcpy(chc_warnmsg, "§A»{¿é¤F!");
+ cuser.chc_lose++;
+ } else {
+ strcpy(chc_warnmsg, "©M´Ñ");
+ cuser.chc_tie++;
+ }
+ cuser.chc_lose--;
+ passwd_update(usernum, &cuser);
+ chc_drawline(board, WARN_ROW);
+ bell();
+ oflush();
+}
+
+extern userec_t xuser;
+
+static void chc_init(int s, board_t board) {
+ userinfo_t *my = currutmp;
+
+ setutmpmode(CHC);
+ clear();
+ chc_warnmsg[0] = 0;
+ chc_my = my->turn;
+ chc_mateid = my->mateid;
+ chc_firststep = 1;
+ chc_init_board(board);
+ chc_redraw(board);
+ chc_cursor.r = 9, chc_cursor.c = 0;
+ add_io(s, 0);
+
+ if(my->turn) chc_recvmove(s);
+ passwd_query(usernum, &xuser);
+ cuser.chc_win = xuser.chc_win;
+ cuser.chc_lose = xuser.chc_lose + 1;
+ cuser.chc_tie = xuser.chc_tie;
+ cuser.money = xuser.money;
+ passwd_update(usernum, &cuser);
+
+ getuser(chc_mateid);
+ chc_hiswin = xuser.chc_win;
+ chc_hislose = xuser.chc_lose;
+ chc_histie = xuser.chc_tie;
+
+ if(!my->turn) {
+ chc_sendmove(s);
+ chc_hislose++;
+ }
+
+ chc_redraw(board);
+}
+
+void chc(int s) {
+ board_t board;
+
+ chc_init(s, board);
+ mainloop(s, board);
+ close(s);
+ add_io(0, 0);
+ if(chc_my) pressanykey();
+}
diff --git a/mbbsd/chc_rule.c b/mbbsd/chc_rule.c
new file mode 100644
index 00000000..35d8fe6a
--- /dev/null
+++ b/mbbsd/chc_rule.c
@@ -0,0 +1,186 @@
+/* $Id: chc_rule.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "proto.h"
+
+extern rc_t chc_from, chc_to;
+extern int chc_my;
+
+#define CENTER(a, b) (((a) + (b)) >> 1)
+
+void chc_init_board(board_t board) {
+ memset(board, 0, sizeof(board_t));
+ board[0][4] = CHE(1, chc_my ^ 1); /* ±N */
+ board[0][3] = board[0][5] = CHE(2, chc_my ^ 1); /* ¤h */
+ board[0][2] = board[0][6] = CHE(3, chc_my ^ 1); /* ¶H */
+ board[0][0] = board[0][8] = CHE(4, chc_my ^ 1); /* ¨® */
+ board[0][1] = board[0][7] = CHE(5, chc_my ^ 1); /* °¨ */
+ board[2][1] = board[2][7] = CHE(6, chc_my ^ 1); /* ¥] */
+ board[3][0] = board[3][2] = board[3][4] =
+ board[3][6] = board[3][8] = CHE(7, chc_my ^ 1); /* ¨ò */
+
+ board[9][4] = CHE(1, chc_my); /* «Ó */
+ board[9][3] = board[9][5] = CHE(2, chc_my); /* ¥K */
+ board[9][2] = board[9][6] = CHE(3, chc_my); /* ¬Û */
+ board[9][0] = board[9][8] = CHE(4, chc_my); /* ¨® */
+ board[9][1] = board[9][7] = CHE(5, chc_my); /* ØX */
+ board[7][1] = board[7][7] = CHE(6, chc_my); /* ¦ */
+ board[6][0] = board[6][2] = board[6][4] =
+ board[6][6] = board[6][8] = CHE(7, chc_my); /* §L */
+}
+
+void chc_movechess(board_t board) {
+ board[chc_to.r][chc_to.c] = board[chc_from.r][chc_from.c];
+ board[chc_from.r][chc_from.c] = 0;
+}
+
+static int dist(rc_t from, rc_t to, int rowcol) {
+ int d;
+
+ d = rowcol ? from.c - to.c : from.r - to.r;
+ return d > 0 ? d : -d;
+}
+
+static int between(board_t board, rc_t from, rc_t to, int rowcol) {
+ int i, rtv = 0;
+
+ if(rowcol) {
+ if(from.c > to.c)
+ i = from.c, from.c = to.c, to.c = i;
+ for(i = from.c + 1; i < to.c; i++)
+ if(board[to.r][i]) rtv++;
+ } else {
+ if(from.r > to.r)
+ i = from.r, from.r = to.r, to.r = i;
+ for(i = from.r + 1; i < to.r; i++)
+ if(board[i][to.c]) rtv++;
+ }
+ return rtv;
+}
+
+int chc_canmove(board_t board, rc_t from, rc_t to) {
+ int i;
+ int rd, cd, turn;
+
+ rd = dist(from, to, 0);
+ cd = dist(from, to, 1);
+ turn = CHE_O(board[from.r][from.c]);
+
+ /* general check */
+ if(board[to.r][to.c] && CHE_O(board[to.r][to.c]) == turn)
+ return 0;
+
+ /* individual check */
+ switch(CHE_P(board[from.r][from.c])) {
+ case 1: /* ±N «Ó */
+ if(!(rd == 1 && cd == 0) &&
+ !(rd == 0 && cd == 1))
+ return 0;
+ if((turn == (chc_my ^ 1) && to.r > 2) ||
+ (turn == chc_my && to.r < 7) ||
+ to.c < 3 || to.c > 5)
+ return 0;
+ break;
+ case 2: /* ¤h ¥K */
+ if(!(rd == 1 && cd == 1))
+ return 0;
+ if((turn == (chc_my ^ 1) && to.r > 2) ||
+ (turn == chc_my && to.r < 7) ||
+ to.c < 3 || to.c > 5)
+ return 0;
+ break;
+ case 3: /* ¶H ¬Û */
+ if(!(rd == 2 && cd == 2))
+ return 0;
+ if((turn == (chc_my ^ 1) && to.r > 4) ||
+ (turn == chc_my && to.r < 5))
+ return 0;
+ /* ©ä¶H»L */
+ if(board[CENTER(from.r, to.r)][CENTER(from.c, to.c)])
+ return 0;
+ break;
+ case 4: /* ¨® */
+ if(!(rd > 0 && cd == 0) &&
+ !(rd == 0 && cd > 0))
+ return 0;
+ if(between(board, from, to, rd == 0))
+ return 0;
+ break;
+ case 5: /* °¨ ØX */
+ if(!(rd == 2 && cd == 1) &&
+ !(rd == 1 && cd == 2))
+ return 0;
+ /* ©ä°¨¸} */
+ if(rd == 2) {
+ if(board[CENTER(from.r, to.r)][from.c])
+ return 0;
+ } else {
+ if(board[from.r][CENTER(from.c, to.c)])
+ return 0;
+ }
+ break;
+ case 6: /* ¥] ¬¶ */
+ if(!(rd > 0 && cd == 0) &&
+ !(rd == 0 && cd > 0))
+ return 0;
+ i = between(board, from, to, rd == 0);
+ if((i > 1) ||
+ (i == 1 && !board[to.r][to.c]) ||
+ (i == 0 && board[to.r][to.c]))
+ return 0;
+ break;
+ case 7: /* ¨ò §L */
+ if(!(rd == 1 && cd == 0) &&
+ !(rd == 0 && cd == 1))
+ return 0;
+ if(((turn == (chc_my ^ 1) && to.r < 5) ||
+ (turn == chc_my && to.r > 4)) &&
+ cd != 0)
+ return 0;
+ if((turn == (chc_my ^ 1) && to.r < from.r) ||
+ (turn == chc_my && to.r > from.r))
+ return 0;
+ break;
+ }
+ return 1;
+}
+
+static void findking(board_t board, int turn, rc_t *buf) {
+ int i, r, c;
+
+ r = (turn == (chc_my ^ 1)) ? 0 : 7;
+ for(i = 0; i < 3; r++, i++)
+ for(c = 3; c < 6; c++)
+ if(CHE_P(board[r][c]) == 1 &&
+ CHE_O(board[r][c]) == turn) {
+ buf->r = r, buf->c = c;
+ return ;
+ }
+}
+
+int chc_iskfk(board_t board) {
+ rc_t from, to;
+
+ findking(board, 0, &to);
+ findking(board, 1, &from);
+ if(from.c == to.c && between(board, from, to, 0) == 0)
+ return 1;
+ return 0;
+}
+
+int chc_ischeck(board_t board, int turn) {
+ rc_t from, to;
+
+ findking(board, turn, &to);
+ for(from.r = 0;from.r < BRD_ROW; from.r++)
+ for(from.c = 0; from.c < BRD_COL; from.c++)
+ if(board[from.r][from.c] &&
+ CHE_O(board[from.r][from.c]) != turn)
+ if(chc_canmove(board, from, to))
+ return 1;
+ return 0;
+}
diff --git a/mbbsd/chicken.c b/mbbsd/chicken.c
new file mode 100644
index 00000000..f789925f
--- /dev/null
+++ b/mbbsd/chicken.c
@@ -0,0 +1,989 @@
+/* $Id: chicken.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "modes.h"
+#include "proto.h"
+
+#define NUM_KINDS 13 /* ¦³¦h¤ÖºØ°Êª« */
+
+static const char *cage[17] = {
+ "½Ï¥Í", "¶g·³", "¥®¦~", "¤Ö¦~", "«C¬K", "«C¦~",
+ "«C¦~", "¬¡¤O", "§§¦~", "§§¦~", "§§¦~", "¤¤¦~",
+ "¤¤¦~", "¦Ñ¦~", "¦Ñ¦~", "¦Ñáàáà", "¥j§Æ"};
+static const char *chicken_type[NUM_KINDS] = {
+ "¤pÂû", "¬ü¤Ö¤k", "«i¤h", "»jµï",
+ "®£Às", "¦ÑÆN", "¿ß", "Äúµ§¤p·s",
+ "ª¯ª¯", "´cÅ]", "§ÔªÌ", "£««ó",
+ "°¨­^¤E"};
+static const char *chicken_food[NUM_KINDS] = {
+ "Âû¹}®Æ", "Àç¾i«p¤ù", "Âû±Æ«K·í", "¦º½¹½º",
+ "«ÍÅé", "¤pÂû", "¿ß»æ°®", "¤pºµ»æ°®",
+ "Ä_¿ý", "ÆF®ð", "¶º¹Î", "«K·í",
+ "Âû»L"};
+static const int egg_price[NUM_KINDS] = {
+ 5, 25, 30, 40,
+ 80, 50, 15, 35,
+ 17, 100, 85, 200,
+ 200};
+static const int food_price[NUM_KINDS] = {
+ 4, 6, 8, 10,
+ 12, 12, 5, 6,
+ 5, 20, 15, 23,
+ 23};
+static const char *attack_type[NUM_KINDS] = {
+ "°Ö", "Ã@¥´", "ºl", "«r",
+ "¼²À»", "°Ö", "§ì", "½ð",
+ "«r","¿U¿N","·tÀ»","´Ò¥´",
+ "¼CÀ»"};
+
+static const char *damage_degree[] = {
+ "°A¤l¦üªº", "ÄÌÄo¦üªº", "¤p¤Oªº", "»´·Lªº",
+ "¦³ÂI¯kªº", "¨Ï¤Oªº", "¶Ë¤Hªº", "­«­«ªº",
+ "¨Ï¥þ¤Oªº", "´c¬½¬½ªº", "¦MÀIªº", "ºÆ¨gªº",
+ "²r¯Pªº", "¨g­·¼É«B¦üªº", "Åå¤Ñ°Ê¦aªº",
+ "­P©Rªº", NULL};
+
+enum {
+ OO, FOOD, WEIGHT, CLEAN, RUN, ATTACK, BOOK, HAPPY, SATIS,
+ TEMPERAMENT, TIREDSTRONG, SICK, HP_MAX, MM_MAX
+};
+
+extern userec_t cuser;
+
+static chicken_t *mychicken = &cuser.mychicken;
+static int age;
+
+static const int time_change[NUM_KINDS][14] =
+/* ¸É«~ ­¹ª« Åé­« °®²b ±Ó±¶ §ðÀ»¤O ª¾ÃÑ §Ö¼Ö º¡·N ®ð½è ¯h³Ò ¯f®ð º¡¦å º¡ªk*/
+{
+/*Âû*/
+ { 1, 1, 30, 3, 8, 3, 3, 40, 9, 1, 7, 3, 30, 1},
+/*¬ü¤Ö¤k*/
+ { 1, 1, 110, 1, 4, 7, 41, 20, 9, 25, 25, 7, 110, 15},
+/*«i¤h*/
+ { 1, 1, 200, 5, 4, 10, 33, 20, 15, 10, 27, 1, 200, 9},
+/*»jµï*/
+ { 1, 1, 10, 5, 8, 1, 1, 5, 3, 1, 4, 1, 10, 30},
+/*®£Às*/
+ { 1, 1,1000, 9, 1, 13, 4, 12, 3, 1, 200, 1, 1000, 3},
+/*¦ÑÆN*/
+ { 1, 1, 90, 7, 10, 7, 4, 12, 3, 30, 20, 5, 90, 20},
+/*¿ß*/
+ { 1, 1, 30, 5, 5, 6, 4, 8, 3, 15, 7, 4, 30, 21},
+/*Äúµ§¤p·s*/
+ { 1, 1, 100, 9, 7, 7, 20, 50, 10, 8, 24, 4, 100, 9},
+/*ª¯*/
+ { 1, 1, 45, 8, 7, 9, 3, 40, 20, 3, 9, 5, 45, 1},
+/* ´cÅ] */
+ { 1, 1, 45, 10, 11, 11, 5, 21, 11, 1, 9, 5, 45, 25},
+/* §ÔªÌ */
+ { 1, 1, 45, 2, 12, 10, 25, 1, 1, 10, 9, 5, 45, 26},
+/* ªü«ó */
+ { 1, 1, 150, 4, 8, 13, 95, 25, 7, 10, 25, 5, 175, 85},
+/* °¨­^¤E */
+ { 1, 1, 147, 2, 10, 10, 85, 20, 4, 25, 25, 5, 145, 95}
+};
+
+extern userec_t xuser;
+extern int usernum;
+
+int reload_chicken() {
+ passwd_query(usernum, &xuser);
+ memcpy(mychicken, &xuser.mychicken, sizeof(chicken_t));
+ if(!mychicken->name[0])
+ return 0;
+ else return 1;
+}
+
+#define CHICKENLOG "etc/chicken"
+
+static int new_chicken() {
+ char buf[150];
+ int price;
+ time_t now;
+
+ clear();
+ move(2,0);
+ outs("ÅwªïÆ[Á{ \033[33m¡·\033[37;44m PttÃdª«¥«³õ \033[33;40m¡·\033[m.. "
+ "¥Ø«e³J»ù¡G\n"
+ "(a)¤pÂû $5 (b)¬ü¤Ö¤k $25 (c)«i¤h $30 (d)»jµï $40 "
+ "(e)®£Às $80\n"
+ "(f)¦ÑÆN $50 (g)¿ß $15 (h)Äúµ§¤p·s$35 (i)ª¯ª¯ $17 "
+ "(j)´cÅ] $100\n"
+ "(k)§ÔªÌ $85 (l)ªü«ó $200 (m)°¨­^¤E $200\n"
+ "[0]¦Û¤v $0\n");
+ getdata_str(6, 0, "½Ð¿ï¾Ü§A­n¾iªº°Êª«¡G", buf, 3, LCECHO, "0");
+
+ buf[0] -= 'a';
+ if(buf[0]<0 || buf[0]>NUM_KINDS-1)
+ return 0;
+
+ mychicken->type = buf[0];
+
+ reload_money();
+ price = egg_price[(int)mychicken->type];
+ if(cuser.money < price) {
+ prints("\n ¿ú¤£°÷¶R³J³J,³J³J­n %d ¤¸", price);
+ refresh();
+ return 0;
+ }
+ vice(price,"Ãdª«³J");
+ while(strlen(mychicken->name)<3)
+ getdata(8, 0, "À°¨e¨ú­Ó¦n¦W¦r¡G", mychicken->name, 18, DOECHO);
+
+ now = time(NULL);
+ sprintf(buf,"\033[31m%s \033[m¾i¤F¤@°¦¥s\033[33m %s \033[mªº "
+ "\033[32m%s\033[m ©ó %s",cuser.userid,
+ mychicken->name,chicken_type[(int)mychicken->type],ctime(&now));
+ log_file(CHICKENLOG,buf);
+ mychicken->lastvisit = mychicken->birthday = mychicken->cbirth = now;
+ mychicken->food = 0;
+ mychicken->weight = time_change[(int)mychicken->type][WEIGHT]/3;
+ mychicken->clean = 0;
+ mychicken->run = time_change[(int)mychicken->type][RUN];
+ mychicken->attack = time_change[(int)mychicken->type][ATTACK];
+ mychicken->book = time_change[(int)mychicken->type][BOOK];
+ mychicken->happy = time_change[(int)mychicken->type][HAPPY];
+ mychicken->satis = time_change[(int)mychicken->type][SATIS];
+ mychicken->temperament = time_change[(int)mychicken->type][TEMPERAMENT];
+ mychicken->tiredstrong = 0;
+ mychicken->sick = 0;
+ mychicken->hp = time_change[(int)mychicken->type][WEIGHT];
+ mychicken->hp_max = time_change[(int)mychicken->type][WEIGHT];
+ mychicken->mm = 0;
+ mychicken->mm_max = 0;
+ return 1;
+}
+
+int show_file(char *filename, int y, int lines, int mode) {
+ FILE *fp;
+ char buf[256];
+
+ if(y >= 0)
+ move(y,0);
+ clrtoline(lines + y);
+ if((fp=fopen(filename,"r"))) {
+ while(fgets(buf,256,fp) && lines--)
+ outs(Ptt_prints(buf,mode));
+ fclose(fp);
+ } else
+ return 0;
+ return 1;
+}
+
+static void show_chicken_stat(chicken_t *thechicken) {
+ struct tm *ptime;
+
+ ptime = localtime(&thechicken->birthday);
+ prints(" Name :\033[33m%s\033[m (\033[32m%s\033[m)%*s¥Í¤é "
+ ":\033[31m%02d\033[m¦~\033[31m%2d\033[m¤ë\033[31m%2d\033[m¤é "
+ "(\033[32m%s %d·³\033[m)\n"
+ " Åé:\033[33m%5d/%-5d\033[m ªk:\033[33m%5d/%-5d\033[m §ðÀ»¤O:"
+ "\033[33m%-7d\033[m ±Ó±¶ :\033[33m%-7d\033[m ª¾ÃÑ :\033[33m%-7d"
+ "\033[m \n"
+ " §Ö¼Ö :\033[33m%-7d\033[m º¡·N :\033[33m%-7d\033[m ¯h³Ò :"
+ "\033[33m%-7d\033[m ®ð½è :\033[33m%-7d \033[mÅé­« :"
+ "\033[33m%-5.2f\033[m \n"
+ " ¯f®ð :\033[33m%-7d\033[m °®²b :\033[33m%-7d\033[m ­¹ª« :"
+ "\033[33m%-7d\033[m ¤j¸É¤Y:\033[33m%-7d\033[m ÃÄ«~ :\033[33m%-7d"
+ "\033[m \n",
+ thechicken->name, chicken_type[(int)thechicken->type],
+ 15 - strlen(thechicken->name), "",
+ ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday,
+ cage[age > 16 ? 16 : age], age, thechicken->hp, thechicken->hp_max,
+ thechicken->mm, thechicken->mm_max,
+ thechicken->attack, thechicken->run, thechicken->book,
+ thechicken->happy, thechicken->satis, thechicken->tiredstrong,
+ thechicken->temperament,
+ ((float)(thechicken->hp_max+(thechicken->weight/50))) / 100,
+ thechicken->sick, thechicken->clean, thechicken->food,
+ thechicken->oo, thechicken->medicine);
+}
+
+#define CHICKEN_PIC "etc/chickens"
+extern char *BBSName;
+
+void show_chicken_data(chicken_t *thechicken, chicken_t *pkchicken) {
+ char buf[1024];
+ age = ((time(NULL) - thechicken->cbirth)/ (60*60*24));
+ if(age < 0) {
+ thechicken->birthday = thechicken->cbirth = time(NULL)-10*(60*60*24);
+ age = 10;
+ }
+ /*Ptt:debug*/
+ thechicken->type %= NUM_KINDS;
+ clear();
+ showtitle(pkchicken ? "¢Þtt°«Âû³õ" : "¢Þtt¾iÂû³õ", BBSName);
+ move(1,0);
+
+ show_chicken_stat(thechicken);
+
+ sprintf(buf, CHICKEN_PIC "/%c%d", thechicken->type + 'a',
+ age > 16 ? 16 : age);
+ show_file(buf, 5, 14, NO_RELOAD);
+
+ move(18,0);
+
+ if(thechicken->sick)
+ outs("¥Í¯f¤F...");
+ if(thechicken->sick > thechicken->hp / 5)
+ outs("\033[5;31m¾á¤ß...¯f­«!!\033[m");
+
+ if(thechicken->clean > 150)
+ outs("\033[31m¤S¯ä¤Sżªº..\033[m");
+ else if(thechicken->clean > 80)
+ outs("¦³ÂIż..");
+ else if(thechicken->clean < 20)
+ outs("\033[32m«Ü°®²b..\033[m");
+
+ if(thechicken->weight > thechicken->hp_max*4)
+ outs("\033[31m§Ö¹¡¦º¤F!.\033[m");
+ else if(thechicken->weight > thechicken->hp_max*3)
+ outs("\033[32m¹¡¹Ê¹Ê..\033[m");
+ else if(thechicken->weight < (thechicken->hp_max / 4))
+ outs("\033[31m§Ö¾j¦º¤F!..\033[m");
+ else if(thechicken->weight < (thechicken->hp_max / 2))
+ outs("¾j¤F..");
+
+ if(thechicken->tiredstrong > thechicken->hp * 1.7)
+ outs("\033[31m²Ö±o©ü°g¤F...\033[m");
+ else if(thechicken->tiredstrong > thechicken->hp)
+ outs("²Ö¤F..");
+ else if(thechicken->tiredstrong < thechicken->hp / 4)
+ outs("\033[32mºë¤O©ô²±...\033[m");
+
+ if(thechicken->hp < thechicken->hp_max / 4)
+ outs("\033[31mÅé¤O¥ÎºÉ..©a©a¤@®§..\033[m");
+ if(thechicken->happy > 500)
+ outs("\033[32m«Ü§Ö¼Ö..\033[m");
+ else if(thechicken->happy < 100)
+ outs("¤£§Ö¼Ö..");
+ if(thechicken->satis > 500)
+ outs("\033[32m«Üº¡¨¬..\033[m");
+ else if(thechicken->satis < 50)
+ outs("¤£º¡¨¬..");
+
+ if(pkchicken) {
+ outs("\n");
+ show_chicken_stat(pkchicken);
+ outs("[¥ô·NÁä] §ðÀ»¹ï¤è [q] ¸¨¶] [o] ¦Y¤j¸É¤Y");
+ }
+}
+
+static void ch_eat() {
+ if(mychicken->food) {
+ mychicken->weight += time_change[(int)mychicken->type][WEIGHT] +
+ mychicken->hp_max/5 ;
+ mychicken->tiredstrong +=
+ time_change[(int)mychicken->type][TIREDSTRONG] / 2;
+ mychicken->hp_max++;
+ mychicken->happy += 5;
+ mychicken->satis += 7;
+ mychicken->food--;
+ move(10, 10);
+
+ show_file(CHICKEN_PIC "/eat", 5, 14, NO_RELOAD);
+ pressanykey();
+ }
+}
+
+static void ch_clean() {
+ mychicken->clean = 0;
+ mychicken->tiredstrong +=
+ time_change[(int)mychicken->type][TIREDSTRONG] / 3;
+ show_file(CHICKEN_PIC "/clean", 5, 14, NO_RELOAD);
+ pressanykey();
+}
+
+static void ch_guess() {
+ char *guess[3] = {"°Å¤M", "¥ÛÀY", "¥¬"}, me, ch, win;
+
+ mychicken->happy += time_change[(int)mychicken->type][HAPPY]*1.5;
+ mychicken->satis += time_change[(int)mychicken->type][SATIS];
+ mychicken->tiredstrong += time_change[(int)mychicken->type][TIREDSTRONG];
+ mychicken->attack += time_change[(int)mychicken->type][ATTACK]/4;
+ move(20,0);
+ clrtobot();
+ outs("§A­n¥X[\033[32m1\033[m]\033[33m°Å¤M\033[m(\033[32m2\033[m)"
+ "\033[33m¥ÛÀY\033[m(\033[32m3\033[m)\033[33m¥¬\033[m:\n");
+ me = igetch();
+ me -= '1';
+ if(me > 2 || me < 0)
+ me = 0;
+ win = (int)(3.0 * rand()/(RAND_MAX + 1.0)) - 1;
+ ch = (me + win + 3)%3;
+ prints("%s:%s ! %s:%s !.....%s",
+ cuser.userid, guess[(int)me], mychicken->name, guess[(int)ch],
+ win==0 ? "¥­¤â" : win < 0 ? "­C..ŤF :D!!" : "¶ã..§Ú¿é¤F :~");
+ pressanykey();
+}
+
+static void ch_book() {
+ mychicken->book += time_change[(int)mychicken->type][BOOK];
+ mychicken->tiredstrong += time_change[(int)mychicken->type][TIREDSTRONG];
+ show_file(CHICKEN_PIC "/read", 5, 14, NO_RELOAD);
+ pressanykey();
+}
+
+static void ch_kiss() {
+ mychicken->happy += time_change[(int)mychicken->type][HAPPY];
+ mychicken->satis += time_change[(int)mychicken->type][SATIS];
+ mychicken->tiredstrong +=
+ time_change[(int)mychicken->type][TIREDSTRONG] / 2;
+ show_file(CHICKEN_PIC "/kiss", 5, 14, NO_RELOAD);
+ pressanykey();
+}
+
+static void ch_hit() {
+ mychicken->attack += time_change[(int)mychicken->type][ATTACK];
+ mychicken->run += time_change[(int)mychicken->type][RUN];
+ mychicken->mm_max += time_change[(int)mychicken->type][MM_MAX]/15;
+ mychicken->weight -= mychicken->hp_max / 15 ;
+ mychicken->hp -= (int)((float)time_change[(int)mychicken->type][HP_MAX] *
+ rand()/(RAND_MAX+1.0)) / 2 + 1;
+
+ if(mychicken->book > 2)
+ mychicken->book -= 2;
+ if(mychicken->happy > 2)
+ mychicken->happy -= 2;
+ if(mychicken->satis > 2)
+ mychicken->satis -= 2;
+ mychicken->tiredstrong += time_change[(int)mychicken->type][TIREDSTRONG];
+ show_file(CHICKEN_PIC "/hit", 5, 14, NO_RELOAD);
+ pressanykey();
+}
+
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+
+void ch_buyitem(int money, char *picture, int *item) {
+ int num = 0;
+ char buf[5];
+
+ getdata_str(b_lines - 1, 0, "­n¶R¦h¤Ö¥÷©O:", buf, 4, DOECHO, "1");
+ num = atoi(buf);
+ if(num < 1)
+ return;
+ reload_money();
+ if(cuser.money > money*num) {
+ *item += num;
+ vice(money*num,"ÁʶRÃdª«,½ä½L¶µ¥Ø");
+ show_file(picture, 5, 14, NO_RELOAD);
+ } else {
+ move(b_lines-1,0);
+ clrtoeol();
+ outs("²{ª÷¤£°÷ !!!");
+ }
+ pressanykey();
+}
+
+static void ch_eatoo() {
+ if(mychicken->oo > 0) {
+ mychicken->oo--;
+ mychicken->tiredstrong = 0;
+ if(mychicken->happy > 5)
+ mychicken->happy -= 5;
+ show_file(CHICKEN_PIC "/oo", 5, 14, NO_RELOAD);
+ pressanykey();
+ }
+}
+
+static void ch_eatmedicine() {
+ if(mychicken->medicine > 0) {
+ mychicken->medicine--;
+ mychicken->sick = 0;
+ if(mychicken->hp_max > 10)
+ mychicken->hp_max -= 3;
+ mychicken->hp = mychicken->hp_max;
+ if(mychicken->happy>10)
+ mychicken->happy -= 10;
+ show_file(CHICKEN_PIC "/medicine", 5, 14, NO_RELOAD);
+ pressanykey();
+ }
+}
+
+static void ch_kill() {
+ char buf[150],ans[4];
+
+ sprintf(buf, "±ó¾i³o%s­n³Q»@ 100 ¤¸, ¬O§_­n±ó¾i?(y/N)",
+ chicken_type[(int)mychicken->type]);
+ getdata_str(23, 0, buf, ans, 3, DOECHO, "N");
+ if(ans[0] == 'y') {
+ time_t now = time(NULL);
+
+ vice(100,"±ó¾iÃdª«¶O");
+ more(CHICKEN_PIC "/deadth",YEA);
+ sprintf(buf, "\033[31m%s \033[m§â \033[33m%s\033[m\033[32m %s "
+ "\033[m®_¤F ©ó %s", cuser.userid,
+ mychicken->name, chicken_type[(int)mychicken->type], ctime(&now));
+ log_file(CHICKENLOG, buf);
+ mychicken->name[0]=0;
+ }
+}
+
+static int ch_sell() {
+/*
+ int money = (mychicken->weight - time_change[(int)mychicken->type][WEIGHT])
+ *(food_price[(int)mychicken->type])/4 +
+ (
+ + ((mychicken->clean / time_change[(int)mychicken->type][CLEAN])
+ + (mychicken->run / time_change[(int)mychicken->type][RUN])
+ + (mychicken->attack / time_change[(int)mychicken->type][ATTACK])
+ + (mychicken->book / time_change[(int)mychicken->type][BOOK])
+ + (mychicken->happy / time_change[(int)mychicken->type][HAPPY])
+ + (mychicken->satis / time_change[(int)mychicken->type][SATIS])
+ + (mychicken->temperament / time_change[(int)mychicken->type][TEMPERAMENT])
+ - (mychicken->tiredstrong / time_change[(int)mychicken->type][TIREDSTRONG])
+ - (mychicken->sick / time_change[(int)mychicken->type][SICK])
+ + (mychicken->hp / time_change[(int)mychicken->type][HP_MAX])
+ + (mychicken->mm / time_change[(int)mychicken->type][MM_MAX])
+ + 7 - abs(age - 7)) * 3
+ ;
+*/
+ int money = (age * food_price[(int)mychicken->type] * 3
+ + (mychicken->hp_max * 10 + mychicken->weight) /
+ time_change[(int)mychicken->type][HP_MAX]) * 3 / 2 -
+ mychicken->sick;
+ char buf[150],ans[4];
+ time_t now = time(NULL);
+
+ if(money < 0)
+ money =0 ;
+ else if(money > MAX_CHICKEN_MONEY)
+ money = MAX_CHICKEN_MONEY; //¨¾¤î©ÇÂû
+ if(mychicken->type == 1 || mychicken->type == 7) {
+ outs("\n\033[31m £­..¿Ë·Rªº..³c½æ¤H¤f¬O·|¥Çªkªº­ò..\033[m");
+ pressanykey();
+ return 0;
+ }
+ if(age < 5) {
+ outs("\n ÁÙ¥¼¦¨¦~¤£¯à½æ");
+ pressanykey();
+ return 0;
+ }
+ if(age > 30) {
+ outs("\n\033[31m ³o..¤Ó¦Ñ¨S¤H­n¤F\033[m");
+ pressanykey();
+ return 0;
+ }
+
+ sprintf(buf, "³o°¦%d·³%s¥i¥H½æ %d ¤¸, ¬O§_­n½æ?(y/N)", age,
+ chicken_type[(int)mychicken->type], money);
+ getdata_str(23, 0, buf, ans, 3, DOECHO, "N");
+ if(ans[0]=='y') {
+ sprintf(buf, "\033[31m%s\033[m §â \033[33m%s\033[m "
+ "\033[32m%s\033[m ¥Î \033[36m%d\033[m ½æ¤F ©ó %s",
+ cuser.userid, mychicken->name,
+ chicken_type[(int)mychicken->type],money,ctime(&now));
+ log_file(CHICKENLOG, buf);
+ mychicken->lastvisit = mychicken->name[0]=0;
+ passwd_update(usernum, &cuser);
+ more(CHICKEN_PIC "/sell",YEA);
+ demoney(money);
+ return 1;
+ }
+ return 0;
+}
+
+static void geting_old(int *hp, int *weight, int diff, int age) {
+ float ex = 0.9;
+
+ if(age > 70)
+ ex = 0.1;
+ else if(age > 30)
+ ex = 0.5;
+ else if(age > 20)
+ ex = 0.7;
+
+ diff /= 60*6;
+ while(diff--) {
+ *hp *= ex;
+ *weight *= ex;
+ }
+}
+
+/* ¨Ì®É¶¡Åܰʪº¸ê®Æ */
+void time_diff(chicken_t *thechicken) {
+ int diff;
+ int theage = ((time(NULL) - thechicken->cbirth)/ (60 * 60 * 24));
+
+ thechicken->type %= NUM_KINDS ;
+ diff = (time(NULL)-thechicken->lastvisit)/60;
+
+ if((diff) < 1)
+ return;
+
+ if(theage > 13 ) /* ¦Ñ¦º */
+ geting_old(&thechicken->hp_max, &thechicken->weight, diff, age);
+
+ thechicken->lastvisit = time(NULL);
+ thechicken->weight -= thechicken->hp_max * diff / 540; /* Åé­« */
+ if(thechicken->weight < 1) {
+ thechicken->sick -= thechicken->weight / 10; /* ¾j±o¯f®ð¤W¤É */
+ thechicken->weight =1;
+ }
+
+ /* ²M¼ä«× */
+ thechicken->clean += diff * time_change[(int)thechicken->type][CLEAN] / 30;
+
+ /* §Ö¼Ö«× */
+ thechicken->happy -= diff / 60;
+ if(thechicken->happy < 0)
+ thechicken->happy=0;
+ thechicken->attack -=
+ time_change[(int)thechicken->type][ATTACK] * diff / (60 * 32);
+ if(thechicken->attack < 0)
+ thechicken->attack = 0;
+ /* §ðÀ»¤O */
+ thechicken->run -= time_change[(int)thechicken->type][RUN] * diff / (60 * 32);
+ /* ±Ó±¶ */
+ if(thechicken->run < 0)
+ thechicken->run = 0;
+ thechicken->book -= time_change[(int)thechicken->type][BOOK]*diff/ (60*32);
+ /* ª¾ÃÑ */
+ if(thechicken->book < 0)
+ thechicken->book = 0;
+ /* ®ð½è */
+ thechicken->temperament++;
+
+ thechicken->satis -= diff / 60 / 3 * time_change[(int)thechicken->type][SATIS];
+ /* º¡·N«× */
+ if(thechicken->satis < 0)
+ thechicken->satis = 0;
+
+ /* ż¯fªº */
+ if(mychicken->clean > 1000)
+ mychicken->sick += (mychicken->clean - 400) / 10;
+
+ if(thechicken->weight > 1)
+ thechicken->sick -= diff / 60;
+ /* ¯f®ð«ìÅ@ */
+ if(thechicken->sick < 0)
+ thechicken->sick = 0;
+ thechicken->tiredstrong -= diff *
+ time_change[(int)thechicken->type][TIREDSTRONG] / 4;
+ /* ¯h³Ò */
+ if(thechicken->tiredstrong < 0)
+ thechicken->tiredstrong = 0;
+ /* hp_max */
+ if(thechicken->hp >= thechicken->hp_max/2)
+ thechicken->hp_max +=
+ time_change[(int)thechicken->type][HP_MAX]*diff/ (60*12);
+ /* hp«ìÅ@ */
+ if(!thechicken->sick)
+ thechicken->hp +=
+ time_change[(int)thechicken->type][HP_MAX]*diff/ (60*6);
+ if(thechicken->hp>thechicken->hp_max)
+ thechicken->hp = thechicken->hp_max;
+ /* mm_max */
+ if(thechicken->mm >= thechicken->mm_max/2)
+ thechicken->mm_max +=
+ time_change[(int)thechicken->type][MM_MAX]*diff/ (60*8);
+ /* mm«ìÅ@ */
+ if(!thechicken->sick)
+ thechicken->mm += diff;
+ if(thechicken->mm>thechicken->mm_max)
+ thechicken->mm = thechicken->mm_max;
+}
+
+static void check_sick() {
+ /* ż¯fªº */
+ if(mychicken->tiredstrong > mychicken->hp * 0.3 && mychicken->clean > 150)
+ mychicken->sick += (mychicken->clean - 150) / 10;
+ /* ²Ö¯fªº */
+ if(mychicken->tiredstrong > mychicken->hp*1.3)
+ mychicken->sick += time_change[(int)mychicken->type][SICK];
+ /* ¯f®ð¤Ó­«ÁÙ°µ¨Æ´îhp */
+ if(mychicken->sick > mychicken->hp / 5) {
+ mychicken->hp -= (mychicken->sick - mychicken->hp / 5)/4;
+ if(mychicken->hp < 0 )
+ mychicken->hp = 0;
+ }
+}
+
+static int deadtype(chicken_t *thechicken) {
+ int i;
+ char buf[150];
+ time_t now = time(NULL);
+
+ if(thechicken->hp <= 0) /* hp¥ÎºÉ */
+ i = 1;
+ else if(thechicken->tiredstrong > thechicken->hp * 3 ) /* ¾Þ³Ò¹L«× */
+ i = 2;
+ else if(thechicken->weight > thechicken->hp_max*5) /* ªÎ­D¹L«× */
+ i = 3;
+ else if(thechicken->weight == 1 &&
+ thechicken->sick > thechicken->hp_max / 4)
+ i = 4; /* ¾j¦º¤F */
+ else if(thechicken->satis <= 0) /* «Ü¤£º¡·N */
+ i = 5;
+ else
+ return 0;
+
+ if(thechicken == mychicken) {
+ sprintf(buf,"\033[31m%s\033[m ©Ò¯k·Rªº\033[33m %s\033[32m %s "
+ "\033[m±¾¤F ©ó %s",
+ cuser.userid, thechicken->name,
+ chicken_type[(int)thechicken->type],
+ ctime(&now));
+ log_file(CHICKENLOG, buf);
+ mychicken->name[0] = 0;
+ passwd_update(usernum, &cuser);
+ }
+ return i;
+}
+
+int showdeadth(int type) {
+ switch(type) {
+ case 1:
+ more(CHICKEN_PIC "/nohp",YEA);
+ break;
+ case 2:
+ more(CHICKEN_PIC "/tootired",YEA);
+ break;
+ case 3:
+ more(CHICKEN_PIC "/toofat",YEA);
+ break;
+ case 4:
+ more(CHICKEN_PIC "/nofood",YEA);
+ break;
+ case 5:
+ more(CHICKEN_PIC "/nosatis", YEA);
+ break;
+ default:
+ return 0;
+ }
+ more(CHICKEN_PIC "/deadth",YEA);
+ return type;
+}
+
+int isdeadth(chicken_t *thechicken) {
+ int i;
+
+ if(!(i = deadtype(thechicken)))
+ return 0;
+ return showdeadth(i);
+}
+
+static void ch_changename() {
+ char buf[150], newname[20] = "";
+ time_t now = time(NULL);
+
+ getdata_str(b_lines - 1, 0, "¶â..§ï­Ó¦n¦W¦r§a:", newname, 18, DOECHO,
+ mychicken->name);
+
+ if(strlen(newname) >= 3 && strcmp(newname,mychicken->name)) {
+ sprintf(buf, "\033[31m%s\033[m §â¯k·Rªº\033[33m %s\033[32m %s "
+ "\033[m§ï¦W¬°\033[33m %s\033[m ©ó %s",
+ cuser.userid, mychicken->name,
+ chicken_type[(int)mychicken->type],
+ newname, ctime(&now));
+ strcpy(mychicken->name, newname);
+ log_file(CHICKENLOG,buf);
+ }
+}
+
+static int select_menu() {
+ char ch;
+
+ reload_money();
+ move(19,0);
+ prints("\033[44;37m ¿ú :\033[33m %-10d "
+ " \033[m\n"
+ "\033[33m(\033[37m1\033[33m)²M²z (\033[37m2\033[33m)¦Y¶º "
+ "(\033[37m3\033[33m)²q®± (\033[37m4\033[33m)°á®Ñ "
+ "(\033[37m5\033[33m)¿Ë¥L (\033[37m6\033[33m)¥´¥L "
+ "(\033[37m7\033[33m)¶R%s$%d (\033[37m8\033[33m)¦Y¸É¤Y\n"
+ "(\033[37m9\033[33m)¦Y¯fÃÄ (\033[37mo\033[33m)¶R¤j¸É¤Y$100 "
+ "(\033[37mm\033[33m)¶RÃÄ$10 (\033[37mk\033[33m)±ó¾i "
+ "(\033[37ms\033[33m)½æ±¼ (\033[37mn\033[33m)§ï¦W "
+ "(\033[37mq\033[33m)Â÷¶}:\033[m",
+ cuser.money,
+ /*chicken_food[(int)mychicken->type],
+ chicken_type[(int)mychicken->type],
+ chicken_type[(int)mychicken->type],*/
+ chicken_food[(int)mychicken->type],
+ food_price[(int)mychicken->type]);
+ do {
+ switch(ch = igetch()) {
+ case '1':
+ ch_clean();
+ check_sick();
+ break;
+ case '2':
+ ch_eat();
+ check_sick();
+ break;
+ case '3':
+ ch_guess();
+ check_sick();
+ break;
+ case '4':
+ ch_book();
+ check_sick();
+ break;
+ case '5':
+ ch_kiss();
+ break;
+ case '6':
+ ch_hit();
+ check_sick();
+ break;
+ case '7':
+ ch_buyitem(food_price[(int)mychicken->type], CHICKEN_PIC "/food",
+ &mychicken->food);
+ break;
+ case '8':
+ ch_eatoo();
+ break;
+ case '9':
+ ch_eatmedicine();
+ break;
+ case 'O':
+ case 'o':
+ ch_buyitem(100, CHICKEN_PIC "/buyoo", &mychicken->oo);
+ break;
+ case 'M':
+ case 'm':
+ ch_buyitem(10, CHICKEN_PIC "/buymedicine", &mychicken->medicine);
+ break;
+ case 'N':
+ case 'n':
+ ch_changename();
+ break;
+ case 'K':
+ case 'k':
+ ch_kill();
+ return 0;
+ case 'S':
+ case 's':
+ if(!ch_sell()) break;
+ case 'Q':
+ case 'q':
+ return 0;
+ }
+ } while(ch < ' ' || ch>'z');
+ return 1;
+}
+
+static int recover_chicken(chicken_t *thechicken) {
+ char buf[200];
+ int price = egg_price[(int)thechicken->type],
+ money = price + (rand() % price);
+
+ if(time(NULL) - thechicken->lastvisit > (60 * 60 * 24 * 7))
+ return 0;
+ outmsg("\033[33;44m¡¹ÆF¬É¦u½Ã\033[37;45m §O®`©È §Ú¬O¨ÓÀ°§Aªº \033[m");
+ bell();
+ igetch();
+ outmsg("\033[33;44m¡¹ÆF¬É¦u½Ã\033[37;45m §AµLªk¥á¨ì§Ú¤ô²y ¦]¬°§Ú¬O¸tÆF, "
+ "³Ìªñ¯Ê¿ú·QÁÈ¥~§Ö \033[m");
+ bell();
+ igetch();
+ sprintf(buf, "\033[33;44m¡¹ÆF¬É¦u½Ã\033[37;45m "
+ "§A¦³¤@­Ó­è¨«¤£¤[ªº%s­n©Û´«¦^¨Ó¶Ü? ¥u­n%d¤¸­ò \033[m",
+ chicken_type[(int)thechicken->type], price*2);
+ outmsg(buf);
+ bell();
+ getdata_str(21, 0, " ¿ï¾Ü¡G(N:§|¤H¹À/y:½ÐÀ°À°§Ú)", buf, 3, LCECHO, "N");
+ if(buf[0] == 'y' || buf[0] == 'Y') {
+ reload_money();
+ if(cuser.money < price*2) {
+ outmsg("\033[33;44m¡¹ÆF¬É¦u½Ã\033[37;45m ¤°»ò ¿ú¨S±a°÷ "
+ "¨S¿úªº¤p°­ §Ö¥hÄw¿ú§a \033[m");
+ bell();
+ igetch();
+ return 0;
+ }
+ strcpy(thechicken->name, "[¾ß¦^¨Óªº]");
+ thechicken->hp = thechicken->hp_max;
+ thechicken->sick = 0;
+ thechicken->satis = 2;
+ vice(money,"ÆF¬É¦u½Ã");
+ sprintf(buf, "\033[33;44m¡¹ÆF¬É¦u½Ã\033[37;45m OK¤F °O±oÁý¥LÂIªF¦è "
+ "¤£µM¥i¯à¥¢®Ä ©À¦b§Ú¤]¦³ª±Ptt ®³§A%d´N¦n \033[m", money);
+ outmsg(buf);
+ bell();
+ igetch();
+ return 1;
+ }
+ outmsg("\033[33;44m¡¹ÆF¬É¦u½Ã\033[37;45m ³ºµM»¡§Ú§|¤H! ³o¦~ÀY©R¯u¤£­È¿ú "
+ "°£«D§Ú¦A¨Ó§ä§A §A¦A¤]¨S¾÷·|¤F \033[m");
+ bell();
+ igetch();
+ thechicken->lastvisit = 0;
+ passwd_update(usernum, &cuser);
+ return 0;
+}
+
+#define lockreturn0(unmode, state) if(lockutmpmode(unmode, state)) return 0
+
+int chicken_main() {
+ lockreturn0(CHICKEN, LOCK_MULTI);
+
+ reload_chicken();
+ age = ((time(NULL) - mychicken->cbirth)/ (60*60*24));
+ if(!mychicken->name[0] && !recover_chicken(mychicken) && !new_chicken()) {
+ unlockutmpmode();
+ return 0;
+ }
+
+ do {
+ time_diff(mychicken);
+ if(isdeadth(mychicken))
+ break;
+ show_chicken_data(mychicken, NULL);
+ } while(select_menu());
+ reload_money();
+ passwd_update(usernum, &cuser);
+ unlockutmpmode();
+ return 0;
+}
+
+extern userinfo_t *currutmp;
+extern struct utmpfile_t *utmpshm;
+
+int chickenpk(int fd) {
+ char mateid[IDLEN + 1], data[200], buf[200];
+ int ch = 0;
+
+ userinfo_t *uin = &utmpshm->uinfo[currutmp->destuip];
+ userec_t ouser;
+ chicken_t *ochicken = &ouser.mychicken;
+ int r, attmax, i, datac, duid = currutmp->destuid, catched=0, count=0;
+
+ lockreturn0(CHICKEN, LOCK_MULTI);
+
+ strcpy(mateid, currutmp->mateid); /*§â¹ï¤âªºid¥Îlocal buffer°O¦í*/
+
+ getuser(mateid) ;
+ memcpy(&ouser, &xuser, sizeof(userec_t));
+ reload_chicken();
+ if(!ochicken->name[0] || !mychicken->name[0]) {
+ outmsg("¦³¤@¤è¨S¦³Ãdª«"); /* Ptt:§«¤îpage®É§âÃdª«½æ±¼ */
+ bell();
+ refresh();
+ add_io(0, 0);
+ close(fd);
+ unlockutmpmode();
+ sleep(1);
+ return 0;
+ }
+
+ show_chicken_data(ochicken, mychicken);
+ add_io(fd, 3); /* §âfd¥[¨ìigetchºÊµø */
+ while(1) {
+ r = rand();
+ ch = igetkey();
+ getuser(mateid) ;
+ memcpy(&ouser, &xuser, sizeof(userec_t));
+ reload_chicken();
+ show_chicken_data(ochicken, mychicken);
+ time_diff(mychicken);
+
+ i = mychicken->attack* mychicken->hp / mychicken->hp_max;
+ for(attmax=2; (i = i*9/10); attmax++);
+
+ if(ch == I_OTHERDATA) {
+ count =0;
+ datac = recv(fd, data, sizeof(data), 0);
+ if(datac <= 1)
+ break;
+ move(17,0);
+ outs(data+1);
+ switch(data[0]) {
+ case 'c':
+ catched=1;
+ move(16,0);
+ outs("­n©ñ¥L¨«¶Ü?(y/N)");
+ break;
+ case 'd':
+ move(16,0);
+ outs("ªü~­Ë¤U¤F!!");
+ break;
+ }
+ if(data[0] == 'd' || data[0]=='q' || data[0]=='l')
+ break;
+ continue;
+ } else if(currutmp->turn) {
+ count = 0;
+ currutmp->turn = 0;
+ uin->turn = 1;
+ mychicken->tiredstrong ++;
+ switch(ch) {
+ case 'y':
+ if(catched == 1) {
+ sprintf(data, "lÅý %s ¸¨¶]¤F\n",
+ ochicken->name);
+ }
+ break;
+ case 'n':
+ catched =0;
+ default:
+ case 'k':
+ r = r % (attmax + 2);
+ if(r) {
+ sprintf(data, "M%s %s%s %s ¶Ë¤F %d ÂI\n", mychicken->name,
+ damage_degree[r/3>15 ? 15:r/3],
+ attack_type[(int)mychicken->type],
+ ochicken->name, r);
+ ochicken->hp-=r;
+ } else
+ sprintf(data, "M%s ı±o¤â³n¥XÀ»µL®Ä\n", mychicken->name);
+ break;
+ case 'o':
+ if(mychicken->oo > 0) {
+ mychicken->oo--;
+ mychicken->hp += 300;
+ if(mychicken->hp > mychicken->hp_max)
+ mychicken->hp = mychicken->hp_max;
+ mychicken->tiredstrong = 0;
+ sprintf(data, "M%s ¦Y¤FÁû¤j¸É¤Y¸É¥RÅé¤O\n",
+ mychicken->name);
+ } else
+ sprintf(data, "M%s ·Q¦Y¤j¸É¤Y, ¥i¬O¨S¦³¤j¸É¤Y¥i¦Y\n",
+ mychicken->name);
+ break;
+ case 'q':
+ if(r % (mychicken->run+1) > r % (ochicken->run+1))
+ sprintf(data, "q%s ¸¨¶]¤F\n",
+ mychicken->name);
+ else
+ sprintf(data, "c%s ·Q¸¨¶], ¦ý³Q %s §ì¨ì¤F\n",
+ mychicken->name, ochicken->name);
+ break;
+ }
+ if(deadtype(ochicken)) {
+ strtok(data,"\n");
+ strcpy(buf, data);
+ sprintf(data, "d%s , %s ³Q %s ¥´¦º¤F\n",
+ buf + 1, ochicken->name, mychicken->name);
+ }
+ move(17,0);
+ outs(data+1);
+ i = strlen(data) +1;
+ passwd_update(duid, &ouser);
+ passwd_update(usernum, &cuser);
+ send(fd, data, i, 0);
+ if(data[0]=='q' || data[0]=='d')
+ break;
+ } else {
+ move(17, 0);
+ if(count++ > 30)
+ break;
+ }
+ }
+ add_io(0, 0); /* §âigetch«ìÅ@¦^ */
+ pressanykey();
+ close(fd);
+ if(!showdeadth(deadtype(mychicken)));
+ unlockutmpmode();
+ return 0;
+}
diff --git a/mbbsd/dark.c b/mbbsd/dark.c
new file mode 100644
index 00000000..52741617
--- /dev/null
+++ b/mbbsd/dark.c
@@ -0,0 +1,456 @@
+/* $Id: dark.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "proto.h"
+
+#define RED 1
+#define BLACK 0
+typedef short int sint;
+
+typedef struct item {
+ short int color,value,die,out;
+} item;
+
+typedef struct cur{
+ short int y,x,end;
+} cur;
+
+static item brd[4][8];
+static cur curr; /* 6 ­Ó bytes */
+extern userinfo_t *currutmp;
+
+static char *rname[]={"§L","¬¶","ØX","¨®","¬Û","¥K","«Ó"};
+static char *bname[]={"¨ò","¥]","°¨","¨®","¶H","¤h","±N"};
+
+static sint cury[]={3,5,7,9}, curx[]={5,9,13,17,21,25,29,33};
+static sint rcount,bcount,cont,fix; /* cont:¬O§_¥i³s¦Y */
+static sint my=0,mx=0,mly=-1,mlx=-1; /* ²¾°Êªº®y¼Ð ¸ò ¿ï¤lªº®y¼Ð */
+
+static sint cur_eaty,cur_eatx; /* ¦Y±¼¹ï¤è¨ä¤lªº¨q¥X®y¼Ð */
+static void brdswap(sint y,sint x,sint ly,sint lx) {
+ memcpy(&brd[y][x],&brd[ly][lx],sizeof(item));
+ brd[ly][lx].die=1;
+ brd[ly][lx].color=-1; /* ¨S³o­Ócolor */
+ brd[ly][lx].value=-1;
+}
+
+static void pprints(sint y,sint x,char* s) {
+ move(y,x);
+ clrtoeol();
+ prints("%s",s);
+}
+
+static sint Is_win(item att, item det, sint y, sint x, sint ly, sint lx) {
+ sint i,c=0,min,max;
+ if(att.value == 1) /* ¯¥ */
+ {
+ if(y!=ly && x!=lx) return 0;
+ if((abs(ly-y)==1 && brd[y][x].die==0)||
+ (abs(lx-x)==1 && brd[y][x].die==0))
+ return 0;
+ if(y==ly){
+ if(x>lx) {max=x;min=lx;}
+ else {max=lx;min=x;}
+ for(i=min+1;i<max;i++)
+ if(brd[y][i].die==0) c++;
+ }else if(x==lx){
+ if(y>ly) {max=y;min=ly;}
+ else {max=ly;min=y;}
+ for(i=min+1;i<max;i++)
+ if(brd[i][x].die==0) c++;
+ }
+ if(c != 1) return 0;
+ if(det.die == 1) return 0;
+ return 1;
+ }
+ /* «D¯¥ */
+ if( ((abs(ly-y)==1&&x==lx) || (abs(lx-x)==1&&ly==y)) && brd[y][x].out==1 )
+ {
+ if(att.value == 0 && det.value == 6) return 1;
+ else if(att.value == 6 && det.value == 0) return 0;
+ else if(att.value >= det.value) return 1;
+ else return 0;
+ }
+ return 0;
+}
+
+static sint Is_move(sint y,sint x, sint ly, sint lx) {
+ if(brd[y][x].die==1 && ((abs(ly-y)==1&&x==lx) || (abs(lx-x)==1&&ly==y)))
+ return 1;
+ return 0;
+}
+
+static void brd_rand() {
+ sint y,x,index;
+ sint tem[32];
+ sint value[32]={0,0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,
+ 0,0,0,0,0,1,1,2,2,3,3,4,4,5,5,6};
+
+ bzero(brd, sizeof(brd));
+ bzero(tem, sizeof(tem));
+ bzero(&curr, sizeof(curr));
+ srand(getpid()%2731+time(NULL)%3219);
+ for(y=0;y<4;y++)
+ for(x=0;x<8;x++)
+ while(1) {
+ index=rand()%32;
+ if(tem[index]) continue;
+ brd[y][x].color=(index>15)?0:1;
+ brd[y][x].value=value[index];
+ tem[index]=1;
+ break;
+ }
+}
+
+static void brd_prints() {
+ clear();
+ move(1,0);
+ outs("
+ ¢~¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢¡
+ ¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x
+ ¢u¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t
+ ¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x
+ ¢u¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t
+ ¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x
+ ¢u¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t
+ ¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x¡´¢x
+ ¢¢¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢£
+ ");
+}
+
+static void draw_line(sint y, sint f) {
+ sint i;
+ char buf[1024],tmp[256];
+
+ *buf = 0;
+ *tmp = 0;
+ strcpy(buf,"\033[43;30m");
+ for(i=0; i<8; i++)
+ {
+ if(brd[y][i].die==1)
+ sprintf(tmp,"¢x ");
+ else if(brd[y][i].out==0)
+ sprintf(tmp,"¢x¡´");
+ else {
+ sprintf(tmp, "¢x\033[%s1;%dm%s\033[m\033[43;30m",
+ (f==i)?"1;47;":"",(brd[y][i].color)?31:34,
+ (brd[y][i].color)?rname[brd[y][i].value]:
+ bname[brd[y][i].value]);
+ }
+ strcat(buf,tmp);
+ }
+ strcat(buf,"¢x\033[m");
+
+ move(cury[y],3);
+ clrtoeol();
+ prints("%s",buf);
+}
+
+static void redraw() {
+ sint i=0;
+ for(;i<4;i++)
+ draw_line(i,-1);
+}
+
+static sint playing(sint fd, sint color,sint ch,sint *b, userinfo_t *uin) {
+ curr.end = 0;
+ move(cury[my],curx[mx]);
+
+ if(fix) {
+ if(ch=='s') {
+ fix=0; *b=0; return 0;
+ } else {
+ draw_line(mly,-1);
+ }
+ }
+
+ switch(ch) {
+ case KEY_LEFT:
+ if(mx == 0) mx=7;
+ else mx--;
+ move(cury[my],curx[mx]);
+ *b=-1;
+ break;
+ case KEY_RIGHT:
+ if(mx==7) mx=0;
+ else mx++;
+ move(cury[my],curx[mx]);
+ *b=-1;
+ break;
+ case KEY_UP:
+ if(my==0) my=3;
+ else my--;
+ move(cury[my],curx[mx]);
+ *b=-1;
+ break;
+ case KEY_DOWN:
+ if(my==3) my=0;
+ else my++;
+ move(cury[my],curx[mx]);
+ *b=-1;
+ break;
+ case 'q':case 'Q':
+ if(!color) bcount=0;
+ else rcount=0;
+ *b=0;
+ return -2;
+ case 'p':case 'P':
+ return -3;
+ case 'c':
+ return -4;
+ case 'g':
+ return -5;
+ case 's': /* ½¶}´Ñ¤l ©Î¬O¿ï¾Ü´Ñ¤l */
+ /* ¿ï¾Ü´Ñ¤l */
+ if(brd[my][mx].out==1)
+ {
+ if(brd[my][mx].color != color)
+ {
+ *b=-1;
+ break;
+ }
+ if(mly<0) /*¥i¥H¿ï¾Ü*/
+ {
+ mly=my;mlx=mx;
+ draw_line(my,mx);
+ *b=-1;
+ break;
+ }
+ else if(mly == my && mlx == mx) /*¤£¿ï¤F*/
+ {
+ mly=-1;mlx=-1;
+ draw_line(my,-1);
+ }else
+ {
+ draw_line(mly,-1);
+ mly=my;mlx=mx;
+ if(brd[mly][mlx].value == 1) fix=1;
+ draw_line(my,mx);
+ }
+ *b=-1;
+ break;
+ }
+ /* ½¶}´Ñ¤l */
+ if(mly >=0 ){ *b=-1; break;} /*¥»¨Ó´N¬O½¶}ªº*/
+ /* ¨M©w¤@¶}©lªºÃC¦â */
+ if(currutmp->color=='.'){
+ if(uin->color!='1' && uin->color!='0')
+ currutmp->color=(brd[my][mx].color)?'1':'0';
+ else
+ currutmp->color=(uin->color=='0')?'1':'0';}
+ brd[my][mx].out=1;
+ draw_line(my,-1);
+ move(cury[my],curx[mx]);
+ *b=0;
+ break;
+ case 'u':
+ move(0,0);clrtoeol();
+ prints("%s¦â%s cont=%d",(brd[my][mx].color == RED)?"¬õ":"¶Â",rname[brd[my][mx].value],cont);
+ *b=-1;
+ break;
+ case '\r': /* ¦Y or ²¾°Ê ly¸òlx¥²¶·¤j©ó0*/
+ case '\n':
+ if(
+ mly >= 0 /* ­n¥ý¿ï¤l */
+ &&
+ brd[mly][mlx].color != brd[my][mx].color /* ¦P¦â¤£¯à²¾°Ê¤]¤£¯à¦Y */
+ &&
+ (Is_move(my,mx,mly,mlx) || Is_win(brd[mly][mlx],brd[my][mx],my,mx,mly,mlx))
+ )
+ {
+ if(fix && brd[my][mx].value<0)
+ {
+ *b=-1;return 0;
+ }
+ if(brd[my][mx].value>=0&&brd[my][mx].die==0)
+ {
+ if(!color) bcount--;
+ else rcount--;
+ move(cur_eaty,cur_eatx);
+ prints("%s",(color)?bname[brd[my][mx].value]:rname[brd[my][mx].value]);
+ if(cur_eatx>=26)
+ { cur_eatx=5;cur_eaty++; }
+ else
+ cur_eatx+=3;
+ }
+ brdswap(my,mx,mly,mlx);
+ draw_line(mly,-1);
+ draw_line( my,-1);
+ if(fix==1) *b=-1;
+ else { mly=-1;mlx=-1;*b=0; }
+ }
+ else *b=-1;
+ break;
+ default:
+ *b=-1;
+ }
+
+ if(!rcount)
+ return -1;
+ else if(!bcount)
+ return -1;
+ if(*b == -1) return 0;
+ curr.y = my;curr.x = mx; curr.end=(!*b)?1:0;
+ send(fd,&curr,sizeof(curr),0);
+ send(fd,&brd,sizeof(brd),0);
+ return 0;
+}
+
+int main_dark(int fd,userinfo_t *uin) {
+ sint end=0,ch=1,go_on,i=0,cont=0;
+ char buf[16];
+ *buf=0;fix=0;
+ currutmp->color='.'; // '.' ªí¥ÜÁÙ¨S¨M©wÃC¦â
+ rcount=16;bcount=16; // initialize
+ cur_eaty=18,cur_eatx=5;
+ brd_prints();
+ if(currutmp->turn)
+ {
+ brd_rand();
+ send(fd,&brd,sizeof(brd),0);
+ pprints(21,0," ¡»§A¬O¥ý¤â");
+ pprints(22,0," ¡»½ü¨ì§A¤U¤F");
+ }else
+ {
+ recv(fd,&brd,sizeof(brd),0);
+ pprints(21,0," ¡»§A¬O«á¤â");
+ }
+ move(12,3);
+ prints("%s[0³Ó0±Ñ]¢þ¢û.%s[0³Ó0±Ñ]",currutmp->userid,currutmp->mateid);
+ outs("
+ ¢®¢¬¥\\¯àªí¢­¢®¢­¢¬¢®¢­
+ ¢¬ ¡ô¡ö¡õ¡÷: ²¾°Ê
+ ¢® ¢û:  ¿ï¤l,½¤l
+ ¢¬ enter:  ¦Y´Ñ,©ñ´Ñ
+¡@¤w¸g¸Ñ¨Mªº:¡@¡@ ¢® ¢ø:  ¦X´Ñ
+ ¡@¡@ ¢¬ ¢ù:  »{¿é
+ ¢® ¢ë:  ´«Ãä");
+
+ if(currutmp->turn) move(cury[0],curx[0]);
+
+ add_io(fd, 0);
+ while(end<=0)
+ {
+ if(uin->turn=='w' || currutmp->turn=='w') { end=-1; break; }
+
+ ch = igetkey();
+ if(ch == I_OTHERDATA)
+ {
+ ch=recv(fd,&curr,sizeof(curr),0);
+ if(ch!=sizeof(curr))
+ {
+ if(uin->turn=='e') { end=-3;break; }
+ else if(uin->turn!='w') { end=-1; currutmp->turn='w'; break; }
+ end=-1; break;
+ }
+
+ if(curr.end==-3) pprints(23,30,"\033[33m­n¨D¦X´Ñ\033[m");
+ else if(curr.end==-4) pprints(23,30,"\033[33m­n¨D´«Ãä\033[m");
+ else if(curr.end==-5) pprints(23,30,"\033[33m­n¨D³s¦Y\033[m");
+ else pprints(23,30,"");
+
+ recv(fd,&brd,sizeof(brd),0);
+ my=curr.y;mx=curr.x;
+ redraw();
+ if(curr.end)
+ pprints(22,0," ¡»½ü¨ì§A¤U¤F");
+ move(cury[my],curx[mx]);
+ }else
+ {
+ if(currutmp->turn=='p')
+ {
+ if(ch=='y') { end=-3; currutmp->turn='e'; break; }
+ else { pprints(23,30,""); *buf=0; currutmp->turn=(uin->turn)?0:1; }
+ }else if(currutmp->turn=='c')
+ {
+ if(ch=='y') { currutmp->color=(currutmp->color=='1')?'0':'1';
+ uin->color=(uin->color=='1')?'0':'1';
+ pprints(21,0,(currutmp->color=='1')?" \033[1;33m¡»§A«ù¬õ¦â´Ñ\033[m":" \033[1;33m¡»§A«ù¶Â¦â´Ñ\033[m");
+ }
+ else { pprints(23,30,""); currutmp->turn=(uin->turn)?0:1; }
+ }else if(currutmp->turn=='g')
+ {
+ if(ch=='y') {
+ cont=1;
+ pprints(21,0," \033[1;33m¡»§A«ù¬õ¦â´Ñ\033[m ¥i³s¦Y");
+ }
+ else { pprints(23,30,""); currutmp->turn=(uin->turn)?0:1; }
+ }
+
+ if(currutmp->turn==1)
+ {
+ if(uin->turn=='g') { cont=1;uin->turn=(currutmp->turn)?0:1; pprints(21,10,"¥i³s¦Y"); }
+ end=playing(fd,currutmp->color-'0',ch,&go_on,uin);
+
+ if(end == -1) { currutmp->turn='w';break; }
+ else if(end == -2) { uin->turn='w';break; }
+ else if(end == -3) {
+ uin->turn='p';curr.end=-3;
+ send(fd,&curr,sizeof(curr),0);
+ send(fd,&brd,sizeof(buf),0);
+ continue;
+ }
+ else if(end == -4) {
+ if(currutmp->color!='1'&&currutmp->color!='0')
+ continue;
+ uin->turn='c';i=0;curr.end=-4;
+ send(fd,&curr,sizeof(curr),0);
+ send(fd,&brd,sizeof(buf),0);
+ continue;
+ }
+ else if(end == -5) {
+ uin->turn='g';curr.end=-5;
+ send(fd,&curr,sizeof(curr),0);
+ send(fd,&brd,sizeof(buf),0);
+ continue;
+ }
+ if(!i && currutmp->color=='1')
+ { pprints(21,0," \033[1;33m¡»§A«ù¬õ¦â´Ñ\033[m");i++;move(cury[my],curx[mx]); }
+ if(!i && currutmp->color=='0')
+ { pprints(21,0," \033[1;33m¡»§A«ù¶Â¦â´Ñ\033[m");i++;move(cury[my],curx[mx]); }
+
+ if(uin->turn == 'e') { end=-3; break; }
+ if(go_on < 0) continue;
+
+ move(22,0);clrtoeol();
+ prints(" ¡»½ü¨ì%s¤U §O©È§O©È ¥LºâÔ£¦Ì",currutmp->mateid);
+ currutmp->turn = 0;
+ uin->turn = 1;
+ }else
+ {
+ if(ch == 'q'){uin->turn='w';break;}
+ move(22,0);clrtoeol();
+ prints(" ¡»½ü¨ì%s¤U §O©È§O©È ¥LºâÔ£¦Ì",currutmp->mateid);
+ }
+ }
+ }
+
+ switch(end)
+ {
+ case -1:
+ case -2:
+ if(currutmp->turn=='w'){ move(22,0);clrtoeol();prints("§AŤF.. ¯u¬O®¥³ß~~");}
+ else {move(22,0);clrtoeol();prints("¿é±¼¤F°Õ.....¤U¦¸Åý¥L¦n¬Ý!!");}
+ break;
+ case -3:
+ pprints(22,0,"¦X´Ñ­ò!! ¤U¦¸¦b¤À°ª¤U§a ^_^");
+ break;
+ default:
+ add_io(0,0);
+ close(fd);
+ pressanykey();
+ return 0;
+ }
+ add_io(0,0);
+ close(fd);
+ pressanykey();
+ return 0;
+}
diff --git a/mbbsd/descrypt.c b/mbbsd/descrypt.c
new file mode 100644
index 00000000..3bb0a5e5
--- /dev/null
+++ b/mbbsd/descrypt.c
@@ -0,0 +1,616 @@
+/* $Id: descrypt.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+
+/*
+ * FreeSec: libcrypt for NetBSD
+ *
+ * Copyright (c) 1994 David Burren
+ * All rights reserved.
+ *
+ * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet
+ * crypt.c should now *only* export crypt(), in order to make
+ * binaries of libcrypt exportable from the USA
+ *
+ * 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.
+ * 4. Neither the name of the author nor the names of other contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: src/secure/lib/libcrypt/crypt.c,v 1.11 1999/08/28 01:30:24 peter Exp $
+ *
+ * This is an original implementation of the DES and the crypt(3) interfaces
+ * by David Burren <davidb@werj.com.au>.
+ *
+ * An excellent reference on the underlying algorithm (and related
+ * algorithms) is:
+ *
+ * B. Schneier, Applied Cryptography: protocols, algorithms,
+ * and source code in C, John Wiley & Sons, 1994.
+ *
+ * Note that in that book's description of DES the lookups for the initial,
+ * pbox, and final permutations are inverted (this has been brought to the
+ * attention of the author). A list of errata for this book has been
+ * posted to the sci.crypt newsgroup by the author and is available for FTP.
+ *
+ * ARCHITECTURE ASSUMPTIONS:
+ * This code assumes that u_longs are 32 bits. It will probably not
+ * operate on 64-bit machines without modifications.
+ * It is assumed that the 8-byte arrays passed by reference can be
+ * addressed as arrays of u_longs (ie. the CPU is not picky about
+ * alignment).
+ */
+
+#ifndef HAVE_DES_CRYPT
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <pwd.h>
+#include <string.h>
+
+static unsigned char IP[64] = {
+ 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
+};
+
+static unsigned char inv_key_perm[64];
+static unsigned char u_key_perm[56];
+static unsigned char key_perm[56] = {
+ 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
+};
+
+static unsigned char key_shifts[16] = {
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+static unsigned char inv_comp_perm[56];
+static unsigned char comp_perm[48] = {
+ 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
+};
+
+/*
+ * No E box is used, as it's replaced by some ANDs, shifts, and ORs.
+ */
+
+static unsigned char u_sbox[8][64];
+static unsigned char sbox[8][64] = {
+ {
+ 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
+ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
+ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
+ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13
+ },
+ {
+ 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
+ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
+ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
+ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
+ },
+ {
+ 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
+ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
+ 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
+ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12
+ },
+ {
+ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
+ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
+ 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
+ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
+ },
+ {
+ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
+ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
+ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
+ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3
+ },
+ {
+ 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
+ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
+ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
+ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
+ },
+ {
+ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
+ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
+ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
+ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
+ },
+ {
+ 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
+ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
+ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
+ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
+ }
+};
+
+static unsigned char un_pbox[32];
+static unsigned char pbox[32] = {
+ 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
+ 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
+};
+
+static unsigned long bits32[32] = {
+ 0x80000000, 0x40000000, 0x20000000, 0x10000000,
+ 0x08000000, 0x04000000, 0x02000000, 0x01000000,
+ 0x00800000, 0x00400000, 0x00200000, 0x00100000,
+ 0x00080000, 0x00040000, 0x00020000, 0x00010000,
+ 0x00008000, 0x00004000, 0x00002000, 0x00001000,
+ 0x00000800, 0x00000400, 0x00000200, 0x00000100,
+ 0x00000080, 0x00000040, 0x00000020, 0x00000010,
+ 0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+static unsigned char bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+
+static unsigned long saltbits;
+static long old_salt;
+static unsigned long *bits28, *bits24;
+static unsigned char init_perm[64], final_perm[64];
+static unsigned long en_keysl[16], en_keysr[16];
+static unsigned long de_keysl[16], de_keysr[16];
+static int des_initialised = 0;
+static unsigned char m_sbox[4][4096];
+static unsigned long psbox[4][256];
+static unsigned long ip_maskl[8][256], ip_maskr[8][256];
+static unsigned long fp_maskl[8][256], fp_maskr[8][256];
+static unsigned long key_perm_maskl[8][128], key_perm_maskr[8][128];
+static unsigned long comp_maskl[8][128], comp_maskr[8][128];
+static unsigned long old_rawkey0, old_rawkey1;
+
+static unsigned char ascii64[] =
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+/* 0000000000111111111122222222223333333333444444444455555555556666 */
+/* 0123456789012345678901234567890123456789012345678901234567890123 */
+
+static int ascii_to_bin(char ch) {
+ if(ch > 'z')
+ return 0;
+ if(ch >= 'a')
+ return ch - 'a' + 38;
+ if(ch > 'Z')
+ return 0;
+ if(ch >= 'A')
+ return ch - 'A' + 12;
+ if(ch > '9')
+ return 0;
+ if(ch >= '.')
+ return ch - '.';
+ return 0;
+}
+
+static void des_init() {
+ int i, j, b, k, inbit, obit;
+ unsigned long *p, *il, *ir, *fl, *fr;
+
+ old_rawkey0 = old_rawkey1 = 0L;
+ saltbits = 0L;
+ old_salt = 0L;
+ bits24 = (bits28 = bits32 + 4) + 4;
+
+ /*
+ * Invert the S-boxes, reordering the input bits.
+ */
+ for(i = 0; i < 8; i++)
+ for(j = 0; j < 64; j++) {
+ b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf);
+ u_sbox[i][j] = sbox[i][b];
+ }
+
+ /*
+ * Convert the inverted S-boxes into 4 arrays of 8 bits.
+ * Each will handle 12 bits of the S-box input.
+ */
+ for(b = 0; b < 4; b++)
+ for(i = 0; i < 64; i++)
+ for(j = 0; j < 64; j++)
+ m_sbox[b][(i << 6) | j] =
+ (u_sbox[(b << 1)][i] << 4) |
+ u_sbox[(b << 1) + 1][j];
+
+ /*
+ * Set up the initial & final permutations into a useful form, and
+ * initialise the inverted key permutation.
+ */
+ for(i = 0; i < 64; i++) {
+ init_perm[final_perm[i] = IP[i] - 1] = i;
+ inv_key_perm[i] = 255;
+ }
+
+ /*
+ * Invert the key permutation and initialise the inverted key
+ * compression permutation.
+ */
+ for(i = 0; i < 56; i++) {
+ u_key_perm[i] = key_perm[i] - 1;
+ inv_key_perm[key_perm[i] - 1] = i;
+ inv_comp_perm[i] = 255;
+ }
+
+ /*
+ * Invert the key compression permutation.
+ */
+ for(i = 0; i < 48; i++) {
+ inv_comp_perm[comp_perm[i] - 1] = i;
+ }
+
+ /*
+ * Set up the OR-mask arrays for the initial and final permutations,
+ * and for the key initial and compression permutations.
+ */
+ for(k = 0; k < 8; k++) {
+ for(i = 0; i < 256; i++) {
+ *(il = &ip_maskl[k][i]) = 0L;
+ *(ir = &ip_maskr[k][i]) = 0L;
+ *(fl = &fp_maskl[k][i]) = 0L;
+ *(fr = &fp_maskr[k][i]) = 0L;
+ for(j = 0; j < 8; j++) {
+ inbit = 8 * k + j;
+ if(i & bits8[j]) {
+ if((obit = init_perm[inbit]) < 32)
+ *il |= bits32[obit];
+ else
+ *ir |= bits32[obit-32];
+ if ((obit = final_perm[inbit]) < 32)
+ *fl |= bits32[obit];
+ else
+ *fr |= bits32[obit - 32];
+ }
+ }
+ }
+ for(i = 0; i < 128; i++) {
+ *(il = &key_perm_maskl[k][i]) = 0L;
+ *(ir = &key_perm_maskr[k][i]) = 0L;
+ for(j = 0; j < 7; j++) {
+ inbit = 8 * k + j;
+ if(i & bits8[j + 1]) {
+ if((obit = inv_key_perm[inbit]) == 255)
+ continue;
+ if(obit < 28)
+ *il |= bits28[obit];
+ else
+ *ir |= bits28[obit - 28];
+ }
+ }
+ *(il = &comp_maskl[k][i]) = 0L;
+ *(ir = &comp_maskr[k][i]) = 0L;
+ for(j = 0; j < 7; j++) {
+ inbit = 7 * k + j;
+ if(i & bits8[j + 1]) {
+ if((obit=inv_comp_perm[inbit]) == 255)
+ continue;
+ if(obit < 24)
+ *il |= bits24[obit];
+ else
+ *ir |= bits24[obit - 24];
+ }
+ }
+ }
+ }
+
+ /*
+ * Invert the P-box permutation, and convert into OR-masks for
+ * handling the output of the S-box arrays setup above.
+ */
+ for(i = 0; i < 32; i++)
+ un_pbox[pbox[i] - 1] = i;
+
+ for(b = 0; b < 4; b++)
+ for(i = 0; i < 256; i++) {
+ *(p = &psbox[b][i]) = 0L;
+ for (j = 0; j < 8; j++) {
+ if (i & bits8[j])
+ *p |= bits32[un_pbox[8 * b + j]];
+ }
+ }
+
+ des_initialised = 1;
+}
+
+static void setup_salt(long salt) {
+ unsigned long obit, saltbit;
+ int i;
+
+ if (salt == old_salt)
+ return;
+ old_salt = salt;
+
+ saltbits = 0L;
+ saltbit = 1;
+ obit = 0x800000;
+ for (i = 0; i < 24; i++) {
+ if (salt & saltbit)
+ saltbits |= obit;
+ saltbit <<= 1;
+ obit >>= 1;
+ }
+}
+
+static int des_setkey(const char *key) {
+ unsigned long k0, k1, rawkey0, rawkey1;
+ int shifts, round;
+
+ if(!des_initialised)
+ des_init();
+
+ rawkey0 = ntohl(*(unsigned long *) key);
+ rawkey1 = ntohl(*(unsigned long *) (key + 4));
+
+ if((rawkey0 | rawkey1)
+ && rawkey0 == old_rawkey0
+ && rawkey1 == old_rawkey1) {
+ /*
+ * Already setup for this key.
+ * This optimisation fails on a zero key (which is weak and
+ * has bad parity anyway) in order to simplify the starting
+ * conditions.
+ */
+ return 0;
+ }
+ old_rawkey0 = rawkey0;
+ old_rawkey1 = rawkey1;
+
+ /*
+ * Do key permutation and split into two 28-bit subkeys.
+ */
+ k0 = key_perm_maskl[0][rawkey0 >> 25]
+ | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f]
+ | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f]
+ | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f]
+ | key_perm_maskl[4][rawkey1 >> 25]
+ | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f]
+ | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f]
+ | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f];
+ k1 = key_perm_maskr[0][rawkey0 >> 25]
+ | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f]
+ | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f]
+ | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f]
+ | key_perm_maskr[4][rawkey1 >> 25]
+ | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f]
+ | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f]
+ | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f];
+ /*
+ * Rotate subkeys and do compression permutation.
+ */
+ shifts = 0;
+ for(round = 0; round < 16; round++) {
+ unsigned long t0, t1;
+
+ shifts += key_shifts[round];
+
+ t0 = (k0 << shifts) | (k0 >> (28 - shifts));
+ t1 = (k1 << shifts) | (k1 >> (28 - shifts));
+
+ de_keysl[15 - round] =
+ en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f]
+ | comp_maskl[1][(t0 >> 14) & 0x7f]
+ | comp_maskl[2][(t0 >> 7) & 0x7f]
+ | comp_maskl[3][t0 & 0x7f]
+ | comp_maskl[4][(t1 >> 21) & 0x7f]
+ | comp_maskl[5][(t1 >> 14) & 0x7f]
+ | comp_maskl[6][(t1 >> 7) & 0x7f]
+ | comp_maskl[7][t1 & 0x7f];
+
+ de_keysr[15 - round] = en_keysr[round] =
+ comp_maskr[0][(t0 >> 21) & 0x7f]
+ | comp_maskr[1][(t0 >> 14) & 0x7f]
+ | comp_maskr[2][(t0 >> 7) & 0x7f]
+ | comp_maskr[3][t0 & 0x7f]
+ | comp_maskr[4][(t1 >> 21) & 0x7f]
+ | comp_maskr[5][(t1 >> 14) & 0x7f]
+ | comp_maskr[6][(t1 >> 7) & 0x7f]
+ | comp_maskr[7][t1 & 0x7f];
+ }
+ return 0;
+}
+
+static int do_des(unsigned long l_in, unsigned long r_in, unsigned long *l_out,
+ unsigned long *r_out, int count) {
+ /*
+ * l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format.
+ */
+ unsigned long l, r, *kl, *kr, *kl1, *kr1;
+ unsigned long f, r48l, r48r;
+ int round;
+
+ if(count == 0) {
+ return 1;
+ } else if(count > 0) {
+ /*
+ * Encrypting
+ */
+ kl1 = en_keysl;
+ kr1 = en_keysr;
+ } else {
+ /*
+ * Decrypting
+ */
+ count = -count;
+ kl1 = de_keysl;
+ kr1 = de_keysr;
+ }
+
+ /*
+ * Do initial permutation (IP).
+ */
+ l = ip_maskl[0][l_in >> 24]
+ | ip_maskl[1][(l_in >> 16) & 0xff]
+ | ip_maskl[2][(l_in >> 8) & 0xff]
+ | ip_maskl[3][l_in & 0xff]
+ | ip_maskl[4][r_in >> 24]
+ | ip_maskl[5][(r_in >> 16) & 0xff]
+ | ip_maskl[6][(r_in >> 8) & 0xff]
+ | ip_maskl[7][r_in & 0xff];
+ r = ip_maskr[0][l_in >> 24]
+ | ip_maskr[1][(l_in >> 16) & 0xff]
+ | ip_maskr[2][(l_in >> 8) & 0xff]
+ | ip_maskr[3][l_in & 0xff]
+ | ip_maskr[4][r_in >> 24]
+ | ip_maskr[5][(r_in >> 16) & 0xff]
+ | ip_maskr[6][(r_in >> 8) & 0xff]
+ | ip_maskr[7][r_in & 0xff];
+
+ while(count--) {
+ /*
+ * Do each round.
+ */
+ kl = kl1;
+ kr = kr1;
+ round = 16;
+ while(round--) {
+ /*
+ * Expand R to 48 bits (simulate the E-box).
+ */
+ r48l = ((r & 0x00000001) << 23)
+ | ((r & 0xf8000000) >> 9)
+ | ((r & 0x1f800000) >> 11)
+ | ((r & 0x01f80000) >> 13)
+ | ((r & 0x001f8000) >> 15);
+
+ r48r = ((r & 0x0001f800) << 7)
+ | ((r & 0x00001f80) << 5)
+ | ((r & 0x000001f8) << 3)
+ | ((r & 0x0000001f) << 1)
+ | ((r & 0x80000000) >> 31);
+ /*
+ * Do salting for crypt() and friends, and
+ * XOR with the permuted key.
+ */
+ f = (r48l ^ r48r) & saltbits;
+ r48l ^= f ^ *kl++;
+ r48r ^= f ^ *kr++;
+ /*
+ * Do sbox lookups (which shrink it back to 32 bits)
+ * and do the pbox permutation at the same time.
+ */
+ f = psbox[0][m_sbox[0][r48l >> 12]]
+ | psbox[1][m_sbox[1][r48l & 0xfff]]
+ | psbox[2][m_sbox[2][r48r >> 12]]
+ | psbox[3][m_sbox[3][r48r & 0xfff]];
+ /*
+ * Now that we've permuted things, complete f().
+ */
+ f ^= l;
+ l = r;
+ r = f;
+ }
+ r = l;
+ l = f;
+ }
+ /*
+ * Do final permutation (inverse of IP).
+ */
+ *l_out = fp_maskl[0][l >> 24]
+ | fp_maskl[1][(l >> 16) & 0xff]
+ | fp_maskl[2][(l >> 8) & 0xff]
+ | fp_maskl[3][l & 0xff]
+ | fp_maskl[4][r >> 24]
+ | fp_maskl[5][(r >> 16) & 0xff]
+ | fp_maskl[6][(r >> 8) & 0xff]
+ | fp_maskl[7][r & 0xff];
+ *r_out = fp_maskr[0][l >> 24]
+ | fp_maskr[1][(l >> 16) & 0xff]
+ | fp_maskr[2][(l >> 8) & 0xff]
+ | fp_maskr[3][l & 0xff]
+ | fp_maskr[4][r >> 24]
+ | fp_maskr[5][(r >> 16) & 0xff]
+ | fp_maskr[6][(r >> 8) & 0xff]
+ | fp_maskr[7][r & 0xff];
+ return 0;
+}
+
+char *crypt(char *key, char *setting) {
+ unsigned long count, salt, l, r0, r1, keybuf[2];
+ unsigned char *p, *q;
+ static unsigned char output[21];
+
+ if(!des_initialised)
+ des_init();
+ /*
+ * Copy the key, shifting each character up by one bit
+ * and padding with zeros.
+ */
+ q = (unsigned char *)keybuf;
+ while(q - (unsigned char *)keybuf - 8) {
+ if((*q++ = *key << 1))
+ key++;
+ }
+ if(des_setkey((unsigned char *)keybuf))
+ return NULL;
+
+ /*
+ * "old"-style:
+ * setting - 2 bytes of salt
+ * key - up to 8 characters
+ */
+ count = 25;
+
+ salt = (ascii_to_bin(setting[1]) << 6)
+ | ascii_to_bin(setting[0]);
+
+ output[0] = setting[0];
+ /*
+ * If the encrypted password that the salt was extracted from
+ * is only 1 character long, the salt will be corrupted. We
+ * need to ensure that the output string doesn't have an extra
+ * NUL in it!
+ */
+ output[1] = setting[1] ? setting[1] : output[0];
+
+ p = output + 2;
+
+ setup_salt(salt);
+ /*
+ * Do it.
+ */
+ if(do_des(0L, 0L, &r0, &r1, count))
+ return NULL;
+ /*
+ * Now encode the result...
+ */
+ l = (r0 >> 8);
+ *p++ = ascii64[(l >> 18) & 0x3f];
+ *p++ = ascii64[(l >> 12) & 0x3f];
+ *p++ = ascii64[(l >> 6) & 0x3f];
+ *p++ = ascii64[l & 0x3f];
+
+ l = (r0 << 16) | ((r1 >> 16) & 0xffff);
+ *p++ = ascii64[(l >> 18) & 0x3f];
+ *p++ = ascii64[(l >> 12) & 0x3f];
+ *p++ = ascii64[(l >> 6) & 0x3f];
+ *p++ = ascii64[l & 0x3f];
+
+ l = r1 << 2;
+ *p++ = ascii64[(l >> 12) & 0x3f];
+ *p++ = ascii64[(l >> 6) & 0x3f];
+ *p++ = ascii64[l & 0x3f];
+ *p = 0;
+
+ return output;
+}
+#endif
diff --git a/mbbsd/dice.c b/mbbsd/dice.c
new file mode 100644
index 00000000..d64ce63c
--- /dev/null
+++ b/mbbsd/dice.c
@@ -0,0 +1,447 @@
+/* $Id: dice.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "modes.h"
+#include "proto.h"
+
+#define DICE_TXT BBSHOME "/etc/dice.txt"
+#define DICE_DATA BBSHOME "/etc/dice.data"
+#define DICE_WIN BBSHOME "/etc/windice.log"
+#define DICE_LOST BBSHOME "/etc/lostdice.log"
+
+#define B_MAX 500
+#define B_MIN 10
+#define B_COMMON 1
+#define B_TIMES 5
+#define B_THIRD 3
+
+extern int usernum;
+static int flag[100], value[100];
+
+typedef struct dicedata_t {
+ int mybet;
+ int mymoney;
+} dicedata_t;
+
+static void set_bingo(int bet[]) {
+ int i, j = 0, k = 0, m = 0;
+
+ for(i = 0; i < 3; i++)
+ for(j = 2; j > i; j--)
+ if(bet[j] < bet[j - 1]) {
+ m = bet[j];
+ bet[j] = bet[j - 1];
+ bet[j - 1]=m;
+ }
+
+ for(i = 0; i < 100; i++)
+ flag[i] = 0;
+
+ for(i = 0; i < 3; i++)
+ flag[bet[i]]++;
+ j = bet[0] + bet[1] + bet[2];
+
+ if((abs(bet[1] - bet[0]) == 1 && abs(bet[2] - bet[0]) == 2) ||
+ (abs(bet[2] - bet[0]) == 1 && abs(bet[1] - bet[0]) == 2))
+ flag[66] = B_TIMES;
+
+ if(j < 10){
+ flag[7] = B_COMMON;
+ for(i = 0; i < 3; i++)
+ if(bet[i] == 4)
+ flag[74] = B_TIMES;
+ } else if(j > 11) {
+ flag[8] = B_COMMON;
+ for(i = 0; i < 3; i++)
+ if(bet[i] == 3)
+ flag[83]=B_TIMES;
+ } else
+ flag[11] = B_THIRD;
+
+ for(i = 0; i < 3; i++)
+ for(j = i; j < 3; j++) {
+ m = bet[i];
+ k = bet[j];
+ if(m != k)
+ flag[m * 10 + k] = B_TIMES;
+ }
+}
+
+static int bingo(int mybet) {
+ return flag[mybet];
+}
+
+int IsNum(char *a, int n) {
+ int i;
+
+ for(i = 0; i < n; i++)
+ if (a[i] > '9' || a[i] < '0' )
+ return 0;
+ return 1;
+}
+
+int IsSNum(char *a) {
+ int i;
+
+ for(i = 0; a[i]; i++)
+ if(a[i] > '9' || a[i] < '0')
+ return 0;
+ return 1;
+}
+
+static void show_data(void) {
+ move(0, 0);
+ prints("\033[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¢{\033[m\n");
+ prints("\033[45;37m­¿²v¤@\033[m\033[31m ¢x \033[33m[1]©ã¤@ÂI [2]©ã¤GÂI "
+ "[3]©ã¤TÂI [4]©ã¥|ÂI [5]©ã¤­ÂI [6]©ã¤»ÂI \033[31m ¢x\033[m\n");
+ prints("\033[31m ¢x \033[33m[7]©ã¤p [8]©ã¤j "
+ " \033[31m ¢x\033[m\n");
+ prints("\033[31m ¢x "
+ " ¢x\033[m\n");
+ prints("\033[45;37m½ß²v¤T\033[m\033[31m ¢x \033[33m[11]©ã¤¤(Á`ÂI¼Æµ¥©ó11"
+ "©Î10) \033[31m ¢x\033[m\n");
+ prints("\033[31m ¢x "
+ " ¢x\033[m\n");
+ prints("\033[45;37m½ß²v¤­\033[m\033[31m ¢x \033[33m[74]©ã¤p¥B¥|ÂI [83]©ã"
+ "¤j¥B¤TÂI [66]©ã³s¸¹ \033[31m ¢x\033[m\n");
+ prints("\033[31m ¢x "
+ " ¢x\033[m\n");
+ prints("\033[31m ¢x \033[33m[12]©ã¤@¤GÂI [13]©ã¤@¤TÂI [14]©ã¤@¥|ÂI"
+ " [15]©ã¤@¤­ÂI [16]©ã¤@¤»ÂI\033[31m ¢x\033[m\n");
+ prints("\033[31m ¢x \033[33m[23]©ã¤G¤TÂI [24]©ã¤G¥|ÂI [25]©ã¤G¤­ÂI"
+ " [26]©ã¤G¤»ÂI [34]©ã¤T¥|ÂI\033[31m ¢x\033[m\n");
+ prints("\033[31m ¢x \033[33m[35]©ã¤T¤­ÂI [36]©ã¤T¤»ÂI [45]©ã¥|¤­ÂI"
+ " [46]©ã¥|¤»ÂI [56]©ã¤­¤»ÂI\033[31m ¢x\033[m\n");
+ prints("\033[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\n");
+}
+
+static void show_count(int index, int money) {
+ int i = 0, count = 2, j, k;
+
+ value[index] += money;
+ move(14,0);
+ clrtoline(18);
+ for(i = 1, j = 13; i <= 8; i++, count += 12) {
+ if(i == 6) {
+ j = 14;
+ count = 2;
+ }
+ move(j,count);
+ prints("[%2d]:%d ", i, value[i]);
+ }
+
+ count = 2;
+ i = 15;
+ for(j = 1; j <= 5; j++)
+ for(k = j + 1; k <= 6; k++, count += 12) {
+ if(j == 2 && k == 4) {
+ i = 16;
+ count = 2;
+ } else if(j==4 && k==5) {
+ i = 17;
+ count = 2;
+ }
+ move(i,count);
+ prints("[%d%d]:%d ", j, k, value[j * 10 + k]);
+ }
+
+ move(18,2);
+ prints("[11]:%d",value[11]);
+ move(18,14);
+ prints("[66]:%d",value[66]);
+ move(18,26);
+ prints("[74]:%d",value[74]);
+ move(18,38);
+ prints("[83]:%d",value[83]);
+}
+
+static int check_index(int index) {
+ int i,tp[] = {1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 23, 24, 25,
+ 26, 34, 35, 36, 45, 46, 56, 66, 74, 83};
+ if(index < 0 || index > 100)
+ return 0;
+ for(i = 0; i < 27; i++)
+ if(index == tp[i])
+ return 1;
+ return 0;
+}
+
+extern userec_t cuser;
+
+static int del(int total, dicedata_t *table) {
+ int index, money;
+ char data[10];
+ int i;
+
+ while(1) {
+ do {
+ move(22,0);
+ clrtoeol();
+ getdata(21, 0, "¿é¤J°h¿ïªº¼Æ¦r(¥´qÂ÷¶}): ", data, 3, LCECHO);
+ if(data[0] == 'q' || data[0] == 'Q')
+ return 0;
+ } while(!IsNum(data,strlen(data)));
+
+ index = atoi(data);
+ for(i = 0; i < total; i++) {
+ if(table[i].mybet == index){
+ do {
+ getdata(21, 0, "¦h¤Ö¿ú: ", data, 10, LCECHO);
+ } while(!IsNum(data,strlen(data)));
+ money = atoi(data);
+ if(money>table[i].mymoney) {
+ move(22,0);
+ clrtoeol();
+ prints("¤£°÷¦©°Õ");
+ i--;
+ continue;
+ }
+ demoney(money);
+ move(19,0);
+ clrtoeol();
+ prints("§A²{¦b¦³ %u Ptt$¼Ú", cuser.money);
+ table[i].mymoney -= money;
+ show_count(index, -money);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static int IsLegal(char *data) {
+ int money = atoi(data);
+ if(IsNum(data,strlen(data)) && money<=B_MAX && money>=B_MIN)
+ return money;
+ return 0;
+}
+
+static void show_output(int bet[]) {
+ int i, j = 10;
+
+ move(12,0);
+ clrtoline(17);
+ /* ¼È®É­°°Õ ¦]¬°¨º¦Uclrtoline©Ç©Çªº */
+ for(i = 13; i <= 18; i++) {
+ move(i,0);
+ prints(" ");
+ }
+ move(12,0);
+ prints("\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¢{\033[m\n\n\n\n\n\n");
+ prints("\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¢}\033[m");
+ for(i = 0; i < 3; i++, j += 25) {
+ switch(bet[i]) {
+ case 1:
+ move(13, j);prints("\033[37m¢~¢w¢w¢w¢w¢¡\033[m");
+ move(14, j);prints("\033[37m¢x ¢x\033[m");
+ move(15, j);prints("\033[37m¢x ¡´ ¢x\033[m");
+ move(16, j);prints("\033[37m¢x ¢x\033[m");
+ move(17, j);prints("\033[37m¢¢¢w¢w¢w¢w¢£\033[m");
+ break;
+ case 2:
+ move(13, j);prints("\033[37m¢~¢w¢w¢w¢w¢¡\033[m");
+ move(14, j);prints("\033[37m¢x ¡´¢x\033[m");
+ move(15, j);prints("\033[37m¢x ¢x\033[m");
+ move(16, j);prints("\033[37m¢x¡´ ¢x\033[m");
+ move(17, j);prints("\033[37m¢¢¢w¢w¢w¢w¢£\033[m");
+ break;
+ case 3:
+ move(13, j);prints("\033[37m¢~¢w¢w¢w¢w¢¡\033[m");
+ move(14, j);prints("\033[37m¢x ¡´¢x\033[m");
+ move(15, j);prints("\033[37m¢x ¡´ ¢x\033[m");
+ move(16, j);prints("\033[37m¢x¡´ ¢x\033[m");
+ move(17, j);prints("\033[37m¢¢¢w¢w¢w¢w¢£\033[m");
+ break;
+ case 4:
+ move(13, j);prints("\033[37m¢~¢w¢w¢w¢w¢¡\033[m");
+ move(14, j);prints("\033[37m¢x¡´ ¡´¢x\033[m");
+ move(15, j);prints("\033[37m¢x ¢x\033[m");
+ move(16, j);prints("\033[37m¢x¡´ ¡´¢x\033[m");
+ move(17, j);prints("\033[37m¢¢¢w¢w¢w¢w¢£\033[m");
+ break;
+ case 5:
+ move(13, j);prints("\033[37m¢~¢w¢w¢w¢w¢¡\033[m");
+ move(14, j);prints("\033[37m¢x¡´ ¡´¢x\033[m");
+ move(15, j);prints("\033[37m¢x ¡´ ¢x\033[m");
+ move(16, j);prints("\033[37m¢x¡´ ¡´¢x\033[m");
+ move(17, j);prints("\033[37m¢¢¢w¢w¢w¢w¢£\033[m");
+ break;
+ case 6:
+ move(13, j);prints("\033[37m¢~¢w¢w¢w¢w¢¡\033[m");
+ move(14, j);prints("\033[37m¢x¡´ ¡´¢x\033[m");
+ move(15, j);prints("\033[37m¢x¡´ ¡´¢x\033[m");
+ move(16, j);prints("\033[37m¢x¡´ ¡´¢x\033[m");
+ move(17, j);prints("\033[37m¢¢¢w¢w¢w¢w¢£\033[m");
+ break;
+ }
+ }
+}
+
+#define lockreturn0(unmode, state) if(lockutmpmode(unmode, state)) return 0
+
+int dice_main(void) {
+ char input[10],data[256], ch;
+ dicedata_t table[256];
+ int bet[3], index, money = 0, i, ya = 0, j, total, sig = 0;
+ FILE *winfp/* , *lostfp */;
+
+ more(DICE_TXT, NA);
+ reload_money();
+ if(cuser.money < 10){
+ move(19,0);
+ prints("\033[1;37m¶W¹L¤Q¤¸¦A¨Óª±§a~~\033[m");
+ pressanykey();
+ return 0;
+ }
+
+ lockreturn0(DICE, LOCK_MULTI);
+ winfp = fopen(DICE_WIN,"a");
+ /*lostfp = fopen(DICE_LOST,"a");*/
+ if(!winfp /*|| !lostfp*/)
+ return 0;
+
+ do {
+ total = 0; i = 0;
+ ch = 'y';
+ clear();
+ show_data();
+ for(j = 0; j < 3; j++)
+ bet[j] = rand() % 6 + 1;
+
+ for(j = 0; j < 100; j++)
+ value[j] = 0;
+
+ while(1) {
+ move(19,0);
+ prints("\033[1;32m§A²{¦b¦³\033[1;31m %u \033[1;32mPtt$¼Ú\033[m",
+ cuser.money);
+ getdata(20, 0, "\033[1;37m¼Æ¦r:¥[¿ï d:°h¿ï s:¶}©l©ÎÂ÷¶}\033[m: ",
+ input, 5, LCECHO);
+ reload_money();
+ if(input[0] != 's' && input[0] != 'd' && cuser.money < 10) {
+ move(21, 0);
+ clrtoeol();
+ prints("\033[1;37m¶W¹L¤Q¤¸¤~¯à½ä~\033[m");
+ continue;
+ }
+ if(input[0] == 'd' || input[0] == 'D') {
+ del(i, table);
+ continue;
+ }
+ if(input[0] == 's' || input[0] == 'S')
+ break;
+
+ if(!IsNum(input,strlen(input)))
+ continue;
+
+ index=atoi(input);
+ if(check_index(index) == 0)
+ continue;
+/*¿é¤J¿úªºloop*/
+ while(1) {
+ if(cuser.money < 10)
+ break;
+ getdata(21, 0, "\033[1;32m½ä¦h¤Ö¿ú©O\033[1;37m(¤j©ó10 ¤p©ó500)"
+ "\033[m: ", input, 9, LCECHO);
+ if(!(money = IsLegal(input))||input[0] == '0')
+ continue;
+ reload_money();
+ if(money > cuser.money)
+ continue;
+ for(j = 0, sig = 0; j < i; j++)
+ if(table[j].mybet == index) {
+ if(table[j].mymoney == B_MAX)
+ sig = 2;
+ else if(table[j].mymoney+money>B_MAX) {
+ sig = 1;
+ break;
+ } else {
+ vice(money,"»ë¤l");
+ table[j].mymoney += money;
+ j = -1;
+ break;
+ }
+ }
+ if(sig == 2)
+ break;
+ if(sig == 1)
+ continue;
+ if(j != -1) {
+ bzero((char*)&table[i], sizeof(dicedata_t));
+ table[i].mybet = index;
+ table[i++].mymoney = money;
+ vice(money,"»ë¤l");
+ }
+ break;
+ }
+ reload_money();
+ move(19,0);
+ prints("\033[1;32m§A²{¦b¦³ \033[1;31m%u\033[1;32m Ptt$¼Ú",
+ cuser.money);
+ if(sig != 2)
+ show_count(index, money);
+ }
+
+ if(i == 0) {
+ fclose(winfp);
+ /*fclose(lostfp);*/
+ unlockutmpmode();
+ return 0;
+ }
+
+ show_output(bet);
+ set_bingo(bet);
+
+ for(j = 0; j < i; j++) {
+ if(table[j].mymoney <= 0)
+ continue;
+ ya = bingo(table[j].mybet);
+ if(ya == 0) {
+ /*sprintf(data, "%-15s ¿é¤F %-8d $", cuser.userid,
+ table[j].mymoney);
+ fprintf(lostfp, "%s\n", data);*/
+ continue;
+ }
+ demoney(table[j].mymoney * ya + table[j].mymoney);
+ total += table[j].mymoney * ya;
+ if (table[j].mymoney * ya > 500){ /* ¶W¹L500¶ô¿ú¤~°µlog ´î¤Öio */
+ sprintf(data, "%-15s ©ã%-2d¿ï¶µ%-8d¶ô¿ú ¤¤¤F%d­¿ ²bÁÈ:%-8d\n",
+ cuser.userid,table[j].mybet,
+ table[j].mymoney, ya, table[j].mymoney * ya);
+ fputs(data,winfp);
+ }
+ ya = 0;
+ }
+
+ if(total > 0) {
+ move(21,0);
+ prints("\033[1;32m§AŤF \033[1;31m%d\033[1;32m Ptt$ ­ò~~"
+ " \033[m", total);
+ } else {
+ move(21,0);
+ clrtoeol();
+ prints("\033[1;32m¯u¥i±¤ ¤U¦¸¦A¨Ó¸I¸I¹B®ð§a\033[m");
+ }
+
+ move(19,0);
+ clrtoeol();
+ prints("\033[1;32m§A²{¦b¦³ \033[1;31m%u\033[1;32m Ptt$¼Ú\033[m",
+ cuser.money);
+
+ getdata(23, 0, "\033[1;32mÄ~Äò¾Ä°«[\033[1;37my/n\033[1;32m]\033[m: ",
+ input, 2, LCECHO);
+ } while(input[0] != 'n' && input[0] != 'N');
+ fclose(winfp);
+ /*fclose(lostfp);*/
+ unlockutmpmode();
+ return 0;
+}
diff --git a/mbbsd/edit.c b/mbbsd/edit.c
new file mode 100644
index 00000000..19f437af
--- /dev/null
+++ b/mbbsd/edit.c
@@ -0,0 +1,2256 @@
+/* $Id: edit.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "config.h"
+#include "common.h"
+#include "modes.h"
+#include "perm.h"
+#include "proto.h"
+
+#define WRAPMARGIN (511)
+
+typedef struct textline_t {
+ struct textline_t *prev;
+ struct textline_t *next;
+ int len;
+ char data[WRAPMARGIN + 1];
+} textline_t;
+
+extern int current_font_type;
+extern char *str_author1;
+extern char *str_author2;
+extern int t_lines, t_columns; /* Screen size / width */
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+extern char quote_file[80];
+extern char quote_user[80];
+extern int curredit;
+extern unsigned int currbrdattr;
+extern char currboard[]; /* name of currently selected board */
+extern char *str_reply;
+extern char *str_post1;
+extern char *str_post2;
+extern char *BBSName;
+extern char fromhost[];
+extern unsigned int currstat;
+extern crosspost_t postrecord;
+extern userinfo_t *currutmp;
+extern int KEY_ESC_arg;
+extern char reset_color[];
+extern char trans_buffer[256];
+
+#define KEEP_EDITING -2
+#define BACKUP_LIMIT 100
+#define SCR_WIDTH 80
+
+enum {
+ NOBODY, MANAGER, SYSOP
+};
+
+static textline_t *firstline = NULL;
+static textline_t *lastline = NULL;
+static textline_t *currline = NULL;
+static textline_t *blockline = NULL;
+static textline_t *top_of_win = NULL;
+static textline_t *deleted_lines = NULL;
+
+extern int local_article;
+extern char real_name[20];
+static char line[WRAPMARGIN + 2];
+static int ifuseanony=0;
+static int currpnt, currln, totaln;
+static int curr_window_line;
+static int redraw_everything;
+static int insert_character;
+static int my_ansimode;
+static int raw_mode;
+static int edit_margin;
+static int blockln = -1;
+static int blockpnt;
+static int prevln = -1;
+static int prevpnt;
+static int line_dirty;
+static int indent_mode;
+static int insert_c = ' ';
+
+static char fp_bak[] = "bak";
+
+char save_title[STRLEN];
+
+/* °O¾ÐÅéºÞ²z»P½s¿è³B²z */
+static void indigestion(i) {
+ fprintf(stderr, "ÄY­«¤º¶Ë %d\n", i);
+}
+
+/* Thor: ansi ®y¼ÐÂà´« for color ½s¿è¼Ò¦¡ */
+static int ansi2n(int ansix, textline_t * line) {
+ register char *data, *tmp;
+ register char ch;
+
+ data = tmp = line->data;
+
+ while(*tmp) {
+ if(*tmp == KEY_ESC) {
+ while((ch = *tmp) && !isalpha(ch))
+ tmp++;
+ if(ch)
+ tmp++;
+ continue;
+ }
+ if(ansix <= 0)
+ break;
+ tmp++;
+ ansix--;
+ }
+ return tmp - data;
+}
+
+static int n2ansi(int nx, textline_t * line) {
+ register int ansix = 0;
+ register char *tmp,*nxp;
+ register char ch;
+
+ tmp = nxp = line->data;
+ nxp += nx;
+
+ while(*tmp) {
+ if(*tmp == KEY_ESC) {
+ while((ch = *tmp) && !isalpha(ch))
+ tmp++;
+ if(ch)
+ tmp++;
+ continue;
+ }
+ if(tmp >= nxp)
+ break;
+ tmp++;
+ ansix++;
+ }
+ return ansix;
+}
+
+/* ¿Ã¹õ³B²z¡G»²§U°T®§¡BÅã¥Ü½s¿è¤º®e */
+static void edit_msg() {
+ static char *edit_mode[2] = {"¨ú¥N", "´¡¤J"};
+ register int n = currpnt;
+
+ if(my_ansimode) /* Thor: §@ ansi ½s¿è */
+ n = n2ansi(n, currline);
+ n++;
+ move(b_lines, 0);
+ clrtoeol();
+ prints("\033[%sm ½s¿è¤å³¹ \033[31;47m (Ctrl-Z)\033[30m»²§U»¡©ú "
+ "\033[31;47m(^G)\033[30m´¡¤J¹Ï¤å®w \033[31m(^X,^Q)"
+ "\033[30mÂ÷¶}ùø%s¢x%c%c%c%cùø %3d:%3d \033[m",
+ "37;44",
+ edit_mode[insert_character],
+ my_ansimode ? 'A' : 'a', indent_mode ? 'I' : 'i',
+ 'P' , raw_mode ? 'R' : 'r',
+ currln + 1, n);
+}
+
+static textline_t *back_line(textline_t *pos, int num) {
+ while(num-- > 0) {
+ register textline_t *item;
+
+ if(pos && (item = pos->prev)) {
+ pos = item;
+ currln--;
+ }
+ }
+ return pos;
+}
+
+static textline_t *forward_line(textline_t *pos, int num) {
+ while(num-- > 0) {
+ register textline_t *item;
+
+ if(pos && (item = pos->next)) {
+ pos = item;
+ currln++;
+ }
+ }
+ return pos;
+}
+
+static int getlineno() {
+ int cnt = 0;
+ textline_t *p = currline;
+
+ while(p && (p != top_of_win)) {
+ cnt++;
+ p = p->prev;
+ }
+ return cnt;
+}
+
+static char *killsp(char *s) {
+ while(*s == ' ')
+ s++;
+ return s;
+}
+
+static textline_t *alloc_line() {
+ register textline_t *p;
+
+ if((p = (textline_t *)malloc(sizeof(textline_t)))) {
+ memset(p, 0, sizeof(textline_t));
+ return p;
+ }
+
+ indigestion(13);
+ abort_bbs(0);
+ return NULL;
+}
+
+/* append p after line in list. keeps up with last line */
+static void append(textline_t *p, textline_t *line) {
+ register textline_t *n;
+
+ if((p->next = n = line->next))
+ n->prev = p;
+ else
+ lastline = p;
+ line->next = p;
+ p->prev = line;
+}
+
+/*
+ delete_line deletes 'line' from the list,
+ and maintains the lastline, and firstline pointers.
+*/
+
+static void delete_line(textline_t *line) {
+ register textline_t *p = line->prev;
+ register textline_t *n = line->next;
+
+ if(!p && !n) {
+ line->data[0] = line->len = 0;
+ return;
+ }
+ if(n)
+ n->prev = p;
+ else
+ lastline = p;
+ if(p)
+ p->next = n;
+ else
+ firstline = n;
+ strcat(line->data, "\n");
+ line->prev = deleted_lines;
+ deleted_lines = line;
+ totaln--;
+}
+
+static int ask(char *prompt) {
+ int ch;
+
+ move (0, 0);
+ clrtoeol ();
+ standout ();
+ prints ("%s", prompt);
+ standend ();
+ ch = igetkey ();
+ move (0, 0);
+ clrtoeol ();
+ return (ch);
+}
+
+static int indent_spcs() {
+ textline_t* p;
+ int spcs;
+
+ if(!indent_mode)
+ return 0;
+
+ for(p = currline; p; p = p->prev) {
+ for(spcs = 0; p->data[spcs] == ' '; ++spcs);
+ if (p->data[spcs])
+ return spcs;
+ }
+ return 0;
+}
+
+/* split 'line' right before the character pos */
+static void split(textline_t *line, int pos) {
+ if(pos <= line->len) {
+ register textline_t *p = alloc_line();
+ register char *ptr;
+ int spcs = indent_spcs();
+
+ totaln++;
+
+ p->len = line->len - pos + spcs;
+ line->len = pos;
+
+ memset(p->data, ' ', spcs);
+ p->data[spcs] = 0;
+ strcat(p->data, (ptr = line->data + pos));
+ ptr[0] = '\0';
+ append(p, line);
+ if(line == currline && pos <= currpnt) {
+ currline = p;
+ if(pos == currpnt)
+ currpnt = spcs;
+ else
+ currpnt -= pos;
+ curr_window_line++;
+ currln++;
+ }
+ redraw_everything = YEA;
+ }
+}
+
+static void insert_char(int ch) {
+ register textline_t *p = currline;
+ register int i = p->len;
+ register char *s;
+ int wordwrap = YEA;
+
+ if(currpnt > i) {
+ indigestion(1);
+ return;
+ }
+ if(currpnt < i && !insert_character) {
+ p->data[currpnt++] = ch;
+ /* Thor: ansi ½s¿è, ¥i¥Hoverwrite, ¤£»\¨ì ansi code */
+ if(my_ansimode)
+ currpnt = ansi2n(n2ansi(currpnt, p),p);
+ } else {
+ while(i >= currpnt) {
+ p->data[i + 1] = p->data[i];
+ i--;
+ }
+ p->data[currpnt++] = ch;
+ i = ++(p->len);
+ }
+ if(i < WRAPMARGIN)
+ return;
+ s = p->data + (i - 1);
+ while(s != p->data && *s == ' ')
+ s--;
+ while(s != p->data && *s != ' ')
+ s--;
+ if(s == p->data) {
+ wordwrap = NA;
+ s = p->data + (i - 2);
+ }
+ split(p, (s - p->data) + 1);
+ p = p->next;
+ i = p->len;
+ if(wordwrap && i >= 1) {
+ if(p->data[i - 1] != ' ') {
+ p->data[i] = ' ';
+ p->data[i + 1] = '\0';
+ p->len++;
+ }
+ }
+}
+
+static void insert_string(char *str) {
+ int ch;
+
+ while((ch = *str++)) {
+ if(isprint2(ch) || ch == '\033')
+ insert_char(ch);
+ else if(ch == '\t') {
+ do {
+ insert_char(' ');
+ } while(currpnt & 0x7);
+ } else if(ch == '\n')
+ split(currline, currpnt);
+ }
+}
+
+static int undelete_line() {
+ textline_t* p = deleted_lines;
+ textline_t* currline0 = currline;
+ textline_t* top_of_win0 = top_of_win;
+ int currpnt0 = currpnt;
+ int currln0 = currln;
+ int curr_window_line0 = curr_window_line;
+ int indent_mode0 = indent_mode;
+
+ if(!deleted_lines)
+ return 0;
+
+ indent_mode = 0;
+ insert_string(deleted_lines->data);
+ indent_mode = indent_mode0;
+ deleted_lines = deleted_lines->prev;
+ free(p);
+
+ currline = currline0;
+ top_of_win = top_of_win0;
+ currpnt = currpnt0;
+ currln = currln0;
+ curr_window_line = curr_window_line0;
+ return 0;
+}
+
+/*
+ 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 join(textline_t *line) {
+ register textline_t *n;
+ register int ovfl;
+
+ if(!(n = line->next))
+ return YEA;
+ if(!*killsp(n->data))
+ return YEA;
+
+ ovfl = line->len + n->len - WRAPMARGIN;
+ if(ovfl < 0) {
+ strcat(line->data, n->data);
+ line->len += n->len;
+ delete_line(n);
+ return YEA;
+ } else {
+ register char *s;
+
+ s = n->data + n->len - ovfl - 1;
+ while(s != n->data && *s == ' ')
+ s--;
+ while(s != n->data && *s != ' ')
+ s--;
+ if(s == n->data)
+ return YEA;
+ split(n, (s - n->data) + 1);
+ if(line->len + n->len >= WRAPMARGIN) {
+ indigestion(0);
+ return YEA;
+ }
+ join(line);
+ n = line->next;
+ ovfl = n->len - 1;
+ if(ovfl >= 0 && ovfl < WRAPMARGIN - 2) {
+ s = &(n->data[ovfl]);
+ if(*s != ' ') {
+ strcpy(s, " ");
+ n->len++;
+ }
+ }
+ return NA;
+ }
+}
+
+static void delete_char() {
+ register int len;
+
+ if((len = currline->len)) {
+ register int i;
+ register char *s;
+
+ if(currpnt >= len) {
+ indigestion(1);
+ return;
+ }
+ for(i = currpnt, s = currline->data + i; i != len; i++, s++)
+ s[0] = s[1];
+ currline->len--;
+ }
+}
+
+static void load_file(FILE *fp) {
+ int indent_mode0 = indent_mode;
+
+ indent_mode = 0;
+ while(fgets(line, WRAPMARGIN + 2, fp))
+ insert_string(line);
+ fclose(fp);
+ indent_mode = indent_mode0;
+}
+
+/* ¼È¦sÀÉ */
+char *ask_tmpbuf(int y) {
+ static char fp_buf[10] = "buf.0";
+ static char msg[] = "½Ð¿ï¾Ü¼È¦sÀÉ (0-9)[0]: ";
+
+ msg[19] = fp_buf[4];
+ do {
+ if(!getdata(y, 0, msg, fp_buf + 4, 4, DOECHO))
+ fp_buf[4] = msg[19];
+ } while(fp_buf[4] < '0' || fp_buf[4] > '9');
+ return fp_buf;
+}
+
+static void read_tmpbuf(int n) {
+ FILE *fp;
+ char fp_tmpbuf[80];
+ char tmpfname[] = "buf.0";
+ char *tmpf;
+ char ans[4] = "y";
+
+ if(0 <= n && n <= 9) {
+ tmpfname[4] = '0' + n;
+ tmpf = tmpfname;
+ } else {
+ tmpf = ask_tmpbuf(3);
+ n = tmpf[4] - '0';
+ }
+
+ setuserfile(fp_tmpbuf, tmpf);
+ if(n != 0 && n != 5 && more(fp_tmpbuf, NA) != -1)
+ getdata(b_lines - 1, 0, "½T©wŪ¤J¶Ü(Y/N)?[Y]", ans, 4, LCECHO);
+ if(*ans != 'n' && (fp = fopen(fp_tmpbuf, "r"))) {
+ prevln = currln;
+ prevpnt = currpnt;
+ load_file(fp);
+ while(curr_window_line >= b_lines) {
+ curr_window_line--;
+ top_of_win = top_of_win->next;
+ }
+ }
+}
+
+static void write_tmpbuf() {
+ FILE *fp;
+ char fp_tmpbuf[80], ans[4];
+ textline_t *p;
+
+ setuserfile(fp_tmpbuf, ask_tmpbuf(3));
+ if(dashf(fp_tmpbuf)) {
+ more(fp_tmpbuf, NA);
+ getdata(b_lines - 1, 0, "¼È¦sÀɤw¦³¸ê®Æ (A)ªþ¥[ (W)Âмg (Q)¨ú®ø¡H[A] ",
+ ans, 4, LCECHO);
+
+ if(ans[0] == 'q')
+ return;
+ }
+
+ if((fp = fopen(fp_tmpbuf, (ans[0] == 'w' ? "w" : "a+")))) {
+ for(p = firstline; p; p = p->next) {
+ if(p->next || p->data[0])
+ fprintf(fp, "%s\n", p->data);
+ }
+ fclose(fp);
+ }
+}
+
+static void erase_tmpbuf() {
+ char fp_tmpbuf[80];
+ char ans[4] = "n";
+
+ setuserfile(fp_tmpbuf, ask_tmpbuf(3));
+ if(more(fp_tmpbuf, NA) != -1)
+ getdata(b_lines - 1, 0, "½T©w§R°£¶Ü(Y/N)?[N]", ans, 4, LCECHO);
+ if(*ans == 'y')
+ unlink(fp_tmpbuf);
+}
+
+/* ½s¿è¾¹¦Û°Ê³Æ¥÷ */
+void auto_backup() {
+ if(currline) {
+ FILE *fp;
+ textline_t *p, *v;
+ char bakfile[64];
+ int count = 0;
+
+ setuserfile(bakfile, fp_bak);
+ if((fp = fopen(bakfile, "w"))) {
+ for(p = firstline; p != NULL && count < 512; p = v,count++) {
+ v = p->next;
+ fprintf(fp, "%s\n", p->data);
+ free(p);
+ }
+ fclose(fp);
+ }
+ currline = NULL;
+ }
+}
+
+void restore_backup() {
+ char bakfile[80], buf[80];
+
+ setuserfile(bakfile, fp_bak);
+ if(dashf(bakfile)) {
+ stand_title("½s¿è¾¹¦Û°Ê´_­ì");
+ getdata(1, 0, "±z¦³¤@½g¤å³¹©|¥¼§¹¦¨¡A(S)¼g¤J¼È¦sÀÉ (Q)ºâ¤F¡H[S] ",
+ buf, 4, LCECHO);
+ if(buf[0] != 'q') {
+ setuserfile(buf, ask_tmpbuf(3));
+ Rename(bakfile, buf);
+ } else
+ unlink(bakfile);
+ }
+}
+
+/* ¤Þ¥Î¤å³¹ */
+static int garbage_line(char *str) {
+ int qlevel = 0;
+
+ while(*str == ':' || *str == '>') {
+ if(*(++str) == ' ')
+ str++;
+ if(qlevel++ >= 1)
+ return 1;
+ }
+ while(*str == ' ' || *str == '\t')
+ str++;
+ if(qlevel >= 1) {
+ if(!strncmp(str, "¡° ", 3) || !strncmp(str, "==>", 3) ||
+ strstr(str, ") ´£¨ì:\n"))
+ return 1;
+ }
+ return (*str == '\n');
+}
+
+static void do_quote() {
+ int op;
+ char buf[256];
+
+ getdata(b_lines - 1, 0, "½Ð°Ý­n¤Þ¥Î­ì¤å¶Ü(Y/N/All/Repost)¡H[Y] ",
+ buf, 3, LCECHO);
+ op = buf[0];
+
+ if(op != 'n') {
+ FILE *inf;
+
+ if((inf = fopen(quote_file, "r"))) {
+ char *ptr;
+ int indent_mode0 = indent_mode;
+
+ fgets(buf, 256, inf);
+ if((ptr = strrchr(buf, ')')))
+ ptr[1] = '\0';
+ else if((ptr = strrchr(buf, '\n')))
+ ptr[0] = '\0';
+
+ if((ptr = strchr(buf, ':'))) {
+ char *str;
+
+ while(*(++ptr) == ' ');
+
+ /* ¶¶¤â²o¦Ï¡A¨ú±o author's address */
+ if((curredit & EDIT_BOTH) && (str = strchr(quote_user, '.'))) {
+ strcpy(++str, ptr);
+ str = strchr(str, ' ');
+ str[0] = '\0';
+ }
+ } else
+ ptr = quote_user;
+
+ indent_mode = 0;
+ insert_string("¡° ¤Þ­z¡m");
+ insert_string(ptr);
+ insert_string("¡n¤§»Ê¨¥¡G\n");
+
+ if(op != 'a') /* ¥h±¼ header */
+ while(fgets(buf, 256, inf) && buf[0] != '\n');
+
+ if(op == 'a')
+ while(fgets(buf, 256, inf)) {
+ insert_char(':');
+ insert_char(' ');
+ insert_string(Ptt_prints(buf,STRIP_ALL));
+ }
+ else if(op == 'r')
+ while(fgets(buf, 256, inf))
+ insert_string(Ptt_prints(buf,NO_RELOAD));
+ else {
+ if(curredit & EDIT_LIST) /* ¥h±¼ mail list ¤§ header */
+ while (fgets(buf, 256, inf) && (!strncmp(buf, "¡° ", 3)));
+ while(fgets(buf, 256, inf)) {
+ if(!strcmp(buf, "--\n"))
+ break;
+ if(!garbage_line(buf)) {
+ insert_char(':');
+ insert_char(' ');
+ insert_string(Ptt_prints(buf,STRIP_ALL));
+ }
+ }
+ }
+ indent_mode = indent_mode0;
+ fclose(inf);
+ }
+ }
+}
+
+/* ¼f¬d user ¤Þ¨¥ªº¨Ï¥Î */
+static int check_quote() {
+ register textline_t *p = firstline;
+ register char *str;
+ int post_line;
+ int included_line;
+
+ post_line = included_line = 0;
+ while(p) {
+ if(!strcmp(str = p->data, "--"))
+ break;
+ if(str[1] == ' ' && ((str[0] == ':') || (str[0] == '>')))
+ included_line++;
+ else {
+ while(*str == ' ' || *str == '\t')
+ str++;
+ if(*str)
+ post_line++;
+ }
+ p = p->next;
+ }
+
+ if((included_line >> 2) > post_line) {
+ move(4, 0);
+ outs("¥»½g¤å³¹ªº¤Þ¨¥¤ñ¨Ò¶W¹L 80%¡A½Ð±z°µ¨Ç·Lªº­×¥¿¡G\n\n"
+ "\033[1;33m1) ¼W¥[¤@¨Ç¤å³¹ ©Î 2) §R°£¤£¥²­n¤§¤Þ¨¥\033[m");
+ {
+ char ans[4];
+
+ getdata(12, 12, "(E)Ä~Äò½s¿è (W)±j¨î¼g¤J¡H[E] ", ans, 4, LCECHO);
+ if(ans[0] == 'w')
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/* Àɮ׳B²z¡GŪÀÉ¡B¦sÀÉ¡B¼ÐÃD¡Bñ¦WÀÉ */
+static void read_file(char *fpath) {
+ FILE *fp;
+
+ if((fp = fopen(fpath, "r")) == NULL) {
+ if((fp = fopen(fpath, "w+"))) {
+ fclose(fp);
+ return;
+ }
+ indigestion(4);
+ abort_bbs(0);
+ }
+ load_file(fp);
+}
+
+extern userec_t cuser;
+
+void write_header(FILE *fp) {
+ time_t now = time(0);
+
+ if(curredit & EDIT_MAIL || curredit & EDIT_LIST) {
+ fprintf(fp, "%s %s (%s)\n", str_author1, cuser.userid,
+#if defined(REALINFO) && defined(MAIL_REALNAMES)
+ cuser.realname
+#else
+ cuser.username
+#endif
+ );
+ } else {
+ char *ptr;
+ struct {
+ char author[IDLEN + 1];
+ char board[IDLEN + 1];
+ char title[66];
+ time_t date; /* last post's date */
+ int number; /* post number */
+ } postlog;
+
+ strcpy(postlog.author, cuser.userid);
+ ifuseanony=0;
+#ifdef HAVE_ANONYMOUS
+ if(currbrdattr& BRD_ANONYMOUS) {
+ int defanony = (currbrdattr & BRD_DEFAULTANONYMOUS);
+ if(defanony)
+ getdata(3, 0, "½Ð¿é¤J§A·Q¥ÎªºID¡A¤]¥iª½±µ«ö[Enter]¡A"
+ "©Î¬O«ö[r]¥Î¯u¦W¡G", real_name, 12, DOECHO);
+ else
+ getdata(3, 0, "½Ð¿é¤J§A·Q¥ÎªºID¡A¤]¥iª½±µ«ö[Enter]¨Ï¥Î­ìID¡G",
+ real_name, 12, DOECHO);
+ if(!real_name[0] && defanony) {
+ strcpy(real_name, "Anonymous");
+ strcpy(postlog.author, real_name);
+ ifuseanony = 1;
+ } else {
+ if(!strcmp("r",real_name) || (!defanony && !real_name[0]))
+ sprintf(postlog.author,"%s",cuser.userid);
+ else {
+ sprintf(postlog.author,"%s.",real_name);
+ ifuseanony=1;
+ }
+ }
+ }
+#endif
+ strcpy(postlog.board, currboard);
+ ptr = save_title;
+ if(!strncmp(ptr, str_reply, 4))
+ ptr += 4;
+ strncpy(postlog.title, ptr, 65);
+ postlog.date = now;
+ postlog.number = 1;
+ append_record(".post", (fileheader_t *)&postlog, sizeof(postlog));
+#ifdef HAVE_ANONYMOUS
+ if(currbrdattr & BRD_ANONYMOUS) {
+ int defanony = (currbrdattr & BRD_DEFAULTANONYMOUS);
+
+ fprintf(fp, "%s %s (%s) %s %s\n", str_author1, postlog.author ,
+ (((!strcmp(real_name,"r") && defanony) ||
+ (!real_name[0] && (!defanony))) ? cuser.username :
+ "²q²q§Ú¬O½Ö ? ^o^"),
+ local_article ? str_post2 : str_post1, currboard);
+ } else {
+ fprintf(fp, "%s %s (%s) %s %s\n", str_author1, cuser.userid,
+#if defined(REALINFO) && defined(POSTS_REALNAMES)
+ cuser.realname,
+#else
+ cuser.username,
+#endif
+ local_article ? str_post2 : str_post1, currboard);
+ }
+#else /* HAVE_ANONYMOUS */
+ fprintf(fp, "%s %s (%s) %s %s\n", str_author1, cuser.userid,
+#if defined(REALINFO) && defined(POSTS_REALNAMES)
+ cuser.realname,
+#else
+ cuser.username,
+#endif
+ local_article ? str_post2 : str_post1, currboard);
+#endif /* HAVE_ANONYMOUS */
+
+ }
+ save_title[72] = '\0';
+ fprintf(fp, "¼ÐÃD: %s\n®É¶¡: %s\n", save_title, ctime(&now));
+}
+
+void addsignature(FILE *fp, int ifuseanony) {
+ FILE *fs;
+ int i;
+ char buf[WRAPMARGIN + 1];
+ char fpath[STRLEN];
+
+ static char msg[] = "½Ð¿ï¾Üñ¦WÀÉ (1-9, 0=¤£¥[)[0]: ";
+ char ch;
+
+ if(!strcmp(cuser.userid,STR_GUEST)) {
+ fprintf(fp, "\n--\n¡° µo«H¯¸ :" BBSNAME "(" MYHOSTNAME
+ ") \n¡» From: %s\n", fromhost);
+ return;
+ }
+ if(!ifuseanony) {
+ i = showsignature(fpath);
+ msg[27] = ch = '0' | (cuser.uflag & SIG_FLAG);
+ getdata(0, 0, msg, buf, 4, DOECHO);
+
+ if(ch != buf[0] && buf[0] >= '0' && buf[0] <= '9') {
+ ch = buf[0];
+ cuser.uflag = (cuser.uflag & ~SIG_FLAG) | (ch & SIG_FLAG);
+ }
+
+ if(ch != '0') {
+ fpath[i] = ch;
+ if((fs = fopen(fpath, "r"))) {
+ fputs("\n--\n", fp);
+ for(i = 0; i < MAX_SIGLINES &&
+ fgets(buf, sizeof(buf), fs); i++)
+ fputs(buf, fp);
+ fclose(fs);
+ }
+ }
+ }
+#ifdef HAVE_ORIGIN
+#ifdef HAVE_ANONYMOUS
+ if(ifuseanony)
+ fprintf(fp, "\n--\n¡° µo«H¯¸: " BBSNAME "(" MYHOSTNAME
+ ") \n¡» From: %s\n", "¼Ê¦W¤Ñ¨Ïªº®a");
+ else {
+ char temp[32];
+
+ strncpy(temp, fromhost, 31);
+ temp[32] = '\0';
+ fprintf(fp, "\n--\n¡° µo«H¯¸: " BBSNAME "(" MYHOSTNAME
+ ") \n¡» From: %s\n", temp);
+ }
+#else
+ strncpy (temp,fromhost,15);
+ fprintf(fp, "\n--\n¡° µo«H¯¸: " BBSNAME "(" MYHOSTNAME
+ ") \n¡» From: %s\n", temp);
+#endif
+#endif
+}
+
+static int
+write_file(char *fpath, int saveheader, int *islocal) {
+ time_t now;
+ struct tm *ptime;
+ FILE *fp = NULL;
+ textline_t *p, *v;
+ char ans[TTLEN], *msg;
+ int aborted = 0, line = 0, checksum[3], sum = 0, po = 1;
+
+ stand_title("Àɮ׳B²z");
+ if(currstat == SMAIL)
+ msg = "[S]Àx¦s (A)©ñ±ó (T)§ï¼ÐÃD (E)Ä~Äò (R/W/D)Ū¼g§R¼È¦sÀÉ¡H";
+ else if(local_article)
+ msg = "[L]¯¸¤º«H¥ó (S)Àx¦s (A)©ñ±ó (T)§ï¼ÐÃD (E)Ä~Äò "
+ "(R/W/D)Ū¼g§R¼È¦sÀÉ¡H";
+ else
+ msg = "[S]Àx¦s (L)¯¸¤º«H¥ó (A)©ñ±ó (T)§ï¼ÐÃD (E)Ä~Äò "
+ "(R/W/D)Ū¼g§R¼È¦sÀÉ¡H";
+ getdata(1, 0, msg, ans, 3, LCECHO);
+
+ switch(ans[0]) {
+ case 'a':
+ outs("¤å³¹\033[1m ¨S¦³ \033[m¦s¤J");
+ safe_sleep(1);
+ aborted = -1;
+ break;
+ case 'r':
+ read_tmpbuf(-1);
+ case 'e':
+ return KEEP_EDITING;
+ case 'w':
+ write_tmpbuf();
+ return KEEP_EDITING;
+ case 'd':
+ erase_tmpbuf();
+ return KEEP_EDITING;
+ case 't':
+ move(3, 0);
+ prints("¼ÐÃD¡G%s", save_title);
+ strcpy(ans,save_title);
+ if(getdata_buf(4, 0, "·s¼ÐÃD¡G", ans, TTLEN, DOECHO))
+ strcpy(save_title, ans);
+ return KEEP_EDITING;
+ case 's':
+ if(!HAS_PERM(PERM_LOGINOK)) {
+ local_article = 1;
+ move(2, 0);
+ prints("±z©|¥¼³q¹L¨­¥÷½T»{¡A¥u¯à Local Save¡C\n");
+ pressanykey();
+ } else
+ local_article = 0;
+ break;
+ case 'l':
+ local_article = 1;
+ }
+
+ if(!aborted) {
+ if(saveheader && !(curredit & EDIT_MAIL) && check_quote())
+ return KEEP_EDITING;
+
+ if(!*fpath) {
+ sethomepath(fpath, cuser.userid);
+ strcpy(fpath, tempnam(fpath, "ve_"));
+ }
+
+ if((fp = fopen(fpath, "w")) == NULL) {
+ indigestion(5);
+ abort_bbs(0);
+ }
+ if(saveheader)
+ write_header(fp);
+ }
+
+ for(p = firstline; p; p = v) {
+ v = p->next;
+ if(!aborted) {
+ msg = p->data;
+ if(v || msg[0]) {
+ trim(msg);
+
+ line++;
+ if(currstat == POSTING && po) {
+ saveheader = str_checksum(msg);
+ if(saveheader) {
+ if(postrecord.checksum[po] == saveheader) {
+ po++;
+ if(po > 3) {
+ postrecord.times++;
+ po =0;
+ }
+ } else
+ po = 1;
+ if(currstat == POSTING && line >= totaln/2 &&
+ sum < 3) {
+ checksum[sum++] = saveheader;
+ }
+ }
+ }
+#ifdef SUPPORT_GB
+ if(current_font_type == TYPE_GB)
+ {
+ fprintf(fp, "%s\n", hc_convert_str(msg, HC_GBtoBIG, HC_DO_SINGLE));
+ }
+ else
+#endif
+ fprintf(fp, "%s\n", msg);
+ }
+ }
+ free(p);
+ }
+ currline = NULL;
+
+ if(postrecord.times > MAX_CROSSNUM - 1)
+ anticrosspost();
+
+ if(po && sum == 3) {
+ memcpy(&postrecord.checksum[1], checksum, sizeof(int) * 3);
+ postrecord.times =0;
+ }
+ if(!aborted) {
+ if(islocal)
+ *islocal = (local_article == 1);
+ if(currstat == POSTING || currstat == SMAIL)
+ addsignature(fp,ifuseanony);
+ else if(currstat == REEDIT
+#ifndef ALL_REEDIT_LOG
+ && strcmp(currboard, "SYSOP") == 0
+#endif
+ )
+ {
+ time(&now);
+ ptime = localtime(&now);
+ fprintf(fp,
+ "¡° ½s¿è: %-15s ¨Ó¦Û: %-20s (%02d/%02d %02d:%02d)\n",
+ cuser.userid, fromhost,
+ ptime->tm_mon+1,ptime->tm_mday,ptime->tm_hour,ptime->tm_min);
+ }
+
+ fclose(fp);
+ if(local_article && (currstat == POSTING))
+ return 0;
+ return 0;
+ }
+ return aborted;
+}
+
+
+static void display_buffer() {
+ register textline_t *p;
+ register int i;
+ int inblock;
+ char buf[WRAPMARGIN + 2];
+ int min, max;
+
+ if(currpnt > blockpnt) {
+ min = blockpnt;
+ max = currpnt;
+ } else {
+ min = currpnt;
+ max = blockpnt;
+ }
+
+ for(p = top_of_win, i = 0; i < b_lines; i++) {
+ move(i, 0);
+ clrtoeol();
+ if(blockln >= 0 &&
+ ((blockln <= currln && blockln <= (currln - curr_window_line + i) &&
+ (currln - curr_window_line + i) <= currln) ||
+ (currln <= (currln - curr_window_line + i) &&
+ (currln - curr_window_line + i) <= blockln))) {
+ outs("\033[7m");
+ inblock = 1;
+ } else
+ inblock = 0;
+ if(p) {
+ if(my_ansimode)
+ if(currln == blockln && p == currline && max > min) {
+ outs("\033[m");
+ strncpy(buf, p->data, min);
+ buf[min] = 0;
+ outs(buf);
+ outs("\033[7m");
+ strncpy(buf, p->data + min, max - min);
+ buf[max - min] = 0;
+ outs(buf);
+ outs("\033[m");
+ outs(p->data + max);
+ } else
+ outs(p->data);
+ else if(currln == blockln && p == currline && max > min) {
+ outs("\033[m");
+ strncpy(buf, p->data, min);
+ buf[min] = 0;
+ edit_outs(buf);
+ outs("\033[7m");
+ strncpy(buf, p->data + min, max - min);
+ buf[max - min] = 0;
+ edit_outs(buf);
+ outs("\033[m");
+ edit_outs(p->data + max);
+ } else
+ edit_outs(&p->data[edit_margin]);
+ p = p->next;
+ if(inblock)
+ outs("\033[m");
+ } else
+ outch('~');
+ }
+ edit_msg();
+}
+
+static void goto_line(int lino) {
+ char buf[10];
+
+ if(lino > 0 ||
+ (getdata(b_lines - 1, 0, "¸õ¦Ü²Ä´X¦æ:", buf, 10, DOECHO) &&
+ sscanf(buf, "%d", &lino) && lino > 0)) {
+ textline_t* p;
+
+ prevln = currln;
+ prevpnt = currpnt;
+ p = firstline;
+ currln = lino - 1;
+
+ while(--lino && p->next)
+ p = p->next;
+
+ if(p)
+ currline = p;
+ else {
+ currln = totaln;
+ currline = lastline;
+ }
+ currpnt = 0;
+ if(currln < 11) {
+ top_of_win = firstline;
+ curr_window_line = currln;
+ } else {
+ int i;
+
+ curr_window_line = 11;
+ for(i = curr_window_line; i; i--)
+ p = p->prev;
+ top_of_win = p;
+ }
+ }
+ redraw_everything = YEA;
+}
+
+char *strcasestr(const char* big, const char* little) {
+ char* ans = (char*)big;
+ int len = strlen(little);
+ char* endptr = (char*)big + strlen(big) - len;
+
+ while(ans <= endptr)
+ if(!strncasecmp(ans, little, len))
+ return ans;
+ else
+ ans++;
+ return 0;
+}
+
+/*
+ mode:
+ 0: prompt
+ 1: forward
+ -1: backward
+*/
+static void search_str(int mode) {
+ static char str[80];
+ typedef char* (*FPTR)();
+ static FPTR fptr;
+ char ans[4] = "n";
+
+ if(!mode) {
+ if(getdata_buf(b_lines - 1, 0,"[·j´M]ÃöÁä¦r:",str, 65, DOECHO))
+ if(*str) {
+ if(getdata(b_lines - 1, 0, "°Ï¤À¤j¤p¼g(Y/N/Q)? [N] ",
+ ans, 4, LCECHO) && *ans == 'y')
+ fptr = strstr;
+ else
+ fptr = strcasestr;
+ }
+ }
+
+ if(*str && *ans != 'q') {
+ textline_t* p;
+ char *pos = NULL;
+ int lino;
+
+ if(mode >= 0) {
+ for(lino = currln, p = currline; p; p = p->next, lino++)
+ if((pos = fptr(p->data + (lino == currln ? currpnt + 1 : 0),
+ str)) && (lino != currln ||
+ pos - p->data != currpnt))
+ break;
+ } else {
+ for(lino = currln, p = currline; p; p = p->prev, lino--)
+ if((pos = fptr(p->data, str)) &&
+ (lino != currln || pos - p->data != currpnt))
+ break;
+ }
+ if(pos) {
+ prevln = currln;
+ prevpnt = currpnt;
+ currline = p;
+ currln = lino;
+ currpnt = pos - p->data;
+ if(lino < 11) {
+ top_of_win = firstline;
+ curr_window_line = currln;
+ } else {
+ int i;
+
+ curr_window_line = 11;
+ for(i = curr_window_line; i; i--)
+ p = p->prev;
+ top_of_win = p;
+ }
+ redraw_everything = YEA;
+ }
+ }
+ if(!mode)
+ redraw_everything = YEA;
+}
+
+static void match_paren() {
+ static char parens[] = "()[]{}";
+ int type;
+ int parenum = 0;
+ char *ptype;
+ textline_t* p;
+ int lino;
+ int c, i = 0;
+
+ if(!(ptype = strchr(parens, currline->data[currpnt])))
+ return;
+
+ type = (ptype - parens) / 2;
+ parenum += ((ptype - parens) % 2) ? -1 : 1;
+
+ if(parenum > 0) {
+ for(lino = currln, p = currline; p; p = p->next, lino++) {
+ lino = lino;
+ for(i = (lino == currln) ? currpnt + 1 : 0;
+ i < strlen(p->data); i++)
+ if(p->data[i] == '/' && p->data[++i] == '*') {
+ ++i;
+ while(1) {
+ while(i < strlen(p->data) - 1 &&
+ !(p->data[i] == '*' && p->data[i + 1] == '/'))
+ i++;
+ if(i >= strlen(p->data) - 1 && p->next) {
+ p = p->next;
+ ++lino;
+ i = 0;
+ } else
+ break;
+ }
+ } else if((c = p->data[i]) == '\'' || c == '"') {
+ while(1) {
+ while(i < (int)(strlen(p->data) - 1))
+ if(p->data[++i] == '\\' && i < strlen(p->data) - 2)
+ ++i;
+ else if(p->data[i] == c)
+ goto end_quote;
+ if(i >= strlen(p->data) - 1 && p->next) {
+ p = p->next;
+ ++lino;
+ i = -1;
+ } else
+ break;
+ }
+end_quote:
+ ;
+ } else if((ptype = strchr(parens, p->data[i])) &&
+ (ptype - parens) / 2 == type)
+ if(!(parenum += ((ptype - parens) % 2) ? -1 : 1))
+ goto p_outscan;
+ }
+ } else {
+ for(lino = currln, p = currline; p; p = p->prev, lino--)
+ for(i = (lino == currln) ? currpnt - 1 : strlen(p->data) - 1;
+ i >= 0; i--)
+ if(p->data[i] == '/' && p->data[--i] == '*' && i > 0) {
+ --i;
+ while(1) {
+ while(i > 0 &&
+ !(p->data[i] == '*' && p->data[i - 1] == '/'))
+ i--;
+ if(i <= 0 && p->prev) {
+ p = p->prev;
+ --lino;
+ i = strlen(p->data) - 1;
+ } else
+ break;
+ }
+ } else if((c = p->data[i]) == '\'' || c == '"') {
+ while(1) {
+ while(i > 0)
+ if(i > 1 && p->data[i - 2] == '\\')
+ i -= 2;
+ else if((p->data[--i]) == c)
+ goto begin_quote;
+ if(i <= 0 && p->prev) {
+ p = p->prev;
+ --lino;
+ i = strlen(p->data);
+ } else
+ break;
+ }
+begin_quote:
+ ;
+ } else if((ptype = strchr(parens, p->data[i])) &&
+ (ptype - parens) / 2 == type)
+ if(!(parenum += ((ptype - parens) % 2) ? -1 : 1))
+ goto p_outscan;
+ }
+p_outscan:
+ if(!parenum) {
+ int top = currln - curr_window_line;
+ int bottom = currln - curr_window_line + b_lines - 1;
+
+ currpnt = i;
+ currline = p;
+ curr_window_line += lino - currln;
+ currln = lino;
+
+ if(lino < top || lino > bottom) {
+ if(lino < 11) {
+ top_of_win = firstline;
+ curr_window_line = currln;
+ } else {
+ int i;
+
+ curr_window_line = 11;
+ for(i = curr_window_line; i; i--)
+ p = p->prev;
+ top_of_win = p;
+ }
+ redraw_everything = YEA;
+ }
+ }
+}
+
+static void block_del(int hide) {
+ if(blockln < 0) {
+ blockln = currln;
+ blockpnt = currpnt;
+ blockline = currline;
+ } else {
+ char fp_tmpbuf[80];
+ FILE* fp;
+ textline_t *begin, *end, *p;
+ char tmpfname[10] = "buf.0";
+ char ans[6] = "w+n";
+
+ move(b_lines - 1, 0);
+ clrtoeol();
+ if(hide == 1)
+ tmpfname[4] = 'q';
+ else if(!hide && !getdata(b_lines - 1, 0, "§â°Ï¶ô²¾¦Ü¼È¦sÀÉ "
+ "(0:Cut, 5:Copy, 6-9, q: Cancel)[0] ",
+ tmpfname + 4, 4, LCECHO))
+ tmpfname[4] = '0';
+ if(tmpfname[4] < '0' || tmpfname[4] > '9')
+ tmpfname[4] = 'q';
+ if('1' <= tmpfname[4] && tmpfname[4] <= '9') {
+ setuserfile(fp_tmpbuf, tmpfname);
+ if(tmpfname[4] != '5' && dashf(fp_tmpbuf)) {
+ more(fp_tmpbuf, NA);
+ getdata(b_lines - 1, 0, "¼È¦sÀɤw¦³¸ê®Æ (A)ªþ¥[ (W)Âмg "
+ "(Q)¨ú®ø¡H[W] ", ans, 4, LCECHO);
+ if(*ans == 'q')
+ tmpfname[4] = 'q';
+ else if(*ans != 'a')
+ *ans = 'w';
+ }
+ if(tmpfname[4] != '5') {
+ getdata(b_lines - 1, 0, "§R°£°Ï¶ô(Y/N)?[N] ",
+ ans + 2, 4, LCECHO);
+ if(ans[2] != 'y')
+ ans[2] = 'n';
+ }
+ } else if(hide != 3)
+ ans[2] = 'y';
+
+ tmpfname[5] = ans[1] = ans[3] = 0;
+ if(tmpfname[4] != 'q') {
+ if(currln >= blockln) {
+ begin = blockline;
+ end = currline;
+ if(ans[2] == 'y' && !(begin == end && currpnt != blockpnt)) {
+ curr_window_line -= (currln - blockln);
+ if(curr_window_line < 0) {
+ curr_window_line = 0;
+ if(end->next)
+ (top_of_win = end->next)->prev = begin->prev;
+ else
+ top_of_win = (lastline = begin->prev);
+ }
+ currln -= (currln - blockln);
+ }
+ } else {
+ begin = currline;
+ end = blockline;
+ }
+ if(ans[2] == 'y' && !(begin == end && currpnt != blockpnt)) {
+ if(begin->prev)
+ begin->prev->next = end->next;
+ else if(end->next)
+ top_of_win = firstline = end->next;
+ else {
+ currline = top_of_win = firstline =
+ lastline = alloc_line();
+ currln = curr_window_line = edit_margin = 0;
+ }
+
+ if(end->next)
+ (currline = end->next)->prev = begin->prev;
+ else if(begin->prev) {
+ currline = (lastline = begin->prev);
+ currln--;
+ if(curr_window_line > 0)
+ curr_window_line--;
+ }
+ }
+
+ setuserfile(fp_tmpbuf, tmpfname);
+ if((fp = fopen(fp_tmpbuf, ans))) {
+ if(begin == end && currpnt != blockpnt) {
+ char buf[WRAPMARGIN + 2];
+
+ if(currpnt > blockpnt) {
+ strcpy(buf, begin->data + blockpnt);
+ buf[currpnt - blockpnt] = 0;
+ } else {
+ strcpy(buf, begin->data + currpnt);
+ buf[blockpnt - currpnt] = 0;
+ }
+ fputs(buf, fp);
+ } else {
+ for(p = begin; p != end; p = p->next)
+ fprintf(fp, "%s\n", p->data);
+ fprintf(fp, "%s\n", end->data);
+ }
+ fclose(fp);
+ }
+
+ if(ans[2] == 'y') {
+ if(begin == end && currpnt != blockpnt) {
+ int min, max;
+
+ if(currpnt > blockpnt) {
+ min = blockpnt;
+ max = currpnt;
+ } else {
+ min = currpnt;
+ max = blockpnt;
+ }
+ strcpy(begin->data + min, begin->data + max);
+ begin->len -= max - min;
+ currpnt = min;
+ } else {
+ for(p = begin; p != end; totaln--)
+ free((p = p->next)->prev);
+ free(end);
+ totaln--;
+ currpnt = 0;
+ }
+ }
+ }
+ blockln = -1;
+ redraw_everything = YEA;
+ }
+}
+
+static void block_shift_left() {
+ textline_t *begin, *end, *p;
+
+ if(currln >= blockln) {
+ begin = blockline;
+ end = currline;
+ } else {
+ begin = currline;
+ end = blockline;
+ }
+ p = begin;
+ while(1) {
+ if(p->len) {
+ strcpy(p->data, p->data + 1);
+ --p->len;
+ }
+ if(p == end)
+ break;
+ else
+ p = p->next;
+ }
+ if(currpnt > currline->len)
+ currpnt = currline->len;
+ redraw_everything = YEA;
+}
+
+static void block_shift_right() {
+ textline_t *begin, *end, *p;
+
+ if(currln >= blockln) {
+ begin = blockline;
+ end = currline;
+ } else {
+ begin = currline;
+ end = blockline;
+ }
+ p = begin;
+ while(1) {
+ if(p->len < WRAPMARGIN) {
+ int i = p->len + 1;
+
+ while(i--)
+ p->data[i + 1] = p->data[i];
+ p->data[0] = insert_character ? ' ' : insert_c;
+ ++p->len;
+ }
+ if(p == end)
+ break;
+ else
+ p = p->next;
+ }
+ if(currpnt > currline->len)
+ currpnt = currline->len;
+ redraw_everything = YEA;
+}
+
+static void transform_to_color(char* line) {
+ while(line[0] && line[1])
+ if(line[0] == '*' && line[1] == '[') {
+ line[0] = KEY_ESC;
+ line += 2;
+ } else
+ ++line;
+}
+
+static void block_color() {
+ textline_t *begin, *end, *p;
+
+ if(currln >= blockln) {
+ begin = blockline;
+ end = currline;
+ } else {
+ begin = currline;
+ end = blockline;
+ }
+ p = begin;
+ while(1) {
+ transform_to_color(p->data);
+ if(p == end)
+ break;
+ else
+ p = p->next;
+ }
+ block_del(1);
+}
+
+/* ½s¿è³B²z¡G¥Dµ{¦¡¡BÁä½L³B²z */
+int vedit(char *fpath, int saveheader, int *islocal) {
+ FILE *fp1;
+ char last = 0, buf[200]; /* the last key you press */
+ int ch, foo;
+ int lastindent = -1;
+ int last_margin;
+ int mode0 = currutmp->mode;
+ int destuid0 = currutmp->destuid;
+ unsigned int money=0;
+ unsigned short int interval=0;
+ time_t now=0,th;
+
+ textline_t* firstline0 = firstline;
+ textline_t* lastline0 = lastline;
+ textline_t* currline0 = currline;
+ textline_t* blockline0 = blockline;
+ textline_t* top_of_win0 = top_of_win;
+ int local_article0 = local_article;
+ int currpnt0 = currpnt;
+ int currln0 = currln;
+ int totaln0 = totaln;
+ int curr_window_line0 = curr_window_line;
+ int insert_character0 = insert_character;
+ int my_ansimode0 = my_ansimode;
+ int edit_margin0 = edit_margin;
+ int blockln0 = blockln, count=0, tin=0;
+
+ currutmp->mode = EDITING;
+ currutmp->destuid = currstat;
+ insert_character = redraw_everything = 1;
+ prevln = blockln = -1;
+
+ line_dirty = currpnt = totaln = my_ansimode = 0;
+ currline = top_of_win = firstline = lastline = alloc_line();
+
+ if(*fpath)
+ read_file(fpath);
+
+ if(*quote_file) {
+ do_quote();
+ *quote_file = '\0';
+ if(quote_file[79] == 'L')
+ local_article = 1;
+ }
+
+ currline = firstline;
+ currpnt = currln = curr_window_line = edit_margin = last_margin = 0;
+
+ while(1) {
+ if(redraw_everything || blockln >= 0) {
+ display_buffer();
+ redraw_everything = NA;
+ }
+ if(my_ansimode)
+ ch = n2ansi(currpnt, currline);
+ else
+ ch = currpnt - edit_margin;
+ move(curr_window_line, ch);
+ if(!line_dirty && strcmp(line, currline->data))
+ strcpy(line, currline->data);
+ ch = igetkey();
+ /* jochang debug */
+ if((interval = (unsigned short int)((th = currutmp->lastact) - now))) {
+ now = th;
+ if((char)ch != last) {
+ money++;
+ last = (char)ch;
+ }
+ }
+ if(interval && interval == tin)
+ count++;
+ else
+ {
+ count=0;
+ tin = interval;
+ }
+ /* ³sÄò240­Óinterval¤@¼Ë , ¤À©ú¬O¦bÀÄ°] */
+ if(count >= 240) {
+ sprintf(buf, "\033[1;33;46m%s\033[37m¦b\033[37;45m%s"
+ "\033[37mªO¹HªkÁÈ¿ú , %s\033[m", cuser.userid,
+ currboard,ctime(&now));
+ log_file ("etc/illegal_money",buf);
+ money = 0 ;
+ post_violatelaw(cuser.userid, "Ptt ¨t²Îĵ¹î", "¹HªkÁÈ¿ú", "¦©°£¤£ªk©Ò±o");
+ mail_violatelaw(cuser.userid, "Ptt ¨t²Îĵ¹î", "¹HªkÁÈ¿ú", "¦©°£¤£ªk©Ò±o");
+// demoney(10000);
+// abort_bbs(0);
+ }
+
+ if(raw_mode)
+ switch (ch) {
+ case Ctrl('S'):
+ case Ctrl('Q'):
+ case Ctrl('T'):
+ continue;
+ break;
+ }
+ if(ch < 0x100 && isprint2(ch)) {
+ insert_char(ch);
+ lastindent = -1;
+ line_dirty = 1;
+ } else {
+ if(ch == Ctrl('P') || ch == KEY_UP || ch == KEY_DOWN ||
+ ch == Ctrl('N')) {
+ if(lastindent == -1)
+ lastindent = currpnt;
+ } else
+ lastindent = -1;
+ if(ch == KEY_ESC)
+ switch(KEY_ESC_arg) {
+ case ',':
+ ch = Ctrl(']');
+ break;
+ case '.':
+ ch = Ctrl('T');
+ break;
+ case 'v':
+ ch = KEY_PGUP;
+ break;
+ case 'a':
+ case 'A':
+ ch = Ctrl('V');
+ break;
+ case 'X':
+ ch = Ctrl('X');
+ break;
+ case 'q':
+ ch = Ctrl('Q');
+ break;
+ case 'o':
+ ch = Ctrl('O');
+ break;
+ case '-':
+ ch = Ctrl('_');
+ break;
+ case 's':
+ ch = Ctrl('S');
+ break;
+ }
+
+ switch(ch) {
+ case Ctrl('X'): /* Save and exit */
+ foo = write_file(fpath, saveheader, islocal);
+ if(foo != KEEP_EDITING) {
+ currutmp->mode = mode0;
+ currutmp->destuid = destuid0;
+ firstline = firstline0;
+ lastline = lastline0;
+ currline = currline0;
+ blockline = blockline0;
+ top_of_win = top_of_win0;
+ local_article = local_article0;
+ currpnt = currpnt0;
+ currln = currln0;
+ totaln = totaln0;
+ curr_window_line = curr_window_line0;
+ insert_character = insert_character0;
+ my_ansimode = my_ansimode0;
+ edit_margin = edit_margin0;
+ blockln = blockln0;
+ if(!foo)
+ return money;
+ else
+ return foo;
+ }
+ line_dirty = 1;
+ redraw_everything = YEA;
+ break;
+ case Ctrl('W'):
+ if(blockln >= 0)
+ block_del(2);
+ line_dirty = 1;
+ break;
+ case Ctrl('Q'): /* Quit without saving */
+ ch = ask("µ²§ô¦ý¤£Àx¦s (Y/N)? [N]: ");
+ if(ch == 'y' || ch == 'Y') {
+ currutmp->mode = mode0;
+ currutmp->destuid = destuid0;
+ firstline = firstline0;
+ lastline = lastline0;
+ currline = currline0;
+ blockline = blockline0;
+ top_of_win = top_of_win0;
+ local_article = local_article0;
+ currpnt = currpnt0;
+ currln = currln0;
+ totaln = totaln0;
+ curr_window_line = curr_window_line0;
+ insert_character = insert_character0;
+ my_ansimode = my_ansimode0;
+ edit_margin = edit_margin0;
+ blockln = blockln0;
+ return -1;
+ }
+ line_dirty = 1;
+ redraw_everything = YEA;
+ break;
+ case Ctrl('C'):
+ ch = insert_character;
+ insert_character = redraw_everything = YEA;
+ if(!my_ansimode)
+ insert_string(reset_color);
+ else {
+ char ans[4];
+ move(b_lines - 2, 55);
+ outs("\033[1;33;40mB\033[41mR\033[42mG\033[43mY\033[44mL"
+ "\033[45mP\033[46mC\033[47mW\033[m");
+ if(getdata(b_lines - 1, 0,
+ "½Ð¿é¤J «G«×/«e´º/­I´º[¥¿±`¥Õ¦r¶Â©³][0wb]¡G",
+ ans, 4, LCECHO)) {
+ char t[] = "BRGYLPCW";
+ char color[15];
+ char *tmp, *apos = ans;
+ int fg, bg;
+
+ strcpy(color, "\033[");
+ if(isdigit(*apos)) {
+ sprintf(color, "%s%c", color, *(apos++));
+ if(*apos)
+ sprintf(color, "%s;", 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);
+ }
+ sprintf(color, "%sm", color);
+ insert_string(color);
+ } else
+ insert_string(reset_color);
+ }
+ insert_character = ch;
+ line_dirty = 1;
+ break;
+ case KEY_ESC:
+ line_dirty = 0;
+ switch(KEY_ESC_arg) {
+ case 'U':
+ t_users();
+ redraw_everything = YEA;
+ line_dirty = 1;
+ break;
+ case 'i':
+ t_idle();
+ redraw_everything = YEA;
+ line_dirty = 1;
+ break;
+ case 'n':
+ search_str(1);
+ break;
+ case 'p':
+ search_str(-1);
+ break;
+ case 'L':
+ case 'J':
+ goto_line(0);
+ break;
+ case ']':
+ match_paren();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ read_tmpbuf(KEY_ESC_arg - '0');
+ redraw_everything = YEA;
+ break;
+ case 'l': /* block delete */
+ case ' ':
+ block_del(0);
+ line_dirty = 1;
+ break;
+ case 'u':
+ if(blockln >= 0)
+ block_del(1);
+ line_dirty = 1;
+ break;
+ case 'c':
+ if(blockln >= 0)
+ block_del(3);
+ line_dirty = 1;
+ break;
+ case 'y':
+ undelete_line();
+ break;
+ case 'R':
+ raw_mode ^= 1;
+ line_dirty = 1;
+ break;
+ case 'I':
+ indent_mode ^= 1;
+ line_dirty = 1;
+ break;
+ case 'j':
+ if(blockln >= 0)
+ block_shift_left();
+ else if(currline->len) {
+ int currpnt0 = currpnt;
+ currpnt = 0;
+ delete_char();
+ currpnt = (currpnt0 <= currline->len) ? currpnt0 :
+ currpnt0 - 1;
+ if(my_ansimode)
+ currpnt = ansi2n(n2ansi(currpnt, currline),
+ currline);
+ }
+ line_dirty = 1;
+ break;
+ case 'k':
+ if(blockln >= 0)
+ block_shift_right();
+ else {
+ int currpnt0 = currpnt;
+
+ currpnt = 0;
+ insert_char(' ');
+ currpnt = currpnt0;
+ }
+ line_dirty = 1;
+ break;
+ case 'f':
+ while(currpnt < currline->len &&
+ isalnum(currline->data[++currpnt]));
+ while(currpnt < currline->len &&
+ isspace(currline->data[++currpnt]));
+ line_dirty = 1;
+ break;
+ case 'b':
+ while(currpnt && isalnum(currline->data[--currpnt]));
+ while(currpnt && isspace(currline->data[--currpnt]));
+ line_dirty = 1;
+ break;
+ case 'd':
+ while(currpnt < currline->len) {
+ delete_char();
+ if(!isalnum(currline->data[currpnt]))
+ break;
+ }
+ while(currpnt < currline->len) {
+ delete_char();
+ if(!isspace(currline->data[currpnt]))
+ break;
+ }
+ line_dirty = 1;
+ break;
+ default:
+ line_dirty = 1;
+ }
+ break;
+ case Ctrl('_'):
+ if(strcmp(line, currline->data)) {
+ char buf[WRAPMARGIN];
+
+ strcpy(buf, currline->data);
+ strcpy(currline->data, line);
+ strcpy(line, buf);
+ currline->len = strlen(currline->data);
+ currpnt = 0;
+ line_dirty = 1;
+ }
+ break;
+ case Ctrl('S'):
+ search_str(0);
+ break;
+ case Ctrl('U'):
+ insert_char('\033');
+ line_dirty = 1;
+ break;
+ case Ctrl('V'): /* Toggle ANSI color */
+ my_ansimode ^= 1;
+ if(my_ansimode && blockln >= 0)
+ block_color();
+ clear();
+ redraw_everything = YEA;
+ line_dirty = 1;
+ break;
+ case Ctrl('I'):
+ do {
+ insert_char(' ');
+ } while(currpnt & 0x7);
+ line_dirty = 1;
+ break;
+ case '\r':
+ case '\n':
+ split(currline, currpnt);
+ line_dirty = 0;
+ break;
+ case Ctrl('G'):
+ {
+ unsigned int currstat0 = currstat;
+ setutmpmode(EDITEXP);
+ a_menu("½s¿è»²§U¾¹", "etc/editexp",
+ (HAS_PERM(PERM_SYSOP) ? SYSOP : NOBODY));
+ currstat = currstat0;
+ }
+ if(trans_buffer[0]) {
+ if((fp1 = fopen(trans_buffer, "r"))) {
+ int indent_mode0 = indent_mode;
+
+ indent_mode = 0;
+ prevln = currln;
+ prevpnt = currpnt;
+ while(fgets(line, WRAPMARGIN + 2, fp1)) {
+ if(!strncmp(line,"§@ªÌ:",5) ||
+ !strncmp(line,"¼ÐÃD:",5) ||
+ !strncmp(line,"®É¶¡:",5))
+ continue;
+ insert_string(line);
+ }
+ fclose(fp1);
+ indent_mode = indent_mode0;
+ while(curr_window_line >= b_lines) {
+ curr_window_line--;
+ top_of_win = top_of_win->next;
+ }
+ }
+ }
+ redraw_everything = YEA;
+ line_dirty = 1;
+ break;
+ case Ctrl('Z'): /* Help */
+ more("etc/ve.hlp",YEA);
+ redraw_everything = YEA;
+ line_dirty = 1;
+ break;
+ case Ctrl('L'):
+ clear();
+ redraw_everything = YEA;
+ line_dirty = 1;
+ break;
+ case KEY_LEFT:
+ if(currpnt) {
+ if(my_ansimode)
+ currpnt = n2ansi(currpnt, currline);
+ currpnt--;
+ if(my_ansimode)
+ currpnt = ansi2n(currpnt, currline);
+ line_dirty = 1;
+ } else if(currline->prev) {
+ curr_window_line--;
+ currln--;
+ currline = currline->prev;
+ currpnt = currline->len;
+ line_dirty = 0;
+ }
+ break;
+ case KEY_RIGHT:
+ if(currline->len != currpnt) {
+ if(my_ansimode)
+ currpnt = n2ansi(currpnt, currline);
+ currpnt++;
+ if(my_ansimode)
+ currpnt = ansi2n(currpnt, currline);
+ line_dirty = 1;
+ } else if(currline->next) {
+ currpnt = 0;
+ curr_window_line++;
+ currln++;
+ currline = currline->next;
+ line_dirty = 0;
+ }
+ break;
+ case KEY_UP:
+ case Ctrl('P'):
+ if(currline->prev) {
+ if(my_ansimode)
+ ch = n2ansi(currpnt,currline);
+ curr_window_line--;
+ currln--;
+ currline = currline->prev;
+ if(my_ansimode)
+ currpnt = ansi2n(ch , currline);
+ else
+ currpnt = (currline->len > lastindent) ? lastindent :
+ currline->len;
+ line_dirty = 0;
+ }
+ break;
+ case KEY_DOWN:
+ case Ctrl('N'):
+ if(currline->next) {
+ if(my_ansimode)
+ ch = n2ansi(currpnt,currline);
+ currline = currline->next;
+ curr_window_line++;
+ currln++;
+ if(my_ansimode)
+ currpnt = ansi2n(ch , currline);
+ else
+ currpnt = (currline->len > lastindent) ? lastindent :
+ currline->len;
+ line_dirty = 0;
+ }
+ break;
+ case Ctrl('B'):
+ case KEY_PGUP:
+ redraw_everything = currln;
+ top_of_win = back_line(top_of_win, 22);
+ currln = redraw_everything;
+ currline = back_line(currline, 22);
+ curr_window_line = getlineno();
+ if(currpnt > currline->len)
+ currpnt = currline->len;
+ redraw_everything = YEA;
+ line_dirty = 0;
+ break;
+ case KEY_PGDN:
+ case Ctrl('F'):
+ redraw_everything = currln;
+ top_of_win = forward_line(top_of_win, 22);
+ currln = redraw_everything;
+ currline = forward_line(currline, 22);
+ curr_window_line = getlineno();
+ if(currpnt > currline->len)
+ currpnt = currline->len;
+ redraw_everything = YEA;
+ line_dirty = 0;
+ break;
+ case KEY_END:
+ case Ctrl('E'):
+ currpnt = currline->len;
+ line_dirty = 1;
+ break;
+ case Ctrl(']'): /* start of file */
+ prevln = currln;
+ prevpnt = currpnt;
+ currline = top_of_win = firstline;
+ currpnt = currln = curr_window_line = 0;
+ redraw_everything = YEA;
+ line_dirty = 0;
+ break;
+ case Ctrl('T'): /* tail of file */
+ prevln = currln;
+ prevpnt = currpnt;
+ top_of_win = back_line(lastline, 23);
+ currline = lastline;
+ curr_window_line = getlineno();
+ currln = totaln;
+ redraw_everything = YEA;
+ currpnt = 0;
+ line_dirty = 0;
+ break;
+ case KEY_HOME:
+ case Ctrl('A'):
+ currpnt = 0;
+ line_dirty = 1;
+ break;
+ case KEY_INS: /* Toggle insert/overwrite */
+ case Ctrl('O'):
+ if(blockln >= 0 && insert_character) {
+ char ans[4];
+
+ getdata(b_lines - 1, 0,
+ "°Ï¶ô·L½Õ¥k²¾´¡¤J¦r¤¸(¹w³]¬°ªÅ¥Õ¦r¤¸)",
+ ans, 4, LCECHO);
+ insert_c = (*ans) ? *ans : ' ';
+ }
+ insert_character ^= 1;
+ line_dirty = 1;
+ break;
+ case Ctrl('H'):
+ case '\177': /* backspace */
+ line_dirty = 1;
+ if(my_ansimode) {
+ my_ansimode = 0;
+ clear();
+ redraw_everything = YEA;
+ } else {
+ if(currpnt == 0) {
+ textline_t *p;
+
+ if(!currline->prev)
+ break;
+ line_dirty = 0;
+ curr_window_line--;
+ currln--;
+ currline = currline->prev;
+ currpnt = currline->len;
+ redraw_everything = YEA;
+ if(*killsp(currline->next->data) == '\0') {
+ delete_line(currline->next);
+ break;
+ }
+ p = currline;
+ while(!join(p)) {
+ p = p->next;
+ if(p == NULL) {
+ indigestion(2);
+ abort_bbs(0);
+ }
+ }
+ break;
+ }
+ currpnt--;
+ delete_char();
+ }
+ break;
+ case Ctrl('D'):
+ case KEY_DEL: /* delete current character */
+ line_dirty = 1;
+ if(currline->len == currpnt) {
+ textline_t *p = currline;
+
+ while(!join(p)) {
+ p = p->next;
+ if(p == NULL) {
+ indigestion(2);
+ abort_bbs(0);
+ }
+ }
+ line_dirty = 0;
+ redraw_everything = YEA;
+ } else {
+ delete_char();
+ if(my_ansimode)
+ currpnt = ansi2n(n2ansi(currpnt, currline), currline);
+ }
+ break;
+ case Ctrl('Y'): /* delete current line */
+ currline->len = currpnt = 0;
+ case Ctrl('K'): /* delete to end of line */
+ if(currline->len == 0) {
+ textline_t *p = currline->next;
+ if(!p) {
+ p = currline->prev;
+ if(!p)
+ break;
+ if(curr_window_line > 0) {
+ curr_window_line--;
+ currln--;
+ }
+ }
+ if(currline == top_of_win)
+ top_of_win = p;
+ delete_line(currline);
+ currline = p;
+ redraw_everything = YEA;
+ line_dirty = 0;
+ break;
+ }
+ if(currline->len == currpnt) {
+ textline_t *p = currline;
+
+ while(!join(p)) {
+ p = p->next;
+ if(p == NULL) {
+ indigestion(2);
+ abort_bbs(0);
+ }
+ }
+ redraw_everything = YEA;
+ line_dirty = 0;
+ break;
+ }
+ currline->len = currpnt;
+ currline->data[currpnt] = '\0';
+ line_dirty = 1;
+ break;
+ }
+ if(currln < 0)
+ currln = 0;
+ if(curr_window_line < 0) {
+ curr_window_line = 0;
+ if(!top_of_win->prev)
+ indigestion(6);
+ else {
+ top_of_win = top_of_win->prev;
+ rscroll();
+ }
+ }
+ if(curr_window_line == b_lines) {
+ curr_window_line = t_lines - 2;
+ if(!top_of_win->next)
+ indigestion(7);
+ else {
+ top_of_win = top_of_win->next;
+ move(b_lines, 0);
+ clrtoeol();
+ scroll();
+ }
+ }
+ }
+ edit_margin = currpnt < SCR_WIDTH - 1 ? 0 : currpnt / 72 * 72;
+
+ if(!redraw_everything) {
+ if(edit_margin != last_margin) {
+ last_margin = edit_margin;
+ redraw_everything = YEA;
+ } else {
+ move(curr_window_line, 0);
+ clrtoeol();
+ if(my_ansimode)
+ outs(currline->data);
+ else
+ edit_outs(&currline->data[edit_margin]);
+ edit_msg();
+ }
+ }
+ }
+}
diff --git a/mbbsd/friend.c b/mbbsd/friend.c
new file mode 100644
index 00000000..3d2167ae
--- /dev/null
+++ b/mbbsd/friend.c
@@ -0,0 +1,509 @@
+/* $Id: friend.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "perm.h"
+#include "proto.h"
+
+extern char currboard[]; /* name of currently selected board */
+extern char *fn_overrides;
+extern userinfo_t *currutmp;
+extern char *fn_reject;
+extern int usernum;
+extern char *str_space;
+extern char *msg_uid;
+
+/* ------------------------------------- */
+/* ¯S§O¦W³æ */
+/* ------------------------------------- */
+
+/* Ptt ¨ä¥L¯S§O¦W³æªºÀɦW */
+static char special_list[] = "list.0";
+static char special_des[] = "ldes.0";
+
+/* ¯S§O¦W³æªº¤W­­ */
+static unsigned int friend_max[8] = {
+ MAX_FRIEND,
+ MAX_REJECT,
+ MAX_LOGIN_INFO,
+ MAX_POST_INFO,
+ MAX_NAMELIST,
+ MAX_NAMELIST,
+ MAX_NAMELIST,
+ MAX_NAMELIST
+};
+/* ÁöµM¦n¤Í¸òÃa¤H¦W³æ³£¬O * 2 ¦ý¬O¤@¦¸³Ì¦hload¨ìshm¥u¯à¦³128 */
+
+/* Ptt ¦UºØ¯S§O¦W³æªºÀɦW */
+char *friend_file[8] = {
+ FN_OVERRIDES,
+ FN_REJECT,
+ "alohaed",
+ "postlist",
+ "",
+ FN_CANVOTE,
+ FN_WATER,
+ FN_VISABLE
+};
+
+/* Ptt ¦UºØ¯S§O¦W³æªº¸É­z */
+static char *friend_desc[8] = {
+ "¤Í½Ë´y­z¡G",
+ "´c§Î´cª¬¡G",
+ "",
+ "",
+ "´y­z¤@¤U¡G",
+ "§ë²¼ªÌ´y­z¡G",
+ "´c§Î´cª¬¡G",
+ "¬ÝªO¦n¤Í´y­z"
+};
+
+/* Ptt ¦UºØ¯S§O¦W³æªº¤¤¤å±Ô­z */
+static char *friend_list[8] = {
+ "¦n¤Í¦W³æ",
+ "Ãa¤H¦W³æ",
+ "¤W½u³qª¾",
+ "·s¤å³¹³qª¾",
+ "¨ä¥¦¯S§O¦W³æ",
+ "¨p¤H§ë²¼¦W³æ",
+ "¬ÝªO¸TÁn¦W³æ",
+ "¬ÝªO¦n¤Í¦W³æ"
+};
+
+static void setfriendfile(char *fpath, int type) {
+ if (type <= 4) /* user list Ptt */
+ setuserfile(fpath, friend_file[type]);
+ else /* board list */
+ setbfile(fpath, currboard, friend_file[type]);
+}
+
+static int friend_count(char *fname) {
+ FILE *fp;
+ int count = 0;
+ char buf[200];
+
+#if 0
+ if ((fp = fopen(fname, "r")))
+ while (fgets(buf, 200, fp))
+ count++;
+#endif
+
+/*rocker.011018: §Ñ°OÃöÀɤF... */
+ if ((fp = fopen(fname, "r")))
+ {
+ while (fgets(buf, 200, fp)) count++;
+ fclose (fp);
+ }
+
+ return count;
+}
+
+void friend_add(char *uident, int type) {
+ char fpath[80];
+
+ setfriendfile(fpath, type);
+ if (friend_count(fpath) > friend_max[type])
+ return;
+
+ if ((uident[0] > ' ') && !belong(fpath, uident))
+ {
+ FILE *fp;
+ char buf[40] = "";
+ char t_uident[IDLEN + 1];
+
+ /* Thor: avoid uident run away when get data */
+ strcpy(t_uident, uident);
+
+ if (type != FRIEND_ALOHA && type != FRIEND_POST)
+ getdata(2, 0, friend_desc[type], buf, 40, DOECHO);
+
+ if ((fp = fopen(fpath, "a")))
+ {
+ flock(fileno(fp), LOCK_EX);
+ fprintf(fp, "%-13s%s\n", t_uident, buf);
+ flock(fileno(fp), LOCK_UN);
+ fclose(fp);
+ }
+ }
+}
+
+static void friend_special() {
+ char genbuf[70], i, fname[70];
+
+ friend_file[FRIEND_SPECIAL] = special_list;
+ for (i = 0; i <= 9; i++)
+ {
+ sprintf(genbuf, " (\033[36m%d\033[m) .. ", i);
+ special_des[5] = i + '0';
+ setuserfile(fname, special_des);
+ if (dashf(fname))
+ {
+ /* no NULL check?? */
+ FILE *fp = fopen(fname, "r");
+
+ fgets(genbuf + 15, 40, fp);
+ genbuf[47] = 0;
+ }
+ move(i + 12, 0);
+ clrtoeol();
+ outs(genbuf);
+ }
+ getdata(22, 0, "½Ð¿ï¾Ü²Ä´X¸¹¯S§O¦W³æ (0~9)[0]?", genbuf, 3, LCECHO);
+ if (genbuf[0] >= '0' && genbuf[0] <= '9')
+ {
+ special_list[5] = genbuf[0];
+ special_des[5] = genbuf[0];
+ }
+ else
+ {
+ special_list[5] = '0';
+ special_des[5] = '0';
+ }
+}
+
+static void friend_append(int type, int count) {
+ char fpath[80], i, j, buf[80], sfile[80];
+ FILE *fp, *fp1;
+
+ setfriendfile(fpath, type);
+
+ do
+ {
+ move(2, 0);
+ clrtobot();
+ outs("­n¤Þ¤J­þ¤@­Ó¦W³æ?\n");
+ for (i = 0, j = 0; i <= 7; i++)
+ {
+ if (i == type)
+ continue;
+ j++;
+ if (i <= 4)
+ sprintf(buf, " (%d) %-s\n", j, friend_list[(int) i]);
+ else
+ sprintf(buf, " (%d) %s ª©ªº %s\n", j, currboard,
+ friend_list[(int) i]);
+ outs(buf);
+ }
+ outs(" (S) ¿ï¾Ü¨ä¥L¬ÝªOªº¯S§O¦W³æ");
+ getdata(11, 0, "½Ð¿ï¾Ü ©Î ª½±µ[Enter] ©ñ±ó:", buf, 3, LCECHO);
+ if (!buf[0])
+ return;
+ if (buf[0] == 's')
+ Select();
+ }
+ while (buf[0] < '1' || buf[0] > '9');
+
+ j = buf[0] - '1';
+ if (j >= type)
+ j++;
+ if (j == FRIEND_SPECIAL)
+ friend_special();
+
+ setfriendfile(sfile, j);
+
+ fp = fopen(sfile, "r");
+ while (fgets(buf, 80, fp) && count <= friend_max[type])
+ {
+ char the_id[15];
+
+ sscanf(buf, "%s", the_id);
+ if (!belong(fpath, the_id))
+ {
+ if ((fp1 = fopen(fpath, "a")))
+ {
+ flock(fileno(fp1), LOCK_EX);
+ fputs(buf, fp1);
+ flock(fileno(fp1), LOCK_UN);
+ fclose(fp1);
+ }
+ }
+ }
+ fclose(fp);
+}
+
+void friend_delete(char *uident, int type) {
+ FILE *fp, *nfp;
+ char fn[80], fnnew[80];
+ char genbuf[200];
+
+ setfriendfile(fn, type);
+
+ sprintf(fnnew, "%s-", fn);
+ if ((fp = fopen(fn, "r")) && (nfp = fopen(fnnew, "w")))
+ {
+ int length = strlen(uident);
+
+ while (fgets(genbuf, STRLEN, fp))
+ if ((genbuf[0] > ' ') && strncmp(genbuf, uident, length))
+ fputs(genbuf, nfp);
+ fclose(fp);
+ fclose(nfp);
+ Rename(fnnew, fn);
+ }
+}
+
+static void friend_editdesc(char *uident, int type) {
+ FILE *fp, *nfp;
+ char fnnew[200], genbuf[200], fn[200];
+ setfriendfile(fn, type);
+ sprintf(fnnew, "%s-", fn);
+ if ((fp = fopen(fn, "r")) && (nfp = fopen(fnnew, "w")))
+ {
+ int length = strlen(uident);
+
+ while (fgets(genbuf, STRLEN, fp))
+ {
+ if ((genbuf[0] > ' ') && strncmp(genbuf, uident, length))
+ fputs(genbuf, nfp);
+ else if (!strncmp(genbuf, uident, length))
+ {
+ char buf[50] = "";
+ getdata(2, 0, "­×§ï´y­z¡G", buf, 40, DOECHO);
+ fprintf(nfp, "%-13s%s\n", uident, buf);
+ }
+ }
+ fclose(fp);
+ fclose(nfp);
+ Rename(fnnew, fn);
+ }
+}
+
+void friend_load() {
+ FILE *fp;
+ int myfriends[MAX_FRIEND];
+ int myrejects[MAX_REJECT];
+ int friendcount, rejectedcount;
+ char genbuf[200];
+
+ memset(myfriends, 0, sizeof(myfriends));
+ friendcount = 0;
+ setuserfile(genbuf, fn_overrides);
+ if ((fp = fopen(genbuf, "r")))
+ {
+ int unum;
+
+ while (fgets(genbuf, STRLEN, fp) && friendcount < MAX_FRIEND - 1)
+ if (strtok(genbuf, str_space))
+ if ((unum = searchuser(genbuf)))
+ myfriends[friendcount++] = unum;
+ fclose(fp);
+ }
+ memcpy(currutmp->friend, myfriends, sizeof(myfriends));
+
+ memset(myrejects, 0, sizeof(myrejects));
+ rejectedcount = 0;
+ setuserfile(genbuf, fn_reject);
+ if ((fp = fopen(genbuf, "r")))
+ {
+ int unum;
+
+ while (fgets(genbuf, STRLEN, fp) && rejectedcount < MAX_REJECT - 1)
+ if (strtok(genbuf, str_space))
+ if ((unum = searchuser(genbuf)))
+ myrejects[rejectedcount++] = unum;
+ fclose(fp);
+ }
+ memcpy(currutmp->reject, myrejects, sizeof(myrejects));
+ if(currutmp->friendtotal) logout_friend_online();
+ login_friend_online();
+}
+
+extern userec_t cuser;
+
+static void friend_water(char *message, int type) { /* ¸sÅé¤ô²y added by Ptt */
+ char fpath[80], line[80], userid[IDLEN + 1];
+ FILE *fp;
+
+ setfriendfile(fpath, type);
+ if ((fp = fopen(fpath, "r")))
+ while(fgets(line, 80, fp)) {
+ userinfo_t *uentp;
+ int tuid;
+
+ sscanf(line, "%s", userid);
+ if((tuid = searchuser(userid)) && tuid != usernum &&
+ (uentp = (userinfo_t *) search_ulist(tuid)) &&
+ isvisible_uid(tuid))
+ my_write(uentp->pid, message, uentp->userid, 1);
+ }
+ fclose(fp);
+}
+
+void friend_edit(int type) {
+ char fpath[80], line[80], uident[20];
+ int count, column, dirty;
+ FILE *fp;
+ char genbuf[200];
+
+ if (type == FRIEND_SPECIAL)
+ friend_special();
+ setfriendfile(fpath, type);
+
+ if (type == FRIEND_ALOHA || type == FRIEND_POST)
+ {
+ if (dashf(fpath))
+ {
+ sprintf(genbuf, "/bin/cp %s %s.old", fpath, fpath);
+ system(genbuf);
+ }
+ }
+
+ dirty = 0;
+ while (1)
+ {
+ stand_title(friend_list[type]);
+ move(0, 40);
+ sprintf(line, "(¦W³æ¤W­­:%d­Ó¤H)", friend_max[type]);
+ outs(line);
+ count = 0;
+ CreateNameList();
+
+ if ((fp = fopen(fpath, "r")))
+ {
+ move(3, 0);
+ column = 0;
+ while (fgets(genbuf, STRLEN, fp))
+ {
+ if (genbuf[0] <= ' ')
+ continue;
+ strtok(genbuf, str_space);
+ AddNameList(genbuf);
+ prints("%-13s", genbuf);
+ count++;
+ if (++column > 5)
+ {
+ column = 0;
+ outc('\n');
+ }
+ }
+ fclose(fp);
+ }
+ getdata(1, 0, (count ?
+ "(A)¼W¥[(D)§R°£(E)­×§ï(P)¤Þ¤J(L)¸Ô²Ó¦C¥X"
+ "(K)§R°£¾ã­Ó¦W³æ(W)¥á¤ô²y(Q)µ²§ô¡H[Q]" :
+ "(A)¼W¥[ (P)¤Þ¤J¨ä¥L¦W³æ (Q)µ²§ô¡H[Q]"),
+ uident, 3, LCECHO);
+ if (*uident == 'a')
+ {
+ move(1, 0);
+ usercomplete(msg_uid, uident);
+ if (uident[0] && searchuser(uident) && !InNameList(uident))
+ {
+ friend_add(uident, type);
+ dirty = 1;
+ }
+ }
+ else if (*uident == 'p')
+ {
+ friend_append(type, count);
+ dirty = 1;
+ }
+ else if (*uident == 'e' && count)
+ {
+ move(1, 0);
+ namecomplete(msg_uid, uident);
+ if (uident[0] && InNameList(uident))
+ {
+ friend_editdesc(uident, type);
+ }
+ }
+ else if (*uident == 'd' && count)
+ {
+ move(1, 0);
+ namecomplete(msg_uid, uident);
+ if (uident[0] && InNameList(uident))
+ {
+ friend_delete(uident, type);
+ dirty = 1;
+ }
+ }
+ else if (*uident == 'l' && count)
+ more(fpath, YEA);
+ else if (*uident == 'k' && count)
+ {
+ getdata(2, 0, "¾ã¥÷¦W³æ±N·|³Q§R°£,±z½T©w¶Ü (a/N)?", uident, 3,
+ LCECHO);
+ if (*uident == 'a')
+ unlink(fpath);
+ dirty = 1;
+ }
+ else if (*uident == 'w' && count)
+ {
+ if (!getdata(0, 0, "¸sÅé¤ô²y:", uident, 60, DOECHO))
+ continue;
+ if (getdata(0, 0, "½T©w¥á¥X¸sÅé¤ô²y? [Y]", line, 4, LCECHO) &&
+ *line == 'n')
+ continue;
+ friend_water(uident, type);
+ }
+ else
+ break;
+ }
+ if (dirty)
+ {
+ move(2, 0);
+ outs("§ó·s¸ê®Æ¤¤..½Ðµy­Ô.....");
+ refresh();
+ if (type == FRIEND_ALOHA || type == FRIEND_POST)
+ {
+ sprintf(genbuf, "%s.old", fpath);
+ if ((fp = fopen(genbuf, "r")))
+ {
+ while (fgets(line, 80, fp))
+ {
+ sscanf(line, "%s", uident);
+ sethomefile(genbuf, uident,
+ type == FRIEND_ALOHA ? "aloha" : "postnotify");
+ del_distinct(genbuf, cuser.userid);
+ }
+ fclose(fp);
+ }
+ sprintf(genbuf, "%s", fpath);
+ if ((fp = fopen(genbuf, "r")))
+ {
+ while (fgets(line, 80, fp))
+ {
+ sscanf(line, "%s", uident);
+ sethomefile(genbuf, uident,
+ type == FRIEND_ALOHA ? "aloha" : "postnotify");
+ add_distinct(genbuf, cuser.userid);
+ }
+ fclose(fp);
+ }
+ }
+ else if (type == FRIEND_SPECIAL)
+ {
+ genbuf[0] = 0;
+ setuserfile(line, special_des);
+ if ((fp = fopen(line, "r")))
+ {
+ fgets(genbuf, 30, fp);
+ fclose(fp);
+ }
+ getdata_buf(2, 0, " ½Ð¬°¦¹¯S§O¦W³æ¨ú¤@­Ó²µu¦WºÙ:", genbuf, 30,
+ DOECHO);
+ if ((fp = fopen(line, "w")))
+ {
+ fprintf(fp, "%s", genbuf);
+ fclose(fp);
+ }
+ }
+ friend_load();
+ }
+}
+
+int t_override() {
+ friend_edit(FRIEND_OVERRIDE);
+ return 0;
+}
+
+int t_reject() {
+ friend_edit(FRIEND_REJECT);
+ return 0;
+}
diff --git a/mbbsd/gamble.c b/mbbsd/gamble.c
new file mode 100644
index 00000000..23867450
--- /dev/null
+++ b/mbbsd/gamble.c
@@ -0,0 +1,361 @@
+/* $Id: gamble.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "modes.h"
+#include "proto.h"
+extern int usernum;
+
+#ifndef _BBS_UTIL_C_
+extern userec_t cuser;
+extern int b_lines;
+
+#define MAX_ITEM 8 //³Ì¤j ½ä¶µ(item) ­Ó¼Æ
+#define MAX_ITEM_LEN 30 //³Ì¤j ¨C¤@½ä¶µ¦W¦rªø«×
+#define MAX_SUBJECT_LEN 650 //8*81 = 648 ³Ì¤j ¥DÃDªø«×
+
+static char betname[MAX_ITEM][MAX_ITEM_LEN];
+static int currbid;
+
+int post_msg(char* bname, char* title, char *msg, char* author)
+{
+ FILE *fp;
+ int bid;
+ fileheader_t fhdr;
+ time_t now = time(0);
+ char genbuf[256];
+
+ /* ¦b bname ª©µoªí·s¤å³¹ */
+ sprintf(genbuf, "boards/%s", bname);
+ stampfile(genbuf, &fhdr);
+ fp = fopen(genbuf,"w");
+
+ if(!fp)
+ return -1;
+
+ fprintf(fp, "§@ªÌ: %s ¬ÝªO: %s\n¼ÐÃD: %s \n",author,bname,title);
+ fprintf(fp, "®É¶¡: %s\n", ctime(&now));
+
+ /* ¤å³¹ªº¤º®e */
+ fprintf(fp, "%s", msg);
+ fclose(fp);
+
+ /* ±NÀÉ®×¥[¤J¦Cªí */
+ strcpy(fhdr.title, title);
+ strcpy(fhdr.owner, author);
+ setbdir(genbuf,bname);
+ if(append_record(genbuf, &fhdr, sizeof(fhdr))!=-1)
+ if((bid = getbnum(bname)) > 0)
+ setbtotal(bid);
+ return 0;
+}
+
+int post_file(char* bname, char* title, char *filename, char* author)
+{
+ int size=dashs(filename);
+ char *msg;
+ FILE *fp;
+
+ if(size<=0) return -1;
+ if(!(fp=fopen(filename,"r")) ) return -1;
+ msg= (char *)malloc(size);
+ fread(msg,1,size,fp);
+ size= post_msg(bname, title, msg, author);
+ fclose(fp);
+ free(msg);
+ return size;
+}
+
+
+static int load_ticket_record(char *direct, int ticket[])
+{
+ char buf[256];
+ int i, total=0;
+ FILE *fp;
+ sprintf(buf,"%s/"FN_TICKET_RECORD,direct);
+ if(!(fp=fopen(buf,"r"))) return 0;
+ for(i=0;i<MAX_ITEM && fscanf(fp, "%9d ",&ticket[i]); i++)
+ total=total+ticket[i];
+ fclose(fp);
+ return total;
+}
+
+static int show_ticket_data(char *direct, int *price, boardheader_t *bh) {
+ int i,count, total = 0, end=0,
+ ticket[MAX_ITEM] = {0, 0, 0, 0, 0, 0, 0, 0};
+ FILE *fp;
+ char genbuf[256];
+
+ clear();
+ if (bh)
+ {
+ sprintf(genbuf,"%s ½ä½L", bh->brdname);
+ showtitle(genbuf, BBSNAME);
+ }
+ else
+ showtitle("Ptt½ä½L", BBSNAME);
+ move(2, 0);
+ sprintf(genbuf, "%s/"FN_TICKET_ITEMS, direct);
+ if(!(fp = fopen(genbuf,"r")))
+ {
+ prints("\n¥Ø«e¨Ã¨S¦³Á|¿ì½ä½L\n");
+ sprintf(genbuf, "%s/"FN_TICKET_OUTCOME, direct);
+ if(more(genbuf, NA));
+ return 0;
+ }
+ fgets(genbuf,MAX_ITEM_LEN,fp);
+ *price=atoi(genbuf);
+ for(count=0; fgets(betname[count],MAX_ITEM_LEN,fp)&&count<MAX_ITEM; count++)
+ strtok(betname[count],"\r\n");
+ fclose(fp);
+
+ prints("\033[32m¯¸³W:\033[m 1.¥iÁʶR¥H¤U¤£¦PÃþ«¬ªº±m²¼¡C¨C±i­nªá \033[32m%d\033[m ¤¸¡C\n"
+ " 2.%s\n"
+ " 3.¶}¼ú®É¥u¦³¤@ºØ±m²¼¤¤¼ú, ¦³ÁʶR¸Ó±m²¼ªÌ, «h¥i¨ÌÁʶRªº±i¼Æ§¡¤À"
+ "Á`½äª÷¡C\n"
+ " 4.¨Cµ§¼úª÷¥Ñ¨t²Î©â¨ú 5% ¤§µ|ª÷%s¡C\n\n"
+ "\033[32m%s:\033[m", *price,
+ bh?"¦¹½ä½L¥Ñª©¥D­t³dÁ|¿ì¨Ã¥B¨M©w¶}¼ú®É¶¡µ²ªG, ¯¸ªø¤£ºÞ, Ä@½äªA¿é¡C":
+ "¨t²Î¨C¤Ñ 2:00 11:00 16:00 21:00 ¶}¼ú¡C",
+ bh?", ¨ä¤¤ 2% ¤Àµ¹¶}¼úª©¥D":"",
+ bh?"ª©¥D¦Û­q³W«h¤Î»¡©ú":"«e´X¦¸¶}¼úµ²ªG");
+
+
+ sprintf(genbuf, "%s/"FN_TICKET, direct);
+ if(!dashf(genbuf))
+ {
+ sprintf(genbuf, "%s/"FN_TICKET_END, direct);
+ end=1;
+ }
+ show_file(genbuf, 8, -1, NO_RELOAD);
+ move(15,0);
+ prints("\033[1;32m¥Ø«e¤Uª`ª¬ªp:\033[m\n");
+
+ total=load_ticket_record(direct, ticket);
+
+ prints("\033[33m");
+ for(i = 0 ; i<count; i++)
+ {
+ prints("%d.%-8s: %-7d", i+1, betname[i], ticket[i]);
+ if(i==3) prints("\n");
+ }
+ prints("\033[m\n\033[42m ¤Uª`Á`ª÷ÃB:\033[31m %d ¤¸ \033[m",total*(*price));
+ if(end)
+ {
+ prints("\n½ä½L¤w¸g°±¤î¤Uª`\n");
+ return -count;
+ }
+ return count;
+}
+
+static void append_ticket_record(char *direct, int ch, int n, int count) {
+ FILE *fp;
+ int ticket[8] = {0,0,0,0,0,0,0,0}, i;
+ char genbuf[256];
+ sprintf(genbuf, "%s/"FN_TICKET_USER, direct);
+
+ if((fp = fopen(genbuf,"a"))) {
+ fprintf(fp, "%s %d %d\n", cuser.userid, ch, n);
+ fclose(fp);
+ }
+ load_ticket_record(direct, ticket);
+ ticket[ch] += n;
+ sprintf(genbuf, "%s/" FN_TICKET_RECORD, direct);
+ if((fp = fopen(genbuf,"w"))) {
+ for(i=0; i<count; i++)
+ fprintf(fp,"%d ", ticket[i]);
+ fclose(fp);
+ }
+}
+
+#define lockreturn0(unmode, state) if(lockutmpmode(unmode, state)) return 0
+int ticket(int bid)
+{
+ int ch, n, price, count, end=0;
+ char path[128],fn_ticket[128];
+ boardheader_t *bh=NULL;
+
+ if(bid)
+ {
+ bh=getbcache(bid);
+ setbpath(path, bh->brdname);
+ setbfile(fn_ticket, bh->brdname, FN_TICKET);
+ currbid = bid;
+ }
+ else
+ strcpy(path,"etc/");
+
+ lockreturn0(TICKET, LOCK_MULTI);
+ while(1) {
+ count=show_ticket_data(path, &price, bh);
+ if(count<=0)
+ {
+ pressanykey();
+ break;
+ }
+ move(20, 0);
+ reload_money();
+ prints("\033[44m¿ú: %-10d \033[m\n\033[1m½Ð¿ï¾Ü­nÁʶRªººØÃþ(1~%d)"
+ "[Q:Â÷¶}]\033[m:", cuser.money,count);
+ ch = igetch();
+ /*--
+ Tim011127
+ ¬°¤F±±¨îCS°ÝÃD ¦ý¬O³oÃäÁÙ¤£¯à§¹¥þ¸Ñ¨M³o°ÝÃD,
+ ­Yuser³q¹LÀˬd¤U¥h, ­è¦nª©¥D¶}¼ú, ÁÙ¬O·|³y¦¨userªº³o¦¸¬ö¿ý
+ «Ü¦³¥i¯à¶]¨ì¤U¦¸½ä½Lªº¬ö¿ý¥h, ¤]«Ü¦³¥i¯à³Qª©¥D·s¶}½ä½L®É¬~±¼
+ ¤£¹L³oÃä¦Ü¤Ö¥i¥H°µ¨ìªº¬O, ³»¦h¥u·|¦³¤@µ§¸ê®Æ¬O¿ùªº
+ --*/
+ if(bid && !dashf(fn_ticket))
+ {
+ move(b_lines-1,0);
+ prints("«z!! ­@£«®º...ª©¥D¤w¸g°±¤î¤Uª`¤F ¤£¯à½äÂP");
+ pressanykey();
+ break;
+ }
+
+ if(ch=='q' || ch == 'Q')
+ break;
+ ch-='1';
+ if(end || ch >= count || ch < 0)
+ continue;
+ n=0;
+ ch_buyitem(price, "etc/buyticket", &n);
+ if(n > 0)
+ append_ticket_record(path,ch,n,count);
+ }
+ unlockutmpmode();
+ return 0;
+}
+
+int openticket(int bid) {
+ char path[128],buf[256],outcome[128];
+ int i, money=0, count, bet, price, total = 0, ticket[8]={0,0,0,0,0,0,0,0};
+ boardheader_t *bh=getbcache(bid);
+ time_t now = time(NULL);
+ FILE *fp, *fp1;
+
+ setbpath(path, bh->brdname);
+ count=-show_ticket_data(path, &price, bh);
+ if(count==0)
+ {
+ setbfile(buf,bh->brdname,FN_TICKET_END);
+ unlink(buf); //Ptt: ¦³bug
+ return 0;
+ }
+ lockreturn0(TICKET, LOCK_MULTI);
+ do
+ {
+ do
+ {
+ getdata(20, 0, "\033[1m¿ï¾Ü¤¤¼úªº¸¹½X(0:¨ú®ø)\033[m:", buf, 3, LCECHO);
+ bet=atoi(buf);
+ move(0,0);
+ clrtoeol();
+ } while(bet<0 || bet>count);
+ if(bet==0)
+ {unlockutmpmode(); return 0;}
+ getdata(21, 0, "\033[1m¦A¦¸½T»{¤¤¼úªº¸¹½X\033[m:", buf, 3, LCECHO);
+ }while(bet!=atoi(buf));
+
+ bet -= 1; //Âন¯x°}ªºindex
+
+ total=load_ticket_record(path, ticket);
+ setbfile(buf,bh->brdname,FN_TICKET_END);
+ if(!(fp1 = fopen(buf,"r")))
+ {
+ unlockutmpmode();
+ return 0;
+ }
+ // ÁÙ¨S¶}§¹¼ú¤£¯à½ä³Õ ¥u­nmv¤@¶µ´N¦n
+ money=total*price;
+ demoney(money*0.02);
+ mail_redenvelop("[½ä³õ©âÀY]", cuser.userid, money*0.02, 'n');
+ money = ticket[bet] ? money*0.95/ticket[bet]:9999999;
+ setbfile(outcome,bh->brdname,FN_TICKET_OUTCOME);
+ if((fp = fopen(outcome, "w")))
+ {
+ fprintf(fp,"½ä½L»¡©ú\n");
+ while(fgets(buf,256,fp1))
+ {
+ buf[255]=0;
+ fprintf(fp,"%s",buf);
+ }
+ fprintf(fp,"¤Uª`±¡ªp\n");
+
+ fprintf(fp, "\033[33m");
+ for(i = 0 ; i<count; i++)
+ {
+ fprintf(fp, "%d.%-8s: %-7d",i+1,betname[i], ticket[i]);
+ if(i==3) fprintf(fp,"\n");
+ }
+ fprintf(fp, "\033[m\n");
+
+ fprintf(fp, "\n\n¶}¼ú®É¶¡¡G %s \n\n"
+ "¶}¼úµ²ªG¡G %s \n\n"
+ "©Ò¦³ª÷ÃB¡G %d ¤¸ \n"
+ "¤¤¼ú¤ñ¨Ò¡G %d±i/%d±i (%f)\n"
+ "¨C±i¤¤¼ú±m²¼¥i±o %d ªT¢Þ¹ô \n\n",
+ Cdatelite(&now), betname[bet], total*price, ticket[bet], total,
+ (float) ticket[bet] / total, money);
+
+ fprintf(fp, "%s ½ä½L¶}¥X:%s ©Ò¦³ª÷ÃB:%d ¤¸ ¼úª÷/±i:%d ¤¸ ¾÷²v:%1.2f\n",
+ Cdatelite(&now), betname[bet], total*price, money,
+ total? (float)ticket[bet] / total:0);
+
+ fclose(fp);
+ }
+ fclose(fp1);
+
+ setbfile(buf, bh->brdname, FN_TICKET_END);
+ unlink(buf);
+/*
+ if(fork())
+ {
+ more(outcome,YEA);
+ unlockutmpmode();
+ return 0;
+ }
+*/
+ sprintf(buf, "[¤½§i] %s ½ä½L¶}¼ú", bh->brdname);
+ post_file(bh->brdname, buf, outcome, "[½ä¯«]");
+ post_file("Record", buf+7, outcome, "[°¨¸ô±´¤l]");
+ /*
+ ¥H¤U¬Oµ¹¿ú°Ê§@
+ */
+ setbfile(buf, bh->brdname, FN_TICKET_USER);
+ if (ticket[bet] && (fp = fopen(buf, "r")))
+ {
+ int mybet, uid;
+ char userid[IDLEN];
+
+ while (fscanf(fp, "%s %d %d\n", userid, &mybet, &i) != EOF)
+ {
+ if (mybet == bet)
+ {
+ printf("®¥³ß %-15s¶R¤F%9d ±i %s, Àò±o %d ªT¢Þ¹ô\n"
+ ,userid, i, betname[mybet], money * i);
+ if((uid=getuser(userid))==0) continue;
+ deumoney(uid, money * i);
+ sprintf(buf, "%s ¤¤¼ú«¨! $ %d", bh->brdname, money * i);
+ mail_id(userid, buf, outcome, "Ptt½ä³õ");
+ }
+ }
+ }
+ setbfile(buf, bh->brdname, FN_TICKET_RECORD);
+ unlink(buf);
+ setbfile(buf, bh->brdname, FN_TICKET_USER);
+ unlink(buf);
+ return 0;
+}
+
+int ticket_main() {
+ ticket(0);
+ return 0;
+}
+#endif
diff --git a/mbbsd/gomo.c b/mbbsd/gomo.c
new file mode 100644
index 00000000..06062ce4
--- /dev/null
+++ b/mbbsd/gomo.c
@@ -0,0 +1,417 @@
+/* $Id: gomo.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <string.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "gomo.h"
+#include "common.h"
+#include "modes.h"
+#include "proto.h"
+
+extern int usernum;
+extern userinfo_t *currutmp;
+
+char ku[BRDSIZ][BRDSIZ];
+static char *chess[] = { "¡´", "¡³" };
+static int tick, lastcount, mylasttick, hislasttick;
+
+unsigned char *pat, *adv;
+
+typedef struct {
+ char x;
+ char y;
+} Horder_t;
+
+static Horder_t *v, pool[225];
+
+static void HO_init() {
+ memset(pool, 0, sizeof(pool));
+ v = pool;
+ pat = pat_gomoku;
+ adv = adv_gomoku;
+ memset(ku, 0, sizeof(ku));
+}
+
+static void HO_add(Horder_t *mv) {
+ *v++ = *mv;
+}
+
+static void HO_undo(Horder_t *mv) {
+ char *str = "¢z¢s¢{¢u¢q¢t¢|¢r¢}";
+ int n1, n2, loc;
+
+ *mv = *(--v);
+ ku[(int)mv->x][(int)mv->y] = BBLANK;
+ BGOTO(mv->x, mv->y);
+ n1 = (mv->x == 0) ? 0 : (mv->x == 14) ? 2 : 1;
+ n2 = (mv->y == 14)? 0 : (mv->y == 0) ? 2 : 1;
+ loc= 2 * ( n2 * 3 + n1);
+ prints("%.2s", str + loc);
+}
+
+extern userec_t cuser;
+
+static void HO_log(char *user) {
+ int i;
+ FILE *log;
+ char buf[80];
+ char buf1[80];
+ char title[80];
+ Horder_t *ptr = pool;
+ extern screenline_t *big_picture;
+ fileheader_t mymail;
+
+ sprintf(buf, "home/%c/%s/F.%d", cuser.userid[0], cuser.userid,
+ rand() & 65535);
+ log = fopen(buf, "w");
+
+ for(i = 1; i < 17; i++)
+ fprintf(log, "%.*s\n", big_picture[i].len, big_picture[i].data);
+
+ i = 0;
+ do {
+ fprintf(log, "[%2d]%s ==> %c%d%c", i + 1, chess[i % 2],
+ 'A' + ptr->x, ptr->y + 1, (i % 2) ? '\n' : '\t');
+ i++;
+ } while( ++ptr < v);
+ fclose(log);
+
+ sethomepath(buf1, cuser.userid);
+ stampfile(buf1, &mymail);
+
+ mymail.savemode = 'H'; /* hold-mail flag */
+ mymail.filemode = FILE_READ;
+ strcpy(mymail.owner, "[³Æ.§Ñ.¿ý]");
+ sprintf(mymail.title, "\033[37;41m´ÑÃÐ\033[m %s VS %s",
+ cuser.userid, user);
+ sethomedir(title, cuser.userid);
+ Rename(buf, buf1);
+ append_record(title, &mymail, sizeof(mymail));
+
+ unlink(buf);
+}
+
+static int countgomo() {
+ Horder_t *ptr;
+ int i;
+
+ ptr = pool;
+ i = 0;
+ do {
+ i++;
+ } while(++ptr < v);
+ return i;
+}
+
+static int chkmv(Horder_t *mv, int color, int limit) {
+ char *xtype[] = {"\033[1;31m¸õ¤T\033[m", "\033[1;31m¬¡¤T\033[m",
+ "\033[1;31m¦º¥|\033[m", "\033[1;31m¸õ¥|\033[m",
+ "\033[1;31m¬¡¥|\033[m", "\033[1;31m¥|¤T\033[m",
+ "\033[1;31mÂù¤T\033[m", "\033[1;31mÂù¥|\033[m",
+ "\033[1;31mÂù¥|\033[m", "\033[1;31m³s¤»\033[m",
+ "\033[1;31m³s¤­\033[m"};
+ int rule = getstyle(mv->x, mv->y, color, limit);
+ if(rule > 1 && rule < 13) {
+ move(15, 40);
+ outs(xtype[rule - 2]);
+ bell();
+ }
+ return chkwin(rule, limit);
+}
+
+static int gomo_key(int fd, int ch, Horder_t *mv) {
+ if( ch >= 'a' && ch <= 'o') {
+ char pbuf[4], vx, vy;
+
+ *pbuf = ch;
+ if(fd)
+ add_io(0, 0);
+ oldgetdata(17, 0, "ª½±µ«ü©w¦ì¸m :", pbuf, 4, DOECHO);
+ if(fd)
+ add_io(fd, 0);
+ vx = pbuf[0] - 'a';
+ vy = atoi(pbuf + 1) - 1;
+ if(vx >= 0 && vx < 15 && vy >= 0 && vy < 15 &&
+ ku[(int)vx][(int)vy] == BBLANK) {
+ mv->x = vx;
+ mv->y = vy;
+ return 1;
+ }
+ } else {
+ switch(ch) {
+ case KEY_RIGHT:
+ mv->x = (mv->x == BRDSIZ - 1) ? mv->x : mv->x + 1;
+ break;
+ case KEY_LEFT:
+ mv->x = (mv->x == 0 ) ? 0 : mv->x - 1;
+ break;
+ case KEY_UP:
+ mv->y = (mv->y == BRDSIZ - 1) ? mv->y : mv->y + 1;
+ break;
+ case KEY_DOWN:
+ mv->y = (mv->y == 0 ) ? 0 : mv->y - 1;
+ break;
+ case ' ':
+ case '\r':
+ if(ku[(int)mv->x][(int)mv->y] == BBLANK)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+extern userec_t xuser;
+
+static int reload_gomo() {
+ passwd_query(usernum, &xuser);
+ cuser.five_win = xuser.five_win;
+ cuser.five_lose = xuser.five_lose;
+ cuser.five_tie = xuser.five_tie;
+ return 0;
+}
+
+int gomoku(int fd) {
+ Horder_t mv;
+ int me, he, win, ch;
+ int hewantpass, iwantpass;
+ userinfo_t *my = currutmp;
+
+ HO_init();
+ me = !(my->turn) + 1;
+ he = my->turn + 1;
+ win = 1;
+ tick=time(0) + MAX_TIME;
+ lastcount = MAX_TIME;
+ setutmpmode(M_FIVE);
+ clear();
+
+ prints("\033[1;46m ¤­¤l´Ñ¹ï¾Ô \033[45m%30s VS %-30s\033[m",
+ cuser.userid, my->mateid);
+ show_file("etc/@five", 1, -1, ONLY_COLOR);
+ move(11, 40);
+ prints("§Ú¬O %s", me == BBLACK ? "¥ý¤â ¡´, ¦³¸T¤â" : "«á¤â ¡³");
+ move(16, 40);
+ prints("\033[1;33m%s", cuser.userid);
+ move(17, 40);
+ prints("\033[1;33m%s", my->mateid);
+
+ reload_gomo();
+ move(16, 60);
+ prints("\033[1;31m%d\033[37m³Ó \033[34m%d\033[37m±Ñ \033[36m%d\033[37m©M"
+ "\033[m", cuser.five_win, cuser.five_lose, cuser.five_tie);
+
+ getuser(my->mateid);
+ move(17, 60);
+ prints("\033[1;31m%d\033[37m³Ó \033[34m%d\033[37m±Ñ \033[36m%d\033[37m"
+ "©M\033[m", xuser.five_win, xuser.five_lose, xuser.five_tie);
+
+ cuser.five_lose++;
+ /* ¤@¶i¨Ó¥ý¥[¤@³õ±Ñ³õ, ŤF«á¦A¦©¦^¥h, ÁקK§Ö¿é¤F´c·NÂ_½u */
+ passwd_update(usernum, &cuser);
+
+ add_io(fd, 0);
+
+ hewantpass = iwantpass = 0;
+ mv.x = mv.y = 7;
+ move(18, 40);
+ prints("%s®É¶¡ÁÙ³Ñ%d:%02d\n", my->turn ? "§Aªº" : "¹ï¤è",
+ MAX_TIME / 60, MAX_TIME % 60);
+ for(;;) {
+ move(13, 40);
+ outs(my->turn ? "½ü¨ì¦Û¤v¤U¤F!": "µ¥«Ý¹ï¤è¤U¤l..");
+ if(lastcount != tick-time(0)) {
+ lastcount = tick-time(0);
+ move(18, 40);
+ prints("%s®É¶¡ÁÙ³Ñ%d:%02d\n", my->turn ? "§Aªº" : "¹ï¤è",
+ lastcount / 60, lastcount % 60);
+ if(lastcount <= 0 && my->turn) {
+ move(19, 40);
+ outs("®É¶¡¤w¨ì, §A¿é¤F");
+ my->five_lose++;
+ send(fd, '\0', 1, 0);
+ break;
+ }
+ if(lastcount <= -5 && !my->turn) {
+ move(19, 40);
+ outs("¹ï¤â¤Ó¤[¨S¤U, §AŤF!");
+ win = 1;
+ cuser.five_lose--;
+ cuser.five_win++;
+ my->five_win++;
+ passwd_update(usernum, &cuser);
+ mv.x = mv.y = -2;
+ send(fd, &mv, sizeof(Horder_t), 0);
+ mv = *(v - 1);
+ break;
+ }
+ }
+ move(14, 40);
+ if(hewantpass) {
+ outs("\033[1;32m©M´Ñ­n¨D!\033[m");
+ bell();
+ } else
+ clrtoeol();
+ BGOTOCUR(mv.x, mv.y);
+ ch = igetkey();
+ if(ch != I_OTHERDATA)
+ iwantpass = 0;
+ if(ch == 'q') {
+ if(countgomo() < 10) {
+ cuser.five_lose--;
+ passwd_update(usernum, &cuser);
+ }
+ send(fd, '\0', 1, 0);
+ break;
+ } else if(ch == 'u' && !my->turn && v > pool) {
+ mv.x = mv.y = -1;
+ ch = send(fd, &mv, sizeof(Horder_t), 0);
+ if(ch == sizeof(Horder_t)) {
+ HO_undo(&mv);
+ tick = mylasttick;
+ my->turn = 1;
+ continue;
+ } else
+ break;
+ }
+ if(ch == 'p') {
+ if(my->turn ) {
+ if(iwantpass == 0) {
+ iwantpass = 1;
+ mv.x = mv.y = -2;
+ send(fd, &mv, sizeof(Horder_t), 0);
+ mv = *(v - 1);
+ }
+ continue;
+ } else if(hewantpass) {
+ win = 0;
+ cuser.five_lose--;
+ cuser.five_tie++;
+ my->five_tie++;
+ passwd_update(usernum, &cuser);
+ mv.x=mv.y=-2;
+ send(fd, &mv, sizeof(Horder_t), 0);
+ mv = *(v - 1);
+ break;
+ }
+ }
+
+ if(ch == I_OTHERDATA) {
+ ch = recv(fd, &mv, sizeof(Horder_t), 0);
+ if(ch != sizeof(Horder_t)) {
+ lastcount=tick-time(0);
+ if(lastcount >=0) {
+ win = 1;
+ cuser.five_lose--;
+ if(countgomo() >=10) {
+ cuser.five_win++;
+ my->five_win++;
+ }
+ passwd_update(usernum, &cuser);
+ outmsg("¹ï¤è»{¿é¤F!!");
+ break;
+ } else {
+ win = 0;
+ outmsg("§A¶W¹L®É¶¡¥¼¤U¤l, ¿é¤F!");
+ my->five_lose++;
+ break;
+ }
+ } else if(mv.x == -2 && mv.y == -2) {
+ if(iwantpass == 1) {
+ win = 0;
+ cuser.five_lose--;
+ cuser.five_tie++;
+ my->five_tie++;
+ passwd_update(usernum, &cuser);
+ break;
+ } else {
+ hewantpass = 1;
+ mv = *(v - 1);
+ continue;
+ }
+ }
+ if(my->turn && mv.x == -1 && mv.y == -1) {
+ outmsg("¹ï¤è®¬´Ñ");
+ tick = hislasttick;
+ HO_undo(&mv);
+ my->turn = 0;
+ continue;
+ }
+
+ if(!my->turn) {
+ win = chkmv(&mv, he, he == BBLACK);
+ HO_add(&mv);
+ hislasttick = tick;
+ tick = time(0) + MAX_TIME;
+ ku[(int)mv.x][(int)mv.y] = he;
+ bell();
+ BGOTO(mv.x, mv.y);
+ outs(chess[he - 1]);
+
+ if(win) {
+ outmsg(win == 1 ? "¹ï¤èŤF!" : "¹ï¤è¸T¤â");
+ if(win != 1) {
+ cuser.five_lose--;
+ cuser.five_win++;
+ my->five_win++;
+ passwd_update(usernum, &cuser);
+ } else
+ my->five_lose++;
+ win = -win;
+ break;
+ }
+ my->turn = 1;
+ }
+ continue;
+ }
+
+ if(my->turn) {
+ if(gomo_key(fd, ch, &mv))
+ my->turn = 0;
+ else
+ continue;
+
+ if(!my->turn) {
+ HO_add(&mv);
+ BGOTO(mv.x, mv.y);
+ outs(chess[me - 1]);
+ win = chkmv( &mv, me, me == BBLACK);
+ ku[(int)mv.x][(int)mv.y] = me;
+ mylasttick = tick;
+ tick = time(0) + MAX_TIME; /*­Ë¼Æ*/
+ lastcount = MAX_TIME;
+ if(send(fd, &mv, sizeof(Horder_t), 0) != sizeof(Horder_t))
+ break;
+ if(win) {
+ outmsg(win == 1 ? "§ÚĹÅo~~" : "¸T¤â¿é¤F" );
+ if(win == 1) {
+ cuser.five_lose--;
+ cuser.five_win++;
+ my->five_win++;
+ passwd_update(usernum, &cuser);
+ } else
+ my->five_lose++;
+ break;
+ }
+ move(15, 40);
+ clrtoeol();
+ }
+ }
+ }
+ add_io(0, 0);
+ close(fd);
+
+ igetch();
+ if(v > pool) {
+ char ans[4];
+
+ getdata(19 , 0, "­n«O¯d¥»§½¦¨´ÑÃжÜ?(y/N)", ans, 4, LCECHO);
+ if(*ans == 'y')
+ HO_log(my->mateid);
+ }
+ return 0;
+}
diff --git a/mbbsd/gomo1.c b/mbbsd/gomo1.c
new file mode 100644
index 00000000..953bad2d
--- /dev/null
+++ b/mbbsd/gomo1.c
@@ -0,0 +1,136 @@
+/* $Id: gomo1.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "proto.h"
+
+#define QCAST int (*)(const void *, const void *)
+
+#define BBLANK (0) /* ªÅ¥Õ */
+#define BBLACK (1) /* ¶Â¤l, ¥ý¤â */
+#define BWHITE (2) /* ¥Õ¤l, «á¤â */
+#ifndef BRDSIZ
+#define BRDSIZ (15) /* ´Ñ½L³æÃä¤j¤p */
+#endif
+
+extern char ku[BRDSIZ][BRDSIZ];
+
+/* pattern and advance map */
+extern unsigned char *pat, *adv;
+
+static int intrevcmp(const void *a, const void *b) {
+ return (*(int *)b - *(int *)a);
+}
+
+/* x,y: 0..BRDSIZ-1 ; color: CBLACK,CWHITE ; dx,dy: -1,0,+1 */
+static int gomo_getindex(int x, int y, int color, int dx, int dy) {
+ int i, k, n;
+ for(n = -1, i = 0, k = 1; i < 5; i++, k <<= 1) {
+ x += dx;
+ y += dy;
+
+ if((x < 0) || (x >= BRDSIZ) || ( y < 0) || ( y >= BRDSIZ)) {
+ n += k;
+ break;
+ } else if(ku[x][y] != BBLANK) {
+ n += k;
+ if(ku[x][y] != color)
+ break;
+ }
+ }
+
+ if(i >= 5)
+ n += k;
+
+ return n;
+}
+
+int chkwin(int style, int limit) {
+ if(style == 0x0c)
+ return 1 /* style */;
+ else if(limit == 0) {
+ if(style == 0x0b)
+ return 1 /* style */;
+ return 0;
+ }
+ if((style < 0x0c) && (style > 0x07))
+ return -1 /* -style */;
+ return 0;
+}
+
+/* x,y: 0..BRDSIZ-1 ; color: CBLACK,CWHITE ; limit:1,0 ; dx,dy: 0,1 */
+static int dirchk(int x, int y, int color, int limit, int dx, int dy) {
+ int le, ri, loc, style;
+
+ le = gomo_getindex(x, y, color, -dx, -dy);
+ ri = gomo_getindex(x, y, color, dx, dy);
+
+ loc = (le > ri) ? (((le * (le + 1)) >> 1) + ri) :
+ (((ri * (ri + 1)) >> 1) + le);
+
+ style = pat[loc];
+
+ if(limit == 0)
+ return (style & 0x0f);
+
+ style >>= 4;
+
+ if((style == 3) || (style == 2)) {
+ int i, n, tmp, nx, ny;
+
+ n = adv[loc >> 1];
+
+ ((loc & 1) == 0) ? (n >>= 4) : (n &= 0x0f);
+
+ ku[x][y] = color;
+
+ for(i = 0; i < 2; i++) {
+ if((tmp = (i == 0) ? (-(n >> 2)):(n & 3)) != 0) {
+ nx = x + (le > ri ? 1 : -1) * tmp * dx;
+ ny = y + (le > ri ? 1 : -1) * tmp * dy;
+
+ if((dirchk(nx, ny, color, 0, dx, dy) == 0x06) &&
+ (chkwin(getstyle(nx, ny, color, limit), limit) >= 0))
+ break;
+ }
+ }
+ if(i >= 2)
+ style = 0;
+ ku[x][y] = BBLANK;
+ }
+ return style;
+}
+
+/* ¨Ò¥~=F ¿ù»~=E ¦³¤l=D ³s¤­=C ³s¤»=B Âù¥|=A ¥|¥|=9 ¤T¤T=8 */
+/* ¥|¤T=7 ¬¡¥|=6 Â_¥|=5 ¦º¥|=4 ¬¡¤T=3 Â_¤T=2 «O¯d=1 µL®Ä=0 */
+
+/* x,y: 0..BRDSIZ-1 ; color: CBLACK,CWHITE ; limit: 1,0 */
+int getstyle(int x, int y, int color, int limit) {
+ int i, j, dir[4], style;
+
+ if((x < 0) || (x >= BRDSIZ) || ( y < 0) || (y >= BRDSIZ))
+ return 0x0f;
+ if(ku[x][y] != BBLANK)
+ return 0x0d;
+
+ for(i = 0; i < 4; i++)
+ dir[i] = dirchk(x, y, color, limit, i ? (i>>1) : -1, i ? (i&1) : 1);
+
+ qsort(dir, 4, sizeof(int), (QCAST)intrevcmp);
+
+ if((style = dir[0]) >= 2) {
+ for(i = 1, j = 6 + (limit ? 1 : 0); i < 4; i++) {
+ if((style > j) || (dir[i] < 2))
+ break;
+ if(dir[i] > 3)
+ style = 9;
+ else if((style < 7) && (style > 3))
+ style = 7;
+ else
+ style = 8;
+ }
+ }
+ return style;
+}
diff --git a/mbbsd/guess.c b/mbbsd/guess.c
new file mode 100644
index 00000000..27a337f7
--- /dev/null
+++ b/mbbsd/guess.c
@@ -0,0 +1,364 @@
+/* $Id: guess.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "modes.h"
+#include "proto.h"
+
+extern char *BBSName;
+extern int usernum;
+#define LOGPASS BBSHOME "/etc/winguess.log"
+
+static void show_table(char TABLE[], char ifcomputer) {
+ int i;
+
+ move(0, 35);
+ prints("\033[1;44;33m ¡i ²q¼Æ¦r ¡j \033[m");
+ move(8, 1);
+ prints("\033[1;44;36m¥Ø «e ­¿ ²v\033[m\n");
+ prints("\033[1;33m=================\033[m\n");
+ if(ifcomputer) {
+ prints("Ĺ¹q¸£: 2 ­¿\n");
+ prints("¿é¹q¸£: 0 ­¿\n");
+ } else {
+ for(i = 1; i <= 6; i++)
+ prints("²Ä%d¦¸, %02d­¿\n",i,TABLE[i]);
+ }
+ prints("\033[33m=================\033[m");
+}
+
+extern userec_t cuser;
+
+static unsigned long int get_money(void) {
+ int money, i;
+ char data[20];
+
+ move(1, 0);
+ prints("±z¥Ø«e¦³:%d Ptt$", cuser.money);
+ do {
+ getdata(2, 0, "­n½ä¦h¤Ö(5-10©Î«öqÂ÷¶}): ", data, 9, LCECHO);
+ money = strlen(data);
+ if(data[0] == 'q' || data[0] == 'Q') {
+ unlockutmpmode();
+ return 0;
+ }
+ for(i = 0; i < money; i++)
+ if(data[i]<'0' || data[i]>'9') {
+ money = -1;
+ break;
+ }
+ if(money != -1){
+ money = atol(data);
+ reload_money();
+ if(money > cuser.money || money <= 4 || money > 10 ||
+ money < 1)
+ money = -1;
+ }
+ } while(money == -1);
+ move(1,0);
+ clrtoeol();
+ reload_money();
+ prints("±z¥Ø«e¦³:%d Ptt$", cuser.money - money);
+ return money;
+}
+
+static int check_data(char *str) {
+ int i, j;
+
+ if(strlen(str) != 4)
+ return -1;
+ for(i = 0; i < 4; i++)
+ if(str[i] < '0' || str[i] > '9')
+ return -1;
+ for(i = 0; i < 4; i++)
+ for(j = i + 1; j < 4; j++)
+ if(str[i] == str[j])
+ return -1;
+ return 1;
+}
+
+static char *get_data(int count) {
+ static char data[5];
+ while(1) {
+ getdata(6, 0, "¿é¤J¥|¦ì¼Æ¦r(¤£­«½Æ): ", data, 5, LCECHO);
+ if(check_data(data) == 1)
+ break;
+ }
+ return data;
+}
+
+static int guess_play(char *data, char *answer, int count) {
+ int A_num = 0, B_num = 0;
+ int i, j;
+
+ for(i = 0; i < 4; i++) {
+ if(data[i] == answer[i])
+ A_num++;
+ for(j = 0; j < 4; j++)
+ if(i == j)
+ continue;
+ else if(data[i] == answer[j]) {
+ B_num++;
+ break;
+ }
+ }
+ if(A_num == 4)
+ return 1;
+ move(count + 8,55);
+ prints("%s => \033[1;32m%dA %dB\033[m", data, A_num, B_num);
+ return 0;
+}
+
+static int result(int correct, int number) {
+ char a = 0, b = 0, i, j;
+ char n1[5], n2[5];
+
+ sprintf(n1, "%04d",correct);
+ sprintf(n2, "%04d",number);
+ for(i = 0; i < 4; i++)
+ for(j = 0; j < 4; j++)
+ if(n1[(int)i] == n2[(int)j])
+ b++;
+ for(i = 0; i < 4; i++)
+ if(n1[(int)i] == n2[(int)i]) {
+ b--;
+ a++;
+ }
+ return 10 * a + b;
+}
+
+static int legal(int number) {
+ char i, j;
+ char temp[5];
+
+ sprintf(temp, "%04d", number);
+ for(i = 0; i < 4; i++)
+ for(j = i + 1; j < 4; j++)
+ if(temp[(int)i] == temp[(int)j])
+ return 0;
+ return 1;
+}
+
+static void initcomputer(char flag[]) {
+ int i;
+
+ for(i = 0; i < 10000; i++)
+ if(legal(i))
+ flag[i] = 1;
+ else
+ flag[i] = 0;
+}
+
+static int computer(int correct, int total, char flag[], int n[]) {
+ int guess;
+ static int j;
+ int k,i;
+ char data[5];
+
+ if(total == 1) {
+ do {
+ guess = rand() % 10000;
+ } while(!legal(guess));
+ } else
+ guess = n[rand() % j];
+ k = result(correct, guess);
+ if(k == 40) {
+ move(total + 8, 25);
+ sprintf(data, "%04d", guess);
+ prints("%s => ²q¤¤¤F!!", data);
+ return 1;
+ } else {
+ move(total + 8, 25);
+ sprintf(data, "%04d", guess);
+ prints("%s => \033[1;32m%dA %dB\033[m", data, k / 10, k % 10);
+ }
+ j = 0;
+ for(i = 0; i < 10000; i++)
+ if(flag[i]) {
+ if(result(i, guess) != k)
+ flag[i] = 0;
+ else
+ n[j++] = i;
+ }
+ return 0;
+}
+
+static void Diff_Random(char *answer) {
+ register int i = 0, j, k;
+
+ while(i < 4) {
+ k = rand() % 10 + '0';
+ for(j = 0; j < i; j++)
+ if(k == answer[j])
+ break;
+ if(j == i) {
+ answer[j] = k;
+ i++;
+ }
+ }
+ answer[4] = 0;
+}
+
+#define lockreturn0(unmode, state) if(lockutmpmode(unmode, state)) return 0
+
+int guess_main() {
+ unsigned long int money;
+ char computerwin = 0,youwin = 0;
+ int count = 0,c_count = 0;
+ char ifcomputer;
+ char answer[5];
+ int *n = NULL;
+ char yournum[5];
+ char *flag = NULL;
+ static char TABLE[]={0,10,8,4,2,1,0,0,0,0,0};
+ FILE *file;
+
+ clear();
+ showtitle("²q¼Æ¦r", BBSName);
+ lockreturn0(GUESSNUM, LOCK_MULTI);
+
+ reload_money();
+ if(cuser.money < 5) {
+ clear();
+ move(12, 35);
+ prints("¿ú¤£°÷°Õ ¦Ü¤Ö­n 5 Ptt$");
+ unlockutmpmode();
+ pressanykey();
+ return 1;
+ }
+ if((money = get_money()) == 0)
+ return 1;
+ vice(money,"²q¼Æ¦r");
+
+ Diff_Random(answer);
+ move(2, 0);
+ clrtoeol();
+ prints("±z¤Uª` :%d Ptt$", money);
+
+ getdata_str(4, 0, "±z­n©M¹q¸£¤ñÁɶÜ? <y/n>[y]:", &ifcomputer, 2,
+ LCECHO, "y");
+ if(ifcomputer == 'y') {
+ ifcomputer = 1;
+ show_table(TABLE, 1);
+ } else {
+ ifcomputer = 0;
+ show_table(TABLE, 0);
+ }
+ if(ifcomputer) {
+ do {
+ getdata(5, 0, "½Ð¿é¤J±z­nÅý¹q¸£²qªº¼Æ¦r: ", yournum, 5, LCECHO);
+ } while(!legal(atoi(yournum)));
+ move(8, 25);
+ prints("¹q¸£²q");
+ flag = malloc(sizeof(char) * 10000);
+ n = malloc(sizeof(int) * 1500);
+ initcomputer(flag);
+ }
+ move(8, 55);
+ prints("§A²q");
+ while(((!computerwin || !youwin) && count <10 && (ifcomputer)) ||
+ (!ifcomputer && count < 10 && !youwin)) {
+ if(!computerwin && ifcomputer) {
+ ++c_count;
+ if(computer(atoi(yournum), c_count, flag, n))
+ computerwin = 1;
+ }
+ move(20, 55);
+ prints("²Ä %d ¦¸¾÷·| ", count + 1);
+ if(!youwin) {
+ ++count;
+ if(guess_play(get_data(count),answer,count))
+ youwin=1;
+ }
+ }
+ move(17, 35);
+ if(ifcomputer) {
+ free(flag);
+ free(n);
+ if(count > c_count) {
+ prints("§A¿éµ¹¹q¸£¤F");
+ move(18, 35);
+ prints("§A½ß¤F %d ", money);
+ if((file = fopen(LOGPASS,"a"))) {
+ fprintf(file, "¹q¸£²Ä%d¦¸²q¤¤, ", c_count);
+ if(youwin)
+ fprintf(file, "%s ²Ä%d¦¸²q¤¤, ", cuser.userid, count);
+ else
+ fprintf(file, "%s ¨S²q¤¤, ", cuser.userid);
+ fprintf(file,"¹q¸£ÁȨ«¤F%s %ld Ptt$\n", cuser.userid, money);
+ fclose(file);
+ }
+ unlockutmpmode();
+ pressanykey();
+ return 1;
+ } else if(count < c_count) {
+ prints("¯u¼F®`, Åý§AÁȨìÅo");
+ move(18,35);prints("§AÁȨ«¤F %d ",money*2);
+ demoney(money*2);
+ if((file = fopen(LOGPASS,"a"))) {
+ fprintf(file, "id: %s, ²Ä%d¦¸²q¤¤, ¹q¸£²Ä%d¦¸²q¤¤, "
+ "ŤF¹q¸£ %ld Ptt$\n", cuser.userid, count,
+ c_count, money * 2);
+ fclose(file);
+ }
+ unlockutmpmode();
+ pressanykey();
+ return 1;
+ } else {
+ prints("¯u¼F®`, ©M¹q¸£¥´¦¨¥­¤â¤F, ®³¦^¥»¿ú%d\n", money);
+ demoney(money);
+ if((file = fopen(LOGPASS,"a"))) {
+ fprintf(file, "id: %s ©M¹q¸£¥´¦¨¤F¥­¤â\n", cuser.userid);
+ fclose(file);
+ }
+ unlockutmpmode();
+ pressanykey();
+ return 1;
+ }
+ }
+ if(youwin) {
+ demoney(TABLE[count]*money);
+ if(count < 5) {
+ prints("¯u¼F®`, ¿ú³Q§AÁȨ«¤F");
+ if((file = fopen(LOGPASS,"a"))) {
+ fprintf(file, "id: %s, ²Ä%d¦¸²q¤¤, ŤF %ld Ptt$\n",
+ cuser.userid, count, TABLE[count] * money);
+ fclose(file);
+ }
+ } else if(count > 5) {
+ prints("­ü, ¤Ó¦h¦¸¤~²q¥X¨Ó¤F");
+ if((file = fopen(LOGPASS,"a"))) {
+ fprintf(file, "id: %s, ²Ä%d¦¸¤~²q¤¤, ½ß¤F %ld Ptt$\n",
+ cuser.userid, count, money);
+ fclose(file);
+ }
+ }
+ else {
+ prints("¤­¦¸²q¥X¨Ó, ÁÙ§A¥»¿ú§a");
+ move(18,35);
+ clrtoeol();
+ prints("§A®³¦^¤F%d Ptt$\n", money);
+ if((file = fopen(LOGPASS,"a"))) {
+ fprintf(file, "id: %s, ²Ä%d¦¸²q¤¤, ®³¦^¤F¥»¿ú %ld Ptt$\n",
+ cuser.userid, count, money);
+ fclose(file);
+ }
+ }
+ unlockutmpmode();
+ pressanykey();
+ return 1;
+ }
+ move(17,35);
+ prints("¼K¼K ¼Ð·Çµª®×¬O %s ", answer);
+ move(18,35);
+ prints("¤U¦¸¦A¨Ó§a");
+ if((file = fopen(BBSHOME "/etc/loseguess.log","a"))) {
+ fprintf(file,"id: %s ½ä¤F %ld Ptt$\n",cuser.userid,money);
+ fclose(file);
+ }
+ return 1;
+}
diff --git a/mbbsd/indict.c b/mbbsd/indict.c
new file mode 100644
index 00000000..407b5ae9
--- /dev/null
+++ b/mbbsd/indict.c
@@ -0,0 +1,184 @@
+/* $Id: indict.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "perm.h"
+#include "common.h"
+#include "modes.h"
+#include "proto.h"
+
+#define REFER "etc/dicts"
+
+extern userec_t cuser;
+char dict[41],database[41];
+
+static void addword(char word[]) {
+ char buf[150],temp[150],a[3];
+ FILE *fp = fopen(database,"r+");
+
+ fgets(buf,130,fp);
+ fseek(fp,0,2);
+ if(HAVE_PERM(PERM_LOGINOK)) {
+ clear();
+ move(4,0);
+ outs(" \033[31mĵ§i\033[m:­Y»W·N¶ñ¼g°²¸ê®Æ±N\033[36m¬åid\033[m³B¥÷\n");
+ sprintf(temp, "\n¿é¤J½d§Q\n:\033[33m%s\033[m", buf);
+ outs(temp);
+ outs("\n½Ð¨Ì¤W¦C½d¨Ò¿é¤J¤@¦æ¸ê®Æ(ª½±µenter©ñ±ó)\n");
+ getdata(10, 0, ":", buf, 65, DOECHO);
+ if(buf[0]) {
+ getdata(13, 0, "½T©w·s¼W?(Y/n)", a, 2, LCECHO);
+ if(a[0] != 'n')
+ fprintf(fp, "%-65s[%s]\n", buf, cuser.userid);
+ }
+ }
+ fclose(fp);
+ clear();
+}
+
+static int choose_dict(void) {
+ int c;
+ FILE *fp;
+ char buf[10][21], data[10][21], cho[130];
+
+ move(12, 0);
+ clrtobot();
+ outs(" "
+ "¡´ \033[45;33m¦r¨å­ò ¡º ­n¬d­þ¤@¥»¡H\033[m ¡´");
+
+ if((fp = fopen(REFER, "r"))) {
+ for(c = 0; fscanf(fp, "%s %s", buf[c], data[c]) != EOF; c++ ) {
+ sprintf(cho,"\n "
+ "(\033[36m%d\033[m) %-20s¤j¦r¨å",c+1,buf[c]);
+ outs(cho);
+ }
+
+ getdata(22, 14, " ¡¹ ½Ð¿ï¾Ü¡A[Enter]Â÷¶}¡G", cho, 3, LCECHO);
+ cho[0] -= '1';
+ if(cho[1])
+ cho[0] = (cho[0] + 1) * 10 + (cho[1] - '1');
+
+ if(cho[0] >= 0 && cho[0] < c) {
+ strcpy(dict, buf[(int)cho[0]]);
+ strcpy(database, data[(int)cho[0]]);
+ return 1;
+ } else
+ return 0;
+ }
+ return 0;
+}
+
+static char *lower(char str[]) {
+ int c;
+ static char temp[200];
+
+ strcpy(temp,str);
+ for(c = 0; temp[c] !=0; c++)
+ if(temp[c] >= 'A' && temp[c] <= 'Z')
+ temp[c] += 'a' - 'A';
+ return temp;
+}
+
+int use_dict() {
+ FILE *fp;
+ char lang[150], word[80] = "";
+ char j, f, buf[120], sys[] = "|\033[31me\033[m:½sÄy¦r¨å";
+ int i = 0;
+
+ setutmpmode(DICT);
+ if(!HAS_PERM(PERM_SYSOP))
+ sys[0]=0;
+
+ clear();
+
+ sprintf(buf,"\033[45m ¡´\033[1;44;33m"
+ " %-14s\033[3;45m ¡´ ", dict);
+ strcpy(&buf[100],"\033[m\n");
+ for(;;) {
+ move(0, 0);
+ sprintf(lang, " ½Ð¿é¤JÃöÁä¦r¦ê(%s) ©Î«ü¥O(h,t,a)\n", dict);
+ outs(lang);
+ sprintf(lang, "[\033[32m<ÃöÁä¦r>\033[m|\033[32mh\033[m:help|\033[32m"
+ "t\033[m:©Ò¦³¸ê®Æ|\033[32ma\033[m:·s¼W¸ê®Æ%s]\n:", sys);
+ outs(lang);
+ getdata(2, 0, ":", word, 18, DOECHO);
+ outs("¸ê®Æ·j´M¤¤½Ðµy­Ô....");
+ strcpy(word,lower(word));
+ if(word[0] == 0)
+ return 0;
+ clear();
+ move(4, 0);
+ outs(buf);
+ if(strlen(word) == 1) {
+ if(word[0] == 'a') {
+ clear();
+ move(4,0);
+ outs(buf);
+ addword(word);
+ continue;
+ } else if(word[0] == 't')
+ word[0] = 0;
+ else if(word[0] == 'h') {
+ more("etc/dict.hlp",YEA);
+ clear();
+ continue;
+ } else if(word[0]=='e') {
+ vedit(database,NA, NULL);
+ clear();
+ continue;
+ } else {
+ outs("¦r¦ê¤Óµu,½Ð¿é¤J¦h¤@ÂIÃöÁä¦r");
+ continue;
+ }
+ }
+
+ if((fp = fopen(database,"r"))) {
+ i = 0;
+ while(fgets(lang,150,fp) != NULL) {
+ if(lang[65] == '[') {
+ lang[65] = 0;
+ f = 1;
+ } else
+ f = 0;
+ if(strstr(lower(lang),word)) {
+ if(f == 1)
+ lang[65] = '[';
+ outs(lang);
+ i++;
+ if(!((i+1)%17)) {
+ move(23, 0);
+ outs("\033[45m "
+ "¥ô·NÁäÄ~Äò Q:Â÷¶} "
+ "\033[m ");
+ j = igetch();
+ if(j == 'q')
+ break;
+ else {
+ clear();
+ move(4,0);
+ outs(buf);
+ }
+ }
+ }
+ }
+ }
+ fclose(fp);
+ if(i == 0) {
+ getdata(5, 0, "¨S³o­Ó¸ê®Æ­C,·s¼W¶Ü?(y/N)", lang, 3, LCECHO);
+ if(lang[0] == 'y') {
+ clear();
+ move(4,0);
+ outs(buf);
+ addword(word);
+ }
+ }
+ }
+}
+
+int x_dict() {
+ if(choose_dict())
+ use_dict();
+ return 0;
+}
diff --git a/mbbsd/io.c b/mbbsd/io.c
new file mode 100644
index 00000000..e3d03b9b
--- /dev/null
+++ b/mbbsd/io.c
@@ -0,0 +1,611 @@
+/* $Id: io.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "perm.h"
+#include "modes.h"
+#include "common.h"
+#include "proto.h"
+
+#if defined(linux)
+#define OBUFSIZE 2048
+#define IBUFSIZE 128
+#else
+#define OBUFSIZE 4096
+#define IBUFSIZE 256
+#endif
+
+extern int current_font_type;
+extern char *fn_proverb;
+extern userinfo_t *currutmp;
+extern unsigned int currstat;
+extern pid_t currpid;
+extern int errno;
+extern screenline_t *big_picture;
+extern int t_lines, t_columns; /* Screen size / width */
+extern int curr_idle_timeout;
+extern water_t water[6], *swater[5], *water_which;
+extern char water_usies;
+
+static char outbuf[OBUFSIZE], inbuf[IBUFSIZE];
+static int obufsize = 0, ibufsize = 0;
+static int icurrchar = 0;
+
+/* ----------------------------------------------------- */
+/* ©w®ÉÅã¥Ü°ÊºA¬ÝªO */
+/* ----------------------------------------------------- */
+extern userec_t cuser;
+
+static void hit_alarm_clock() {
+ if(HAS_PERM(PERM_NOTIMEOUT) || PERM_HIDE(currutmp) || currstat == MAILALL)
+ return;
+// if(time(0) - currutmp->lastact > IDLE_TIMEOUT - 2) {
+ if(time(0) - currutmp->lastact > curr_idle_timeout - 2) {
+ clear();
+ if(currpid > 0) kill(currpid, SIGHUP);
+ }
+// alarm(IDLE_TIMEOUT);
+ alarm(curr_idle_timeout);
+}
+
+void init_alarm() {
+ signal(SIGALRM, (void (*)(int))hit_alarm_clock);
+// alarm(IDLE_TIMEOUT);
+ alarm(curr_idle_timeout);
+}
+
+/* ----------------------------------------------------- */
+/* output routines */
+/* ----------------------------------------------------- */
+
+void oflush() {
+ if(obufsize) {
+ write(1, outbuf, obufsize);
+ obufsize = 0;
+ }
+}
+
+void init_buf()
+{
+
+ memset(inbuf,0,IBUFSIZE);
+}
+void output(char *s, int len) {
+ /* Invalid if len >= OBUFSIZE */
+
+ if(obufsize + len > OBUFSIZE) {
+ write(1, outbuf, obufsize);
+ obufsize = 0;
+ }
+ memcpy(outbuf + obufsize, s, len);
+ obufsize += len;
+}
+
+int ochar(int c) {
+ if(obufsize > OBUFSIZE - 1) {
+ write(1, outbuf, obufsize);
+ obufsize = 0;
+ }
+ outbuf[obufsize++] = c;
+ return 0;
+}
+
+/* ----------------------------------------------------- */
+/* input routines */
+/* ----------------------------------------------------- */
+
+static int i_newfd = 0;
+static struct timeval i_to, *i_top = NULL;
+static int (*flushf) () = NULL;
+
+void add_io(int fd, int timeout) {
+ i_newfd = fd;
+ if(timeout) {
+ i_to.tv_sec = timeout;
+ i_to.tv_usec = 16384; /* Ptt: §ï¦¨16384 ÁקK¤£«ö®Éfor loop¦Ycpu time
+ 16384 ¬ù¨C¬í64¦¸ */
+ i_top = &i_to;
+ } else
+ i_top = NULL;
+}
+
+int num_in_buf() {
+ return icurrchar - ibufsize;
+}
+
+int watermode = -1;
+/* Ptt ¤ô²y¦^ÅU¥Îªº°Ñ¼Æ */
+/* watermode = -1 ¨S¦b¦^¤ô²y
+ = 0 ¦b¦^¤W¤@Áû¤ô²y (Ctrl-R)
+ > 0 ¦b¦^«e n Áû¤ô²y (Ctrl-R Ctrl-R) */
+
+/*
+ dogetch() is not reentrant-safe. SIGUSR[12] might happen at any time,
+ and dogetch() might be called again, and then ibufsize/icurrchar/inbuf
+ might be inconsistent.
+ We try to not segfault here...
+*/
+
+static int dogetch() {
+ int len;
+
+ if(ibufsize <= icurrchar) {
+
+ if(flushf)
+ (*flushf)();
+
+ refresh();
+
+ if(i_newfd) {
+
+ struct timeval timeout;
+ fd_set readfds;
+
+ if(i_top) timeout=*i_top; /* copy it because select() might change it */
+
+ FD_ZERO(&readfds);
+ FD_SET(0, &readfds);
+ FD_SET(i_newfd, &readfds);
+
+ /* jochang: modify first argument of select from FD_SETSIZE */
+ /* since we are only waiting input from fd 0 and i_newfd(>0) */
+
+ while((len = select(i_newfd+1, &readfds, NULL, NULL, i_top?&timeout:NULL))<0)
+ {
+ if(errno != EINTR)
+ abort_bbs(0);
+ /* raise(SIGHUP); */
+ }
+
+ if(len == 0)
+ return I_TIMEOUT;
+
+ if(i_newfd && FD_ISSET(i_newfd, &readfds))
+ return I_OTHERDATA;
+ }
+
+ while((len = read(0, inbuf, IBUFSIZE)) <= 0) {
+ if(len == 0 || errno != EINTR)
+ abort_bbs(0);
+ /* raise(SIGHUP); */
+ }
+ ibufsize = len;
+ icurrchar = 0;
+ }
+
+ if(currutmp)
+ currutmp->lastact = time(0);
+ return inbuf[icurrchar++];
+}
+
+static int water_which_flag=0;
+int igetch() {
+ register int ch;
+ while((ch = dogetch())) {
+ switch(ch) {
+ case Ctrl('L'):
+ redoscr();
+ continue;
+ case Ctrl('U'):
+ if(currutmp != NULL && currutmp->mode != EDITING
+ && currutmp->mode != LUSERS && currutmp->mode) {
+
+ screenline_t *screen0 = calloc(t_lines, sizeof(screenline_t));
+ int y, x, my_newfd;
+
+ getyx(&y, &x);
+ memcpy(screen0, big_picture, t_lines * sizeof(screenline_t));
+ my_newfd = i_newfd;
+ i_newfd = 0;
+ t_users();
+ i_newfd = my_newfd;
+ memcpy(big_picture, screen0, t_lines * sizeof(screenline_t));
+ move(y, x);
+ free(screen0);
+ redoscr();
+ continue;
+ } else
+ return (ch);
+ case KEY_TAB:
+ if( WATERMODE(WATER_ORIG) || WATERMODE(WATER_NEW) )
+ if( currutmp != NULL && watermode > 0 ){
+ watermode = (watermode + water_which->count)
+ % water_which->count + 1;
+ t_display_new();
+ continue;
+ }
+ return ch;
+ break;
+
+ case Ctrl('R'):
+ if(currutmp == NULL)
+ return (ch);
+ if( WATERMODE(WATER_ORIG) || WATERMODE(WATER_NEW) ){
+ if( watermode > 0 ){
+ watermode = (watermode + water_which->count)
+ % water_which->count + 1;
+ t_display_new();
+ continue;
+ }
+ else if( currutmp->mode == 0 &&
+ (currutmp->chatid[0]==2 || currutmp->chatid[0]==3) &&
+ water_which->count != 0 && watermode == 0) {
+ /* ²Ä¤G¦¸«ö Ctrl-R */
+ watermode = 1;
+ t_display_new();
+ continue;
+ }
+ else if(currutmp->msgs[0].pid) {
+ /* ²Ä¤@¦¸«ö Ctrl-R (¥²¶·¥ý³Q¥á¹L¤ô²y) */
+ screenline_t *screen0;
+ int y, x, my_newfd;
+ screen0 = calloc(t_lines, sizeof(screenline_t));
+ getyx(&y, &x);
+ memcpy(screen0, big_picture, t_lines*sizeof(screenline_t));
+
+ /* ¦pªG¥¿¦btalkªº¸Ü¥ý¤£³B²z¹ï¤è°e¹L¨Óªº«Ê¥] (¤£¥hselect) */
+ my_newfd = i_newfd;
+ i_newfd = 0;
+ show_last_call_in(0);
+ watermode = 0;
+ my_write(currutmp->msgs[0].pid, "¤ô²y¥á¹L¥h ¡G ",
+ currutmp->msgs[0].userid, 0);
+ i_newfd = my_newfd;
+
+ /* ÁÙ­ì¿Ã¹õ */
+ memcpy(big_picture, screen0, t_lines*sizeof(screenline_t));
+ move(y, x);
+ free(screen0);
+ redoscr();
+ continue;
+ }
+ else
+ return ch;
+ }
+
+ if( currutmp->msgs[0].pid &&
+ WATERMODE(WATER_OFO) && watermode == -1 ){
+ int y, x, my_newfd;
+ screenline_t *screen0 = calloc(t_lines, sizeof(screenline_t));
+ memcpy(screen0, big_picture, t_lines * sizeof(screenline_t));
+ getyx(&y, &x);
+ my_newfd = i_newfd;
+ i_newfd = 0;
+ my_write2();
+ memcpy(big_picture, screen0, t_lines * sizeof(screenline_t));
+ i_newfd = my_newfd;
+ move(y, x);
+ free(screen0);
+ redoscr();
+ continue;
+ }
+
+ return ch;
+ case '\n': /* Ptt§â \n®³±¼ */
+ continue;
+ case Ctrl('T'):
+ if( WATERMODE(WATER_ORIG) || WATERMODE(WATER_NEW) ){
+ if(watermode > 0) {
+ if(watermode>1)
+ watermode--;
+ else
+ watermode = water_which->count;
+ t_display_new();
+ continue;
+ }
+ }
+ return (ch);
+
+ case Ctrl('E'):
+ if( WATERMODE(WATER_ORIG) || WATERMODE(WATER_NEW) ){
+ if(watermode >0){
+ if( water_which_flag == (int)water_usies )
+ water_which_flag = 0;
+ else
+ water_which_flag =
+ (water_which_flag+1) % (int)(water_usies+1);
+ if(water_which_flag==0)
+ water_which = &water[0];
+ else
+ water_which = swater[water_which_flag-1];
+ watermode = 1;
+ t_display_new();
+ continue;
+ }
+ }
+ return ch;
+
+ case Ctrl('W'):
+ if(watermode >0)
+ {
+ water_which_flag=(water_which_flag+water_usies)%(water_usies+1);
+ if(water_which_flag==0)
+ water_which = &water[0];
+ else
+ water_which = swater[water_which_flag-1];
+ watermode = 1;
+ t_display_new();
+ continue;
+ }
+ else return ch;
+ default:
+ return ch;
+ }
+ }
+ return 0;
+}
+
+int oldgetdata(int line, int col, char *prompt, char *buf, int len, int echo) {
+ register int ch, i;
+ int clen;
+ int x = col, y = line;
+ extern unsigned char scr_cols;
+#define MAXLASTCMD 12
+ static char lastcmd[MAXLASTCMD][80];
+
+ strip_ansi(buf, buf, STRIP_ALL);
+
+ if(prompt) {
+
+ move(line, col);
+
+ clrtoeol();
+
+ outs(prompt);
+
+ x += strip_ansi(NULL,prompt,0);
+ }
+
+ if(!echo) {
+ len--;
+ clen = 0;
+ while((ch = igetch()) != '\r') {
+ if(ch == '\177' || ch == Ctrl('H')) {
+ if(!clen) {
+ bell();
+ continue;
+ }
+ clen--;
+ if(echo) {
+ ochar(Ctrl('H'));
+ ochar(' ');
+ ochar(Ctrl('H'));
+ }
+ continue;
+ }
+// Ptt
+#ifdef BIT8
+ if(!isprint2(ch))
+#else
+ if(!isprint(ch))
+#endif
+ {
+ if(echo)
+ bell();
+ continue;
+ }
+
+ if(clen >= len) {
+ if(echo)
+ bell();
+ continue;
+ }
+ buf[clen++] = ch;
+ if(echo)
+ ochar(ch);
+ }
+ buf[clen] = '\0';
+ outc('\n');
+ oflush();
+ } else {
+ int cmdpos = -1;
+ int currchar = 0;
+
+ standout();
+ for(clen = len--; clen; clen--)
+ outc(' ');
+ standend();
+ buf[len] = 0;
+ move(y, x);
+ edit_outs(buf);
+ clen = currchar = strlen(buf);
+
+ while(move(y, x + currchar), (ch = igetkey()) != '\r') {
+ switch(ch) {
+ case KEY_DOWN:
+ case Ctrl('N'):
+ buf[clen] = '\0'; /* Ptt */
+ strncpy(lastcmd[cmdpos], buf, 79);
+ cmdpos += MAXLASTCMD - 2;
+ case Ctrl('P'):
+ case KEY_UP:
+ if(ch == KEY_UP || ch == Ctrl('P')) {
+ buf[clen] = '\0'; /* Ptt */
+ strncpy(lastcmd[cmdpos], buf, 79);
+ }
+ cmdpos++;
+ cmdpos %= MAXLASTCMD;
+ strncpy(buf, lastcmd[cmdpos], len);
+ buf[len] = 0;
+
+ move(y, x); /* clrtoeof */
+ for(i = 0; i <= clen; i++)
+ outc(' ');
+ move(y, x);
+ edit_outs(buf);
+ clen = currchar = strlen(buf);
+ break;
+ case KEY_LEFT:
+ if(currchar)
+ --currchar;
+ break;
+ case KEY_RIGHT:
+ if(buf[currchar])
+ ++currchar;
+ break;
+ case '\177':
+ case Ctrl('H'):
+ if(currchar) {
+ currchar--;
+ clen--;
+ for(i = currchar; i <= clen; i++)
+ buf[i] = buf[i + 1];
+ move(y, x + clen);
+ outc(' ');
+ move(y, x);
+ edit_outs(buf);
+ }
+ break;
+ case Ctrl('Y'):
+ currchar = 0;
+ case Ctrl('K'):
+ buf[currchar] = 0;
+ move(y, x + currchar);
+ for(i = currchar; i < clen; i++)
+ outc(' ');
+ clen = currchar;
+ break;
+ case Ctrl('D'):
+ if(buf[currchar]) {
+ clen--;
+ for(i = currchar; i <= clen; i++)
+ buf[i] = buf[i + 1];
+ move(y, x + clen);
+ outc(' ');
+ move(y, x);
+ edit_outs(buf);
+ }
+ break;
+ case Ctrl('A'):
+ currchar = 0;
+ break;
+ case Ctrl('E'):
+ currchar = clen;
+ break;
+ default:
+ if(isprint2(ch) && clen < len && x + clen < scr_cols) {
+ for(i = clen + 1; i > currchar;i--)
+ buf[i] = buf[i - 1];
+ buf[currchar] = ch;
+ move(y, x + currchar);
+ edit_outs(buf + currchar);
+ currchar++;
+ clen++;
+ }
+ break;
+ }/* end case */
+ } /* end while */
+
+ if(clen > 1)
+ for(cmdpos = MAXLASTCMD - 1; cmdpos; cmdpos--) {
+ strcpy(lastcmd[cmdpos], lastcmd[cmdpos - 1]);
+ strncpy(lastcmd[0], buf, len);
+ }
+ if(echo)
+ outc('\n');
+ refresh();
+ }
+ if((echo == LCECHO) && ((ch = buf[0]) >= 'A') && (ch <= 'Z'))
+ buf[0] = ch | 32;
+#ifdef SUPPORT_GB
+ if(echo == DOECHO && current_font_type == TYPE_GB)
+ {
+ strcpy(buf,hc_convert_str(buf, HC_GBtoBIG, HC_DO_SINGLE));
+ }
+#endif
+ return clen;
+}
+
+/* Ptt */
+int getdata_buf(int line, int col, char *prompt, char *buf, int len, int echo) {
+ return oldgetdata(line, col, prompt, buf, len, echo);
+}
+
+char
+getans(char *prompt)
+{
+ char ans[5];
+
+ getdata(t_lines-1, 0, prompt, ans, 4, LCECHO);
+ return ans[0];
+}
+
+int getdata_str(int line, int col, char *prompt, char *buf, int len, int echo, char *defaultstr) {
+ strncpy(buf, defaultstr, len);
+
+ buf[len] = 0;
+ return oldgetdata(line, col, prompt, buf, len, echo);
+}
+
+int getdata(int line, int col, char *prompt, char *buf, int len, int echo) {
+ buf[0] = 0;
+ return oldgetdata(line, col, prompt, buf, len, echo);
+}
+
+int
+rget(int x,char *prompt)
+{
+ register int ch;
+
+ move(x,0);
+ clrtobot();
+ outs(prompt);
+ refresh();
+
+ ch = igetch();
+ if( ch >= 'A' && ch <= 'Z') ch |= 32;
+
+ return ch;
+}
+
+
+int KEY_ESC_arg;
+
+int igetkey() {
+ int mode;
+ int ch, last;
+
+ mode = last = 0;
+ while(1) {
+ ch = igetch();
+ if(mode == 0) {
+ if(ch == KEY_ESC)
+ mode = 1;
+ else
+ return ch; /* Normal Key */
+ } else if (mode == 1) { /* Escape sequence */
+ if(ch == '[' || ch == 'O')
+ mode = 2;
+ else if(ch == '1' || ch == '4')
+ mode = 3;
+ else {
+ KEY_ESC_arg = ch;
+ return KEY_ESC;
+ }
+ } 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/mbbsd/kaede.c b/mbbsd/kaede.c
new file mode 100644
index 00000000..c0bd5103
--- /dev/null
+++ b/mbbsd/kaede.c
@@ -0,0 +1,95 @@
+/* $Id: kaede.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "proto.h"
+
+extern struct utmpfile_t *utmpshm;
+extern userec_t cuser;
+
+char *Ptt_prints(char *str, int mode) {
+ char *po , strbuf[256];
+
+ while((po = strstr(str, "\033*s"))) {
+ po[0] = 0;
+ sprintf(strbuf, "%s%s%s", str, cuser.userid, po + 3);
+ strcpy(str, strbuf);
+ }
+ while((po = strstr(str, "\033*t"))) {
+ time_t now = time(0);
+
+ po[0] = 0;
+ sprintf(strbuf, "%s%s", str, Cdate(&now));
+ str[strlen(strbuf)-1] = 0;
+ strcat(strbuf, po + 3);
+ strcpy(str, strbuf);
+ }
+ while((po = strstr(str, "\033*u"))) {
+ int attempts;
+
+ attempts = utmpshm->number;
+ po[0] = 0;
+ sprintf(strbuf, "%s%d%s", str, attempts, po + 3);
+ strcpy(str, strbuf);
+ }
+ while((po = strstr(str, "\033*b"))) {
+ po[0] = 0;
+ sprintf(strbuf, "%s%d/%d%s", str, cuser.month, cuser.day, po + 3);
+ strcpy(str, strbuf);
+ }
+ while((po = strstr(str, "\033*l"))) {
+ po[0] = 0;
+ sprintf(strbuf, "%s%d%s", str, cuser.numlogins, po + 3);
+ strcpy(str, strbuf);
+ }
+ while((po = strstr(str, "\033*p"))) {
+ po[0] = 0;
+ sprintf(strbuf, "%s%d%s", str, cuser.numposts, po + 3);
+ strcpy(str, strbuf);
+ }
+ while((po = strstr(str, "\033*n"))) {
+ po[0] = 0;
+ sprintf(strbuf, "%s%s%s", str, cuser.username, po + 3);
+ strcpy(str, strbuf);
+ }
+ while((po = strstr(str, "\033*m"))) {
+ po[0] = 0;
+ sprintf(strbuf, "%s%d%s", str, cuser.money, po + 3);
+ strcpy(str, strbuf);
+ }
+ strip_ansi(str, str ,mode);
+ return str;
+}
+
+int Rename(char* src, char* dst) {
+ if(rename(src, dst) == 0)
+ return 0;
+ return -1;
+}
+
+int Link(char* src, char* dst) {
+ char cmd[200];
+
+ if(strcmp(src, BBSHOME "/home") == 0)
+ return 1;
+ if(link(src, dst) == 0)
+ return 0;
+
+ sprintf(cmd, "/bin/cp -R %s %s", src, dst);
+ return system(cmd);
+}
+
+char *my_ctime(const time_t *t) {
+ struct tm *tp;
+ static char ans[100];
+
+ tp = localtime(t);
+ sprintf(ans, "%02d/%02d/%02d %02d:%02d:%02d", (tp->tm_year % 100),
+ tp->tm_mon + 1,tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec);
+ return ans;
+}
diff --git a/mbbsd/lovepaper.c b/mbbsd/lovepaper.c
new file mode 100644
index 00000000..52e8cbd5
--- /dev/null
+++ b/mbbsd/lovepaper.c
@@ -0,0 +1,120 @@
+/* $Id: lovepaper.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "modes.h"
+#include "common.h"
+#include "proto.h"
+
+#define DATA "etc/lovepaper.dat"
+
+extern userec_t cuser;
+
+int x_love() {
+ char buf1[200], save_title[TTLEN + 1];
+ char receiver[61], path[STRLEN] = "home/";
+ int x, y = 0, tline = 0, poem = 0;
+ FILE *fp, *fpo;
+ time_t timenow;
+ struct tm *gtime;
+ fileheader_t mhdr;
+
+ setutmpmode(LOVE);
+ time(&timenow);
+ gtime = localtime(&timenow);
+ sprintf(buf1,"%c/%s/love%d%d",
+ cuser.userid[0], cuser.userid,gtime->tm_sec,gtime->tm_min);
+ strcat(path,buf1);
+ move(1,0);
+ clrtobot();
+
+ outs("\nÅwªï¨Ï¥Î±¡®Ñ²£¥Í¾¹ v0.00 ª© \n");
+ outs("¦³¦óÃø¥H±Ò¾¦ªº¸Ü,¥æ¥Ñ¨t²ÎÀ°§A»¡§a.\nª¨ª¨»¡ : Àݱ¡¤£¥Çªk.\n");
+
+ if(!getdata(7, 0, "¦¬«H¤H¡G", receiver, 60, DOECHO)) return 0;
+ if(receiver[0] && !(searchuser(receiver) &&
+ getdata(8, 0, "¥D ÃD¡G", save_title,
+ TTLEN, DOECHO))) {
+ move(10, 0);
+ outs("¦¬«H¤H©Î¥DÃD¤£¥¿½T, ±¡®ÑµLªk¶Ç»¼. ");
+ pressanykey();
+ return 0;
+ }
+
+ fpo = fopen(path, "w");
+ fprintf(fpo, "\n");
+ if((fp = fopen(DATA, "r"))) {
+ while(fgets(buf1,100, fp)) {
+ switch(buf1[0]) {
+ case '#':
+ break;
+ case '@':
+ if(!strncmp(buf1, "@begin", 6) || !strncmp(buf1, "@end", 4))
+ tline=3;
+ else if(!strncmp(buf1,"@poem",5)) {
+ poem = 1;
+ tline = 1;
+ fprintf(fpo, "\n\n");
+ } else
+ tline=2;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ sscanf(buf1,"%d",&x);
+ y = (rand() % (x - 1)) * tline;
+ break;
+ default:
+ if(!poem) {
+ if(y > 0)
+ y = y - 1;
+ else {
+ if(tline > 0) {
+ fprintf(fpo, "%s", buf1);
+ tline--;
+ }
+ }
+ } else {
+ if(buf1[0] == '$')
+ y--;
+ else if(y == 0)
+ fprintf(fpo,"%s",buf1);
+ }
+ }
+
+ }
+
+ fclose(fp);
+ fclose(fpo);
+ if(vedit(path, YEA, NULL) == -1) {
+ unlink(path);
+ clear();
+ outs("\n\n ©ñ±ó±H±¡®Ñ\n");
+ pressanykey();
+ return -2;
+ }
+ sethomepath(buf1, receiver);
+ stampfile(buf1, &mhdr);
+ Rename(path, buf1);
+ strncpy(mhdr.title, save_title, TTLEN);
+ strcpy(mhdr.owner, cuser.userid);
+ mhdr.savemode = '\0';
+ sethomedir(path, receiver );
+ if(append_record(path, &mhdr, sizeof(mhdr)) == -1)
+ return -1;
+ hold_mail(buf1, receiver);
+ return 1;
+ }
+ return 0;
+}
diff --git a/mbbsd/mail.c b/mbbsd/mail.c
new file mode 100644
index 00000000..e480abb2
--- /dev/null
+++ b/mbbsd/mail.c
@@ -0,0 +1,1675 @@
+/* $Id: mail.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "perm.h"
+#include "modes.h"
+#include "proto.h"
+
+extern int TagNum;
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+extern char save_title[]; /* used by editor when inserting */
+extern int curredit;
+extern char *err_uid;
+extern char *msg_cancel;
+extern char *msg_uid;
+extern char *fn_overrides;
+extern char quote_file[80];
+extern char quote_user[80];
+extern char *fn_notes;
+extern char *msg_mailer;
+extern char *msg_sure_ny;
+extern char *BBSName;
+extern char currtitle[44];
+extern unsigned char currfmode; /* current file mode */
+extern char *msg_del_ny;
+extern char currfile[FNLEN];
+extern int currmode;
+extern char currboard[]; /* name of currently selected board */
+extern char *str_space;
+extern char *str_author1;
+extern char *str_author2;
+extern userinfo_t *currutmp;
+extern unsigned int currstat;
+extern pid_t currpid;
+extern int usernum;
+extern char *str_mail_address;
+extern userec_t cuser;
+
+char currmaildir[32];
+static char msg_cc[] = "\033[32m[¸s²Õ¦W³æ]\033[m\n";
+static char listfile[] = "list.0";
+static int mailkeep = 0, mailsum = 0;
+static int mailsumlimit = 0,mailmaxkeep = 0;
+
+int setforward() {
+ char buf[80], ip[50] = "", yn[4];
+ FILE *fp;
+
+ sethomepath(buf, cuser.userid);
+ strcat(buf,"/.forward");
+ if((fp = fopen(buf,"r"))) {
+ fscanf(fp,"%s",ip);
+ fclose(fp);
+ }
+ getdata_buf(b_lines - 1, 0, "½Ð¿é¤J«H½c¦Û°ÊÂà±Hªºemail¦a§}:",
+ ip, 41, DOECHO);
+ if(ip[0] && ip[0] != ' ') {
+ getdata(b_lines, 0, "½T©w¶}±Ò¦Û°ÊÂà«H¥\\¯à?(Y/n)", yn, 3,
+ LCECHO);
+ if(yn[0] != 'n' && (fp = fopen(buf, "w"))) {
+ move(b_lines,0);
+ clrtoeol();
+ fprintf(fp,"%s",ip);
+ fclose(fp);
+ outs("³]©w§¹¦¨!");
+ refresh();
+ return 0;
+ }
+ }
+ move(b_lines,0);
+ clrtoeol();
+ outs("¨ú®ø¦Û°ÊÂà«H!");
+ unlink(buf);
+ refresh();
+ return 0;
+}
+
+int built_mail_index() {
+ char genbuf[128];
+
+ getdata(b_lines, 0,
+ "­««Ø«H½c?(ĵ§i:½Ð½T©w«H½c¦³°ÝÃD®É¤~¨Ï¥Î)(y/N)", genbuf, 3,
+ LCECHO);
+ if(genbuf[0] != 'y') return 0;
+
+ sprintf(genbuf, BBSHOME "/bin/buildir " BBSHOME "/home/%c/%s",
+ cuser.userid[0], cuser.userid);
+ move(22,0);
+ prints("\033[1;31m¤w¸g³B²z§¹²¦!! ½Ñ¦h¤£«K ·q½Ð­ì½Ì~\033[m");pressanykey();
+ system(genbuf);
+ return 0;
+}
+
+int mailalert(char *userid)
+{
+ userinfo_t *uentp=NULL;
+ int n,tuid,i;
+
+ if((tuid=searchuser(userid))==0) return -1;
+
+ n=count_logins(tuid, 0);
+ for(i=1;i<=n;i++)
+ if((uentp = (userinfo_t *)search_ulistn(tuid, i)))
+ uentp->mailalert=1;
+ return 0;
+}
+
+int mail_muser(userec_t muser, char *title, char *filename) {
+ return mail_id(muser.userid, title, filename, cuser.userid);
+}
+
+/* Heat: ¥Îid¨Ó±H«H,¤º®e«hlink·Ç³Æ¦nªºÀÉ®× */
+int mail_id(char* id, char *title, char *filename, char *owner) {
+ fileheader_t mhdr;
+ char genbuf[128];
+ sethomepath(genbuf, id);
+ if(stampfile(genbuf, &mhdr))
+ return 0;
+ strcpy(mhdr.owner, owner);
+ strncpy(mhdr.title, title, TTLEN);
+ mhdr.savemode = 0;
+ mhdr.filemode = 0;
+ Link(filename, genbuf);
+ sethomedir(genbuf,id);
+ append_record(genbuf, &mhdr, sizeof(mhdr));
+ mailalert(id);
+ return 0;
+}
+
+int invalidaddr(char *addr) {
+ if(*addr == '\0')
+ return 1; /* blank */
+ while(*addr) {
+ if(not_alnum(*addr) && !strchr("[].%!@:-_;", *addr))
+ return 1;
+ addr++;
+ }
+ return 0;
+}
+
+int m_internet() {
+ char receiver[60];
+
+ getdata(20, 0, "¦¬«H¤H¡G", receiver, 60, DOECHO);
+ if(strchr(receiver, '@') && !invalidaddr(receiver) &&
+ getdata(21, 0, "¥D ÃD¡G", save_title, TTLEN, DOECHO))
+ do_send(receiver, save_title);
+ else {
+ move(22, 0);
+ outs("¦¬«H¤H©Î¥DÃD¤£¥¿½T, ½Ð­«·s¿ï¨ú«ü¥O");
+ pressanykey();
+ }
+ return 0;
+}
+
+void m_init() {
+ sethomedir(currmaildir, cuser.userid);
+}
+
+int chkmailbox() {
+ if(!HAVE_PERM(PERM_SYSOP) && !HAVE_PERM(PERM_MAILLIMIT)) {
+ int max_keepmail = MAX_KEEPMAIL;
+ if ( HAS_PERM(PERM_SYSSUBOP) || HAS_PERM(PERM_SMG) ||
+ HAS_PERM(PERM_PRG) || HAS_PERM(PERM_ACTION) || HAS_PERM(PERM_PAINT))
+ {
+ mailsumlimit = 700;
+ max_keepmail = 500;
+ }
+ else if(HAS_PERM(PERM_BM))
+ {
+ mailsumlimit = 500;
+ max_keepmail = 300;
+ }
+ else if(HAS_PERM(PERM_LOGINOK))
+ mailsumlimit = 200;
+ else
+ mailsumlimit = 50;
+ mailsumlimit += cuser.exmailbox * 10;
+ mailmaxkeep = max_keepmail + cuser.exmailbox;
+ m_init();
+ if((mailkeep = get_num_records(currmaildir, sizeof(fileheader_t))) >
+ mailmaxkeep) {
+ move(b_lines, 0);
+ clrtoeol();
+ bell();
+ prints("±z«O¦s«H¥ó¼Æ¥Ø %d ¶W¥X¤W­­ %d, ½Ð¾ã²z",
+ mailkeep, mailmaxkeep);
+ bell();
+ refresh();
+ igetch();
+ return mailkeep;
+ }
+ if((mailsum = get_sum_records(currmaildir, sizeof(fileheader_t))) >
+ mailsumlimit) {
+ move(b_lines, 0);
+ clrtoeol();
+ bell();
+ prints("±z«O¦s«H¥ó®e¶q %d(k)¶W¥X¤W­­ %d(k), ½Ð¾ã²z",
+ mailsum, mailsumlimit);
+ bell();
+ refresh();
+ igetch();
+ return mailkeep;
+ }
+ }
+ return 0;
+}
+
+static void do_hold_mail(char *fpath, char *receiver, char *holder) {
+ char buf[80], title[128];
+
+ fileheader_t mymail;
+
+ sethomepath(buf, holder);
+ stampfile(buf, &mymail);
+
+ mymail.savemode = 'H'; /* hold-mail flag */
+ mymail.filemode = FILE_READ;
+ strcpy(mymail.owner, "[³Æ.§Ñ.¿ý]");
+ if(receiver) {
+ sprintf(title, "(%s) %s", receiver, save_title);
+ strncpy(mymail.title, title, TTLEN);
+ } else
+ strcpy(mymail.title, save_title);
+
+ sethomedir(title, holder);
+
+ unlink(buf);
+ Link(fpath, buf);
+ /* Ptt: append_record->do_append */
+ do_append(title, &mymail, sizeof(mymail));
+}
+
+extern userec_t xuser;
+
+void hold_mail(char *fpath, char *receiver) {
+ char buf[4];
+
+ getdata(b_lines - 1, 0, "¤w¶¶§Q±H¥X¡A¬O§_¦Û¦s©³½Z(Y/N)¡H[N] ",
+ buf, 4, LCECHO);
+
+ if(buf[0] == 'y')
+ do_hold_mail(fpath, receiver, cuser.userid);
+}
+
+int do_send(char *userid, char *title) {
+ fileheader_t mhdr;
+ char fpath[STRLEN];
+ char receiver[IDLEN];
+ char genbuf[200];
+ int internet_mail, i;
+
+ if(strchr(userid, '@'))
+ internet_mail = 1;
+ else {
+ internet_mail = 0;
+ if(!getuser(userid))
+ return -1;
+ if(!(xuser.userlevel & PERM_READMAIL))
+ return -3;
+
+ if(!title)
+ getdata(2, 0, "¥DÃD¡G", save_title, TTLEN, DOECHO);
+ curredit |= EDIT_MAIL;
+ curredit &= ~EDIT_ITEM;
+ }
+
+ setutmpmode(SMAIL);
+
+ fpath[0] = '\0';
+
+ if(internet_mail) {
+ int res, ch;
+
+ if(vedit(fpath, NA, NULL) == -1) {
+ unlink(fpath);
+ clear();
+ return -2;
+ }
+ clear();
+ prints("«H¥ó§Y±N±Hµ¹ %s\n¼ÐÃD¬°¡G%s\n½T©w­n±H¥X¶Ü? (Y/N) [Y]",
+ userid, title);
+ ch = igetch();
+ switch(ch) {
+ case 'N':
+ case 'n':
+ outs("N\n«H¥ó¤w¨ú®ø");
+ res = -2;
+ break;
+ default:
+ outs("Y\n½Ðµy­Ô, «H¥ó¶Ç»¼¤¤...\n");
+ res =
+#ifndef USE_BSMTP
+ bbs_sendmail(fpath, title, userid);
+#else
+ bsmtp(fpath, title, userid,0);
+#endif
+ hold_mail(fpath, userid);
+ }
+ unlink(fpath);
+ return res;
+ } else {
+ strcpy(receiver, userid);
+ sethomepath(genbuf, userid);
+ stampfile(genbuf, &mhdr);
+ strcpy(mhdr.owner, cuser.userid);
+ strncpy(mhdr.title, save_title, TTLEN);
+ mhdr.savemode = '\0';
+ if(vedit(genbuf, YEA, NULL) == -1) {
+ unlink(genbuf);
+ clear();
+ return -2;
+ }
+ clear();
+ sethomefile(fpath, userid, FN_OVERRIDES);
+ i=belong(fpath, cuser.userid);
+ sethomefile(fpath, userid, FN_REJECT);
+
+ if(i || !belong(fpath, cuser.userid)) //Ptt:¥Îbelong¦³ÂI°Q¹½
+ {
+ sethomedir(fpath, userid);
+ if(append_record(fpath, &mhdr, sizeof(mhdr)) == -1)
+ return -1;
+ mailalert(userid);
+ }
+ hold_mail(genbuf, userid);
+ return 0;
+ }
+}
+
+void my_send(char *uident) {
+ switch(do_send(uident, NULL)) {
+ case -1:
+ outs(err_uid);
+ break;
+ case -2:
+ outs(msg_cancel);
+ break;
+ case -3:
+ prints("¨Ï¥ÎªÌ [%s] µLªk¦¬«H", uident);
+ break;
+ }
+ pressanykey();
+}
+
+int m_send() {
+ char uident[40];
+
+ stand_title("¥BÅ¥­·ªº¸Ü");
+ usercomplete(msg_uid, uident);
+ showplans(uident);
+ if(uident[0])
+ my_send(uident);
+ return 0;
+}
+
+/* ¸s²Õ±H«H¡B¦^«H : multi_send, multi_reply */
+extern struct word_t *toplev;
+
+static void multi_list(int *reciper) {
+ char uid[16];
+ char genbuf[200];
+
+ while(1) {
+ stand_title("¸s²Õ±H«H¦W³æ");
+ ShowNameList(3, 0, msg_cc);
+ getdata(1, 0,
+ "(I)¤Þ¤J¦n¤Í (O)¤Þ¤J¤W½u³qª¾ (N)¤Þ¤J·s¤å³¹³qª¾ "
+ "(0-9)¤Þ¤J¨ä¥L¯S§O¦W³æ\n"
+ "(A)¼W¥[ (D)§R°£ (M)½T»{±H«H¦W³æ (Q)¨ú®ø ¡H[M]",
+ genbuf, 4, LCECHO);
+ switch(genbuf[0]) {
+ case 'a':
+ while(1) {
+ move(1, 0);
+ usercomplete("½Ð¿é¤J­n¼W¥[ªº¥N¸¹(¥u«ö ENTER µ²§ô·s¼W): ", uid);
+ if(uid[0] == '\0')
+ break;
+
+ move(2, 0);
+ clrtoeol();
+
+ if(!searchuser(uid))
+ outs(err_uid);
+ else if(!InNameList(uid)) {
+ AddNameList(uid);
+ (*reciper)++;
+ }
+ ShowNameList(3, 0, msg_cc);
+ }
+ break;
+ case 'd':
+ while(*reciper) {
+ move(1, 0);
+ namecomplete("½Ð¿é¤J­n§R°£ªº¥N¸¹(¥u«ö ENTER µ²§ô§R°£): ", uid);
+ if(uid[0] == '\0')
+ break;
+ if(RemoveNameList(uid))
+ (*reciper)--;
+ ShowNameList(3, 0, msg_cc);
+ }
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ listfile[5] = genbuf[0];
+ genbuf[0] = '1';
+ case 'i':
+ setuserfile(genbuf, genbuf[0] == '1' ? listfile : fn_overrides);
+ ToggleNameList(reciper, genbuf, msg_cc);
+ break;
+ case 'o':
+ setuserfile(genbuf, "alohaed");
+ ToggleNameList(reciper, genbuf, msg_cc);
+ break;
+ case 'n':
+ setuserfile(genbuf, "postlist");
+ ToggleNameList(reciper, genbuf, msg_cc);
+ break;
+ case 'q':
+ *reciper = 0;
+ return;
+ default:
+ return;
+ }
+ }
+}
+
+static void multi_send(char *title) {
+ FILE *fp;
+ struct word_t *p;
+ fileheader_t mymail;
+ char fpath[TTLEN], *ptr;
+ int reciper, listing;
+ char genbuf[256];
+
+ CreateNameList();
+ listing = reciper = 0;
+ if(*quote_file) {
+ AddNameList(quote_user);
+ reciper = 1;
+ fp = fopen(quote_file, "r");
+ while(fgets(genbuf, 256, fp)) {
+ if(strncmp(genbuf, "¡° ", 3)) {
+ if(listing)
+ break;
+ } else {
+ if(listing) {
+ strtok(ptr = genbuf + 3, " \n\r");
+ do {
+ if(searchuser(ptr) && !InNameList(ptr) &&
+ strcmp(cuser.userid, ptr)) {
+ AddNameList(ptr);
+ reciper++;
+ }
+ } while((ptr = (char *)strtok(NULL, " \n\r")));
+ } else if(!strncmp(genbuf + 3, "[³q§i]", 6))
+ listing = 1;
+ }
+ }
+ ShowNameList(3, 0, msg_cc);
+ }
+
+ multi_list(&reciper);
+ move(1, 0);
+ clrtobot();
+
+ if(reciper) {
+ setutmpmode(SMAIL);
+ if(title)
+ do_reply_title(2, title);
+ else {
+ getdata(2, 0, "¥DÃD¡G", fpath, 64, DOECHO);
+ sprintf(save_title, "[³q§i] %s", fpath);
+ }
+
+ setuserfile(fpath, fn_notes);
+
+ if((fp = fopen(fpath, "w"))) {
+ fprintf(fp, "¡° [³q§i] ¦@ %d ¤H¦¬¥ó", reciper);
+ listing = 80;
+
+ for(p = toplev; p; p = p->next) {
+ reciper = strlen(p->word) + 1;
+ if(listing + reciper > 75) {
+ listing = reciper;
+ fprintf(fp, "\n¡°");
+ } else
+ listing += reciper;
+
+ fprintf(fp, " %s", p->word);
+ }
+ memset(genbuf, '-', 75);
+ genbuf[75] = '\0';
+ fprintf(fp, "\n%s\n\n", genbuf);
+ fclose(fp);
+ }
+
+ curredit |= EDIT_LIST;
+
+ if(vedit(fpath, YEA, NULL) == -1) {
+ unlink(fpath);
+ curredit = 0;
+ outs(msg_cancel);
+ pressanykey();
+ return;
+ }
+
+ stand_title("±H«H¤¤...");
+ refresh();
+
+ listing = 80;
+
+ for(p = toplev; p; p = p->next) {
+ reciper = strlen(p->word) + 1;
+ if(listing + reciper > 75) {
+ listing = reciper;
+ outc('\n');
+ } else {
+ listing += reciper;
+ outc(' ');
+ }
+ outs(p->word);
+ if(searchuser(p->word) && strcmp(STR_GUEST, p->word) )
+ sethomepath(genbuf, p->word);
+ else
+ continue;
+ stampfile(genbuf, &mymail);
+ unlink(genbuf);
+ Link(fpath, genbuf);
+
+ strcpy(mymail.owner, cuser.userid);
+ strcpy(mymail.title, save_title);
+ mymail.savemode = 'M'; /* multi-send flag */
+ sethomedir(genbuf, p->word);
+ if(append_record(genbuf, &mymail, sizeof(mymail)) == -1)
+ outs(err_uid);
+ mailalert(p->word);
+ }
+ hold_mail(fpath, NULL);
+ unlink(fpath);
+ curredit = 0;
+ } else
+ outs(msg_cancel);
+ pressanykey();
+}
+
+static int multi_reply(int ent, fileheader_t *fhdr, char *direct) {
+ if(fhdr->savemode != 'M')
+ return mail_reply(ent, fhdr, direct);
+
+ stand_title("¸s²Õ¦^«H");
+ strcpy(quote_user, fhdr->owner);
+ setuserfile(quote_file, fhdr->filename);
+ multi_send(fhdr->title);
+ return 0;
+}
+
+int mail_list() {
+ stand_title("¸s²Õ§@·~");
+ multi_send(NULL);
+ return 0;
+}
+
+int mail_all() {
+ FILE *fp;
+ fileheader_t mymail;
+ char fpath[TTLEN];
+ char genbuf[200];
+ extern struct uhash_t *uhash;
+ int i, unum;
+ char *userid;
+
+ stand_title("µ¹©Ò¦³¨Ï¥ÎªÌªº¨t²Î³q§i");
+ setutmpmode(SMAIL);
+ getdata(2, 0, "¥DÃD¡G", fpath, 64, DOECHO);
+ sprintf(save_title, "[¨t²Î³q§i]\033[1;32m %s\033[m", fpath);
+
+ setuserfile(fpath, fn_notes);
+
+ if((fp = fopen(fpath, "w"))) {
+ fprintf(fp, "¡° [\033[1m¨t²Î³q§i\033[m] ³o¬O«Êµ¹©Ò¦³¨Ï¥ÎªÌªº«H\n");
+ fprintf(fp, "-----------------------------------------------------"
+ "----------------------\n");
+ fclose(fp);
+ }
+
+ *quote_file = 0;
+
+ curredit |= EDIT_MAIL;
+ curredit &= ~EDIT_ITEM;
+ if(vedit(fpath, YEA, NULL) == -1) {
+ curredit = 0;
+ unlink(fpath);
+ outs(msg_cancel);
+ pressanykey();
+ return 0;
+ }
+ curredit = 0;
+
+ setutmpmode(MAILALL);
+ stand_title("±H«H¤¤...");
+
+ sethomepath(genbuf, cuser.userid);
+ stampfile(genbuf, &mymail);
+ unlink(genbuf);
+ Link(fpath, genbuf);
+ unlink(fpath);
+ strcpy(fpath, genbuf);
+
+ strcpy(mymail.owner, cuser.userid); /*¯¸ªø ID*/
+ strcpy(mymail.title, save_title);
+ mymail.savemode = 0;
+
+ sethomedir(genbuf, cuser.userid);
+ if(append_record(genbuf, &mymail, sizeof(mymail)) == -1)
+ outs(err_uid);
+
+ for(unum = uhash->number, i = 0; i < unum; i++) {
+ if(bad_user_id(uhash->userid[i]))
+ continue; /* Ptt */
+
+ userid = uhash->userid[i];
+ if(strcmp(userid,STR_GUEST) && strcmp(userid, "new") &&
+ strcmp(userid, cuser.userid)) {
+ sethomepath(genbuf, userid);
+ stampfile(genbuf, &mymail);
+ unlink(genbuf);
+ Link(fpath, genbuf);
+
+ strcpy(mymail.owner, cuser.userid);
+ strcpy(mymail.title, save_title);
+ mymail.savemode = 0;
+ /* mymail.filemode |= FILE_MARKED; Ptt ¤½§i§ï¦¨¤£·|mark */
+ sethomedir(genbuf, userid);
+ if(append_record(genbuf, &mymail, sizeof(mymail)) == -1)
+ outs(err_uid);
+ sprintf(genbuf, "%*s %5d / %5d", IDLEN + 1, userid, i + 1, unum);
+ outmsg(genbuf);
+ refresh();
+ }
+ }
+ return 0;
+}
+
+int mail_mbox() {
+ char cmd[100];
+ fileheader_t fhdr;
+
+ sprintf(cmd, "/tmp/%s.uu", cuser.userid);
+ sprintf(fhdr.title, "%s ¨p¤H¸ê®Æ", cuser.userid);
+ doforward(cmd, &fhdr, 'Z');
+ return 0;
+}
+
+static int m_forward(int ent, fileheader_t *fhdr, char *direct) {
+ char uid[STRLEN];
+
+ stand_title("Âà¹F«H¥ó");
+ usercomplete(msg_uid, uid);
+ if(uid[0] == '\0')
+ return FULLUPDATE;
+
+ strcpy(quote_user, fhdr->owner);
+ setuserfile(quote_file, fhdr->filename);
+ sprintf(save_title, "%.64s (fwd)", fhdr->title);
+ move(1, 0);
+ clrtobot();
+ prints("Âà«Hµ¹: %s\n¼Ð ÃD: %s\n", uid, save_title);
+
+ switch(do_send(uid, save_title)) {
+ case -1:
+ outs(err_uid);
+ break;
+ case -2:
+ outs(msg_cancel);
+ break;
+ case -3:
+ prints("¨Ï¥ÎªÌ [%s] µLªk¦¬«H", uid);
+ break;
+ }
+ pressanykey();
+ return FULLUPDATE;
+}
+
+static int delmsgs[128];
+static int delcnt;
+static int mrd;
+
+static int read_new_mail(fileheader_t *fptr) {
+ static int idc;
+ char done = NA, delete_it;
+ char fname[256];
+ char genbuf[4];
+
+ if(fptr == NULL) {
+ delcnt = 0;
+ idc = 0;
+ return 0;
+ }
+ idc++;
+ if(fptr->filemode)
+ return 0;
+ clear();
+ move(10, 0);
+ prints("±z­nŪ¨Ó¦Û[%s]ªº°T®§(%s)¶Ü¡H", fptr->owner, fptr->title);
+ getdata(11, 0, "½Ð±z½T©w(Y/N/Q)?[Y] ", genbuf, 3, DOECHO);
+ if(genbuf[0] == 'q')
+ return QUIT;
+ if(genbuf[0] == 'n')
+ return 0;
+
+ setuserfile(fname, fptr->filename);
+ fptr->filemode |= FILE_READ;
+ if(substitute_record(currmaildir, fptr, sizeof(*fptr), idc))
+ return -1;
+
+ mrd = 1;
+ delete_it = NA;
+ while(!done) {
+ int more_result = more(fname, YEA);
+
+ switch(more_result) {
+ case 1:
+ return READ_PREV;
+ case 2:
+ return RELATE_PREV;
+ case 3:
+ return READ_NEXT;
+ case 4:
+ return RELATE_NEXT;
+ case 5:
+ return RELATE_FIRST;
+ case 6:
+ return 0;
+ case 7:
+ mail_reply(idc, fptr, currmaildir);
+ return FULLUPDATE;
+ case 8:
+ multi_reply(idc, fptr, currmaildir);
+ return FULLUPDATE;
+ }
+ move(b_lines, 0);
+ clrtoeol();
+ outs(msg_mailer);
+ refresh();
+
+ switch(egetch()) {
+ case 'r':
+ case 'R':
+ mail_reply(idc, fptr, currmaildir);
+ break;
+ case 'x':
+ m_forward(idc, fptr, currmaildir);
+ break;
+ case 'y':
+ multi_reply(idc, fptr, currmaildir);
+ break;
+ case 'd':
+ case 'D':
+ delete_it = YEA;
+ default:
+ done = YEA;
+ }
+ }
+ if(delete_it) {
+ clear();
+ prints("§R°£«H¥ó¡m%s¡n", fptr->title);
+ getdata(1, 0, msg_sure_ny, genbuf, 2, LCECHO);
+ if(genbuf[0] == 'y') {
+ unlink(fname);
+ delmsgs[delcnt++] = idc;
+ }
+ }
+ clear();
+ return 0;
+}
+
+int m_new() {
+ clear();
+ mrd = 0;
+ setutmpmode(RMAIL);
+ read_new_mail(NULL);
+ clear();
+ curredit |= EDIT_MAIL;
+ curredit &= ~EDIT_ITEM;
+ if(apply_record(currmaildir, read_new_mail, sizeof(fileheader_t)) == -1) {
+ outs("¨S¦³·s«H¥ó¤F");
+ pressanykey();
+ return -1;
+ }
+ curredit = 0;
+ if(delcnt) {
+ while(delcnt--)
+ delete_record(currmaildir, sizeof(fileheader_t), delmsgs[delcnt]);
+ }
+ outs(mrd ? "«H¤w¾\\²¦" : "¨S¦³·s«H¥ó¤F");
+ pressanykey();
+ return -1;
+}
+
+static void mailtitle() {
+ char buf[256] = "";
+
+ showtitle("\0¶l¥ó¿ï³æ", BBSName);
+ sprintf(buf,"[¡ö]Â÷¶}[¡ô¡õ]¿ï¾Ü[¡÷]¾\\Ū«H¥ó [R]¦^«H [x]Âà¹F "
+ "[y]¸s²Õ¦^«H [O]¯¸¥~«H:%s [h]¨D§U\n\033[7m"
+ "½s¸¹ ¤é ´Á §@ ªÌ «H ¥ó ¼Ð ÃD \033[32m",
+ HAS_PERM(PERM_NOOUTMAIL)? "\033[31mÃö\033[m":"¶}");
+ outs(buf);
+ buf[0]=0;
+ if(mailsumlimit) {
+ sprintf(buf,"(®e¶q:%d/%dk %d/%d½g)", mailsum, mailsumlimit,
+ mailkeep, mailmaxkeep);
+ }
+ sprintf(buf, "%s%*s\033[m", buf, 29 - (int) strlen(buf), "");
+ outs(buf);
+}
+
+static void maildoent(int num, fileheader_t *ent) {
+ char *title, *mark, color, type = "+ Mm"[ent->filemode];
+
+ if (TagNum && !Tagger(atoi(ent->filename + 2), 0, TAG_NIN))
+ type = 'D';
+
+ title = subject(mark = ent->title);
+ if(title == mark) {
+ color = '1';
+ mark = "¡º";
+ } else {
+ color = '3';
+ mark = "R:";
+ }
+
+ if(strncmp(currtitle, title, 40))
+ prints("%5d %c %-7s%-15.14s%s %.46s\n", num, type,
+ ent->date, ent->owner, mark, title);
+ else
+ prints("%5d %c %-7s%-15.14s\033[1;3%cm%s %.46s\033[0m\n", num, type,
+ ent->date, ent->owner, color, mark, title);
+}
+
+#ifdef POSTBUG
+extern int bug_possible;
+#endif
+
+
+static int m_idle(int ent, fileheader_t *fhdr, char *direct) {
+ t_idle();
+ return FULLUPDATE;
+}
+
+static int mail_del(int ent, fileheader_t *fhdr, char *direct) {
+ char genbuf[200];
+
+ if(fhdr->filemode & FILE_MARKED)
+ return DONOTHING;
+
+ getdata(1, 0, msg_del_ny, genbuf, 3, LCECHO);
+ if(genbuf[0] == 'y') {
+ strcpy(currfile, fhdr->filename);
+ if(!delete_file(direct, sizeof(*fhdr), ent, cmpfilename)) {
+ setdirpath(genbuf, direct, fhdr->filename);
+ unlink(genbuf);
+ if((currmode & MODE_SELECT)) {
+ int now;
+
+ sethomedir(genbuf, cuser.userid);
+ now = getindex(genbuf, fhdr->filename, sizeof(fileheader_t));
+ delete_file(genbuf, sizeof(fileheader_t), now, cmpfilename);
+ }
+ return DIRCHANGED;
+ }
+ }
+ return FULLUPDATE;
+}
+
+static int mail_read(int ent, fileheader_t *fhdr, char *direct) {
+ char buf[64];
+ char done, delete_it, replied;
+
+ clear();
+ setdirpath(buf, direct, fhdr->filename);
+ strncpy(currtitle, subject(fhdr->title), 40);
+ done = delete_it = replied = NA;
+ while(!done) {
+ int more_result = more(buf, YEA);
+
+ if(more_result != -1) {
+ fhdr->filemode |= FILE_READ;
+ if((currmode & MODE_SELECT)) {
+ int now;
+
+ now = getindex(currmaildir, fhdr->filename,
+ sizeof(fileheader_t));
+ substitute_record(currmaildir, fhdr, sizeof(*fhdr), now);
+ substitute_record(direct, fhdr, sizeof(*fhdr), ent);
+ }
+ else
+ substitute_record(currmaildir, fhdr, sizeof(*fhdr), ent);
+ }
+ switch(more_result) {
+ case 1:
+ return READ_PREV;
+ case 2:
+ return RELATE_PREV;
+ case 3:
+ return READ_NEXT;
+ case 4:
+ return RELATE_NEXT;
+ case 5:
+ return RELATE_FIRST;
+ case 6:
+ return FULLUPDATE;
+ case 7:
+ mail_reply(ent, fhdr, direct);
+ return FULLUPDATE;
+ case 8:
+ multi_reply(ent, fhdr, direct);
+ return FULLUPDATE;
+ }
+ move(b_lines, 0);
+ clrtoeol();
+ refresh();
+ outs(msg_mailer);
+
+ switch(egetch()) {
+ case 'r':
+ case 'R':
+ replied = YEA;
+ mail_reply(ent, fhdr, direct);
+ break;
+ case 'x':
+ m_forward(ent, fhdr, direct);
+ break;
+ case 'y':
+ multi_reply(ent, fhdr, direct);
+ break;
+ case 'd':
+ delete_it = YEA;
+ default:
+ done = YEA;
+ }
+ }
+ if(delete_it)
+ mail_del(ent, fhdr, direct);
+ else {
+ fhdr->filemode |= FILE_READ;
+#ifdef POSTBUG
+ if(replied)
+ bug_possible = YEA;
+#endif
+ if((currmode & MODE_SELECT)) {
+ int now;
+
+ now = getindex(currmaildir, fhdr->filename, sizeof(fileheader_t));
+ substitute_record(currmaildir, fhdr, sizeof(*fhdr), now);
+ substitute_record(direct, fhdr, sizeof(*fhdr), ent);
+ } else
+ substitute_record(currmaildir, fhdr, sizeof(*fhdr), ent);
+#ifdef POSTBUG
+ bug_possible = NA;
+#endif
+ }
+ return FULLUPDATE;
+}
+
+/* in boards/mail ¦^«Hµ¹­ì§@ªÌ¡AÂà«H¯¸¥ç¥i */
+int mail_reply(int ent, fileheader_t *fhdr, char *direct) {
+ char uid[STRLEN];
+ char *t;
+ FILE *fp;
+ char genbuf[512];
+
+ stand_title("¦^ «H");
+
+ /* §PÂ_¬O boards ©Î mail */
+ if(curredit & EDIT_MAIL)
+ setuserfile(quote_file, fhdr->filename);
+ else
+ setbfile(quote_file, currboard, fhdr->filename);
+
+ /* find the author */
+ strcpy(quote_user, fhdr->owner);
+ if(strchr(quote_user, '.')) {
+ genbuf[0] = '\0';
+ if((fp = fopen(quote_file, "r"))) {
+ fgets(genbuf, 512, fp);
+ fclose(fp);
+ }
+
+ t = strtok(genbuf, str_space);
+ if(!strcmp(t, str_author1) || !strcmp(t, str_author2))
+ strcpy(uid, strtok(NULL, str_space));
+ else {
+ outs("¿ù»~: §ä¤£¨ì§@ªÌ¡C");
+ pressanykey();
+ return FULLUPDATE;
+ }
+ } else
+ strcpy(uid, quote_user);
+
+ /* make the title */
+ do_reply_title(3, fhdr->title);
+ prints("\n¦¬«H¤H: %s\n¼Ð ÃD: %s\n", uid, save_title);
+
+ /* edit, then send the mail */
+ ent = curredit;
+ switch(do_send(uid, save_title)) {
+ case -1:
+ outs(err_uid);
+ break;
+ case -2:
+ outs(msg_cancel);
+ break;
+ case -3:
+ prints("¨Ï¥ÎªÌ [%s] µLªk¦¬«H", uid);
+ break;
+ }
+ curredit = ent;
+ pressanykey();
+ return FULLUPDATE;
+}
+
+static int mail_edit(int ent, fileheader_t *fhdr, char *direct) {
+ char genbuf[200];
+
+ if(!HAS_PERM(PERM_SYSOP) &&
+ strcmp(cuser.userid, fhdr->owner) &&
+ strcmp("[³Æ.§Ñ.¿ý]", fhdr->owner))
+ return DONOTHING;
+
+ setdirpath(genbuf, direct, fhdr->filename);
+ vedit(genbuf, NA, NULL);
+ return FULLUPDATE;
+}
+
+static int mail_nooutmail(int ent, fileheader_t *fhdr, char *direct)
+{
+ cuser.userlevel ^= PERM_NOOUTMAIL;
+ passwd_update(usernum, &cuser);
+ return FULLUPDATE;
+
+}
+
+static int mail_mark(int ent, fileheader_t *fhdr, char *direct) {
+ fhdr->filemode ^= FILE_MARKED;
+
+ if((currmode & MODE_SELECT)) {
+ int now;
+
+ now = getindex(currmaildir, fhdr->filename, sizeof(fileheader_t));
+ substitute_record(currmaildir, fhdr, sizeof(*fhdr), now);
+ substitute_record(direct, fhdr, sizeof(*fhdr), ent);
+ } else
+ substitute_record(currmaildir, fhdr, sizeof(*fhdr), ent);
+ return PART_REDRAW;
+}
+
+/* help for mail reading */
+static char *mail_help[] = {
+ "\0¹q¤l«H½c¾Þ§@»¡©ú",
+ "\01°ò¥»©R¥O",
+ "(p)(¡ô) «e¤@½g¤å³¹",
+ "(n)(¡õ) ¤U¤@½g¤å³¹",
+ "(P)(PgUp) «e¤@­¶",
+ "(N)(PgDn) ¤U¤@­¶",
+ "(##)(cr) ¸õ¨ì²Ä ## µ§",
+ "($) ¸õ¨ì³Ì«á¤@µ§",
+ "\01¶i¶¥©R¥O",
+ "(r)(¡÷)/(R)Ū«H / ¦^«H",
+ "(O) Ãö³¬/¶}±Ò ¯¸¥~«H¥óÂà¤J",
+ "(c/z) ¦¬¤J¦¹«H¥ó¶i¤J¨p¤H«H¥ó§¨/¶i¤J¨p¤H«H¥ó§¨",
+ "(x/X) Âà¹F«H¥ó/Âà¿ý¤å³¹¨ì¨ä¥L¬ÝªO",
+ "(y) ¸s²Õ¦^«H",
+ "(F) ±N«H¶Ç°e¦^±zªº¹q¤l«H½c (u)¤ô²y¾ã²z±H¦^«H½c",
+ "(d) ±þ±¼¦¹«H",
+ "(D) ±þ±¼«ü©w½d³òªº«H",
+ "(m) ±N«H¼Ð°O¡A¥H¨¾³Q²M°£",
+ "(^G) ¥ß§Y­««Ø«H½c («H½c·´·l®É¥Î)",
+ "(t) ¼Ð°O±ý§R°£«H¥ó",
+ "(^D) §R°£¤w¼Ð°O«H¥ó",
+ NULL
+};
+
+static int m_help() {
+ show_help(mail_help);
+ return FULLUPDATE;
+}
+
+static int mail_cross_post(int ent, fileheader_t *fhdr, char *direct) {
+ char xboard[20], fname[80], xfpath[80], xtitle[80], inputbuf[10];
+ fileheader_t xfile;
+ FILE *xptr;
+ int author = 0;
+ char genbuf[200];
+ char genbuf2[4];
+
+ make_blist();
+ move(2, 0);
+ clrtoeol();
+ move(3, 0);
+ clrtoeol();
+ move(1, 0);
+ namecomplete("Âà¿ý¥»¤å³¹©ó¬ÝªO¡G", xboard);
+ if(*xboard == '\0' || !haspostperm(xboard))
+ return FULLUPDATE;
+
+ ent = 1;
+ if(HAS_PERM(PERM_SYSOP) || !strcmp(fhdr->owner, cuser.userid)) {
+ getdata(2, 0, "(1)­ì¤åÂà¸ü (2)ÂÂÂà¿ý®æ¦¡¡H[1] ",
+ genbuf, 3, DOECHO);
+ if(genbuf[0] != '2') {
+ ent = 0;
+ getdata(2, 0, "«O¯d­ì§@ªÌ¦WºÙ¶Ü?[Y] ", inputbuf, 3, DOECHO);
+ if(inputbuf[0] != 'n' && inputbuf[0] != 'N')
+ author = 1;
+ }
+ }
+
+ if(ent)
+ sprintf(xtitle, "[Âà¿ý]%.66s", fhdr->title);
+ else
+ strcpy(xtitle, fhdr->title);
+
+ sprintf(genbuf, "±Ä¥Î­ì¼ÐÃD¡m%.60s¡n¶Ü?[Y] ", xtitle);
+ getdata(2, 0, genbuf, genbuf2, 4, LCECHO);
+ if(*genbuf2 == 'n')
+ if(getdata(2, 0, "¼ÐÃD¡G", genbuf, TTLEN, DOECHO))
+ strcpy(xtitle, genbuf);
+
+ getdata(2, 0, "(S)¦sÀÉ (L)¯¸¤º (Q)¨ú®ø¡H[Q] ", genbuf, 3, LCECHO);
+ if(genbuf[0] == 'l' || genbuf[0] == 's') {
+ int currmode0 = currmode;
+
+ currmode = 0;
+ setbpath(xfpath, xboard);
+ stampfile(xfpath, &xfile);
+ if(author)
+ strcpy(xfile.owner, fhdr->owner);
+ else
+ strcpy(xfile.owner, cuser.userid);
+ strcpy(xfile.title, xtitle);
+ if(genbuf[0] == 'l') {
+ xfile.savemode = 'L';
+ xfile.filemode = FILE_LOCAL;
+ } else
+ xfile.savemode = 'S';
+
+ setuserfile(fname, fhdr->filename);
+ if(ent) {
+ xptr = fopen(xfpath, "w");
+
+ strcpy(save_title, xfile.title);
+ strcpy(xfpath, currboard);
+ strcpy(currboard, xboard);
+ write_header(xptr);
+ strcpy(currboard, xfpath);
+
+ fprintf(xptr, "¡° [¥»¤åÂà¿ý¦Û %s «H½c]\n\n", cuser.userid);
+
+ b_suckinfile(xptr, fname);
+ addsignature(xptr,0);
+ fclose(xptr);
+ } else {
+ unlink(xfpath);
+ Link(fname, xfpath);
+ }
+
+ setbdir(fname, xboard);
+ append_record(fname, &xfile, sizeof(xfile));
+ setbtotal(getbnum(xboard));
+ if(!xfile.filemode)
+ outgo_post(&xfile, xboard);
+ cuser.numposts++;
+ passwd_update(usernum, &cuser);
+ outs("¤å³¹Âà¿ý§¹¦¨");
+ pressanykey();
+ currmode = currmode0;
+ }
+ return FULLUPDATE;
+}
+
+int mail_man() {
+ char buf[64],buf1[64];
+ if (HAS_PERM(PERM_MAILLIMIT)) {
+ int mode0 = currutmp->mode;
+ int stat0 = currstat;
+
+ sethomeman(buf, cuser.userid);
+ sprintf(buf1, "%s ªº«H¥ó§¨", cuser.userid);
+ a_menu(buf1, buf, 1);
+ currutmp->mode = mode0;
+ currstat = stat0;
+ return FULLUPDATE;
+ }
+ return DONOTHING;
+}
+
+static int mail_cite(int ent, fileheader_t *fhdr, char *direct) {
+ char fpath[256];
+ char title[TTLEN + 1];
+ static char xboard[20];
+ char buf[20];
+ boardheader_t *bp;
+
+ setuserfile(fpath, fhdr->filename);
+ strcpy(title, "¡º ");
+ strncpy(title+3, fhdr->title, TTLEN-3);
+ title[TTLEN] = '\0';
+ a_copyitem(fpath, title, 0, 1);
+
+ if(cuser.userlevel >= PERM_BM) {
+ move(2, 0);
+ clrtoeol();
+ move(3, 0);
+ clrtoeol();
+ move(1, 0);
+ make_blist();
+ namecomplete("¿é¤J¬Ýª©¦WºÙ (ª½±µEnter¶i¤J¨p¤H«H¥ó§¨)¡G", buf);
+ if(*buf)
+ strcpy(xboard, buf);
+ if(*xboard && (bp = getbcache(getbnum(xboard)))) {
+ setapath(fpath, xboard);
+ setutmpmode(ANNOUNCE);
+ a_menu(xboard, fpath, HAS_PERM(PERM_ALLBOARD) ? 2 :
+ is_BM(bp->BM) ? 1 : 0);
+ } else {
+ mail_man();
+ }
+ return FULLUPDATE;
+ } else {
+ mail_man();
+ return FULLUPDATE;
+ }
+}
+
+static int mail_save(int ent, fileheader_t *fhdr, char *direct) {
+ char fpath[256];
+ char title[TTLEN+1];
+
+ if(HAS_PERM(PERM_MAILLIMIT)) {
+ setuserfile(fpath, fhdr->filename);
+ strcpy(title, "¡º ");
+ strncpy(title + 3, fhdr->title, TTLEN - 3);
+ title[TTLEN] = '\0';
+ a_copyitem(fpath, title, fhdr->owner, 1);
+ sethomeman(fpath, cuser.userid);
+ a_menu(cuser.userid, fpath, 1);
+ return FULLUPDATE;
+ }
+ return DONOTHING;
+}
+
+#ifdef OUTJOBSPOOL
+static int mail_waterball(int ent, fileheader_t *fhdr, char *direct)
+{
+ static char address[60], cmode = 1;
+ char fname[500], genbuf[200];
+ FILE *fp;
+ int now;
+
+ if(!address[0])
+ strcpy(address, cuser.email);
+ if(address[0]) {
+ sprintf(genbuf, "±Hµ¹ [%s] ¶Ü(Y/N/Q)¡H[Y] ", address);
+ getdata(b_lines - 2, 0, genbuf, fname, 3, LCECHO);
+ if(fname[0] == 'q') { outmsg("¨ú®ø³B²z"); return 1; }
+ if(fname[0] == 'n')
+ address[0] = '\0';
+ }
+
+ if(!address[0]) {
+ getdata(b_lines - 2, 0, "½Ð¿é¤J¶l¥ó¦a§}¡G", fname, 60, DOECHO);
+ if(fname[0] && strchr(fname, '.')) {
+ strcpy(address, fname);
+ } else {
+ outmsg("¨ú®ø³B²z");
+ return 1;
+ }
+ }
+ if(invalidaddr(address))
+ return -2;
+
+ // sprintf(fname, "%d\n", cmode);
+ getdata(b_lines - 1, 0, "¨Ï¥Î¼Ò¦¡(0/1)? [1]", fname, 3, LCECHO);
+ cmode = (fname[0] != '0' && fname[0] != '1') ? 1 : fname[0] - '0';
+
+ now = time(NULL);
+ sprintf(fname, BBSHOME "/jobspool/water.src.%s-%d",
+ cuser.userid, now);
+ sprintf(genbuf, "cp " BBSHOME "/home/%c/%s/%s %s",
+ cuser.userid[0], cuser.userid, fhdr->filename, fname);
+ system(genbuf);
+ /* dirty code ;x */
+ sprintf(fname, BBSHOME "/jobspool/water.des.%s-%d",
+ cuser.userid, now);
+ fp = fopen(fname, "wt");
+ fprintf(fp, "%s\n%s\n%d\n", cuser.userid, address, cmode);
+ fclose(fp);
+ return FULLUPDATE;
+}
+#endif
+static struct onekey_t mail_comms[] = {
+ {'z', mail_man},
+ {'c', mail_cite},
+ {'s', mail_save},
+ {'d', mail_del},
+ {'D', del_range},
+ {'r', mail_read},
+ {'R', mail_reply},
+ {'E', mail_edit},
+ {'m', mail_mark},
+ {'O', mail_nooutmail},
+ {'T', edit_title},
+ {'x', m_forward},
+ {'X', mail_cross_post},
+ {Ctrl('G'), built_mail_index}, /* ­×«H½c */
+ {'y', multi_reply},
+ {Ctrl('I'), m_idle},
+ {'h', m_help},
+#ifdef OUTJOBSPOOL
+ {'u', mail_waterball},
+#endif
+ {'\0', NULL}
+};
+
+int m_read() {
+ if(get_num_records(currmaildir, sizeof(fileheader_t))) {
+ curredit = EDIT_MAIL;
+ curredit &= ~EDIT_ITEM;
+ i_read(RMAIL, currmaildir, mailtitle, maildoent, mail_comms, -1);
+ curredit = 0;
+ currutmp->mailalert = load_mailalert(cuser.userid);
+ return 0;
+ } else {
+ outs("±z¨S¦³¨Ó«H");
+ return XEASY;
+ }
+}
+
+/* ±H¯¸¤º«H */
+static int send_inner_mail(char *fpath, char *title, char *receiver) {
+ char genbuf[256];
+ fileheader_t mymail;
+
+ if(!searchuser(receiver))
+ return -2;
+ sethomepath(genbuf, receiver);
+ stampfile(genbuf, &mymail);
+ if(!strcmp(receiver, cuser.userid)) {
+ strcpy(mymail.owner, "[" BBSNAME "]");
+ mymail.filemode = FILE_READ;
+ } else
+ strcpy(mymail.owner, cuser.userid);
+ strncpy(mymail.title, title, TTLEN);
+ unlink(genbuf);
+ Link(fpath, genbuf);
+ sethomedir(genbuf, receiver);
+ return do_append(genbuf, &mymail, sizeof(mymail));
+}
+
+#include <netdb.h>
+#include <pwd.h>
+#include <time.h>
+
+#ifndef USE_BSMTP
+static int bbs_sendmail(char *fpath, char *title, char *receiver) {
+ static int configured = 0;
+ static char myhostname[STRLEN];
+ static char myusername[20];
+ struct hostent *hbuf;
+ struct passwd *pbuf;
+ char *ptr;
+ char genbuf[256];
+ FILE *fin, *fout;
+
+ /* ¤¤³~ÄdºI */
+ if((ptr = strchr(receiver, ';'))) {
+ struct tm *ptime;
+ time_t now;
+
+ *ptr = '\0';
+ }
+
+ if((ptr = strstr(receiver, str_mail_address)) || !strchr(receiver,'@')) {
+ char hacker[20];
+ int len;
+
+ if(strchr(receiver,'@')) {
+ len = ptr - receiver;
+ memcpy(hacker, receiver, len);
+ hacker[len] = '\0';
+ } else
+ strcpy(hacker,receiver);
+ return send_inner_mail(fpath, title, hacker);
+ }
+
+ /* setup the hostname and username */
+ if(!configured) {
+ /* get host name */
+ hbuf = gethostbyname("localhost");
+ if(hbuf)
+ strncpy(myhostname, hbuf->h_name, STRLEN);
+
+ /* get bbs uident */
+ pbuf = getpwuid(getuid());
+ if(pbuf)
+ strncpy(myusername, pbuf->pw_name, 20);
+ if(hbuf && pbuf)
+ configured = 1;
+ else
+ return -1;
+ }
+
+ /* Running the sendmail */
+ if(fpath == NULL) {
+ sprintf(genbuf, "/usr/sbin/sendmail %s > /dev/null", receiver);
+ fin = fopen("etc/confirm", "r");
+ } else {
+ sprintf(genbuf, "/usr/sbin/sendmail -f %s%s %s > /dev/null",
+ cuser.userid, str_mail_address, receiver);
+ fin = fopen(fpath, "r");
+ }
+ fout = popen(genbuf, "w");
+ if(fin == NULL || fout == NULL)
+ return -1;
+
+ if(fpath)
+ fprintf(fout, "Reply-To: %s%s\nFrom: %s%s\n",
+ cuser.userid, str_mail_address, cuser.userid,
+ str_mail_address);
+ fprintf(fout, "To: %s\nSubject: %s\n", receiver, title);
+ fprintf(fout, "X-Disclaimer: " BBSNAME "¹ï¥»«H¤º®e®¤¤£­t³d¡C\n\n");
+
+ while(fgets(genbuf, 255, fin)) {
+ if(genbuf[0] == '.' && genbuf[1] == '\n')
+ fputs(". \n", fout);
+ else
+ fputs(genbuf, fout);
+ }
+ fclose(fin);
+ fprintf(fout, ".\n");
+ pclose(fout);
+ return 0;
+}
+#else /* USE_BSMTP */
+
+int bsmtp(char *fpath, char *title, char *rcpt, int method) {
+ char buf[80], *ptr;
+ time_t chrono;
+ MailQueue mqueue;
+
+ /* check if the mail is a inner mail */
+ if((ptr = strstr(rcpt, str_mail_address)) || !strchr(rcpt, '@')) {
+ char hacker[20];
+ int len;
+
+ if(strchr(rcpt,'@')) {
+ len = ptr - rcpt;
+ memcpy(hacker, rcpt, len);
+ hacker[len] = '\0';
+ } else
+ strcpy(hacker, rcpt);
+ return send_inner_mail(fpath, title, hacker);
+ }
+
+ chrono = time(NULL);
+ if(method != MQ_JUSTIFY) { /* »{ÃÒ«H */
+ /* stamp the queue file */
+ strcpy(buf, "out/");
+ for(;;) {
+ sprintf(buf + 4,"M.%ld.A", ++chrono);
+ if(!dashf(buf)) {
+ Link(fpath, buf);
+ break;
+ }
+ }
+
+ fpath = buf;
+
+ strcpy(mqueue.filepath, fpath);
+ strcpy(mqueue.subject, title);
+ }
+ /* setup mail queue */
+ mqueue.mailtime = chrono;
+ mqueue.method = method;
+ strcpy(mqueue.sender, cuser.userid);
+ strcpy(mqueue.username, cuser.username);
+ strcpy(mqueue.rcpt, rcpt);
+ if(do_append("out/.DIR", (fileheader_t *)&mqueue, sizeof(mqueue)) < 0)
+ return 0;
+ return chrono;
+}
+#endif /* USE_BSMTP */
+
+int doforward(char *direct, fileheader_t *fh, int mode) {
+ static char address[60];
+ char fname[500];
+ int return_no;
+ char genbuf[200];
+
+ if(!address[0])
+ strcpy(address, cuser.email);
+
+ if(address[0]) {
+ sprintf(genbuf, "½T©wÂà±Hµ¹ [%s] ¶Ü(Y/N/Q)¡H[Y] ", address);
+ getdata(b_lines - 1, 0, genbuf, fname, 3, LCECHO);
+
+ if(fname[0] == 'q') {
+ outmsg("¨ú®øÂà±H");
+ return 1;
+ }
+ if(fname[0] == 'n')
+ address[0] = '\0';
+ }
+
+ if(!address[0]) {
+ do{
+ getdata(b_lines - 1, 0, "½Ð¿é¤JÂà±H¦a§}¡G", fname, 60, DOECHO);
+ if(fname[0]) {
+ if(strchr(fname, '.'))
+ strcpy(address, fname);
+ else
+ sprintf(address, "%s.bbs@%s", fname, MYHOSTNAME);
+ } else {
+ outmsg("¨ú®øÂà±H");
+ return 1;
+ }
+ }while(mode=='Z' && strstr(address, MYHOSTNAME));
+ }
+ if(invalidaddr(address))
+ return -2;
+
+ sprintf(fname, "¥¿Âà±Hµ¹ %s, ½Ðµy­Ô...", address);
+ outmsg(fname);
+ move(b_lines - 1, 0);
+ refresh();
+
+ /* °lÂÜ¨Ï¥ÎªÌ */
+ if(HAS_PERM(PERM_LOGUSER)) {
+ time_t now = time(NULL);
+ char msg[200];
+
+ sprintf(msg, "%s mailforward to %s at %s",
+ cuser.userid, address, Cdate(&now));
+ log_user(msg);
+ }
+
+ if(mode == 'Z') {
+ sprintf(fname, TAR_PATH " cfz - home/%c/%s | "
+ "/usr/bin/uuencode %s.tgz > %s",
+ cuser.userid[0], cuser.userid, cuser.userid, direct);
+ system(fname);
+ strcpy(fname, direct);
+ } else if(mode == 'U') {
+ char tmp_buf[128];
+
+ sprintf(fname, "/tmp/bbs.uu%05d", currpid);
+ sprintf(tmp_buf, "/usr/bin/uuencode %s/%s uu.%05d > %s",
+ direct, fh->filename, currpid, fname);
+ system(tmp_buf);
+ } else if (mode == 'F'){
+ char tmp_buf[128];
+
+ sprintf(fname, "/tmp/bbs.f%05d", currpid);
+ sprintf(tmp_buf, "cp %s/%s %s",direct,fh->filename,fname);
+ system(tmp_buf);
+ } else
+ return -1;
+
+ return_no =
+#ifndef USE_BSMTP
+ bbs_sendmail(fname, fh->title, address);
+#else
+ bsmtp(fname, fh->title, address,mode);
+#endif
+ unlink(fname);
+ return (return_no);
+}
+
+int load_mailalert(char *userid) {
+ struct stat st;
+ char maildir[256];
+ int fd;
+ register int numfiles;
+ fileheader_t my_mail;
+
+ sethomedir(maildir, userid);
+ if(!HAS_PERM(PERM_BASIC))
+ return 0;
+ if(stat(maildir, &st) < 0)
+ return 0;
+ numfiles = st.st_size / sizeof(fileheader_t);
+ if(numfiles <= 0)
+ return 0;
+
+ /* ¬Ý¬Ý¦³¨S¦³«H¥óÁÙ¨SŪ¹L¡H±qÀɧÀ¦^ÀYÀˬd¡A®Ä²v¸û°ª */
+ if((fd = open(maildir, O_RDONLY)) > 0) {
+ lseek(fd, st.st_size - sizeof(fileheader_t), SEEK_SET);
+ while(numfiles--) {
+ read(fd, &my_mail, sizeof(fileheader_t));
+ if(!(my_mail.filemode & FILE_READ)) {
+ close(fd);
+ return 1;
+ }
+ lseek(fd, -(off_t)2 * sizeof(fileheader_t), SEEK_CUR);
+ }
+ close(fd);
+ }
+ return 0;
+}
+
+#ifdef EMAIL_JUSTIFY
+static void mail_justify(userec_t muser) {
+ fileheader_t mhdr;
+ char title[128], buf1[80];
+ FILE* fp;
+
+ sethomepath(buf1, muser.userid);
+ stampfile(buf1, &mhdr);
+ unlink(buf1);
+ strcpy(mhdr.owner, cuser.userid);
+ strncpy(mhdr.title, "[¼f®Ö³q¹L]", TTLEN);
+ mhdr.savemode = 0;
+ mhdr.filemode = 0;
+
+ if(valid_ident(muser.email) && !invalidaddr(muser.email)) {
+ char title[80], *ptr;
+ unsigned short checksum; /* 16-bit is enough */
+ char ch;
+
+ checksum = searchuser(muser.userid);
+ ptr = muser.email;
+ while((ch = *ptr++)) {
+ if(ch <= ' ')
+ break;
+ if(ch >= 'A' && ch <= 'Z')
+ ch |= 0x20;
+ checksum = (checksum << 1) ^ ch;
+ }
+
+ sprintf(title, "[PTT BBS]To %s(%d:%d) [User Justify]",
+ muser.userid, getuser(muser.userid) + MAGIC_KEY, checksum);
+ if(
+#ifndef USE_BSMTP
+ bbs_sendmail(NULL, title, muser.email)
+#else
+ bsmtp(NULL, title, muser.email, MQ_JUSTIFY);
+#endif
+ < 0)
+ Link("etc/bademail", buf1);
+ else
+ Link("etc/replyemail", buf1);
+ } else
+ Link("etc/bademail", buf1);
+ sethomedir(title, muser.userid);
+ append_record(title, &mhdr, sizeof(mhdr));
+}
+#endif /* EMAIL_JUSTIFY */
diff --git a/mbbsd/mbbsd.c b/mbbsd/mbbsd.c
new file mode 100644
index 00000000..c4849da5
--- /dev/null
+++ b/mbbsd/mbbsd.c
@@ -0,0 +1,1465 @@
+/* $Id: mbbsd.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <errno.h>
+#include <netdb.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/telnet.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "perm.h"
+#include "modes.h"
+#include "proto.h"
+#ifdef FreeBSD
+ #include <machine/limits.h>
+#else
+ #include <limits.h>
+#endif
+
+#define SOCKET_QLEN 4
+#define TH_LOW 100
+#define TH_HIGH 120
+
+extern int t_lines, t_columns; /* Screen size / width */
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+extern userinfo_t *currutmp;
+extern int curr_idle_timeout;
+
+static void do_aloha (char *hello);
+
+static jmp_buf byebye;
+
+int talkrequest = NA;
+
+static char remoteusername[40] = "?";
+
+extern struct fromcache_t *fcache;
+extern struct utmpfile_t *utmpshm;
+extern int fcache_semid;
+
+static unsigned char enter_uflag;
+static int use_shell_login_mode = 0;
+
+char fromhost[STRLEN] = "\0";
+
+static struct sockaddr_in xsin;
+
+/* set signal handler, which won't be reset once signal comes */
+static void
+signal_restart (int signum, void (*handler) (int))
+{
+ struct sigaction act;
+ act.sa_handler = handler;
+ memset (&(act.sa_mask), 0, sizeof (sigset_t));
+ act.sa_flags = 0;
+ sigaction (signum, &act, NULL);
+}
+
+static void
+start_daemon ()
+{
+ int n;
+ char buf[80];
+
+ /*
+ * 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 = time (NULL);
+ struct tm *dummy_time = localtime (&dummy);
+
+ strftime (buf, 80, "%d/%b/%Y:%H:%M:%S", dummy_time);
+
+ if ((n = fork ())){
+ exit (0);
+ }
+
+ /* rocker.011018: it's a good idea to close all unexcept fd!! */
+ n = getdtablesize ();
+ while (n)
+ close (--n);
+ /* rocker.011018: we don't need to remember original tty,
+ so request a new session id */
+ setsid ();
+
+ /* rocker.011018: after new session,
+ we should insure the process is clean daemon */
+ if ((n = fork ())){
+ exit (0);
+ }
+}
+
+static void
+reapchild (int sig)
+{
+ int state, pid;
+
+ while ((pid = waitpid (-1, &state, WNOHANG | WUNTRACED)) > 0)
+ ;
+}
+
+#define BANNER \
+"¡i" BBSNAME "¡j¡· ¥x¤j¬y¦æºô ¡·(" MYHOSTNAME ") ½Õ´T(" MYIP ") "
+/*
+#define BANNER \
+"¡i" BBSNAME "¡j¡· ¥x¤j¬y¦æºô ¡·(" MYHOSTNAME ")\r\n"\
+" ½Õ´T(" MYIP ") "
+*/
+/* check load and print approriate banner string in buf */
+static int
+chkload (char *buf)
+{
+ char cpu_load[30];
+ int i;
+
+ i = cpuload (cpu_load);
+
+ sprintf (buf, BANNER" ¨t²Î­t²ü\r\n %s %s \r\n", cpu_load,
+ (i > MAX_CPULOAD ? "¡A°ª­t²ü¶q¡A½Ðµy«á¦A¨Ó "
+ "(½Ð§Q¥Îport 3000~3010³s½u)" : ""));
+#ifdef INSCREEN
+ strcpy(buf, (i > MAX_CPULOAD ? BANNER
+ "°ª­t²ü¶q¡A½Ðµy«á¦A¨Ó(½Ð§Q¥Îport 3000~3010³s½u)" : ""));
+#else
+ sprintf(buf, BANNER "%s\r\n",
+ (i > MAX_CPULOAD ? "°ª­t²ü¶q¡A½Ðµy«á¦A¨Ó(½Ð§Q¥Îport 3000~3010³s½u)":""));
+#endif
+ if (i > MAX_CPULOAD)
+ return 1;
+ else if (i > MAX_CPULOAD / 2)
+ curr_idle_timeout = 10 * 60;
+ else
+ curr_idle_timeout = 30 * 60;
+
+ return 0;
+}
+
+extern userec_t cuser;
+
+void
+log_user (char *msg)
+{
+ char filename[200];
+
+ sprintf (filename, BBSHOME "/home/%c/%s/USERLOG",
+ cuser.userid[0], cuser.userid);
+ log_file (filename, msg);
+}
+
+extern time_t login_start_time;
+
+void
+log_usies (char *mode, char *mesg)
+{
+ char genbuf[200];
+ time_t now = time (0);
+
+ if (!mesg)
+ sprintf (genbuf, cuser.userid[0] ? "%s %s %-12s Stay:%d (%s)" :
+ "%s %s %s Stay:%d (%s)",
+ Cdate (&now), mode, cuser.userid,
+ (int)(now - login_start_time) / 60, cuser.username);
+ else
+ sprintf (genbuf, cuser.userid[0] ? "%s %s %-12s %s" : "%s %s %s%s",
+ Cdate (&now), mode, cuser.userid, mesg);
+ log_file (FN_USIES, genbuf);
+
+ /* °lÂÜ¨Ï¥ÎªÌ */
+ if (HAS_PERM (PERM_LOGUSER))
+ log_user (genbuf);
+}
+
+static void
+setflags (int mask, int value)
+{
+ if (value)
+ cuser.uflag |= mask;
+ else
+ cuser.uflag &= ~mask;
+}
+
+extern int usernum;
+extern int currmode;
+
+void
+u_exit (char *mode)
+{
+ //userec_t xuser;
+ int diff = (time (0) - login_start_time) / 60;
+
+ reload_money();
+ auto_backup ();
+ save_brdbuf();
+ setflags (PAGER_FLAG, currutmp->pager != 1);
+ setflags (CLOAK_FLAG, currutmp->invisible);
+
+ cuser.invisible = currutmp->invisible;
+ cuser.pager = currutmp->pager;
+ cuser.mind = currutmp->mind;
+ if (!(HAS_PERM (PERM_SYSOP) && HAS_PERM (PERM_DENYPOST)) &&
+ !currutmp->invisible )
+ do_aloha ("<<¤U¯¸³qª¾>> -- §Ú¨«Åo¡I");
+
+ purge_utmp (currutmp);
+ if ((cuser.uflag != enter_uflag) || (currmode & MODE_DIRTY) || diff)
+ {
+ if (!diff && cuser.numlogins)
+ cuser.numlogins = --cuser.numlogins;
+ /* Leeym ¤W¯¸°±¯d®É¶¡­­¨î¦¡ */
+ }
+ passwd_update (usernum, &cuser);
+ log_usies (mode, NULL);
+}
+
+static void
+system_abort ()
+{
+ if (currmode)
+ u_exit ("ABORT");
+
+ clear ();
+ refresh ();
+ fprintf (stdout, "ÁÂÁÂ¥úÁ{, °O±o±`¨Ó³á !\n");
+ exit (0);
+}
+
+void
+abort_bbs (int sig)
+{
+ if (currmode)
+ u_exit ("AXXED");
+ exit (0);
+}
+
+static void
+abort_bbs_debug (int sig)
+{
+ static int reentrant = 0;
+
+ if (!reentrant){
+ reentrant = 1;
+ if (currmode)
+ u_exit ("AXXED");
+ setproctitle("debug me!(%d)",sig);
+ sleep(3600); /* wait 60 mins for debug */
+ }
+ exit (0);
+}
+
+/* µn¿ý BBS µ{¦¡ */
+static void
+mysrand ()
+{
+ srand (time (NULL) + currutmp->pid); /* ®É¶¡¸ò pid ·í rand ªº seed */
+}
+
+extern userec_t xuser;
+
+int
+dosearchuser (char *userid)
+{
+ if ((usernum = getuser (userid)))
+ memcpy (&cuser, &xuser, sizeof (cuser));
+ else
+ memset (&cuser, 0, sizeof (cuser));
+ return usernum;
+}
+
+static void
+talk_request ()
+{
+ bell ();
+ bell ();
+ if (currutmp->msgcount){
+ char buf[200];
+ time_t now = time (0);
+
+ sprintf (buf, "\033[33;41m¡¹%s\033[34;47m [%s] %s \033[0m",
+ utmpshm->uinfo[currutmp->destuip].userid, my_ctime (&now),
+ (currutmp->sig == 2)? "­«­n®ø®§¼s¼½¡I(½ÐCtrl-U,l¬d¬Ý¼ö°T°O¿ý)"
+ : "©I¥s¡B©I¥s¡AÅ¥¨ì½Ð¦^µª");
+ move (0, 0);
+ clrtoeol ();
+ outs (buf);
+ refresh ();
+ }
+ else{
+ unsigned char mode0 = currutmp->mode;
+ char c0 = currutmp->chatid[0];
+ screenline_t *screen0 = calloc (t_lines, sizeof (screenline_t));
+ extern screenline_t *big_picture;
+
+ currutmp->mode = 0;
+ currutmp->chatid[0] = 1;
+ memcpy (screen0, big_picture, t_lines * sizeof (screenline_t));
+ talkreply ();
+ currutmp->mode = mode0;
+ currutmp->chatid[0] = c0;
+ memcpy (big_picture, screen0, t_lines * sizeof (screenline_t));
+ free (screen0);
+ redoscr ();
+ }
+}
+
+extern char *fn_writelog;
+FILE *fp_writelog = NULL;
+
+void
+show_last_call_in (int save)
+{
+ char buf[200];
+ sprintf (buf, "\033[1;33;46m¡¹%s\033[37;45m %s \033[m",
+ currutmp->msgs[0].userid, currutmp->msgs[0].last_call_in);
+ move (b_lines, 0);
+ clrtoeol ();
+ refresh ();
+ outmsg (buf);
+
+ if (save){
+ char genbuf[200];
+ time_t now;
+ if (!fp_writelog){
+ sethomefile (genbuf, cuser.userid, fn_writelog);
+ fp_writelog = fopen (genbuf, "a");
+ }
+ if (fp_writelog){
+ time (&now);
+ fprintf (fp_writelog, "%s \033[0m[%s]\n", buf, Cdatelite (&now));
+ }
+ }
+}
+
+extern unsigned int currstat;
+water_t water[6], *swater[6], *water_which=&water[0];
+char water_usies=0;
+extern int watermode;
+static int add_history_water(water_t *w, msgque_t *msg)
+{
+ memcpy(&w->msg[w->top], msg, sizeof(msgque_t));
+ w->top++;
+ w->top %= WATERMODE(WATER_OFO) ? 5 : MAX_REVIEW;
+
+ if (w->count < MAX_REVIEW)
+ w->count++;
+
+ return w->count;
+}
+
+static int
+add_history(msgque_t *msg)
+{
+ int i,j;
+ water_t *tmp;
+ add_history_water(&water[0], msg);
+ for(i = 0 ; i < 5 && swater[i] ; i++ )
+ if( swater[i]->pid == msg->pid )
+ break;
+ if( i != 5 ){
+ if( !swater[i] ){
+ water_usies = i + 1;
+ swater[i] = &water[i + 1];
+ strcpy(swater[i]->userid, msg->userid);
+ swater[i]->pid = msg->pid;
+ }
+ tmp = swater[i];
+ }
+ else{
+ tmp = swater[4];
+ memset(swater[4], 0, sizeof (water_t));
+ strcpy(swater[4]->userid, msg->userid);
+ swater[4]->pid = msg->pid;
+ i = 4;
+ }
+
+ for( j = i ; j > 0 ; j-- )
+ swater[j] = swater[j - 1];
+ swater[0] = tmp;
+ add_history_water(swater[0], msg);
+
+ if(WATERMODE(WATER_ORIG) || WATERMODE(WATER_NEW) ){
+ if( watermode > 0 &&
+ (water_which == swater[0] || water_which == &water[0]) ){
+ if (watermode < water_which->count)
+ watermode++;
+ t_display_new();
+ }
+ }
+ return i;
+}
+
+static void
+write_request (int sig)
+{
+ struct tm *ptime;
+ time_t now;
+
+ time (&now);
+ ptime = localtime (&now);
+
+ if (currutmp->pager != 0 &&
+ cuser.userlevel != 0 &&
+ currutmp->msgcount != 0 &&
+ currutmp->mode != TALK &&
+ currutmp->mode != EDITING &&
+ currutmp->mode != CHATING &&
+ currutmp->mode != PAGE &&
+ currutmp->mode != IDLE &&
+ currutmp->mode != MAILALL && currutmp->mode != MONITOR)
+ {
+ int i;
+ char c0 = currutmp->chatid[0];
+ int currstat0 = currstat;
+ unsigned char mode0 = currutmp->mode;
+
+ currutmp->mode = 0;
+ currutmp->chatid[0] = 2;
+ currstat = XMODE;
+
+ do
+ {
+ bell ();
+ show_last_call_in (1);
+ igetch ();
+ currutmp->msgcount--;
+ if (currutmp->msgcount >= MAX_MSGS)
+ {
+ /* this causes chaos... jochang */
+ raise (SIGFPE);
+ }
+
+ add_history(&currutmp->msgs[0]);
+ for (i = 0; i < currutmp->msgcount; i++)
+ currutmp->msgs[i] = currutmp->msgs[i + 1];
+ }
+ while (currutmp->msgcount);
+ currutmp->chatid[0] = c0;
+ currutmp->mode = mode0;
+ currstat = currstat0;
+ }
+ else
+ {
+ bell ();
+ show_last_call_in (1);
+ add_history(&currutmp->msgs[0]);
+
+ refresh ();
+ currutmp->msgcount = 0;
+ }
+}
+
+#if 0
+static void
+write_request (int sig)
+{
+ int i, mtimemin, wu;
+ static char inlock = 0;
+ if( inlock ) /* ¦pªG¤w¸g¶i¨Ó¤F (ªí¥Ü¤W­Ó¤ô²yÁÙ¨S¦³³B²z§¹,
+ ·sªº¤ô²y¤S¶i¨Ó) «h¤£°µ¥ô¦ó¨Æª½±µ return */
+ return;
+ inlock = 1;
+ do{
+ for( wu = 0 ; wu < 5 ; ++wu )
+ if( water[wu].pid == currutmp->msgs[0].pid )
+ break;
+ if( wu == 5 ){
+ for( i = 0, mtimemin = INT_MAX ; i < 5 ; ++i )
+ if( water[i].pid == 0 ){
+ ++water_usies;
+ wu = i;
+ break;
+ }
+ else if( water[i].mtime < mtimemin ){
+ mtimemin = water[i].mtime;
+ wu = i;
+ }
+ water[wu].pid = currutmp->msgs[0].pid;
+ strcpy(water[wu].userid, currutmp->msgs[0].userid);
+ water[wu].msgtop = 0;
+ for( i = 0 ; i < 5 ; ++i )
+ water[wu].msg[i][0] = 0;
+ }
+ water[wu].mtime = time(NULL);
+ strncpy(water[wu].msg[ (int)water[wu].msgtop ],
+ currutmp->msgs[0].last_call_in, 64);
+ ++water[wu].msgtop;
+ water[wu].msgtop %= 5;
+
+ bell ();
+ show_last_call_in (1);
+ refresh();
+
+ if( watermode == 0 ){ /* in waterball selection mode
+ if( wu != 0 ){
+ water_scr(water_which, 0);
+ qsort(water, 5, sizeof(water_t), cmpwatermtime);
+ for( i = 0 ; i < 5 ; ++i )
+ if( water[i].pid == 0 )
+ break;
+ else
+ water_scr(i, 0);
+ water_scr(water_which = 0, 1);
+ refresh();
+ } */
+ }
+ --currutmp->msgcount;
+ for( i = 0 ; i < currutmp->msgcount - 1 ; ++i )
+ currutmp->msgs[i] = currutmp->msgs[i + 1];
+ } while( currutmp->msgcount > 0 );
+ inlock = 0;
+}
+#endif
+
+static void
+multi_user_check ()
+{
+ register userinfo_t *ui;
+ register pid_t pid;
+ char genbuf[3];
+
+ if (HAS_PERM (PERM_SYSOP))
+ return; /* don't check sysops */
+
+ if (cuser.userlevel){
+ if (!(ui = (userinfo_t *) search_ulist (usernum)))
+ return; /* user isn't logged in */
+
+ pid = ui->pid;
+ if (!pid /*|| (kill(pid, 0) == -1) */ )
+ return; /* stale entry in utmp file */
+
+ getdata (b_lines - 1, 0, "±z·Q§R°£¨ä¥L­«½Æªº login (Y/N)¶Ü¡H[Y] ",
+ genbuf, 3, LCECHO);
+
+ if (genbuf[0] != 'n'){
+ if (pid > 0)
+ kill (pid, SIGHUP);
+ log_usies ("KICK ", cuser.username);
+ }
+ else{
+ if (search_ulistn(usernum, 3)!=NULL)
+ system_abort (); /* Goodbye(); */
+ }
+ }
+ else{
+ /* allow multiple guest user */
+ if (search_ulistn(usernum, 100)!=NULL){
+ outs ("\n©êºp¡A¥Ø«e¤w¦³¤Ó¦h guest, ½Ðµy«á¦A¸Õ¡C\n");
+ pressanykey ();
+ oflush ();
+ exit (1);
+ }
+ }
+}
+
+/* bad login */
+static char str_badlogin[] = "logins.bad";
+
+static void
+logattempt (char *uid, char type)
+{
+ char fname[40];
+ int fd, len;
+ char genbuf[200];
+
+ sprintf (genbuf, "%c%-12s[%s] %s@%s\n", type, uid,
+ Cdate (&login_start_time), remoteusername, fromhost);
+ len = strlen (genbuf);
+ if ((fd = open (str_badlogin, O_WRONLY | O_CREAT | O_APPEND, 0644)) > 0){
+ write (fd, genbuf, len);
+ close (fd);
+ }
+ if (type == '-'){
+ sprintf (genbuf, "[%s] %s\n", Cdate (&login_start_time), fromhost);
+ len = strlen (genbuf);
+ sethomefile (fname, uid, str_badlogin);
+ if ((fd = open (fname, O_WRONLY | O_CREAT | O_APPEND, 0644)) > 0){
+ write (fd, genbuf, len);
+ close (fd);
+ }
+ }
+}
+
+extern char *str_new;
+extern char *err_uid;
+
+static void
+login_query ()
+{
+ char uid[IDLEN + 1], passbuf[PASSLEN];
+ int attempts;
+ char genbuf[200];
+ extern struct utmpfile_t *utmpshm;
+ resolve_utmp ();
+ attach_uhash ();
+ attempts = utmpshm->number;
+ show_file ("etc/Welcome", 1, -1, NO_RELOAD);
+ output ("1", 1);
+ if (attempts >= MAX_ACTIVE){
+ outs ("¥Ñ©ó¤H¼Æ¤Ó¦h¡A½Ð±zµy«á¦A¨Ó¡C\n");
+ refresh ();
+ exit (1);
+ }
+
+ /* hint */
+
+ attempts = 0;
+ while (1){
+ if (attempts++ >= LOGINATTEMPTS){
+ more ("etc/goodbye", NA);
+ pressanykey ();
+ exit (1);
+ }
+ getdata (20, 0, "½Ð¿é¤J¥N¸¹¡A©Î¥H[guest]°ÑÆ[¡A¥H[new]µù¥U¡G",
+ uid, IDLEN + 1, DOECHO);
+ if (strcasecmp (uid, str_new) == 0){
+#ifdef LOGINASNEW
+ new_register ();
+ break;
+#else
+ outs ("¥»¨t²Î¥Ø«eµLªk¥H new µù¥U, ½Ð¥Î guest ¶i¤J\n");
+ continue;
+#endif
+ }
+ else if (uid[0] == '\0' || !dosearchuser (uid)){
+ outs (err_uid);
+ }
+ else if (strcmp (uid, STR_GUEST)){
+ getdata (21, 0, MSG_PASSWD, passbuf, PASSLEN, NOECHO);
+ passbuf[8] = '\0';
+
+ if (!checkpasswd (cuser.passwd, passbuf)
+ /* || (HAS_PERM(PERM_SYSOP) && !use_shell_login_mode) */ ){
+ logattempt (cuser.userid, '-');
+ outs (ERR_PASSWD);
+ }
+ else{
+ logattempt (cuser.userid, ' ');
+ if (strcasecmp ("SYSOP", cuser.userid) == 0)
+ cuser.userlevel = PERM_BASIC | PERM_CHAT | PERM_PAGE |
+ PERM_POST | PERM_LOGINOK | PERM_MAILLIMIT |
+ PERM_CLOAK | PERM_SEECLOAK | PERM_XEMPT |
+ PERM_DENYPOST | PERM_BM | PERM_ACCOUNTS |
+ PERM_CHATROOM | PERM_BOARD | PERM_SYSOP | PERM_BBSADM;
+ break;
+ }
+ }
+ else{ /* guest */
+ cuser.userlevel = 0;
+ cuser.uflag = COLOR_FLAG | PAGER_FLAG | BRDSORT_FLAG | MOVIE_FLAG;
+ break;
+ }
+ }
+ multi_user_check ();
+ sethomepath (genbuf, cuser.userid);
+ mkdir (genbuf, 0755);
+}
+
+void
+add_distinct (char *fname, char *line)
+{
+ FILE *fp;
+ int n = 0;
+
+ if ((fp = fopen (fname, "a+"))){
+ char buffer[80];
+ char tmpname[100];
+ FILE *fptmp;
+
+ strcpy (tmpname, fname);
+ strcat (tmpname, "_tmp");
+ if (!(fptmp = fopen (tmpname, "w"))){
+ fclose (fp);
+ return;
+ }
+ rewind (fp);
+ while (fgets (buffer, 80, fp)){
+ char *p = buffer + strlen (buffer) - 1;
+
+ if (p[-1] == '\n' || p[-1] == '\r')
+ p[-1] = 0;
+ if (!strcmp (buffer, line))
+ break;
+ sscanf (buffer + strlen (buffer) + 2, "%d", &n);
+ fprintf (fptmp, "%s%c#%d\n", buffer, 0, n);
+ }
+
+ if (feof (fp))
+ fprintf (fptmp, "%s%c#1\n", line, 0);
+ else{
+ sscanf (buffer + strlen (buffer) + 2, "%d", &n);
+ fprintf (fptmp, "%s%c#%d\n", buffer, 0, n + 1);
+ while (fgets (buffer, 80, fp)){
+ sscanf (buffer + strlen (buffer) + 2, "%d", &n);
+ fprintf (fptmp, "%s%c#%d\n", buffer, 0, n);
+ }
+ }
+ fclose (fp);
+ fclose (fptmp);
+ unlink (fname);
+ rename (tmpname, fname);
+ }
+}
+
+void
+del_distinct (char *fname, char *line)
+{
+ FILE *fp;
+ int n = 0;
+
+ if ((fp = fopen (fname, "r"))){
+ char buffer[80];
+ char tmpname[100];
+ FILE *fptmp;
+
+ strcpy (tmpname, fname);
+ strcat (tmpname, "_tmp");
+ if (!(fptmp = fopen (tmpname, "w"))){
+ fclose (fp);
+ return;
+ }
+ rewind (fp);
+ while (fgets (buffer, 80, fp)){
+ char *p = buffer + strlen (buffer) - 1;
+
+ if (p[-1] == '\n' || p[-1] == '\r')
+ p[-1] = 0;
+ if (!strcmp (buffer, line))
+ break;
+ sscanf (buffer + strlen (buffer) + 2, "%d", &n);
+ fprintf (fptmp, "%s%c#%d\n", buffer, 0, n);
+ }
+
+ if (!feof (fp))
+ while (fgets (buffer, 80, fp)){
+ sscanf (buffer + strlen (buffer) + 2, "%d", &n);
+ fprintf (fptmp, "%s%c#%d\n", buffer, 0, n);
+ }
+ fclose (fp);
+ fclose (fptmp);
+ unlink (fname);
+ rename (tmpname, fname);
+ }
+}
+
+#ifdef WHERE
+static int
+where (char *from)
+{
+ register int i = 0, count = 0, j;
+
+ for (j = 0; j < fcache->top; j++){
+ char *token = strtok (fcache->domain[j], "&");
+
+ i = 0;
+ count = 0;
+ while (token){
+ if (strstr (from, token))
+ count++;
+ token = strtok (NULL, "&");
+ i++;
+ }
+ if (i == count)
+ break;
+ }
+ if (i != count)
+ return 0;
+ return j;
+}
+#endif
+
+static void
+check_BM ()
+{
+ int i;
+ boardheader_t *bhdr;
+ extern boardheader_t *bcache;
+ extern int numboards;
+
+ cuser.userlevel &= ~PERM_BM;
+ for (i = 0, bhdr = bcache; i < numboards && !is_BM (bhdr->BM); i++, bhdr++)
+ ;
+}
+
+extern pid_t currpid;
+extern crosspost_t postrecord;
+
+static void
+setup_utmp (int mode)
+{
+ userinfo_t uinfo;
+ /*
+ char buf[80];
+ char remotebuf[1024];
+ time_t now = time(NULL);
+ */
+ memset (&uinfo, 0, sizeof (uinfo));
+ uinfo.pid = currpid = getpid ();
+ uinfo.uid = usernum;
+ uinfo.mode = currstat = mode;
+ uinfo.msgcount = 0;
+ uinfo.mailalert = load_mailalert (cuser.userid);
+ if (!(cuser.numlogins % 20) && cuser.userlevel & PERM_BM)
+ check_BM (); /* Ptt ¦Û°Ê¨ú¤UÂ÷¾ªO¥DÅv¤O */
+
+ uinfo.userlevel = cuser.userlevel;
+ uinfo.sex = cuser.sex % 8;
+ uinfo.lastact = time (NULL);
+
+ postrecord.times = 0; /* ­pºâcrosspost¼Æ */
+
+ strcpy (uinfo.userid, cuser.userid);
+ strcpy (uinfo.realname, cuser.realname);
+ strcpy (uinfo.username, cuser.username);
+ strncpy (uinfo.from, fromhost, 23);
+
+ uinfo.five_win = cuser.five_win;
+ uinfo.five_lose = cuser.five_lose;
+ uinfo.five_tie = cuser.five_tie;
+
+ uinfo.invisible = cuser.invisible % 2;
+ uinfo.pager = cuser.pager%5;
+ uinfo.mind = cuser.mind;
+ uinfo.brc_id = 0;
+#ifdef WHERE
+ uinfo.from_alias = where (fromhost);
+#else
+ uinfo.from_alias = 0;
+#endif
+#ifndef FAST_LOGIN
+ setuserfile (buf, "remoteuser");
+
+ strcpy (remotebuf, fromhost);
+ strcat (remotebuf, ctime (&now));
+ remotebuf[strlen (remotebuf) - 1] = 0;
+ add_distinct (buf, remotebuf);
+#endif
+ if (enter_uflag & CLOAK_FLAG)
+ uinfo.invisible = YEA;
+ getnewutmpent (&uinfo);
+#ifndef _BBS_UTIL_C_
+ friend_load ();
+#endif
+}
+
+extern char margs[];
+extern char *str_sysop;
+extern char *loginview_file[NUMVIEWFILE][2];
+
+static void
+user_login ()
+{
+ char ans[4], i;
+ char genbuf[200];
+ struct tm *ptime, *tmp;
+ time_t now;
+ int a;
+ /*** Heat:¼s§iµü
+ char *ADV[] = {
+ "7/17 @LIVE ¶Ã¼u, ¦óªYÁJ ªº ¤J³õ¨÷­n°eµ¹ ptt ªº·R¥ÎªÌ!",
+ "±ýª¾¸Ô±¡½Ð¬Ý PttAct ªO!!",
+ }; ***/
+
+ log_usies ("ENTER", fromhost);
+ setproctitle ("%s: %s", margs, cuser.userid);
+ resolve_garbage ();
+ resolve_fcache ();
+ resolve_boards ();
+ memset( &water[0],0,sizeof(water_t) * 6);
+ strcpy(water[0].userid, " ¥þ³¡ ");
+ /* ªì©l¤Æ uinfo¡Bflag¡Bmode */
+ setup_utmp (LOGIN);
+ mysrand (); /* ªì©l¤Æ: random number ¼W¥[user¸ò®É¶¡ªº®t²§ */
+ currmode = MODE_STARTED;
+ enter_uflag = cuser.uflag;
+
+ /* get local time */
+ time (&now);
+ ptime = localtime (&now);
+ tmp = localtime (&cuser.lastlogin);
+ if ((a = utmpshm->number) > fcache->max_user){
+ fcache->max_user = a;
+ fcache->max_time = now;
+ }
+ init_brdbuf();
+ brc_initial (DEFAULT_BOARD);
+ set_board ();
+ /* µe­±³B²z¶}©l */
+ if (!(HAS_PERM (PERM_SYSOP) && HAS_PERM (PERM_DENYPOST)) && !currutmp->invisible )
+ do_aloha ("<<¤W¯¸³qª¾>> -- §Ú¨Ó°Õ¡I");
+ if (ptime->tm_mday == cuser.day && ptime->tm_mon + 1 == cuser.month){
+ more ("etc/Welcome_birth", NA);
+ currutmp->birth = 1;
+ }
+ else{
+#ifdef MULTI_WELCOME_LOGIN
+ char buf[80];
+ int nScreens;
+ for( nScreens = 0 ; nScreens < 10 ; ++nScreens ){
+ sprintf(buf, "etc/Welcome_login.%d", nScreens);
+ if( access(buf, 0) < 0 )
+ break;
+ }
+ printf("%d\n", nScreens);
+ if( nScreens == 0 ){ // multi screen error?
+ more ("etc/Welcome_login", NA);
+ }
+ else{
+ sprintf(buf, "etc/Welcome_login.%d", (int)login_start_time % nScreens);
+ more (buf, NA);
+ }
+#else
+ more ("etc/Welcome_login", NA);
+#endif
+// pressanykey();
+// more("etc/CSIE_Week", NA);
+ currutmp->birth = 0;
+ }
+
+ if (cuser.userlevel){/* not guest */
+ move (t_lines - 4, 0);
+ prints (" Åwªï±z²Ä \033[1;33m%d\033[0;37m «×«ô³X¥»¯¸¡A"
+ "¤W¦¸±z¬O±q \033[1;33m%s\033[0;37m ³s©¹¥»¯¸¡A\n"
+ " §Ú°O±o¨º¤Ñ¬O \033[1;33m%s\033[0;37m¡C\n",
+ ++cuser.numlogins, cuser.lasthost, Cdate (&cuser.lastlogin));
+ pressanykey ();
+
+ if (currutmp->birth && tmp->tm_mday != ptime->tm_mday){
+ more ("etc/birth.post", YEA);
+ brc_initial ("WhoAmI");
+ set_board ();
+ do_post ();
+ }
+ setuserfile (genbuf, str_badlogin);
+ if (more (genbuf, NA) != -1){
+ getdata (b_lines - 1, 0, "±z­n§R°£¥H¤W¿ù»~¹Á¸Õªº°O¿ý¶Ü(Y/N)?[Y]",
+ ans, 3, LCECHO);
+ if (*ans != 'n')
+ unlink (genbuf);
+ }
+ check_register ();
+ strncpy (cuser.lasthost, fromhost, 16);
+ cuser.lasthost[15] = '\0';
+ restore_backup ();
+ }
+ else if (!strcmp (cuser.userid, STR_GUEST)){
+ char *nick[13] = {
+ "·¦¤l", "¨©´ß", "¤º¦ç", "Ä_¯S²~", "½¨®³½",
+ "¾ð¸­", "¯BµÓ", "¾c¤l", "¼ç¤ô¸¥", "Å]¤ý",
+ "ÅKÅø", "¦Ò¨÷", "¤j¬ü¤k"
+ };
+ char *name[13] = {
+ "¤j¤ý·¦¤l", "ÆxÄMÁ³", "¤ñ°ò¥§", "¥i¤f¥i¼Ö", "¥õªaªº³½",
+ "¾Ð", "°ª©£«Î", "AIR Jordon", "¬õ¦â¤Q¤ë¸¹", "§å½ð½ð",
+ "SASAYA·¦¥¤", "Àn³J", "¥¬¾|§J÷«³½­»µ·"
+ };
+ char *addr[13] = {
+ "¤Ñ°ó¼Ö¶é", "¤j®ü", "ºñ®q¤p©]¦±", "¬ü°ê", "ºñ¦â¬À·äÁG",
+ "»·¤è", "­ì¥»®ü", "NIKE", "ĬÁp", "¨k¤K618«Ç",
+ "·R¤§¨ý", "¤Ñ¤W", "ÂŦâ¬À·äÁG"
+ };
+ i = login_start_time % 13;
+ sprintf (cuser.username, "®üÃäº}¨Óªº%s", nick[(int) i]);
+ sprintf (currutmp->username, cuser.username);
+ sprintf (cuser.realname, name[(int) i]);
+ sprintf (currutmp->realname, cuser.realname);
+ sprintf (cuser.address, addr[(int) i]);
+ cuser.sex = i % 8;
+ currutmp->pager = 2;
+ pressanykey ();
+ }
+ else
+ pressanykey ();
+
+ if (!PERM_HIDE (currutmp))
+ cuser.lastlogin = login_start_time;
+
+ passwd_update (usernum, &cuser);
+
+ for (i = 0; i < NUMVIEWFILE; i++)
+ if ((cuser.loginview >> i) & 1)
+ more (loginview_file[(int) i][0], YEA);
+
+
+}
+
+static void
+do_aloha (char *hello)
+{
+ FILE *fp;
+ char userid[80];
+ char genbuf[200];
+
+ setuserfile (genbuf, "aloha");
+ if ((fp = fopen (genbuf, "r"))){
+ sprintf (genbuf, hello);
+ while (fgets (userid, 80, fp)){
+ userinfo_t *uentp;
+ int tuid;
+
+ if ((tuid = searchuser (userid)) && tuid != usernum &&
+ (uentp = (userinfo_t *) search_ulist (tuid)) &&
+ isvisible(uentp, currutmp)){
+ my_write (uentp->pid, genbuf, uentp->userid, 2);
+ }
+ }
+ fclose (fp);
+ }
+}
+
+static void
+do_term_init ()
+{
+ term_init ();
+ initscr ();
+}
+
+extern char *fn_register;
+extern int showansi;
+
+static void
+start_client ()
+{
+ extern struct commands_t cmdlist[];
+#if FORCE_PROCESS_REGISTER_FORM
+ int nreg;
+#endif
+
+ /* system init */
+ nice (2); /* Ptt: lower priority */
+ login_start_time = time (0);
+ currmode = 0;
+
+ signal (SIGHUP, abort_bbs);
+ signal (SIGTERM, abort_bbs);
+ signal (SIGPIPE, abort_bbs);
+
+ signal (SIGINT, abort_bbs_debug);
+ signal (SIGQUIT, abort_bbs_debug);
+ signal (SIGILL, abort_bbs_debug);
+ signal (SIGABRT, abort_bbs_debug);
+ signal (SIGFPE, abort_bbs_debug);
+ signal (SIGBUS, abort_bbs_debug);
+ signal (SIGSEGV, abort_bbs_debug);
+
+ signal_restart (SIGUSR1, talk_request);
+ signal_restart (SIGUSR2, write_request);
+
+ dup2 (0, 1);
+
+ do_term_init ();
+ signal (SIGALRM, abort_bbs);
+ alarm (600);
+ login_query (); /* Ptt ¥[¤Wlogin time out */
+ user_login ();
+ m_init ();
+
+#if FORCE_PROCESS_REGISTER_FORM
+ if (HAS_PERM (PERM_SYSOP) && (nreg = dashs (fn_register) / 163) > 100){
+ char cpu_load[30];
+ if (cpuload (cpu_load) > MAX_CPULOAD * 2 / 3)
+ /* DickG: ®Ú¾Ú¥Ø«eªº load ¨Ó¨M©w­n¼f®Öªº¼Æ¥Ø */
+ scan_register_form (fn_register, 1, nreg / 20);
+ else
+ scan_register_form (fn_register, 1, nreg / 10);
+ }
+#endif
+ if (HAVE_PERM (PERM_SYSOP | PERM_BM))
+ b_closepolls ();
+ if (!(cuser.uflag & COLOR_FLAG))
+ showansi = 0;
+#ifdef DOTIMEOUT
+ /* init_alarm(); */// cause strange logout with saving post.
+ signal (SIGALRM, SIG_IGN);
+#else
+ signal (SIGALRM, SIG_IGN);
+#endif
+ if (chkmailbox ())
+ m_read ();
+
+ domenu (MMENU, "¥D¥\\¯àªí", (currutmp->mailalert ? 'M' : 'C'), cmdlist);
+}
+
+/* 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
+ };
+ char *cmd;
+ int n, len, rset;
+ struct timeval to;
+ char buf[64];
+ for (n = 0, cmd = svr; n < 4; n++){
+ len = (n == 1 ? 6 : 3);
+ write (0, cmd, len);
+ cmd += len;
+ to.tv_sec = 3;
+ to.tv_usec = 0;
+ rset=1;
+ if (select (1, (fd_set *) & rset, NULL, NULL, &to) > 0)
+ recv(0, buf, sizeof (buf),0);
+ }
+}
+
+/* ¨ú±o remote user name ¥H§P©w¨­¥÷ */
+/*
+ * rfc931() 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. This routine intercepts alarm signals.
+ *
+ * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
+ */
+
+#define STRN_CPY(d,s,l) { strncpy((d),(s),(l)); (d)[(l)-1] = 0; }
+#define RFC931_TIMEOUT 10
+#define RFC931_PORT 113 /* Semi-well-known port */
+#define ANY_PORT 0 /* Any old port will do */
+
+/* timeout - handle timeouts */
+static void
+timeout (int sig)
+{
+ longjmp (byebye, sig);
+}
+
+static void
+getremotename (struct sockaddr_in *from, char *rhost, char *rname)
+{
+
+ /* get remote host name */
+
+#ifdef FAST_LOGIN
+ strcpy (rhost, (char *) inet_ntoa (from->sin_addr));
+#else
+ struct sockaddr_in our_sin;
+ struct sockaddr_in rmt_sin;
+ unsigned rmt_port, rmt_pt;
+ unsigned our_port, our_pt;
+ FILE *fp;
+ char buffer[512], user[80], *cp;
+ int s;
+ static struct hostent *hp;
+
+
+ hp = NULL;
+ if (setjmp (byebye) == 0){
+ signal (SIGALRM, timeout);
+ alarm (3);
+ hp = gethostbyaddr ((char *) &from->sin_addr, sizeof (struct in_addr),
+ from->sin_family);
+ alarm (0);
+ }
+ strcpy (rhost, hp ? hp->h_name : (char *) inet_ntoa (from->sin_addr));
+
+/*
+ * 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.
+ */
+
+ s = sizeof (our_sin);
+ if (getsockname (0, (struct sockaddr *) &our_sin, &s) < 0)
+ return;
+
+ if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0)
+ return;
+
+ if (!(fp = fdopen (s, "r+"))){
+ close (s);
+ return;
+ }
+ /* Set up a timer so we won't get stuck while waiting for the server. */
+ if (setjmp (byebye) == 0){
+ signal (SIGALRM, timeout);
+ alarm (RFC931_TIMEOUT);
+
+/*
+ * 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.
+ */
+ our_pt = ntohs (our_sin.sin_port);
+ our_sin.sin_port = htons (ANY_PORT);
+
+ rmt_sin = *from;
+ rmt_pt = ntohs (rmt_sin.sin_port);
+ rmt_sin.sin_port = htons (RFC931_PORT);
+
+ setbuf (fp, (char *) 0);
+ s = fileno (fp);
+
+ if (bind (s, (struct sockaddr *) &our_sin, sizeof (our_sin)) >= 0 &&
+ connect (s, (struct sockaddr *) &rmt_sin, sizeof (rmt_sin)) >= 0){
+/*
+ * 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.
+ */
+ fprintf (fp, "%u,%u\r\n", rmt_pt, our_pt);
+ fflush (fp);
+/*
+ * Read response from server. Use fgets()/sscanf() so we can work
+ * around System V stdio libraries that incorrectly assume EOF when a
+ * read from a socket returns less than requested.
+ */
+ if (fgets (buffer, sizeof (buffer), fp) && !ferror (fp)
+ && !feof (fp)
+ && sscanf (buffer, "%u , %u : USERID :%*[^:]:%79s", &rmt_port,
+ &our_port, user) == 3 && rmt_pt == rmt_port
+ && our_pt == our_port){
+
+/*
+ * Strip trailing carriage return. It is part of the protocol, not
+ * part of the data.
+ */
+ if ((cp = (char *) strchr (user, '\r')))
+ *cp = 0;
+ strcpy (rname, user);
+ }
+ }
+ alarm (0);
+ }
+ fclose (fp);
+#endif
+}
+
+static int
+bind_port (int port)
+{
+ int sock, on;
+
+ sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ on = 1;
+ setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on));
+ setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof (on));
+
+ on = 0;
+ setsockopt (sock, SOL_SOCKET, SO_LINGER, (char *) &on, sizeof (on));
+
+ xsin.sin_port = htons (port);
+ if (bind (sock, (struct sockaddr *) &xsin, sizeof xsin) < 0){
+ syslog (LOG_INFO, "bbsd bind_port can't bind to %d", port);
+ exit (1);
+ }
+ if (listen (sock, SOCKET_QLEN) < 0){
+ syslog (LOG_INFO, "bbsd bind_port can't listen to %d", port);
+ exit (1);
+ }
+ return sock;
+}
+
+
+/*******************************************************/
+
+
+static void shell_login (int argc, char *argv[], char *envp[]);
+static void daemon_login (int argc, char *argv[], char *envp[]);
+static int check_ban_and_load (int fd);
+#ifdef SUPPORT_GB
+extern int current_font_type;
+#endif
+
+int
+main (int argc, char *argv[], char *envp[])
+{
+ /* avoid SIGPIPE */
+ signal (SIGPIPE, SIG_IGN);
+
+ /* avoid erroneous signal from other mbbsd */
+ signal (SIGUSR1, SIG_IGN);
+ signal (SIGUSR2, SIG_IGN);
+
+ /* check if invoked as "bbs" */
+ if (argc == 3)
+ shell_login (argc, argv, envp);
+ else
+ daemon_login (argc, argv, envp);
+
+ return 0;
+}
+
+static void
+shell_login (int argc, char *argv[], char *envp[])
+{
+
+ /* Give up root privileges: no way back from here */
+ setgid (BBSGID);
+ setuid (BBSUID);
+ chdir (BBSHOME);
+
+ /* mmap passwd file */
+ if (passwd_mmap ())
+ exit (1);
+
+ use_shell_login_mode = 1;
+ initsetproctitle (argc, argv, envp);
+
+ /* copy fromindent: Standard input:1138: Error:Unexpected end of file
+ the original "bbs" */
+ if (argc > 1){
+ strcpy (fromhost, argv[1]);
+ if (argc > 3)
+ strcpy (remoteusername, argv[3]);
+ }
+
+ close (2);
+ /* don't close fd 1, at least init_tty need it */
+
+ init_tty ();
+ if (check_ban_and_load (0)){
+ exit (0);
+ }
+ start_client ();
+}
+
+static void
+daemon_login (int argc, char *argv[], char *envp[])
+{
+ int msock, csock; /* socket for Master and Child */
+ FILE *fp;
+ int listen_port = 23;
+ int len_of_sock_addr;
+ char buf[256];
+
+ /* setup standalone */
+
+ start_daemon();
+
+ signal_restart(SIGCHLD, reapchild);
+
+ /* choose port */
+ if(argc == 1)
+ listen_port = 3006;
+ else if(argc >= 2)
+ listen_port = atoi(argv[1]);
+
+ sprintf(margs, "%s %d ", argv[0],listen_port);
+
+ /* port binding */
+ xsin.sin_family = AF_INET;
+ msock = bind_port(listen_port);
+ if(msock<0) {
+ syslog(LOG_INFO, "mbbsd bind_port failed.\n");
+ exit(1);
+ }
+
+
+ initsetproctitle(argc, argv, envp);
+ setproctitle("%s: listening ", margs);
+
+ /* Give up root privileges: no way back from here */
+ setgid(BBSGID);
+ setuid(BBSUID);
+ chdir(BBSHOME);
+
+ /* mmap passwd file */
+ if(passwd_mmap())
+ {
+ exit(1);
+ }
+ sprintf(buf, "run/mbbsd.%d.pid", listen_port);
+ if((fp = fopen(buf, "w"))) {
+ fprintf(fp, "%d\n", getpid());
+ fclose(fp);
+ }
+
+ /* main loop */
+ for(;;) {
+ len_of_sock_addr = sizeof(xsin);
+ csock = accept(msock, (struct sockaddr *)&xsin, &len_of_sock_addr);
+
+ if(csock < 0) {
+ if(errno!=EINTR) sleep(1);
+ continue;
+ }
+
+ if(check_ban_and_load(csock))
+ {
+ close(csock);
+ continue;
+ }
+
+ if(fork()==0)
+ break;
+ else
+ close(csock);
+
+ }
+ /* here is only child running */
+
+ setproctitle("%s: ...login wait... ", margs);
+ close(msock);
+ dup2(csock, 0);
+ close(csock);
+
+ getremotename(&xsin, fromhost, remoteusername);
+ telnet_init();
+ start_client();
+ close(0);
+ close(1);
+}
+
+/* check if we're banning login and if the load is too high.
+ if login is permitted, return 0;
+ else return -1;
+ approriate message is output to fd.
+*/
+static int check_ban_and_load(int fd)
+{
+ FILE *fp;
+ static char buf[256];
+ static time_t chkload_time = 0;
+ static int overload = 0; /* overload or banned, update every 1 sec */
+ static int banned = 0;
+
+ if((time(0) - chkload_time) > 1) {
+ overload = chkload(buf);
+ banned = !access(BBSHOME "/BAN",R_OK) &&
+ (strcmp(fromhost, "localhost") != 0);
+ chkload_time = time(0);
+ }
+
+ write(fd, buf, strlen(buf));
+
+ if(banned && (fp = fopen(BBSHOME "/BAN", "r"))) {
+ while(fgets(buf, 256, fp))
+ write(fd, buf, strlen(buf));
+ fclose(fp);
+ }
+
+ if(banned || overload)
+ return -1;
+
+#ifdef INSCREEN
+ write(fd, INSCREEN, strlen(INSCREEN));
+#endif
+
+ return 0;
+}
diff --git a/mbbsd/menu.c b/mbbsd/menu.c
new file mode 100644
index 00000000..d48670b3
--- /dev/null
+++ b/mbbsd/menu.c
@@ -0,0 +1,596 @@
+/* $Id: menu.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/types.h>
+#include <string.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "perm.h"
+#include "modes.h"
+#include "proto.h"
+extern int usernum;
+extern int talkrequest;
+extern char *fn_register;
+extern char currboard[]; /* name of currently selected board */
+extern int currmode;
+extern unsigned int currstat;
+extern char reset_color[];
+extern userinfo_t *currutmp;
+extern char *BBSName;
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+
+/* help & menu processring */
+static int refscreen = NA;
+extern char *boardprefix;
+extern struct utmpfile_t *utmpshm;
+
+int egetch() {
+ int rval;
+
+ while(1) {
+ rval = igetkey();
+ if(talkrequest) {
+ talkreply();
+ refscreen = YEA;
+ return rval;
+ }
+ if(rval != Ctrl('L'))
+ return rval;
+ redoscr();
+ }
+}
+
+extern userec_t cuser;
+extern char *fn_board;
+extern char board_hidden_status;
+
+void showtitle(char *title, char *mid) {
+ char buf[40], numreg[50];
+ int nreg, spc = 0, pad, bid;
+ boardheader_t bh;
+ static char lastboard[16] = {0};
+
+ spc = strlen(mid);
+ if(title[0] == 0)
+ title++;
+ else if(currutmp->mailalert) {
+ mid = "\033[41;5m ¶l®t¨Ó«ö¹aÅo " TITLE_COLOR;
+ spc = 22;
+ } else if(HAS_PERM(PERM_SYSOP) && (nreg = dashs(fn_register)/163) > 10) {
+ /* ¶W¹L¤Q­Ó¤H¥¼¼f®Ö */
+ sprintf(numreg, "\033[41;5m ¦³%03d/%03d¥¼¼f®Ö " TITLE_COLOR,
+ nreg,
+ (int)dashs("register.new.tmp") / 163);
+ mid = numreg;
+ spc = 22;
+ }
+ spc = 66 - strlen(title) - spc - strlen(currboard);
+ if(spc < 0)
+ spc = 0;
+ pad = 1 - (spc & 1);
+ memset(buf, ' ', spc >>= 1);
+ buf[spc] = '\0';
+
+ clear();
+ prints(TITLE_COLOR "¡i%s¡j%s\033[33m%s%s%s\033[3%s¡m",
+ title, buf, mid, buf, " " + pad,
+ currmode & MODE_SELECT ? "6m¨t¦C" : currmode & MODE_ETC ? "5m¨ä¥L" :
+ currmode & MODE_DIGEST ? "2m¤åºK" : "7m¬ÝªO");
+
+ if( strcmp(currboard, lastboard) ){ /* change board */
+ if( currboard[0] != 0 &&
+ (bid = getbnum(currboard)) > 0 &&
+ (get_record(fn_board, &bh, sizeof(bh), bid) != -1) ){
+ board_hidden_status = ((bh.brdattr & BRD_HIDE) &&
+ (bh.brdattr & BRD_POSTMASK));
+ strncpy(lastboard, currboard, sizeof(lastboard));
+ }
+ }
+
+ if( board_hidden_status )
+ prints("\033[32m%s", currboard);
+ else
+ prints("%s", currboard);
+ prints("\033[3%dm¡n\033[0m\n", currmode & MODE_SELECT ? 6 :
+ currmode & MODE_ETC ? 5 : currmode & MODE_DIGEST ? 2 : 7);
+}
+
+/* °Êµe³B²z */
+#define FILMROW 11
+static unsigned char menu_row = 12;
+static unsigned char menu_column = 20;
+static char mystatus[160];
+
+static int u_movie() {
+ cuser.uflag ^= MOVIE_FLAG;
+ return 0;
+}
+
+void movie(int i) {
+ extern struct pttcache_t *ptt;
+ static short history[MAX_HISTORY];
+ static char myweek[] = "¤Ñ¤@¤G¤T¥|¤­¤»";
+ const char *msgs[] = {"Ãö³¬", "¥´¶}", "©Þ±¼", "¨¾¤ô","¦n¤Í"};
+ time_t now = time(NULL);
+ struct tm *ptime = localtime(&now);
+
+ if((currstat != CLASS) && (cuser.uflag & MOVIE_FLAG) &&
+ !ptt->busystate && ptt->max_film > 0) {
+ if(currstat == PSALE) {
+ i = PSALE;
+ reload_money();
+ } else {
+ do {
+ if(!i)
+ i = 1 + (int)(((float)ptt->max_film *
+ rand()) / (RAND_MAX + 1.0));
+
+ for(now = ptt->max_history; now >= 0; now--)
+ if(i == history[now]) {
+ i = 0;
+ break;
+ }
+ } while(i == 0);
+ }
+
+ memcpy(history, &history[1], ptt->max_history * sizeof(short));
+ history[ptt->max_history] = now = i;
+
+ if(i == 999) /* Goodbye my friend */
+ i = 0;
+
+ move(1, 0);
+ clrtoline(1 + FILMROW); /* ²M±¼¤W¦¸ªº */
+ Jaky_outs(ptt->notes[i], 11); /* ¥u¦L11¦æ´N¦n */
+ outs(reset_color);
+ }
+ i = ptime->tm_wday << 1;
+ sprintf(mystatus, "\033[34;46m[%d/%d ¬P´Á%c%c %d:%02d]\033[1;33;45m%-14s"
+ "\033[30;47m ¥Ø«e§{¸Ì¦³ \033[31m%d\033[30m¤H, §Ú¬O\033[31m%-12s"
+ "\033[30m[¦©¾÷]\033[31m%s\033[0m",
+ ptime->tm_mon + 1, ptime->tm_mday, myweek[i], myweek[i + 1],
+ ptime->tm_hour, ptime->tm_min, currutmp->birth ?
+ "¥Í¤é­n½Ð«È­ò" : ptt->today_is,
+ utmpshm->number, cuser.userid, msgs[currutmp->pager]);
+ outmsg(mystatus);
+ refresh();
+}
+
+static int show_menu(commands_t *p) {
+ register int n = 0;
+ register char *s;
+ const char *state[4]={"¥Î¥\\«¬", "¦w¶h«¬", "¦Û©w«¬", "SHUTUP"};
+ char buf[80];
+
+ movie(currstat);
+
+ move(menu_row, 0);
+ while((s = p[n].desc)) {
+ if(HAS_PERM(p[n].level)) {
+ sprintf(buf, s + 2, state[cuser.proverb % 4]);
+ prints("%*s (\033[1;36m%c\033[0m)%s\n", menu_column, "", s[1],
+ buf);
+ }
+ n++;
+ }
+ return n - 1;
+}
+
+void domenu(int cmdmode, char *cmdtitle, int cmd, commands_t cmdtable[]) {
+ int lastcmdptr;
+ int n, pos, total, i;
+ int err;
+ int chkmailbox();
+ static char cmd0[LOGIN];
+
+ if(cmd0[cmdmode])
+ cmd = cmd0[cmdmode];
+
+ setutmpmode(cmdmode);
+
+ showtitle(cmdtitle, BBSName);
+
+ total = show_menu(cmdtable);
+
+ outmsg(mystatus);
+ lastcmdptr = pos = 0;
+
+ do {
+ i = -1;
+ switch(cmd) {
+ case Ctrl('C'):
+ cal();
+ i = lastcmdptr;
+ refscreen = YEA;
+ break;
+ case Ctrl('I'):
+ t_idle();
+ refscreen = YEA;
+ i = lastcmdptr;
+ break;
+ case Ctrl('N'):
+ New();
+ refscreen = YEA;
+ i = lastcmdptr;
+ break;
+ case Ctrl('A'):
+ if(mail_man() == FULLUPDATE)
+ refscreen = YEA;
+ i = lastcmdptr;
+ break;
+ case KEY_DOWN:
+ i = lastcmdptr;
+ case KEY_HOME:
+ case KEY_PGUP:
+ do {
+ if(++i > total)
+ i = 0;
+ } while(!HAS_PERM(cmdtable[i].level));
+ break;
+ case KEY_END:
+ case KEY_PGDN:
+ i = total;
+ break;
+ case KEY_UP:
+ i = lastcmdptr;
+ do {
+ if(--i < 0)
+ i = total;
+ } while(!HAS_PERM(cmdtable[i].level));
+ break;
+ case KEY_LEFT:
+ case 'e':
+ case 'E':
+ if(cmdmode == MMENU)
+ cmd = 'G';
+ else if((cmdmode == MAIL) && chkmailbox())
+ cmd = 'R';
+ else
+ return;
+ default:
+ if((cmd == 's' || cmd == 'r') &&
+ (currstat == MMENU || currstat == TMENU || currstat == XMENU)) {
+ if(cmd == 's')
+ ReadSelect();
+ else
+ Read();
+ refscreen = YEA;
+ i = lastcmdptr;
+ break;
+ }
+
+ if(cmd == '\n' || cmd == '\r' || cmd == KEY_RIGHT) {
+ move(b_lines, 0);
+ clrtoeol();
+
+ currstat = XMODE;
+
+ if((err = (*cmdtable[lastcmdptr].cmdfunc) ()) == QUIT)
+ return;
+ currutmp->mode = currstat = cmdmode;
+
+ if(err == XEASY) {
+ refresh();
+ safe_sleep(1);
+ } else if(err != XEASY + 1 || err == FULLUPDATE)
+ refscreen = YEA;
+
+ if(err != -1)
+ cmd = cmdtable[lastcmdptr].desc[0];
+ else
+ cmd = cmdtable[lastcmdptr].desc[1];
+ cmd0[cmdmode] = cmdtable[lastcmdptr].desc[0];
+ }
+
+ if(cmd >= 'a' && cmd <= 'z')
+ cmd &= ~0x20;
+ while(++i <= total)
+ if(cmdtable[i].desc[1] == cmd)
+ break;
+ }
+
+ if(i > total || !HAS_PERM(cmdtable[i].level))
+ continue;
+
+ if(refscreen) {
+ showtitle(cmdtitle, BBSName);
+
+ show_menu(cmdtable);
+
+ outmsg(mystatus);
+ refscreen = NA;
+ }
+ cursor_clear(menu_row + pos, menu_column);
+ n = pos = -1;
+ while(++n <= (lastcmdptr = i))
+ if(HAS_PERM(cmdtable[n].level))
+ pos++;
+
+ cursor_show(menu_row + pos, menu_column);
+ } while(((cmd = egetch()) != EOF) || refscreen);
+
+ abort_bbs(0);
+}
+/* INDENT OFF */
+
+/* administrator's maintain menu */
+static commands_t adminlist[] = {
+ {m_user, PERM_ACCOUNTS, "UUser ¨Ï¥ÎªÌ¸ê®Æ"},
+ {search_user_bypwd, PERM_SYSOP, "SSearch User ¯S®í·j´M¨Ï¥ÎªÌ"},
+ {search_user_bybakpwd,PERM_SYSOP, "OOld User data ¬d¾\\³Æ¥÷¨Ï¥ÎªÌ¸ê®Æ"},
+ {m_board, PERM_SYSOP, "BBoard ³]©w¬ÝªO"},
+ {m_register, PERM_SYSOP, "RRegister ¼f®Öµù¥Uªí³æ"},
+ {cat_register, PERM_SYSOP, "CCatregister µLªk¼f®Ö®É¥Îªº"},
+ {x_file, PERM_SYSOP|PERM_VIEWSYSOP, "XXfile ½s¿è¨t²ÎÀÉ®×"},
+ {give_money, PERM_SYSOP|PERM_VIEWSYSOP, "GGivemoney ¬õ¥]Âû"},
+#ifdef HAVE_MAILCLEAN
+ {m_mclean, PERM_SYSOP, "MMail Clean ²M²z¨Ï¥ÎªÌ­Ó¤H«H½c"},
+#endif
+#ifdef HAVE_REPORT
+ {m_trace, PERM_SYSOP, "TTrace ³]©w¬O§_°O¿ý°£¿ù¸ê°T"},
+#endif
+ {NULL, 0, NULL}
+};
+
+/* mail menu */
+static commands_t maillist[] = {
+ {m_new, PERM_READMAIL, "RNew ¾\\Ū·s¶i¶l¥ó"},
+ {m_read, PERM_READMAIL, "RRead ¦h¥\\¯àŪ«H¿ï³æ"},
+ {m_send, PERM_BASIC, "RSend ¯¸¤º±H«H"},
+ {main_bbcall, PERM_LOGINOK, "BBBcall \033[1;31m¹q¸Ü¯µ®Ñ\033[m"},
+ {x_love, PERM_LOGINOK, "PPaper \033[1;32m±¡®Ñ²£¥Í¾¹\033[m "},
+ {mail_list, PERM_BASIC, "RMail List ¸s²Õ±H«H"},
+ {setforward, PERM_LOGINOK,"FForward \033[32m³]©w«H½c¦Û°ÊÂà±H\033[m"},
+ {m_sysop, 0, "YYes, sir! ½Ô´A¯¸ªø"},
+ {m_internet, PERM_INTERNET, "RInternet ±H«H¨ì Internet"},
+ {mail_mbox, PERM_INTERNET, "RZip UserHome §â©Ò¦³¨p¤H¸ê®Æ¥´¥]¦^¥h"},
+ {built_mail_index, PERM_LOGINOK, "SSavemail §â«H¥ó±Ï¦^¨Ó"},
+ {mail_all, PERM_SYSOP, "RAll ±H«Hµ¹©Ò¦³¨Ï¥ÎªÌ"},
+ {NULL, 0, NULL}
+};
+
+/* Talk menu */
+static commands_t talklist[] = {
+ {t_users, 0, "UUsers §¹¥þ²á¤Ñ¤â¥U"},
+ {t_pager, PERM_BASIC, "PPager ¤Á´«©I¥s¾¹"},
+ {t_idle, 0, "IIdle µo§b"},
+ {t_query, 0, "QQuery ¬d¸ßºô¤Í"},
+ {t_qchicken, 0, "WWatch Pet ¬d¸ßÃdª«"},
+ {t_talk, PERM_PAGE, "TTalk §ä¤H²á²á"},
+ {t_chat, PERM_CHAT, "CChat §ä®a¯ù§{³ð¯ù¥h"},
+#ifdef HAVE_MUD
+ {x_mud, 0, "VVrChat \033[1;32mµêÀÀ¹ê·~²á¤Ñ¼s³õ\033[m"},
+#endif
+ {t_display, 0, "DDisplay Åã¥Ü¤W´X¦¸¼ö°T"},
+ {NULL, 0, NULL}
+};
+
+/* name menu */
+static int t_aloha() {
+ friend_edit(FRIEND_ALOHA);
+ return 0;
+}
+
+static int t_special() {
+ friend_edit(FRIEND_SPECIAL);
+ return 0;
+}
+
+static commands_t namelist[] = {
+ {t_override, PERM_LOGINOK,"OOverRide ¦n¤Í¦W³æ"},
+ {t_reject, PERM_LOGINOK, "BBlack Ãa¤H¦W³æ"},
+ {t_aloha,PERM_LOGINOK, "AALOHA ¤W¯¸³qª¾¦W³æ"},
+#ifdef POSTNOTIFY
+ {t_post,PERM_LOGINOK, "NNewPost ·s¤å³¹³qª¾¦W³æ"},
+#endif
+ {t_special,PERM_LOGINOK, "SSpecial ¨ä¥L¯S§O¦W³æ"},
+ {NULL, 0, NULL}
+};
+
+/* User menu */
+static commands_t userlist[] = {
+ {u_info, PERM_LOGINOK, "IInfo ³]©w­Ó¤H¸ê®Æ»P±K½X"},
+ {calendar, PERM_LOGINOK, "CCalendar ­Ó¤H¦æ¨Æ¾ä"},
+ {u_editcalendar, PERM_LOGINOK, "CCalendarEdit ½s¿è­Ó¤H¦æ¨Æ¾ä"},
+ {u_loginview, PERM_LOGINOK, "LLogin View ¿ï¾Ü¶i¯¸µe­±"},
+ {u_ansi, 0, "AANSI ¤Á´« ANSI \033[36m±m\033[35m¦â\033[37m/"
+ "\033[30;47m¶Â\033[1;37m¥Õ\033[m¼Ò¥Ü"},
+ {u_movie, 0, "MMovie ¤Á´«°Êµe¼Ò¥Ü"},
+#ifdef HAVE_SUICIDE
+ {u_kill, PERM_BASIC, "IKill ¦Û±þ¡I¡I"},
+#endif
+ {u_editplan, PERM_LOGINOK, "QQueryEdit ½s¿è¦W¤ùÀÉ"},
+ {u_editsig, PERM_LOGINOK, "SSignature ½s¿èñ¦WÀÉ"},
+#if HAVE_FREECLOAK
+ {u_cloak, PERM_LOGINOK, "CCloak Áô¨­³N"},
+#else
+ {u_cloak, PERM_CLOAK, "CCloak Áô¨­³N"},
+#endif
+ {u_register, PERM_BASIC, "RRegister ¶ñ¼g¡mµù¥U¥Ó½Ð³æ¡n"},
+ {u_list, PERM_SYSOP, "UUsers ¦C¥Xµù¥U¦W³æ"},
+ {NULL, 0, NULL}
+};
+
+/* XYZ tool menu */
+static commands_t xyzlist[] = {
+#ifdef HAVE_LICENSE
+ {x_gpl, 0, "LLicense GNU ¨Ï¥Î°õ·Ó"},
+#endif
+#ifdef HAVE_INFO
+ {x_program, 0, "PProgram ¥»µ{¦¡¤§ª©¥»»Pª©Åv«Å§i"},
+#endif
+ {x_boardman,0, "MMan Boards ¡m¬Ýª©ºëµØ°Ï±Æ¦æº]¡n"},
+// {x_boards,0, "HHot Boards ¡m¬Ýª©¤H®ð±Æ¦æº]¡n"},
+ {x_history, 0, "HHistory ¡m§Ú­Ìªº¦¨ªø¡n"},
+ {x_note, 0, "NNote ¡m»Ä²¢­W»¶¬y¨¥ª©¡n"},
+ {x_login,0, "SSystem ¡m¨t²Î­«­n¤½§i¡n"},
+ {x_week, 0, "WWeek ¡m¥»¶g¤­¤Q¤j¼öªù¸ÜÃD¡n"},
+ {x_issue, 0, "IIssue ¡m¤µ¤é¤Q¤j¼öªù¸ÜÃD¡n"},
+ {x_today, 0, "TToday ¡m¤µ¤é¤W½u¤H¦¸²Î­p¡n"},
+ {x_yesterday, 0, "YYesterday ¡m¬Q¤é¤W½u¤H¦¸²Î­p¡n"},
+ {x_user100 ,0, "UUsers ¡m¨Ï¥ÎªÌ¦Ê¤j±Æ¦æº]¡n"},
+ {x_birth, 0, "BBirthday ¡m¤µ¤é¹Ø¬P¤jÆ[¡n"},
+ {p_sysinfo, 0, "XXload ¡m¬d¬Ý¨t²Î­t²ü¡n"},
+ {NULL, 0, NULL}
+};
+
+/* Ptt money menu */
+static commands_t moneylist[] = {
+ {p_give, 0, "00Give µ¹¨ä¥L¤H¿ú"},
+ {save_violatelaw, 0,"11ViolateLaw ú»@³æ"},
+#if !HAVE_FREECLOAK
+ {p_cloak, 0, "22Cloak ¤Á´« Áô¨­/²{¨­ $19 /¦¸"},
+#endif
+ {p_from, 0, "33From ¼È®É­×§ï¬G¶m $49 /¦¸"},
+ {ordersong,0, "44OSong ¼Ú®á°ÊºAÂIºq¾÷ $200 /¦¸"},
+ {p_exmail, 0, "55Exmail ÁʶR«H½c $1000/«Ê"},
+ {NULL, 0, NULL}
+};
+
+static int p_money() {
+ domenu(PSALE, "¢Þtt¶q³c©±", '0', moneylist);
+ return 0;
+};
+
+static commands_t jceelist[] = {
+ {x_90,PERM_LOGINOK, "0090 JCEE ¡i90¾Ç¦~«×¤j¾ÇÁp©Û¬dº]¨t²Î¡j"},
+ {x_89,PERM_LOGINOK, "1189 JCEE ¡i89¾Ç¦~«×¤j¾ÇÁp©Û¬dº]¨t²Î¡j"},
+ {x_88,PERM_LOGINOK, "2288 JCEE ¡i88¾Ç¦~«×¤j¾ÇÁp©Û¬dº]¨t²Î¡j"},
+ {x_87,PERM_LOGINOK, "3387 JCEE ¡i87¾Ç¦~«×¤j¾ÇÁp©Û¬dº]¨t²Î¡j"},
+ {x_86,PERM_LOGINOK, "4486 JCEE ¡i86¾Ç¦~«×¤j¾ÇÁp©Û¬dº]¨t²Î¡j"},
+ {NULL, 0, NULL}
+};
+
+static int m_jcee() {
+ domenu(JCEE, "¢Þtt¬dº]¨t²Î", '0', jceelist);
+ return 0;
+}
+
+static int forsearch();
+static int playground();
+
+/* Ptt Play menu */
+static commands_t playlist[] = {
+#if HAVE_JCEE
+ {m_jcee, PERM_LOGINOK, "JJCEE ¡i ¤j¾ÇÁp¦Ò¬dº]¨t²Î ¡j"},
+#endif
+ {note, PERM_LOGINOK, "NNote ¡i ¨è¨è¬y¨¥ª© ¡j"},
+ {x_weather,0 , "WWeather ¡i ®ð¶H¹w³ø ¡j"},
+ {x_stock,0 , "SStock ¡i ªÑ¥«¦æ±¡ ¡j"},
+#ifdef HAVE_BIG2
+ {x_big2, 0, "BBig2 ¡i ºô¸ô¤j¦Ñ¤G ¡j"},
+#endif
+#ifdef HAVE_MJ
+ {x_mj, PERM_LOGINOK, "QQkmj ¡i ºô¸ô¥´³Â±N ¡j"},
+#endif
+#ifdef HAVE_BRIDGE
+ {x_bridge, PERM_LOGINOK, "OOkBridge ¡i ¾ôµPÄv§Þ ¡j"},
+#endif
+#ifdef HAVE_GOPHER
+ {x_gopher, PERM_LOGINOK, "GGopher ¡i ¦a¹«¸ê®Æ®w ¡j"},
+#endif
+#ifdef HAVE_TIN
+ {x_tin, PERM_LOGINOK, "NNEWS ¡i ºô»Ú·s»D ¡j"},
+#endif
+#ifdef BBSDOORS
+ {x_bbsnet, PERM_LOGINOK, "BBBSNet ¡i ¨ä¥L BBS¯¸ ¡j"},
+#endif
+#ifdef HAVE_WWW
+ {x_www, PERM_LOGINOK, "WWWW Browser ¡i ¨L¨L¨L ¡j"},
+#endif
+ {forsearch,PERM_LOGINOK, "SSearchEngine¡i\033[1;35m ¢Þtt·j´M¾¹ \033[m¡j"},
+ {topsong,PERM_LOGINOK, "TTop Songs ¡i\033[1;32m¼Ú®áÂIºq±Æ¦æº]\033[m¡j"},
+ {p_money,PERM_LOGINOK, "PPay ¡i\033[1;31m ¢Þtt¶q³c©± \033[m¡j"},
+ {chicken_main,PERM_LOGINOK, "CChicken "
+ "¡i\033[1;34m ¢Þtt¾iÂû³õ \033[m¡j"},
+ {playground,PERM_LOGINOK, "AAmusement ¡i\033[1;33m ¢Þtt¹C¼Ö³õ \033[m¡j"},
+ {NULL, 0, NULL}
+};
+
+static commands_t plist[] = {
+
+/* {p_ticket_main, PERM_LOGINOK,"00Pre ¡i Á`²Î¾÷ ¡j"},
+ {alive, PERM_LOGINOK, "00Alive ¡i ­q²¼Âû ¡j"},
+*/
+ {ticket_main, PERM_LOGINOK, "11Gamble ¡i ¢Þtt½ä³õ ¡j"},
+ {guess_main, PERM_LOGINOK, "22Guess number¡i ²q¼Æ¦r ¡j"},
+ {othello_main, PERM_LOGINOK, "33Othello ¡i ¶Â¥Õ´Ñ ¡j"},
+// {dice_main, PERM_LOGINOK, "44Dice ¡i ª±»ë¤l ¡j"},
+ {vice_main, PERM_LOGINOK, "44Vice ¡i µo²¼¹ï¼ú ¡j"},
+ {g_card_jack, PERM_LOGINOK, "55Jack ¡i ¶Â³Ç§J ¡j"},
+ {g_ten_helf, PERM_LOGINOK, "66Tenhalf ¡i ¤QÂI¥b ¡j"},
+ {card_99, PERM_LOGINOK, "77Nine ¡i ¤E¤Q¤E ¡j"},
+ {NULL, 0, NULL}
+};
+
+static int playground() {
+ domenu(AMUSE, "¢Þtt¹C¼Ö³õ",'1',plist);
+ return 0;
+}
+
+static commands_t slist[] = {
+ {x_dict,0, "11Dictionary "
+ "¡i\033[1;33m ½ì¨ý¤j¦r¨å \033[m¡j"},
+ {main_railway, PERM_LOGINOK, "33Railway "
+ "¡i\033[1;32m ¤õ¨®ªí¬d¸ß \033[m¡j"},
+ {NULL, 0, NULL}
+};
+
+static int forsearch() {
+ domenu(SREG, "¢Þtt·j´M¾¹", '1', slist);
+ return 0;
+}
+
+/* main menu */
+
+static int admin() {
+ domenu(ADMIN, "¨t²ÎºûÅ@", 'X', adminlist);
+ return 0;
+}
+
+static int Mail() {
+ domenu(MAIL, "¹q¤l¶l¥ó", 'R', maillist);
+ return 0;
+}
+
+static int Talk() {
+ domenu(TMENU, "²á¤Ñ»¡¸Ü", 'U', talklist);
+ return 0;
+}
+
+static int User() {
+ domenu(UMENU, "­Ó¤H³]©w", 'A', userlist);
+ return 0;
+}
+
+static int Xyz() {
+ domenu(XMENU, "¤u¨ãµ{¦¡", 'M', xyzlist);
+ return 0;
+}
+
+static int Play_Play() {
+ domenu(PMENU, "ºô¸ô¹C¼Ö³õ", 'A', playlist);
+ return 0;
+}
+
+static int Name_Menu() {
+ domenu(NMENU, "¥Õ¦â®£©Æ", 'O', namelist);
+ return 0;
+}
+
+commands_t cmdlist[] = {
+ {admin,PERM_SYSOP|PERM_VIEWSYSOP, "00Admin ¡i ¨t²ÎºûÅ@°Ï ¡j"},
+ {Announce, 0, "AAnnounce ¡i ºëµØ¤½§GÄæ ¡j"},
+ {Boards, 0, "FFavorite ¡i §Ú ªº ³Ì·R ¡j"},
+ {root_board, 0, "CClass ¡i ¤À²Õ°Q½×°Ï ¡j"},
+ {Mail, PERM_BASIC, "MMail ¡i ¨p¤H«H¥ó°Ï ¡j"},
+ {Talk, 0, "TTalk ¡i ¥ð¶¢²á¤Ñ°Ï ¡j"},
+ {User, 0, "UUser ¡i ­Ó¤H³]©w°Ï ¡j"},
+ {Xyz, 0, "XXyz ¡i ¨t²Î¤u¨ã°Ï ¡j"},
+ {Play_Play,0, "PPlay ¡i ¹C¼Ö³õ/¤j¾Ç¬dº]¡j"},
+ {Name_Menu,PERM_LOGINOK, "NNamelist ¡i ½s¯S§O¦W³æ ¡j"},
+ {Goodbye, 0, "GGoodbye Â÷¶}¡A¦A¨£¡K¡K"},
+ {NULL, 0, NULL}
+};
diff --git a/mbbsd/more.c b/mbbsd/more.c
new file mode 100644
index 00000000..f7755874
--- /dev/null
+++ b/mbbsd/more.c
@@ -0,0 +1,931 @@
+/* $Id: more.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "modes.h"
+#include "perm.h"
+#include "proto.h"
+
+extern int showansi;
+extern int t_lines, t_columns; /* Screen size / width */
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+extern char *str_author1;
+extern char *str_author2;
+extern char *str_post1;
+extern char *str_post2;
+extern char *msg_seperator;
+extern char reset_color[];
+
+#define MORE_BUFSIZE 4096
+#define MORE_WINSIZE 4096
+#define STR_ANSICODE "[0123456789;,"
+
+static int more_base, more_size, more_head;
+static unsigned char more_pool[MORE_BUFSIZE];
+
+
+#define MAXPATHLEN 256
+static char *more_help[] = {
+ "\0¾\\Ū¤å³¹¥\\¯àÁä¨Ï¥Î»¡©ú",
+ "\01´å¼Ð²¾°Ê¥\\¯àÁä",
+ "(¡ô) ¤W±²¤@¦æ",
+ "(¡õ)(Enter) ¤U±²¤@¦æ",
+ "(^B)(PgUp)(BackSpace) ¤W±²¤@­¶",
+ "(¡÷)(PgDn)(Space) ¤U±²¤@­¶",
+ "(0)(g)(Home) Àɮ׶}ÀY",
+ "($)(G) (End) ÀÉ®×µ²§À",
+ "\01¨ä¥L¥\\¯àÁä",
+ "(/) ·j´M¦r¦ê",
+ "(n/N) ­«½Æ¥¿/¤Ï¦V·j´M",
+ "(TAB) URL³sµ²",
+ "(Ctrl-T) ¦s¨ì¼È¦sÀÉ",
+ "(:/f/b) ¸õ¦Ü¬Y­¶/¤U/¤W½g",
+ "(F/B) ¸õ¦Ü¦P¤@·j´M¥DÃD¤U/¤W½g",
+ "(a/A) ¸õ¦Ü¦P¤@§@ªÌ¤U/¤W½g",
+ "([/]) ¥DÃD¦¡¾\\Ū ¤W/¤U",
+ "(t) ¥DÃD¦¡´`§Ç¾\\Ū",
+ "(Ctrl-C) ¤p­pºâ¾÷",
+ "(q)(¡ö) µ²§ô",
+ "(h)(H)(?) »²§U»¡©úµe­±",
+ NULL
+};
+
+int beep = 0;
+
+static void
+more_goto (int fd, off_t off)
+{
+ int base = more_base;
+
+ if (off < base || off >= base + more_size)
+ {
+ more_base = base = off & (-MORE_WINSIZE);
+ lseek (fd, base, SEEK_SET);
+ more_size = read (fd, more_pool, MORE_BUFSIZE);
+ }
+ more_head = off - base;
+}
+
+static int
+more_readln (int fd, unsigned char *buf)
+{
+ int ch;
+
+ unsigned char *data, *tail, *cc;
+ int len, bytes, in_ansi;
+ int size, head, ansilen;
+
+ len = bytes = in_ansi = ansilen = 0;
+ tail = buf + ANSILINELEN - 1;
+ size = more_size;
+ head = more_head;
+ data = &more_pool[head];
+
+ do
+ {
+ if (head >= size)
+ {
+ more_base += size;
+ data = more_pool;
+ more_size = size = read (fd, data, MORE_BUFSIZE);
+ if (size == 0)
+ break;
+ head = 0;
+ }
+
+ ch = *data++;
+ head++;
+ bytes++;
+ if (ch == '\n')
+ {
+ break;
+ }
+ if (ch == '\t')
+ {
+ do
+ {
+ *buf++ = ' ';
+ }
+ while ((++len & 7) && len < 80);
+ }
+ else if (ch == '\033')
+ {
+ if (atoi (data + 1) > 47)
+ {
+ if ((cc = strchr (data + 1, 'm')) != NULL)
+ {
+ ch = cc - data + 1;
+
+ data += ch;
+ head += ch;
+ bytes += ch;
+ }
+ }
+ else
+ {
+ if (showansi)
+ *buf++ = ch;
+ in_ansi = 1;
+ }
+ }
+ else if (in_ansi)
+ {
+ if (showansi)
+ *buf++ = ch;
+ if (!strchr (STR_ANSICODE, ch))
+ in_ansi = 0;
+ }
+ else if (isprint2 (ch))
+ {
+ len++;
+ *buf++ = ch;
+ }
+ }
+ while (len < 80 && buf < tail);
+ *buf = '\0';
+ more_head = head;
+ return bytes;
+}
+
+/* not used
+static int readln(FILE *fp, char *buf) {
+ register int ch, i, len, bytes, in_ansi;
+
+ len = bytes = in_ansi = i = 0;
+ while(len < 80 && i < ANSILINELEN && (ch = getc(fp)) != EOF) {
+ bytes++;
+ if(ch == '\n')
+ break;
+ else if(ch == '\t')
+ do {
+ buf[i++] = ' ';
+ } while((++len & 7) && len < 80);
+ else if(ch == '\a')
+ beep = 1;
+ else if(ch == '\033') {
+ if(showansi)
+ buf[i++] = ch;
+ in_ansi = 1;
+ } else if(in_ansi) {
+ if(showansi)
+ buf[i++] = ch;
+ if(!strchr("[0123456789;,", ch))
+ in_ansi = 0;
+ } else if(isprint2(ch)) {
+ len++;
+ buf[i++] = ch;
+ }
+ }
+ buf[i] = '\0';
+ return bytes;
+}
+*/
+
+extern userec_t cuser;
+
+static int more_web(char *fpath, int promptend);
+
+int more(char *fpath, int promptend) {
+ extern char* strcasestr();
+ static char *head[4] = {"§@ªÌ", "¼ÐÃD", "®É¶¡" ,"Âà«H"};
+ char *ptr, *word = NULL, buf[ANSILINELEN + 1], *ch1;
+ struct stat st;
+
+/* rocker */
+ //FILE *fp;
+ int fd, fsize;
+
+ unsigned int pagebreak[MAX_PAGES], pageno, lino = 0;
+ int line, ch, viewed, pos, numbytes;
+ int header = 0;
+ int local = 0;
+ char search_char0=0;
+ static char search_str[81]="";
+ typedef char* (*FPTR)();
+ static FPTR fptr;
+ int searching = 0;
+ int scrollup = 0;
+ char *printcolor[3]= {"44","33;45","0;34;46"}, color =0;
+ char *http[80]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+ /* Ptt */
+ char pagemode = 0;
+ char pagecount = 0;
+
+ memset(pagebreak, 0, sizeof(pagebreak));
+ if(*search_str)
+ search_char0 = *search_str;
+ *search_str = 0;
+
+
+ fd = open (fpath, O_RDONLY, 0600);
+ if (fd < 0) return -1;
+
+ if(fstat(fd, &st) || ((fsize = st.st_size) <= 0) || S_ISDIR (st.st_mode))
+ {
+ close(fd); //Ptt
+ return -1;
+ }
+ pagebreak[0] = pageno = viewed = line = pos = 0;
+ clear();
+
+/* rocker */
+
+ more_base = more_head = more_size = 0;
+
+ while((numbytes = more_readln(fd, buf)) || (line == t_lines)) {
+ if(scrollup) {
+ rscroll();
+ move(0, 0);
+ }
+ if(numbytes) { /* ¤@¯ë¸ê®Æ³B²z */
+ if(!viewed) { /* begin of file */
+ if(showansi) { /* header processing */
+ if(!strncmp(buf, str_author1, LEN_AUTHOR1)) {
+ line = 3;
+ word = buf + LEN_AUTHOR1;
+ local = 1;
+ } else if(!strncmp(buf, str_author2, LEN_AUTHOR2)) {
+ line = 4;
+ word = buf + LEN_AUTHOR2;
+ }
+
+ while(pos < line) {
+ if(!pos && ((ptr = strstr(word, str_post1)) ||
+ (ptr = strstr(word, str_post2)))) {
+ ptr[-1] = '\0';
+ prints("\033[47;34m %s \033[44;37m%-53.53s"
+ "\033[47;34m %.4s \033[44;37m%-13s\033[m\n",
+ head[0], word, ptr, ptr + 5);
+ } else if (pos < 4)
+ prints("\033[47;34m %s \033[44;37m%-72.72s"
+ "\033[m\n", head[pos], word);
+
+ viewed += numbytes;
+ numbytes = more_readln(fd, buf);
+
+ /* ²Ä¤@¦æ¤Óªø¤F */
+ if(!pos && viewed > 79) {
+ /* ²Ä¤G¦æ¤£¬O [¼Ð....] */
+ if(memcmp( buf, head[1], 2)) {
+ /* Ū¤U¤@¦æ¶i¨Ó³B²z */
+ viewed += numbytes;
+ numbytes = more_readln(fd, buf);
+ }
+ }
+ pos++;
+ }
+ if(pos) {
+ header = 1;
+
+ prints("\033[36m%s\033[m\n", msg_seperator);
+ line = pos = 4;
+ }
+ }
+ lino = pos;
+ word = NULL;
+ }
+
+ /* ¡°³B²z¤Þ¥ÎªÌ & ¤Þ¨¥ */
+ if((buf[1] == ' ') && (buf[0] == ':' || buf[0] == '>'))
+ word = "\033[36m";
+ else if(!strncmp(buf, "¡°", 2) || !strncmp(buf, "==>", 3))
+ word = "\033[32m";
+
+ ch1 = buf;
+ while(1) {
+ int i;
+ char e,*ch2;
+
+ if((ch2 = strstr(ch1, "http://")))
+ ;
+ else if((ch2 = strstr(ch1,"gopher://")))
+ ;
+ else if((ch2 = strstr(ch1,"mailto:")))
+ ;
+ else
+ break;
+ for(e = 0; ch2[(int)e] != ' ' && ch2[(int)e] != '\n' &&
+ ch2[(int)e] != '\0' && ch2[(int)e] != '"' &&
+ ch2[(int)e] != ';' && ch2[(int)e] != ']'; e++);
+ for(i = 0; http[i] && i < 80; i++)
+ if(!strncmp(http[i], ch2, e) && http[(int)e] == 0)
+ break;
+ if(!http[i]) {
+ http[i] = (char *)malloc(e + 1);
+ strncpy(http[i], ch2, e);
+ http[i][(int)e] = 0;
+ pagecount++;
+ }
+ ch1 = &ch2[7];
+ }
+ if(word)
+ outs(word);
+ {
+ char msg[500], *pos;
+
+ if(*search_str && (pos = fptr(buf, search_str))) {
+ char SearchStr[81];
+ char buf1[100], *pos1;
+
+ strncpy(SearchStr, pos, strlen(search_str));
+ SearchStr[strlen(search_str)] = 0;
+ searching = 0;
+ sprintf(msg, "%.*s\033[7m%s\033[m", pos - buf, buf,
+ SearchStr);
+ while((pos = fptr(pos1 = pos + strlen(search_str),
+ search_str))) {
+ sprintf(buf1, "%.*s\033[7m%s\033[m", pos - pos1,
+ pos1, SearchStr);
+ strcat(msg, buf1);
+ }
+ strcat(msg, pos1);
+ outs(Ptt_prints(msg,NO_RELOAD));
+ } else
+ outs(Ptt_prints(buf,NO_RELOAD));
+ }
+ if(word) {
+ outs("\033[m");
+ word = NULL;
+ }
+ outch('\n');
+
+ if(beep) {
+ bell();
+ beep = 0;
+ }
+
+ if(line < b_lines) /* ¤@¯ë¸ê®ÆŪ¨ú */
+ line++;
+
+ if(line == b_lines && searching == -1) {
+ if(pageno > 0)
+ more_goto(fd, viewed = pagebreak[--pageno]);
+ else
+ searching = 0;
+ lino = pos = line = 0;
+ clear();
+ continue;
+ }
+
+ if(scrollup) {
+ move(line = b_lines, 0);
+ clrtoeol();
+ for(pos = 1; pos < b_lines; pos++)
+ viewed += more_readln(fd, buf);
+ } else if(pos == b_lines) /* ±²°Ê¿Ã¹õ */
+ scroll();
+ else
+ pos++;
+
+ if(!scrollup && ++lino >= b_lines && pageno < MAX_PAGES - 1) {
+ pagebreak[++pageno] = viewed;
+ lino = 1;
+ }
+
+ if(scrollup) {
+ lino = scrollup;
+ scrollup = 0;
+ }
+ viewed += numbytes; /* ²Ö­pŪ¹L¸ê®Æ */
+ } else
+ line = b_lines; /* end of END */
+
+ if(promptend &&
+ ((!searching && line == b_lines) || viewed == fsize)) {
+ /* Kaede ­è¦n 100% ®É¤£°± */
+ move(b_lines, 0);
+ if(viewed == fsize) {
+ if(searching == 1)
+ searching = 0;
+ color = 0;
+ } else if(pageno == 1 && lino == 1) {
+ if(searching == -1)
+ searching = 0;
+ color = 1;
+ } else
+ color = 2;
+
+ prints("\033[m\033[%sm ÂsÄý P.%d(%d%%) %s %-30.30s%s",
+ printcolor[(int)color],
+ pageno,
+ (int)((viewed * 100) / fsize),
+ pagemode ? "\033[30;47m" : "\033[31;47m",
+ pagemode ? http[pagemode-1] : "(h)\033[30m¨D§U \033[31m¡÷¡õ[PgUp][",
+ pagemode ? "\033[31m[TAB]\033[30m¤Á´« \033[31m[Enter]\033[30m¿ï©w \033[31m¡ö\033[30m©ñ±ó\033[m" : "PgDn][Home][End]\033[30m´å¼Ð²¾°Ê \033[31m¡ö[q]\033[30mµ²§ô \033[m");
+
+
+ while(line == b_lines || (line > 0 && viewed == fsize)) {
+ switch((ch = egetch())) {
+ case ':':
+ {
+ char buf[10];
+ int i = 0;
+
+ getdata(b_lines - 1, 0, "Goto Page: ", buf, 5, DOECHO);
+ sscanf(buf, "%d", &i);
+ if(0 < i && i < MAX_PAGES && (i == 1 || pagebreak[i - 1]))
+ pageno = i - 1;
+ else if(pageno)
+ pageno--;
+ lino = line = 0;
+ break;
+ }
+ case '/':
+ {
+ char ans[4] = "n";
+
+ *search_str = search_char0;
+ getdata_buf(b_lines - 1, 0,"[·j´M]ÃöÁä¦r:", search_str,
+ 40, DOECHO);
+ if(*search_str) {
+ searching = 1;
+ if(getdata(b_lines - 1, 0, "°Ï¤À¤j¤p¼g(Y/N/Q)? [N] ",
+ ans, 4, LCECHO) && *ans == 'y')
+ fptr = strstr;
+ else
+ fptr = strcasestr;
+ }
+ if(*ans == 'q')
+ searching = 0;
+ if(pageno)
+ pageno--;
+ lino = line = 0;
+ break;
+ }
+ case 'n':
+ if(*search_str) {
+ searching = 1;
+ if(pageno)
+ pageno--;
+ lino = line = 0;
+ }
+ break;
+ case 'N':
+ if(*search_str) {
+ searching = -1;
+ if(pageno)
+ pageno--;
+ lino = line = 0;
+ }
+ break;
+ case 'r':
+ case 'R':
+ case 'Y':
+ close(fd);
+ return 7;
+ case 'y':
+ close(fd);
+ return 8;
+ case 'A':
+ close(fd);
+ return 9;
+ case 'a':
+ close(fd);
+ return 10;
+ case 'F':
+ close(fd);
+ return 11;
+ case 'B':
+ close(fd);
+ return 12;
+ case KEY_LEFT:
+ if(pagemode) {
+ pagemode = 0;
+ *search_str = 0;
+ if(pageno)
+ pageno--;
+ lino = line = 0;
+ break;
+ }
+ close(fd);
+ return 6;
+ case 'q':
+ close(fd);
+ return 0;
+ case 'b':
+ close(fd);
+ return 1;
+ case 'f':
+ close(fd);
+ return 3;
+ case ']': /* Kaede ¬°¤F¥DÃD¾\Ū¤è«K */
+ close(fd);
+ return 4;
+ case '[': /* Kaede ¬°¤F¥DÃD¾\Ū¤è«K */
+ close(fd);
+ return 2;
+ case '=': /* Kaede ¬°¤F¥DÃD¾\Ū¤è«K */
+ close(fd);
+ return 5;
+ case Ctrl('F'):
+ case KEY_PGDN:
+ line = 1;
+ break;
+ case 't':
+ if(viewed == fsize) {
+ close(fd);
+ return 4;
+ }
+ line = 1;
+ break;
+ case ' ':
+ if(viewed == fsize) {
+ close(fd);
+ return 3;
+ }
+ line = 1;
+ break;
+ case KEY_RIGHT:
+ if(viewed == fsize) {
+ close(fd);
+ return 0;
+ }
+ line = 1;
+ break;
+ case '\r':
+ case '\n':
+ if(pagemode) {
+ more_web(http[pagemode-1],YEA);
+ pagemode = 0;
+ *search_str = 0;
+ if(pageno)
+ pageno--;
+ lino = line = 0;
+ break;
+ }
+ case KEY_DOWN:
+ if(viewed == fsize ||
+ (promptend == 2 && (ch == '\r' || ch == '\n'))) {
+ close(fd);
+ return 3;
+ }
+ line = t_lines - 2;
+ break;
+ case '$':
+ case 'G':
+ case KEY_END:
+ line = t_lines;
+ break;
+ case '0':
+ case 'g':
+ case KEY_HOME:
+ pageno = line = 0;
+ break;
+ case 'h':
+ case 'H':
+ case '?':
+ /* Kaede Buggy ... */
+ show_help(more_help);
+ if(pageno)
+ pageno--;
+ lino = line = 0;
+ break;
+ case 'E':
+ if(HAS_PERM(PERM_SYSOP) && strcmp(fpath, "etc/ve.hlp")) {
+ close(fd);
+ vedit(fpath, NA, NULL);
+ return 0;
+ }
+ break;
+ case Ctrl('C'):
+ cal();
+ if(pageno)
+ pageno--;
+ lino = line = 0;
+ break;
+
+ case Ctrl('T'):
+ getdata(b_lines - 2, 0, "§â³o½g¤å³¹¦¬¤J¨ì¼È¦sÀÉ¡H[y/N] ",
+ buf, 4, LCECHO);
+ if(buf[0] == 'y') {
+ char tmpbuf[128];
+
+ setuserfile(tmpbuf, ask_tmpbuf(b_lines - 1));
+ sprintf(buf, "cp -f %s %s", fpath, tmpbuf);
+ system(buf);
+ }
+ if(pageno)
+ pageno--;
+ lino = line = 0;
+ break;
+#if 0
+ case Ctrl('I'):
+ if(!pagecount)
+ break;
+ pagemode = (pagemode % pagecount) + 1;
+ strncpy(search_str,http[pagemode-1],80);
+ search_str[80] =0;
+ fptr = strstr;
+ if(pageno)
+ pageno--;
+ lino = line = 0;
+ break;
+#endif
+ case KEY_UP:
+ line = -1;
+ break;
+ case Ctrl('B'):
+ case KEY_PGUP:
+ if(pageno > 1) {
+ if(lino < 2)
+ pageno -= 2;
+ else
+ pageno--;
+ lino = line = 0;
+ } else if(pageno && lino > 1)
+ pageno = line = 0;
+ break;
+ case Ctrl('H'):
+ if(pageno > 1) {
+ if(lino < 2)
+ pageno -= 2;
+ else
+ pageno--;
+ lino = line = 0;
+ } else if(pageno && lino > 1)
+ pageno = line = 0;
+ else {
+ close(fd);
+ return 1;
+ }
+ }
+ }
+
+ if(line > 0) {
+ move(b_lines, 0);
+ clrtoeol();
+ refresh();
+ } else if(line < 0) { /* Line scroll up */
+ if(pageno <= 1) {
+ if(lino == 1 || !pageno) {
+ close(fd);
+ return 1;
+ }
+ if(header && lino <= 5) {
+ more_goto(fd, viewed = pagebreak[scrollup = lino =
+ pageno = 0] = 0);
+ clear();
+ }
+ }
+ if(pageno && lino > 1 + local) {
+ line = (lino - 2) - local;
+ if(pageno > 1 && viewed == fsize)
+ line += local;
+ scrollup = lino - 1;
+ more_goto(fd, viewed = pagebreak[pageno - 1]);
+ while(line--)
+ viewed += more_readln(fd, buf);
+ } else if(pageno > 1) {
+ scrollup = b_lines - 1;
+ line = (b_lines - 2) - local;
+ more_goto(fd, viewed = pagebreak[--pageno - 1]);
+ while(line--)
+ viewed += more_readln(fd, buf);
+ }
+ line = pos = 0;
+ } else {
+ pos = 0;
+ more_goto (fd, viewed = pagebreak[pageno]);
+ move(0,0);
+ clear();
+ }
+ }
+ }
+
+ close(fd);
+ if(promptend) {
+ pressanykey();
+ clear();
+ } else
+ outs(reset_color);
+ return 0;
+}
+
+static int more_web(char *fpath, int promptend) {
+ char *ch, *ch1 = NULL;
+ char *hostname = fpath,userfile[MAXPATHLEN],file[MAXPATHLEN]="/";
+ char genbuf[200];
+ time_t dtime;
+#if !defined(USE_LYNX) && defined(USE_PROXY)
+ int a;
+ FILE *fp;
+ struct hostent *h;
+ struct sockaddr_in sin;
+#endif
+
+ if((ch = strstr(fpath, "mailto:"))) {
+ if(!HAS_PERM(PERM_LOGINOK)) {
+ move(b_lines - 1,0);
+ outs("\033[41m ±zªºÅv­­¤£¨¬µLªk¨Ï¥Îinternet mail... \033[m");
+ refresh();
+ return 0;
+ }
+ if(!invalidaddr(&ch[7]) &&
+ getdata(b_lines - 1, 0, "[±H«H]¥DÃD¡G", genbuf, 40, DOECHO))
+ do_send(&ch[7], genbuf);
+ else {
+ move(b_lines - 1,0);
+ outs("\033[41m ¦¬«H¤Hemail ©Î ¼ÐÃD ¦³»~... \033[m");
+ refresh();
+ }
+ return 0;
+ }
+ if((ch = strstr(fpath, "gopher://"))) {
+ item_t item;
+
+ strcpy(item.X.G.server, &ch[9]);
+ strcpy(item.X.G.path, "1/");
+ item.X.G.port = 70;
+ gem(fpath , &item, 0);
+ return 0;
+ }
+ if((ch = strstr(fpath, "http://")))
+ hostname=&ch[7];
+ if((ch = strchr(hostname, '/'))) {
+ *ch = 0;
+ if(&ch1[1])
+ strcat(file,&ch[1]);
+ }
+ if(file[strlen(file) - 1] == '/')
+ strcat(file,"index.html");
+ move(b_lines-1,0);
+ clrtoeol();
+#ifdef USE_PROXY
+ sprintf(genbuf, "\033[33;44m ¥¿¦b³s©¹%s.(proxy:%s).....½Ðµy­Ô....\033[m",
+ hostname, PROXYSERVER);
+#else
+ sprintf(genbuf, "\033[33;44m ¥¿¦b³s©¹%s......½Ðµy­Ô....\033[m", hostname);
+#endif
+ outs(genbuf);
+ refresh();
+
+#ifdef LOCAL_PROXY
+/* ¥ý§ä local disk ªº proxy */
+ time(&dtime);
+ sprintf(userfile,"hproxy/%s%s",hostname,file);
+ if(dashf(userfile) && (dtime - dasht(userfile)) < HPROXYDAY * 24 * 60
+ && more(userfile,promptend)) {
+ return 1;
+ }
+ ch=userfile - 1;
+ while((ch1 = strchr(ch + 1,'/'))) {
+ *ch1 = 0;
+ if(!dashd(ch))
+ mkdir(ch+1,0755);
+ chdir(ch+1);
+ *ch1 = '/';
+ ch = ch1;
+ }
+ chdir(BBSHOME);
+#endif
+
+#ifndef USE_LYNX
+#ifdef USE_PROXY
+ if(!(h = gethostbyname(PROXYSERVER))) {
+ outs("\033[33;44m §ä¤£¨ì³o­Óproxy server!..\033[m");
+ refresh();
+ return;
+ }
+ ()memset((char *)&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+
+ if(h == NULL)
+ sin.sin_addr.s_addr = inet_addr(PROXYSERVER);
+ else
+ ()memcpy(&sin.sin_addr.s_addr, h->h_addr, h->h_length);
+
+ sin.sin_port = htons((ushort)PROXYPORT); /* HTTP port */
+ a = socket(AF_INET, SOCK_STREAM, 0);
+ if((connect(a, (struct sockaddr *) & sin, sizeof sin)) < 0) {
+ outs("\033[1;44m ³s±µ¨ìproxy¨ü¨ì©Úµ´ ! \033[m");
+ refresh();
+ return;
+ }
+ sprintf(genbuf,"GET http://%s/%s HTTP/1.1\n",hostname,file);
+#else
+ if(!(h = gethostbyname(hostname))) {
+ outs("\033[33;44m §ä¤£¨ì³o­Óserver!..\033[m");
+ refresh();
+ return;
+ }
+ ()memset((char *) &sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+
+ if(h == NULL)
+ sin.sin_addr.s_addr = inet_addr(hostname);
+ else
+ ()memcpy(&sin.sin_addr.s_addr, h->h_addr, h->h_length);
+
+ sin.sin_port = htons((ushort)80);
+ a = socket(AF_INET, SOCK_STREAM, 0);
+ if((connect(a, (struct sockaddr *) & sin, sizeof sin)) < 0) {
+ outs("\033[1;44m ³s±µ¨ü¨ì©Úµ´ ! \033[m");
+ refresh();
+ return;
+ }
+ sprintf(genbuf, "GET %s\n", file);
+#endif
+
+ for(i = strlen(file); file[i - 1] != '/' && i > 0 ; i--);
+ file[i] = 0;
+
+ i = strlen(genbuf);
+ write(a, genbuf, i);
+
+#define BLANK 001
+#define ISPRINT 002
+#define PRE 004
+#define CENTER 010
+ if((fp = fopen(userfile,"w"))) {
+ int flag = 2, c;
+ char path[MAXPATHLEN];
+ unsigned char j, k;
+
+ while((i = read(a,genbuf,200))) {
+ if(i < 0)
+ return;
+ genbuf[i]=0;
+
+ for(j = 0, k = 0; genbuf[j] && j < i; j++) {
+ if((flag & ISPRINT) && genbuf[j] == '<')
+ flag |= BLANK;
+ else if((flag & ISPRINT) && genbuf[j] == '>')
+ flag &= ~BLANK;
+ else {
+ if(!(flag & BLANK)) {
+ if(j != k && (genbuf[j] != '\n' || flag & PRE))
+ genbuf[k++] = genbuf[j];
+ } else {
+ switch(char_lower(genbuf[j])) {
+ case 'a':
+ break;
+ case 'b':
+ if(genbuf[j + 1] == 'r' && genbuf[j + 2] == '>')
+ genbuf[k++] = '\n';
+ break;
+ case 'h':
+ if(genbuf[j + 1] == 'r' &&
+ (genbuf[j + 2] == '>' ||
+ genbuf[j + 2] == 's')) {
+ strncpy(&genbuf[k], "\n--\n", 4);
+ k += 4;
+ }
+ break;
+ case 'l':
+ if(genbuf[j + 1] == 'i' && genbuf[j + 2]=='>') {
+ strncpy(&genbuf[k], "\n¡· ", 4);
+ k += 4;
+ }
+ break;
+ case 'p':
+ if(genbuf[j + 1]=='>') {
+ genbuf[k++] = '\n';
+ genbuf[k++] = '\n';
+ } else if(genbuf[j + 1] == 'r' &&
+ genbuf[j + 2] == 'e')
+ flag ^= PRE;
+ break;
+ case 't':
+ if(genbuf[j + 1] == 'd' && genbuf[j + 2]=='>') {
+ strncpy(&genbuf[k], "\n-\n", 3);
+ k += 3;
+ }
+ break;
+ }
+ }
+ if((genbuf[j] & 0x80) && (flag & ISPRINT))
+ flag &= ~ISPRINT;
+ else
+ flag |= ISPRINT;
+ }
+ }
+ genbuf[k]=0;
+ fputs(genbuf, fp);
+ }
+ fclose(fp);
+ close(a);
+ return more(userfile, promptend);
+ }
+ return 0;
+#else /* use lynx dump */
+ sprintf(genbuf, "lynx -dump http://%s%s > %s", hostname, file, userfile);
+ system(genbuf);
+ return more(userfile, promptend);
+#endif
+}
diff --git a/mbbsd/name.c b/mbbsd/name.c
new file mode 100644
index 00000000..2f84a1fe
--- /dev/null
+++ b/mbbsd/name.c
@@ -0,0 +1,473 @@
+/* $Id: name.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <signal.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "proto.h"
+
+extern char *str_space;
+extern int p_lines; /* a Page of Screen line numbers: tlines-4 */
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+
+word_t *toplev = NULL;
+static word_t *current = NULL;
+static char *msg_more = "\033[7m-- More --\033[m";
+
+typedef char (*arrptr)[];
+/* name complete for user ID */
+
+static int UserMaxLen(char cwlist[][IDLEN + 1], int cwnum, int morenum,
+ int count) {
+ int len, max = 0;
+
+ while(count-- > 0 && morenum < cwnum) {
+ len = strlen(cwlist[morenum++]);
+ if (len > max)
+ max = len;
+ }
+ return max;
+}
+
+static int UserSubArray(char cwbuf[][IDLEN + 1], char cwlist[][IDLEN + 1],
+ int cwnum, int key, int pos) {
+ int key2, num = 0;
+ int n, ch;
+
+ key = chartoupper(key);
+ if(key >= 'A' && key <= 'Z')
+ key2 = key | 0x20;
+ else
+ key2 = key ;
+
+ for(n = 0; n < cwnum; n++) {
+ ch = cwlist[n][pos];
+ if(ch == key || ch == key2)
+ strcpy(cwbuf[num++], cwlist[n]);
+ }
+ return num;
+}
+
+static void FreeNameList() {
+ word_t *p, *temp;
+
+ for(p = toplev; p; p = temp) {
+ temp = p->next;
+ free(p->word);
+ free(p);
+ }
+}
+
+void CreateNameList() {
+ if(toplev)
+ FreeNameList();
+ toplev = current = NULL;
+}
+
+void AddNameList(char *name) {
+ word_t *node;
+
+ node = (word_t *)malloc(sizeof(word_t));
+ node->next = NULL;
+ node->word = (char *)malloc(strlen(name) + 1);
+ strcpy(node->word, name);
+
+ if(toplev)
+ current = current->next = node;
+ else
+ current = toplev = node;
+}
+
+int RemoveNameList(char *name) {
+ word_t *curr, *prev = NULL;
+
+ for(curr = toplev; curr; curr = curr->next) {
+ if(!strcmp(curr->word, name)) {
+ if(prev == NULL)
+ toplev = curr->next;
+ else
+ prev->next = curr->next;
+
+ if(curr == current)
+ current = prev;
+ free(curr->word);
+ free(curr);
+ return 1;
+ }
+ prev = curr;
+ }
+ return 0;
+}
+
+int InNameList(char *name) {
+ word_t *p;
+
+ for(p = toplev; p; p = p->next)
+ if(!strcmp(p->word, name))
+ return 1;
+ return 0;
+}
+
+void ShowNameList(int row, int column, char *prompt) {
+ word_t *p;
+
+ move(row, column);
+ clrtobot();
+ outs(prompt);
+
+ column = 80;
+ for(p = toplev; p; p = p->next) {
+ row = strlen(p->word) + 1;
+ if(column + row > 76) {
+ column = row;
+ outc('\n');
+ } else {
+ column += row;
+ outc(' ');
+ }
+ outs(p->word);
+ }
+}
+
+void ToggleNameList(int *reciper, char *listfile, char *msg) {
+ FILE *fp;
+ char genbuf[200];
+
+ if((fp = fopen(listfile, "r"))) {
+ while(fgets(genbuf, STRLEN, fp)) {
+ strtok(genbuf, str_space);
+ if(!InNameList(genbuf)) {
+ AddNameList(genbuf);
+ (*reciper)++;
+ } else {
+ RemoveNameList(genbuf);
+ (*reciper)--;
+ }
+ }
+ fclose(fp);
+ ShowNameList(3, 0, msg);
+ }
+}
+
+static int NumInList(word_t *list) {
+ register int i;
+
+ for(i = 0; list; i++)
+ list = list->next;
+ return i;
+}
+
+int chkstr(char *otag, char *tag, char *name) {
+ char ch, *oname = name;
+
+ while(*tag) {
+ ch = *name++;
+ if(*tag != chartoupper(ch))
+ return 0;
+ tag++;
+ }
+ if(*tag && *name == '\0')
+ strcpy(otag, oname);
+ return 1;
+}
+
+static word_t *GetSubList(char *tag, word_t *list) {
+ word_t *wlist, *wcurr;
+ char tagbuf[STRLEN];
+ int n;
+
+ wlist = wcurr = NULL;
+ for(n = 0; tag[n]; n++)
+ tagbuf[n] = chartoupper(tag[n]);
+ tagbuf[n] = '\0';
+
+ while(list) {
+ if(chkstr(tag, tagbuf, list->word)) {
+ register word_t *node;
+
+ node = (word_t *)malloc(sizeof(word_t));
+ node->word = list->word;
+ node->next = NULL;
+ if(wlist)
+ wcurr->next = node;
+ else
+ wlist = node;
+ wcurr = node;
+ }
+ list = list->next;
+ }
+ return wlist;
+}
+
+static void ClearSubList(word_t *list) {
+ struct word_t *tmp_list;
+
+ while(list) {
+ tmp_list = list->next;
+ free(list);
+ list = tmp_list;
+ }
+}
+
+static int MaxLen(word_t *list, int count) {
+ int len = strlen(list->word);
+ int t;
+
+ while(list && count) {
+ if((t = strlen(list->word)) > len)
+ len = t;
+ list = list->next;
+ count--;
+ }
+ return len;
+}
+
+void namecomplete(char *prompt, char *data) {
+ char *temp;
+ word_t *cwlist, *morelist;
+ int x, y, origx, origy;
+ int ch;
+ int count = 0;
+ int clearbot = NA;
+
+ if(toplev == NULL)
+ AddNameList("");
+ cwlist = GetSubList("", toplev);
+ morelist = NULL;
+ temp = data;
+
+ outs(prompt);
+ clrtoeol();
+ getyx(&y, &x);
+ getyx(&origy, &origx);
+ standout();
+ prints("%*s", IDLEN + 1, "");
+ standend();
+ move(y, x);
+ refresh();
+
+ while((ch = igetch()) != EOF) {
+ if(ch == '\n' || ch == '\r') {
+ *temp = '\0';
+ outc('\n');
+ if(NumInList(cwlist) == 1)
+ strcpy(data, cwlist->word);
+ ClearSubList(cwlist);
+ break;
+ }
+ if(ch == ' ') {
+ int col, len;
+
+ if(NumInList(cwlist) == 1) {
+ strcpy(data, cwlist->word);
+ move(y, x);
+ outs(data + count);
+ count = strlen(data);
+ temp = data + count;
+ getyx(&y, &x);
+ continue;
+ }
+ clearbot = YEA;
+ col = 0;
+ if(!morelist)
+ morelist = cwlist;
+ len = MaxLen(morelist, p_lines);
+ move(2, 0);
+ clrtobot();
+ printdash("¬ÛÃö¸ê°T¤@Äýªí");
+ while(len + col < 80) {
+ int i;
+
+ for(i = p_lines; (morelist) && (i > 0); i--) {
+ move(3 + (p_lines - i), col);
+ outs(morelist->word);
+ morelist = morelist->next;
+ }
+ col += len + 2;
+ if(!morelist)
+ break;
+ len = MaxLen(morelist, p_lines);
+ }
+ if(morelist) {
+ move(b_lines, 0);
+ outs(msg_more);
+ }
+ move(y, x);
+ continue;
+ }
+ if(ch == '\177' || ch == '\010') {
+ if(temp == data)
+ continue;
+ temp--;
+ count--;
+ *temp = '\0';
+ ClearSubList(cwlist);
+ cwlist = GetSubList(data, toplev);
+ morelist = NULL;
+ x--;
+ move(y, x);
+ outc(' ');
+ move(y, x);
+ continue;
+ }
+
+ if(count < STRLEN && isprint(ch)) {
+ word_t *node;
+
+ *temp++ = ch;
+ count++;
+ *temp = '\0';
+ node = GetSubList(data, cwlist);
+ if(node == NULL) {
+ temp--;
+ *temp = '\0';
+ count--;
+ continue;
+ }
+ ClearSubList(cwlist);
+ cwlist = node;
+ morelist = NULL;
+ move(y, x);
+ outc(ch);
+ x++;
+ }
+ }
+ if(ch == EOF)
+ /* longjmp(byebye, -1); */
+ raise(SIGHUP); /* jochang: don't know if this is necessary... */
+ outc('\n');
+ refresh();
+ if(clearbot) {
+ move(2, 0);
+ clrtobot();
+ }
+ if(*data) {
+ move(origy, origx);
+ outs(data);
+ outc('\n');
+ }
+}
+
+void usercomplete(char *prompt, char *data) {
+ char *temp;
+ char *cwbuf, *cwlist;
+ int cwnum, x, y, origx, origy;
+ int clearbot = NA, count = 0, morenum = 0;
+ char ch;
+
+ cwbuf = malloc(MAX_USERS * (IDLEN + 1));
+ cwlist = u_namearray((arrptr)cwbuf, &cwnum, "");
+ temp = data;
+
+ outs(prompt);
+ clrtoeol();
+ getyx(&y, &x);
+ getyx(&origy, &origx);
+ standout();
+ prints("%*s", IDLEN + 1, "");
+ standend();
+ move(y, x);
+ while((ch = igetch()) != EOF) {
+ if(ch == '\n' || ch == '\r') {
+ int i;
+ char *ptr;
+
+ *temp = '\0';
+ outc('\n');
+ ptr = (char *)cwlist;
+ for(i = 0; i < cwnum; i++) {
+ if(strncasecmp(data, ptr, IDLEN + 1) == 0)
+ strcpy(data, ptr);
+ ptr += IDLEN + 1;
+ }
+ break;
+ } else if(ch == ' ') {
+ int col, len;
+
+ if(cwnum == 1) {
+ strcpy(data, (char *)cwlist);
+ move(y, x);
+ outs(data + count);
+ count = strlen(data);
+ temp = data + count;
+ getyx(&y, &x);
+ continue;
+ }
+ clearbot = YEA;
+ col = 0;
+ len = UserMaxLen((arrptr)cwlist, cwnum, morenum, p_lines);
+ move(2, 0);
+ clrtobot();
+ printdash("¨Ï¥ÎªÌ¥N¸¹¤@Äýªí");
+ while(len + col < 79) {
+ int i;
+
+ for(i = 0; morenum < cwnum && i < p_lines; i++) {
+ move(3 + i, col);
+ prints("%s ", cwlist + (IDLEN + 1) * morenum++);
+ }
+ col += len + 2;
+ if(morenum >= cwnum)
+ break;
+ len = UserMaxLen((arrptr)cwlist, cwnum, morenum, p_lines);
+ }
+ if(morenum < cwnum) {
+ move(b_lines, 0);
+ outs(msg_more);
+ } else
+ morenum = 0;
+ move(y, x);
+ continue;
+ } else if(ch == '\177' || ch == '\010') {
+ if(temp == data)
+ continue;
+ temp--;
+ count--;
+ *temp = '\0';
+ cwlist = u_namearray((arrptr)cwbuf, &cwnum, data);
+ morenum = 0;
+ x--;
+ move(y, x);
+ outc(' ');
+ move(y, x);
+ continue;
+ } else if(count < STRLEN && isprint(ch)) {
+ int n;
+
+ *temp++ = ch;
+ *temp = '\0';
+ n = UserSubArray((arrptr)cwbuf, (arrptr)cwlist, cwnum, ch, count);
+ if(n == 0) {
+ temp--;
+ *temp = '\0';
+ continue;
+ }
+ cwlist = cwbuf;
+ count++;
+ cwnum = n;
+ morenum = 0;
+ move(y, x);
+ outc(ch);
+ x++;
+ }
+ }
+ free(cwbuf);
+ if(ch == EOF)
+ /* longjmp(byebye, -1); */
+ raise(SIGHUP); /* jochang: don't know if this is necessary */
+ outc('\n');
+ refresh();
+ if(clearbot) {
+ move(2, 0);
+ clrtobot();
+ }
+ if(*data) {
+ move(origy, origx);
+ outs(data);
+ outc('\n');
+ }
+}
diff --git a/mbbsd/osdep.c b/mbbsd/osdep.c
new file mode 100644
index 00000000..967a4db0
--- /dev/null
+++ b/mbbsd/osdep.c
@@ -0,0 +1,79 @@
+/* $Id: osdep.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#if defined(linux)
+int cpuload(char *str) {
+ double l[3] = {-1, -1, -1};
+ FILE *fp;
+
+ if((fp = fopen("/proc/loadavg", "r"))) {
+ if(fscanf(fp, "%lf %lf %lf", &l[0], &l[1], &l[2]) != 3)
+ l[0] = -1;
+ fclose(fp);
+ }
+ if(str) {
+ if(l[0] != -1)
+ sprintf(str, " %.2f %.2f %.2f", l[0], l[1], l[2]);
+ else
+ strcpy(str, " (unknown) ");
+ }
+ return (int)l[0];
+}
+
+double swapused(long *total, long *used) {
+ double percent = -1;
+ char buf[101];
+ FILE *fp;
+
+ if((fp = fopen("/proc/meminfo","r"))) {
+ while(fgets(buf, 100, fp) && buf[0] != 'S');
+ if(sscanf(buf + 6, "%ld %ld", total, used) == 2)
+ if(*total != 0)
+ percent = (double)*used / (double)*total;
+ fclose(fp);
+ }
+ return percent;
+}
+
+#elif __FreeBSD__ >=4
+
+#include <kvm.h>
+
+int cpuload(char *str) {
+ double l[3] = {-1, -1, -1};
+ if(getloadavg(l, 3) != 3)
+ l[0] = -1;
+
+ if(str) {
+ if(l[0] != -1)
+ sprintf(str, " %.2f %.2f %.2f", l[0], l[1], l[2]);
+ else
+ strcpy(str, " (unknown) ");
+ }
+ return (int)l[0];
+}
+
+double swapused(long *total, long *used) {
+ double percent = -1;
+ kvm_t *kd;
+ struct kvm_swap swapinfo;
+ int pagesize;
+
+ kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
+ if(kd) {
+ if(kvm_getswapinfo(kd, &swapinfo, 1, 0) == 0) {
+ pagesize = getpagesize();
+ *total = swapinfo.ksw_total * pagesize;
+ *used = swapinfo.ksw_used * pagesize;
+ if(*total != 0)
+ percent = (double)*used / (double)*total;
+ }
+ kvm_close(kd);
+ }
+ return percent;
+}
+#endif
diff --git a/mbbsd/othello.c b/mbbsd/othello.c
new file mode 100644
index 00000000..47b8cef3
--- /dev/null
+++ b/mbbsd/othello.c
@@ -0,0 +1,541 @@
+/* $Id: othello.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "modes.h"
+#include "proto.h"
+
+extern char *BBSName;
+
+#define LOGFILE "etc/othello.log"
+#define SECRET "etc/othello.secret"
+#define NR_TABLE 2
+
+#define true 1
+#define false 0
+#define STARTX 3
+#define STARTY 20
+#define NONE_CHESS " "
+#define WHITE_CHESS "¡´"
+#define BLACK_CHESS "¡³"
+#define HINT_CHESS "¡­"
+#define NONE 0
+#define HINT 1
+#define BLACK 2
+#define WHITE 3
+
+#define INVERT(COLOR) (((COLOR))==WHITE?BLACK:WHITE)
+
+static char nowx = 3, nowy = 3;
+static char *CHESS_TYPE[] = {NONE_CHESS, HINT_CHESS, BLACK_CHESS, WHITE_CHESS};
+static char DIRX[] = {-1,-1,-1, 0, 1, 1, 1, 0};
+static char DIRY[] = {-1, 0, 1, 1, 1, 0,-1,-1};
+static char number[2];
+
+static char pass = 0;
+static char if_hint = 0;
+static int think, which_table;
+
+static char nowboard[10][10]=
+{{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {-1, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, -1},
+ {-1, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, -1},
+ {-1, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, -1},
+ {-1, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, -1},
+ {-1, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, -1},
+ {-1, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, -1},
+ {-1, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, -1},
+ {-1, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, -1},
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}};
+static char init_table[NR_TABLE+1][5][5] = {
+ {{ 0, 0, 0, 0, 0},
+ { 0,30,-3, 2, 2},
+ { 0,-3,-3,-1,-1},
+ { 0, 2,-1, 1, 1},
+ { 0, 2,-1, 1, 0}},
+
+ {{ 0, 0, 0, 0, 0},
+ { 0,70, 5,20,30},
+ { 0, 5,-5, 3, 3},
+ { 0,20, 3, 5, 5},
+ { 0,30, 3, 5, 5}},
+
+ {{ 0, 0, 0, 0, 0},
+ { 0, 5, 2, 2, 2},
+ { 0, 2, 1, 1, 1},
+ { 0, 2, 1, 1, 1},
+ { 0, 2, 1, 1, 1}}
+};
+
+static char table[NR_TABLE + 1][10][10];
+static void print_chess(int x, int y, char chess) {
+ move(STARTX - 1 + x * 2, STARTY - 2 + y * 4);
+ if(chess != HINT || if_hint == 1)
+ prints(CHESS_TYPE[(int)chess]);
+ else
+ prints(CHESS_TYPE[NONE]);
+ refresh();
+}
+
+extern userec_t cuser;
+
+static void printboard() {
+ int i;
+
+ move(STARTX, STARTY);
+ prints("¢z¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢s¢w¢{");
+ for(i = 0; i < 7; i++) {
+ move(STARTX + 1 + i * 2, STARTY);
+ prints ("¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x");
+ move(STARTX + 2 + i * 2, STARTY);
+ prints ("¢u¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢q¢w¢t");
+ }
+ move(STARTX + 1 + i * 2, STARTY);
+ prints("¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x ¢x");
+ move(STARTX + 2 + i * 2, STARTY);
+ prints("¢|¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢r¢w¢}");
+ print_chess(4, 4, WHITE);
+ print_chess(5, 5, WHITE);
+ print_chess(4, 5, BLACK);
+ print_chess(5, 4, BLACK);
+ move(3, 56);
+ prints("(¶Â)%s",cuser.userid);
+ move(3, 72);
+ prints(": 02");
+ move(4, 56);
+ prints("(¥Õ)¹q¸£ : 02");
+ move(6, 56);
+ prints("¡­ ¥i¥H¤U¤§³B");
+ move(7, 56);
+ prints("[q] °h¥X");
+ move(8, 56);
+ prints("[h] ¶}±Ò/Ãö³¬ ´£¥Ü");
+ move(9,56);
+ prints("[Enter][Space] ¤U´Ñ");
+ move(10, 56);
+ prints("¤W:¡ô, i");
+ move(11, 56);
+ prints("¤U:¡õ, k");
+ move(12, 56);
+ prints("¥ª:¡ö, j");
+ move(13, 56);
+ prints("¥k:¡÷, l");
+}
+
+static int get_key(char nowx, char nowy) {
+ int ch;
+
+ move(STARTX - 1 + nowx * 2, STARTY - 1 + nowy * 4);
+ ch = igetkey();
+ move(STARTX - 1 + nowx * 2, STARTY - 2 + nowy * 4);
+ if(nowboard[(int)nowx][(int)nowy] != HINT || if_hint==1)
+ outs(CHESS_TYPE[(int)nowboard[(int)nowx][(int)nowy]]);
+ else
+ outs(CHESS_TYPE[NONE]);
+ return ch;
+}
+
+static int eatline(int i, int j, char color, int dir, char chessboard[][10]) {
+ int tmpx,tmpy;
+ char tmpchess;
+
+ tmpx = i + DIRX[dir];
+ tmpy = j + DIRY[dir];
+ tmpchess = chessboard[tmpx][tmpy];
+ if(tmpchess == -1)
+ return false;
+ if(tmpchess != INVERT(color))
+ return false;
+
+ tmpx += DIRX[dir];
+ tmpy += DIRY[dir];
+ tmpchess = chessboard[tmpx][tmpy];
+ while(tmpchess != -1) {
+ if(tmpchess < BLACK)
+ return false;
+ if(tmpchess == color) {
+ while(i != tmpx || j != tmpy) {
+ chessboard[i][j] = color;
+ i += DIRX[dir];
+ j += DIRY[dir];
+ }
+ return true;
+ }
+ tmpx += DIRX[dir];
+ tmpy += DIRY[dir];
+ tmpchess = chessboard[tmpx][tmpy];
+ }
+ return false;
+}
+
+static int if_can_put(int x, int y, char color, char chessboard[][10]) {
+ int i, temp, checkx, checky;
+
+ if(chessboard[x][y]<BLACK)
+ for(i = 0; i < 8; i++) {
+ checkx = x + DIRX[i];
+ checky = y + DIRY[i];
+ temp = chessboard[checkx][checky];
+ if(temp < BLACK)
+ continue;
+ if(temp != color)
+ while(chessboard[checkx += DIRX[i]][checky += DIRY[i]] > HINT)
+ if(chessboard[checkx][checky] == color)
+ return true;
+ }
+ return false;
+}
+
+static int get_hint(char color) {
+ int i, j, temp = 0;
+
+ for(i = 1; i <= 8; i++)
+ for(j = 1; j <= 8; j++) {
+ if(nowboard[i][j] == HINT)
+ nowboard[i][j] = NONE;
+ if(if_can_put(i, j, color, nowboard)) {
+ nowboard[i][j] = HINT;
+ temp++;
+ }
+ print_chess(i, j, nowboard[i][j]);
+ }
+ return temp;
+}
+
+static void eat(int x, int y, int color, char chessboard[][10]) {
+ int k;
+
+ for(k = 0; k < 8; k++)
+ eatline(x, y, color, k, chessboard);
+}
+
+static void end_of_game(int quit) {
+ FILE *fp,*fp1;
+ char *opponent[] = {"","CD-65","","À¦¨à","¤p«Ä","","¤j¤H","±M®a"};
+
+ move(STARTX - 1, 30);
+ prints (" ");
+ move(22, 35);
+ fp = fopen(LOGFILE, "a");
+ if(!quit) {
+ fp1 = fopen(SECRET, "a");
+ if(fp1) {
+ fprintf(fp1, "%d,%d,%s,%02d,%02d\n", think, which_table,
+ cuser.userid, number[0], number[1]);
+ fclose(fp1);
+ }
+ }
+
+ if(quit) {
+ if(number[0] == 2 && number[1] == 2) {
+ if(fp)
+ fclose(fp);
+ return;
+ }
+ fprintf(fp, "¦b%s¯Å¤¤, %sÁ{°}²æ°k\n", opponent[think], cuser.userid);
+ if(fp)
+ fclose(fp);
+ return;
+ }
+ if(number[0] > number[1]) {
+ prints("§AŤF¹q¸£%02d¤l", number[0] - number[1]);
+ if(think == 6 && number[0] - number[1] >= 50)
+ demoney(200);
+ if(think == 7 && number[0] - number[1] >= 40)
+ demoney(200);
+ if(fp)
+ fprintf(fp, "¦b%s¯Å¤¤, %s¥H %02d:%02d ŤF¹q¸£%02d¤l\n",
+ opponent[think], cuser.userid, number[0], number[1],
+ number[0] - number[1]);
+ } else if(number[1] > number[0]) {
+ prints("¹q¸£Ä¹¤F§A%02d¤l", number[1] - number[0]);
+ if(fp) {
+ fprintf(fp, "¦b%s¯Å¤¤, ", opponent[think]);
+ if(number[1] - number[0] > 20)
+ fprintf(fp, "¹q¸£¥H %02d:%02d ºG¹q%s %02d¤l\n", number[1],
+ number[0], cuser.userid, number[1] - number[0]);
+ else
+ fprintf(fp, "¹q¸£¥H %02d:%02d ŤF%s %02d¤l\n", number[1],
+ number[0], cuser.userid, number[1] - number[0]);
+ }
+ } else {
+ prints("§A©M¹q¸£¥´¦¨¥­¤â!!");
+ if(fp)
+ fprintf(fp, "¦b%s¯Å¤¤, %s©M¹q¸£¥H %02d:%02d ¥´¦¨¤F¥­¤â\n",
+ opponent[think], cuser.userid, number[1], number[0]);
+ }
+ if(fp)
+ fclose(fp);
+ move(1,1);
+ igetkey();
+}
+
+static void othello_redraw() {
+ int i, j;
+
+ for(i = 1; i <= 8; i++)
+ for(j = 1; j <= 8; j++)
+ print_chess(i, j, nowboard[i][j]);
+}
+
+static int player(char color) {
+ int ch;
+
+ if(get_hint(color)) {
+ while(true) {
+ ch = get_key(nowx,nowy);
+ switch(ch) {
+ case 'J':
+ case 'j':
+ case KEY_LEFT:
+ nowy--;
+ break;
+ case 'L':
+ case 'l':
+ case KEY_RIGHT:
+ nowy++;
+ break;
+ case 'I':
+ case 'i':
+ case KEY_UP:
+ nowx--;
+ break;
+ case 'K':
+ case 'k':
+ case KEY_DOWN:
+ nowx++;
+ break;
+ case ' ':
+ case '\r':
+ if(nowboard[(int)nowx][(int)nowy] != HINT)
+ break;
+ pass = 0;
+ nowboard[(int)nowx][(int)nowy] = color;
+ eat(nowx, nowy, color, nowboard);
+ print_chess(nowx, nowy, color);
+ return true;
+ case 'q':
+ end_of_game(1);
+ return false;
+ case 'H':
+ case 'h':
+ if_hint = if_hint^1;
+ othello_redraw();
+ break;
+ }
+ if(nowx == 9)
+ nowx=1;
+ if(nowx == 0)
+ nowx=8;
+ if(nowy == 9)
+ nowy=1;
+ if(nowy == 0)
+ nowy=8;
+ }
+ } else {
+ pass++;
+ if(pass == 1) {
+ move(23, 34);
+ prints("§A¥²»Ý©ñ±ó³o¤@¨B!!");
+ igetch();
+ move(28,23);
+ prints(" ");
+ } else {
+ end_of_game(0);
+ return false;
+ }
+ }
+ return 0;
+}
+
+static void init() {
+ int i, j, i1, j1;
+
+ nowx = 4;
+ nowy = 4;
+ number[0] = number[1] = 2;
+ for(i = 1; i <= 8; i++)
+ for(j = 1;j <= 8; j++) {
+ i1 = 4.5 - abs(4.5 - i);
+ j1 = 4.5 - abs(4.5 - j);
+ table[0][i][j] = init_table[0][i1][j1];
+ table[1][i][j] = init_table[1][i1][j1];
+ }
+ for(i = 1; i <= 8; i++)
+ for(j = 1; j <= 8; j++)
+ nowboard[i][j] = NONE;
+ nowboard[4][4] = nowboard[5][5] = WHITE;
+ nowboard[4][5] = nowboard[5][4] = BLACK;
+}
+
+static void report() {
+ int i, j;
+
+ number[0] = number[1] = 0;
+ for(i = 1; i <= 8; i++)
+ for(j = 1; j <= 8; j++)
+ if(nowboard[i][j] == BLACK)
+ number[0]++;
+ else if(nowboard[i][j] == WHITE)
+ number[1]++;
+ move(3, 60);
+ prints("%s", cuser.userid);
+ move(3, 72);
+ prints(": %02d", number[0]);
+ move(4, 60);
+ prints("¹q¸£ : %02d", number[1]);
+}
+
+static int EVL(char chessboard[][10], int color, int table_number) {
+ int points = 0,a,b;
+ for(a = 1; a <= 8; a++)
+ for(b = 1; b <= 8; b++)
+ if(chessboard[a][b] > HINT) {
+ if(chessboard[a][b] == BLACK)
+ points += table[table_number][a][b];
+ else
+ points -= table[table_number][a][b];
+ }
+ return ((color == BLACK) ? points : -points);
+}
+
+static int alphabeta(int alpha, int beta, int level, char chessboard[][10],
+ int thinkstep, int color, int table) {
+ int i, j, k, flag = 1;
+ char tempboard[10][10];
+ if(level == thinkstep+1)
+ return EVL(chessboard, (level & 1 ? color : ((color - 2) ^ 1) + 2),
+ table);
+ for(i = 1; i <= 8; i++) {
+ for(j = 1; j <= 8; j++) {
+ if(if_can_put(i, j, color, chessboard)) {
+ flag = 0;
+ memcpy(tempboard, chessboard, sizeof(char) * 100);
+ eat(i, j, color, tempboard);
+
+ k = alphabeta(alpha, beta, level + 1, tempboard, thinkstep,
+ ((color - 2) ^ 1) + 2, table);
+ if(((level & 1) && k > alpha))
+ alpha = k;
+ else if(!(level & 1) && k < beta)
+ beta = k;
+ if(alpha >= beta)
+ break;
+ }
+ }
+ }
+ if(flag)
+ return EVL(chessboard, color, table);
+ return ((level & 1) ? alpha : beta);
+}
+
+static int Computer(int thinkstep, int table) {
+ int i, j, maxi = 0, maxj = 0, level = 1;
+ char chessboard[10][10];
+ int alpha = -10000, k;
+ if((number[0] + number[1]) > 44)
+ table = NR_TABLE;
+ for(i = 1; i <= 8; i++)
+ for(j = 1; j <= 8; j++) {
+ if(if_can_put(i,j,WHITE,nowboard)) {
+ memcpy(chessboard, nowboard, sizeof(char) * 100);
+ eat(i, j, WHITE, chessboard);
+ k = alphabeta(alpha, 10000, level + 1, chessboard, thinkstep,
+ BLACK, table);
+ if(k > alpha) {
+ alpha = k;
+ maxi = i;
+ maxj = j;
+ }
+ }
+ }
+ if(alpha != -10000) {
+ eat(maxi, maxj, WHITE, nowboard);
+ pass = 0;
+ nowx = maxi;
+ nowy = maxj;
+ } else {
+ move(23, 30);
+ prints("¹q¸£©ñ±ó³o¤@¨B´Ñ!!");
+ pass++;
+ if(pass == 2) {
+ move(23, 24);
+ prints(" ");
+ end_of_game(0);
+ return false;
+ }
+ igetch();
+ move(23, 24);
+ prints(" ");
+ }
+ return true;
+}
+
+static int choose() {
+ char thinkstep[2];
+
+ move(2, 0);
+ prints("½Ð¿ï¾ÜÃø«×:");
+ move(5, 0);
+ prints("(1) CD-65\n"); /* ·Q 1 ¨B */
+ prints("(2) À¦¨à\n"); /* ·Q 3 ¨B */
+ prints("(3) ¤p«Ä\n"); /* ·Q 4 ¨B */
+ do {
+ getdata(4, 0, "½Ð¿ï¾Ü¤@­Ó¹ï¶H©M±z¹ï¥´:(1~5)", thinkstep, 2, LCECHO);
+ } while(thinkstep[0] < '1' || thinkstep[0] > '3');
+ clear();
+ switch(thinkstep[0]) {
+ case '2':
+ thinkstep[0] = '3';
+ break;
+ case '3':
+ thinkstep[0] = '4';
+ break;
+ default:
+ thinkstep[0] = '1';
+ break;
+ }
+ return atoi(thinkstep);
+}
+
+#define lockreturn0(unmode, state) if(lockutmpmode(unmode, state)) return 0
+
+int othello_main() {
+ lockreturn0(OTHELLO, LOCK_MULTI);
+ clear();
+ init();
+ think = choose();
+ showtitle("¶Â¥Õ´Ñ", BBSName);
+ printboard();
+ which_table = rand() % NR_TABLE;
+ while(true) {
+ move(STARTX - 1, 30);
+ prints("½ü¨ì§A¤U¤F...");
+ if(!player(BLACK))
+ break;
+ report();
+ othello_redraw();
+ if(number[0] + number[1] == 64) {
+ end_of_game(0);
+ break;
+ }
+ move(STARTX - 1, 30);
+ prints("¹q¸£«ä¦Ò¤¤...");
+ refresh();
+ if(!Computer(think, which_table))
+ break;
+ report();
+ othello_redraw();
+ if(number[0] + number[1] == 64) {
+ end_of_game(0);
+ break;
+ }
+ }
+ more(LOGFILE, YEA);
+ unlockutmpmode();
+ return 1;
+}
diff --git a/mbbsd/page.c b/mbbsd/page.c
new file mode 100644
index 00000000..c77ef421
--- /dev/null
+++ b/mbbsd/page.c
@@ -0,0 +1,130 @@
+/* $Id: page.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "modes.h"
+#include "common.h"
+#include "proto.h"
+
+#define hpressanykey(a) {move(22, 0); prints(a); pressanykey();}
+static void filt_railway(char* fpath) {
+ char buf[256], tmppath[32];
+ FILE* fp = fopen(fpath, "w"), *tp;
+
+ sprintf(tmppath, "%s.railway", fpath);
+ if(!fp || !(tp = fopen(tmppath, "r")))
+ return;
+
+ while(fgets(buf, 255, tp)) {
+ if(strstr(buf, "INLINE"))
+ continue;
+ if(strstr(buf, "LINK"))
+ break;
+ fprintf(fp, "%s", buf);
+ }
+ fclose(fp);
+ fclose(tp);
+ unlink(tmppath);
+}
+
+extern userec_t cuser;
+
+int main_railway() {
+ fileheader_t mhdr;
+ char genbuf[200];
+ int from, to, time_go, time_reach;
+ char tt[2], type[2];
+ char command[256], buf[8];
+ char *addr[]= {
+ "°ò¶©", "¤K°ô", "¤C°ô", "¤­°ô", "¦Á¤î", "«n´ä", "ªQ¤s", "¥x¥_", "¸UµØ",
+ "ªO¾ô", "¾ðªL", "¤s¨Î", "Åaºq", "®ç¶é", "¤ºÃc", "¤¤Ãc", "®H¤ß", "·¨±ö",
+ "´ò¤f", "·sÂ×", "¦Ë¥_", "·s¦Ë", "­»¤s", "±T³»", "¦Ë«n", "³y¾ô", "Â×´I",
+ "½Í¤å", "¤j¤s", "«áÀs", "Às´ä", "¥Õ¨F¤Ù", "·s®H", "³q¾]", "­b¸Ì",
+ "¤é«n", "¤j¥Ò", "»O¤¤´ä", "²M¤ô", "¨F³À", "Às¤«", "¤j¨{", "°l¤À",
+ "­]®ß", "«n¶Õ", "»ÉÆr", "¤T¸q", "³Ó¿³", "®õ¦w", "¦Z¨½", "Â×­ì", "¼æ¤l",
+ "¥x¤¤", "¯Q¤é", "¦¨¥\\", "¹ü¤Æ", "ªá¾Â", "­ûªL", "¥Ã¹t", "ªÀÀY",
+ "¥Ð¤¤", "¤G¤ô", "ªL¤º", "¥Ûºh", "¤æ¤»", "¤æ«n", "¥ÛÀt", "¤jªL",
+ "¥Á¶¯", "¹Å¸q", "¤ô¤W", "«n¹t", "«á¾À", "·sÀç", "¬hÀç", "ªL»ñÀç",
+ "¶©¥Ð", "©ÞªL", "µ½¤Æ", "·s¥«", "¥Ã±d", "¥x«n", "«O¦w", "¤¤¬w",
+ "¤j´ò", "¸ô¦Ë", "©£¤s", "¾ôÀY", "·£±ê", "¥ªÀç", "°ª¶¯", "»ñ¤s",
+ "¤E¦±°ó", "«ÌªF", NULL, NULL
+ };
+
+ setutmpmode(RAIL_WAY);
+ clear();
+ move(0,25);
+ prints("\033[1;37;45m ¤õ¨®¬d¸ß¨t²Î \033[1;44;33m§@ªÌ:Heat\033[m");
+ move(1,0);
+ outs("\033[1;33m
+ 1.°ò¶© 16.¤¤Ãc 31.Às´ä 46.»ÉÆr 61.¥Ð¤¤ 76.ªL»ñÀç 91.°ª¶¯
+ 2.¤K°ô 17.®H¤ß 32.¥Õ¨F¤Ù 47.¤T¸q 62.¤G¤ô 77.¶©¥Ð 92.»ñ¤s
+ 3.¤C°ô 18.·¨±ö 33.·s®H 48.³Ó¿³ 63.ªL¤º 78.©ÞªL 93.¤E¦±°ó
+ 4.¤­°ô 19.´ò¤f 34.³q¾] 49.®õ¦w 64.¥Ûºh 79.µ½¤Æ 94.«ÌªF
+ 5.¦Á¤î 20.·sÂ× 35.­b¸Ì 50.¦Z¨½ 65.¤æ¤» 80.·s¥«
+ 6.«n´ä 21.¦Ë¥_ 36.¤é«n 51.Â×­ì 66.¤æ«n 81.¥Ã±d
+ 7.ªQ¤s 22.·s¦Ë 37.¤j¥Ò 52.¼æ¤l 67.¥ÛÀt 82.¥x«n
+ 8.¥x¥_ 23.­»¤s 38.»O¤¤´ä 53.¥x¤¤ 68.¤jªL 83.«O¦w
+ 9.¸UµØ 24.±T³» 39.²M¤ô 54.¯Q¤é 69.¥Á¶¯ 84.¤¤¬w
+10.ªO¾ô 25.¦Ë«n 40.¨F³À 55.¦¨¥\\ 70.¹Å¸q 85.¤j´ò
+11.¾ðªL 26.³y¾ô 41.Às¤« 56.¹ü¤Æ 71.¤ô¤W 86.¸ô¦Ë
+12.¤s¨Î 27.Â×´I 42.¤j¨{ 57.ªá¾Â 72.«n¹t 87.©£¤s
+13.Åaºq 28.½Í¤å 43.°l¤À 58.­ûªL 73.«á¾À 88.¾ôÀY
+14.®ç¶é 29.¤j¤s 44.­]®ß 59.¥Ã¹t 74.·sÀç 89.·£±ê
+15.¤ºÃc 30.«áÀs 45.«n¶Õ 60.ªÀÀY 75.¬hÀç 90.¥ªÀç\033[m");
+
+ getdata(17, 0, "\033[1;35m§A½T©w­n·j´M¶Ü?[y/n]:\033[m", buf, 2, LCECHO);
+ if(buf[0] != 'y' && buf[0] != 'Y')
+ return 0;
+ while(1)
+ if(getdata(18, 0, "\033[1;35m½Ð¿é¤J°_¯¸(1-94):\033[m", buf, 3, LCECHO) &&
+ (from = atoi(buf)) >= 1 && from <= 94)
+ break;
+ while(1)
+ if(getdata(18, 40, "\033[1;35m½Ð¿é¤J¥Øªº¦a(1-94):\033[m",
+ buf, 3, LCECHO) &&
+ (to = atoi(buf)) >= 1 && to <= 94)
+ break;
+ while(1)
+ if(getdata(19, 0, "\033[1;35m½Ð¿é¤J®É¶¡°Ï¬q(0-23) ¥Ñ:\033[m",
+ buf,3,LCECHO) &&
+ (time_go = atoi(buf)) >= 0 && time_go <= 23)
+ break;
+ while(1)
+ if(getdata(19, 40, "\033[1;35m¨ì:\033[m", buf, 3, LCECHO) &&
+ (time_reach=atoi(buf)) >= 0 && time_reach <= 23)
+ break;
+ while(1)
+ if(getdata(20, 0, "\033[1;35m·Q¬d¸ß 1:¹ï¸¹§Ö¨® 2:´¶³q¥­§Ö\033[m",
+ type,2,LCECHO) && (type[0] == '1' || type[0] == '2'))
+ break;
+ while(1)
+ if(getdata(21, 0, "\033[1;35m±ý¬d¸ß 1:¥Xµo®É¶¡ 2:¨ì¹F®É¶¡\033[m",
+ tt, 2, LCECHO) &&
+ (tt[0]=='1' || tt[0]=='2'))
+ break;
+ sethomepath(genbuf, cuser.userid);
+ stampfile(genbuf, &mhdr);
+ strcpy(mhdr.owner, "Ptt·j´M¾¹");
+ strncpy(mhdr.title, "¤õ¨®®É¨è·j´Mµ²ªG", TTLEN);
+ mhdr.savemode = '\0';
+
+ sprintf(command,"echo \"from-station=%s&to-station=%s"
+ "&from-time=%02d00&to-time=%02d00&tt=%s&type=%s\" | "
+ "lynx -dump -post_data "
+ "\"http://www.railway.gov.tw/cgi-bin/timetk.cgi\" > %s.railway",
+ addr[from - 1], addr[to - 1], time_go, time_reach,
+ (tt[0] == '1') ? "start" : "arriv",
+ (type[0] == '1') ? "fast" : "slow", genbuf);
+
+ system(command);
+ filt_railway(genbuf);
+ sethomedir(genbuf, cuser.userid);
+ if(append_record(genbuf, &mhdr, sizeof(mhdr)) == -1)
+ return -1;
+ hpressanykey("\033[1;31m§Ú­Ì·|§â·j´Mµ²ªG«Ü§Ö´N±Hµ¹§A­ò ^_^\033[m");
+ return 0;
+}
diff --git a/mbbsd/passwd.c b/mbbsd/passwd.c
new file mode 100644
index 00000000..28a31119
--- /dev/null
+++ b/mbbsd/passwd.c
@@ -0,0 +1,138 @@
+/* $Id: passwd.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "modes.h"
+#include "proto.h"
+
+extern char *fn_passwd;
+
+static userec_t *passwd_image = NULL;
+static int passwd_image_size;
+static int semid = -1;
+
+#ifndef SEM_R
+#define SEM_R 0400
+#endif
+
+#ifndef SEM_A
+#define SEM_A 0200
+#endif
+
+#ifndef __FreeBSD__
+union semun {
+ int val; /* value for SETVAL */
+ struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
+ u_short *array; /* array for GETALL & SETALL */
+ struct seminfo *__buf; /* buffer for IPC_INFO */
+};
+#endif
+
+int passwd_mmap() {
+ int fd;
+
+ fd = open(fn_passwd, O_RDWR);
+ if(fd > 0)
+ {
+ struct stat st;
+
+ fstat(fd, &st);
+ passwd_image_size = st.st_size;
+ passwd_image = mmap(NULL, passwd_image_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if(passwd_image == (userec_t *)-1) {
+ perror("mmap");
+ return -1;
+ }
+/* rocker 011018: after success get mmap, close file descript */
+ close (fd);
+
+ semid = semget(PASSWDSEM_KEY, 1, SEM_R | SEM_A | IPC_CREAT | IPC_EXCL);
+ if(semid == -1) {
+ if(errno == EEXIST) {
+ semid = semget(PASSWDSEM_KEY, 1, SEM_R | SEM_A);
+ if(semid == -1) {
+ perror("semget");
+ exit(1);
+ }
+ } else {
+ perror("semget");
+ exit(1);
+ }
+ } else {
+ union semun s;
+
+ s.val = 1;
+ if(semctl(semid, 0, SETVAL, s) == -1) {
+ perror("semctl");
+ exit(1);
+ }
+ }
+ } else {
+ perror(fn_passwd);
+ return -1;
+ }
+ return 0;
+}
+
+extern int usernum;
+int passwd_update_money(int num) {
+ int money;
+ if(num < 1 || num > MAX_USERS)
+ return -1;
+ money = moneyof(num);
+ memcpy(&passwd_image[num - 1].money, &money, sizeof(int));
+ return 0;
+}
+
+int passwd_update(int num, userec_t *buf) {
+ if(num < 1 || num > MAX_USERS)
+ return -1;
+ buf->money = moneyof(num);
+ memcpy(&passwd_image[num - 1], buf, sizeof(userec_t));
+ return 0;
+}
+
+int passwd_query(int num, userec_t *buf) {
+ if(num < 1 || num > MAX_USERS)
+ return -1;
+ memcpy(buf, &passwd_image[num - 1], sizeof(userec_t));
+ return 0;
+}
+
+int passwd_apply(int (*fptr)(userec_t *)) {
+ int i;
+
+ for(i = 0; i < MAX_USERS; i++)
+ if((*fptr)(&passwd_image[i]) == QUIT)
+ return QUIT;
+ return 0;
+}
+
+void passwd_lock() {
+ struct sembuf buf = { 0, -1, SEM_UNDO };
+
+ if(semop(semid, &buf, 1)) {
+ perror("semop");
+ exit(1);
+ }
+}
+
+void passwd_unlock() {
+ struct sembuf buf = { 0, 1, SEM_UNDO };
+
+ if(semop(semid, &buf, 1)) {
+ perror("semop");
+ exit(1);
+ }
+}
diff --git a/mbbsd/read.c b/mbbsd/read.c
new file mode 100644
index 00000000..b92f95e7
--- /dev/null
+++ b/mbbsd/read.c
@@ -0,0 +1,998 @@
+/* $Id: read.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "modes.h"
+#include "common.h"
+#include "perm.h"
+#include "proto.h"
+
+#define MAXPATHLEN 256
+
+extern int p_lines; /* a Page of Screen line numbers: tlines-4 */
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+extern char currowner[IDLEN + 2];
+extern char currtitle[44];
+extern char currauthor[IDLEN + 2];
+extern char *str_reply;
+extern char *msg_fwd_ok;
+extern char *msg_fwd_err1;
+extern char *msg_fwd_err2;
+extern int currmode;
+extern unsigned int currstat;
+extern char currboard[]; /* name of currently selected board */
+extern int KEY_ESC_arg;
+extern int curredit;
+extern char *msg_mailer;
+extern int currbid;
+extern bcache_t *brdshm;
+
+char currdirect[64];
+static fileheader_t *headers = NULL;
+static int last_line;
+static int hit_thread;
+
+/* rocker.011018: add new tag */
+
+extern int rget();
+extern char getans();
+extern void touchdircache();
+extern int get_fileheader_cache();
+
+/* rocker.011018: ·sªºtag¤è¦¡ */
+
+#define MAXTAGS 256
+
+#include <sys/mman.h>
+
+typedef struct
+{
+ time_t chrono;
+ int recno;
+} TagItem;
+
+
+/* ----------------------------------------------------- */
+/* Tag List ¼ÐÅÒ */
+/* ----------------------------------------------------- */
+
+
+int TagNum; /* tag's number */
+TagItem TagList[MAXTAGS]; /* ascending list */
+
+void
+UnTagger (int locus)
+{
+ if (locus > TagNum) return;
+
+ TagNum--;
+
+ if (TagNum > locus)
+ memcpy(&TagList[locus], &TagList[locus + 1],
+ (TagNum - locus) * sizeof(TagItem));
+}
+
+int
+Tagger(time_t chrono, int recno, int mode)
+{
+ int head, tail, posi = 0, comp;
+
+ for (head = 0, tail = TagNum - 1, comp = 1; head <= tail;)
+ {
+ posi = (head + tail) >> 1;
+ comp = TagList[posi].chrono - chrono;
+ if (!comp)
+ {
+ break;
+ }
+ else if (comp < 0)
+ {
+ head = posi + 1;
+ }
+ else
+ {
+ tail = posi - 1;
+ }
+ }
+
+ if (mode == TAG_NIN)
+ {
+ if (!comp && recno) /* µ´¹ïÄYÂÔ¡G³s recno ¤@°_¤ñ¹ï */
+ comp = recno - TagList[posi].recno;
+ return comp;
+
+ }
+
+ if (!comp)
+ {
+ if (mode != TAG_TOGGLE)
+ return NA;
+
+ TagNum--;
+ memcpy(&TagList[posi], &TagList[posi + 1],
+ (TagNum - posi) * sizeof(TagItem));
+ }
+ else if (TagNum < MAXTAGS)
+ {
+ TagItem *tagp, buf[MAXTAGS];
+
+ tail = (TagNum - head) * sizeof(TagItem);
+ tagp = &TagList[head];
+ memcpy(buf, tagp, tail);
+ tagp->chrono = chrono;
+ tagp->recno = recno;
+ memcpy(++tagp, buf, tail);
+ TagNum++;
+ }
+ else
+ {
+ bell();
+ return 0; /* full */
+ }
+ return YEA;
+}
+
+
+void
+EnumTagName( char *fname, int locus)
+{
+ sprintf(fname, "M.%d.A", (int) TagList[locus].chrono);
+}
+
+void
+EnumTagFhdr(fileheader_t *fhdr, char *direct, int locus)
+{
+ get_record(direct, fhdr, sizeof(fileheader_t), TagList[locus].recno);
+}
+
+/* -1 : ¨ú®ø */
+/* 0 : single article */
+/* ow: whole tag list */
+
+int
+AskTag(char *msg)
+{
+ char buf[80];
+ int num;
+
+ num = TagNum;
+ sprintf(buf, "¡» %s A)¤å³¹ T)¼Ð°O Q)uit?", msg);
+ switch (rget(b_lines-1, buf))
+ {
+ case 'q':
+ num = -1;
+ break;
+ case 'a':
+ num = 0;
+ }
+ return num;
+}
+
+
+#include <sys/mman.h>
+
+#define BATCH_SIZE 65536
+
+char *
+f_map (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, MAP_SHARED, fd, 0);
+ close(fd);
+ *fsize = size;
+ return fpath;
+}
+
+
+static int
+TagThread(char *direct)
+{
+ int fsize, count;
+ char *title, *fimage;
+ fileheader_t *head, *tail;
+
+ fimage = f_map(direct, &fsize);
+ if ( fimage == (char *) -1)
+ return DONOTHING;
+
+ head = (fileheader_t *) fimage;
+ tail = (fileheader_t *) (fimage + fsize);
+ count = 0;
+ do
+ {
+ count++;
+ title = subject(head->title);
+ if (!strncmp( currtitle, title,TTLEN))
+ {
+ if (!Tagger(atoi (head->filename + 2), count, TAG_INSERT))
+ break;
+ }
+ } while (++head < tail);
+
+ munmap(fimage, fsize);
+ return FULLUPDATE;
+}
+
+
+int
+TagPruner(int bid)
+{
+ if (TagNum && ((currstat != READING) || (currmode & MODE_BOARD)))
+ {
+ if(getans("§R°£©Ò¦³¼Ð°O[N]?") != 'y')
+ return FULLUPDATE;
+ delete_range(currdirect, 0, 0);
+ TagNum = 0;
+ if(bid>0);
+ setbtotal(bid);
+ return NEWDIRECT;
+ }
+ return DONOTHING;
+}
+
+
+/* ----------------------------------------------------- */
+/* cursor & reading record position control */
+/* ----------------------------------------------------- */
+keeploc_t *getkeep(char *s, int def_topline, int def_cursline) {
+ static struct keeploc_t *keeplist = NULL;
+ struct keeploc_t *p;
+ void *malloc();
+
+ if(def_cursline >= 0)
+ for(p = keeplist; p; p = p->next) {
+ if(!strcmp(s, p->key)) {
+ if(p->crs_ln < 1)
+ p->crs_ln = 1;
+ return p;
+ }
+ }
+ else
+ def_cursline = -def_cursline;
+ p = (keeploc_t *)malloc(sizeof(keeploc_t));
+ p->key = (char *)malloc(strlen(s) + 1);
+ strcpy(p->key, s);
+ p->top_ln = def_topline;
+ p->crs_ln = def_cursline;
+ p->next = keeplist;
+ return (keeplist = p);
+}
+
+void fixkeep(char *s, int first) {
+ keeploc_t *k;
+
+ k = getkeep(s, 1, 1);
+ if(k->crs_ln >= first) {
+ k->crs_ln = (first == 1 ? 1 : first - 1);
+ k->top_ln = (first < 11 ? 1 : first - 10);
+ }
+}
+
+/* calc cursor pos and show cursor correctly */
+static int cursor_pos(keeploc_t *locmem, int val, int from_top) {
+ int top;
+
+ if(val > last_line) {
+ bell();
+ val = last_line;
+ }
+ if(val <= 0) {
+ bell();
+ val = 1;
+ }
+
+ top = locmem->top_ln;
+ if(val >= top && val < top + p_lines) {
+ cursor_clear(3 + locmem->crs_ln - top, 0);
+ locmem->crs_ln = val;
+ cursor_show(3 + val - top, 0);
+ return DONOTHING;
+ }
+ locmem->top_ln = val - from_top;
+ if(locmem->top_ln <= 0)
+ locmem->top_ln = 1;
+ locmem->crs_ln = val;
+ return PARTUPDATE;
+}
+
+static int move_cursor_line(keeploc_t *locmem, int mode) {
+ int top, crs;
+ int reload = 0;
+
+ top = locmem->top_ln;
+ crs = locmem->crs_ln;
+ if(mode == READ_PREV) {
+ if(crs <= top) {
+ top -= p_lines - 1;
+ if(top < 1)
+ top = 1;
+ reload = 1;
+ }
+ if(--crs < 1) {
+ crs = 1;
+ reload = -1;
+ }
+ } else if(mode == READ_NEXT) {
+ if(crs >= top + p_lines - 1) {
+ top += p_lines - 1;
+ reload = 1;
+ }
+ if(++crs > last_line) {
+ crs = last_line;
+ reload = -1;
+ }
+ }
+ locmem->top_ln = top;
+ locmem->crs_ln = crs;
+ return reload;
+}
+
+static int thread(keeploc_t *locmem, int stype) {
+ static char a_ans[32], t_ans[32];
+ char ans[32], s_pmt[64];
+ register char *tag, *query = NULL;
+ register int now, pos, match, near = 0;
+ fileheader_t fh;
+ int circulate_flag = 1; /* circulate at end or begin */
+
+ match = hit_thread = 0;
+ now = pos = locmem->crs_ln;
+ if(stype == 'A') {
+ if(!*currowner)
+ return DONOTHING;
+ str_lower(a_ans, currowner);
+ query = a_ans;
+ circulate_flag = 0;
+ stype = 0;
+ } else if(stype == 'a') {
+ if(!*currowner)
+ return DONOTHING;
+ str_lower(a_ans, currowner);
+ query = a_ans;
+ circulate_flag = 0;
+ stype = RS_FORWARD;
+ } else if(stype == '/') {
+ if(!*t_ans)
+ return DONOTHING;
+ query = t_ans;
+ circulate_flag = 0;
+ stype = RS_TITLE | RS_FORWARD;
+ } else if(stype == '?') {
+ if(!*t_ans)
+ return DONOTHING;
+ circulate_flag = 0;
+ query = t_ans;
+ stype = RS_TITLE;
+ } else if(stype & RS_RELATED) {
+ tag = headers[pos - locmem->top_ln].title;
+ if(stype & RS_CURRENT) {
+ if(stype & RS_FIRST) {
+ if(!strncmp(currtitle, tag, 40))
+ return DONOTHING;
+ near = 0;
+ }
+ query = currtitle;
+ } else {
+ query = subject(tag);
+ if(stype & RS_FIRST) {
+ if(query == tag)
+ return DONOTHING;
+ near = 0;
+ }
+ }
+ } else if(!(stype & RS_THREAD)) {
+ query = (stype & RS_TITLE) ? t_ans : a_ans;
+ if(!*query && query == a_ans) {
+ if(*currowner)
+ strcpy(a_ans, currowner);
+ else if (*currauthor)
+ strcpy(a_ans, currauthor);
+ }
+ sprintf(s_pmt, "%s·j´M%s [%s] ",(stype & RS_FORWARD) ? "©¹«á":"©¹«e",
+ (stype & RS_TITLE) ? "¼ÐÃD" : "§@ªÌ", query);
+ getdata(b_lines - 1, 0, s_pmt, ans, 30, DOECHO);
+ if(*ans)
+ strcpy(query, ans);
+ else if(*query == '\0')
+ return DONOTHING;
+ }
+
+ tag = fh.owner;
+
+ do {
+ if(!circulate_flag || stype & RS_RELATED) {
+ if(stype & RS_FORWARD) {
+ if(++now > last_line)
+ return DONOTHING;
+ } else {
+ if(--now <= 0) {
+ if((stype & RS_FIRST) && (near)) {
+ hit_thread = 1;
+ return cursor_pos(locmem, near, 10);
+ }
+ return DONOTHING;
+ }
+ }
+ } else {
+ if(stype & RS_FORWARD) {
+ if(++now > last_line)
+ now = 1;
+ } else if(--now <= 0)
+ now = last_line;
+ }
+
+ get_record(currdirect, &fh, sizeof(fileheader_t), now);
+
+ if(fh.owner[0] == '-')
+ continue;
+
+ if(stype & RS_THREAD) {
+ if(strncasecmp(fh.title, str_reply, 3)) {
+ hit_thread = 1;
+ return cursor_pos(locmem, now, 10);
+ }
+ continue;
+ }
+
+ if(stype & RS_TITLE)
+ tag = subject(fh.title);
+
+ if(((stype & RS_RELATED) && !strncmp(tag, query, 40)) ||
+ (!(stype & RS_RELATED) && ((query == currowner) ?
+ !strcmp(tag, query) :
+ strstr_lower(tag, query)))) {
+ if((stype & RS_FIRST) && tag != fh.title) {
+ near = now;
+ continue;
+ }
+
+ hit_thread = 1;
+ match = cursor_pos(locmem, now, 10);
+ if((!(stype & RS_CURRENT)) &&
+ (stype & RS_RELATED) &&
+ strncmp(currtitle, query, 40)) {
+ strncpy(currtitle, query, 40);
+ match = PARTUPDATE;
+ }
+ break;
+ }
+ } while(now != pos);
+
+ return match;
+}
+
+
+#ifdef INTERNET_EMAIL
+static void mail_forward(fileheader_t *fhdr, char *direct, int mode) {
+ int i;
+ char buf[STRLEN];
+ char *p;
+
+ strncpy(buf, direct, sizeof(buf));
+ if((p = strrchr(buf, '/')))
+ *p = '\0';
+ switch(i = doforward(buf, fhdr, mode)) {
+ case 0:
+ outmsg(msg_fwd_ok);
+ break;
+ case -1:
+ outmsg(msg_fwd_err1);
+ break;
+ case -2:
+ outmsg(msg_fwd_err2);
+ break;
+ default:
+ break;
+ }
+ refresh();
+ sleep(1);
+}
+#endif
+
+extern userec_t cuser;
+
+static int select_read(keeploc_t *locmem, int sr_mode) {
+ register char *tag,*query,*temp;
+ fileheader_t fh;
+ char fpath[80], genbuf[MAXPATHLEN], buf3[5];
+ char static t_ans[TTLEN+1]="";
+ char static a_ans[IDLEN+1]="";
+ int fd, fr, size = sizeof(fileheader_t);
+ struct stat st;
+/* rocker.011018: make a reference number for process article */
+ int reference = 0;
+
+ if((currmode & MODE_SELECT))
+ return -1;
+ if(sr_mode == RS_TITLE)
+ query = subject(headers[locmem->crs_ln - locmem->top_ln].title);
+ else if(sr_mode == RS_NEWPOST)
+ {
+ strcpy(buf3, "Re: ");
+ query = buf3;
+ }
+ else
+ {
+ char buff[80];
+
+ query = (sr_mode == RS_RELATED) ? t_ans : a_ans;
+ sprintf(buff, "·j´M%s [%s] ",
+ (sr_mode == RS_RELATED) ? "¼ÐÃD" : "§@ªÌ", query);
+ getdata(b_lines, 0,buff, query, 30, DOECHO);
+ if(!(*query))
+ return DONOTHING;
+ }
+
+ if((fd = open(currdirect, O_RDONLY, 0)) != -1) {
+ sprintf(genbuf,"SR.%s",cuser.userid);
+ if(currstat==RMAIL)
+ sethomefile(fpath,cuser.userid,genbuf);
+ else
+ setbfile(fpath,currboard,genbuf);
+ if(((fr = open(fpath,O_WRONLY | O_CREAT | O_TRUNC,0600)) != -1)) {
+ switch(sr_mode) {
+ case RS_TITLE:
+ while(read(fd,&fh,size) == size) {
+ ++reference;
+ tag = subject(fh.title);
+ if(!strncmp(tag, query, 40))
+ {
+ fh.money = reference | FHR_REFERENCE;
+ write(fr,&fh,size);
+ }
+ }
+ break;
+ case RS_RELATED:
+ while(read(fd,&fh,size) == size) {
+ ++reference;
+ tag = fh.title;
+ if(strcasestr(tag,query))
+ {
+ fh.money = reference | FHR_REFERENCE;
+ write(fr,&fh,size);
+ }
+ }
+ break;
+ case RS_NEWPOST:
+ while(read(fd, &fh, size) == size) {
+ ++reference;
+ tag = fh.title;
+ temp = strstr(tag, query);
+ if(temp == NULL || temp != tag)
+ {
+ write(fr, &fh, size);
+ fh.money = reference | FHR_REFERENCE;
+ }
+ }
+ case RS_AUTHOR:
+ while(read(fd,&fh,size) == size) {
+ ++reference;
+ tag = fh.owner;
+ if(strcasestr(tag,query))
+ {
+ write(fr,&fh,size);
+ fh.money = reference | FHR_REFERENCE;
+ }
+ }
+ break;
+ }
+ fstat(fr,&st);
+ close(fr);
+ }
+ close(fd);
+ if(st.st_size) {
+ currmode |= MODE_SELECT;
+ strcpy(currdirect,fpath);
+ }
+ }
+ return st.st_size;
+}
+
+extern userec_t xuser;
+
+static int i_read_key(onekey_t *rcmdlist, keeploc_t *locmem, int ch, int bid) {
+ int i, mode = DONOTHING;
+
+ switch(ch) {
+ case 'q':
+ case 'e':
+ case KEY_LEFT:
+ return (currmode & MODE_SELECT) ? board_select() :
+ (currmode & MODE_ETC) ? board_etc() :
+ (currmode & MODE_DIGEST) ? board_digest() : DOQUIT;
+ case Ctrl('L'):
+ redoscr();
+ break;
+/*
+ case Ctrl('C'):
+ cal();
+ return FULLUPDATE;
+ break;
+*/
+ case KEY_ESC:
+ if(KEY_ESC_arg == 'i') {
+ t_idle();
+ return FULLUPDATE;
+ }
+ break;
+ case Ctrl('H'):
+ if(select_read(locmem, RS_NEWPOST))
+ return NEWDIRECT;
+ else
+ return READ_REDRAW;
+ case 'a':
+ case 'A':
+ if(select_read(locmem,RS_AUTHOR))
+ return NEWDIRECT;
+ else
+ return READ_REDRAW;
+ case '/':
+ case '?':
+ if(select_read(locmem,RS_RELATED))
+ return NEWDIRECT;
+ else
+ return READ_REDRAW;
+ case 'S':
+ if(select_read(locmem,RS_TITLE))
+ return NEWDIRECT;
+ else
+ return READ_REDRAW;
+ /* quick search title first */
+ case '=':
+ return thread(locmem, RELATE_FIRST);
+ case '\\':
+ return thread(locmem, CURSOR_FIRST);
+ /* quick search title forword */
+ case ']':
+ return thread(locmem, RELATE_NEXT);
+ case '+':
+ return thread(locmem, CURSOR_NEXT);
+ /* quick search title backword */
+ case '[':
+ return thread(locmem, RELATE_PREV);
+ case '-':
+ return thread(locmem, CURSOR_PREV);
+ case '<':
+ case ',':
+ return thread(locmem, THREAD_PREV);
+ case '.':
+ case '>':
+ return thread(locmem, THREAD_NEXT);
+ case 'p':
+ case 'k':
+ case KEY_UP:
+ return cursor_pos(locmem, locmem->crs_ln - 1, p_lines - 2);
+ case 'n':
+ case 'j':
+ case KEY_DOWN:
+ return cursor_pos(locmem, locmem->crs_ln + 1, 1);
+ case ' ':
+ case KEY_PGDN:
+ case 'N':
+ case Ctrl('F'):
+ if(last_line >= locmem->top_ln + p_lines) {
+ if(last_line > locmem->top_ln + p_lines)
+ locmem->top_ln += p_lines;
+ else
+ locmem->top_ln += p_lines - 1;
+ locmem->crs_ln = locmem->top_ln;
+ return PARTUPDATE;
+ }
+ cursor_clear(3 + locmem->crs_ln - locmem->top_ln, 0);
+ locmem->crs_ln = last_line;
+ cursor_show(3 + locmem->crs_ln - locmem->top_ln, 0);
+ break;
+ case KEY_PGUP:
+ case Ctrl('B'):
+ case 'P':
+ if(locmem->top_ln > 1) {
+ locmem->top_ln -= p_lines;
+ if(locmem->top_ln <= 0)
+ locmem->top_ln = 1;
+ locmem->crs_ln = locmem->top_ln;
+ return PARTUPDATE;
+ }
+ break;
+ case KEY_END:
+ case '$':
+ if(last_line >= locmem->top_ln + p_lines) {
+ locmem->top_ln = last_line - p_lines + 1;
+ if(locmem->top_ln <= 0)
+ locmem->top_ln = 1;
+ locmem->crs_ln = last_line;
+ return PARTUPDATE;
+ }
+ cursor_clear(3 + locmem->crs_ln - locmem->top_ln, 0);
+ locmem->crs_ln = last_line;
+ cursor_show(3 + locmem->crs_ln - locmem->top_ln, 0);
+ break;
+ case 'F':
+ case 'U':
+ if(HAS_PERM(PERM_FORWARD)) {
+ mail_forward(&headers[locmem->crs_ln - locmem->top_ln],
+ currdirect, ch /*== 'U'*/);
+ /*by CharlieL*/
+ return FULLUPDATE;
+ }
+ break;
+ case Ctrl('Q'):
+ return my_query(headers[locmem->crs_ln - locmem->top_ln].owner);
+ case Ctrl('S'):
+ if(HAS_PERM(PERM_ACCOUNTS)) {
+ int id;
+ userec_t muser;
+
+ strcpy(currauthor, headers[locmem->crs_ln - locmem->top_ln].owner);
+ stand_title("¨Ï¥ÎªÌ³]©w");
+ move(1, 0);
+ if((id = getuser(headers[locmem->crs_ln - locmem->top_ln].owner))){
+ memcpy(&muser, &xuser, sizeof(muser));
+ user_display(&muser, 1);
+ uinfo_query(&muser, 1, id);
+ }
+ return FULLUPDATE;
+ }
+ break;
+
+/* rocker.011018: ±Ä¥Î·sªºtag¼Ò¦¡ */
+ case 't':
+/* rocker.011112: ¸Ñ¨M¦Aselect mode¼Ð°O¤å³¹ªº°ÝÃD */
+ if (Tagger(atoi(headers[locmem->crs_ln - locmem->top_ln].filename + 2),
+ (currmode & MODE_SELECT) ?
+ (headers[locmem->crs_ln - locmem->top_ln].money & ~FHR_REFERENCE) :
+ locmem->crs_ln, TAG_TOGGLE))
+ return POS_NEXT;
+ return DONOTHING;
+
+ case Ctrl('C'):
+ if (TagNum)
+ {
+ TagNum = 0;
+ return FULLUPDATE;
+ }
+ return DONOTHING;
+
+ case Ctrl('T'):
+ return TagThread(currdirect);
+ case Ctrl('D'):
+ return TagPruner(bid);
+ case '\n':
+ case '\r':
+ case 'l':
+ case KEY_RIGHT:
+ ch = 'r';
+ default:
+ for(i = 0; rcmdlist[i].fptr; i++) {
+ if(rcmdlist[i].key == ch) {
+ mode = (*(rcmdlist[i].fptr))(locmem->crs_ln,
+ &headers[locmem->crs_ln -
+ locmem->top_ln], currdirect);
+ break;
+ }
+ if(rcmdlist[i].key == 'h')
+ if(currmode & (MODE_ETC | MODE_DIGEST))
+ return DONOTHING;
+ }
+ }
+ return mode;
+}
+
+void i_read(int cmdmode, char *direct, void (*dotitle)(), void (*doentry)(), onekey_t *rcmdlist, int bidcache) {
+ keeploc_t *locmem = NULL;
+ int recbase = 0, mode, ch;
+ int num = 0, entries = 0;
+ int i;
+ int jump = 0;
+ char genbuf[4];
+ char currdirect0[64];
+ int last_line0 = last_line;
+ int hit_thread0 = hit_thread;
+ fileheader_t *headers0 = headers;
+
+ strcpy(currdirect0 ,currdirect);
+#define FHSZ sizeof(fileheader_t)
+// Ptt:³oÃäheaders ¥i¥H°w¹ï¬ÝªOªº³Ì«á60½g°µcache
+ headers = (fileheader_t *)calloc(p_lines, FHSZ);
+ strcpy(currdirect, direct);
+ mode = NEWDIRECT;
+
+/* rocker.011018: ¥[¤J·sªºtag¾÷¨î */
+ TagNum = 0;
+
+ do {
+ /* ¨Ì¾Ú mode Åã¥Ü fileheader */
+ setutmpmode(cmdmode);
+ switch(mode) {
+ case NEWDIRECT: /* ²Ä¤@¦¸¸ü¤J¦¹¥Ø¿ý */
+ case DIRCHANGED:
+ if(bidcache>0 && !(currmode & (MODE_SELECT| MODE_DIGEST)) )
+ last_line=getbtotal(currbid);
+ else
+ last_line= get_num_records(currdirect, FHSZ);
+
+ if(mode == NEWDIRECT) {
+ if(last_line == 0) {
+ if(curredit & EDIT_ITEM) {
+ outs("¨S¦³ª««~");
+ refresh();
+ goto return_i_read;
+ } else if(curredit & EDIT_MAIL) {
+ outs("¨S¦³¨Ó«H");
+ refresh();
+ goto return_i_read;
+ } else if(currmode & MODE_ETC) {
+ board_etc(); /* Kaede */
+ outmsg("©|¥¼¦¬¿ý¨ä¥¦¤å³¹");
+ refresh();
+ } else if(currmode & MODE_DIGEST) {
+ board_digest(); /* Kaede */
+ outmsg("©|¥¼¦¬¿ý¤åºK");
+ refresh();
+ } else if(currmode & MODE_SELECT) {
+ board_select(); /* Leeym */
+ outmsg("¨S¦³¦¹¨t¦Cªº¤å³¹");
+ refresh();
+ } else {
+ getdata(b_lines - 1, 0,
+ "¬ÝªO·s¦¨¥ß (P)µoªí¤å³¹ (Q)Â÷¶}¡H[Q] ",
+ genbuf, 4, LCECHO);
+ if(genbuf[0] == 'p')
+ do_post();
+ goto return_i_read;
+ }
+ }
+ num = last_line - p_lines + 1;
+ locmem = getkeep(currdirect, num < 1 ? 1 : num, last_line);
+ }
+ recbase = -1;
+
+ case FULLUPDATE:
+ (*dotitle)();
+
+ case PARTUPDATE:
+ if(last_line < locmem->top_ln + p_lines) {
+ if(bidcache>0 && !(currmode & (MODE_SELECT| MODE_DIGEST)))
+ num=getbtotal(currbid);
+ else
+ num = get_num_records(currdirect, FHSZ);
+
+ if(last_line != num) {
+ last_line = num;
+ recbase = -1;
+ }
+ }
+
+ if(last_line == 0)
+ goto return_i_read;
+ else if(recbase != locmem->top_ln) {
+ recbase = locmem->top_ln;
+ if(recbase > last_line) {
+ recbase = (last_line - p_lines) >> 1;
+ if(recbase < 1)
+ recbase = 1;
+ locmem->top_ln = recbase;
+ }
+ if(bidcache>0 && !(currmode & (MODE_SELECT| MODE_DIGEST))
+ && (last_line - recbase) < DIRCACHESIZE )
+ entries = get_fileheader_cache(currbid, currdirect, headers,
+ recbase, p_lines);
+ else
+ entries = get_records(currdirect, headers, FHSZ, recbase,
+ p_lines);
+ }
+ if(locmem->crs_ln > last_line)
+ locmem->crs_ln = last_line;
+ move(3, 0);
+ clrtobot();
+ case PART_REDRAW:
+ move(3, 0);
+ for (i = 0; i < entries; i++)
+ (*doentry) (locmem->top_ln + i, &headers[i]);
+ case READ_REDRAW:
+ outmsg(curredit & EDIT_ITEM ?
+ "\033[44m ¨p¤H¦¬Âà \033[30;47m Ä~Äò? \033[m" :
+ curredit & EDIT_MAIL ? msg_mailer : MSG_POSTER);
+ break;
+ case READ_PREV:
+ case READ_NEXT:
+ case RELATE_PREV:
+ case RELATE_NEXT:
+ case RELATE_FIRST:
+ case POS_NEXT:
+ case 'A':
+ case 'a':
+ case '/':
+ case '?':
+ jump = 1;
+ break;
+ }
+
+ /* Ū¨úÁä½L¡A¥[¥H³B²z¡A³]©w mode */
+ if(!jump) {
+ cursor_show(3 + locmem->crs_ln - locmem->top_ln, 0);
+ ch = egetch();
+ mode = DONOTHING;
+ } else
+ ch = ' ';
+
+ if(mode == POS_NEXT) {
+ mode = cursor_pos(locmem, locmem->crs_ln + 1, 1);
+ if(mode == DONOTHING)
+ mode = PART_REDRAW;
+ jump = 0;
+ } else if(ch >= '0' && ch <= '9') {
+ if((i = search_num(ch, last_line)) != -1)
+ mode = cursor_pos(locmem, i + 1, 10);
+ } else {
+ if(!jump)
+ mode = i_read_key(rcmdlist, locmem, ch, currbid);
+ while(mode == READ_NEXT || mode == READ_PREV ||
+ mode == RELATE_FIRST || mode == RELATE_NEXT ||
+ mode == RELATE_PREV || mode == THREAD_NEXT ||
+ mode == THREAD_PREV || mode == 'A' || mode == 'a' ||
+ mode == '/' || mode == '?') {
+ int reload;
+
+ if(mode == READ_NEXT || mode == READ_PREV)
+ reload = move_cursor_line(locmem, mode);
+ else {
+ reload = thread(locmem, mode);
+ if(!hit_thread) {
+ mode = FULLUPDATE;
+ break;
+ }
+ }
+
+ if(reload == -1) {
+ mode = FULLUPDATE;
+ break;
+ } else if(reload) {
+ recbase = locmem->top_ln;
+
+ if(bidcache>0 && !(currmode &(MODE_SELECT| MODE_DIGEST))
+ && last_line-recbase<DIRCACHESIZE )
+ entries = get_fileheader_cache(currbid, currdirect,
+ headers, recbase, p_lines);
+ else
+ entries = get_records(currdirect, headers, FHSZ, recbase,
+ p_lines);
+
+ if(entries <= 0) {
+ last_line = -1;
+ break;
+ }
+ }
+ num = locmem->crs_ln - locmem->top_ln;
+ if(headers[num].owner[0] != '-')
+ mode = i_read_key(rcmdlist, locmem, ch, bidcache);
+ }
+ }
+ } while(mode != DOQUIT);
+#undef FHSZ
+
+ return_i_read:
+ free(headers);
+ last_line = last_line0;
+ hit_thread = hit_thread0;
+ headers = headers0;
+ strcpy(currdirect ,currdirect0);
+ return;
+}
diff --git a/mbbsd/record.c b/mbbsd/record.c
new file mode 100644
index 00000000..59bc6a75
--- /dev/null
+++ b/mbbsd/record.c
@@ -0,0 +1,536 @@
+/* $Id: record.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "modes.h"
+#include "proto.h"
+
+#undef HAVE_MMAP
+#define BUFSIZE 512
+
+extern char *str_reply;
+
+static void PttLock(int fd, int size, int mode) {
+ static struct flock lock_it;
+ int ret;
+
+ lock_it.l_whence = SEEK_CUR; /* from current point */
+ lock_it.l_start = 0; /* -"- */
+ lock_it.l_len = size; /* length of data */
+ lock_it.l_type = mode; /* set exclusive/write lock */
+ lock_it.l_pid = 0; /* pid not actually interesting */
+ while((ret = fcntl(fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR);
+}
+
+#define safewrite write
+
+int get_num_records(char *fpath, int size) {
+ struct stat st;
+ if(stat(fpath, &st) == -1)
+ return 0;
+ return st.st_size / size;
+}
+
+int get_sum_records(char* fpath, int size) {
+ struct stat st;
+ long ans = 0;
+ FILE* fp;
+ fileheader_t fhdr;
+ char buf[200], *p;
+
+ if(!(fp = fopen(fpath, "r")))
+ return -1;
+
+ strcpy(buf, fpath);
+ p = strrchr(buf, '/') + 1;
+
+ while(fread(&fhdr, size, 1, fp) == 1) {
+ strcpy(p, fhdr.filename);
+ if(stat(buf, &st) == 0 && S_ISREG(st.st_mode) && st.st_nlink == 1)
+ ans += st.st_size;
+ }
+ fclose(fp);
+ return ans / 1024;
+}
+
+int get_record(char *fpath, void *rptr, int size, int id) {
+ int fd = -1;
+
+ if(id < 1 || (fd = open(fpath, O_RDONLY, 0)) != -1) {
+ if(lseek(fd, (off_t)(size * (id - 1)), SEEK_SET) != -1) {
+ if(read(fd, rptr, size) == size) {
+ close(fd);
+ return 0;
+ }
+ }
+ close(fd);
+ }
+ return -1;
+}
+
+int get_records(char *fpath, void *rptr, int size, int id, int number) {
+ int fd;
+
+ if(id < 1 || (fd = open(fpath, O_RDONLY, 0)) == -1)
+ return -1;
+
+ if(lseek(fd, (off_t)(size * (id - 1)), SEEK_SET) == -1) {
+ close(fd);
+ return 0;
+ }
+ if((id = read(fd, rptr, size * number)) == -1) {
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ return id / size;
+}
+
+int substitute_record(char *fpath, void *rptr, int size, int id) {
+ int fd;
+
+ if(id < 1 || (fd = open(fpath, O_WRONLY | O_CREAT, 0644)) == -1)
+ return -1;
+
+ lseek(fd, (off_t) (size * (id - 1)), SEEK_SET);
+ PttLock(fd, size, F_WRLCK);
+ safewrite(fd, rptr, size);
+ PttLock(fd, size, F_UNLCK);
+ close(fd);
+
+ return 0;
+}
+
+/* rocker.011022: ÁקKlockÀɶ}±Ò®É¤£¥¿±`Â_½u,³y¦¨¥Ã¤[lock */
+static int
+force_open (char *fname)
+{
+ int fd;
+ time_t expire;
+
+ expire = time(NULL) - 3600; /* lock ¦s¦b¶W¹L¤@­Ó¤p®É´N¬O¦³°ÝÃD! */
+
+ if (dasht (fname) < expire) return -1;
+ unlink(fname);
+ fd = open (fname, O_WRONLY|O_TRUNC, 0644);
+
+ return fd;
+}
+
+
+#if !defined(_BBS_UTIL_C_)
+/* new/old/lock file processing */
+typedef struct nol_t {
+ char newfn[256];
+ char oldfn[256];
+ char lockfn[256];
+} nol_t;
+
+static void nolfilename(nol_t *n, char *fpath) {
+ sprintf(n->newfn, "%s.new", fpath);
+ sprintf(n->oldfn, "%s.old", fpath);
+ sprintf(n->lockfn, "%s.lock", fpath);
+}
+
+int delete_record(char fpath[], int size, int id) {
+ nol_t my;
+ char abuf[BUFSIZE];
+ int fdr, fdw, fd;
+ int count;
+
+ nolfilename(&my, fpath);
+ if((fd = open(my.lockfn, O_RDWR | O_CREAT | O_APPEND, 0644)) == -1)
+ return -1;
+
+ flock(fd, LOCK_EX);
+
+ if((fdr = open(fpath, O_RDONLY, 0)) == -1) {
+ move(10,10);
+ outs("delete_record failed!!! (open)");
+ pressanykey();
+ flock(fd, LOCK_UN);
+ close(fd);
+ return -1;
+ }
+
+ if(
+ ((fdw = open(my.newfn, O_WRONLY | O_CREAT | O_EXCL, 0644)) == -1) &&
+ ((fdw = force_open (my.newfn)) == -1)) {
+ flock(fd, LOCK_UN);
+ close(fd);
+ close(fdr);
+ return -1;
+ }
+ count = 1;
+ while(read(fdr, abuf, size) == size) {
+ if(id != count++ && (safewrite(fdw, abuf, size) == -1)) {
+ unlink(my.newfn);
+ close(fdr);
+ close(fdw);
+ flock(fd, LOCK_UN);
+ close(fd);
+ return -1;
+ }
+ }
+ close(fdr);
+ close(fdw);
+ if(Rename(fpath, my.oldfn) == -1 || Rename(my.newfn, fpath) == -1) {
+ flock(fd, LOCK_UN);
+ close(fd);
+ return -1;
+ }
+ flock(fd, LOCK_UN);
+ close(fd);
+ return 0;
+}
+
+static char *title_body(char *title) {
+ if(!strncasecmp(title, str_reply, 3)) {
+ title += 3;
+ if(*title == ' ')
+ title++;
+ }
+ return title;
+}
+
+int delete_range(char *fpath, int id1, int id2) {
+ fileheader_t fhdr;
+ nol_t my;
+ char fullpath[STRLEN], *t;
+ int fdr, fdw, fd;
+ int count;
+ extern int Tagger();
+
+ nolfilename(&my, fpath);
+
+ if((fd = open(my.lockfn, O_RDWR | O_CREAT | O_APPEND, 0644)) == -1)
+ return -1;
+
+ flock(fd, LOCK_EX);
+
+ if((fdr = open(fpath, O_RDONLY, 0)) == -1) {
+ flock(fd, LOCK_UN);
+ close(fd);
+ return -1;
+ }
+
+ if(
+ ((fdw = open(my.newfn, O_WRONLY | O_CREAT | O_EXCL, 0644)) == -1) &&
+ ((fdw = force_open (my.newfn)) == -1)) {
+ close(fdr);
+ flock(fd, LOCK_UN);
+ close(fd);
+ return -1;
+ }
+
+ count = 1;
+ strcpy(fullpath, fpath);
+ t = strrchr(fullpath, '/') + 1;
+
+ while(read(fdr, &fhdr, sizeof(fileheader_t)) == sizeof(fileheader_t))
+ {
+ strcpy(t, fhdr.filename);
+
+/* rocker.011018: add new tag delete */
+ if (
+ (fhdr.filemode & FILE_MARKED) || /* ¼Ð°O */
+ (fhdr.filemode & FILE_DIGEST) || /* ¤åºK */
+ (id1 && (count < id1 || count > id2)) || /* range */
+ (!id1 && Tagger(atoi (t + 2), count, TAG_NIN))) /* TagList */
+ {
+ if((safewrite(fdw, &fhdr, sizeof(fileheader_t)) == -1)) {
+ close(fdr);
+ close(fdw);
+ unlink(my.newfn);
+ flock(fd, LOCK_UN);
+ close(fd);
+ return -1;
+ }
+ }
+ else
+ {
+ //if(dashd(fullpath))
+ unlink(fullpath);
+ }
+ ++count;
+ }
+ close(fdr);
+ close(fdw);
+ if(Rename(fpath, my.oldfn) == -1 || Rename(my.newfn, fpath) == -1) {
+ flock(fd, LOCK_UN);
+ close(fd);
+ return -1;
+ }
+ flock(fd, LOCK_UN);
+ close(fd);
+ return 0;
+}
+
+int search_rec(char* dirname, int (*filecheck)()) {
+ fileheader_t fhdr;
+ FILE *fp;
+ int ans = 0;
+
+ if(!(fp = fopen(dirname, "r")))
+ return 0;
+
+ while(fread(&fhdr, sizeof(fhdr), 1, fp)) {
+ ans++;
+ if((*filecheck) (&fhdr)) {
+ fclose(fp);
+ return ans;
+ }
+ }
+ fclose(fp);
+ return 0;
+}
+
+int delete_files(char* dirname, int (*filecheck)(), int record) {
+ fileheader_t fhdr;
+ FILE *fp, *fptmp;
+ int ans = 0;
+ char tmpfname[128];
+ char genbuf[256];
+ char deleted[256];
+ fileheader_t delfh;
+ char deletedDIR[] = "boards/deleted/.DIR";
+
+ strcpy(deleted, "boards/deleted");
+
+ if(!(fp = fopen(dirname, "r")))
+ return ans;
+
+ strcpy(tmpfname, dirname);
+ strcat(tmpfname, "_tmp");
+
+ if(!(fptmp = fopen(tmpfname, "w"))) {
+ fclose(fp);
+ return ans;
+ }
+
+ while(fread(&fhdr, sizeof(fhdr), 1, fp)){
+ if((*filecheck)(&fhdr)) {
+ ans++;
+ setdirpath(genbuf, dirname, fhdr.filename);
+ if (record){
+ deleted[14] = '\0';
+ stampfile(deleted, &delfh);
+ strcpy(delfh.owner, fhdr.owner);
+ strcpy(delfh.title, fhdr.title);
+ Link(genbuf, deleted);
+ append_record(deletedDIR, &delfh, sizeof(delfh));
+ }
+ unlink(genbuf);
+ } else
+ fwrite(&fhdr, sizeof(fhdr), 1, fptmp);
+ }
+
+ fclose(fp);
+ fclose(fptmp);
+ unlink(dirname);
+ Rename(tmpfname, dirname);
+
+ return ans;
+}
+
+int delete_file(char *dirname, int size, int ent, int (*filecheck)()) {
+ char abuf[BUFSIZE];
+ int fd;
+ struct stat st;
+ long numents;
+
+ if(ent < 1 || (fd = open(dirname, O_RDWR)) == -1)
+ return -1;
+ flock(fd, LOCK_EX);
+ fstat(fd, &st);
+ numents = ((long) st.st_size) / size;
+ if(((long) st.st_size) % size)
+ fprintf(stderr, "align err\n");
+ if(lseek(fd, (off_t) size * (ent - 1), SEEK_SET) != -1) {
+ if(read(fd, abuf, size) == size){
+ if((*filecheck) (abuf)) {
+ int i;
+
+ for(i = ent; i < numents; i++) {
+ if(lseek(fd, (off_t)((i) * size), SEEK_SET) == -1 ||
+ read(fd, abuf, size) != size ||
+ lseek(fd, (off_t)(i - 1) * size, SEEK_SET) == -1)
+ break;
+ if(safewrite(fd, abuf, size) != size)
+ break;
+ }
+ ftruncate(fd, (off_t) size * (numents - 1));
+ flock(fd, LOCK_UN);
+ close(fd);
+ return 0;
+ }
+ }
+ }
+ lseek(fd, 0, SEEK_SET);
+ ent = 1;
+ while(read(fd, abuf, size) == size) {
+ if((*filecheck)(abuf)) {
+ int i;
+
+ for(i = ent; i < numents; i++) {
+ if(lseek(fd, (off_t) (i + 1) * size, SEEK_SET) == -1 ||
+ read(fd, abuf, size) != size ||
+ lseek(fd, (off_t) (i) * size, SEEK_SET) == -1 ||
+ safewrite(fd, abuf, size) != size)
+ break;
+ }
+ ftruncate(fd, (off_t) size * (numents - 1));
+ flock(fd, LOCK_UN);
+ close(fd);
+ return 0;
+ }
+ ent++;
+ }
+ flock(fd, LOCK_UN);
+ close(fd);
+ return -1;
+}
+
+#endif /* !defined(_BBS_UTIL_C_) */
+
+int apply_record(char *fpath, int (*fptr)(), int size) {
+ char abuf[BUFSIZE];
+ FILE* fp;
+
+ if(!(fp = fopen(fpath, "r")))
+ return -1;
+
+ while(fread(abuf, 1, size, fp) == size)
+ if((*fptr) (abuf) == QUIT) {
+ fclose(fp);
+ return QUIT;
+ }
+ fclose(fp);
+ return 0;
+}
+
+/* mail / post ®É¡A¨Ì¾Ú®É¶¡«Ø¥ßÀɮסA¥[¤W¶lÂW */
+int stampfile(char *fpath, fileheader_t *fh) {
+ register char *ip = fpath;
+ time_t dtime;
+ struct tm *ptime;
+ int fp = 0;
+
+ if(access(fpath, X_OK | R_OK | W_OK))
+ mkdir(fpath, 0755);
+
+ time(&dtime);
+ while (*(++ip));
+ *ip++ = '/';
+ do {
+ sprintf(ip, "M.%ld.A", ++dtime );
+ if(fp == -1 && errno != EEXIST)
+ return -1;
+ } while((fp = open(fpath, O_CREAT | O_EXCL | O_WRONLY, 0644)) == -1);
+ close(fp);
+ memset(fh, 0, sizeof(fileheader_t));
+ strcpy(fh->filename, ip);
+ ptime = localtime(&dtime);
+ sprintf(fh->date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday);
+ return 0;
+}
+
+void stampdir(char *fpath, fileheader_t *fh) {
+ register char *ip = fpath;
+ time_t dtime;
+ struct tm *ptime;
+
+ if(access(fpath, X_OK | R_OK | W_OK))
+ mkdir(fpath, 0755);
+
+ time(&dtime);
+ while(*(++ip));
+ *ip++ = '/';
+ do {
+ sprintf(ip, "D%lX", ++dtime & 07777);
+ } while(mkdir(fpath, 0755) == -1);
+ memset(fh, 0, sizeof(fileheader_t));
+ strcpy(fh->filename, ip);
+ ptime = localtime(&dtime);
+ sprintf(fh->date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday);
+}
+
+void stamplink(char *fpath, fileheader_t *fh) {
+ register char *ip = fpath;
+ time_t dtime;
+ struct tm *ptime;
+
+ if(access(fpath, X_OK | R_OK | W_OK))
+ mkdir(fpath, 0755);
+
+ time(&dtime);
+ while(*(++ip));
+ *ip++ = '/';
+ do {
+ sprintf(ip, "S%lX", ++dtime );
+ } while(symlink("temp", fpath) == -1);
+ memset(fh, 0, sizeof(fileheader_t));
+ strcpy(fh->filename, ip);
+ ptime = localtime(&dtime);
+ sprintf(fh->date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday);
+}
+
+int do_append(char *fpath, fileheader_t *record, int size) {
+ int fd;
+
+ if((fd = open(fpath, O_WRONLY | O_CREAT, 0644)) == -1) {
+ perror("open");
+ return -1;
+ }
+ flock(fd, LOCK_EX);
+ lseek(fd, 0, SEEK_END);
+
+ safewrite(fd, record, size);
+
+ flock(fd, LOCK_UN);
+ close(fd);
+ return 0;
+}
+
+int append_record(char *fpath, fileheader_t *record, int size) {
+#if !defined(_BBS_UTIL_C_)
+ int m,n;
+ if(get_num_records(fpath, sizeof(fileheader_t)) <= MAX_KEEPMAIL * 2) {
+ FILE *fp;
+ char buf[512],address[200];
+
+ for(n = strlen(fpath) - 1 ; fpath[n] != '/' && n > 0; n--);
+ strncpy(buf, fpath, n + 1);
+ buf[n + 1] = 0;
+ for(m = strlen(buf) - 2 ; buf[m] != '/' && m > 0 ; m--);
+ strcat(buf, ".forward");
+ if((fp = fopen(buf,"r"))) {
+ fscanf(fp,"%s",address);
+ fclose(fp);
+ if(buf[0] != 0 && buf[0] != ' ') {
+ buf[n + 1] = 0;
+ strcat(buf, record->filename);
+ do_append(fpath,record,size);
+#ifndef USE_BSMTP
+ bbs_sendmail(buf,record->title,address);
+#else
+ bsmtp(buf, record->title, address, 0);
+#endif
+ return 0;
+ }
+ }
+ }
+#endif
+
+ do_append(fpath,record,size);
+
+ return 0;
+}
diff --git a/mbbsd/register.c b/mbbsd/register.c
new file mode 100644
index 00000000..e9c25be5
--- /dev/null
+++ b/mbbsd/register.c
@@ -0,0 +1,339 @@
+/* $Id: register.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#define _XOPEN_SOURCE
+
+#include <stdio.h>
+#include <strings.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "perm.h"
+#include "common.h"
+#include "proto.h"
+
+extern char *str_new;
+extern char *msg_uid;
+extern int t_lines, t_columns; /* Screen size / width */
+extern char *str_mail_address;
+
+/* password encryption */
+static char pwbuf[14];
+
+char *genpasswd(char *pw) {
+ if(pw[0]) {
+ char saltc[2], c;
+ int i;
+
+ 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);
+ }
+ return "";
+}
+
+int checkpasswd(char *passwd, char *test) {
+ char *pw;
+
+ strncpy(pwbuf, test, 14);
+ pw = crypt(pwbuf, passwd);
+ return (!strncmp(pw, passwd, 14));
+}
+
+/* Àˬd user µù¥U±¡ªp */
+int bad_user_id(char *userid) {
+ int len, i;
+ len = strlen(userid);
+
+ if(len < 2)
+ return 1;
+
+ if (not_alpha(userid[0]))
+ return 1;
+ for (i=1; i<len; i++) //DickG:­×¥¿¤F¥u¤ñ¸û userid ²Ä¤@­Ó¦r¤¸ªº bug
+ if(not_alnum(userid[i]))
+ return 1;
+
+ if(strcasecmp(userid, str_new) == 0)
+ return 1;
+
+ /* while((ch = *(++userid)))
+ if(not_alnum(ch))
+ return 1;*/
+ return 0;
+}
+
+/* -------------------------------- */
+/* New policy for allocate new user */
+/* (a) is the worst user currently */
+/* (b) is the object to be compared */
+/* -------------------------------- */
+static int compute_user_value(userec_t *urec, time_t clock) {
+ int value;
+
+ /* if (urec) has XEMPT permission, don't kick it */
+ if((urec->userid[0] == '\0') || (urec->userlevel & PERM_XEMPT)
+ /*|| (urec->userlevel & PERM_LOGINOK)*/
+ || !strcmp(STR_GUEST,urec->userid))
+ return 999999;
+ value = (clock - urec->lastlogin) / 60; /* minutes */
+
+ /* new user should register in 30 mins */
+ if(strcmp(urec->userid, str_new) == 0)
+ return 30 - value;
+#if 0
+ if (!urec->numlogins) /* ¥¼ login ¦¨¥\ªÌ¡A¤£«O¯d */
+ return -1;
+ if (urec->numlogins <= 3) /* #login ¤Ö©ó¤TªÌ¡A«O¯d 20 ¤Ñ */
+ return 20 * 24 * 60 - value;
+#endif
+ /* ¥¼§¹¦¨µù¥UªÌ¡A«O¯d 15 ¤Ñ */
+ /* ¤@¯ë±¡ªp¡A«O¯d 120 ¤Ñ */
+ return (urec->userlevel & PERM_LOGINOK ? 120 : 15) * 24 * 60 - value;
+}
+
+int check_and_expire_account(int uid,userec_t *urec)
+{
+ userec_t zerorec;
+ time_t now=time(NULL);
+ char genbuf[200],genbuf2[200];
+ int val;
+ if((val = compute_user_value(urec, now)) < 0) {
+ sprintf(genbuf, "#%d %-12s %15.15s %d %d %d",
+ uid, urec->userid, ctime(&(urec->lastlogin)) + 4,
+ urec->numlogins, urec->numposts, val);
+ if(val > -1 * 60 * 24 * 365) {
+ memset(&zerorec, 0, sizeof(zerorec));
+ log_usies("CLEAN", genbuf);
+ sprintf(genbuf, "home/%c/%s", urec->userid[0],
+ urec->userid);
+ sprintf(genbuf2, "tmp/%s", urec->userid);
+ if(dashd(genbuf) && Rename(genbuf, genbuf2)) {
+ sprintf(genbuf, "/bin/rm -fr home/%c/%s >/dev/null 2>&1",
+ urec->userid[0],urec->userid);
+ system(genbuf);
+ }
+ passwd_update(uid, &zerorec);
+ remove_from_uhash(uid - 1);
+ add_to_uhash(uid - 1, "");
+ }
+ else
+ {
+ val=0;
+ log_usies("DATED", genbuf);
+ }
+ }
+ return val;
+}
+
+extern char *fn_passwd;
+
+int getnewuserid() {
+ char genbuf[50];
+ static char *fn_fresh = ".fresh";
+ userec_t utmp,zerorec;
+ time_t clock;
+ struct stat st;
+ int fd, i;
+
+ memset(&zerorec, 0, sizeof(zerorec));
+ clock = time(NULL);
+
+ /* Lazy method : ¥ý§ä´M¤w¸g²M°£ªº¹L´Á±b¸¹ */
+ if((i = searchnewuser(0)) == 0) {
+ /* ¨C 1 ­Ó¤p®É¡A²M²z user ±b¸¹¤@¦¸ */
+ if((stat(fn_fresh, &st) == -1) || (st.st_mtime < clock - 3600)) {
+ if((fd = open(fn_fresh, O_RDWR | O_CREAT, 0600)) == -1)
+ return -1;
+ write(fd, ctime(&clock), 25);
+ close(fd);
+ log_usies("CLEAN", "dated users");
+
+ fprintf(stdout, "´M§ä·s±b¸¹¤¤, ½Ðµy«Ý¤ù¨è...\n\r");
+
+ if((fd = open(fn_passwd, O_RDWR | O_CREAT, 0600)) == -1)
+ return -1;
+
+ /* ¤£¾å±o¬°¤°»ò­n±q 2 ¶}©l... Ptt:¦]¬°SYSOP¦b1 */
+ for(i = 2; i <= MAX_USERS; i++) {
+ passwd_query(i, &utmp);
+ check_and_expire_account(i,&utmp);
+ }
+ }
+ }
+
+ passwd_lock();
+ i = searchnewuser(1);
+ if((i <= 0) || (i > MAX_USERS)) {
+ passwd_unlock();
+ if(more("etc/user_full", NA) == -1)
+ fprintf(stdout, "©êºp¡A¨Ï¥ÎªÌ±b¸¹¤w¸gº¡¤F¡AµLªkµù¥U·sªº±b¸¹\n\r");
+ safe_sleep(2);
+ exit(1);
+ }
+
+ sprintf(genbuf, "uid %d", i);
+ log_usies("APPLY", genbuf);
+
+ strcpy(zerorec.userid, str_new);
+ zerorec.lastlogin = clock;
+ passwd_update(i, &zerorec);
+ setuserid(i, zerorec.userid);
+ passwd_unlock();
+ return i;
+}
+
+void new_register() {
+ extern userec_t xuser;
+ userec_t newuser;
+ char passbuf[STRLEN];
+ int allocid, try, id;
+
+ memset(&newuser, 0, sizeof(newuser));
+ more("etc/register", NA);
+ try = 0;
+ while(1) {
+ if(++try >= 6) {
+ outs("\n±z¹Á¸Õ¿ù»~ªº¿é¤J¤Ó¦h¡A½Ð¤U¦¸¦A¨Ó§a\n");
+ refresh();
+
+ pressanykey();
+ oflush();
+ exit(1);
+ }
+ getdata(17, 0, msg_uid, newuser.userid, IDLEN + 1, DOECHO);
+
+ if(bad_user_id(newuser.userid))
+ outs("µLªk±µ¨ü³o­Ó¥N¸¹¡A½Ð¨Ï¥Î­^¤å¦r¥À¡A¨Ã¥B¤£­n¥]§tªÅ®æ\n");
+ else if ((id=getuser(newuser.userid)) &&
+ (id=check_and_expire_account(id,&xuser))>=0)
+ {
+ if(id==999999)
+ outs("¦¹¥N¸¹¤w¸g¦³¤H¨Ï¥Î ¬O¤£¦º¤§¨­");
+ else
+ {
+ sprintf(passbuf,"¦¹¥N¸¹¤w¸g¦³¤H¨Ï¥Î ÁÙ¦³%d¤Ñ¤~¹L´Á \n",id/(60*24));
+ outs(passbuf);
+ }
+ }
+ else
+ break;
+ }
+
+ try = 0;
+ while(1) {
+ if(++try >= 6) {
+ outs("\n±z¹Á¸Õ¿ù»~ªº¿é¤J¤Ó¦h¡A½Ð¤U¦¸¦A¨Ó§a\n");
+ refresh();
+
+ pressanykey();
+ oflush();
+ exit(1);
+ }
+ if((getdata(19, 0, "½Ð³]©w±K½X¡G", passbuf, PASSLEN, NOECHO) < 3) ||
+ !strcmp(passbuf, newuser.userid)) {
+ outs("±K½X¤Ó²³æ¡A©ö¾D¤J«I¡A¦Ü¤Ö­n 4 ­Ó¦r¡A½Ð­«·s¿é¤J\n");
+ continue;
+ }
+ strncpy(newuser.passwd, passbuf, PASSLEN);
+ getdata(20, 0, "½ÐÀˬd±K½X¡G", passbuf, PASSLEN, NOECHO);
+ if(strncmp(passbuf, newuser.passwd, PASSLEN)) {
+ outs("±K½X¿é¤J¿ù»~, ½Ð­«·s¿é¤J±K½X.\n");
+ continue;
+ }
+ passbuf[8] = '\0';
+ strncpy(newuser.passwd, genpasswd(passbuf), PASSLEN);
+ break;
+ }
+ newuser.userlevel = PERM_DEFAULT;
+ newuser.uflag = COLOR_FLAG | BRDSORT_FLAG | MOVIE_FLAG;
+ newuser.firstlogin = newuser.lastlogin = time(NULL);
+ newuser.money = 0;
+ newuser.pager = 1;
+ allocid = getnewuserid();
+ if(allocid > MAX_USERS || allocid <= 0) {
+ fprintf(stderr, "¥»¯¸¤H¤f¤w¹F¹¡©M¡I\n");
+ exit(1);
+ }
+
+ if(passwd_update(allocid, &newuser) == -1) {
+ fprintf(stderr, "«Èº¡¤F¡A¦A¨£¡I\n");
+ exit(1);
+ }
+ setuserid(allocid, newuser.userid);
+ if(!dosearchuser(newuser.userid)) {
+ fprintf(stderr, "µLªk«Ø¥ß±b¸¹\n");
+ exit(1);
+ }
+}
+
+extern userec_t cuser;
+
+void check_register() {
+ char *ptr = NULL;
+
+ stand_title("½Ð¸Ô²Ó¶ñ¼g­Ó¤H¸ê®Æ");
+
+ while(strlen(cuser.username) < 2)
+ getdata(2, 0, "ºï¸¹¼ÊºÙ¡G", cuser.username, 24, DOECHO);
+
+ for(ptr = cuser.username; *ptr; ptr++) {
+ if (*ptr == 9) /* TAB convert */
+ *ptr = ' ';
+ }
+ while(strlen(cuser.realname) < 4)
+ getdata(4, 0, "¯u¹ê©m¦W¡G", cuser.realname, 20, DOECHO);
+
+ while(strlen(cuser.address) < 8)
+ getdata(6, 0, "Ápµ¸¦a§}¡G", cuser.address, 50, DOECHO);
+
+
+ if(!strchr(cuser.email, '@')) {
+ bell();
+ move(t_lines - 4, 0);
+ prints("¡° ¬°¤F±zªºÅv¯q¡A½Ð¶ñ¼g¯u¹êªº E-mail address¡A "
+ "¥H¸ê½T»{»Õ¤U¨­¥÷¡A\n"
+ "®æ¦¡¬° \033[44muser@domain_name\033[0m ©Î \033[44muser"
+ "@\\[ip_number\\]\033[0m¡C\n\n"
+ "¡° ¦pªG±z¯uªº¨S¦³ E-mail¡A½Ðª½±µ«ö [return] §Y¥i¡C");
+
+ do {
+ getdata(8, 0, "¹q¤l«H½c¡G", cuser.email, 50, DOECHO);
+ if(!cuser.email[0])
+ sprintf(cuser.email, "%s%s", cuser.userid, str_mail_address);
+ } while(!strchr(cuser.email, '@'));
+
+ }
+ if(!HAS_PERM(PERM_SYSOP) && !HAS_PERM(PERM_LOGINOK)) {
+ /* ¦^ÂйL¨­¥÷»{ÃÒ«H¨ç¡A©Î´¿¸g E-mail post ¹L */
+ clear();
+ move(9,3);
+ prints("½Ð¸Ô¶ñ¼g\033[32mµù¥U¥Ó½Ð³æ\033[m¡A"
+ "³q§i¯¸ªø¥HÀò±o¶i¶¥¨Ï¥ÎÅv¤O¡C\n\n\n\n");
+ u_register();
+ }
+
+#ifdef NEWUSER_LIMIT
+ if(!(cuser.userlevel & PERM_LOGINOK) && !HAS_PERM(PERM_SYSOP)) {
+ if(cuser.lastlogin - cuser.firstlogin < 3 * 86400)
+ cuser.userlevel &= ~PERM_POST;
+ more("etc/newuser", YEA);
+ }
+#endif
+}
diff --git a/mbbsd/screen.c b/mbbsd/screen.c
new file mode 100644
index 00000000..46ad5b38
--- /dev/null
+++ b/mbbsd/screen.c
@@ -0,0 +1,559 @@
+/* $Id: screen.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "proto.h"
+
+extern int t_lines, t_columns; /* Screen size / width */
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+extern int p_lines; /* a Page of Screen line numbers: tlines-4 */
+extern int showansi;
+
+extern char *clearbuf;
+extern char *cleolbuf;
+extern char *scrollrev;
+extern char *strtstandout;
+extern char *endstandout;
+extern int clearbuflen;
+extern int cleolbuflen;
+extern int scrollrevlen;
+extern int strtstandoutlen;
+extern int endstandoutlen;
+extern int automargins;
+#ifdef SUPPORT_GB
+static int current_font_type=TYPE_BIG5;
+static int gbinited=0;
+#endif
+#define SCR_WIDTH 80
+#define o_clear() output(clearbuf,clearbuflen)
+#define o_cleol() output(cleolbuf,cleolbuflen)
+#define o_scrollrev() output(scrollrev,scrollrevlen)
+#define o_standup() output(strtstandout,strtstandoutlen)
+#define o_standdown() output(endstandout,endstandoutlen)
+
+unsigned char scr_lns, scr_cols;
+static unsigned char cur_ln = 0, cur_col = 0;
+static unsigned char docls, downfrom = 0;
+static unsigned char standing = NA;
+static char roll = 0;
+static int scrollcnt, tc_col, tc_line;
+
+screenline_t *big_picture = NULL;
+
+#define MODIFIED (1) /* if line has been modifed, screen output */
+#define STANDOUT (2) /* if this line has a standout region */
+
+int tputs(const char *str, int affcnt, int (*putc)(int));
+
+void initscr() {
+ if(!big_picture) {
+ scr_lns = t_lines;
+ scr_cols = t_columns = ANSILINELEN;
+ /* scr_cols = MIN(t_columns, ANSILINELEN); */
+ big_picture = (screenline_t *) calloc(scr_lns, sizeof(screenline_t));
+ docls = YEA;
+ }
+}
+
+void move(int y, int x) {
+ cur_col = x;
+ cur_ln = y;
+}
+
+void getyx(int *y, int *x) {
+ *y = cur_ln;
+ *x = cur_col;
+}
+
+static void rel_move(int was_col, int was_ln, int new_col, int new_ln) {
+ if(new_ln >= t_lines || new_col >= t_columns)
+ return;
+
+ tc_col = new_col;
+ tc_line = new_ln;
+ if(new_col == 0) {
+ if(new_ln == was_ln) {
+ if(was_col)
+ ochar('\r');
+ return;
+ } else if(new_ln == was_ln + 1) {
+ ochar('\n');
+ if(was_col)
+ ochar('\r');
+ return;
+ }
+ }
+
+ if(new_ln == was_ln) {
+ if(was_col == new_col)
+ return;
+
+ if(new_col == was_col - 1) {
+ ochar(Ctrl('H'));
+ return;
+ }
+ }
+ do_move(new_col, new_ln);
+}
+
+static void standoutput(char *buf, int ds, int de, int sso, int eso) {
+ int st_start, st_end;
+
+ if(eso <= ds || sso >= de) {
+ output(buf + ds, de - ds);
+ } else {
+ st_start = MAX(sso, ds);
+ st_end = MIN(eso, de);
+ if(sso > ds)
+ output(buf + ds, sso - ds);
+ o_standup();
+ output(buf + st_start, st_end - st_start);
+ o_standdown();
+ if(de > eso)
+ output(buf + eso, de - eso);
+ }
+}
+
+void redoscr() {
+ register screenline_t *bp;
+ register int i, j, len;
+
+ o_clear();
+ for(tc_col = tc_line = i = 0, j = roll; i < scr_lns; i++, j++) {
+ if(j >= scr_lns)
+ j = 0;
+ bp = &big_picture[j];
+ if((len = bp->len)) {
+ rel_move(tc_col, tc_line, 0, i);
+ if(bp->mode & STANDOUT)
+ standoutput(bp->data, 0, len, bp->sso, bp->eso);
+ else
+ output(bp->data, len);
+ tc_col += len;
+ if(tc_col >= t_columns) {
+ if (automargins)
+ tc_col = t_columns - 1;
+ else {
+ tc_col -= t_columns;
+ tc_line++;
+ if(tc_line >= t_lines)
+ tc_line = b_lines;
+ }
+ }
+ bp->mode &= ~(MODIFIED);
+ bp->oldlen = len;
+ }
+ }
+ rel_move(tc_col, tc_line, cur_col, cur_ln);
+ docls = scrollcnt = 0;
+ oflush();
+}
+
+void refresh() {
+ register screenline_t *bp = big_picture;
+ register int i, j, len;
+ extern int automargins;
+ extern int scrollrevlen;
+ if(num_in_buf())
+ return;
+
+ if((docls) || (abs(scrollcnt) >= (scr_lns - 3))) {
+ redoscr();
+ return;
+ }
+
+ if(scrollcnt < 0) {
+ if(!scrollrevlen) {
+ redoscr();
+ return;
+ }
+ rel_move(tc_col, tc_line, 0, 0);
+ do {
+ o_scrollrev();
+ } while(++scrollcnt);
+ } else if (scrollcnt > 0) {
+ rel_move(tc_col, tc_line, 0, b_lines);
+ do {
+ ochar('\n');
+ } while(--scrollcnt);
+ }
+
+ for(i = 0, j = roll; i < scr_lns; i++, j++) {
+ if(j >= scr_lns)
+ j = 0;
+ bp = &big_picture[j];
+ len = bp->len;
+ if(bp->mode & MODIFIED && bp->smod < len) {
+ bp->mode &= ~(MODIFIED);
+ if(bp->emod >= len)
+ bp->emod = len - 1;
+ rel_move(tc_col, tc_line, bp->smod, i);
+
+ if(bp->mode & STANDOUT)
+ standoutput(bp->data, bp->smod, bp->emod + 1,
+ bp->sso, bp->eso);
+ else
+ output(&bp->data[bp->smod], bp->emod - bp->smod + 1);
+ tc_col = bp->emod + 1;
+ if(tc_col >= t_columns) {
+ if(automargins) {
+ tc_col -= t_columns;
+ if(++tc_line >= t_lines)
+ tc_line = b_lines;
+ } else
+ tc_col = t_columns - 1;
+ }
+ }
+
+ if(bp->oldlen > len) {
+ rel_move(tc_col, tc_line, len, i);
+ o_cleol();
+ }
+ bp->oldlen = len;
+
+ }
+
+ rel_move(tc_col, tc_line, cur_col, cur_ln);
+
+ oflush();
+}
+
+void clear() {
+ register screenline_t *slp;
+
+ register int i;
+
+ docls = YEA;
+ cur_col = cur_ln = roll = downfrom = i = 0;
+ do {
+ slp = &big_picture[i];
+ slp->mode = slp->len = slp->oldlen = 0;
+ } while(++i < scr_lns);
+}
+
+void clrtoeol() {
+ register screenline_t *slp;
+ register int ln;
+
+ standing = NA;
+ if((ln = cur_ln + roll) >= scr_lns)
+ ln -= scr_lns;
+ slp = &big_picture[ln];
+ if(cur_col <= slp->sso)
+ slp->mode &= ~STANDOUT;
+
+ if(cur_col > slp->oldlen) {
+ for(ln = slp->len; ln <= cur_col; ln++)
+ slp->data[ln] = ' ';
+ }
+
+ if(cur_col < slp->oldlen) {
+ for(ln = slp->len; ln >= cur_col; ln--)
+ slp->data[ln] = ' ';
+ }
+
+ slp->len = cur_col;
+}
+
+void clrtoline(int line) {
+ register screenline_t *slp;
+ register int i, j;
+
+ for(i = cur_ln, j = i + roll; i < line; i++, j++) {
+ if(j >= scr_lns)
+ j -= scr_lns;
+ slp = &big_picture[j];
+ slp->mode = slp->len = 0;
+ if(slp->oldlen)
+ slp->oldlen = 255;
+ }
+}
+
+void clrtobot() {
+ clrtoline(scr_lns);
+}
+
+void outch(unsigned char c) {
+ register screenline_t *slp;
+ register int i;
+
+ if((i = cur_ln + roll) >= scr_lns)
+ i -= scr_lns;
+ slp = &big_picture[i];
+
+ if(c == '\n' || c == '\r') {
+ if(standing) {
+ slp->eso = MAX(slp->eso, cur_col);
+ standing = NA;
+ }
+ if((i = cur_col - slp->len) > 0)
+ memset(&slp->data[slp->len], ' ', i + 1);
+ slp->len = cur_col;
+ cur_col = 0;
+ if(cur_ln < scr_lns)
+ cur_ln++;
+ return;
+ }
+/*
+ else if(c != '\033' && !isprint2(c))
+ {
+ c = '*'; //substitute a '*' for non-printable
+ }
+*/
+ if(cur_col >= slp->len) {
+ for(i = slp->len; i < cur_col; i++)
+ slp->data[i] = ' ';
+ slp->data[cur_col] = '\0';
+ slp->len = cur_col + 1;
+ }
+
+ if(slp->data[cur_col] != c) {
+ slp->data[cur_col] = c;
+ if((slp->mode & MODIFIED) != MODIFIED)
+ slp->smod = slp->emod = cur_col;
+ slp->mode |= MODIFIED;
+ if(cur_col > slp->emod)
+ slp->emod = cur_col;
+ if(cur_col < slp->smod)
+ slp->smod = cur_col;
+ }
+
+ if (++cur_col >= scr_cols)
+ {
+ if (standing && (slp->mode & STANDOUT))
+ {
+ standing = 0;
+ slp->eso = MAX(slp->eso, cur_col);
+ }
+ cur_col = 0;
+ if (cur_ln < scr_lns)
+ cur_ln++;
+ }
+
+}
+
+static void parsecolor(char *buf) {
+ char *val;
+ char data[24];
+
+ data[0] = '\0';
+ val = (char *)strtok(buf, ";");
+
+ while(val) {
+ if(atoi(val) < 30) {
+ if(data[0])
+ strcat(data, ";");
+ strcat(data, val);
+ }
+ val = (char *) strtok(NULL, ";");
+ }
+ strcpy(buf, data);
+}
+
+#define NORMAL (00)
+#define ESCAPE (01)
+#define VTKEYS (02)
+
+void outc(unsigned char ch) {
+ if(showansi)
+ outch(ch);
+ else {
+ static char buf[24];
+ static int p = 0;
+ static int mode = NORMAL;
+ int i;
+
+ switch(mode) {
+ case NORMAL:
+ if(ch == '\033')
+ mode = ESCAPE;
+ else
+ outch(ch);
+ return;
+ case ESCAPE:
+ if(ch == '[')
+ mode = VTKEYS;
+ else {
+ mode = NORMAL;
+ outch('');
+ outch(ch);
+ }
+ return;
+ case VTKEYS:
+ if(ch == 'm') {
+ buf[p++] = '\0';
+ parsecolor(buf);
+ } else if((p < 24) && (not_alpha(ch))) {
+ buf[p++] = ch;
+ return;
+ }
+ if(buf[0]) {
+ outch('');
+ outch('[');
+
+ for(i = 0; (p = buf[i]); i++)
+ outch(p);
+ outch(ch);
+ }
+ p = 0;
+ mode = NORMAL;
+ }
+ }
+}
+
+static void do_outs(char *str) {
+ while(*str)
+ {
+ outc(*str++);
+ }
+}
+#ifdef SUPPORT_GB
+static void gb_init()
+{
+ if(current_font_type == TYPE_GB)
+ {
+ hc_readtab(BBSHOME"/etc/hc.tab");
+ }
+ gbinited = 1;
+}
+
+static void gb_outs(char *str)
+{
+ do_outs(hc_convert_str(str, HC_BIGtoGB, HC_DO_SINGLE));
+}
+#endif
+int edit_outs(char *text) {
+ register int column = 0;
+ register char ch;
+#ifdef SUPPORT_GB
+ if(current_font_type == TYPE_GB)
+ text = hc_convert_str(text, HC_BIGtoGB, HC_DO_SINGLE);
+#endif
+ while((ch = *text++) && (++column < SCR_WIDTH))
+ outch(ch == 27 ? '*' : ch);
+
+ return 0;
+}
+
+void outs(char *str) {
+#ifdef SUPPORT_GB
+ if(current_font_type == TYPE_BIG5)
+#endif
+ do_outs(str);
+#ifdef SUPPORT_GB
+ else
+ {
+ if(!gbinited) gb_init();
+ gb_outs(str);
+ }
+#endif
+}
+
+
+/* Jaky */
+void Jaky_outs(char *str, int line) {
+#ifdef SUPPORT_GB
+ if(current_font_type == TYPE_GB)
+ str = hc_convert_str(str, HC_BIGtoGB, HC_DO_SINGLE);
+#endif
+ while(*str && line) {
+ outc(*str);
+ if(*str=='\n')
+ line--;
+ str++;
+ }
+}
+
+void outmsg(char *msg) {
+ move(b_lines, 0);
+ clrtoeol();
+#ifdef SUPPORT_GB
+ if(current_font_type == TYPE_GB)
+ msg = hc_convert_str(msg, HC_BIGtoGB, HC_DO_SINGLE);
+#endif
+ while(*msg)
+ outc(*msg++);
+}
+
+void prints(char *fmt, ...) {
+ va_list args;
+ char buff[1024];
+
+ va_start(args, fmt);
+ vsprintf(buff, fmt, args);
+ va_end(args);
+ outs(buff);
+}
+
+void mprints(int y, int x, char *str) {
+ move(y, x);
+ clrtoeol();
+ prints(str);
+}
+
+void scroll() {
+ scrollcnt++;
+ if(++roll >= scr_lns)
+ roll = 0;
+ move(b_lines, 0);
+ clrtoeol();
+}
+
+void rscroll() {
+ scrollcnt--;
+ if(--roll < 0)
+ roll = b_lines;
+ move(0, 0);
+ clrtoeol();
+}
+
+void region_scroll_up(int top, int bottom) {
+ int i;
+
+ if(top > bottom) {
+ i = top;
+ top = bottom;
+ bottom = i;
+ }
+
+ if(top < 0 || bottom >= scr_lns)
+ return;
+
+ for(i = top; i < bottom; i++)
+ big_picture[i] = big_picture[i + 1];
+ memset(big_picture + i, 0, sizeof(*big_picture));
+ memset(big_picture[i].data, ' ', scr_cols);
+ save_cursor();
+ change_scroll_range(top, bottom);
+ do_move(0, bottom);
+ scroll_forward();
+ change_scroll_range(0, scr_lns - 1);
+ restore_cursor();
+ refresh();
+}
+
+void standout() {
+ if(!standing && strtstandoutlen) {
+ register screenline_t *slp;
+
+ slp = &big_picture[((cur_ln + roll) % scr_lns)];
+ standing = YEA;
+ slp->sso = slp->eso = cur_col;
+ slp->mode |= STANDOUT;
+ }
+}
+
+void standend() {
+ if(standing && strtstandoutlen) {
+ register screenline_t *slp;
+
+ slp = &big_picture[((cur_ln + roll) % scr_lns)];
+ standing = NA;
+ slp->eso = MAX(slp->eso, cur_col);
+ }
+}
diff --git a/mbbsd/stuff.c b/mbbsd/stuff.c
new file mode 100644
index 00000000..9218b7f0
--- /dev/null
+++ b/mbbsd/stuff.c
@@ -0,0 +1,524 @@
+/* $Id: stuff.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "modes.h"
+#include "common.h"
+#include "perm.h"
+#include "proto.h"
+
+extern int currmode;
+extern char *fn_mandex;
+extern char *str_reply;
+extern char *str_space;
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+extern userec_t cuser;
+
+/* ----------------------------------------------------- */
+/* set file path for boards/user home */
+/* ----------------------------------------------------- */
+static char *str_home_file = "home/%c/%s/%s";
+static char *str_board_file = "boards/%s/%s";
+
+#define STR_DOTDIR ".DIR"
+static char *str_dotdir = STR_DOTDIR;
+
+void setcalfile(char *buf, char *userid) {
+ sprintf(buf, "home/%c/%s/calendar", userid[0], userid);
+}
+
+void sethomepath(char *buf, char *userid) {
+ sprintf(buf, "home/%c/%s", userid[0], userid);
+}
+
+void sethomedir(char *buf, char *userid) {
+ sprintf(buf, str_home_file, userid[0], userid, str_dotdir);
+}
+
+void sethomeman(char *buf, char *userid) {
+ sprintf(buf, str_home_file, userid[0], userid, "man");
+}
+
+void sethomefile(char *buf, char *userid, char *fname) {
+ sprintf(buf, str_home_file, userid[0], userid, fname);
+}
+
+void setuserfile(char *buf, char *fname) {
+ sprintf(buf, str_home_file, cuser.userid[0], cuser.userid, fname);
+}
+
+void setapath(char *buf, char *boardname) {
+ sprintf(buf, "man/boards/%s", boardname);
+}
+
+void setadir(char *buf, char *path) {
+ sprintf(buf, "%s/%s", path, str_dotdir);
+}
+
+void setbpath(char *buf, char *boardname) {
+ sprintf(buf, "boards/%s", boardname);
+}
+
+void setbdir(char *buf, char *boardname) {
+ sprintf(buf, str_board_file, boardname,
+ currmode & MODE_ETC ? ".ETC" :
+ (currmode & MODE_DIGEST ? fn_mandex : str_dotdir));
+}
+
+void setbfile(char *buf, char *boardname, char *fname) {
+ sprintf(buf, str_board_file, boardname, fname);
+}
+
+void setdirpath(char *buf, char *direct, char *fname) {
+ strcpy(buf, direct);
+ direct = strrchr(buf, '/');
+ strcpy(direct + 1, fname);
+}
+
+char *subject(char *title) {
+ if(!strncasecmp(title, str_reply, 3)) {
+ title += 3;
+ if(*title == ' ')
+ title++;
+ }
+ return title;
+}
+
+/* ----------------------------------------------------- */
+/* ¦r¦êÂà´«Àˬd¨ç¼Æ */
+/* ----------------------------------------------------- */
+int str_checksum(char *str) {
+ int n = 1;
+ if(strlen(str) < 6)
+ return 0;
+ while(*str)
+ n += *(str++) * (n);
+ return n;
+}
+
+void str_lower(char *t, char *s) {
+ register unsigned char ch;
+
+ do {
+ ch = *s++;
+ *t++ = char_lower(ch);
+ } while(ch);
+}
+
+int strstr_lower(char *str, char *tag) {
+ char buf[STRLEN];
+
+ str_lower(buf, str);
+ return (int)strstr(buf, tag);
+}
+
+void trim(char *buf) { /* remove trailing space */
+ char *p = buf;
+
+ while(*p)
+ p++;
+ while(--p >= buf) {
+ if(*p == ' ')
+ *p = '\0';
+ else
+ break;
+ }
+}
+
+/* ----------------------------------------------------- */
+/* ¦r¦êÀˬd¨ç¼Æ¡G­^¤å¡B¼Æ¦r¡BÀɦW¡BE-mail address */
+/* ----------------------------------------------------- */
+int isprint2(char ch) {
+ return ((ch & 0x80) ? 1 : isprint(ch));
+ //return 1;
+}
+
+int not_alpha(char ch) {
+ return (ch < 'A' || (ch > 'Z' && ch < 'a') || ch > 'z');
+}
+
+int not_alnum(char ch) {
+ return (ch < '0' || (ch > '9' && ch < 'A') ||
+ (ch > 'Z' && ch < 'a') || ch > 'z');
+}
+
+int invalid_pname(char *str) {
+ char *p1, *p2, *p3;
+
+ p1 = str;
+ while(*p1) {
+ if(!(p2 = strchr(p1, '/')))
+ p2 = str + strlen(str);
+ if(p1 + 1 > p2 || p1 + strspn(p1, ".") == p2)
+ return 1;
+ for(p3 = p1; p3 < p2; p3++)
+ if(not_alnum(*p3) && !strchr("@[]-._", *p3))
+ return 1;
+ p1 = p2 + (*p2 ? 1 : 0);
+ }
+ return 0;
+}
+
+int valid_ident(char *ident) {
+ static char *invalid[] = {"unknown@", "root@", "gopher@", "bbs@",
+ "@bbs", "guest@", "@ppp", "@slip", NULL};
+ char buf[128];
+ int i;
+
+ str_lower(buf, ident);
+ for(i = 0; invalid[i]; i++)
+ if(strstr(buf, invalid[i]))
+ return 0;
+ return 1;
+}
+
+int is_uBM(char *list, char *id) {
+ register int len;
+
+ if(list[0] == '[')
+ list++;
+ if(list[0] > ' ') {
+ len = strlen(id);
+ do {
+ if(!strncasecmp(list, id, len)) {
+ list += len;
+ if((*list == 0) || (*list == '/') ||
+ (*list == ']') || (*list == ' '))
+ return 1;
+ }
+ if((list = strchr(list,'/')) != NULL)
+ list++;
+ else
+ break;
+ } while(1);
+ }
+ return 0;
+}
+
+int is_BM(char *list) {
+ if(is_uBM(list,cuser.userid)) {
+ cuser.userlevel |= PERM_BM; /* Ptt ¦Û°Ê¥[¤WBMªºÅv§Q */
+ return 1;
+ }
+ return 0;
+}
+
+int userid_is_BM(char *userid, char *list) {
+ register int ch, len;
+
+ ch = list[0];
+ if((ch > ' ') && (ch < 128)) {
+ len = strlen(userid);
+ do {
+ if(!strncasecmp(list, userid, len)) {
+ ch = list[len];
+ if((ch == 0) || (ch == '/') || (ch == ']'))
+ return 1;
+ }
+ while((ch = *list++)) {
+ if(ch == '/')
+ break;
+ }
+ } while(ch);
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------- */
+/* ÀÉ®×Àˬd¨ç¼Æ¡GÀɮסB¥Ø¿ý¡BÄÝ©ó */
+/* ----------------------------------------------------- */
+off_t dashs(char *fname) {
+ struct stat st;
+
+ if(!stat(fname, &st))
+ return st.st_size;
+ else
+ return -1;
+}
+
+long dasht(char *fname) {
+ struct stat st;
+
+ if(!stat(fname, &st))
+ return st.st_mtime;
+ else
+ return -1;
+}
+
+int dashl(char *fname) {
+ struct stat st;
+
+ return (lstat(fname, &st) == 0 && S_ISLNK(st.st_mode));
+}
+
+int dashf(char *fname) {
+ struct stat st;
+
+ return (stat(fname, &st) == 0 && S_ISREG(st.st_mode));
+}
+
+int dashd(char *fname) {
+ struct stat st;
+
+ return (stat(fname, &st) == 0 && S_ISDIR(st.st_mode));
+}
+
+int belong(char *filelist, char *key) {
+ FILE *fp;
+ int rc = 0;
+
+ if((fp = fopen(filelist, "r"))) {
+ char buf[STRLEN], *ptr;
+
+ while(fgets(buf, STRLEN, fp)) {
+ if((ptr = strtok(buf, str_space)) && !strcasecmp(ptr, key)) {
+ rc = 1;
+ break;
+ }
+ }
+ fclose(fp);
+ }
+ return rc;
+}
+
+char *Cdate(time_t *clock) {
+ static char foo[32];
+ struct tm *mytm = localtime(clock);
+
+ strftime(foo, 32, "%m/%d/%Y %T %a", mytm);
+ return foo;
+}
+
+char *Cdatelite(time_t *clock) {
+ static char foo[32];
+ struct tm *mytm = localtime(clock);
+
+ strftime(foo, 32, "%m/%d/%Y %T", mytm);
+ return foo;
+}
+
+char *Cdatedate(time_t *clock){
+ static char foo[32];
+ struct tm *mytm = localtime(clock);
+
+ strftime(foo, 32, "%m/%d/%Y", mytm);
+ return foo;
+}
+
+static void capture_screen() {
+ char fname[200];
+ FILE* fp;
+ extern screenline_t *big_picture;
+ extern unsigned char scr_lns;
+ int i;
+
+ getdata(b_lines - 2, 0, "§â³o­Óµe­±¦¬¤J¨ì¼È¦sÀÉ¡H[y/N] ",
+ fname, 4, LCECHO);
+ if(fname[0] != 'y' ) return;
+
+ setuserfile(fname, ask_tmpbuf(b_lines - 1));
+ if((fp = fopen(fname, "w"))) {
+ for(i = 0; i < scr_lns; i++)
+ fprintf(fp, "%.*s\n", big_picture[i].len, big_picture[i].data);
+ fclose(fp);
+ }
+}
+
+void pressanykey() {
+ int ch;
+
+ outmsg("\033[37;45;1m "
+ "¡´ ½Ð«ö \033[33m(Space/Return)\033[37m Ä~Äò ¡´"
+ " \033[33m(^T)\033[37m ¦s¼È¦sÀÉ \033[m");
+ do {
+ ch = igetkey();
+
+ if(ch == Ctrl('T')) {
+ capture_screen();
+ break;
+ }
+ } while((ch != ' ') && (ch != KEY_LEFT) && (ch != '\r') && (ch != '\n'));
+ move(b_lines, 0);
+ clrtoeol();
+ refresh();
+}
+
+int vmsg (const char *fmt, ...)
+{
+ va_list ap;
+ char msg[80] = {0};
+ int ch;
+
+ va_start (ap, fmt);
+ vsprintf (msg, fmt, ap);
+ va_end (ap);
+
+ move (b_lines, 0);
+ clrtoeol ();
+
+ if (*msg)
+ prints ("\033[1;36;44m ¡» %-55.54s \033[33;46m \033[200m\033[1431m\033[506m[½Ð«ö¥ô·NÁäÄ~Äò]\033[201m \033[m", msg);
+ else
+ outs ("\033[46;1m \033[37m"
+ "\033[200m\033[1431m\033[506m¡¼ ½Ð«ö \033[33m(Space/Return)\033[37m Ä~Äò ¡¼\033[201m"
+ " \033[m");
+
+ do {
+ ch = igetkey();
+
+ if(ch == Ctrl('T')) {
+ capture_screen();
+ break;
+ }
+ } while((ch != ' ') && (ch != KEY_LEFT) && (ch != '\r') && (ch != '\n'));
+
+
+ move (b_lines, 0);
+ clrtoeol ();
+ refresh ();
+ return ch;
+}
+
+void bell() {
+ char c;
+
+ c = Ctrl('G');
+ write(1, &c, 1);
+}
+
+int search_num(int ch, int max) {
+ int clen = 1;
+ int x, y;
+ extern unsigned char scr_cols;
+ char genbuf[10];
+
+ outmsg("\033[7m ¸õ¦Ü²Ä´X¶µ¡G\033[m");
+ outc(ch);
+ genbuf[0] = ch;
+ getyx(&y, &x);
+ x--;
+ while((ch = igetch()) != '\r') {
+ if(ch == 'q' || ch == 'e')
+ return -1;
+ if(ch == '\n')
+ break;
+ if(ch == '\177' || ch == Ctrl('H')) {
+ if(clen == 0) {
+ bell();
+ continue;
+ }
+ clen--;
+ move(y, x + clen);
+ outc(' ');
+ move(y, x + clen);
+ continue;
+ }
+ if(!isdigit(ch)) {
+ bell();
+ continue;
+ }
+ if(x + clen >= scr_cols || clen >= 6) {
+ bell();
+ continue;
+ }
+ genbuf[clen++] = ch;
+ outc(ch);
+ }
+ genbuf[clen] = '\0';
+ move(b_lines, 0);
+ clrtoeol();
+ if(genbuf[0] == '\0')
+ return -1;
+ clen = atoi(genbuf);
+ if(clen == 0)
+ return 0;
+ if(clen > max)
+ return max;
+ return clen - 1;
+}
+
+void stand_title(char *title) {
+ clear();
+ prints("\033[1;37;46m¡i %s ¡j\033[m\n", title);
+}
+
+void cursor_show(int row, int column) {
+ move(row, column);
+ outs(STR_CURSOR);
+ move(row, column + 1);
+}
+
+void cursor_clear(int row, int column) {
+ move(row, column);
+ outs(STR_UNCUR);
+}
+
+int cursor_key(int row, int column) {
+ int ch;
+
+ cursor_show(row, column);
+ ch = egetch();
+ move(row, column);
+ outs(STR_UNCUR);
+ return ch;
+}
+
+void printdash(char *mesg) {
+ int head = 0, tail;
+
+ if(mesg)
+ head = (strlen(mesg) + 1) >> 1;
+
+ tail = head;
+
+ while(head++ < 38)
+ outch('-');
+
+ if(tail) {
+ outch(' ');
+ outs(mesg);
+ outch(' ');
+ }
+
+ while(tail++ < 38)
+ outch('-');
+ outch('\n');
+}
+
+int log_file(char *filename,char *buf) {
+ FILE *fp;
+
+ if((fp = fopen(filename, "a" )) != NULL ) {
+ fputs( buf, fp );
+ if(!strchr(buf,'\n'))
+ fputc('\n',fp);
+ fclose( fp );
+ return 0;
+ }
+ else
+ return -1;
+}
+
+void show_help(char *helptext[]) {
+ char *str;
+ int i;
+
+ clear();
+ for(i = 0; (str = helptext[i]); i++) {
+ if(*str == '\0')
+ prints("\033[1m¡i %s ¡j\033[0m\n", str + 1);
+ else if(*str == '\01')
+ prints("\n\033[36m¡i %s ¡j\033[m\n", str + 1);
+ else
+ prints(" %s\n", str);
+ }
+ pressanykey();
+}
diff --git a/mbbsd/syspost.c b/mbbsd/syspost.c
new file mode 100644
index 00000000..b7aefe10
--- /dev/null
+++ b/mbbsd/syspost.c
@@ -0,0 +1,102 @@
+/* $Id: syspost.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "perm.h"
+#include "common.h"
+#include "proto.h"
+
+extern char *str_permid[];
+extern userec_t cuser;
+
+void post_change_perm(int oldperm, int newperm, char *sysopid, char *userid) {
+ FILE *fp;
+ fileheader_t fhdr;
+ time_t now = time(0);
+ char genbuf[200], reason[30];
+ int i, flag=0;
+
+ strcpy(genbuf, "boards/Security");
+ stampfile(genbuf, &fhdr);
+ if(!(fp = fopen(genbuf,"w")))
+ return;
+
+ fprintf(fp, "§@ªÌ: [¨t²Î¦w¥þ§½] ¬ÝªO: Security\n"
+ "¼ÐÃD: [¤½¦w³ø§i] ¯¸ªø­×§ïÅv­­³ø§i\n"
+ "®É¶¡: %s\n", ctime(&now));
+ for(i = 5; i < NUMPERMS; i++) {
+ if(((oldperm >> i) & 1) != ((newperm >> i) & 1)) {
+ fprintf (fp, " ¯¸ªø\033[1;32m%s%s%s%s\033[mªºÅv­­\n",
+ sysopid,
+ (((oldperm >> i) & 1) ? "\033[1;33mÃö³¬":"\033[1;33m¶}±Ò"),
+ userid, str_permid[i]);
+ flag++;
+ }
+ }
+
+ if(flag) {
+ clrtobot();
+ clear();
+ while(!getdata_str(5, 0, "½Ð¿é¤J²z¥Ñ¥H¥Ü­t³d¡G",
+ reason, 60, DOECHO, "¬Ýª©ª©¥D:"));
+ fprintf(fp, "\n \033[1;37m¯¸ªø%s­×§ïÅv­­²z¥Ñ¬O¡G%s\033[m",
+ cuser.userid, reason);
+ fclose(fp);
+
+ sprintf(fhdr.title, "[¤½¦w³ø§i] ¯¸ªø%s­×§ï%sÅv­­³ø§i",
+ cuser.userid, userid);
+ strcpy(fhdr.owner, "[¨t²Î¦w¥þ§½]");
+ append_record("boards/Security/.DIR", &fhdr, sizeof(fhdr));
+ }
+}
+
+void post_violatelaw(char* crime, char* police, char* reason, char* result){
+ char genbuf[200];
+ fileheader_t fhdr;
+ time_t now;
+ FILE *fp;
+ strcpy(genbuf, "boards/Security");
+ stampfile(genbuf, &fhdr);
+ if(!(fp = fopen(genbuf,"w")))
+ return;
+ now = time(NULL);
+ fprintf(fp, "§@ªÌ: [Pttªk°|] ¬ÝªO: Security\n"
+ "¼ÐÃD: [³ø§i] %-20s ¹Hªk§P¨M³ø§i\n"
+ "®É¶¡: %s\n"
+ "\033[1;32m%s\033[m§P¨M¡G\n \033[1;32m%s\033[m"
+ "¦]\033[1;35m%s\033[m¦æ¬°¡A\n¹H¤Ï¥»¯¸¯¸³W¡A³B¥H\033[1;35m%s\033[m¡A¯S¦¹¤½§i",
+ crime, ctime(&now), police, crime, reason, result);
+ fclose(fp);
+ sprintf(fhdr.title, "[³ø§i] %-20s ¹Hªk§P¨M³ø§i", crime);
+ strcpy(fhdr.owner, "[Pttªk°|]");
+ append_record("boards/Security/.DIR", &fhdr, sizeof(fhdr));
+
+ strcpy(genbuf, "boards/ViolateLaw");
+ stampfile(genbuf, &fhdr);
+ if(!(fp = fopen(genbuf,"w")))
+ return;
+ now = time(NULL);
+ fprintf(fp, "§@ªÌ: [Pttªk°|] ¬ÝªO: ViolateLaw\n"
+ "¼ÐÃD: [³ø§i] %-20s ¹Hªk§P¨M³ø§i\n"
+ "®É¶¡: %s\n"
+ "\033[1;32m%s\033[m§P¨M¡G\n \033[1;32m%s\033[m"
+ "¦]\033[1;35m%s\033[m¦æ¬°¡A\n¹H¤Ï¥»¯¸¯¸³W¡A³B¥H\033[1;35m%s\033[m¡A¯S¦¹¤½§i",
+ crime, ctime(&now), police, crime, reason, result);
+ fclose(fp);
+ sprintf(fhdr.title, "[³ø§i] %-20s ¹Hªk§P¨M³ø§i", crime);
+ strcpy(fhdr.owner, "[Pttªk°|]");
+
+ append_record("boards/ViolateLaw/.DIR", &fhdr, sizeof(fhdr));
+
+}
+
+void post_newboard(char* bgroup, char* bname, char* bms){
+ char genbuf[256], title[128];
+ sprintf(title, "[·sª©¦¨¥ß] %s", bname);
+ sprintf(genbuf, "%s ¶}¤F¤@­Ó·sª© %s : %s\n\n·s¥ôª©¥D¬° %s\n\n®¥³ß*^_^*\n",
+ cuser.userid, bname, bgroup, bms);
+ post_msg("Record", title, genbuf, "[¨t²Î]");
+}
diff --git a/mbbsd/talk.c b/mbbsd/talk.c
new file mode 100644
index 00000000..3012b2d2
--- /dev/null
+++ b/mbbsd/talk.c
@@ -0,0 +1,2663 @@
+/* $Id: talk.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <netdb.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "perm.h"
+#include "modes.h"
+#include "proto.h"
+
+#define QCAST int (*)(const void *, const void *)
+
+extern userinfo_t *currutmp;
+extern char *ModeTypeTable[MAX_MODES];
+extern char *fn_overrides;
+extern int usernum;
+extern char *msg_sure_ny;
+extern char *msg_cancel;
+extern unsigned int currstat;
+extern char *fn_writelog;
+extern FILE *fp_writelog;
+extern pid_t currpid;
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+extern int t_lines, t_columns; /* Screen size / width */
+extern char *fn_talklog;
+extern char currauthor[IDLEN + 2];
+extern char *msg_usr_left;
+extern char *msg_uid;
+extern char *BBSName;
+extern int p_lines; /* a Page of Screen line numbers: tlines-4 */
+extern char fromhost[];
+extern char *err_uid;
+extern int talkrequest;
+extern char *msg_shortulist;
+extern char *msg_nobody;
+extern boardheader_t *bcache;
+extern int curr_idle_timeout;
+extern userec_t cuser;
+extern userec_t xuser;
+
+
+static char *IdleTypeTable[] = {
+ "°¸¦bªá§b°Õ", "±¡¤H¨Ó¹q", "³V­¹¤¤", "«ô¨£©P¤½", "°²¦ºª¬ºA", "§Ú¦b«ä¦Ò"
+};
+static char *sig_des[] = {
+ "°«Âû", "²á¤Ñ", "", "¤U´Ñ", "¶H´Ñ", "·t´Ñ"
+};
+
+#define MAX_SHOW_MODE 3
+#define M_INT 15 /* monitor mode update interval */
+#define P_INT 20 /* interval to check for page req. in
+ * talk/chat */
+#define BOARDFRI 1
+
+typedef struct talkwin_t {
+ int curcol, curln;
+ int sline, eline;
+} talkwin_t;
+
+typedef struct pickup_t {
+ userinfo_t *ui;
+ time_t idle;
+ int friend;
+} pickup_t;
+
+extern int bind( /* int,struct sockaddr *, int */ );
+extern char *getuserid();
+extern struct utmpfile_t *utmpshm;
+extern int watermode;
+extern water_t water[6], *swater[5], *water_which;
+extern char *friend_file[8], water_usies;
+
+/* °O¿ý friend ªº user number */
+//#define PICKUP_WAYS 7 //Ãö±¼¤k¤hÀu¥ý
+#define PICKUP_WAYS 6
+
+static int pickup_way = 0;
+static char *fcolor[11] = {
+ "", "\033[36m", "\033[32m", "\033[1;32m",
+ "\033[33m", "\033[1;33m", "\033[1;37m", "\033[1;37m",
+ "\033[31m", "\033[1;35m", "\033[1;36m"
+};
+static char save_page_requestor[40];
+static char page_requestor[40];
+static char description[30];
+static FILE *flog;
+
+
+char *modestring(userinfo_t * uentp, int simple) {
+ static char modestr[40];
+ static char *notonline = "¤£¦b¯¸¤W";
+ register int mode = uentp->mode;
+ register char *word;
+ int fri_stat;
+
+/* for debugging */
+ if (mode >= MAX_MODES)
+ {
+ syslog(LOG_WARNING, "what!? mode = %d", mode);
+ word = ModeTypeTable[mode % MAX_MODES];
+ }
+ else
+ word = ModeTypeTable[mode];
+ fri_stat = friend_stat(currutmp, uentp);
+ if (!(HAS_PERM(PERM_SYSOP) || HAS_PERM(PERM_SEECLOAK)) &&
+ (
+ (uentp->invisible || (fri_stat & HRM)) &&
+ !((fri_stat & HFM) && (fri_stat & HRM))
+ )
+ )
+ return notonline;
+ else if (mode == EDITING)
+ {
+ sprintf(modestr, "E:%s",
+ ModeTypeTable[uentp->destuid < EDITING ? uentp->destuid :
+ EDITING]);
+ word = modestr;
+ }
+ else if (!mode && *uentp->chatid == 1)
+ {
+ if (!simple)
+ sprintf(modestr, "¦^À³ %s", getuserid(uentp->destuid));
+ else
+ sprintf(modestr, "¦^À³©I¥s");
+ }
+ else if (!mode && *uentp->chatid == 2)
+ if (uentp->msgcount < 10)
+ {
+ char *cnum[10] =
+ {"", "¤@", "¨â", "¤T", "¥|", "¤­", "¤»", "¤C",
+ "¤K", "¤E"};
+ sprintf(modestr, "¤¤%sÁû¤ô²y", cnum[uentp->msgcount]);
+ }
+ else
+ sprintf(modestr, "¤£¦æ¤F @_@");
+ else if (!mode && *uentp->chatid == 3)
+ sprintf(modestr, "¤ô²y·Ç³Æ¤¤");
+ else if (!mode)
+ return (uentp->destuid == 6) ? uentp->chatid :
+ IdleTypeTable[(0 <= uentp->destuid && uentp->destuid < 6) ?
+ uentp->destuid : 0];
+ else if (simple)
+ return word;
+ else if (uentp->in_chat && mode == CHATING)
+ sprintf(modestr, "%s (%s)", word, uentp->chatid);
+ else if (mode == TALK)
+ {
+ if (!isvisible_uid(uentp->destuid))/* Leeym ¹ï¤è(µµ¦â)Áô§Î */
+ sprintf(modestr, "%s", "¥æ½Í ªÅ®ð");/* Leeym ¤j®a¦Û¤vµo´§§a¡I */
+ else
+ sprintf(modestr, "%s %s", word, getuserid(uentp->destuid));
+ }
+ else if (mode == M_FIVE)
+ {
+ if (!isvisible_uid(uentp->destuid))
+ sprintf(modestr, "%s", "¤­¤l´Ñ ªÅ®ð");
+ else
+ sprintf(modestr, "%s %s", word, getuserid(uentp->destuid));
+ }
+ else if (mode == CHC)
+ {
+ if (isvisible_uid(uentp->destuid))
+ sprintf(modestr, "%s", "¤U¶H´Ñ");
+ else
+ sprintf(modestr, "¤U¶H´Ñ %s", getuserid(uentp->destuid));
+ }
+ else if (mode != PAGE && mode != TQUERY)
+ return word;
+ else
+ sprintf(modestr, "%s %s", word, getuserid(uentp->destuid));
+
+ return (modestr);
+}
+
+int set_friend_bit(userinfo_t * me, userinfo_t * ui) {
+ int unum, *myfriends, hit=0, n;
+
+/* §PÂ_¹ï¤è¬O§_¬°§ÚªºªB¤Í ? */
+ unum = ui->uid;
+ myfriends = me->friend;
+ while ((n = *myfriends++))
+ {
+ if (unum == n)
+ {
+ hit = IFH;
+ break;
+ }
+ }
+
+/* §PÂ_§Ú¬O§_¬°¹ï¤èªºªB¤Í ? */
+ myfriends = ui->friend;
+ while ((unum = *myfriends++))
+ {
+ if (unum == me->uid)
+ {
+ hit |= HFM;
+ break;
+ }
+ }
+
+/* §PÂ_¹ï¤è¬O§_¬°§Úªº¤³¤H ? */
+
+ unum = ui->uid;
+ myfriends = me->reject;
+ while ((n = *myfriends++))
+ {
+ if (unum == n)
+ {
+ hit |= IRH;
+ break;
+ }
+ }
+
+/* §PÂ_§Ú¬O§_¬°¹ï¤èªº¤³¤H ? */
+ myfriends = ui->reject;
+ while ((unum = *myfriends++))
+ {
+ if (unum == me->uid)
+ {
+ hit |= HRM;
+ break;
+ }
+ }
+ return hit;
+}
+int reverse_friend_stat(int stat)
+{
+ int stat1=0;
+ if(stat & IFH)
+ stat1 |=HFM;
+ if(stat & IRH)
+ stat1 |=HRM;
+ if(stat & HFM)
+ stat1 |=IFH;
+ if(stat & HRM)
+ stat1 |=IRH;
+ if(stat & IBH)
+ stat1 |=IBH;
+ return stat1;
+}
+
+int login_friend_online(){
+ userinfo_t *uentp;
+ int i, stat, stat1;
+ int offset=(int) (currutmp - &utmpshm->uinfo[0]);
+ for (i=0;i<utmpshm->number && currutmp->friendtotal<MAX_FRIEND; i++)
+ {
+ uentp = (utmpshm->sorted[utmpshm->currsorted][0][i]);
+ if(uentp && uentp->uid && (stat=set_friend_bit(currutmp,uentp)))
+ {
+ stat1=reverse_friend_stat(stat);
+ stat <<= 24;
+ stat |= (int) (uentp - &utmpshm->uinfo[0]);
+ currutmp->friend_online[currutmp->friendtotal++]=stat;
+ if(uentp!=currutmp && uentp->friendtotal<MAX_FRIEND)
+ {
+ stat1 <<= 24;
+ stat1 |= offset;
+ uentp->friend_online[uentp->friendtotal++]=stat1;
+ }
+ }
+ }
+ return 0;
+}
+
+int logout_friend_online(){
+ int i, j, k;
+ int offset=(int) (currutmp - &utmpshm->uinfo[0]);
+ userinfo_t *ui;
+ while(currutmp->friendtotal)
+ {
+ i = currutmp->friendtotal-1;
+ j = (currutmp->friend_online[i] & 0xFFFFFF);
+ currutmp->friend_online[i]=0;
+ ui = &utmpshm->uinfo[j];
+ if(ui->pid && ui!=currutmp)
+ {
+ for(k=0; k<ui->friendtotal &&
+ (int)(ui->friend_online[k] & 0xFFFFFF) !=offset; k++);
+ if(k<ui->friendtotal)
+ {
+ ui->friendtotal--;
+ ui->friend_online[k]=ui->friend_online[ui->friendtotal];
+ ui->friend_online[ui->friendtotal]=0;
+ }
+ }
+ currutmp->friendtotal--;
+ currutmp->friend_online[currutmp->friendtotal]=0;
+ }
+ return 0;
+}
+
+
+int friend_stat(userinfo_t *me, userinfo_t * ui)
+{
+ int i, j, hit=0;
+/* ¬ÝªO¦n¤Í */
+ if (me->brc_id && ui->brc_id == me->brc_id)
+ {
+ hit = IBH;
+ }
+ for(i=0;me->friend_online[i];i++)
+ {
+ j = (me->friend_online[i] & 0xFFFFFF);
+ if(ui == &utmpshm->uinfo[j])
+ {
+ hit |= me->friend_online[i] >>24;
+ break;
+ }
+ }
+ if (PERM_HIDE(ui))
+ return hit & ST_FRIEND;
+ return hit;
+}
+
+int isvisible_stat(userinfo_t * me, userinfo_t * uentp, int fri_stat) {
+ if (uentp->userid[0] == 0)
+ return 0;
+
+ if (PERM_HIDE(uentp) && !(PERM_HIDE(me)))/* ¹ï¤èµµ¦âÁô§Î¦Ó§A¨S¦³ */
+ return 0;
+ else if ((me->userlevel & PERM_SYSOP) ||
+ ((fri_stat & HRM) && (fri_stat & HFM))) /* ¯¸ªø¬Ýªº¨£¥ô¦ó¤H */
+ return 1;
+
+ if (uentp->invisible && !(me->userlevel & PERM_SEECLOAK)) return 0;
+
+ return (fri_stat & HRM) ? 0 : 1;
+}
+
+int isvisible(userinfo_t * me, userinfo_t * uentp) {
+ return isvisible_stat(currutmp, uentp, friend_stat(me, uentp));
+}
+
+int isvisible_uid(int tuid){
+ userinfo_t *uentp;
+
+ if(!tuid || !(uentp = search_ulist(tuid)))
+ return 1;
+ return isvisible(currutmp, uentp);
+}
+
+/* ¯u¹ê°Ê§@ */
+static void my_kick(userinfo_t * uentp) {
+ char genbuf[200];
+
+ getdata(1, 0, msg_sure_ny, genbuf, 4, LCECHO);
+ clrtoeol();
+ if (genbuf[0] == 'y')
+ {
+ sprintf(genbuf, "%s (%s)", uentp->userid, uentp->username);
+ log_usies("KICK ", genbuf);
+ if((uentp->pid <= 0 || kill(uentp->pid, SIGHUP) == -1) && (errno == ESRCH))
+ purge_utmp(uentp);
+ outs("½ð¥X¥hÅo");
+ }
+ else
+ outs(msg_cancel);
+ pressanykey();
+}
+
+static void chicken_query(char *userid) {
+ char buf[100];
+
+ if (getuser(userid))
+ {
+ if (xuser.mychicken.name[0])
+ {
+ time_diff(&(xuser.mychicken));
+ if (!isdeadth(&(xuser.mychicken)))
+ {
+ show_chicken_data(&(xuser.mychicken), NULL);
+ sprintf(buf, "\n\n¥H¤W¬O %s ªºÃdª«¸ê®Æ..", userid);
+ outs(buf);
+ }
+ }
+ else
+ {
+ move(1, 0);
+ clrtobot();
+ sprintf(buf, "\n\n%s ¨Ã¨S¦³¾iÃdª«..", userid);
+ outs(buf);
+ }
+ pressanykey();
+ }
+}
+
+int my_query(char *uident) {
+ userec_t muser;
+ int tuid, i, fri_stat=0;
+ unsigned long int j;
+ userinfo_t *uentp;
+ static const char *money[10] =
+ {"¶Å¥x°ª¿v", "¨ª³h", "²M´H", "´¶³q", "¤p±d",
+ "¤p´I", "¤¤´I", "¤j´I¯Î", "´I¥i¼Ä°ê", "¤ñº¸»\\¤Ñ"},
+ *sex[8] =
+ {MSG_BIG_BOY, MSG_BIG_GIRL,
+ MSG_LITTLE_BOY, MSG_LITTLE_GIRL,
+ MSG_MAN, MSG_WOMAN, MSG_PLANT, MSG_MIME};
+
+
+ if ((tuid = getuser(uident)))
+ {
+ memcpy(&muser, &xuser, sizeof(muser));
+ move(1, 0);
+ clrtobot();
+ move(1, 0);
+ setutmpmode(TQUERY);
+ currutmp->destuid = tuid;
+
+ j = muser.money;
+ for (i = 0; i < 10 && j > 10; i++)
+ j /= 10;
+ prints("¡m¢×¢Ò¼ÊºÙ¡n%s(%s)%*s¡m¸gÀÙª¬ªp¡n%s\n",
+ muser.userid,
+ muser.username,
+ 26 - strlen(muser.userid) - strlen(muser.username), "",
+ money[i]);
+ prints("¡m¤W¯¸¦¸¼Æ¡n%d¦¸", muser.numlogins);
+ move(2, 40);
+ prints("¡m¤å³¹½g¼Æ¡n%d½g\n", muser.numposts);
+
+ if((uentp = (userinfo_t *) search_ulist(tuid)))
+ fri_stat=friend_stat(currutmp, uentp);
+ prints("\033[1;33m¡m¥Ø«e°ÊºA¡n%-28.28s\033[m",
+ (uentp && isvisible_stat(currutmp, uentp, fri_stat)) ?
+ modestring(uentp, 0) : "¤£¦b¯¸¤W");
+
+ outs(((uentp && uentp->mailalert) || load_mailalert(muser.userid))
+ ? "¡m¨p¤H«H½c¡n¦³·s¶i«H¥óÁÙ¨S¬Ý\n" :
+ "¡m¨p¤H«H½c¡n©Ò¦³«H¥ó³£¬Ý¹L¤F\n");
+ prints("¡m¤W¦¸¤W¯¸¡n%-28.28s¡m¤W¦¸¬G¶m¡n%s\n",
+ Cdate(&muser.lastlogin),
+ (muser.lasthost[0] ? muser.lasthost : "(¤£¸Ô)"));
+ if ((uentp && fri_stat&HFM) || HAS_PERM(PERM_SYSOP))
+ prints("¡m ©Ê §O ¡n%-28.28s¡m¨p¦³°]²£¡n%ld »È¨â\n",
+ sex[muser.sex % 8],
+ muser.money);
+ prints("¡m¤­¤l´Ñ¾ÔÁZ¡n%3d ³Ó %3d ±Ñ %3d ©M "
+ "¡m¶H´Ñ¾ÔÁZ¡n%3d ³Ó %3d ±Ñ %3d ©M",
+ muser.five_win, muser.five_lose, muser.five_tie,
+ muser.chc_win, muser.chc_lose, muser.chc_tie);
+ showplans(uident);
+ pressanykey();
+ return FULLUPDATE;
+ }
+ return DONOTHING;
+}
+
+static char t_last_write[200] = "";
+
+void water_scr(water_t **currwater, int which, char type)
+{
+ if( type == 1 ){
+ int i;
+ int colors[] = {33, 37, 33, 37, 33};
+ move(8 + which, 28);prints(" ");
+ move(8 + which, 28);
+ prints("\033[1;37;45m %-14s \033[0m", currwater[which]->userid);
+ for( i = 0 ; i < 5 ; ++i ){
+ move(16 + i, 4);
+ prints(" ");
+ move(16 + i, 4);
+ if( currwater[which]->msg[ (currwater[which]->top-i+4) % 5 ].last_call_in[0] != 0 )
+ prints("\033[0m \033[1;%d;44m¡¹%-64s\033[0m \n",
+ colors[i],
+ currwater[which]->msg[ (currwater[which]->top-i+4) % 5 ].last_call_in);
+ else
+ prints("\033[0m¡@\n");
+ }
+ move(0, 0);prints(" ");
+ move(0, 0);
+ prints("\033[0m¤ÏÀ» %s:", currwater[which]->userid);
+ clrtoeol();
+ move(0, strlen(currwater[which]->userid) + 6);
+ }
+ else{
+ move(8 + which, 28);
+ prints("123456789012345678901234567890");
+ // refresh();
+ move(8 + which, 28);
+ prints("\033[1;37;44m %-13s¡@\033[0m", currwater[which]->userid);
+ // refresh();
+ }
+}
+
+void my_write2(void)
+{
+ int i, ch, currstat0, currwater_usies;
+ char genbuf[256], msg[80], done = 0, c0, which;
+ water_t *tw, *currwater[5];
+ unsigned char mode0;
+
+ watermode = 0;
+ currstat0 = currstat;
+ c0 = currutmp->chatid[0];
+ mode0 = currutmp->mode;
+ currutmp->mode = 0;
+ currutmp->chatid[0] = 3;
+ currstat = XMODE;
+
+ // init screen
+ memcpy(currwater, swater, sizeof(water_t*) * 5);
+ currwater_usies = water_usies;
+ move(7, 28);
+ prints("\033[1;33;46m ¡ô ¤ô²y¤ÏÀ»¹ï¶H ¡õ\033[0m");
+ for( i = 0 ; i < 5 ; ++i )
+ if( currwater[i] == NULL || currwater[i]->pid == 0 )
+ break;
+ else
+ water_scr(currwater, i, 0);
+ move(15, 4);
+ prints("\033[0m \033[1;35m¡º\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¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\033[1;35m¡º\033[0m ");
+ move(22, 4);
+ prints(" \033[1;35m¡º\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¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\033[1;35m¡º\033[0m ");
+ move(21, 4);prints(" ");
+ move(21, 4);
+ prints("\033[0m \033[1;37;46m%-66s\033[0m \n", t_last_write);
+ water_scr(currwater, 0, 1);
+ refresh();
+
+ which = 0;
+ do{
+ switch( (ch = igetkey()) ){
+ case Ctrl('T'):
+ case KEY_UP:
+ if( currwater_usies != 1 ){
+ water_scr(currwater, which, 0);
+ which = (which - 1 + currwater_usies) % currwater_usies;
+ water_scr(currwater, which, 1);
+ refresh();
+ }
+ break;
+
+ case KEY_DOWN:
+ case Ctrl('R'):
+ if( currwater_usies != 1 ){
+ water_scr(currwater, which, 0);
+ which = (which + 1 + currwater_usies) % currwater_usies;
+ water_scr(currwater, which, 1);
+ refresh();
+ }
+ break;
+
+ case KEY_LEFT:
+ done = 1;
+ break;
+
+ default:
+ done = 1;
+ watermode = 1;
+ tw = currwater[(int)which];
+
+ if( ch != '\r' && ch != '\n' ){
+ msg[0] = ch, msg[1] = 0;
+ }
+ else
+ msg[0] = 0;
+ move(0, 0);prints("\033[m"); clrtoeol();
+ refresh();
+ sprintf(genbuf, "§ðÀ» %s:", tw->userid);
+ if( !oldgetdata(0, 0, genbuf, msg,
+ 80-strlen(tw->userid)-6, DOECHO) )
+ break;
+
+ my_write(tw->pid, msg, tw->userid, 4);
+ break;
+ }
+ } while( !done );
+
+ watermode = -1;
+ currstat = currstat0;
+ currutmp->chatid[0] = c0;
+ currutmp->mode = mode0;
+}
+
+/*
+ ³Q©I¥sªº®É¾÷:
+ 1. ¥á¸s²Õ¤ô²y flag = 1 (pre-edit)
+ 2. ¦^¤ô²y flag = 0
+ 3. ¤W¯¸aloha flag = 2 (pre-edit)
+ 4. ¼s¼½ flag = 3 if SYSOP, otherwise flag = 1 (pre-edit)
+ 5. ¥á¤ô²y flag = 0
+ 6. my_write2 flag = 4 (pre-edit) but confirm
+*/
+int my_write(pid_t pid, char *prompt, char *id, int flag) {
+ int len, currstat0 = currstat, fri_stat;
+ char msg[80], destid[IDLEN + 1];
+ char genbuf[200], buf[200], c0 = currutmp->chatid[0];
+ unsigned char mode0 = currutmp->mode;
+ time_t now;
+ struct tm *ptime;
+ userinfo_t *uin;
+ uin = (userinfo_t *)search_ulist_pid(pid);
+ strcpy(destid, id);
+
+ if(!uin && !(flag == 0 && water_which->count> 0)) {
+ outmsg("\033[1;33;41mÁV¿|! ¹ï¤è¤w¸¨¶]¤F(¤£¦b¯¸¤W)! \033[37m~>_<~\033[m");
+ clrtoeol();
+ refresh();
+ watermode = -1;
+ return 0;
+ }
+ currutmp->mode = 0;
+ currutmp->chatid[0] = 3;
+ currstat = XMODE;
+
+ time(&now);
+ ptime = localtime(&now);
+
+ if(flag == 0) {
+ /* ¤@¯ë¤ô²y */
+ watermode = 0;
+ if(!(len = getdata(0, 0, prompt, msg, 56, DOECHO))) {
+ outmsg("\033[1;33;42mºâ¤F! ©ñ§A¤@°¨...\033[m");
+ clrtoeol();
+ refresh();
+ currutmp->chatid[0] = c0;
+ currutmp->mode = mode0;
+ currstat = currstat0;
+ watermode = -1;
+ return 0;
+ }
+
+ if(watermode > 0) {
+ int i;
+
+ i = (water_which->top- watermode + MAX_REVIEW) % MAX_REVIEW;
+ uin = (userinfo_t *)search_ulist_pid(water_which->msg[i].pid);
+ strcpy(destid, water_which->msg[i].userid);
+ }
+ } else {
+ /* pre-edit ªº¤ô²y */
+ strcpy(msg, prompt);
+ len = strlen(msg);
+ }
+
+ watermode = -1;
+ strip_ansi(msg, msg, 0);
+ if(uin && *uin->userid && (flag == 0 || flag == 4)) {
+ sprintf(buf, "¥áµ¹ %s : %s [Y/n]?", uin->userid, msg);
+ getdata(0, 0, buf, genbuf, 3, LCECHO);
+ if(genbuf[0] == 'n') {
+ outmsg("\033[1;33;42mºâ¤F! ©ñ§A¤@°¨...\033[m");
+ clrtoeol();
+ refresh();
+ currutmp->chatid[0] = c0;
+ currutmp->mode = mode0;
+ currstat = currstat0;
+ watermode = -1;
+ return 0;
+ }
+ }
+
+ if(!uin || !*uin->userid || strcasecmp(destid, uin->userid)) {
+ outmsg("\033[1;33;41mÁV¿|! ¹ï¤è¤w¸¨¶]¤F(¤£¦b¯¸¤W)! \033[37m~>_<~\033[m");
+ clrtoeol();
+ refresh();
+ currutmp->chatid[0] = c0;
+ currutmp->mode = mode0;
+ currstat = currstat0;
+ return 0;
+ }
+
+ fri_stat=friend_stat(currutmp, uin);
+ time(&now);
+ if(flag != 2) { /* aloha ªº¤ô²y¤£¥Î¦s¤U¨Ó */
+ /* ¦s¨ì¦Û¤vªº¤ô²yÀÉ */
+ if(!fp_writelog)
+ {
+ sethomefile(genbuf, cuser.userid, fn_writelog);
+ fp_writelog = fopen(genbuf, "a");
+ }
+ if(fp_writelog) {
+ fprintf(fp_writelog, "To %s: %s [%s]\n",
+ uin->userid, msg, Cdatelite(&now));
+ snprintf(t_last_write, 66, "To %s: %s", uin->userid, msg);
+ }
+ }
+
+ if(flag == 3 && uin->msgcount) {
+ /* ¤£À´ */
+ uin->destuip = currutmp - &utmpshm->uinfo[0];
+ uin->sig = 2;
+ if(uin->pid > 0) kill(uin->pid, SIGUSR1);
+ } else if(flag != 2 &&
+ !HAS_PERM(PERM_SYSOP) &&
+ (uin->pager == 3 ||
+ uin->pager == 2 ||
+ (uin->pager == 4 &&
+ !(fri_stat & HFM))))
+ outmsg("\033[1;33;41mÁV¿|! ¹ï¤è¨¾¤ô¤F! \033[37m~>_<~\033[m");
+ else {
+ if(uin->msgcount < MAX_MSGS) {
+ unsigned char pager0 = uin->pager;
+
+ uin->pager = 2;
+ uin->msgs[uin->msgcount].pid = currpid;
+ strcpy(uin->msgs[uin->msgcount].userid, cuser.userid);
+ strcpy(uin->msgs[uin->msgcount++].last_call_in, msg);
+ uin->pager = pager0;
+ } else if (flag != 2)
+ outmsg("\033[1;33;41mÁV¿|! ¹ï¤è¤£¦æ¤F! (¦¬¨ì¤Ó¦h¤ô²y) \033[37m@_@\033[m");
+
+ if(uin->msgcount == 1 && (uin->pid <= 0 || kill(uin->pid, SIGUSR2) == -1) && flag != 2)
+ outmsg("\033[1;33;41mÁV¿|! ¨S¥´¤¤! \033[37m~>_<~\033[m");
+ else if(uin->msgcount == 1 && flag != 2)
+ outmsg("\033[1;33;44m¤ô²y¯{¹L¥h¤F! \033[37m*^o^*\033[m");
+ else if(uin->msgcount > 1 && uin->msgcount < MAX_MSGS && flag != 2)
+ outmsg("\033[1;33;44m¦A¸É¤W¤@²É! \033[37m*^o^*\033[m");
+ }
+
+ clrtoeol();
+ refresh();
+
+ currutmp->chatid[0] = c0;
+ currutmp->mode = mode0;
+ currstat = currstat0;
+ return 1;
+}
+void t_display_new() {
+ static int t_display_new_flag=0;
+ int i, off=2;
+ if (t_display_new_flag)
+ return;
+ else
+ t_display_new_flag = 1;
+
+ if( WATERMODE(WATER_ORIG) )
+ water_which = &water[0];
+ else
+ off =3;
+
+ if (water[0].count && watermode > 0){
+ move(1, 0);
+ outs("¢w¢w¢w¢w¢w¢w¢w¤ô¢w²y¢w¦^¢wÅU¢w¢w¢w");
+ outs(WATERMODE(WATER_ORIG) ?
+ "¢w¢w¢w¢w¢w¢w¥Î[Ctrl-R Ctrl-T]Áä¤Á´«¢w¢w¢w¢w¢w" :
+ "¥Î[Ctrl-R Ctrl-T Ctrl-E Ctrl-W ]Áä¤Á´«¢w¢w¢w¢w");
+ if( WATERMODE(WATER_NEW) ){
+ move(2, 0);
+ clrtoeol();
+ for (i = 0; i<6 ; i++){
+ if(i>0)
+ prints("%s%-13.13s\033[m",
+ swater[i-1]==water_which?"\033[1;33;47m ":
+ " ",
+ swater[i-1] ? swater[i-1]->userid:"");
+ else
+ prints("%s ¥þ³¡ \033[m",
+ water_which==&water[0]?"\033[1;33;45m ":
+ " ");
+ }
+ }
+
+ for (i = 0; i < water_which->count; i++){
+ int a = (water_which->top - i - 1 + MAX_REVIEW) % MAX_REVIEW,
+ len = 75-strlen(water_which->msg[a].last_call_in)
+ -strlen(water_which->msg[a].userid);
+ if(len<0) len=0;
+
+ move(i + (WATERMODE(WATER_ORIG)?2:3), 0);
+ clrtoeol();
+ if (watermode - 1 != i)
+ prints("\033[1;33;46m %s \033[37;45m %s \033[m%*s",
+ water_which->msg[a].userid,
+ water_which->msg[a].last_call_in, len,
+ "");
+ else
+ prints("\033[1;44m>\033[1;33;47m%s "
+ "\033[37;45m %s \033[m%*s",
+ water_which->msg[a].userid,
+ water_which->msg[a].last_call_in,
+ len,"");
+ }
+
+ if (t_last_write[0]){
+ move(i + off, 0);
+ clrtoeol();
+ prints(t_last_write);
+ i++;
+ }
+ move(i + off, 0);
+ 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¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w");
+ if( WATERMODE(WATER_NEW))
+ while( i++ <= water[0].count ) {
+ move(i + off, 0);
+ clrtoeol();
+ }
+ }
+
+ t_display_new_flag = 0;
+}
+#if 0
+void t_display_new() {
+ int i, which=water_which;
+ char buf[200];
+
+ if (t_display_new_flag)
+ return;
+ else
+ t_display_new_flag = 1;
+
+ if (oldmsg_count && watermode > 0)
+ {
+ move(1, 0);
+ outs(
+ "¢w¢w¢w¢w¢w¢w¢w¤ô¢w²y¢w¦^¢wÅU¢w¢w¢w¢w¢w¢w¢w¢w¢w"
+ "¥Î[Ctrl-R Ctrl-T]Áä¤Á´«¢w¢w¢w¢w¢w");
+ move(2, 0);
+ prints(" |");
+ for (i = 0; i<5 && water[i].pid != 0; i++)
+ prints(" %s%13.13s \033[m|",which==i?"\033[1;33m":"",
+ water[i].userid);
+
+ for( i = 0 ; i < 5 &&
+ water[which].msg[ (water[which].msgtop-i+4) % 5 ][0] != 0; ++i ){
+ move(3 + i, 0);
+ if (watermode - 1 != i)
+ sprintf(buf, "\033[1;33;46m %s \033[37;45m %s \033[m",
+ water[which].userid,
+ water[which].msg[ (water[which].msgtop-i+4) % 5 ]);
+ else
+ sprintf(buf, "\033[1;44m>\033[1;33;47m%s \033[37;45m %s \033[m",
+ water[which].userid,
+ water[which].msg[ (water[which].msgtop-i+4) % 5 ]);
+ }
+ /*
+ for (i = 0; i < oldmsg_count; i++)
+ {
+ int a = (water[water_which].top - i - 1 + MAX_REVIEW) % MAX_REVIEW;
+
+ move(i + 3, 0);
+ clrtoeol();
+ if (watermode - 1 != i)
+ sprintf(buf, "\033[1;33;46m %s \033[37;45m %s \033[m",
+ oldmsg[a].userid, oldmsg[a].last_call_in);
+ else
+ sprintf(buf, "\033[1;44m>\033[1;33;47m%s "
+ "\033[37;45m %s \033[m",
+ oldmsg[a].userid, oldmsg[a].last_call_in);
+ outs(buf);
+ }
+*/
+ if (t_last_write[0])
+ {
+ move(i + 3, 0);
+ clrtoeol();
+ outs(t_last_write);
+ i++;
+ }
+ move(i + 3, 0);
+ 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¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w");
+ }
+ t_display_new_flag = 0;
+}
+#endif
+
+int t_display() {
+ char genbuf[200], ans[4];
+ if(fp_writelog)
+ { fclose(fp_writelog); fp_writelog=NULL;}
+ setuserfile(genbuf, fn_writelog);
+ if (more(genbuf, YEA) != -1)
+ {
+ getdata(b_lines - 1, 0, "²M°£(C) ²¾¦Ü³Æ§Ñ¿ý(M) «O¯d(R) (C/M/R)?[R]",
+ ans, 3, LCECHO);
+ if (*ans == 'm')
+ {
+ fileheader_t mymail;
+ char title[128], buf[80];
+
+ sethomepath(buf, cuser.userid);
+ stampfile(buf, &mymail);
+
+ mymail.savemode = 'H'; /* hold-mail flag */
+ mymail.filemode = FILE_READ;
+ strcpy(mymail.owner, "[³Æ.§Ñ.¿ý]");
+ strcpy(mymail.title, "¼ö½u\033[37;41m°O¿ý\033[m");
+ sethomedir(title, cuser.userid);
+ Rename(genbuf, buf);
+ append_record(title, &mymail, sizeof(mymail));
+ }
+ else if (*ans == 'c')
+ unlink(genbuf);
+ return FULLUPDATE;
+ }
+ return DONOTHING;
+}
+
+static void do_talk_nextline(talkwin_t * twin) {
+ twin->curcol = 0;
+ if (twin->curln < twin->eline)
+ ++(twin->curln);
+ else
+ region_scroll_up(twin->sline, twin->eline);
+ move(twin->curln, twin->curcol);
+}
+
+static void do_talk_char(talkwin_t * twin, int ch) {
+ extern screenline_t *big_picture;
+ screenline_t *line;
+ int i;
+ char ch0, buf[81];
+
+ if (isprint2(ch))
+ {
+ ch0 = big_picture[twin->curln].data[twin->curcol];
+ if (big_picture[twin->curln].len < 79)
+ move(twin->curln, twin->curcol);
+ else
+ do_talk_nextline(twin);
+ outc(ch);
+ ++(twin->curcol);
+ line = big_picture + twin->curln;
+ if (twin->curcol < line->len)
+ { /* insert */
+ ++(line->len);
+ memcpy(buf, line->data + twin->curcol, 80);
+ save_cursor();
+ do_move(twin->curcol, twin->curln);
+ ochar(line->data[twin->curcol] = ch0);
+ for (i = twin->curcol + 1; i < line->len; i++)
+ ochar(line->data[i] = buf[i - twin->curcol - 1]);
+ restore_cursor();
+ }
+ line->data[line->len] = 0;
+ return;
+ }
+
+ switch (ch)
+ {
+ case Ctrl('H'):
+ case '\177':
+ if (twin->curcol == 0)
+ return;
+ line = big_picture + twin->curln;
+ --(twin->curcol);
+ if (twin->curcol < line->len)
+ {
+ --(line->len);
+ save_cursor();
+ do_move(twin->curcol, twin->curln);
+ for (i = twin->curcol; i < line->len; i++)
+ ochar(line->data[i] = line->data[i + 1]);
+ line->data[i] = 0;
+ ochar(' ');
+ restore_cursor();
+ }
+ move(twin->curln, twin->curcol);
+ return;
+ case Ctrl('D'):
+ line = big_picture + twin->curln;
+ if (twin->curcol < line->len)
+ {
+ --(line->len);
+ save_cursor();
+ do_move(twin->curcol, twin->curln);
+ for (i = twin->curcol; i < line->len; i++)
+ ochar(line->data[i] = line->data[i + 1]);
+ line->data[i] = 0;
+ ochar(' ');
+ restore_cursor();
+ }
+ return;
+ case Ctrl('G'):
+ bell();
+ return;
+ case Ctrl('B'):
+ if (twin->curcol > 0)
+ {
+ --(twin->curcol);
+ move(twin->curln, twin->curcol);
+ }
+ return;
+ case Ctrl('F'):
+ if (twin->curcol < 79)
+ {
+ ++(twin->curcol);
+ move(twin->curln, twin->curcol);
+ }
+ return;
+ case KEY_TAB:
+ twin->curcol += 8;
+ if (twin->curcol > 80)
+ twin->curcol = 80;
+ move(twin->curln, twin->curcol);
+ return;
+ case Ctrl('A'):
+ twin->curcol = 0;
+ move(twin->curln, twin->curcol);
+ return;
+ case Ctrl('K'):
+ clrtoeol();
+ return;
+ case Ctrl('Y'):
+ twin->curcol = 0;
+ move(twin->curln, twin->curcol);
+ clrtoeol();
+ return;
+ case Ctrl('E'):
+ twin->curcol = big_picture[twin->curln].len;
+ move(twin->curln, twin->curcol);
+ return;
+ case Ctrl('M'):
+ case Ctrl('J'):
+ line = big_picture + twin->curln;
+ strncpy(buf, line->data, line->len);
+ buf[line->len] = 0;
+ do_talk_nextline(twin);
+ break;
+ case Ctrl('P'):
+ line = big_picture + twin->curln;
+ strncpy(buf, line->data, line->len);
+ buf[line->len] = 0;
+ if (twin->curln > twin->sline)
+ {
+ --(twin->curln);
+ move(twin->curln, twin->curcol);
+ }
+ break;
+ case Ctrl('N'):
+ line = big_picture + twin->curln;
+ strncpy(buf, line->data, line->len);
+ buf[line->len] = 0;
+ if (twin->curln < twin->eline)
+ {
+ ++(twin->curln);
+ move(twin->curln, twin->curcol);
+ }
+ break;
+ }
+ trim(buf);
+ if (*buf)
+ fprintf(flog, "%s%s: %s%s\n",
+ (twin->eline == b_lines - 1) ? "\033[1;35m" : "",
+ (twin->eline == b_lines - 1) ?
+ getuserid(currutmp->destuid) : cuser.userid, buf,
+ (ch == Ctrl('P')) ? "\033[37;45m(Up)\033[m" : "\033[m");
+}
+
+static void do_talk(int fd) {
+ struct talkwin_t mywin, itswin;
+ char mid_line[128], data[200];
+ int i, datac, ch;
+ int im_leaving = 0;
+ FILE *log;
+ struct tm *ptime;
+ time_t now;
+ char genbuf[200], fpath[100];
+
+ time(&now);
+ ptime = localtime(&now);
+
+ sethomepath(fpath, cuser.userid);
+ strcpy(fpath, tempnam(fpath, "talk_"));
+ flog = fopen(fpath, "w");
+
+ setuserfile(genbuf, fn_talklog);
+
+ if ((log = fopen(genbuf, "w")))
+ fprintf(log, "[%d/%d %d:%02d] & %s\n",
+ ptime->tm_mon + 1, ptime->tm_mday, ptime->tm_hour,
+ ptime->tm_min, save_page_requestor);
+ setutmpmode(TALK);
+
+ ch = 58 - strlen(save_page_requestor);
+ sprintf(genbuf, "%s¡i%s", cuser.userid, cuser.username);
+ i = ch - strlen(genbuf);
+ if (i >= 0)
+ i = (i >> 1) + 1;
+ else
+ {
+ genbuf[ch] = '\0';
+ i = 1;
+ }
+ memset(data, ' ', i);
+ data[i] = '\0';
+
+ sprintf(mid_line, "\033[1;46;37m ½Í¤Ñ»¡¦a \033[45m%s%s¡j"
+ " »P %s%s\033[0m", data, genbuf, save_page_requestor, data);
+
+ memset(&mywin, 0, sizeof(mywin));
+ memset(&itswin, 0, sizeof(itswin));
+
+ i = b_lines >> 1;
+ mywin.eline = i - 1;
+ itswin.curln = itswin.sline = i + 1;
+ itswin.eline = b_lines - 1;
+
+ clear();
+ move(i, 0);
+ outs(mid_line);
+ move(0, 0);
+
+ add_io(fd, 0);
+
+ while (1)
+ {
+ ch = igetkey();
+ if (ch == I_OTHERDATA)
+ {
+ datac = recv(fd, data, sizeof(data), 0);
+ if (datac <= 0)
+ break;
+ for (i = 0; i < datac; i++)
+ do_talk_char(&itswin, data[i]);
+ }
+ else
+ {
+ if (ch == Ctrl('C'))
+ {
+ if (im_leaving)
+ break;
+ move(b_lines, 0);
+ clrtoeol();
+ outs("¦A«ö¤@¦¸ Ctrl-C ´N¥¿¦¡¤¤¤î½Í¸ÜÅo¡I");
+ im_leaving = 1;
+ continue;
+ }
+ if (im_leaving)
+ {
+ move(b_lines, 0);
+ clrtoeol();
+ im_leaving = 0;
+ }
+ switch (ch)
+ {
+ case KEY_LEFT: /* §â2byteªºÁä§ï¬°¤@byte */
+ 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;
+ }
+ data[0] = (char) ch;
+ if (send(fd, data, 1, 0) != 1)
+ break;
+ if (log)
+ fprintf(log, "%c", (ch == Ctrl('M')) ? '\n' : (char) *data);
+ do_talk_char(&mywin, *data);
+ }
+ }
+ if (log)
+ fclose(log);
+
+ add_io(0, 0);
+ close(fd);
+
+ if (flog)
+ {
+ char ans[4];
+ extern screenline_t *big_picture;
+ extern unsigned char scr_lns;
+ int i;
+
+ time(&now);
+ fprintf(flog, "\n\033[33;44mÂ÷§Oµe­± [%s] ... \033[m\n",
+ Cdatelite(&now));
+ for (i = 0; i < scr_lns; i++)
+ fprintf(flog, "%.*s\n", big_picture[i].len, big_picture[i].data);
+ fclose(flog);
+ more(fpath, NA);
+ getdata(b_lines - 1, 0, "²M°£(C) ²¾¦Ü³Æ§Ñ¿ý(M). (C/M)?[C]",
+ ans, 4, LCECHO);
+ if (*ans == 'm')
+ {
+ fileheader_t mymail;
+ char title[128];
+
+ sethomepath(genbuf, cuser.userid);
+ stampfile(genbuf, &mymail);
+ mymail.savemode = 'H'; /* hold-mail flag */
+ mymail.filemode = FILE_READ;
+ strcpy(mymail.owner, "[³Æ.§Ñ.¿ý]");
+ sprintf(mymail.title, "¹ï¸Ü°O¿ý \033[1;36m(%s)\033[m",
+ getuserid(currutmp->destuid));
+ sethomedir(title, cuser.userid);
+ Rename(fpath, genbuf);
+ append_record(title, &mymail, sizeof(mymail));
+ }
+ else
+ unlink(fpath);
+ flog = 0;
+ }
+ setutmpmode(XINFO);
+}
+
+#define lockreturn(unmode, state) if(lockutmpmode(unmode, state)) return
+
+static void my_talk(userinfo_t * uin, int fri_stat) {
+ int sock, msgsock, length, ch, error = 0;
+ struct sockaddr_in server;
+ pid_t pid;
+ char c;
+ char genbuf[4];
+
+ unsigned char mode0 = currutmp->mode;
+
+ ch = uin->mode;
+ strcpy(currauthor, uin->userid);
+
+ if (ch == EDITING || ch == TALK || ch == CHATING || ch == PAGE ||
+ ch == MAILALL || ch == MONITOR || ch == M_FIVE || ch == CHC ||
+ (!ch && (uin->chatid[0] == 1 || uin->chatid[0] == 3)) ||
+ uin->lockmode == M_FIVE || uin->lockmode == CHC)
+ {
+ outs("¤H®a¦b¦£°Õ");
+ }
+ else if (!HAS_PERM(PERM_SYSOP) &&
+ (
+ ((fri_stat& HRM) && !(fri_stat& HFM)) ||
+ ((!uin->pager) && !(fri_stat & HFM))
+ )
+ )
+ {
+ outs("¹ï¤èÃö±¼©I¥s¾¹¤F");
+ }
+ else if (!HAS_PERM(PERM_SYSOP) &&
+ (
+ ((fri_stat & HRM) && !(fri_stat& HFM)) ||
+ uin->pager == 2
+ )
+ )
+ {
+ outs("¹ï¤è©Þ±¼©I¥s¾¹¤F");
+ }
+ else if (!HAS_PERM(PERM_SYSOP) &&
+ !(fri_stat & HFM) && uin->pager == 4)
+ {
+ outs("¹ï¤è¥u±µ¨ü¦n¤Íªº©I¥s");
+ }
+ else if (!(pid = uin->pid) /*|| (kill(pid, 0) == -1) */ )
+ {
+// resetutmpent();
+ outs(msg_usr_left);
+ }
+ else
+ {
+ showplans(uin->userid);
+ getdata(2, 0, "­n©M¥L(¦o) (T)½Í¤Ñ(F)¤U¤­¤l´Ñ(P)°«Ãdª«"
+ "(C)¤U¶H´Ñ(D)¤U·t´Ñ(N)¨S¨Æ§ä¿ù¤H¤F?[N] ", genbuf, 4, LCECHO);
+ switch (*genbuf)
+ {
+ case 'y':
+ case 't':
+ uin->sig = SIG_TALK;
+ break;
+ case 'f':
+ lockreturn(M_FIVE, LOCK_THIS);
+ uin->sig = SIG_GOMO;
+ break;
+ case 'c':
+ lockreturn(CHC, LOCK_THIS);
+ uin->sig = SIG_CHC;
+ break;
+ case 'd':
+ uin->sig = SIG_DARK;
+ break;
+ case 'p':
+ reload_chicken();
+ getuser(uin->userid);
+ if (uin->lockmode == CHICKEN || currutmp->lockmode == CHICKEN)
+ error = 1;
+ if (!cuser.mychicken.name[0] || !xuser.mychicken.name[0])
+ error = 2;
+ if (error)
+ {
+ outmsg(error == 2 ? "¨Ã«D¨â¤H³£¾iÃdª«" :
+ "¦³¤@¤èªºÃdª«¥¿¦b¨Ï¥Î¤¤");
+ bell();
+ refresh();
+ sleep(1);
+ return;
+ }
+ uin->sig = SIG_PK;
+ break;
+ default:
+ return;
+ }
+
+ uin->turn = 1;
+ currutmp->turn = 0;
+ strcpy(uin->mateid, currutmp->userid);
+ strcpy(currutmp->mateid, uin->userid);
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ perror("sock err");
+ unlockutmpmode();
+ return;
+ }
+ server.sin_family = PF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+ server.sin_port = 0;
+ if (bind(sock, (struct sockaddr *) &server, sizeof(server)) < 0)
+ {
+ close(sock);
+ perror("bind err");
+ unlockutmpmode();
+ return;
+ }
+ length = sizeof(server);
+ if (getsockname(sock, (struct sockaddr *) &server, &length) < 0)
+ {
+ close(sock);
+ perror("sock name err");
+ unlockutmpmode();
+ return;
+ }
+ currutmp->sockactive = YEA;
+ currutmp->sockaddr = server.sin_port;
+ currutmp->destuid = uin->uid;
+ setutmpmode(PAGE);
+ uin->destuip = currutmp - &utmpshm->uinfo[0];
+ if(pid > 0) kill(pid, SIGUSR1);
+ clear();
+ prints("¥¿©I¥s %s.....\nÁä¤J Ctrl-D ¤¤¤î....", uin->userid);
+
+ listen(sock, 1);
+ add_io(sock, 5);
+ while (1)
+ {
+ ch = igetch();
+ if (ch == I_TIMEOUT)
+ {
+ ch = uin->mode;
+ if (!ch && uin->chatid[0] == 1 &&
+ uin->destuip == currutmp - &utmpshm->uinfo[0])
+ {
+ bell();
+ outmsg("¹ï¤è¦^À³¤¤...");
+ refresh();
+ }
+ else if (ch == EDITING || ch == TALK || ch == CHATING ||
+ ch == PAGE || ch == MAILALL || ch == MONITOR ||
+ ch == M_FIVE || ch == CHC ||
+ (!ch && (uin->chatid[0] == 1 ||
+ uin->chatid[0] == 3)))
+ {
+ add_io(0, 0);
+ close(sock);
+ currutmp->sockactive = currutmp->destuid = 0;
+ outmsg("¤H®a¦b¦£°Õ");
+ pressanykey();
+ unlockutmpmode();
+ return;
+ }
+ else
+ {
+#ifdef linux
+ add_io(sock, 20); /* added for linux... achen */
+#endif
+ move(0, 0);
+ outs("¦A");
+ bell();
+
+ uin->destuip = currutmp - &utmpshm->uinfo[0];
+ if(pid <= 0 || kill(pid, SIGUSR1) == -1)
+ {
+#ifdef linux
+ add_io(sock, 20); /* added 4 linux... achen */
+#endif
+ outmsg(msg_usr_left);
+ refresh();
+ pressanykey();
+ unlockutmpmode();
+ return;
+ }
+ continue;
+ }
+ }
+
+ if (ch == I_OTHERDATA)
+ break;
+
+ if (ch == '\004')
+ {
+ add_io(0, 0);
+ close(sock);
+ currutmp->sockactive = currutmp->destuid = 0;
+ unlockutmpmode();
+ return;
+ }
+ }
+
+ msgsock = accept(sock, (struct sockaddr *) 0, (int *) 0);
+ if (msgsock == -1)
+ {
+ perror("accept");
+ unlockutmpmode();
+ return;
+ }
+ add_io(0, 0);
+ close(sock);
+ currutmp->sockactive = NA;
+ read(msgsock, &c, sizeof c);
+
+ if (c == 'y')
+ {
+ sprintf(save_page_requestor, "%s (%s)",
+ uin->userid, uin->username);
+ /* gomo */
+ switch (uin->sig)
+ {
+ case SIG_DARK:
+ main_dark(msgsock, uin);
+ break;
+ case SIG_PK:
+ chickenpk(msgsock);
+ break;
+ case SIG_GOMO:
+ gomoku(msgsock);
+ break;
+ case SIG_CHC:
+ chc(msgsock);
+ break;
+ case SIG_TALK:
+ default:
+ do_talk(msgsock);
+ }
+ }
+ else
+ {
+ move(9, 9);
+ outs("¡i¦^­µ¡j ");
+ switch (c)
+ {
+ case 'a':
+ outs("§Ú²{¦b«Ü¦£¡A½Ðµ¥¤@·|¨à¦A call §Ú¡A¦n¶Ü¡H");
+ break;
+ case 'b':
+ prints("¹ï¤£°_¡A§Ú¦³¨Æ±¡¤£¯à¸ò§A %s....", sig_des[uin->sig]);
+ break;
+ case 'd':
+ outs("§Ú­nÂ÷¯¸Åo..¤U¦¸¦A²á§a..........");
+ break;
+ case 'c':
+ outs("½Ð¤£­n§n§Ú¦n¶Ü¡H");
+ break;
+ case 'e':
+ outs("§ä§Ú¦³¨Æ¶Ü¡H½Ð¥ý¨Ó«H­ò....");
+ break;
+ case 'f':
+ {
+ char msgbuf[60];
+
+ read(msgsock, msgbuf, 60);
+ prints("¹ï¤£°_¡A§Ú²{¦b¤£¯à¸ò§A %s¡A¦]¬°\n", sig_des[uin->sig]);
+ move(10, 18);
+ outs(msgbuf);
+ }
+ break;
+ case '1':
+ prints("%s¡H¥ý®³100»È¨â¨Ó..", sig_des[uin->sig]);
+ break;
+ case '2':
+ prints("%s¡H¥ý®³1000»È¨â¨Ó..", sig_des[uin->sig]);
+ break;
+ default:
+ prints("§Ú²{¦b¤£·Q %s °Õ.....:)", sig_des[uin->sig]);
+ }
+ close(msgsock);
+ }
+ }
+ currutmp->mode = mode0;
+ currutmp->destuid = 0;
+ unlockutmpmode();
+ pressanykey();
+}
+
+/* ¿ï³æ¦¡²á¤Ñ¤¶­± */
+#define US_PICKUP 1234
+#define US_RESORT 1233
+#define US_ACTION 1232
+#define US_REDRAW 1231
+
+static void t_showhelp() {
+ clear();
+
+ outs("\033[36m¡i ¥ð¶¢²á¤Ñ¨Ï¥Î»¡©ú ¡j\033[m\n\n"
+ "(¡ö)(e) µ²§ôÂ÷¶} (h) ¬Ý¨Ï¥Î»¡©ú\n"
+ "(¡ô)/(¡õ)(n) ¤W¤U²¾°Ê (TAB) ¤Á´«±Æ§Ç¤è¦¡\n"
+ "(PgUp)(^B) ¤W­¶¿ï³æ ( )(PgDn)(^F) ¤U­¶¿ï³æ\n"
+ "(Hm)/($)(Ed) ­º/§À (S) "
+ "¨Ó·½/¦n¤Í´y­z/¾ÔÁZ ¤Á´«\n"
+ "(m) ±H«H (q/c) "
+ "¬d¸ßºô¤Í/Ãdª«\n"
+ "(r) ¾\\Ū«H¥ó (l) ¬Ý¤W¦¸¼ö°T\n"
+ "(f) ¥þ³¡/¦n¤Í¦Cªí (¼Æ¦r) ¸õ¦Ü¸Ó¨Ï¥ÎªÌ\n"
+ "(p) ¤Á´«©I¥s¾¹ (g/i) µ¹¿ú/¤Á´«¤ß±¡\n"
+ "(a/d/o) ¦n¤Í ¼W¥[/§R°£/­×§ï (/)(s) ºô¤ÍID/¼ÊºÙ·j´M");
+
+ if (HAS_PERM(PERM_PAGE))
+ {
+ outs("\n\n\033[36m¡i ¥æ½Í±M¥ÎÁä ¡j\033[m\n\n"
+ "(¡÷)(t)(Enter) ¸ò¥L¡þ¦o²á¤Ñ\n"
+ "(w) ¼ö½u Call in\n"
+ "(b) ¹ï¦n¤Í¼s¼½ (¤@©w­n¦b¦n¤Í¦Cªí¤¤)\n"
+ "(^R) §Y®É¦^À³ (¦³¤H Call in §A®É)");
+ }
+
+ if (HAS_PERM(PERM_SYSOP))
+ {
+ outs("\n\n\033[36m¡i ¯¸ªø±M¥ÎÁä ¡j\033[m\n\n");
+ if (HAS_PERM(PERM_SYSOP))
+ outs("(u)/(H) ³]©w¨Ï¥ÎªÌ¸ê®Æ/¤Á´«Áô§Î¼Ò¦¡\n");
+ outs("(R)/(K) ¬d¸ß¨Ï¥ÎªÌªº¯u¹ê©m¦W/§âÃa³J½ð¥X¥h\n");
+ }
+ pressanykey();
+}
+
+static int listcuent(userinfo_t * uentp) {
+ if((!uentp->invisible || HAS_PERM(PERM_SYSOP) || HAS_PERM(PERM_SEECLOAK)))
+ AddNameList(uentp->userid);
+ return 0;
+}
+
+static void creat_list() {
+ CreateNameList();
+ apply_ulist(listcuent);
+}
+
+static int search_pickup(int num, int actor, pickup_t pklist[]) {
+ char genbuf[IDLEN + 2];
+
+ move(1, 0);
+ creat_list();
+ namecomplete(msg_uid, genbuf);
+ if (genbuf[0])
+ {
+ int n = (num + 1) % actor;
+ while (n != num)
+ {
+ if (!strcasecmp(pklist[n].ui->userid, genbuf))
+ return n;
+ if (++n >= actor)
+ n = 0;
+ }
+ }
+ return -1;
+}
+
+/* Kaede show friend description */
+static char *friend_descript(char *uident) {
+ static char *space_buf = " ";
+ static char desc_buf[80];
+ char fpath[80], name[IDLEN + 2], *desc, *ptr;
+ int len, flag;
+ FILE *fp;
+ char genbuf[200];
+
+ setuserfile(fpath, friend_file[0]);
+
+ if ((fp = fopen(fpath, "r")))
+ {
+ sprintf(name, "%s ", uident);
+ len = strlen(name);
+ desc = genbuf + 13;
+
+ while ((flag = (int) fgets(genbuf, STRLEN, fp)))
+ {
+ if (!memcmp(genbuf, name, len))
+ {
+ if ((ptr = strchr(desc, '\n')))
+ ptr[0] = '\0';
+ if (desc)
+ break;
+ }
+ }
+ fclose(fp);
+ if (desc && flag)
+ strcpy(desc_buf, desc);
+ else
+ return space_buf;
+
+ return desc_buf;
+ }
+ else
+ return space_buf;
+}
+
+static char *descript(int show_mode, userinfo_t * uentp, time_t diff,
+ fromcache_t * fcache) {
+ switch (show_mode)
+ {
+ case 1:
+ return friend_descript(uentp->userid);
+ case 0:
+ return (((uentp->pager != 2 && uentp->pager != 3 && diff) ||
+ HAS_PERM(PERM_SYSOP)) ?
+#ifdef WHERE
+ uentp->from_alias ? fcache->replace[uentp->from_alias] :
+ uentp->from
+#else
+ uentp->from
+#endif
+ : "*");
+ case 2:
+ sprintf(description, "%3d/%3d/%3d", uentp->five_win,
+ uentp->five_lose, uentp->five_tie);
+ description[20] = 0;
+ return description;
+ default:
+ syslog(LOG_WARNING, "damn!!! what's wrong?? show_mode = %d",
+ show_mode);
+ return "";
+ }
+}
+
+static int pickup_user_cmp(time_t now, int sortedway, int cmp_fri,
+ pickup_t pklist[], int *bfriends_number, int *ifh_number,
+ int *hfm_number,int *irh_number, char *keyword)
+{
+ int i, fri_stat, is_friend, count=0, diff;
+ userinfo_t *uentp;
+ for (i=0;i<utmpshm->number;i++)
+ {
+ uentp = (utmpshm->sorted[utmpshm->currsorted][sortedway][i]);
+ if (!uentp || !uentp->pid) continue;
+ fri_stat = friend_stat(currutmp, uentp);
+ if(uentp->uid==currutmp->uid)
+ fri_stat = fri_stat|IFH|HFM;
+ is_friend = (fri_stat & IRH) && !(fri_stat & IFH) ? 0 :
+ fri_stat & ST_FRIEND;
+ if (!isvisible_stat(currutmp, uentp, fri_stat) ||
+ ((cmp_fri==1 && !is_friend) ||
+ (cmp_fri==-1 && is_friend)) ||
+ (keyword[0] && !strcasestr(uentp->username,keyword))
+ ) continue;
+ if (bfriends_number && fri_stat & IBH) (*bfriends_number)++;
+ if (ifh_number && fri_stat & IFH) (*ifh_number)++;
+ if (hfm_number && fri_stat & HFM) (*hfm_number)++;
+ if (irh_number && fri_stat & IRH) (*irh_number)++;
+#ifdef SHOW_IDLE_TIME
+ diff = now - uentp->lastact;
+#ifdef DOTIMEOUT
+ /* prevent fault /dev mount from kicking out users */
+ if ((diff > curr_idle_timeout + 10) &&
+ (diff < 60 * 60 * 24 * 5))
+ {
+ if ((uentp->pid <= 0 || kill(uentp->pid, SIGHUP) == -1) &&
+ (errno == ESRCH))
+ purge_utmp(uentp);
+ continue;
+ }
+#endif
+ pklist[count].idle = diff;
+#endif
+ pklist[count].friend = fri_stat;
+ pklist[count].ui = uentp;
+ count++;
+ }
+ return count;
+}
+
+static int cmputmpfriend(const void *i, const void *j)
+{
+ if((((pickup_t*)j)->friend&ST_FRIEND)==(((pickup_t*)i)->friend&ST_FRIEND))
+ return strcasecmp( ((pickup_t*)i)->ui->userid,
+ ((pickup_t*)j)->ui->userid);
+ else
+ return (((pickup_t*)j)->friend&ST_FRIEND) -
+ (((pickup_t*)i)->friend&ST_FRIEND);
+}
+
+static void pickup_user() {
+ static int real_name = 0;
+ static int show_mode = 0;
+ static int show_uid = 0;
+ static int show_board = 0;
+ static int show_pid = 0;
+ static int num = 0;
+ char genbuf[200];
+
+#ifdef WHERE
+ extern struct fromcache_t *fcache;
+#endif
+
+ register userinfo_t *uentp;
+ register pid_t pid0 = 0; /* Ptt ©w¦ì */
+ register int id0 = 0; /* US_PICKUP®Éªº´å¼Ð¥Î */
+ register int state = US_PICKUP, ch;
+ register int actor = 0, head, foot;
+ int fri_stat, bfriends_number, ifh_number, irh_number, hfm_number;
+ int savemode = currstat;
+ int i, sortedway; /* ¥u¬Oloop¦³¥Î¨ì */
+ time_t diff, freshtime;
+ pickup_t pklist[USHM_SIZE]; /* parameter Pttµù */
+/* num : ²{¦bªº´å¼Ð¦ì */
+/* foot: ¦¹­¶ªº¸}¸} */
+ char buf[20],keyword[13]=""; /* actor:¦@¦³¦h¤Öuser */
+ char pagerchar[5] = "* -Wf";
+ char *msg_pickup_way[PICKUP_WAYS] =
+ {
+ "¶Ù! ªB¤Í",
+ "ºô¤Í¥N¸¹",
+ "ºô¤Í°ÊºA",
+ "µo§b®É¶¡",
+ "¨Ó¦Û¦ó¤è",
+ "¤­¤l´Ñ ",
+// "¤k¤hÀu¥ý"
+ };
+ char *MODE_STRING[MAX_SHOW_MODE] =
+ {
+ "¬G¶m",
+ "¦n¤Í´y­z",
+ "¤­¤l´Ñ¾ÔÁZ"
+ };
+ char
+ *Mind[] =
+ {" ",
+ "^-^", "^_^", "Q_Q", "@_@", "/_\\", "=_=", "-_-", "-.-", ">_<",
+ "-_+", "!_!", "o_o", "z_Z", "O_O", "O.O", "$_$", "^*^", "O_<",
+ "³ß!", "«ã!", "«s!", "¼Ö!", ":) ", ":( ", ":~ ", ":q ", ":O ",
+ ":D ", ":p ", ";) ", ":> ", ";> ", ":< ", ":)~", ":D~", ">< ",
+ "^^;", "^^|", "­ú;", NULL};
+
+ while (1)
+ {
+ if (utmpshm->uptime > freshtime || state == US_PICKUP ||
+ state ==US_RESORT)
+ {
+ state = US_PICKUP;
+ time(&freshtime);
+ ifh_number=hfm_number=irh_number=bfriends_number = actor = ch = 0;
+ if(pickup_way==0)
+ sortedway=0;
+ else
+ sortedway=pickup_way-1;
+
+ //qsort(pklist,actor,sizeof(pickup_t),cmputmpfriend);
+ if(pickup_way==0 || (cuser.uflag & FRIEND_FLAG))
+ {
+ actor=pickup_user_cmp(freshtime, sortedway, 1,
+ pklist, &bfriends_number, &ifh_number, &hfm_number,
+ NULL,keyword);
+ if(sortedway==0)
+ qsort(pklist,actor,sizeof(pickup_t),cmputmpfriend);
+ if(!(cuser.uflag & FRIEND_FLAG))
+ actor=pickup_user_cmp(freshtime, sortedway, -1,
+ pklist+actor, NULL, NULL, NULL, &irh_number,
+ keyword);
+ }
+ else
+ {
+ actor=pickup_user_cmp(freshtime, sortedway, 0,
+ pklist, &bfriends_number, &ifh_number, &hfm_number,
+ &irh_number, keyword);
+ }
+
+
+ if (!actor)
+ {
+ if(keyword[0])
+ {
+ mprints(b_lines-1,0,
+ "·j´M¤£¨ì¥ô¦ó¤H !!");
+ keyword[0]=0;
+ pressanykey();
+ continue;
+ }
+ getdata(b_lines - 1, 0,
+ "§AªºªB¤ÍÁÙ¨S¤W¯¸¡A­n¬Ý¬Ý¤@¯ëºô¤Í¶Ü(Y/N)¡H[Y]",
+ genbuf, 4, LCECHO);
+ if (genbuf[0] != 'n')
+ {
+ cuser.uflag &= ~FRIEND_FLAG;
+ continue;
+ }
+ return;
+ }
+ }
+ if (state >= US_ACTION)
+ {
+ showtitle((cuser.uflag & FRIEND_FLAG) ? "¦n¤Í¦Cªí" : "¥ð¶¢²á¤Ñ",
+ BBSName);
+ prints(" ±Æ§Ç¡G[%s] ¤W¯¸¤H¼Æ¡G%-4d\033[1;32m§ÚªºªB¤Í¡G%-3d"
+ "\033[33m»P§Ú¬°¤Í¡G%-3d\033[36mªO¤Í¡G%-4d\033[31mÃa¤H¡G"
+ "%-2d\033[m\n"
+ "\033[7m %s P%c¥N¸¹ %-17s%-17s%-13s%-10s\033[m\n",
+ msg_pickup_way[pickup_way], actor, ifh_number,
+ hfm_number, bfriends_number, irh_number,
+ show_uid ? "UID" : "No.",
+ (HAS_PERM(PERM_SEECLOAK) || HAS_PERM(PERM_SYSOP)) ? 'C' : ' ',
+ real_name ? "©m¦W" : "¼ÊºÙ",
+ MODE_STRING[show_mode],
+ show_board ? "Board" : "°ÊºA",
+ show_pid ? " PID" : "³Æµù µo§b"
+ );
+ }
+ else
+ {
+ move(3, 0);
+ clrtobot();
+ }
+ if (pid0)
+ for (ch = 0; ch < actor; ch++)
+ {
+ if (pid0 == (pklist[ch].ui)->pid &&
+ id0 == 256 * pklist[ch].ui->userid[0] +
+ pklist[ch].ui->userid[1])
+ {
+ num = ch;
+ }
+ }
+ if (num < 0)
+ num = 0;
+ else if (num >= actor)
+ num = actor - 1;
+ head = (num / p_lines) * p_lines;
+ foot = head + p_lines;
+ if (foot > actor)
+ foot = actor;
+ for (ch = head; ch < foot; ch++)
+ {
+ uentp = pklist[ch].ui;
+
+ if (!uentp->pid)
+ {
+ prints("%5d < Â÷¯¸¤¤..>\n",ch);
+ continue;
+ }
+#ifdef SHOW_IDLE_TIME
+ diff = pklist[ch].idle;
+ if (diff > 59990) diff = 59990; /* Doma: ¥H§K¤@¤j¦êªºµo§b®É¶¡ */
+ if (diff > 0)
+ sprintf(buf, "%3ld'%02ld", diff / 60, diff % 60);
+ else
+ buf[0] = '\0';
+#else
+ buf[0] = '\0';
+#endif
+ i = pklist[ch].friend;
+#ifdef SHOWPID
+ if (show_pid)
+ sprintf(buf, "%6d", uentp->pid);
+#endif
+ if (PERM_HIDE(uentp))
+ state = 9;
+ else if(currutmp == uentp)
+ state =10;
+ else if(i & IRH && !(i & IFH))
+ state = 8;
+ else
+ state =(i&ST_FRIEND)>>2;
+ diff = uentp->pager & !(i&HRM);
+ prints("%5d %c%c%s%-13s%-17.16s\033[m%-17.16s%-13.13s"
+ "\33[33m%-4.4s\33[m%s\n",
+#ifdef SHOWUID
+ show_uid ? uentp->uid :
+#endif
+ (ch + 1),
+ (i & HRM) ? 'X' :
+ pagerchar[uentp->pager % 5],
+ (uentp->invisible ? ')' : ' '),
+ fcolor[state],
+ /* %s */
+ uentp->userid,
+
+ /* %-13s ¼ÊºÙ */
+#ifdef REALINFO
+ real_name ? uentp->realname :
+#endif
+ uentp->username,
+ /* %-17.16s ¬G¶m */
+ descript(show_mode, uentp, diff, fcache),
+
+ /* %-17.16s ¬ÝªO */
+#ifdef SHOWBOARD
+ show_board ? (uentp->brc_id == 0 ? "" :
+ bcache[uentp->brc_id - 1].brdname) :
+#endif
+ /* %-13.13s */
+ modestring(uentp, 0),
+ /* %4s ³Æµù */
+ ((uentp->userlevel & PERM_VIOLATELAW) ? "³q½r" :
+ (uentp->birth ? "¹Ø¬P" :
+ Mind[uentp->mind])),
+ /* %s µo§b */
+ buf);
+ }
+ if (state == US_PICKUP)
+ continue;
+
+ move(b_lines, 0);
+ outs("\033[31;47m(TAB/f)\033[30m±Æ§Ç/¦n¤Í \033[31m(t)\033[30m²á¤Ñ "
+ "\033[31m(a/d/o)\033[30m¥æ¤Í \033[31m(q)\033[30m¬d¸ß "
+ "\033[31m(w)\033[30m¤ô²y \033[31m(m)\033[30m±H«H \033[31m(h)"
+ "\033[30m½u¤W»²§U \033[m");
+ state = 0;
+ while (!state)
+ {
+ ch = cursor_key(num + 3 - head, 0);
+ if (ch == KEY_RIGHT || ch == '\n' || ch == '\r')
+ ch = 't';
+
+ switch (ch)
+ {
+ case KEY_LEFT:
+ case 'e':
+ case 'E':
+ if(!keyword[0]) return;
+ keyword[0]=0;
+ state = US_PICKUP;
+ break;
+
+ case KEY_TAB:
+ pickup_way = (pickup_way + 1) % PICKUP_WAYS;
+ state = US_RESORT;
+ num = 0;
+ break;
+
+ case KEY_DOWN:
+ case 'n':
+ case 'j':
+ if (++num < actor)
+ {
+ if (num >= foot)
+ state = US_REDRAW;
+ break;
+ }
+ case '0':
+ case KEY_HOME:
+ num = 0;
+ if (head)
+ state = US_REDRAW;
+ break;
+ case 'H':
+ if (HAS_PERM(PERM_SYSOP))
+ {
+ currutmp->userlevel ^= PERM_DENYPOST;
+ state = US_REDRAW;
+ }
+ break;
+ case 'D':
+ if (HAS_PERM(PERM_SYSOP))
+ {
+ char buf[100];
+
+ sprintf(buf, "¥N¸¹ [%s]¡G", currutmp->userid);
+ if (!getdata(1, 0, buf, currutmp->userid, IDLEN + 1,
+ DOECHO))
+ strcpy(currutmp->userid, cuser.userid);
+ state = US_REDRAW;
+ }
+ break;
+ case 'F':
+ if (HAS_PERM(PERM_SYSOP))
+ {
+ char buf[100];
+
+ sprintf(buf, "¬G¶m [%s]¡G", currutmp->from);
+ if (!getdata(1, 0, buf, currutmp->from, 17, DOECHO))
+ strncpy(currutmp->from, fromhost, 23);
+ state = US_REDRAW;
+ }
+ break;
+ case 'C':
+#if !HAVE_FREECLOAK
+ if (HAS_PERM(PERM_CLOAK))
+#endif
+ {
+ currutmp->invisible ^= 1;
+ state = US_REDRAW;
+ }
+ break;
+ case ' ':
+ case KEY_PGDN:
+ case Ctrl('F'):
+ if (foot < actor)
+ {
+ num += p_lines;
+ state = US_REDRAW;
+ break;
+ }
+ if (head)
+ num = 0;
+ state = US_PICKUP;
+ break;
+ case KEY_UP:
+ case 'k':
+ if (--num < head)
+ {
+ if (num < 0)
+ {
+ num = actor - 1;
+ if (actor == foot)
+ break;
+ }
+ state = US_REDRAW;
+ }
+ break;
+ case KEY_PGUP:
+ case Ctrl('B'):
+ case 'P':
+ if (head)
+ {
+ num -= p_lines;
+ state = US_REDRAW;
+ break;
+ }
+
+ case KEY_END:
+ case '$':
+ num = actor - 1;
+ if (foot < actor)
+ state = US_REDRAW;
+ break;
+
+ case '/':
+ getdata_buf(b_lines-1,0,"½Ð¿é¤J¼ÊºÙÃöÁä¦r:",keyword, 12,
+ DOECHO);
+ state = US_PICKUP;
+ break;
+ case 's':
+ if ((i = search_pickup(num, actor, pklist)) >= 0)
+ num = i;
+ state = US_ACTION;
+ break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ { /* Thor: ¥i¥H¥´¼Æ¦r¸õ¨ì¸Ó¤H */
+ int tmp;
+ if ((tmp = search_num(ch, actor - 1)) >= 0)
+ num = tmp;
+ state = US_REDRAW;
+ }
+ break;
+#ifdef REALINFO
+ case 'R': /* Åã¥Ü¯u¹ê©m¦W */
+ if (HAS_PERM(PERM_SYSOP))
+ real_name ^= 1;
+ state = US_PICKUP;
+ break;
+#endif
+#ifdef SHOWUID
+ case 'U':
+ if (HAS_PERM(PERM_SYSOP))
+ show_uid ^= 1;
+ state = US_PICKUP;
+ break;
+#endif
+#ifdef SHOWBOARD
+ case 'Y':
+ if (HAS_PERM(PERM_SYSOP))
+ show_board ^= 1;
+ state = US_PICKUP;
+ break;
+#endif
+#ifdef SHOWPID
+ case '#':
+ if (HAS_PERM(PERM_SYSOP))
+ show_pid ^= 1;
+ state = US_PICKUP;
+ break;
+#endif
+
+ case 'b': /* broadcast */
+ if (cuser.uflag & FRIEND_FLAG || HAS_PERM(PERM_SYSOP))
+ {
+ int actor_pos = actor;
+ char ans[4];
+
+ state = US_PICKUP;
+ if (!getdata(0, 0, "¼s¼½°T®§:", genbuf, 60, DOECHO))
+ break;
+ if (getdata(0, 0, "½T©w¼s¼½? [Y]", ans, 4, LCECHO) &&
+ *ans == 'n')
+ break;
+ while (actor_pos)
+ {
+ uentp = pklist[--actor_pos].ui;
+ fri_stat = pklist[actor_pos].friend;
+ if (uentp->pid &&
+ currpid != uentp->pid &&
+ uentp->pid > 0 && kill(uentp->pid, 0) != -1 &&
+ (HAS_PERM(PERM_SYSOP) ||
+ (uentp->pager != 3 &&
+ (uentp->pager != 4 || fri_stat & HFM))))
+ my_write(uentp->pid, genbuf, uentp->userid, HAS_PERM(PERM_SYSOP) ? 3 : 1);
+ }
+ }
+ break;
+ case 'S': /* Åã¥Ü¦n¤Í´y­z */
+ show_mode = (++show_mode) % MAX_SHOW_MODE;
+ state = US_PICKUP;
+ break;
+ case 'u': /* ½u¤W­×§ï¸ê®Æ */
+ case 'K': /* §âÃa³J½ð¥X¥h */
+ if (!HAS_PERM(PERM_ACCOUNTS))
+ continue;
+ state = US_ACTION;
+ break;
+ case 'i':
+ state = US_ACTION;
+ break;
+ case Ctrl('S'):
+ state = US_ACTION;
+ break;
+ case 't':
+ case 'w':
+ if (!(cuser.userlevel & PERM_LOGINOK))
+ continue;
+ state = US_ACTION;
+ break;
+ case 'a':
+ case 'd':
+ case 'o':
+ case 'f':
+ case 'g':
+ if (!HAS_PERM(PERM_LOGINOK))
+ /* µù¥U¤~¦³ Friend */
+ break;
+ if (ch == 'f')
+ {
+ cuser.uflag ^= FRIEND_FLAG;
+ state = US_PICKUP;
+ break;
+ }
+ state = US_ACTION;
+ break;
+ case 'q':
+ case 'c':
+ case 'm':
+ case 'r':
+ case 'l':
+ /* guest ¥u¯à query */
+ if (!cuser.userlevel && ch != 'q' && ch != 'l')
+ break;
+ case 'h':
+ state = US_ACTION;
+ break;
+ case 'p':
+ if (HAS_PERM(PERM_BASIC))
+ {
+ t_pager();
+ state = US_REDRAW;
+ }
+ break;
+ case 'W':
+ {
+ int tmp;
+ char *wm[3] = {"¤@¯ë", "¶i¶¥", "¥¼¨Ó"};
+ tmp = cuser.uflag2 & WATER_MASK;
+ cuser.uflag2 -= tmp;
+ tmp = (tmp + 1) % 3;
+ cuser.uflag2 |= tmp;
+ prints("¤Á´«¨ì %s ¤ô²y¼Ò¦¡", wm[tmp]);
+ refresh();
+ sleep(1);
+ state = US_REDRAW;
+ }
+ default: /* refresh screen */
+ state = US_REDRAW;
+ }
+ }
+
+ if (state != US_ACTION)
+ {
+ pid0 = 0;
+ continue;
+ }
+
+ /* Ptt decide cur */
+ uentp = pklist[num].ui;
+ fri_stat = friend_stat(currutmp, uentp);
+ pid0 = uentp->pid;
+ id0 = 256 * uentp->userid[0] + uentp->userid[1];
+
+ if (ch == 'w')
+ {
+ if ((uentp->pid != currpid) &&
+ (HAS_PERM(PERM_SYSOP) ||
+ (uentp->pager != 3 &&
+ (fri_stat & HFM || uentp->pager != 4))))
+ {
+ cursor_show(num + 3 - head, 0);
+ sprintf(genbuf, "Call-In %s ¡G", uentp->userid);
+ my_write(uentp->pid, genbuf, uentp->userid, 0);
+ }
+ }
+ else if (ch == 'l')
+ { /* Thor: ¬Ý Last call in */
+ t_display();
+ }
+ else
+ {
+ switch (ch)
+ {
+ case 'r':
+ m_read();
+ break;
+ case 'g': /* give money */
+ move(b_lines - 2, 0);
+ if (strcmp(uentp->userid, cuser.userid))
+ {
+ sprintf(genbuf, "­nµ¹ %s ¦h¤Ö¿ú©O? ", uentp->userid);
+ outs(genbuf);
+ if (getdata(b_lines - 1, 0, "[»È¦æÂà±b]:", genbuf, 7,
+ LCECHO))
+ {
+ clrtoeol();
+ if ((ch = atoi(genbuf)) <= 0)
+ break;
+ reload_money();
+ if (ch > cuser.money)
+ outs("\033[41m ²{ª÷¤£¨¬~~\033[m");
+ else
+ {
+ deumoney(uentp->uid, ch);
+ sprintf(genbuf, "\033[44m ¶â..ÁٳѤU %d ¿ú.."
+ "\033[m", demoney(-1*ch));
+ outs(genbuf);
+ sprintf(genbuf, "%s\tµ¹%s\t%d\t%s", cuser.userid,
+ uentp->userid, ch,
+ ctime(&currutmp->lastact));
+ log_file(FN_MONEY, genbuf);
+ mail_redenvelop(cuser.userid, uentp->userid, ch, 'Y');
+ }
+ }
+ else
+ {
+ clrtoeol();
+ outs("\033[41m ¥æ©ö¨ú®ø! \033[m");
+ }
+ }
+ else
+ outs("\033[33m ¦Û¤vµ¹¦Û¤v? ­A²Â..\033[m");
+ refresh();
+ sleep(1);
+ break;
+#ifdef SHOWMIND
+ case 'i':
+ move(3,0);
+ clrtobot();
+ for (i = 1; Mind[i]!=NULL; i++)
+ {
+ move(5+(i-1)/7,((i-1)%7)*10);
+ prints("%2d: %s",i,Mind[i]);
+ }
+ getdata(b_lines - 1, 0, "§A²{¦bªº¤ß±¡ 0:µL q¤£ÅÜ [q]:",
+ genbuf, 3, LCECHO);
+ if (genbuf[0] && genbuf[0] != 'q')
+ currutmp->mind=atoi(genbuf)%i;
+ state = US_REDRAW;
+ break;
+#endif
+ case 'a':
+ friend_add(uentp->userid, FRIEND_OVERRIDE);
+ friend_load();
+ state = US_PICKUP;
+ break;
+ case 'd':
+ friend_delete(uentp->userid, FRIEND_OVERRIDE);
+ friend_load();
+ state = US_PICKUP;
+ break;
+ case 'o':
+ t_override();
+ state = US_PICKUP;
+ break;
+ case 'K':
+ if (uentp->pid > 0 && kill(uentp->pid, 0) != -1)
+ {
+ move(1, 0);
+ clrtobot();
+ move(2, 0);
+ my_kick(uentp);
+ state = US_PICKUP;
+ }
+ break;
+ case 'm':
+ stand_title("±H «H");
+ prints("[±H«H] ¦¬«H¤H¡G%s", uentp->userid);
+ my_send(uentp->userid);
+ break;
+ case 'q':
+ strcpy(currauthor, uentp->userid);
+ my_query(uentp->userid);
+ break;
+ case 'c':
+ chicken_query(uentp->userid);
+ break;
+ case 'u': /* Thor: ¥i½u¤W¬d¬Ý¤Î­×§ï¨Ï¥ÎªÌ */
+ {
+ int id;
+ userec_t muser;
+
+ strcpy(currauthor, uentp->userid);
+ stand_title("¨Ï¥ÎªÌ³]©w");
+ move(1, 0);
+ if ((id = getuser(uentp->userid)))
+ {
+ memcpy(&muser, &xuser, sizeof(muser));
+ user_display(&muser, 1);
+ uinfo_query(&muser, 1, id);
+ }
+ }
+ break;
+
+ case 'h': /* Thor: ¬Ý Help */
+ t_showhelp();
+ break;
+
+ case 't':
+ if (uentp->pid != currpid &&
+ (strcmp(uentp->userid, cuser.userid)))
+ {
+ move(1, 0);
+ clrtobot();
+ move(3, 0);
+ my_talk(uentp, fri_stat);
+ state = US_PICKUP;
+ }
+ break;
+ }
+ }
+ setutmpmode(savemode);
+ }
+}
+
+int t_users() {
+ int destuid0 = currutmp->destuid;
+ int mode0 = currutmp->mode;
+ int stat0 = currstat;
+
+ setutmpmode(LUSERS);
+ pickup_user();
+ currutmp->mode = mode0;
+ currutmp->destuid = destuid0;
+ currstat = stat0;
+ return 0;
+}
+
+int t_pager() {
+ currutmp->pager = (currutmp->pager + 1) % 5;
+ return 0;
+}
+
+int t_idle() {
+ int destuid0 = currutmp->destuid;
+ int mode0 = currutmp->mode;
+ int stat0 = currstat;
+ char genbuf[20];
+ char buf[80], passbuf[PASSLEN];
+
+ setutmpmode(IDLE);
+ getdata(b_lines - 1, 0, "²z¥Ñ¡G[0]µo§b (1)±µ¹q¸Ü (2)³V­¹ (3)¥´½OºÎ "
+ "(4)¸Ë¦º (5)ù¤¦ (6)¨ä¥L (Q)¨S¨Æ¡H", genbuf, 3, DOECHO);
+ if (genbuf[0] == 'q' || genbuf[0] == 'Q')
+ {
+ currutmp->mode = mode0;
+ currstat = stat0;
+ return 0;
+ }
+ else if (genbuf[0] >= '1' && genbuf[0] <= '6')
+ currutmp->destuid = genbuf[0] - '0';
+ else
+ currutmp->destuid = 0;
+
+ if (currutmp->destuid == 6)
+ if (!cuser.userlevel ||
+ !getdata(b_lines - 1, 0, "µo§bªº²z¥Ñ¡G", currutmp->chatid, 11,
+ DOECHO))
+ currutmp->destuid = 0;
+ do
+ {
+ move(b_lines - 2, 0);
+ clrtoeol();
+ sprintf(buf, "(Âê©w¿Ã¹õ)µo§b­ì¦]: %s", (currutmp->destuid != 6) ?
+ IdleTypeTable[currutmp->destuid] : currutmp->chatid);
+ outs(buf);
+ refresh();
+ getdata(b_lines - 1, 0, MSG_PASSWD, passbuf, PASSLEN, NOECHO);
+ passbuf[8] = '\0';
+ }
+ while (!checkpasswd(cuser.passwd, passbuf) &&
+ strcmp(STR_GUEST, cuser.userid));
+
+ currutmp->mode = mode0;
+ currutmp->destuid = destuid0;
+ currstat = stat0;
+
+ return 0;
+}
+
+int t_qchicken() {
+ char uident[STRLEN];
+
+ stand_title("¬d¸ßÃdª«");
+ usercomplete(msg_uid, uident);
+ if (uident[0])
+ chicken_query(uident);
+ return 0;
+}
+
+int t_query() {
+ char uident[STRLEN];
+
+ stand_title("¬d¸ßºô¤Í");
+ usercomplete(msg_uid, uident);
+ if (uident[0])
+ my_query(uident);
+ return 0;
+}
+
+int t_talk() {
+ char uident[16];
+ int tuid, unum, ucount;
+ userinfo_t *uentp;
+ char genbuf[4];
+/*
+ if (count_ulist() <= 1)
+ {
+ outs("¥Ø«e½u¤W¥u¦³±z¤@¤H¡A§ÖÁܽЪB¤Í¨Ó¥úÁ{¡i" BBSNAME "¡j§a¡I");
+ return XEASY;
+ }
+*/
+ stand_title("¥´¶}¸Ü§X¤l");
+ creat_list();
+ namecomplete(msg_uid, uident);
+ if (uident[0] == '\0')
+ return 0;
+
+ move(3, 0);
+ if (!(tuid = searchuser(uident)) || tuid == usernum)
+ {
+ outs(err_uid);
+ pressanykey();
+ return 0;
+ }
+
+/* multi-login check */
+ unum = 1;
+ while ((ucount = count_logins(tuid, 0)) > 1)
+ {
+ outs("(0) ¤£·Q talk ¤F...\n");
+ count_logins(tuid, 1);
+ getdata(1, 33, "½Ð¿ï¾Ü¤@­Ó²á¤Ñ¹ï¶H [0]¡G", genbuf, 4, DOECHO);
+ unum = atoi(genbuf);
+ if (unum == 0)
+ return 0;
+ move(3, 0);
+ clrtobot();
+ if (unum > 0 && unum <= ucount)
+ break;
+ }
+
+ if ((uentp = (userinfo_t *) search_ulistn(tuid, unum)))
+ my_talk(uentp, friend_stat(currutmp, uentp));
+
+ return 0;
+}
+
+/* ¦³¤H¨Ó¦êªù¤l¤F¡A¦^À³©I¥s¾¹ */
+static userinfo_t *uip;
+void talkreply() {
+ struct hostent *h;
+ char buf[4];
+ struct sockaddr_in sin;
+ char genbuf[200];
+ int a, sig = currutmp->sig;
+
+ talkrequest = NA;
+ uip = &utmpshm->uinfo[currutmp->destuip];
+ sprintf(page_requestor, "%s (%s)", uip->userid, uip->username);
+ currutmp->destuid = uip->uid;
+ currstat = XMODE; /* ÁקK¥X²{°Êµe */
+
+ clear();
+
+ prints("\n\n");
+ prints(" (Y) Åý§Ú­Ì %s §a¡I"
+ " (A) §Ú²{¦b«Ü¦£¡A½Ðµ¥¤@·|¨à¦A call §Ú\n", sig_des[sig]);
+ prints(" (N) §Ú²{¦b¤£·Q %s"
+ " (B) ¹ï¤£°_¡A§Ú¦³¨Æ±¡¤£¯à¸ò§A %s\n",
+ sig_des[sig], sig_des[sig]);
+ prints(" (C) ½Ð¤£­n§n§Ú¦n¶Ü¡H"
+ " (D) §Ú­nÂ÷¯¸Åo..¤U¦¸¦A²á§a.......\n");
+ prints(" (E) ¦³¨Æ¶Ü¡H½Ð¥ý¨Ó«H"
+ " (F) \033[1;33m§Ú¦Û¤v¿é¤J²z¥Ñ¦n¤F...\033[m\n");
+ prints(" (1) %s¡H¥ý®³100»È¨â¨Ó"
+ " (2) %s¡H¥ý®³1000»È¨â¨Ó..\n\n", sig_des[sig], sig_des[sig]);
+
+ getuser(uip->userid);
+ currutmp->msgs[0].pid = uip->pid;
+ strcpy(currutmp->msgs[0].userid, uip->userid);
+ strcpy(currutmp->msgs[0].last_call_in, "©I¥s¡B©I¥s¡AÅ¥¨ì½Ð¦^µª (Ctrl-R)");
+ prints("¹ï¤è¨Ó¦Û [%s]¡A¦@¤W¯¸ %d ¦¸¡A¤å³¹ %d ½g\n",
+ uip->from, xuser.numlogins, xuser.numposts);
+ showplans(uip->userid);
+ show_last_call_in(0);
+
+ sprintf(genbuf, "§A·Q¸ò %s %s°Ú¡H½Ð¿ï¾Ü(Y/N/A/B/C/D/E/F/1/2)[N] ",
+ page_requestor, sig_des[sig]);
+ getdata(0, 0, genbuf, buf, 4, LCECHO);
+
+ if (uip->mode != PAGE)
+ {
+ sprintf(genbuf, "%s¤w°±¤î©I¥s¡A«öEnterÄ~Äò...", page_requestor);
+ getdata(0, 0, genbuf, buf, 4, LCECHO);
+ return;
+ }
+ currutmp->msgcount = 0;
+ strcpy(save_page_requestor, page_requestor);
+ memset(page_requestor, 0, sizeof(page_requestor));
+ if (!(h = gethostbyname("localhost")))
+ {
+ perror("gethostbyname");
+ return;
+ }
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = h->h_addrtype;
+ memcpy(&sin.sin_addr, h->h_addr, h->h_length);
+ sin.sin_port = uip->sockaddr;
+ a = socket(sin.sin_family, SOCK_STREAM, 0);
+ if ((connect(a, (struct sockaddr *) &sin, sizeof(sin))))
+ {
+ perror("connect err");
+ return;
+ }
+ if (!buf[0] || !strchr("yabcdef12", buf[0]))
+ buf[0] = 'n';
+ write(a, buf, 1);
+ if (buf[0] == 'f' || buf[0] == 'F')
+ {
+ if (!getdata(b_lines, 0, "¤£¯àªº­ì¦]¡G", genbuf, 60, DOECHO))
+ strcpy(genbuf, "¤£§i¶D§A«¨ !! ^o^");
+ write(a, genbuf, 60);
+ }
+ uip->destuip = currutmp - &utmpshm->uinfo[0];
+ if (buf[0] == 'y')
+ switch (sig)
+ {
+ case SIG_DARK:
+ main_dark(a, uip);
+ break;
+ case SIG_PK:
+ chickenpk(a);
+ break;
+ case SIG_GOMO:
+ gomoku(a);
+ break;
+ case SIG_CHC:
+ chc(a);
+ break;
+ case SIG_TALK:
+ default:
+ do_talk(a);
+ }
+ else
+ close(a);
+ clear();
+}
+
+/* ºô¤Í°ÊºA²ªí */
+/* not used
+static int shortulist(userinfo_t * uentp) {
+ static int lineno, fullactive, linecnt;
+ static int moreactive, page, num;
+ char uentry[50];
+ int state;
+
+ if (!lineno)
+ {
+ lineno = 3;
+ page = moreactive ? (page + p_lines * 3) : 0;
+ linecnt = num = moreactive = 0;
+ move(1, 70);
+ prints("Page: %d", page / (p_lines) / 3 + 1);
+ move(lineno, 0);
+ }
+
+ if (uentp == NULL)
+ {
+ int finaltally;
+
+ clrtoeol();
+ move(++lineno, 0);
+ clrtobot();
+ finaltally = fullactive;
+ lineno = fullactive = 0;
+ return finaltally;
+ }
+ if ((!HAS_PERM(PERM_SYSOP) &&
+ !HAS_PERM(PERM_SEECLOAK) &&
+ uentp->invisible) ||
+ ((friend_stat(currutmp, uentp) & HRM) &&
+ !HAS_PERM(PERM_SYSOP)))
+ {
+ if (lineno >= b_lines)
+ return 0;
+ if (num++ < page)
+ return 0;
+ memset(uentry, ' ', 25);
+ uentry[25] = '\0';
+ }
+ else
+ {
+ fullactive++;
+ if (lineno >= b_lines)
+ {
+ moreactive = 1;
+ return 0;
+ }
+ if (num++ < page)
+ return 0;
+
+ state = (currutmp == uentp) ? 10 :
+ (friend_stat(currutmp,uentp)&ST_FRIEND)>>2;
+
+ if (PERM_HIDE(uentp))
+ state = 9;
+
+ sprintf(uentry, "%s%-13s%c%-10s%s ", fcolor[state],
+ uentp->userid, uentp->invisible ? '#' : ' ',
+ modestring(uentp, 1), state ? "\033[0m" : "");
+ }
+ if (++linecnt < 3)
+ {
+ strcat(uentry, "¢x");
+ outs(uentry);
+ }
+ else
+ {
+ outs(uentry);
+ linecnt = 0;
+ clrtoeol();
+ move(++lineno, 0);
+ }
+ return 0;
+}
+*/
diff --git a/mbbsd/term.c b/mbbsd/term.c
new file mode 100644
index 00000000..61a0128d
--- /dev/null
+++ b/mbbsd/term.c
@@ -0,0 +1,144 @@
+/* $Id: term.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <string.h>
+#include <syslog.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "proto.h"
+
+int tgetent(const char *bp, char *name);
+char *tgetstr(const char *id, char **area);
+int tgetflag(const char *id);
+int tgetnum(const char *id);
+int tputs(const char *str, int affcnt, int (*putc)(int));
+char *tparm(const char *str, ...);
+char *tgoto(const char *cap, int col, int row);
+
+static struct termios tty_state, tty_new;
+
+/* ----------------------------------------------------- */
+/* basic tty control */
+/* ----------------------------------------------------- */
+void init_tty() {
+ if(tcgetattr(1, &tty_state) < 0) {
+ syslog(LOG_ERR, "tcgetattr(): %m");
+ return;
+ }
+ memcpy(&tty_new, &tty_state, sizeof(tty_new));
+ tty_new.c_lflag &= ~(ICANON | ECHO | ISIG);
+/* tty_new.c_cc[VTIME] = 0;
+ tty_new.c_cc[VMIN] = 1; */
+ tcsetattr(1, TCSANOW, &tty_new);
+ system("stty raw -echo");
+}
+
+/* ----------------------------------------------------- */
+/* init tty control code */
+/* ----------------------------------------------------- */
+
+
+#define TERMCOMSIZE (40)
+
+char *clearbuf = "\33[H\33[J";
+int clearbuflen = 6;
+
+char *cleolbuf = "\33[K";
+int cleolbuflen = 3;
+
+char *scrollrev = "\33M";
+int scrollrevlen = 2;
+
+char *strtstandout = "\33[7m";
+int strtstandoutlen = 4;
+
+char *endstandout = "\33[m";
+int endstandoutlen = 3;
+
+int t_lines = 24;
+int b_lines = 23;
+int p_lines = 20;
+int t_columns = 80;
+
+int automargins = 1;
+
+static char *outp;
+static int *outlp;
+
+
+static int outcf(int ch) {
+ if(*outlp < TERMCOMSIZE) {
+ (*outlp)++;
+ *outp++ = ch;
+ }
+ return 0;
+}
+
+extern screenline_t *big_picture;
+
+static void term_resize(int sig) {
+ struct winsize newsize;
+ screenline_t *new_picture;
+
+ signal(SIGWINCH, SIG_IGN); /* Don't bother me! */
+ ioctl(0, TIOCGWINSZ, &newsize);
+ if(newsize.ws_row > t_lines) {
+ new_picture = (screenline_t *)calloc(newsize.ws_row,
+ sizeof(screenline_t));
+ if(new_picture == NULL) {
+ syslog(LOG_ERR, "calloc(): %m");
+ return;
+ }
+ free(big_picture);
+ big_picture = new_picture;
+ }
+
+ t_lines=newsize.ws_row;
+ b_lines=t_lines-1;
+ p_lines=t_lines-4;
+
+ signal(SIGWINCH, term_resize);
+}
+
+int term_init() {
+ signal(SIGWINCH, term_resize);
+ return YEA;
+}
+
+char term_buf[32];
+
+void do_move(int destcol, int destline) {
+ char buf[16], *p;
+
+ sprintf(buf, "\33[%d;%dH", destline + 1, destcol + 1);
+ for(p = buf; *p; p++)
+ ochar(*p);
+}
+
+void save_cursor() {
+ ochar('\33');
+ ochar('7');
+}
+
+void restore_cursor() {
+ ochar('\33');
+ ochar('8');
+}
+
+void change_scroll_range(int top, int bottom) {
+ char buf[16], *p;
+
+ sprintf(buf, "\33[%d;%dr", top + 1, bottom + 1);
+ for(p = buf; *p; p++)
+ ochar(*p);
+}
+
+void scroll_forward() {
+ ochar('\33');
+ ochar('D');
+}
diff --git a/mbbsd/toolkit.c b/mbbsd/toolkit.c
new file mode 100644
index 00000000..81a0d6f0
--- /dev/null
+++ b/mbbsd/toolkit.c
@@ -0,0 +1,14 @@
+/* $Id: toolkit.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <ctype.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+
+unsigned StringHash(unsigned char *s) {
+ unsigned int v=0;
+ while(*s) {
+ v = (v << 8) | (v >> 24);
+ v ^= toupper(*s++); /* note this is case insensitive */
+ }
+ return (v * 2654435769UL) >> (32 - HASH_BITS);
+}
diff --git a/mbbsd/topsong.c b/mbbsd/topsong.c
new file mode 100644
index 00000000..d3a65447
--- /dev/null
+++ b/mbbsd/topsong.c
@@ -0,0 +1,79 @@
+/* $Id: topsong.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "proto.h"
+
+#define MAX_SONGS 300
+#define QCAST int (*)(const void *, const void *)
+
+typedef struct songcmp_t {
+ char name[100];
+ char cname[100];
+ long int count;
+} songcmp_t;
+
+static long int totalcount=0;
+
+static int count_cmp(songcmp_t *b, songcmp_t *a) {
+ return (a->count - b->count);
+}
+
+int topsong() {
+ more(FN_TOPSONG,YEA);
+ return 0;
+}
+
+static int strip_blank(char *cbuf, char *buf) {
+ for(; *buf; buf++)
+ if(*buf != ' ')
+ *cbuf++ = *buf;
+ *cbuf = 0;
+ return 0;
+}
+
+void sortsong() {
+ FILE *fo, *fp = fopen(BBSHOME "/" FN_USSONG, "r");
+ songcmp_t songs[MAX_SONGS + 1];
+ int n;
+ char buf[256], cbuf[256];
+
+ memset(songs , 0, sizeof(songs));
+ if(!fp) return;
+ if(!(fo = fopen(FN_TOPSONG,"w"))) {
+ fclose(fp);
+ return;
+ }
+
+ totalcount = 0;
+ while(fgets(buf, 200, fp)) {
+ strtok(buf, "\n\r");
+ strip_blank(cbuf, buf);
+ if(!cbuf[0] || !isprint2(cbuf[0]))
+ continue;
+
+ for(n = 0; n < MAX_SONGS && songs[n].name[0]; n++)
+ if(!strcmp(songs[n].cname,cbuf))
+ break;
+ strcpy(songs[n].name, buf);
+ strcpy(songs[n].cname, cbuf);
+ songs[n].count++;
+ totalcount++;
+ }
+ qsort(songs, MAX_SONGS, sizeof(songcmp_t), (QCAST)count_cmp);
+ fprintf(fo,
+ " \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[32m¦@%ld¦¸\033[36m¢w¢w\033[m\n", totalcount);
+ for(n = 0; n < 100 && songs[n].name[0]; n++) {
+ fprintf(fo, " %5d. %-38.38s %4ld \033[32m[%.2f]\033[m\n", n + 1,
+ songs[n].name, songs[n].count,
+ (float)songs[n].count/totalcount);
+ }
+ fclose(fp);
+ fclose(fo);
+}
diff --git a/mbbsd/uptime b/mbbsd/uptime
new file mode 100644
index 00000000..4f8281fb
--- /dev/null
+++ b/mbbsd/uptime
@@ -0,0 +1,23 @@
+cache.c: if(fcache->busystate)
+cache.c: fcache->busystate = 1;
+cache.c: bzero(fcache->domain, sizeof fcache->domain);
+cache.c: fcache->top=0;
+cache.c: sscanf(buf,"%s",fcache->domain[fcache->top]);
+cache.c: po = buf + strlen(fcache->domain[fcache->top]);
+cache.c: strncpy(fcache->replace[fcache->top],po,49);
+cache.c: fcache->replace[fcache->top]
+cache.c: [strlen(fcache->replace[fcache->top])-1] = 0;
+cache.c: (fcache->top)++;
+cache.c: if(fcache->top == MAX_FROM)
+cache.c: fcache->max_user=0;
+cache.c: fcache->uptime = fcache->touchtime;
+cache.c: fcache->busystate = 0;
+cache.c: if(fcache->touchtime == 0)
+cache.c: fcache->touchtime = 1;
+cache.c: while(fcache->uptime < fcache->touchtime)
+mbbsd.c: for (j = 0; j < fcache->top; j++){
+mbbsd.c: char *token = strtok (fcache->domain[j], "&");
+mbbsd.c: if ((a = utmpshm->number) > fcache->max_user){
+mbbsd.c: fcache->max_user = a;
+mbbsd.c: fcache->max_time = now;
+talk.c: uentp->from_alias ? fcache->replace[uentp->from_alias] :
diff --git a/mbbsd/user.c b/mbbsd/user.c
new file mode 100644
index 00000000..41aacfa9
--- /dev/null
+++ b/mbbsd/user.c
@@ -0,0 +1,980 @@
+/* $Id: user.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "perm.h"
+#include "modes.h"
+#include "proto.h"
+
+extern int numboards;
+extern boardheader_t *bcache;
+extern char *loginview_file[NUMVIEWFILE][2];
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+extern time_t login_start_time;
+extern char *msg_uid;
+extern int usernum;
+extern char *msg_sure_ny;
+extern userinfo_t *currutmp;
+extern int showansi;
+extern char reset_color[];
+extern char *fn_proverb;
+extern char *fn_plans;
+extern char *msg_del_ok;
+extern char *fn_register;
+extern char *msg_nobody;
+extern userec_t cuser;
+extern userec_t xuser;
+
+static char *sex[8] = {
+ MSG_BIG_BOY, MSG_BIG_GIRL, MSG_LITTLE_BOY, MSG_LITTLE_GIRL,
+ MSG_MAN, MSG_WOMAN, MSG_PLANT, MSG_MIME
+};
+
+int u_loginview() {
+ int i;
+ unsigned int pbits = cuser.loginview;
+ char choice[5];
+
+ clear();
+ move(4,0);
+ for(i = 0; i < NUMVIEWFILE ; i++)
+ prints(" %c. %-20s %-15s \n", 'A' + i,
+ loginview_file[i][1],((pbits >> i) & 1 ? "£¾" : "¢æ"));
+
+ clrtobot();
+ while(getdata(b_lines - 1, 0, "½Ð«ö [A-N] ¤Á´«³]©w¡A«ö [Return] µ²§ô¡G",
+ choice, 3, LCECHO)) {
+ i = choice[0] - 'a';
+ if(i >= NUMVIEWFILE || i < 0)
+ bell();
+ else {
+ pbits ^= (1 << i);
+ move( i + 4 , 28 );
+ prints((pbits >> i) & 1 ? "£¾" : "¢æ");
+ }
+ }
+
+ if(pbits != cuser.loginview) {
+ cuser.loginview = pbits ;
+ passwd_update(usernum, &cuser);
+ }
+ return 0;
+}
+
+void user_display(userec_t *u, int real) {
+ int diff = 0;
+ char genbuf[200];
+
+ clrtobot();
+ prints(
+ " \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");
+ prints(" ¥N¸¹¼ÊºÙ: %s(%s)\n"
+ " ¯u¹ê©m¦W: %s\n"
+ " ©~¦í¦í§}: %s\n"
+ " ¹q¤l«H½c: %s\n"
+ " ©Ê §O: %s\n"
+ " »È¦æ±b¤á: %ld »È¨â\n",
+ u->userid, u->username, u->realname, u->address, u->email,
+ sex[u->sex % 8], u->money);
+
+ sethomedir(genbuf, u->userid);
+ prints(" ¨p¤H«H½c: %d «Ê (ÁʶR«H½c: %d «Ê)\n"
+ " ¨­¤ÀÃÒ¸¹: %s\n"
+ " ¤â¾÷¸¹½X: %010d\n"
+ " ¥Í ¤é: %02i/%02i/%02i\n"
+ " ¤pÂû¦W¦r: %s\n",
+ get_num_records(genbuf, sizeof(fileheader_t)),
+ u->exmailbox, u->ident, u->mobile,
+ u->month, u->day, u->year % 100, u->mychicken.name);
+ prints(" µù¥U¤é´Á: %s", ctime(&u->firstlogin));
+ prints(" «e¦¸¥úÁ{: %s", ctime(&u->lastlogin));
+ prints(" «e¦¸ÂIºq: %s", ctime(&u->lastsong));
+ prints(" ¤W¯¸¤å³¹: %d ¦¸ / %d ½g\n",
+ u->numlogins, u->numposts);
+
+ if(real) {
+ strcpy(genbuf, "bTCPRp#@XWBA#VSM0123456789ABCDEF");
+ for(diff = 0; diff < 32; diff++)
+ if(!(u->userlevel & (1 << diff)))
+ genbuf[diff] = '-';
+ prints(" »{ÃÒ¸ê®Æ: %s\n"
+ " userÅv­­: %s\n",
+ u->justify, genbuf);
+ } else {
+ diff = (time(0) - login_start_time) / 60;
+ prints(" °±¯d´Á¶¡: %d ¤p®É %2d ¤À\n",
+ diff / 60, diff % 60);
+ }
+
+ /* Thor: ·Q¬Ý¬Ý³o­Ó user ¬O¨º¨Çª©ªºª©¥D */
+ if(u->userlevel >= PERM_BM) {
+ int i;
+ boardheader_t *bhdr;
+
+ outs(" ¾á¥ôªO¥D: ");
+
+ for(i = 0, bhdr = bcache; i < numboards; i++, bhdr++) {
+ if(is_uBM(bhdr->BM,u->userid)) {
+ outs(bhdr->brdname);
+ outc(' ');
+ }
+ }
+ outc('\n');
+ }
+ outs(" \033[30;41m¢r¢s¢r¢s¢r¢s¢r¢s¢r¢s¢r¢s¢r¢s¢r¢s¢r¢s¢r¢s¢r¢s¢r"
+ "¢s¢r¢s¢r¢s¢r¢s\033[m");
+
+ outs((u->userlevel & PERM_LOGINOK) ?
+ "\n±zªºµù¥Uµ{§Ç¤w¸g§¹¦¨¡AÅwªï¥[¤J¥»¯¸" :
+ "\n¦pªG­n´£ª@Åv­­¡A½Ð°Ñ¦Ò¥»¯¸¤½§GÄæ¿ì²zµù¥U");
+
+#ifdef NEWUSER_LIMIT
+ if((u->lastlogin - u->firstlogin < 3 * 86400) && !HAS_PERM(PERM_POST))
+ outs("\n·s¤â¤W¸ô¡A¤T¤Ñ«á¶}©ñÅv­­");
+#endif
+}
+
+void mail_violatelaw(char* crime, char* police, char* reason, char* result){
+ char genbuf[200];
+ fileheader_t fhdr;
+ time_t now;
+ FILE *fp;
+ sprintf(genbuf, "home/%c/%s", crime[0], crime);
+ stampfile(genbuf, &fhdr);
+ if(!(fp = fopen(genbuf,"w")))
+ return;
+ now = time(NULL);
+ fprintf(fp, "§@ªÌ: [Pttªk°|]\n"
+ "¼ÐÃD: [³ø§i] ¹Hªk§P¨M³ø§i\n"
+ "®É¶¡: %s\n"
+ "\033[1;32m%s\033[m§P¨M¡G\n \033[1;32m%s\033[m"
+ "¦]\033[1;35m%s\033[m¦æ¬°¡A\n¹H¤Ï¥»¯¸¯¸³W¡A³B¥H\033[1;35m%s\033[m¡A¯S¦¹³qª¾"
+ "\n½Ð¨ì PttLaw ¬d¸ß¬ÛÃöªk³W¸ê°T¡A¨Ã¨ì Play-Pay-ViolateLaw ú¥æ»@³æ",
+ ctime(&now), police, crime, reason, result);
+ fclose(fp);
+ sprintf(fhdr.title, "[³ø§i] ¹Hªk§P¨M³ø§i");
+ strcpy(fhdr.owner, "[Pttªk°|]");
+ sprintf(genbuf, "home/%c/%s/.DIR", crime[0], crime);
+ append_record(genbuf, &fhdr, sizeof(fhdr));
+}
+
+static void violate_law(userec_t *u, int unum){
+ char ans[4], ans2[4];
+ char reason[128];
+ move(1,0);
+ clrtobot();
+ move(2,0);
+ prints("(1)Cross-post (2)¶Ãµo¼s§i«H (3)¶Ãµo³sÂê«H\n");
+ prints("(4)ÄÌÂZ¯¸¤W¨Ï¥ÎªÌ (8)¨ä¥L¥H»@³æ³B¸m¦æ¬°\n(9)¬å id ¦æ¬°\n");
+ getdata(5, 0, "(0)µ²§ô",
+ ans, 3, DOECHO);
+ switch(ans[0]){
+ case '1':
+ sprintf(reason, "%s", "Cross-post");
+ break;
+ case '2':
+ sprintf(reason, "%s", "¶Ãµo¼s§i«H");
+ break;
+ case '3':
+ sprintf(reason, "%s", "¶Ãµo³sÂê«H");
+ break;
+ case '4':
+ while(!getdata(7, 0, "½Ð¿é¤J³QÀËÁ|²z¥Ñ¥H¥Ü­t³d¡G", reason, 50, DOECHO));
+ strcat(reason, "[ÄÌÂZ¯¸¤W¨Ï¥ÎªÌ]");
+ break;
+ case '8':
+ case '9':
+ while(!getdata(6, 0, "½Ð¿é¤J²z¥Ñ¥H¥Ü­t³d¡G", reason, 50, DOECHO));
+ break;
+ default:
+ return;
+ }
+ getdata(7, 0, msg_sure_ny, ans2, 3, LCECHO);
+ if(*ans2 != 'y')
+ return;
+ if (ans[0]=='9'){
+ char src[STRLEN], dst[STRLEN];
+ sprintf(src, "home/%c/%s", u->userid[0], u->userid);
+ sprintf(dst, "tmp/%s", u->userid);
+ Rename(src, dst);
+ log_usies("KILL", u->userid);
+ post_violatelaw(u->userid, cuser.userid, reason, "¬å°£ ID");
+ u->userid[0] = '\0';
+ setuserid(unum, u->userid);
+ passwd_update(unum, u);
+ }
+ else{
+ u->userlevel |= PERM_VIOLATELAW;
+ u->vl_count ++;
+ passwd_update(unum, u);
+ post_violatelaw(u->userid, cuser.userid, reason, "»@³æ³B¥÷");
+ mail_violatelaw(u->userid, cuser.userid, reason, "»@³æ³B¥÷");
+ }
+ pressanykey();
+}
+
+extern char* str_permid[];
+
+void uinfo_query(userec_t *u, int real, int unum) {
+ userec_t x;
+ register int i = 0, fail, mail_changed;
+ char ans[4], buf[STRLEN], *p;
+ char genbuf[200], reason[50];
+ unsigned long int money = 0;
+ fileheader_t fhdr;
+ int flag = 0, temp = 0, money_change = 0;
+ time_t now;
+
+ FILE *fp;
+
+ fail = mail_changed = 0;
+
+ memcpy(&x, u, sizeof(userec_t));
+ getdata(b_lines - 1, 0, real ?
+ "(1)§ï¸ê®Æ(2)³]±K½X(3)³]Åv­­(4)¬å±b¸¹(5)§ïID"
+ "(6)±þ/´_¬¡Ãdª«(7)¼f§P [0]µ²§ô " :
+ "½Ð¿ï¾Ü (1)­×§ï¸ê®Æ (2)³]©w±K½X ==> [0]µ²§ô ",
+ ans, 3, DOECHO);
+
+ if(ans[0] > '2' && !real)
+ ans[0] = '0';
+
+ if(ans[0] == '1' || ans[0] == '3') {
+ clear();
+ i = 2;
+ move(i++, 0);
+ outs(msg_uid);
+ outs(x.userid);
+ }
+
+ switch(ans[0]) {
+ case '7':
+ violate_law(&x, unum);
+ return;
+ case '1':
+ move(0, 0);
+ outs("½Ð³v¶µ­×§ï¡C");
+
+ getdata_buf(i++, 0," ¼Ê ºÙ ¡G",x.username, 24, DOECHO);
+ if(real) {
+ getdata_buf(i++, 0, "¯u¹ê©m¦W¡G", x.realname, 20, DOECHO);
+ getdata_buf(i++, 0, "¨­¤ÀÃÒ¸¹¡G", x.ident, 11, DOECHO);
+ getdata_buf(i++, 0, "©~¦í¦a§}¡G", x.address, 50, DOECHO);
+ }
+ sprintf(buf, "%010d", x.mobile);
+ getdata_buf(i++, 0, "¤â¾÷¸¹½X¡G", buf, 11, LCECHO);
+ x.mobile=atoi(buf);
+ getdata_str(i++, 0, "¹q¤l«H½c[ÅÜ°Ê­n­«·s»{ÃÒ]¡G", buf, 50, DOECHO,
+ x.email);
+ if(strcmp(buf,x.email) && strchr(buf, '@')) {
+ strcpy(x.email,buf);
+ mail_changed = 1 - real;
+ }
+
+ sprintf(genbuf, "%i", (u->sex + 1) % 8);
+ getdata_str(i++, 0, "©Ê§O (1)¸¯®æ (2)©j±µ (3)©³­} (4)¬ü¬Ü (5)Á¦¨û "
+ "(6)ªü«¼ (7)´Óª« (8)Äqª«¡G",
+ buf, 3, DOECHO,genbuf);
+ if(buf[0] >= '1' && buf[0] <= '8')
+ x.sex = (buf[0] - '1') % 8;
+ else
+ x.sex = u->sex % 8;
+
+ while(1) {
+ int len;
+
+ sprintf(genbuf, "%02i/%02i/%02i",
+ u->month, u->day, u->year % 100);
+ len = getdata_str(i, 0, "¥Í¤é ¤ë¤ë/¤é¤é/¦è¤¸¡G", buf, 9,
+ DOECHO,genbuf);
+ if(len && len != 8)
+ continue;
+ if(!len) {
+ x.month = u->month;
+ x.day = u->day;
+ x.year = u->year;
+ } else if(len == 8) {
+ x.month = (buf[0] - '0') * 10 + (buf[1] - '0');
+ x.day = (buf[3] - '0') * 10 + (buf[4] - '0');
+ x.year = (buf[6] - '0') * 10 + (buf[7] - '0');
+ } else
+ continue;
+ if(!real && (x.month > 12 || x.month < 1 || x.day > 31 ||
+ x.day < 1 || x.year > 90 || x.year < 40))
+ continue;
+ i++;
+ break;
+ }
+ if(real) {
+ unsigned long int l;
+ if(HAS_PERM(PERM_BBSADM)) {
+ sprintf(genbuf, "%d", x.money);
+ if(getdata_str(i++, 0,"»È¦æ±b¤á¡G", buf, 10, DOECHO,genbuf))
+ if((l = atol(buf)) >= 0) {
+ if(l != x.money) {
+ money_change = 1;
+ money = x.money;
+ x.money = l;
+ }
+ }
+ }
+ sprintf(genbuf, "%d", x.exmailbox);
+ if(getdata_str(i++, 0,"ÁʶR«H½c¼Æ¡G", buf, 4, DOECHO,genbuf))
+ if((l = atol(buf)) >= 0)
+ x.exmailbox = (int)l;
+
+ getdata_buf(i++, 0, "»{ÃÒ¸ê®Æ¡G", x.justify, 44, DOECHO);
+ getdata_buf(i++, 0, "³Ìªñ¥úÁ{¾÷¾¹¡G", x.lasthost, 16, DOECHO);
+
+ sprintf(genbuf, "%d", x.numlogins);
+ if(getdata_str(i++, 0,"¤W½u¦¸¼Æ¡G", buf, 10, DOECHO,genbuf))
+ if((fail = atoi(buf)) >= 0)
+ x.numlogins = fail;
+
+ sprintf(genbuf,"%d", u->numposts);
+ if(getdata_str(i++, 0, "¤å³¹¼Æ¥Ø¡G", buf, 10, DOECHO,genbuf))
+ if((fail = atoi(buf)) >= 0)
+ x.numposts = fail;
+ sprintf(genbuf, "%d", u->vl_count);
+ if (getdata_str(i++, 0, "¹Hªk°O¿ý¡G", buf, 10, DOECHO, genbuf))
+ if ((fail = atoi(buf)) >= 0)
+ x.vl_count = fail;
+
+ sprintf(genbuf, "%d/%d/%d", u->five_win, u->five_lose,
+ u->five_tie);
+ if(getdata_str(i++, 0, "¤­¤l´Ñ¾ÔÁZ ³Ó/±Ñ/©M¡G", buf, 16, DOECHO,
+ genbuf))
+ while(1) {
+ p = strtok(buf, "/\r\n");
+ if(!p) break;
+ x.five_win = atoi(p);
+ p = strtok(NULL, "/\r\n");
+ if(!p) break;
+ x.five_lose = atoi(p);
+ p = strtok(NULL, "/\r\n");
+ if(!p) break;
+ x.five_tie = atoi(p);
+ break;
+ }
+ sprintf(genbuf, "%d/%d/%d", u->chc_win, u->chc_lose, u->chc_tie);
+ if(getdata_str(i++, 0, "¶H´Ñ¾ÔÁZ ³Ó/±Ñ/©M¡G", buf, 16, DOECHO,
+ genbuf))
+ while(1) {
+ p = strtok(buf, "/\r\n");
+ if(!p) break;
+ x.chc_win = atoi(p);
+ p = strtok(NULL, "/\r\n");
+ if(!p) break;
+ x.chc_lose = atoi(p);
+ p = strtok(NULL, "/\r\n");
+ if(!p) break;
+ x.chc_tie = atoi(p);
+ break;
+ }
+ fail = 0;
+ }
+ break;
+
+ case '2':
+ i = 19;
+ if(!real) {
+ if(!getdata(i++, 0, "½Ð¿é¤J­ì±K½X¡G", buf, PASSLEN, NOECHO) ||
+ !checkpasswd(u->passwd, buf)) {
+ outs("\n\n±z¿é¤Jªº±K½X¤£¥¿½T\n");
+ fail++;
+ break;
+ }
+ }
+ else{
+ char witness[3][32];
+ time_t now = time(NULL);
+ for(i=0;i<3;i++){
+ if(!getdata(19+i, 0, "½Ð¿é¤J¨ó§UÃÒ©ú¤§¨Ï¥ÎªÌ¡G", witness[i], 32, DOECHO)){
+ outs("\n¤£¿é¤J«hµLªk§ó§ï\n");
+ fail++;
+ break;
+ }
+ else if (!getuser(witness[i])){
+ outs("\n¬dµL¦¹¨Ï¥ÎªÌ\n");
+ fail++;
+ break;
+ }
+ else if (now - xuser.firstlogin < 6*30*24*60*60){
+ outs("\nµù¥U¥¼¶W¹L¥b¦~¡A½Ð­«·s¿é¤J\n");
+ i--;
+ }
+ }
+ if (i < 3)
+ break;
+ else
+ i = 20;
+ }
+
+ if(!getdata(i++, 0, "½Ð³]©w·s±K½X¡G", buf, PASSLEN, NOECHO)) {
+ outs("\n\n±K½X³]©w¨ú®ø, Ä~Äò¨Ï¥Î±K½X\n");
+ fail++;
+ break;
+ }
+ strncpy(genbuf, buf, PASSLEN);
+
+ getdata(i++, 0, "½ÐÀˬd·s±K½X¡G", buf, PASSLEN, NOECHO);
+ if(strncmp(buf, genbuf, PASSLEN)) {
+ outs("\n\n·s±K½X½T»{¥¢±Ñ, µLªk³]©w·s±K½X\n");
+ fail++;
+ break;
+ }
+ buf[8] = '\0';
+ strncpy(x.passwd, genpasswd(buf), PASSLEN);
+ if (real)
+ x.userlevel &= (!PERM_LOGINOK);
+ break;
+
+ case '3':
+ i = setperms(x.userlevel, str_permid);
+ if(i == x.userlevel)
+ fail++;
+ else {
+ flag=1;
+ temp=x.userlevel;
+ x.userlevel = i;
+ }
+ break;
+
+ case '4':
+ i = QUIT;
+ break;
+
+ case '5':
+ if (getdata_str(b_lines - 3, 0, "·sªº¨Ï¥ÎªÌ¥N¸¹¡G", genbuf, IDLEN + 1,
+ DOECHO,x.userid)) {
+ if(searchuser(genbuf)) {
+ outs("¿ù»~! ¤w¸g¦³¦P¼Ë ID ªº¨Ï¥ÎªÌ");
+ fail++;
+ } else
+ strcpy(x.userid, genbuf);
+ }
+ break;
+ case '6':
+ if(x.mychicken.name[0])
+ x.mychicken.name[0] = 0;
+ else
+ strcpy(x.mychicken.name,"[¦º]");
+ break;
+ default:
+ return;
+ }
+
+ if(fail) {
+ pressanykey();
+ return;
+ }
+
+ getdata(b_lines - 1, 0, msg_sure_ny, ans, 3, LCECHO);
+ if(*ans == 'y') {
+ if(flag)
+ post_change_perm(temp,i,cuser.userid,x.userid);
+ if(strcmp(u->userid, x.userid)) {
+ char src[STRLEN], dst[STRLEN];
+
+ sethomepath(src, u->userid);
+ sethomepath(dst, x.userid);
+ Rename(src, dst);
+ setuserid(unum, x.userid);
+ }
+ memcpy(u, &x, sizeof(x));
+ if(mail_changed) {
+#ifdef EMAIL_JUSTIFY
+ x.userlevel &= ~PERM_LOGINOK;
+ mail_justify();
+#endif
+ }
+
+ if(i == QUIT) {
+ char src[STRLEN], dst[STRLEN];
+
+ sprintf(src, "home/%c/%s", x.userid[0], x.userid);
+ sprintf(dst, "tmp/%s", x.userid);
+ if(Rename(src, dst)) {
+ sprintf(genbuf, "/bin/rm -fr %s >/dev/null 2>&1", src);
+/* do not remove
+ system(genbuf);
+*/
+ }
+ log_usies("KILL", x.userid);
+ x.userid[0] = '\0';
+ setuserid(unum, x.userid);
+ } else
+ log_usies("SetUser", x.userid);
+ if(money_change)
+ setumoney(unum,x.money);
+ passwd_update(unum, &x);
+ now = time(0);
+ if(money_change) {
+ strcpy(genbuf, "boards/Security");
+ stampfile(genbuf, &fhdr);
+ if(!(fp = fopen(genbuf,"w")))
+ return;
+
+ now = time(NULL);
+ fprintf(fp, "§@ªÌ: [¨t²Î¦w¥þ§½] ¬ÝªO: Security\n"
+ "¼ÐÃD: [¤½¦w³ø§i] ¯¸ªø­×§ïª÷¿ú³ø§i\n"
+ "®É¶¡: %s\n"
+ " ¯¸ªø\033[1;32m%s\033[m§â\033[1;32m%s\033[m"
+ "ªº¿ú±q\033[1;35m%ld\033[m§ï¦¨\033[1;35m%d\033[m",
+ ctime(&now), cuser.userid, x.userid, money, x.money);
+
+ clrtobot ();
+ clear();
+ while(!getdata(5, 0, "½Ð¿é¤J²z¥Ñ¥H¥Ü­t³d¡G", reason, 60, DOECHO));
+
+ fprintf(fp, "\n \033[1;37m¯¸ªø%s­×§ï¿ú²z¥Ñ¬O¡G%s\033[m",
+ cuser.userid, reason);
+ fclose(fp);
+ sprintf(fhdr.title, "[¤½¦w³ø§i] ¯¸ªø%s­×§ï%s¿ú³ø§i", cuser.userid,
+ x.userid);
+ strcpy(fhdr.owner, "[¨t²Î¦w¥þ§½]");
+ append_record("boards/Security/.DIR", &fhdr, sizeof(fhdr));
+ }
+ }
+}
+
+int u_info() {
+ move(2, 0);
+ user_display(&cuser, 0);
+ uinfo_query(&cuser, 0, usernum);
+ strcpy(currutmp->realname, cuser.realname);
+ strcpy(currutmp->username, cuser.username);
+ return 0;
+}
+
+int u_ansi() {
+ showansi ^= 1;
+ cuser.uflag ^= COLOR_FLAG;
+ outs(reset_color);
+ return 0;
+}
+
+int u_cloak() {
+ outs((currutmp->invisible ^= 1) ? MSG_CLOAKED : MSG_UNCLOAK);
+ return XEASY;
+}
+
+int u_switchproverb() {
+/* char *state[4]={"¥Î¥\\«¬","¦w¶h«¬","¦Û©w«¬","SHUTUP"}; */
+ char buf[100];
+
+ cuser.proverb =(cuser.proverb +1) %4;
+ setuserfile(buf,fn_proverb);
+ if(cuser.proverb==2 && dashd(buf)) {
+ FILE *fp = fopen(buf,"a");
+
+ fprintf(fp,"®y¥k»Êª¬ºA¬°[¦Û©w«¬]­n°O±o³]®y¥k»Êªº¤º®e­ò!!");
+ fclose(fp);
+ }
+ passwd_update(usernum, &cuser);
+ return 0;
+}
+
+int u_editproverb() {
+ char buf[100];
+
+ setutmpmode(PROVERB);
+ setuserfile(buf,fn_proverb);
+ move(1,0);
+ clrtobot();
+ outs("\n\n ½Ð¤@¦æ¤@¦æ¨Ì§ÇÁä¤J·Q¨t²Î´£¿ô§Aªº¤º®e,\n"
+ " Àx¦s«á°O±o§âª¬ºA³]¬° [¦Û©w«¬] ¤~¦³§@¥Î\n"
+ " ®y¥k»Ê³Ì¦h100±ø");
+ pressanykey();
+ vedit(buf,NA, NULL);
+ return 0;
+}
+
+void showplans(char *uid) {
+ char genbuf[200];
+
+ sethomefile(genbuf, uid, fn_plans);
+ if(!show_file(genbuf, 7, MAX_QUERYLINES, ONLY_COLOR))
+ prints("¡m­Ó¤H¦W¤ù¡n%s ¥Ø«e¨S¦³¦W¤ù", uid);
+}
+
+int showsignature(char *fname) {
+ FILE *fp;
+ char buf[256];
+ int i, j;
+ char ch;
+
+ clear();
+ move(2, 0);
+ setuserfile(fname, "sig.0");
+ j = strlen(fname) - 1;
+
+ for(ch = '1'; ch <= '9'; ch++) {
+ fname[j] = ch;
+ if((fp = fopen(fname, "r"))) {
+ prints("\033[36m¡i ñ¦WÀÉ.%c ¡j\033[m\n", ch);
+ for(i = 0; i++ < MAX_SIGLINES && fgets(buf, 256, fp); outs(buf));
+ fclose(fp);
+ }
+ }
+ return j;
+}
+
+int u_editsig() {
+ int aborted;
+ char ans[4];
+ int j;
+ char genbuf[200];
+
+ j = showsignature(genbuf);
+
+ getdata(0, 0, "ñ¦WÀÉ (E)½s¿è (D)§R°£ (Q)¨ú®ø¡H[Q] ", ans, 4, LCECHO);
+
+ aborted = 0;
+ if(ans[0] == 'd')
+ aborted = 1;
+ if(ans[0] == 'e')
+ aborted = 2;
+
+ if(aborted) {
+ if(!getdata(1, 0, "½Ð¿ï¾Üñ¦WÀÉ(1-9)¡H[1] ", ans, 4, DOECHO))
+ ans[0] = '1';
+ if(ans[0] >= '1' && ans[0] <= '9') {
+ genbuf[j] = ans[0];
+ if(aborted == 1) {
+ unlink(genbuf);
+ outs(msg_del_ok);
+ } else {
+ setutmpmode(EDITSIG);
+ aborted = vedit(genbuf, NA, NULL);
+ if(aborted != -1)
+ outs("ñ¦WÀɧó·s§¹²¦");
+ }
+ }
+ pressanykey();
+ }
+ return 0;
+}
+
+int u_editplan() {
+ char genbuf[200];
+
+ getdata(b_lines - 1, 0, "¦W¤ù (D)§R°£ (E)½s¿è [Q]¨ú®ø¡H[Q] ",
+ genbuf, 3, LCECHO);
+
+ if(genbuf[0] == 'e') {
+ int aborted;
+
+ setutmpmode(EDITPLAN);
+ setuserfile(genbuf, fn_plans);
+ aborted = vedit(genbuf, NA, NULL);
+ if(aborted != -1)
+ outs("¦W¤ù§ó·s§¹²¦");
+ pressanykey();
+ return 0;
+ } else if(genbuf[0] == 'd') {
+ setuserfile(genbuf, fn_plans);
+ unlink(genbuf);
+ outmsg("¦W¤ù§R°£§¹²¦");
+ }
+ return 0;
+}
+
+int u_editcalendar() {
+ char genbuf[200];
+
+ getdata(b_lines - 1, 0, "¦æ¨Æ¾ä (D)§R°£ (E)½s¿è [Q]¨ú®ø¡H[Q] ",
+ genbuf, 3, LCECHO);
+
+ if(genbuf[0] == 'e') {
+ int aborted;
+
+ setutmpmode(EDITPLAN);
+ setcalfile(genbuf, cuser.userid);
+ aborted = vedit(genbuf, NA, NULL);
+ if(aborted != -1)
+ outs("¦æ¨Æ¾ä§ó·s§¹²¦");
+ pressanykey();
+ return 0;
+ } else if(genbuf[0] == 'd') {
+ setcalfile(genbuf, cuser.userid);
+ unlink(genbuf);
+ outmsg("¦æ¨Æ¾ä§R°£§¹²¦");
+ }
+ return 0;
+}
+
+/* ¨Ï¥ÎªÌ¶ñ¼gµù¥Uªí®æ */
+static void getfield(int line, char *info, char *desc, char *buf, int len) {
+ char prompt[STRLEN];
+ char genbuf[200];
+
+ sprintf(genbuf, "­ì¥ý³]©w¡G%-30.30s (%s)", buf, info);
+ move(line, 2);
+ outs(genbuf);
+ sprintf(prompt, "%s¡G", desc);
+ if(getdata_str(line + 1, 2, prompt, genbuf, len, DOECHO, buf))
+ strcpy(buf, genbuf);
+ move(line, 2);
+ prints("%s¡G%s", desc, buf);
+ clrtoeol();
+}
+
+static int removespace(char* s){
+ int i, index;
+
+ for(i=0, index=0;s[i];i++){
+ if (s[i] != ' ')
+ s[index++] = s[i];
+ }
+ s[index] = '\0';
+ return index;
+}
+
+int u_register() {
+ char rname[20], addr[50], ident[11], mobile[20];
+ char phone[20], career[40], email[50],birthday[9],sex_is[2],year,mon,day;
+ char ans[3], *ptr;
+ FILE *fn;
+ time_t now;
+ char genbuf[200];
+
+ if(cuser.userlevel & PERM_LOGINOK) {
+ outs("±zªº¨­¥÷½T»{¤w¸g§¹¦¨¡A¤£»Ý¶ñ¼g¥Ó½Ðªí");
+ return XEASY;
+ }
+ if((fn = fopen(fn_register, "r"))) {
+ while(fgets(genbuf, STRLEN, fn)) {
+ if((ptr = strchr(genbuf, '\n')))
+ *ptr = '\0';
+ if(strncmp(genbuf, "uid: ", 5) == 0 &&
+ strcmp(genbuf + 5, cuser.userid) == 0) {
+ fclose(fn);
+ outs("±zªºµù¥U¥Ó½Ð³æ©|¦b³B²z¤¤¡A½Ð­@¤ßµ¥­Ô");
+ return XEASY;
+ }
+ }
+ fclose(fn);
+ }
+
+ getdata(b_lines - 1, 0, "±z½T©w­n¶ñ¼gµù¥U³æ¶Ü(Y/N)¡H[N] ", ans, 3, LCECHO);
+ if(ans[0] != 'y')
+ return FULLUPDATE;
+
+ move(2, 0);
+ clrtobot();
+ strcpy(ident, cuser.ident);
+ strcpy(rname, cuser.realname);
+ strcpy(addr, cuser.address);
+ strcpy(email, cuser.email);
+ sprintf(mobile,"0%09d",cuser.mobile);
+ sprintf(birthday, "%02i/%02i/%02i",
+ cuser.month, cuser.day, cuser.year % 100);
+ sex_is[0]=(cuser.sex % 8)+'1';sex_is[1]=0;
+ career[0] = phone[0] = '\0';
+ while(1) {
+ clear();
+ move(1, 0);
+ prints("%s(%s) ±z¦n¡A½Ð¾Ú¹ê¶ñ¼g¥H¤Uªº¸ê®Æ:",
+ cuser.userid, cuser.username);
+ do{
+ getfield(3, "D120908396", "¨­¤ÀÃÒ¸¹", ident, 11);
+ }while(removespace(ident)<10 || !isalpha(ident[0]));
+ do{
+ getfield(5, "½Ð¥Î¤¤¤å", "¯u¹ê©m¦W", rname, 20);
+ }while(!removespace(rname) || isalpha(rname[0]));
+ do{
+ getfield(7, "¾Ç®Õ¨t¯Å©Î³æ¦ì¾ºÙ", "ªA°È³æ¦ì", career, 40);
+ }while(!removespace(career));
+ do{
+ getfield(9, "¥]¬A¹ì«Ç©ÎªùµP¸¹½X", "¥Ø«e¦í§}", addr, 50);
+ }while(!(addr[0]));
+ do{
+ getfield(11, "¥]¬Aªø³~¼·¸¹°Ï°ì½X", "³sµ¸¹q¸Ü", phone, 20);
+ }while(!removespace(phone));
+ getfield(13, "¥u¿é¤J¼Æ¦r ¦p:0912345678", "¤â¾÷¸¹½X", mobile, 20);
+ while(1) {
+ int len;
+
+ getfield(15,"¤ë¤ë/¤é¤é/¦è¤¸ ¦p:09/27/76","¥Í¤é",birthday,9);
+ len = strlen(birthday);
+ if(!len) {
+ sprintf(birthday, "%02i/%02i/%02i",
+ cuser.month, cuser.day, cuser.year % 100);
+ mon = cuser.month;
+ day = cuser.day;
+ year = cuser.year;
+ } else if(len == 8) {
+ mon = (birthday[0] - '0') * 10 + (birthday[1] - '0');
+ day = (birthday[3] - '0') * 10 + (birthday[4] - '0');
+ year = (birthday[6] - '0') * 10 + (birthday[7] - '0');
+ } else
+ continue;
+ if(mon > 12 || mon < 1 || day > 31 || day < 1 || year > 90 ||
+ year < 40)
+ continue;
+ break;
+ }
+ getfield(17, "1.¸¯®æ 2.©j±µ ", "©Ê§O", sex_is, 2);
+ getfield(19, "¨­¤À»{ÃÒ¥Î", "E-Mail Address", email, 50);
+
+ getdata(b_lines - 1, 0, "¥H¤W¸ê®Æ¬O§_¥¿½T(Y/N)¡H(Q)¨ú®øµù¥U [N] ",
+ ans, 3, LCECHO);
+ if(ans[0] == 'q')
+ return 0;
+ if(ans[0] == 'y')
+ break;
+ }
+ strcpy(cuser.ident, ident);
+ strcpy(cuser.realname, rname);
+ strcpy(cuser.address, addr);
+ strcpy(cuser.email, email);
+ cuser.mobile = atoi(mobile);
+ cuser.sex= (sex_is[0] - '1') % 8;
+ cuser.month = mon;
+ cuser.day = day;
+ cuser.year = year;
+ if((fn = fopen(fn_register, "a"))) {
+ now = time(NULL);
+ trim(career);
+ trim(addr);
+ trim(phone);
+ fprintf(fn, "num: %d, %s", usernum, ctime(&now));
+ fprintf(fn, "uid: %s\n", cuser.userid);
+ fprintf(fn, "ident: %s\n", ident);
+ fprintf(fn, "name: %s\n", rname);
+ fprintf(fn, "career: %s\n", career);
+ fprintf(fn, "addr: %s\n", addr);
+ fprintf(fn, "phone: %s\n", phone);
+ fprintf(fn, "mobile: %s\n", mobile);
+ fprintf(fn, "email: %s\n", email);
+ fprintf(fn, "----\n");
+ fclose(fn);
+ }
+ clear();
+ move(9,3);
+ prints("³Ì«áPost¤@½g\033[32m¦Û§Ú¤¶²Ð¤å³¹\033[mµ¹¤j®a§a¡A"
+ "§i¶D©Ò¦³¦Ñ°©ÀY\033[31m§Ú¨Ó°Õ^$¡C\\n\n\n\n");
+ pressanykey();
+ cuser.userlevel |= PERM_POST;
+ brc_initial("WhoAmI");
+ set_board();
+ do_post();
+ cuser.userlevel &= ~PERM_POST;
+ return 0;
+}
+
+/* ¦C¥X©Ò¦³µù¥U¨Ï¥ÎªÌ */
+extern struct uhash_t *uhash;
+static int usercounter, totalusers, showrealname;
+static ushort u_list_special;
+
+static int u_list_CB(userec_t *uentp) {
+ static int i;
+ char permstr[8], *ptr;
+ register int level;
+
+ if(uentp == NULL) {
+ move(2, 0);
+ clrtoeol();
+ prints("\033[7m ¨Ï¥ÎªÌ¥N¸¹ %-25s ¤W¯¸ ¤å³¹ %s "
+ "³Ìªñ¥úÁ{¤é´Á \033[0m\n",
+ showrealname ? "¯u¹ê©m¦W" : "ºï¸¹¼ÊºÙ",
+ HAS_PERM(PERM_SEEULEVELS) ? "µ¥¯Å" : "");
+ i = 3;
+ return 0;
+ }
+
+ if(bad_user_id(uentp->userid))
+ return 0;
+
+ if((uentp->userlevel & ~(u_list_special)) == 0)
+ return 0;
+
+ if(i == b_lines) {
+ prints("\033[34;46m ¤wÅã¥Ü %d/%d ¤H(%d%%) \033[31;47m "
+ "(Space)\033[30m ¬Ý¤U¤@­¶ \033[31m(Q)\033[30m Â÷¶} \033[m",
+ usercounter, totalusers, usercounter * 100 / totalusers);
+ i = igetch();
+ if(i == 'q' || i == 'Q')
+ return QUIT;
+ i = 3;
+ }
+ if(i == 3) {
+ move(3, 0);
+ clrtobot();
+ }
+
+ level = uentp->userlevel;
+ strcpy(permstr, "----");
+ if(level & PERM_SYSOP)
+ permstr[0] = 'S';
+ else if(level & PERM_ACCOUNTS)
+ permstr[0] = 'A';
+ else if(level & PERM_DENYPOST)
+ permstr[0] = 'p';
+
+ if(level & (PERM_BOARD))
+ permstr[1] = 'B';
+ else if(level & (PERM_BM))
+ permstr[1] = 'b';
+
+ if(level & (PERM_XEMPT))
+ permstr[2] = 'X';
+ else if(level & (PERM_LOGINOK))
+ permstr[2] = 'R';
+
+ if(level & (PERM_CLOAK | PERM_SEECLOAK))
+ permstr[3] = 'C';
+
+ ptr = (char *)Cdate(&uentp->lastlogin);
+ ptr[18] = '\0';
+ prints("%-14s %-27.27s%5d %5d %s %s\n",
+ uentp->userid,
+ showrealname ? uentp->realname : uentp->username,
+ uentp->numlogins, uentp->numposts,
+ HAS_PERM(PERM_SEEULEVELS) ? permstr : "", ptr);
+ usercounter++;
+ i++;
+ return 0;
+}
+
+int u_list() {
+ char genbuf[3];
+
+ setutmpmode(LAUSERS);
+ showrealname = u_list_special = usercounter = 0;
+ totalusers = uhash->number;
+ if(HAS_PERM(PERM_SEEULEVELS)) {
+ getdata(b_lines - 1, 0, "Æ[¬Ý [1]¯S®íµ¥¯Å (2)¥þ³¡¡H",
+ genbuf, 3, DOECHO);
+ if(genbuf[0] != '2')
+ u_list_special = PERM_BASIC | PERM_CHAT | PERM_PAGE | PERM_POST | PERM_LOGINOK | PERM_BM;
+ }
+ if(HAS_PERM(PERM_CHATROOM) || HAS_PERM(PERM_SYSOP)) {
+ getdata(b_lines - 1, 0, "Åã¥Ü [1]¯u¹ê©m¦W (2)¼ÊºÙ¡H",
+ genbuf, 3, DOECHO);
+ if(genbuf[0] != '2')
+ showrealname = 1;
+ }
+ u_list_CB(NULL);
+ if(passwd_apply(u_list_CB) == -1) {
+ outs(msg_nobody);
+ return XEASY;
+ }
+ move(b_lines, 0);
+ clrtoeol();
+ prints("\033[34;46m ¤wÅã¥Ü %d/%d ªº¨Ï¥ÎªÌ(¨t²Î®e¶qµL¤W­­) "
+ "\033[31;47m (½Ð«ö¥ô·NÁäÄ~Äò) \033[m", usercounter, totalusers);
+ egetch();
+ return 0;
+}
diff --git a/mbbsd/var.c b/mbbsd/var.c
new file mode 100644
index 00000000..7b07f63b
--- /dev/null
+++ b/mbbsd/var.c
@@ -0,0 +1,268 @@
+/* $Id: var.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+
+char *str_permid[] = {
+ "°ò¥»Åv¤O", /* PERM_BASIC */
+ "¶i¤J²á¤Ñ«Ç", /* PERM_CHAT */
+ "§ä¤H²á¤Ñ", /* PERM_PAGE */
+ "µoªí¤å³¹", /* PERM_POST */
+ "µù¥Uµ{§Ç»{ÃÒ", /* PERM_LOGINOK */
+ "«H¥óµL¤W­­", /* PERM_MAILLIMIT */
+ "Áô¨­³N", /* PERM_CLOAK */
+ "¬Ý¨£§ÔªÌ", /* PERM_SEECLOAK */
+ "¥Ã¤[«O¯d±b¸¹", /* PERM_XEMPT */
+ "¯¸ªøÁô¨­³N", /* PERM_DENYPOST */
+ "ªO¥D", /* PERM_BM */
+ "±b¸¹Á`ºÞ", /* PERM_ACCOUNTS */
+ "²á¤Ñ«ÇÁ`ºÞ", /* PERM_CHATCLOAK */
+ "¬ÝªOÁ`ºÞ", /* PERM_BOARD */
+ "¯¸ªø", /* PERM_SYSOP */
+ "BBSADM", /* PERM_POSTMARK */
+ "¤£¦C¤J±Æ¦æº]", /* PERM_NOTOP */
+ "¹Hªk³q½r¤¤", /* PERM_VIOLATELAW */
+ "¤£±µ¨ü¯¸¥~ªº«H", /* PERM_ */
+ "¨S·Q¨ì", /* PERM_ */
+ "µøı¯¸ªø", /* PERM_VIEWSYSOP */
+ "Æ[¹î¨Ï¥ÎªÌ¦æÂÜ", /* PERM_LOGUSER */
+ "ºëµØ°ÏÁ`¾ã²zÅv", /* PERM_Announce */
+ "¤½Ãö²Õ", /* PERM_RELATION */
+ "¯S°È²Õ", /* PERM_SMG */
+ "µ{¦¡²Õ", /* PERM_PRG */
+ "¬¡°Ê²Õ", /* PERM_ACTION */
+ "¬ü¤u²Õ", /* PERM_PAINT */
+ "¥ßªk²Õ", /* PERM_LAW */
+ "¤p²Õªø", /* PERM_SYSSUBOP */
+ "¤@¯Å¥DºÞ", /* PERM_LSYSOP */
+ "¢Þ¢ü¢ü" /* PERM_PTT */
+};
+
+char *str_permboard[] = {
+ "¤£¥i Zap", /* BRD_NOZAP */
+ "¤£¦C¤J²Î­p", /* BRD_NOCOUNT */
+ "¤£Âà«H", /* BRD_NOTRAN */
+ "¸s²Õª©", /* BRD_GROUP */
+ "ÁôÂê©", /* BRD_HIDE */
+ "­­¨î(¤£»Ý³]©w)", /* BRD_POSTMASK */
+ "°Î¦Wª©", /* BRD_ANONYMOUS */
+ "¹w³]°Î¦Wª©", /* BRD_DEFAULTANONYMOUS */
+ "¹Hªk§ï¶i¤¤¬Ýª©", /* BRD_BAD */
+ "³s¸p±M¥Î¬Ýª©", /* BRD_VOTEBOARD */
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+ "¨S·Q¨ì",
+};
+
+int usernum;
+pid_t currpid; /* current process ID */
+unsigned int currstat;
+int currmode = 0;
+int curredit = 0;
+int showansi = 1;
+int curr_idle_timeout = IDLE_TIMEOUT;
+time_t login_start_time;
+userec_t cuser; /* current user structure */
+userec_t xuser; /* lookup user structure */
+char quote_file[80] = "\0";
+char quote_user[80] = "\0";
+time_t paste_time;
+char paste_title[STRLEN];
+char paste_path[256];
+int paste_level;
+char currtitle[40] = "\0";
+char vetitle[40] = "\0";
+char currowner[IDLEN + 2] = "\0";
+char currauthor[IDLEN + 2] = "\0";
+char currfile[FNLEN]; /* current file name @ bbs.c mail.c */
+unsigned char currfmode; /* current file mode */
+char currboard[IDLEN + 2];
+int currbid;
+unsigned int currbrdattr;
+char currBM[IDLEN * 3 + 10];
+char reset_color[4] = "\033[m";
+char margs[64] = "\0"; /* main argv list*/
+crosspost_t postrecord; /* anti cross post */
+
+/* global string variables */
+/* filename */
+
+char *fn_passwd = FN_PASSWD;
+char *fn_board = FN_BOARD;
+char *fn_note_ans = FN_NOTE_ANS;
+char *fn_register = "register.new";
+char *fn_plans = "plans";
+char *fn_writelog = "writelog";
+char *fn_talklog = "talklog";
+char *fn_overrides = FN_OVERRIDES;
+char *fn_reject = FN_REJECT;
+char *fn_canvote = FN_CANVOTE;
+char *fn_notes = "notes";
+char *fn_water = FN_WATER;
+char *fn_visable = FN_VISABLE;
+char *fn_mandex = "/.Names";
+char *fn_proverb = "proverb";
+
+/* are descript in userec.loginview */
+
+char *loginview_file[NUMVIEWFILE][2] = {
+ {FN_NOTE_ANS ,"»Ä²¢­W»¶¬y¨¥ªO"},
+ {FN_TOPSONG ,"ÂIºq±Æ¦æº]" },
+ {"etc/topusr" ,"¤Q¤j±Æ¦æº]" },
+ {"etc/topusr100" ,"¦Ê¤j±Æ¦æº]" },
+ {"etc/birth.today" ,"¤µ¤é¹Ø¬P" },
+ {"etc/weather.tmp" ,"¤Ñ®ð§Ö³ø" },
+ {"etc/stock.tmp" ,"ªÑ¥«§Ö³ø" },
+ {"etc/day" ,"¤µ¤é¤Q¤j¸ÜÃD" },
+ {"etc/week" ,"¤@¶g¤­¤Q¤j¸ÜÃD"},
+ {"etc/today" ,"¤µ¤Ñ¤W¯¸¤H¦¸" },
+ {"etc/yesterday" ,"¬Q¤é¤W¯¸¤H¦¸" },
+ {"etc/history" ,"¾ú¥v¤Wªº¤µ¤Ñ" },
+ {"etc/topboardman" ,"ºëµØ°Ï±Æ¦æº]" },
+ {"etc/topboard.tmp","¬ÝªO¤H®ð±Æ¦æº]"}
+};
+
+/* message */
+char *msg_seperator = MSG_SEPERATOR;
+char *msg_mailer = MSG_MAILER;
+char *msg_shortulist = MSG_SHORTULIST;
+
+char *msg_cancel = MSG_CANCEL;
+char *msg_usr_left = MSG_USR_LEFT;
+char *msg_nobody = MSG_NOBODY;
+
+char *msg_sure_ny = MSG_SURE_NY;
+char *msg_sure_yn = MSG_SURE_YN;
+
+char *msg_bid = MSG_BID;
+char *msg_uid = MSG_UID;
+
+char *msg_del_ok = MSG_DEL_OK;
+char *msg_del_ny = MSG_DEL_NY;
+
+char *msg_fwd_ok = MSG_FWD_OK;
+char *msg_fwd_err1 = MSG_FWD_ERR1;
+char *msg_fwd_err2 = MSG_FWD_ERR2;
+
+char *err_board_update = ERR_BOARD_UPDATE;
+char *err_bid = ERR_BID;
+char *err_uid = ERR_UID;
+char *err_filename = ERR_FILENAME;
+
+char *str_mail_address = "." BBSUSER "@" MYHOSTNAME;
+char *str_new = "new";
+char *str_reply = "Re: ";
+char *str_space = " \t\n\r";
+char *str_sysop = "SYSOP";
+char *str_author1 = STR_AUTHOR1;
+char *str_author2 = STR_AUTHOR2;
+char *str_post1 = STR_POST1;
+char *str_post2 = STR_POST2;
+char *BBSName = BBSNAME;
+
+/* #define MAX_MODES 78 */
+/* MAX_MODES is defined in common.h */
+
+char *ModeTypeTable[MAX_MODES] = {
+ "µo§b", /* IDLE */
+ "¥D¿ï³æ", /* MMENU */
+ "¨t²ÎºûÅ@", /* ADMIN */
+ "¶l¥ó¿ï³æ", /* MAIL */
+ "¥æ½Í¿ï³æ", /* TMENU */
+ "¨Ï¥ÎªÌ¿ï³æ", /* UMENU */
+ "XYZ ¿ï³æ", /* XMENU */
+ "¤ÀÃþ¬ÝªO", /* CLASS */
+ "Play¿ï³æ", /* PMENU */
+ "½s¯S§O¦W³æ", /* NMENU */
+ "¢Þtt¶q³c©±", /* PSALE */
+ "µoªí¤å³¹", /* POSTING */
+ "¬ÝªO¦Cªí", /* READBRD */
+ "¾\\Ū¤å³¹", /* READING */
+ "·s¤å³¹¦Cªí", /* READNEW */
+ "¿ï¾Ü¬ÝªO", /* SELECT */
+ "Ū«H", /* RMAIL */
+ "¼g«H", /* SMAIL */
+ "²á¤Ñ«Ç", /* CHATING */
+ "¨ä¥L", /* XMODE */
+ "´M§ä¦n¤Í", /* FRIEND */
+ "¤W½u¨Ï¥ÎªÌ", /* LAUSERS */
+ "¨Ï¥ÎªÌ¦W³æ", /* LUSERS */
+ "°lÂܯ¸¤Í", /* MONITOR */
+ "©I¥s", /* PAGE */
+ "¬d¸ß", /* TQUERY */
+ "¥æ½Í", /* TALK */
+ "½s¦W¤ùÀÉ", /* EDITPLAN */
+ "½sñ¦WÀÉ", /* EDITSIG */
+ "§ë²¼¤¤", /* VOTING */
+ "³]©w¸ê®Æ", /* XINFO */
+ "±Hµ¹¯¸ªø", /* MSYSOP */
+ "¨L¨L¨L", /* WWW */
+ "¥´¤j¦Ñ¤G", /* BIG2 */
+ "¦^À³", /* REPLY */
+ "³Q¤ô²y¥´¤¤", /* HIT */
+ "¤ô²y·Ç³Æ¤¤", /* DBACK */
+ "µ§°O¥»", /* NOTE */
+ "½s¿è¤å³¹", /* EDITING */
+ "µo¨t²Î³q§i", /* MAILALL */
+ "ºN¨â°é", /* MJ */
+ "¹q¸£¾Ü¤Í", /* P_FRIEND */
+ "¤W¯¸³~¤¤", /* LOGIN */
+ "¬d¦r¨å", /* DICT */
+ "¥´¾ôµP", /* BRIDGE */
+ "§äÀÉ®×", /* ARCHIE */
+ "¥´¦a¹«", /* GOPHER */
+ "¬ÝNews", /* NEWS */
+ "±¡®Ñ²£¥Í¾¹", /* LOVE */
+ "½sÄy»²§U¾¹", /* EDITEXP */
+ "¥Ó½ÐIP¦ì§}", /* IPREG */
+ "ºôºÞ¿ì¤½¤¤", /* NetAdm */
+ "µêÀÀ¹ê·~§{", /* DRINK */
+ "­pºâ¾÷", /* CAL */
+ "½sÄy®y¥k»Ê", /* PROVERB */
+ "¤½§GÄæ", /* ANNOUNCE */
+ "¨è¬y¨¥ª©", /* EDNOTE */
+ "­^º~½Ķ¾÷", /* CDICT */
+ "À˵ø¦Û¤vª««~", /* LOBJ */
+ "ÂIºq", /* OSONG */
+ "¥¿¦bª±¤pÂû", /* CHICKEN */
+ "ª±±m¨é", /* TICKET */
+ "²q¼Æ¦r", /* GUESSNUM */
+ "¹C¼Ö³õ", /* AMUSE */
+ "¶Â¥Õ´Ñ", /* OTHELLO */
+ "ª±»ë¤l", /* DICE*/
+ "µo²¼¹ï¼ú", /* VICE */
+ "¹G¹Gáàing", /* BBCALL */
+ "ú»@³æ", /* CROSSPOST */
+ "¤­¤l´Ñ", /* M_FIVE */
+ "21ÂIing", /* JACK_CARD */
+ "10ÂI¥bing", /* TENHALF */
+ "¶W¯Å¤E¤Q¤E", /* CARD_99 */
+ "¤õ¨®¬d¸ß", /* RAIL_WAY */
+ "·j´M¿ï³æ", /* SREG */
+ "¤U¶H´Ñ", /* CHC */
+ "¤U·tµX", /* DARK */
+ "NBA¤j²q´ú" /* TMPJACK */
+ "¢Þtt¬dº]¨t²Î", /* JCEE */
+ "­«½s¤å³¹" /* REEDIT */
+};
diff --git a/mbbsd/vice.c b/mbbsd/vice.c
new file mode 100644
index 00000000..46f695d9
--- /dev/null
+++ b/mbbsd/vice.c
@@ -0,0 +1,151 @@
+/* $Id: vice.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "modes.h"
+#include "proto.h"
+extern int usernum;
+
+#define VICE_PLAY BBSHOME "/etc/vice/vice.play"
+#define VICE_DATA "vice.new"
+#define VICE_BINGO BBSHOME "/etc/vice.bingo"
+#define VICE_SHOW BBSHOME "/etc/vice.show"
+#define VICE_LOST BBSHOME "/etc/vice/vice.lost"
+#define VICE_WIN BBSHOME "/etc/vice/vice.win"
+#define VICE_END BBSHOME "/etc/vice/vice.end"
+#define VICE_NO BBSHOME "/etc/vice/vice.no"
+#define MAX_NO_PICTURE 2
+#define MAX_WIN_PICTURE 2
+#define MAX_LOST_PICTURE 3
+#define MAX_END_PICTURE 5
+
+
+
+static int vice_load(char tbingo[6][15]) {
+ FILE *fb = fopen(VICE_BINGO, "r");
+ char buf[16], *ptr;
+ int i = 0;
+ if(!fb) return -1; bzero((char*)tbingo, sizeof(tbingo));
+ while(i < 6 && fgets(buf, 15, fb)) {
+ if((ptr = strchr(buf, '\n')))
+ *ptr = 0;
+ strcpy(tbingo[i++], buf);
+ }
+ fclose(fb);
+ return 0;
+}
+
+static int check(char tbingo[6][15], char *data) {
+ int i = 0, j;
+
+ if(!strcmp(data, tbingo[0]))
+ return 8;
+
+ for(j = 8; j > 0; j--)
+ for(i = 1; i < 6; i++)
+ if(!strncmp(data+8-j, tbingo[i]+8-j,j))
+ return j - 1;
+ return 0;
+}
+// Ptt: showfile ran_showfile more ¤TªÌ­n¾ã¦X
+static int ran_showfile(int y, int x, char *filename, int maxnum) {
+ FILE *fs;
+ char buf[512];
+
+ bzero(buf, sizeof(char) * 512);
+ sprintf(buf, "%s%d", filename, rand() % maxnum + 1);
+ if(!(fs = fopen(buf, "r"))) {
+ move(10,10);
+ prints("can't open file: %s", buf);
+ return 0;
+ }
+
+ move(y, x);
+
+ while(fgets(buf, 511, fs))
+ prints("%s", buf);
+
+ fclose(fs);
+ return 1;
+}
+
+static int ran_showmfile(char *filename, int maxnum) {
+ char buf[256];
+
+ sprintf(buf, "%s%d", filename, rand() % maxnum + 1);
+ return more(buf, YEA);
+}
+
+extern userec_t cuser;
+
+int vice_main() {
+ FILE *fd;
+ char tbingo[6][15];
+ char buf_data[256]
+ , serial[16], ch[2], *ptr;
+ int TABLE[] = {0,10,200,1000,4000,10000,40000,100000,200000};
+ int total = 0, money, i = 4, j = 0;
+
+ setuserfile(buf_data, VICE_DATA);
+ if(!dashf(buf_data)) {
+ ran_showmfile(VICE_NO, MAX_NO_PICTURE);
+ return 0;
+ }
+ if(vice_load(tbingo)<0) return -1;
+ clear();
+ ran_showfile(0, 0, VICE_PLAY, 1);
+ ran_showfile(10, 0, VICE_SHOW, 1);
+
+ if(!(fd = fopen(buf_data, "r")))
+ return 0;
+ j = 0;
+ i = 0;
+ move(10,24);
+ clrtoeol();
+ prints("³o¤@´Áªºµo²¼¸¹½X");
+ while(fgets(serial, 15, fd)) {
+ if((ptr = strchr(serial,'\r')))
+ *ptr = 0;
+ if(j == 0)
+ i++;
+ move(10 + i, 24 + j);
+ prints("%s", serial);
+ j += 9;
+ j %= 45;
+ }
+ getdata(8, 0, "«ö'c'¶}©l¹ï¼ú¤F(©Î¬O¥ô·NÁäÂ÷¶})): ", ch, 2, LCECHO);
+ if(ch[0] != 'c' || lockutmpmode(VICE, LOCK_MULTI)){
+ fclose(fd);
+ return 0;
+ }
+
+ showtitle("µo²¼¹ï¼ú", BBSNAME);
+ rewind(fd);
+ while(fgets(serial, 15, fd)) {
+ if((ptr = strchr(serial,'\n')))
+ *ptr = 0;
+ money = TABLE[check(tbingo,serial)];
+ total += money;
+ prints("%s ¤¤¤F %d\n", serial, money);
+ }
+ pressanykey();
+ if(total > 0) {
+ ran_showmfile(VICE_WIN, MAX_WIN_PICTURE);
+ move(22,0);
+ clrtoeol();
+ prints("¥þ³¡ªºµo²¼¤¤¤F %d ¶ô¿ú\n", total);
+ demoney(total);
+ } else
+ ran_showmfile(VICE_LOST, MAX_LOST_PICTURE);
+
+ fclose(fd);
+ unlink(buf_data);
+ pressanykey();
+ unlockutmpmode();
+ return 0;
+}
diff --git a/mbbsd/vote.c b/mbbsd/vote.c
new file mode 100644
index 00000000..62916c99
--- /dev/null
+++ b/mbbsd/vote.c
@@ -0,0 +1,1068 @@
+/* $Id: vote.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "modes.h"
+#include "common.h"
+#include "perm.h"
+#include "proto.h"
+
+static int total;
+extern int numboards;
+extern boardheader_t *bcache; /* Thor: for speed up */
+extern char *err_board_update;
+extern char *fn_board;
+extern char *msg_seperator;
+extern int t_lines, t_columns; /* Screen size / width */
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+extern int currmode;
+extern int usernum;
+extern char currboard[]; /* name of currently selected board */
+extern userec_t cuser;
+
+static char STR_bv_control[] = "control"; /* §ë²¼¤é´Á ¿ï¶µ */
+static char STR_bv_desc[] = "desc"; /* §ë²¼¥Øªº */
+static char STR_bv_ballots[] = "ballots";
+static char STR_bv_flags[] = "flags";
+static char STR_bv_comments[] = "comments"; /* §ë²¼ªÌªº«Ø·N */
+static char STR_bv_limited[] = "limited"; /* ¨p¤H§ë²¼ */
+static char STR_bv_title[] = "vtitle";
+
+static char STR_bv_results[] = "results";
+
+static char STR_new_control[] = "control0"; /* §ë²¼¤é´Á ¿ï¶µ */
+static char STR_new_desc[] = "desc0"; /* §ë²¼¥Øªº */
+static char STR_new_ballots[] = "ballots0";
+static char STR_new_flags[] = "flags0";
+static char STR_new_comments[] = "comments0"; /* §ë²¼ªÌªº«Ø·N */
+static char STR_new_limited[] = "limited0"; /* ¨p¤H§ë²¼ */
+static char STR_new_title[] = "vtitle0";
+
+int strip_ansi(char *buf, char *str, int mode) {
+ register int ansi, count = 0;
+
+ for(ansi = 0; *str /*&& *str != '\n' */; str++) {
+ if(*str == 27) {
+ if(mode) {
+ if(buf)
+ *buf++ = *str;
+ count++;
+ }
+ ansi = 1;
+ } else if(ansi && strchr("[;1234567890mfHABCDnsuJKc=n", *str)) {
+ if((mode == NO_RELOAD && !strchr("c=n", *str)) ||
+ (mode == ONLY_COLOR && strchr("[;1234567890m", *str))) {
+ if(buf)
+ *buf++ = *str;
+ count++;
+ }
+ if(strchr("mHn ", *str))
+ ansi = 0;
+ } else {
+ ansi =0;
+ if(buf)
+ *buf++ = *str;
+ count++;
+ }
+ }
+ if(buf)
+ *buf = '\0';
+ return count;
+}
+
+void b_suckinfile(FILE *fp, char *fname) {
+ FILE *sfp;
+
+ if((sfp = fopen(fname, "r"))) {
+ char inbuf[256];
+
+ while(fgets(inbuf, sizeof(inbuf), sfp))
+ fputs(inbuf, fp);
+ fclose(sfp);
+ }
+}
+
+static void b_count(char *buf, int counts[]) {
+ char inchar;
+ int fd;
+
+ memset(counts, 0, 31 * sizeof(counts[0]));
+ total = 0;
+ if((fd = open(buf, O_RDONLY)) != -1) {
+ flock(fd, LOCK_EX); /* Thor: ¨¾¤î¦h¤H¦P®Éºâ */
+ while(read(fd, &inchar, 1) == 1) {
+ counts[(int)(inchar - 'A')]++;
+ total++;
+ }
+ flock(fd, LOCK_UN);
+ close(fd);
+ }
+}
+
+
+static int b_nonzeroNum(char *buf) {
+ int i = 0;
+ char inchar;
+ int fd;
+
+ if((fd = open(buf, O_RDONLY)) != -1) {
+ while(read(fd, &inchar, 1) == 1)
+ if(inchar)
+ i++;
+ close(fd);
+ }
+ return i;
+}
+
+static void vote_report(char *bname, char *fname, char *fpath) {
+ register char *ip;
+ time_t dtime;
+ int fd, bid;
+ fileheader_t header;
+
+ ip = fpath;
+ while(*(++ip));
+ *ip++ = '/';
+
+ /* get a filename by timestamp */
+
+ dtime = time(0);
+ for(;;) {
+ sprintf(ip, "M.%ld.A", ++dtime);
+ fd = open(fpath, O_CREAT | O_EXCL | O_WRONLY, 0644);
+ if(fd >= 0)
+ break;
+ dtime++;
+ }
+ close(fd);
+
+ log_usies("TESTfn", fname);
+ log_usies("TESTfp", fpath);
+
+ unlink(fpath);
+ link(fname, fpath);
+
+ /* append record to .DIR */
+
+ memset(&header, 0, sizeof(fileheader_t));
+ strcpy(header.owner, "[°¨¸ô±´¤l]");
+ sprintf(header.title, "[%s] ¬ÝªO ¿ï±¡³ø¾É", bname);
+ {
+ register struct tm *ptime = localtime(&dtime);
+
+ sprintf(header.date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday);
+ }
+ strcpy(header.filename, ip);
+
+ strcpy(ip, ".DIR");
+ if((fd = open(fpath, O_WRONLY | O_CREAT, 0644)) >= 0) {
+ flock(fd, LOCK_EX);
+ lseek(fd, 0, SEEK_END);
+ write(fd, &header, sizeof(fileheader_t));
+ flock(fd, LOCK_UN);
+ close(fd);
+ if((bid = getbnum(bname)) > 0)
+ setbtotal(bid);
+
+ }
+
+}
+
+static void b_result_one(boardheader_t *fh, int ind) {
+ FILE *cfp, *tfp, *frp, *xfp;
+ char *bname ;
+ char buf[STRLEN];
+ char inbuf[80];
+ int counts[31];
+ int num ;
+ int junk;
+ char b_control[64];
+ char b_newresults[64];
+ char b_report[64];
+ time_t closetime, now;
+
+ fh->bvote--;
+
+ if(fh->bvote==0)
+ fh->bvote=2;
+ else if(fh->bvote==2)
+ fh->bvote=1;
+
+ if(ind) {
+ sprintf(STR_new_ballots, "%s%d", STR_bv_ballots, ind);
+ sprintf(STR_new_control, "%s%d", STR_bv_control, ind);
+ sprintf(STR_new_desc, "%s%d", STR_bv_desc, ind);
+ sprintf(STR_new_flags, "%s%d", STR_bv_flags, ind);
+ sprintf(STR_new_comments, "%s%d", STR_bv_comments, ind);
+ sprintf(STR_new_limited, "%s%d", STR_bv_limited, ind);
+ sprintf(STR_new_title, "%s%d", STR_bv_title, ind);
+ } else {
+ strcpy(STR_new_ballots, STR_bv_ballots);
+ strcpy(STR_new_control, STR_bv_control);
+ strcpy(STR_new_desc, STR_bv_desc);
+ strcpy(STR_new_flags, STR_bv_flags);
+ strcpy(STR_new_comments, STR_bv_comments);
+ strcpy(STR_new_limited, STR_bv_limited);
+ strcpy(STR_new_title, STR_bv_title);
+ }
+
+ bname = fh->brdname;
+
+ setbfile(buf, bname, STR_new_control);
+ cfp = fopen(buf,"r");
+ fscanf(cfp, "%d\n%lu\n", &junk, &closetime);
+ fclose(cfp);
+
+ setbfile(b_control, bname, "tmp");
+ if(rename(buf, b_control) == -1)
+ return;
+ setbfile(buf, bname, STR_new_flags);
+ num = b_nonzeroNum(buf);
+ unlink(buf);
+ setbfile(buf, bname, STR_new_ballots);
+ b_count(buf, counts);
+ unlink(buf);
+
+ setbfile(b_newresults, bname, "newresults");
+ if((tfp = fopen(b_newresults, "w")) == NULL)
+ return;
+
+ now = time(NULL);
+ setbfile(buf, bname, STR_new_title);
+
+ if((xfp=fopen(buf,"r"))) {
+ fgets(inbuf, sizeof(inbuf), xfp);
+ fprintf(tfp, "%s\n¡» §ë²¼¦WºÙ: %s\n\n", msg_seperator, inbuf);
+ }
+
+ fprintf(tfp, "%s\n¡» §ë²¼¤¤¤î©ó: %s\n\n¡» ²¼¿ïÃD¥Ø´y­z:\n\n",
+ msg_seperator, ctime(&closetime));
+ fh->vtime = now;
+
+ setbfile(buf, bname, STR_new_desc);
+
+ b_suckinfile(tfp, buf);
+ unlink(buf);
+
+ if((cfp = fopen(b_control, "r"))) {
+ fgets(inbuf, sizeof(inbuf), cfp);
+ fgets(inbuf, sizeof(inbuf), cfp);
+ fprintf(tfp, "\n¡»§ë²¼µ²ªG:(¦@¦³ %d ¤H§ë²¼,¨C¤H³Ì¦h¥i§ë %d ²¼)\n",
+ num, junk);
+ while(fgets(inbuf, sizeof(inbuf), cfp)) {
+ inbuf[(strlen(inbuf) - 1)] = '\0';
+ num = counts[inbuf[0] - 'A'];
+ fprintf(tfp, " %-42s %3d ²¼ %02.2f%%\n", inbuf + 3, num,
+ (float)(num*100)/(float)(total));
+ }
+ fclose(cfp);
+ }
+ unlink(b_control);
+
+ fprintf(tfp, "%s\n¡» ¨Ï¥ÎªÌ«Øij¡G\n\n", msg_seperator);
+ setbfile(buf, bname, STR_new_comments);
+ b_suckinfile(tfp, buf);
+ unlink(buf);
+
+ fprintf(tfp, "%s\n¡» Á`²¼¼Æ = %d ²¼\n\n", msg_seperator, total);
+ fclose(tfp);
+
+ setbfile(b_report, bname, "report");
+ if((frp = fopen(b_report, "w"))) {
+ b_suckinfile(frp, b_newresults);
+ fclose(frp);
+ }
+ sprintf(inbuf, "boards/%s", bname);
+ vote_report(bname, b_report, inbuf);
+ if(!(fh->brdattr &BRD_NOCOUNT)) {
+ sprintf(inbuf, "boards/%s", "Record");
+ vote_report(bname, b_report, inbuf);
+ }
+ unlink(b_report);
+
+ tfp = fopen(b_newresults, "a");
+ setbfile(buf, bname, STR_bv_results);
+ b_suckinfile(tfp, buf);
+ fclose(tfp);
+ Rename(b_newresults, buf);
+}
+
+static void b_result(boardheader_t *fh) {
+ FILE *cfp;
+ time_t closetime, now;
+ int i;
+ char buf[STRLEN];
+ char temp[STRLEN];
+
+ now = time(NULL);
+ for(i = 0; i < 9; i++) {
+ if(i)
+ sprintf(STR_new_control, "%s%d", STR_bv_control, i);
+ else
+ strcpy(STR_new_control, STR_bv_control);
+
+ setbfile(buf, fh->brdname, STR_new_control);
+ cfp = fopen(buf,"r");
+ if (!cfp)
+ continue;
+ fgets(temp,sizeof(temp),cfp);
+ fscanf(cfp, "%lu\n", &closetime);
+ fclose(cfp);
+ if(closetime < now)
+ b_result_one(fh,i);
+ }
+}
+
+static int b_close(boardheader_t *fh) {
+ time_t now;
+ now = time(NULL);
+
+ if(fh->bvote == 2) {
+ if(fh->vtime < now - 3 * 86400) {
+ fh->bvote = 0;
+ return 1;
+ }
+ else
+ return 0;
+ }
+ b_result(fh);
+ return 1;
+}
+
+int b_closepolls() {
+ static char *fn_vote_polling = ".polling";
+ boardheader_t *fhp;
+ FILE *cfp;
+ time_t now;
+ int pos, dirty;
+ time_t last;
+ char timebuf[100];
+
+ now = time(NULL);
+/* Edited by CharlieL for can't auto poll bug */
+
+ if((cfp = fopen(fn_vote_polling,"r"))) {
+ fgets(timebuf,100*sizeof(char),cfp);
+ sscanf(timebuf, "%lu", &last);
+ fclose(cfp);
+ if(last + 3600 >= now)
+ return 0;
+ }
+
+ if((cfp = fopen(fn_vote_polling, "w")) == NULL)
+ return 0;
+ fprintf(cfp, "%lu\n%s\n", now, ctime(&now));
+ fclose(cfp);
+
+ dirty = 0;
+ for(fhp = bcache, pos = 1; pos <= numboards; fhp++, pos++) {
+ if(fhp->bvote && b_close(fhp)) {
+ if(substitute_record(fn_board, fhp, sizeof(*fhp), pos) == -1)
+ outs(err_board_update);
+ dirty = 1;
+ }
+ }
+ if(dirty) /* vote flag changed */
+ reset_board(pos);
+
+ return 0;
+}
+
+static int vote_view(char *bname, int index) {
+ boardheader_t *fhp;
+ FILE* fp;
+ char buf[STRLEN], genbuf[STRLEN], inbuf[STRLEN];
+ struct stat stbuf;
+ int fd, num = 0, i, pos, counts[31];
+ time_t closetime;
+
+ if(index) {
+ sprintf(STR_new_ballots, "%s%d", STR_bv_ballots, index);
+ sprintf(STR_new_control, "%s%d", STR_bv_control, index);
+ sprintf(STR_new_desc, "%s%d", STR_bv_desc, index);
+ sprintf(STR_new_flags, "%s%d", STR_bv_flags, index);
+ sprintf(STR_new_comments, "%s%d", STR_bv_comments, index);
+ sprintf(STR_new_limited, "%s%d", STR_bv_limited, index);
+ sprintf(STR_new_title, "%s%d", STR_bv_title, index);
+ } else {
+ strcpy(STR_new_ballots, STR_bv_ballots);
+ strcpy(STR_new_control, STR_bv_control);
+ strcpy(STR_new_desc, STR_bv_desc);
+ strcpy(STR_new_flags, STR_bv_flags);
+ strcpy(STR_new_comments, STR_bv_comments);
+ strcpy(STR_new_limited, STR_bv_limited);
+ strcpy(STR_new_title, STR_bv_title);
+ }
+
+ setbfile(buf, bname, STR_new_ballots);
+ if((fd = open(buf, O_RDONLY)) > 0) {
+ fstat(fd, &stbuf);
+ close(fd);
+ } else
+ stbuf.st_size = 0;
+
+ setbfile(buf, bname, STR_new_title);
+ move(0, 0);
+ clrtobot();
+
+ if((fp = fopen(buf, "r"))) {
+ fgets(inbuf, sizeof(inbuf), fp);
+ prints("\n§ë²¼¦WºÙ: %s", inbuf);
+ }
+
+ setbfile(buf, bname, STR_new_control);
+ fp = fopen(buf, "r");
+ fgets(inbuf, sizeof(inbuf), fp);
+ fscanf(fp, "%lu\n", &closetime);
+
+ prints("\n¡» ¹wª¾§ë²¼¬ö¨Æ: ¨C¤H³Ì¦h¥i§ë %d ²¼,¥Ø«e¦@¦³ %d ²¼,\n"
+ "¥»¦¸§ë²¼±Nµ²§ô©ó %s", atoi(inbuf), stbuf.st_size,
+ ctime(&closetime));
+
+ /* Thor: ¶}©ñ ²¼¼Æ ¹wª¾ */
+ setbfile(buf, bname, STR_new_flags);
+ num = b_nonzeroNum(buf);
+
+ setbfile(buf, bname, STR_new_ballots);
+ b_count(buf, counts);
+
+ prints("¦@¦³ %d ¤H§ë²¼\n", num);
+ total = 0;
+
+ while(fgets(inbuf, sizeof(inbuf), fp)) {
+ inbuf[(strlen(inbuf) - 1)] = '\0';
+ inbuf[30] = '\0'; /* truncate */
+ i = inbuf[0] - 'A';
+ num = counts[i];
+ move(i % 15 + 6, i / 15 * 40);
+ prints(" %-32s%3d ²¼", inbuf, num);
+ total += num;
+ }
+ fclose(fp);
+ pos = getbnum(bname);
+ fhp = bcache + pos - 1;
+ move(t_lines - 3, 0);
+ prints("¡» ¥Ø«eÁ`²¼¼Æ = %d ²¼", total);
+ getdata(b_lines - 1, 0, "(A)¨ú®ø§ë²¼ (B)´£¦­¶}²¼ (C)Ä~Äò¡H[C] ", genbuf,
+ 4, LCECHO);
+ if(genbuf[0] == 'a') {
+ setbfile(buf, bname, STR_new_control);
+ unlink(buf);
+ setbfile(buf, bname, STR_new_flags);
+ unlink(buf);
+ setbfile(buf, bname, STR_new_ballots);
+ unlink(buf);
+ setbfile(buf, bname, STR_new_desc);
+ unlink(buf);
+ setbfile(buf, bname, STR_new_limited);
+ unlink(buf);
+ setbfile(buf,bname, STR_new_title);
+ unlink(buf);
+
+ if(fhp->bvote)
+ fhp->bvote--;
+ if (fhp->bvote == 2)
+ fhp->bvote = 1;
+
+ if(substitute_record(fn_board, fhp, sizeof(*fhp), pos) == -1)
+ outs(err_board_update);
+ reset_board(pos);
+ } else if(genbuf[0] == 'b') {
+ b_result_one(fhp,index);
+ if(substitute_record(fn_board, fhp, sizeof(*fhp), pos) == -1)
+ outs(err_board_update);
+
+ reset_board(pos);
+ }
+ return FULLUPDATE;
+}
+
+static int vote_view_all(char *bname) {
+ int i;
+ int x = -1;
+ FILE *fp, *xfp;
+ char buf[STRLEN], genbuf[STRLEN];
+ char inbuf[80];
+
+ strcpy(STR_new_control, STR_bv_control);
+ strcpy(STR_new_title, STR_bv_title);
+ setbfile(buf, bname, STR_new_control);
+ move(0, 0);
+ if((fp=fopen(buf,"r"))) {
+ prints("(0) ");
+ x = 0;
+ fclose(fp);
+
+ setbfile(buf, bname, STR_new_title);
+ if((xfp=fopen(buf,"r")))
+ fgets(inbuf, sizeof(inbuf), xfp);
+ else
+ strcpy(inbuf, "µL¼ÐÃD");
+ prints("%s\n", inbuf);
+ fclose(xfp);
+ }
+
+ for(i = 1; i < 9; i++) {
+ sprintf(STR_new_control, "%s%d", STR_bv_control, i);
+ sprintf(STR_new_title, "%s%d", STR_bv_title, i);
+ setbfile(buf, bname, STR_new_control);
+ if((fp=fopen(buf,"r"))) {
+ prints("(%d) ", i);
+ x = i;
+ fclose(fp);
+
+ setbfile(buf, bname, STR_new_title);
+ if((xfp=fopen(buf,"r")))
+ fgets(inbuf, sizeof(inbuf), xfp);
+ else
+ strcpy(inbuf, "µL¼ÐÃD");
+ prints("%s\n", inbuf);
+ fclose(xfp);
+ }
+ }
+
+ if(x < 0)
+ return FULLUPDATE;
+ sprintf(buf, "­n¬Ý´X¸¹§ë²¼ [%d] ", x);
+
+ getdata(b_lines - 1, 0, buf, genbuf, 4, LCECHO);
+
+ if(genbuf[0] < '0' || genbuf[0] > '8')
+ genbuf[0] = '0'+x;
+
+ if(genbuf[0] != '0')
+ sprintf(STR_new_control, "%s%c", STR_bv_control, genbuf[0]);
+ else
+ strcpy(STR_new_control, STR_bv_control);
+
+ setbfile(buf, bname, STR_new_control);
+
+ if((fp=fopen(buf,"r"))) {
+ fclose(fp);
+ return vote_view(bname, genbuf[0] - '0');
+ }
+ else
+ return FULLUPDATE;
+}
+
+static int vote_maintain(char *bname) {
+ FILE *fp = NULL;
+ char inbuf[STRLEN], buf[STRLEN];
+ int num = 0, aborted, pos, x, i;
+ time_t closetime;
+ boardheader_t *fhp;
+ char genbuf[4];
+
+ if(!(currmode & MODE_BOARD))
+ return 0;
+ if((pos = getbnum(bname)) <= 0)
+ return 0;
+
+ stand_title("Á|¿ì§ë²¼");
+ fhp = bcache + pos - 1;
+
+/* CharlieL */
+ if(fhp->bvote != 2 && fhp->bvote !=0) {
+ getdata(b_lines - 1, 0,
+ "(V)Æ[¹î¥Ø«e§ë²¼ (M)Á|¿ì·s§ë²¼ (A)¨ú®ø©Ò¦³§ë²¼ (Q)Ä~Äò [Q]",
+ genbuf, 4, LCECHO);
+ if(genbuf[0] == 'v')
+ return vote_view_all(bname);
+ else if(genbuf[0] == 'a') {
+ fhp->bvote=0;
+
+ setbfile(buf, bname, STR_bv_control);
+ unlink(buf);
+ setbfile(buf, bname, STR_bv_flags);
+ unlink(buf);
+ setbfile(buf, bname, STR_bv_ballots);
+ unlink(buf);
+ setbfile(buf, bname, STR_bv_desc);
+ unlink(buf);
+ setbfile(buf, bname, STR_bv_limited);
+ unlink(buf);
+ setbfile(buf, bname, STR_bv_title);
+ unlink(buf);
+
+ for(i = 1; i < 9; i++) {
+ sprintf(STR_new_ballots, "%s%d", STR_bv_ballots, i);
+ sprintf(STR_new_control, "%s%d", STR_bv_control, i);
+ sprintf(STR_new_desc, "%s%d", STR_bv_desc, i);
+ sprintf(STR_new_flags, "%s%d", STR_bv_flags, i);
+ sprintf(STR_new_comments, "%s%d", STR_bv_comments, i);
+ sprintf(STR_new_limited, "%s%d", STR_bv_limited, i);
+ sprintf(STR_new_title, "%s%d", STR_bv_title, i);
+
+ setbfile(buf, bname, STR_new_control);
+ unlink(buf);
+ setbfile(buf, bname, STR_new_flags);
+ unlink(buf);
+ setbfile(buf, bname, STR_new_ballots);
+ unlink(buf);
+ setbfile(buf, bname, STR_new_desc);
+ unlink(buf);
+ setbfile(buf, bname, STR_new_limited);
+ unlink(buf);
+ setbfile(buf, bname, STR_new_title);
+ unlink(buf);
+ }
+ if(substitute_record(fn_board, fhp, sizeof(*fhp), pos) == -1)
+ outs(err_board_update);
+
+ return FULLUPDATE;
+ } else if(genbuf[0] != 'm' || fhp->bvote > 10)
+ return FULLUPDATE;
+ }
+
+ strcpy(STR_new_control, STR_bv_control);
+ setbfile(buf,bname, STR_new_control);
+ x = 0;
+ while(x < 9 && (fp = fopen(buf,"r")) != NULL) {
+ fclose(fp);
+ x++;
+ sprintf(STR_new_control, "%s%d", STR_bv_control, x);
+ setbfile(buf, bname, STR_new_control);
+ }
+ if(fp)
+ fclose(fp);
+ if(x >=9)
+ return FULLUPDATE;
+ if(x) {
+ sprintf(STR_new_ballots, "%s%d", STR_bv_ballots,x);
+ sprintf(STR_new_control, "%s%d", STR_bv_control,x);
+ sprintf(STR_new_desc, "%s%d", STR_bv_desc,x);
+ sprintf(STR_new_flags, "%s%d", STR_bv_flags,x);
+ sprintf(STR_new_comments, "%s%d", STR_bv_comments,x);
+ sprintf(STR_new_limited, "%s%d", STR_bv_limited,x);
+ sprintf(STR_new_title, "%s%d", STR_bv_title,x);
+ } else {
+ strcpy(STR_new_ballots, STR_bv_ballots);
+ strcpy(STR_new_control, STR_bv_control);
+ strcpy(STR_new_desc, STR_bv_desc);
+ strcpy(STR_new_flags, STR_bv_flags);
+ strcpy(STR_new_comments, STR_bv_comments);
+ strcpy(STR_new_limited, STR_bv_limited);
+ strcpy(STR_new_title, STR_bv_title);
+ }
+ clear();
+ move(0,0);
+ prints("²Ä %d ¸¹§ë²¼\n", x);
+ setbfile(buf, bname, STR_new_title);
+ getdata(4, 0, "½Ð¿é¤J§ë²¼¦WºÙ", inbuf, 30, LCECHO);
+ if(inbuf[0]=='\0')
+ strcpy(inbuf,"¤£ª¾¦Wªº");
+ fp = fopen(buf, "w");
+ fprintf(fp, "%s", inbuf);
+ fclose(fp);
+
+ prints("«ö¥ô¦óÁä¶}©l½s¿è¦¹¦¸ [§ë²¼©v¦®]");
+ pressanykey();
+ setbfile(buf, bname, STR_new_desc);
+ aborted = vedit(buf, NA, NULL);
+ if(aborted== -1) {
+ clear();
+ outs("¨ú®ø¦¹¦¸§ë²¼");
+ pressanykey();
+ return FULLUPDATE;
+ }
+ aborted = 0;
+ setbfile(buf, bname, STR_new_flags);
+ unlink(buf);
+
+ getdata(4, 0,
+ "¬O§_­­©w§ë²¼ªÌ¦W³æ¡G(y)½sÄy¥i§ë²¼¤H­û¦W³æ[n]¥ô¦ó¤H¬Ò¥i§ë²¼:[N]",
+ inbuf, 2, LCECHO);
+ setbfile(buf, bname, STR_new_limited);
+ if(inbuf[0] == 'y') {
+ fp = fopen(buf, "w");
+ fprintf(fp,"¦¹¦¸§ë²¼³]­­");
+ fclose(fp);
+ friend_edit(FRIEND_CANVOTE);
+ } else {
+ if(dashf(buf))
+ unlink(buf);
+ }
+ clear();
+ getdata(0, 0, "¦¹¦¸§ë²¼¶i¦æ´X¤Ñ (¤@¨ì¤Q¤Ñ)¡H", inbuf, 4, DOECHO);
+
+ closetime = atoi(inbuf);
+ if(closetime <= 0)
+ closetime = 1;
+ else if(closetime >10)
+ closetime = 10;
+
+ closetime = closetime * 86400 + time(NULL);
+ setbfile(buf, bname, STR_new_control);
+ fp = fopen(buf, "w");
+ fprintf(fp, "00\n%lu\n", closetime);
+
+ outs("\n½Ð¨Ì§Ç¿é¤J¿ï¶µ, «ö ENTER §¹¦¨³]©w");
+ num = 0;
+ while(!aborted) {
+ sprintf(buf, "%c) ", num + 'A');
+ getdata((num % 15) + 2, (num / 15) * 40, buf, inbuf, 36, DOECHO);
+ if(*inbuf) {
+ fprintf(fp, "%1c) %s\n", (num+'A'), inbuf);
+ num++;
+ }
+ if((*inbuf == '\0' && num >= 1) || num == 30)
+ aborted = 1;
+ }
+ sprintf(buf, "½Ð°Ý¨C¤H³Ì¦h¥i§ë´X²¼¡H([1]¡ã%d): ", num);
+
+ getdata(t_lines-3, 0, buf, inbuf, 3, DOECHO);
+
+ if(atoi(inbuf) <= 0 || atoi(inbuf) > num)
+ strcpy(inbuf,"1");
+
+ rewind(fp);
+ fprintf(fp, "%2d\n", MAX(1, atoi(inbuf)));
+ fclose(fp);
+
+ if(fhp->bvote == 2)
+ fhp->bvote = 0;
+ else if(fhp->bvote == 1)
+ fhp->bvote = 2;
+ else if(fhp->bvote == 2)
+ fhp->bvote = 1;
+
+ fhp->bvote ++;
+
+ if(substitute_record(fn_board, fhp, sizeof(*fhp), pos) == -1)
+ outs(err_board_update);
+ reset_board(pos);
+ outs("¶}©l§ë²¼¤F¡I");
+
+ return FULLUPDATE;
+}
+
+static int vote_flag(char *bname, int index, char val) {
+ char buf[256], flag;
+ int fd, num, size;
+
+ if(index)
+ sprintf(STR_new_flags, "%s%d", STR_bv_flags, index);
+ else
+ strcpy(STR_new_flags, STR_bv_flags);
+
+ num = usernum - 1;
+ setbfile(buf, bname, STR_new_flags);
+ if((fd = open(buf, O_RDWR | O_CREAT, 0600)) == -1)
+ return -1;
+ size = lseek(fd, 0, SEEK_END);
+ memset(buf, 0, sizeof(buf));
+ while(size <= num) {
+ write(fd, buf, sizeof(buf));
+ size += sizeof(buf);
+ }
+ lseek(fd, num, SEEK_SET);
+ read(fd, &flag, 1);
+ if(flag == 0 && val != 0) {
+ lseek(fd, num, SEEK_SET);
+ write(fd, &val, 1);
+ }
+ close(fd);
+ return flag;
+}
+
+static int same(char compare, char list[], int num) {
+ int n;
+ int rep = 0;
+
+ for(n = 0; n < num; n++) {
+ if(compare == list[n])
+ rep = 1;
+ if(rep == 1)
+ list[n] = list[n + 1];
+ }
+ return rep;
+}
+
+static int user_vote_one(char *bname, int ind) {
+ FILE* cfp,*fcm;
+ char buf[STRLEN];
+ boardheader_t *fhp;
+ int pos = 0, i = 0, count = 0, tickets, fd;
+ char inbuf[80], choices[31], vote[4], chosen[31];
+ time_t closetime;
+
+ if(ind) {
+ sprintf(STR_new_ballots, "%s%d", STR_bv_ballots, ind);
+ sprintf(STR_new_control, "%s%d", STR_bv_control, ind);
+ sprintf(STR_new_desc, "%s%d", STR_bv_desc, ind);
+ sprintf(STR_new_flags, "%s%d", STR_bv_flags, ind);
+ sprintf(STR_new_comments, "%s%d", STR_bv_comments, ind);
+ sprintf(STR_new_limited, "%s%d", STR_bv_limited, ind);
+ } else {
+ strcpy(STR_new_ballots, STR_bv_ballots);
+ strcpy(STR_new_control, STR_bv_control);
+ strcpy(STR_new_desc, STR_bv_desc);
+ strcpy(STR_new_flags, STR_bv_flags);
+ strcpy(STR_new_comments, STR_bv_comments);
+ strcpy(STR_new_limited, STR_bv_limited);
+ }
+
+ setbfile(buf, bname, STR_new_control);
+ cfp = fopen(buf,"r");
+ if(!cfp)
+ return FULLUPDATE;
+
+ setbfile(buf, bname, STR_new_limited); /* Ptt */
+ if(dashf(buf)) {
+ setbfile(buf, bname, FN_CANVOTE);
+ if(!belong(buf, cuser.userid)) {
+ fclose(cfp);
+ outs("\n\n¹ï¤£°_! ³o¬O¨p¤H§ë²¼..§A¨Ã¨S¦³¨üÁÜ­ò!");
+ pressanykey();
+ return FULLUPDATE;
+ } else {
+ outs("\n\n®¥³ß§A¨üÁܦ¹¦¸¨p¤H§ë²¼....<«ö¥ô·NÁäÀ˵ø¦¹¦¸¨üÁܦW³æ>");
+ pressanykey();
+ more(buf, YEA);
+ }
+ }
+ if(vote_flag(bname, ind, '\0')) {
+ outs("\n\n¦¹¦¸§ë²¼¡A§A¤w§ë¹L¤F¡I");
+ pressanykey();
+ return FULLUPDATE;
+ }
+
+ setutmpmode(VOTING);
+ setbfile(buf, bname, STR_new_desc);
+ more(buf, YEA);
+
+ stand_title("§ë²¼½c");
+ if((pos = getbnum(bname)) <= 0)
+ return 0;
+
+ fhp = bcache + pos - 1;
+ fgets(inbuf, sizeof(inbuf), cfp);
+ tickets = atoi(inbuf);
+ fscanf(cfp,"%lu\n", &closetime);
+
+ prints("§ë²¼¤è¦¡¡G½T©w¦n±zªº¿ï¾Ü«á¡A¿é¤J¨ä¥N½X(A, B, C...)§Y¥i¡C\n"
+ "¦¹¦¸§ë²¼§A¥i¥H§ë %1d ²¼¡C"
+ "«ö 0 ¨ú®ø§ë²¼ , 1 §¹¦¨§ë²¼\n"
+ "¦¹¦¸§ë²¼±Nµ²§ô©ó¡G%s \n",
+ tickets, ctime(&closetime));
+ move(5, 0);
+ memset(choices, 0, sizeof(choices));
+ memset(chosen , 0, sizeof(chosen));
+
+ while(fgets(inbuf, sizeof(inbuf), cfp)) {
+ move((count % 15) + 5, (count / 15) * 40);
+ prints( " %s", strtok(inbuf, "\n\0"));
+ choices[count++] = inbuf[0];
+ }
+ fclose(cfp);
+
+ while(1) {
+ vote[0] = vote[1] = '\0';
+ move(t_lines - 2, 0);
+ prints("§AÁÙ¥i¥H§ë %2d ²¼", tickets - i);
+ getdata(t_lines - 4, 0, "¿é¤J±zªº¿ï¾Ü: ", vote, 3, DOECHO);
+ *vote = toupper(*vote);
+ if(vote[0] == '0' || (!vote[0] && !i)) {
+ outs("°Oªº¦A¨Ó§ë³á!!");
+ break;
+ } else if(vote[0] == '1' && i)
+ ;
+ else if(!vote[0])
+ continue;
+ else if(index(choices, vote[0]) == NULL) /* µL®Ä */
+ continue;
+ else if(same(vote[0], chosen, i)) {
+ move(((vote[0] - 'A') % 15) + 5, (((vote[0] - 'A')) / 15) * 40);
+ prints(" ");
+ i--;
+ continue;
+ } else {
+ if(i == tickets)
+ continue;
+ chosen[i] = vote[0];
+ move(((vote[0]-'A') % 15) + 5, (((vote[0] - 'A')) / 15) * 40);
+ prints("*");
+ i++;
+ continue;
+ }
+
+ if(vote_flag(bname, ind, vote[0]) != 0)
+ prints("­«ÂЧ벼! ¤£¤©­p²¼¡C");
+ else {
+ setbfile(buf, bname, STR_new_ballots);
+ if((fd = open(buf, O_WRONLY | O_CREAT | O_APPEND, 0600)) == 0)
+ outs("µLªk§ë¤J²¼Ôo\n");
+ else {
+ struct stat statb;
+ char buf[3], mycomments[3][74], b_comments[80];
+
+ for(i = 0; i < 3; i++)
+ strcpy(mycomments[i], "\n");
+
+ flock(fd, LOCK_EX);
+ for(count = 0; count < 31; count++) {
+ if(chosen[count])
+ write(fd, &chosen[count], 1);
+ }
+ flock(fd, LOCK_UN);
+ fstat(fd, &statb);
+ close(fd);
+ getdata(b_lines - 2, 0,
+ "±z¹ï³o¦¸§ë²¼¦³¤°»òÄ_¶Qªº·N¨£¶Ü¡H(y/n)[N]",
+ buf, 3 ,DOECHO);
+ if(buf[0] == 'Y' || buf[0] == 'y'){
+ do {
+ move(5,0);clrtobot();
+ outs("½Ð°Ý±z¹ï³o¦¸§ë²¼¦³¤°»òÄ_¶Qªº·N¨£¡H"
+ "³Ì¦h¤T¦æ¡A«ö[Enter]µ²§ô");
+ for(i = 0; (i < 3) &&
+ getdata(7 + i, 0, "¡G", mycomments[i], 74,
+ DOECHO); i++);
+ getdata(b_lines-2,0, "(S)Àx¦s (E)­«·s¨Ó¹L "
+ "(Q)¨ú®ø¡H[S]", buf, 3, LCECHO);
+ } while(buf[0] == 'E' || buf[0] == 'e');
+ if(buf[0] == 'Q' || buf[0] == 'q')
+ break;
+ setbfile(b_comments, bname, STR_new_comments);
+ if(mycomments[0])
+ if((fcm = fopen(b_comments, "a"))){
+ fprintf(fcm,
+ "\033[36m¡³¨Ï¥ÎªÌ\033[1;36m %s "
+ "\033[;36mªº«Øij¡G\033[m\n",
+ cuser.userid);
+ for(i = 0; i < 3; i++)
+ fprintf(fcm, " %s\n", mycomments[i]);
+ fprintf(fcm, "\n");
+ fclose(fcm);
+ }
+ }
+ move(b_lines - 1 ,0);
+ prints("¤w§¹¦¨§ë²¼¡I\n");
+ }
+ }
+ break;
+ }
+ pressanykey();
+ return FULLUPDATE;
+}
+
+static int user_vote(char *bname) {
+ int pos;
+ boardheader_t *fhp;
+ char buf[STRLEN];
+ FILE* fp,*xfp;
+ int i, x = -1;
+ char genbuf[STRLEN];
+ char inbuf[80];
+
+ if((pos = getbnum(bname)) <= 0)
+ return 0;
+
+ fhp = bcache + pos - 1;
+
+ move(0,0);
+ clrtobot();
+
+ if(fhp->bvote == 2 || fhp->bvote == 0) {
+ outs("\n\n¥Ø«e¨Ã¨S¦³¥ô¦ó§ë²¼Á|¦æ¡C");
+ pressanykey();
+ return FULLUPDATE;
+ }
+
+ if(!HAS_PERM(PERM_LOGINOK)) {
+ outs("\n¹ï¤£°_! ±z¥¼º¡¤G¤Q·³, ÁÙ¨S¦³§ë²¼Åv³á!");
+ pressanykey();
+ return FULLUPDATE;
+ }
+
+ strcpy(STR_new_control, STR_bv_control);
+ strcpy(STR_new_title, STR_bv_title);
+ setbfile(buf, bname, STR_new_control);
+ move(0, 0);
+ if((fp = fopen(buf, "r"))) {
+ prints("(0) ");
+ x = 0;
+ fclose(fp);
+
+ setbfile(buf, bname, STR_new_title);
+ if((xfp = fopen(buf,"r")))
+ fgets(inbuf, sizeof(inbuf), xfp);
+ else
+ strcpy(inbuf, "µL¼ÐÃD");
+ prints("%s\n", inbuf);
+ fclose(xfp);
+ }
+
+ for(i = 1; i < 9; i++) {
+ sprintf(STR_new_control, "%s%d", STR_bv_control, i);
+ sprintf(STR_new_title, "%s%d", STR_bv_title, i);
+ setbfile(buf, bname, STR_new_control);
+ if((fp = fopen(buf, "r"))) {
+ prints("(%d) ", i);
+ x = i;
+ fclose(fp);
+
+ setbfile(buf, bname, STR_new_title);
+ if((xfp = fopen(buf, "r")))
+ fgets(inbuf, sizeof(inbuf), xfp);
+ else
+ strcpy(inbuf, "µL¼ÐÃD");
+ prints("%s\n", inbuf);
+ fclose(xfp);
+ }
+ }
+
+ if(x < 0)
+ return FULLUPDATE;
+
+ sprintf(buf, "­n§ë´X¸¹§ë²¼ [%d] ", x);
+
+ getdata(b_lines - 1, 0, buf, genbuf, 4, LCECHO);
+
+ if(genbuf[0] < '0' || genbuf[0] > '8')
+ genbuf[0] = x + '0';
+
+ if(genbuf[0] != '0')
+ sprintf(STR_new_control, "%s%c", STR_bv_control, genbuf[0]);
+ else
+ strcpy(STR_new_control, STR_bv_control);
+
+ setbfile(buf, bname, STR_new_control);
+
+ if((fp = fopen(buf, "r"))){
+ fclose(fp);
+
+ return user_vote_one(bname, genbuf[0] - '0');
+ } else
+ return FULLUPDATE;
+}
+
+static int vote_results(char *bname) {
+ char buf[STRLEN];
+
+ setbfile(buf, bname, STR_bv_results);
+ if(more(buf, YEA) == -1)
+ outs("\n¥Ø«e¨S¦³¥ô¦ó§ë²¼ªºµ²ªG¡C");
+ return FULLUPDATE;
+}
+
+int b_vote_maintain() {
+ return vote_maintain(currboard);
+}
+
+int b_vote() {
+ return user_vote(currboard);
+}
+
+int b_results() {
+ return vote_results(currboard);
+}
diff --git a/mbbsd/voteboard.c b/mbbsd/voteboard.c
new file mode 100644
index 00000000..1286d986
--- /dev/null
+++ b/mbbsd/voteboard.c
@@ -0,0 +1,447 @@
+/* $Id: voteboard.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "modes.h"
+#include "common.h"
+#include "perm.h"
+#include "proto.h"
+
+#define VOTEBOARD "NewBoard"
+
+extern char currboard[];
+extern int currbid;
+extern boardheader_t *bcache;
+extern int currmode;
+extern userec_t cuser;
+
+void do_voteboardreply(fileheader_t *fhdr){
+ char genbuf[1024];
+ char reason[60];
+ char fpath[80];
+ char oldfpath[80];
+ char opnion[10];
+ char *ptr;
+ FILE *fo, *fp;
+ fileheader_t votefile;
+ int len;
+ int i, j;
+ int fd;
+ time_t endtime, now = time(NULL);
+ int hastime = 0;
+
+
+ clear();
+ if(!(currmode & MODE_POST)) {
+ move(5, 10);
+ outs("¹ï¤£°_¡A±z¥Ø«eµLªk¦b¦¹µoªí¤å³¹¡I");
+ pressanykey();
+ return;
+ }
+
+ setbpath(fpath, currboard);
+ stampfile(fpath, &votefile);
+
+ setbpath(oldfpath, currboard);
+
+ strcat(oldfpath, "/");
+ strcat(oldfpath, fhdr->filename);
+
+ fp = fopen(oldfpath, "r");
+
+ len = strlen(cuser.userid);
+
+ while(fgets(genbuf, 1024, fp)){
+ if (!strncmp(genbuf, "³s¸pµ²§ô®É¶¡", 12)){
+ hastime = 1;
+ ptr = strchr(genbuf, '(');
+ sscanf(ptr+1, "%ld", &endtime);
+ if (endtime < now){
+ prints("³s¸p®É¶¡¤w¹L");
+ pressanykey();
+ fclose(fp);
+ return;
+ }
+ }
+ if (!strncmp(genbuf+4, cuser.userid, len)){
+ move(5, 10);
+ prints("±z¤w¸g³s¸p¹L¥»½g¤F");
+ opnion[0] = 'n';
+ getdata(7, 0, "­n­×§ï±z¤§«eªº³s¸p¶Ü¡H(Y/N) [N]", opnion, 3, LCECHO);
+ if (opnion[0] != 'y'){
+ fclose(fp);
+ return;
+ }
+ strcpy(reason, genbuf+19);
+ }
+ }
+ fclose(fp);
+
+ if((fd = open(oldfpath, O_RDONLY)) == -1)
+ return;
+ flock(fd, LOCK_EX);
+
+ fo = fopen(fpath, "w");
+
+ if (!fo)
+ return;
+ i = 0;
+ while(fo){
+ j = 0;
+ do{
+ if (read(fd, genbuf+j, 1)<=0){
+ flock(fd, LOCK_UN);
+ close(fd);
+ fclose(fo);
+ unlink(fpath);
+ return;
+ }
+ j++;
+ }while(genbuf[j-1] !='\n');
+ genbuf[j] = '\0';
+ i++;
+ if (!strncmp("----------", genbuf, 10))
+ break;
+ if (i > 3)
+ prints(genbuf);
+ fprintf(fo, "%s", genbuf);
+ }
+ if (!hastime){
+ now += 14*24*60*60;
+ fprintf(fo, "³s¸pµ²§ô®É¶¡: (%ld)%s", now, ctime(&now));
+ now -= 14*24*60*60;
+ }
+
+ fprintf(fo, "%s", genbuf);
+
+ do{
+ if (!getdata(18, 0, "½Ð°Ý±z (Y)¤ä«ù (N)¤Ï¹ï ³o­ÓijÃD¡G", opnion, 3, LCECHO)){
+ flock(fd, LOCK_UN);
+ close(fd);
+ fclose(fo);
+ unlink(fpath);
+ return;
+ }
+ }while(opnion[0] != 'y' && opnion[0] != 'n');
+
+ if (!getdata(20, 0, "½Ð°Ý±z»P³o­ÓijÃDªºÃö«Y©Î³s¸p²z¥Ñ¬°¦ó¡G", reason, 40, DOECHO)){
+ flock(fd, LOCK_UN);
+ close(fd);
+ fclose(fo);
+ unlink(fpath);
+ return;
+ }
+
+ i = 0;
+
+ while(fo){
+ i++;
+ j = 0;
+ do{
+ if (read(fd, genbuf+j, 1)<=0){
+ flock(fd, LOCK_UN);
+ close(fd);
+ fclose(fo);
+ unlink(fpath);
+ return;
+ }
+ j++;
+ }while(genbuf[j-1] !='\n');
+ genbuf[j] = '\0';
+ if (!strncmp("----------", genbuf, 10))
+ break;
+ if (strncmp(genbuf+4, cuser.userid, len))
+ fprintf(fo, "%3d.%s", i, genbuf+4);
+ else
+ i--;
+ }
+ if (opnion[0] == 'y')
+ fprintf(fo, "%3d.%-15s%-34s ¨Ó·½:%s\n", i, cuser.userid, reason,cuser.lasthost);
+ i = 0;
+ fprintf(fo, "%s", genbuf);
+ while(fo){
+ i++;
+ j = 0;
+ do{
+ if (!read(fd, genbuf+j, 1))
+ break;
+ j++;
+ }while(genbuf[j-1] !='\n');
+ genbuf[j] = '\0';
+ if (j <= 3)
+ break;
+ if (strncmp(genbuf+4, cuser.userid, len))
+ fprintf(fo, "%3d.%s", i, genbuf+4);
+ else
+ i--;
+ }
+ if (opnion[0] == 'n')
+ fprintf(fo, "%3d.%-15s%-34s ¨Ó·½:%s\n", i, cuser.userid, reason,cuser.lasthost);
+ flock(fd, LOCK_UN);
+ close(fd);
+ fclose(fo);
+ unlink(oldfpath);
+ rename(fpath, oldfpath);
+}
+
+int do_voteboard() {
+ fileheader_t votefile;
+ char topic[100];
+ char title[80];
+ char genbuf[1024];
+ char fpath[80];
+ FILE* fp;
+ int temp, i;
+ time_t now = time(NULL);
+
+ clear();
+ if(!(currmode & MODE_POST)) {
+ move(5, 10);
+ outs("¹ï¤£°_¡A±z¥Ø«eµLªk¦b¦¹µoªí¤å³¹¡I");
+ pressanykey();
+ return FULLUPDATE;
+ }
+
+ move(0, 0);
+ clrtobot();
+ prints("±z¥¿¦b¨Ï¥Î PTT ªº³s¸p¨t²Î\n");
+ prints("¥»³s¸p¨t²Î±N¸ß°Ý±z¤@¨Ç°ÝÃD¡A½Ð¤p¤ß¦^µª¤~¯à¶}©l³s¸p\n");
+ prints("¥ô·N´£¥X³s¸p®×ªÌ¡A±N³Q¦C¤J¥»¨t²Î¤£¨üÅwªï¨Ï¥ÎªÌ³á\n");
+ pressanykey();
+ move(0, 0);
+ clrtobot();
+ prints("(1)¥Ó½Ð·sª© (2)¼o°£Âª© (3)³s¸pª©¥D (4)½}§Kª©¥D\n");
+ if (!strcmp(currboard, VOTEBOARD))
+ prints("(5)³s¸p¤p²Õªø (6)½}§K¤p²Õªø ");
+ if (!strcmp(currboard, VOTEBOARD) && HAS_PERM(PERM_SYSOP))
+ prints("(7)¯¸¥Á¤½§ë");
+ prints("(8)¥Ó½Ð·s¸s²Õ");
+
+ do{
+ getdata(3, 0, "½Ð¿é¤J³s¸pÃþ§O¡G", topic, 3, DOECHO);
+ temp = atoi(topic);
+ }while(temp <= 0 && temp >= 9);
+
+ switch(temp){
+ case 1:
+ do{
+ if (!getdata(4, 0, "½Ð¿é¤J¬Ýª©­^¤å¦WºÙ¡G", topic, IDLEN+1, DOECHO))
+ return FULLUPDATE;
+ else if (invalid_brdname(topic))
+ outs("¤£¬O¥¿½Tªº¬Ýª©¦WºÙ");
+ else if (getbnum(topic) > 0)
+ outs("¥»¦WºÙ¤w¸g¦s¦b");
+ else
+ break;
+ }while(temp > 0);
+ sprintf(title, "[¥Ó½Ð·sª©] %s", topic);
+ sprintf(genbuf, "%s\n\n%s%s\n%s","¥Ó½Ð·sª©", "­^¤å¦WºÙ: ", topic, "¤¤¤å¦WºÙ: ");
+
+ if (!getdata(5, 0, "½Ð¿é¤J¬Ýª©¤¤¤å¦WºÙ¡G", topic, 20, DOECHO))
+ return FULLUPDATE;
+ strcat(genbuf, topic);
+ strcat(genbuf, "\n¬Ýª©Ãþ§O: ");
+ if (!getdata(6, 0, "½Ð¿é¤J¬Ýª©Ãþ§O¡G", topic, 20, DOECHO))
+ return FULLUPDATE;
+ strcat(genbuf, topic);
+ strcat(genbuf, "\nª©¥D¦W³æ: ");
+ getdata(7, 0, "½Ð¿é¤Jª©¥D¦W³æ¡G", topic, IDLEN * 3 + 3, DOECHO);
+ strcat(genbuf, topic);
+ strcat(genbuf, "\n¥Ó½Ð­ì¦]: \n");
+ outs("½Ð¿é¤J¥Ó½Ð­ì¦](¦Ü¦h¤­¦æ)¡A­n²M·¡¶ñ¼g¤£µM¤£·|®Ö­ã³á");
+ for(i= 8;i<13;i++){
+ if (!getdata(i, 0, "¡G", topic, 60, DOECHO))
+ break;
+ strcat(genbuf, topic);
+ strcat(genbuf, "\n");
+ }
+ if (i==8)
+ return FULLUPDATE;
+ break;
+ case 2:
+ do{
+ if (!getdata(4, 0, "½Ð¿é¤J¬Ýª©­^¤å¦WºÙ¡G", topic, IDLEN+1, DOECHO))
+ return FULLUPDATE;
+ else if (getbnum(topic) <= 0)
+ outs("¥»¦WºÙ¨Ã¤£¦s¦b");
+ else
+ break;
+ }while(temp > 0);
+ sprintf(title, "[¼o°£Âª©] %s", topic);
+ sprintf(genbuf, "%s\n\n%s%s\n","¼o°£Âª©", "­^¤å¦WºÙ: ", topic);
+ strcat(genbuf, "\n¼o°£­ì¦]: \n");
+ outs("½Ð¿é¤J¼o°£­ì¦](¦Ü¦h¤­¦æ)¡A­n²M·¡¶ñ¼g¤£µM¤£·|®Ö­ã³á");
+ for(i= 8;i<13;i++){
+ if (!getdata(i, 0, "¡G", topic, 60, DOECHO))
+ break;
+ strcat(genbuf, topic);
+ strcat(genbuf, "\n");
+ }
+ if (i==8)
+ return FULLUPDATE;
+
+ break;
+ case 3:
+ do{
+ if (!getdata(4, 0, "½Ð¿é¤J¬Ýª©­^¤å¦WºÙ¡G", topic, IDLEN+1, DOECHO))
+ return FULLUPDATE;
+ else if (getbnum(topic) <= 0)
+ outs("¥»¦WºÙ¨Ã¤£¦s¦b");
+ else
+ break;
+ }while(temp > 0);
+ sprintf(title, "[³s¸pª©¥D] %s", topic);
+ sprintf(genbuf, "%s\n\n%s%s\n%s%s","³s¸pª©¥D", "­^¤å¦WºÙ: ", topic, "¥Ó½Ð ID : ", cuser.userid);
+ strcat(genbuf, "\n¥Ó½Ð¬F¨£: \n");
+ outs("½Ð¿é¤J¥Ó½Ð¬F¨£(¦Ü¦h¤­¦æ)¡A­n²M·¡¶ñ¼g¤£µM¤£·|®Ö­ã³á");
+ for(i= 8;i<13;i++){
+ if (!getdata(i, 0, "¡G", topic, 60, DOECHO))
+ break;
+ strcat(genbuf, topic);
+ strcat(genbuf, "\n");
+ }
+ if (i==8)
+ return FULLUPDATE;
+ break;
+ case 4:
+ do{
+ if (!getdata(4, 0, "½Ð¿é¤J¬Ýª©­^¤å¦WºÙ¡G", topic, IDLEN+1, DOECHO))
+ return FULLUPDATE;
+ else if ((i = getbnum(topic)) <= 0)
+ outs("¥»¦WºÙ¨Ã¤£¦s¦b");
+ else
+ break;
+ }while(temp > 0);
+ sprintf(title, "[½}§Kª©¥D] %s", topic);
+ sprintf(genbuf, "%s\n\n%s%s\n%s","½}§Kª©¥D", "­^¤å¦WºÙ: ", topic, "ª©¥D ID : ");
+ do{
+ if (!getdata(6, 0, "½Ð¿é¤Jª©¥DID¡G", topic, IDLEN + 1, DOECHO))
+ return FULLUPDATE;
+ else if (!userid_is_BM(topic, bcache[i-1].BM))
+ outs("¤£¬O¸Óª©ªºª©¥D");
+ else
+ break;
+ }while(temp > 0);
+ strcat(genbuf, topic);
+ strcat(genbuf, "\n½}§K­ì¦]: \n");
+ outs("½Ð¿é¤J½}§K­ì¦](¦Ü¦h¤­¦æ)¡A­n²M·¡¶ñ¼g¤£µM¤£·|®Ö­ã³á");
+ for(i= 8;i<13;i++){
+ if (!getdata(i, 0, "¡G", topic, 60, DOECHO))
+ break;
+ strcat(genbuf, topic);
+ strcat(genbuf, "\n");
+ }
+ if (i==8)
+ return FULLUPDATE;
+ break;
+ case 5:
+ if (!getdata(4, 0, "½Ð¿é¤J¤p²Õ¤¤­^¤å¦WºÙ¡G", topic, 30, DOECHO))
+ return FULLUPDATE;
+ sprintf(title, "[³s¸p¤p²Õªø] %s", topic);
+ sprintf(genbuf, "%s\n\n%s%s\n%s%s","³s¸p¤p²Õªø", "¤p²Õ¦WºÙ: ", topic, "¥Ó½Ð ID : ", cuser.userid);
+ strcat(genbuf, "\n¥Ó½Ð¬F¨£: \n");
+ outs("½Ð¿é¤J¥Ó½Ð¬F¨£(¦Ü¦h¤­¦æ)¡A­n²M·¡¶ñ¼g¤£µM¤£·|®Ö­ã³á");
+ for(i= 8;i<13;i++){
+ if (!getdata(i, 0, "¡G", topic, 60, DOECHO))
+ break;
+ strcat(genbuf, topic);
+ strcat(genbuf, "\n");
+ }
+ if (i==8)
+ return FULLUPDATE;
+ break;
+ case 6:
+
+ if (!getdata(4, 0, "½Ð¿é¤J¤p²Õ¤¤­^¤å¦WºÙ¡G", topic, 30, DOECHO))
+ return FULLUPDATE;
+ sprintf(title, "[½}§K¤p²Õªø] %s", topic);
+ sprintf(genbuf, "%s\n\n%s%s\n%s","½}§K¤p²Õªø", "¤p²Õ¦WºÙ: ", topic, "¤p²Õªø ID : ");
+ if (!getdata(6, 0, "½Ð¿é¤J¤p²ÕªøID¡G", topic, IDLEN + 1, DOECHO))
+ return FULLUPDATE;
+ strcat(genbuf, topic);
+ strcat(genbuf, "\n½}§K­ì¦]: \n");
+ outs("½Ð¿é¤J½}§K­ì¦](¦Ü¦h¤­¦æ)¡A­n²M·¡¶ñ¼g¤£µM¤£·|®Ö­ã³á");
+ for(i= 8;i<13;i++){
+ if (!getdata(i, 0, "¡G", topic, 60, DOECHO))
+ break;
+ strcat(genbuf, topic);
+ strcat(genbuf, "\n");
+ }
+ if (i==8)
+ return FULLUPDATE;
+ break;
+ case 7:
+ if (!HAS_PERM(PERM_SYSOP))
+ return FULLUPDATE;
+ if (!getdata(4, 0, "½Ð¿é¤J¤½§ë¥DÃD¡G", topic, 30, DOECHO))
+ return FULLUPDATE;
+ sprintf(title, "%s %s", "[¯¸¥Á¤½§ë]", topic);
+ sprintf(genbuf, "%s\n\n%s%s\n","¯¸¥Á¤½§ë", "¤½§ë¥DÃD: ", topic);
+ strcat(genbuf, "\n¤½§ë­ì¦]: \n");
+ outs("½Ð¿é¤J¤½§ë­ì¦](¦Ü¦h¤­¦æ)¡A­n²M·¡¶ñ¼g¤£µM¤£·|®Ö­ã³á");
+ for(i= 8;i<13;i++){
+ if (!getdata(i, 0, "¡G", topic, 60, DOECHO))
+ break;
+ strcat(genbuf, topic);
+ strcat(genbuf, "\n");
+ }
+ if (i==8)
+ return FULLUPDATE;
+ break;
+ case 8:
+ if(!getdata(4, 0, "½Ð¿é¤J¸s²Õ¤¤­^¤å¦WºÙ¡G", topic, 30, DOECHO))
+ return FULLUPDATE;
+ sprintf(title, "[¥Ó½Ð·s¸s²Õ] %s", topic);
+ sprintf(genbuf, "%s\n\n%s%s\n%s%s","¥Ó½Ð¸s²Õ", "¸s²Õ¦WºÙ: ", topic, "¥Ó½Ð ID : ", cuser.userid);
+ strcat(genbuf, "\n¥Ó½Ð¬F¨£: \n");
+ outs("½Ð¿é¤J¥Ó½Ð¬F¨£(¦Ü¦h¤­¦æ)¡A­n²M·¡¶ñ¼g¤£µM¤£·|®Ö­ã³á");
+ for(i= 8;i<13;i++){
+ if (!getdata(i, 0, "¡G", topic, 60, DOECHO))
+ break;
+ strcat(genbuf, topic);
+ strcat(genbuf, "\n");
+ }
+ if (i==8)
+ return FULLUPDATE;
+ break;
+ default:
+ return FULLUPDATE;
+ }
+ strcat(genbuf, "³s¸pµ²§ô®É¶¡: ");
+ now += 14*24*60*60;
+ sprintf(topic, "(%ld)", now);
+ strcat(genbuf, topic);
+ strcat(genbuf, ctime(&now));
+ now -= 14*24*60*60;
+ strcat(genbuf, "----------¤ä«ù----------\n");
+ strcat(genbuf, "----------¤Ï¹ï----------\n");
+ outs("¶}©l³s¸p¹Æ");
+ setbpath(fpath, currboard);
+ stampfile(fpath, &votefile);
+
+ if (!(fp = fopen(fpath, "w"))){
+ outs("¶}ÀÉ¥¢±Ñ¡A½Ðµy­Ô­«¨Ó¤@¦¸");
+ return FULLUPDATE;
+ }
+ fprintf(fp, "%s%s %s%s\n%s%s\n%s%s", "§@ªÌ: ", cuser.userid,
+ "¬ÝªO: ", currboard,
+ "¼ÐÃD: ", title,
+ "®É¶¡: ", ctime(&now));
+ fprintf(fp, "%s\n", genbuf);
+ fclose(fp);
+ strcpy(votefile.owner, cuser.userid);
+ strcpy(votefile.title, title);
+ votefile.savemode = 'S';
+ setbdir(genbuf, currboard);
+ if(append_record(genbuf, &votefile, sizeof(votefile)) != -1)
+ setbtotal(currbid);
+ do_voteboardreply(&votefile);
+ return FULLUPDATE;
+}
diff --git a/mbbsd/xyz.c b/mbbsd/xyz.c
new file mode 100644
index 00000000..786add30
--- /dev/null
+++ b/mbbsd/xyz.c
@@ -0,0 +1,448 @@
+/* $Id: xyz.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "modes.h"
+#include "proto.h"
+
+extern char *fn_note_ans;
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+extern char *BBSName;
+extern char fromhost[];
+extern userinfo_t *currutmp;
+extern int curr_idle_timeout;
+extern userec_t cuser;
+
+/* ¦UºØ²Î­p¤Î¬ÛÃö¸ê°T¦Cªí */
+/* Ptt90¦~«×¤j¾ÇÁp©Û¬dº]¨t²Î */
+int x_90() {
+ extern char dict[21], database[41];
+ strcpy(dict, "(90)­ã¦ÒÃÒ¸¹/©m¦W/¾Ç®Õ/¬ì¨t/Ãþ²Õ");
+ strcpy(database, "etc/90");
+ use_dict();
+ return 0;
+}
+
+/* Ptt89¦~«×¤j¾ÇÁp©Û¬dº]¨t²Î */
+int x_89() {
+ extern char dict[21], database[41];
+ strcpy(dict, "(89)­ã¦ÒÃÒ¸¹/©m¦W/¾Ç®Õ/¬ì¨t/Ãþ²Õ");
+ strcpy(database, "etc/89");
+ use_dict();
+ return 0;
+}
+/* Ptt88¦~«×¤j¾ÇÁp©Û¬dº]¨t²Î */
+int x_88() {
+ extern char dict[21], database[41];
+
+ strcpy(dict, "(88)­ã¦ÒÃÒ¸¹/©m¦W/¾Ç®Õ/¬ì¨t/Ãþ²Õ");
+ strcpy(database, "etc/88");
+ use_dict();
+ return 0;
+}
+/* Ptt87¦~«×¤j¾ÇÁp©Û¬dº]¨t²Î */
+int x_87() {
+ extern char dict[21], database[41];
+
+ strcpy(dict, "(87)­ã¦ÒÃÒ¸¹/©m¦W/¾Ç®Õ/¬ì¨t");
+ strcpy(database, "etc/87");
+ use_dict();
+ return 0;
+}
+
+/* Ptt86¦~«×¤j¾ÇÁp©Û¬dº]¨t²Î */
+int x_86() {
+ extern char dict[21], database[41];
+
+ strcpy(dict, "(86)­ã¦ÒÃÒ¸¹/©m¦W/¾Ç®Õ/¬ì¨t");
+ strcpy(database, "etc/86");
+ use_dict();
+ return 0;
+}
+
+int x_boardman() {
+ more("etc/topboardman", YEA);
+ return 0;
+}
+
+int x_user100() {
+ more("etc/topusr100", YEA);
+ return 0;
+}
+
+int x_history() {
+ more("etc/history", YEA);
+ return 0;
+}
+
+#ifdef HAVE_X_BOARDS
+static int x_boards() {
+ more("etc/topboard.tmp", YEA);
+ return 0;
+}
+#endif
+
+int x_birth() {
+ more("etc/birth.today", YEA);
+ return 0;
+}
+
+int x_weather() {
+ more("etc/weather.tmp", YEA);
+ return 0;
+}
+
+int x_stock() {
+ more("etc/stock.tmp", YEA);
+ return 0;
+}
+
+int x_note() {
+ more(fn_note_ans, YEA);
+ return 0;
+}
+
+int x_issue() {
+ more("etc/day", YEA);
+ return 0;
+}
+
+int x_week() {
+ more("etc/week", YEA);
+ return 0;
+}
+
+int x_today() {
+ more("etc/today", YEA);
+ return 0;
+}
+
+int x_yesterday() {
+ more("etc/yesterday", YEA);
+ return 0;
+}
+
+int x_login() {
+ more("etc/Welcome_login", YEA);
+ return 0;
+}
+
+#ifdef HAVE_INFO
+static int x_program() {
+ more("etc/version", YEA);
+ return 0;
+}
+#endif
+
+#ifdef HAVE_LICENSE
+static int x_gpl() {
+ more("etc/GPL", YEA);
+ return 0;
+}
+#endif
+
+/* Â÷¶} BBS ¯¸ */
+int note() {
+ static char *fn_note_tmp = "note.tmp";
+ static char *fn_note_dat = "note.dat";
+ int total = 0, i, collect, len;
+ struct stat st;
+ char buf[256], buf2[80];
+ int fd, fx;
+ FILE *fp, *foo;
+
+ typedef struct notedata_t {
+ time_t date;
+ char userid[IDLEN + 1];
+ char username[19];
+ char buf[3][80];
+ } notedata_t;
+ notedata_t myitem;
+
+ if(cuser.money < 5) {
+ outmsg("\033[1;41m «u§r! ­n§ë¤­»È¤~¯à¯d¨¥...¨S¿ú­C..\033[m");
+ clrtoeol();
+ refresh();
+ return 0;
+ }
+
+ setutmpmode(EDNOTE);
+ do {
+ myitem.buf[0][0] = myitem.buf[1][0] = myitem.buf[2][0] = '\0';
+ move(12, 0);
+ clrtobot();
+ outs("\n§ë¤­»È... ¹Í... ½Ð¯d¨¥ (¦Ü¦h¤T¦æ)¡A«ö[Enter]µ²§ô");
+ for(i = 0; (i < 3) && getdata(16 + i, 0, "¡G", myitem.buf[i], 78,
+ DOECHO) && *myitem.buf[i]; i++);
+ getdata(b_lines - 1, 0, "(S)Àx¦s (E)­«·s¨Ó¹L (Q)¨ú®ø¡H[S] ",
+ buf, 3, LCECHO);
+
+ if(buf[0] == 'q' || (i == 0 && *buf != 'e'))
+ return 0;
+ } while(buf[0] == 'e');
+ demoney(-5);
+ strcpy(myitem.userid, cuser.userid);
+ strncpy(myitem.username, cuser.username, 18);
+ myitem.username[18] = '\0';
+ time(&(myitem.date));
+
+ /* begin load file */
+ if((foo = fopen(".note", "a")) == NULL)
+ return 0;
+
+ if((fp = fopen(fn_note_ans, "w")) == NULL)
+ return 0;
+
+ if((fx = open(fn_note_tmp, O_WRONLY | O_CREAT, 0644)) <= 0)
+ return 0;
+
+ if((fd = open(fn_note_dat, O_RDONLY)) == -1)
+ total = 1;
+ else if(fstat(fd, &st) != -1) {
+ total = st.st_size / sizeof(notedata_t) + 1;
+ if (total > MAX_NOTE)
+ total = MAX_NOTE;
+ }
+
+ fputs("\033[1;31;44m¡ó¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t"
+ "\033[37m»Ä²¢­W»¶ªO\033[31m¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¡ó"
+ "\033[m\n", fp);
+ collect = 1;
+
+ while(total) {
+ sprintf(buf, "\033[1;31m¢~¢t\033[32m %s \033[37m(%s)",
+ myitem.userid, myitem.username);
+ len = strlen(buf);
+
+ for(i = len ; i < 73; i++)
+ strcat(buf, " ");
+ sprintf(buf2, " \033[1;36m%.14s\033[31m ¢u¢¡\033[m\n",
+ Cdate(&(myitem.date)));
+ strcat(buf, buf2);
+ fputs(buf, fp);
+ if(collect)
+ fputs(buf, foo);
+ for(i = 0 ; i < 3 && *myitem.buf[i]; i++) {
+ fprintf(fp, "\033[1;31m¢x\033[m%-74.74s\033[1;31m¢x\033[m\n",
+ myitem.buf[i]);
+ if(collect)
+ fprintf(foo, "\033[1;31m¢x\033[m%-74.74s\033[1;31m¢x\033[m\n",
+ myitem.buf[i]);
+ }
+ fputs("\033[1;31m¢¢¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w"
+ "¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢£\033[m\n",fp);
+
+ if(collect) {
+ fputs("\033[1;31m¢¢¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w"
+ "¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢£\033[m\n", foo);
+ fclose(foo);
+ collect = 0;
+ }
+
+ write(fx, &myitem, sizeof(myitem));
+
+ if(--total)
+ read(fd, (char *) &myitem, sizeof(myitem));
+ }
+ fputs("\033[1;31;44m¡ó¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w"
+ "¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¡ó\033[m\n",fp);
+ fclose(fp);
+ close(fd);
+ close(fx);
+ Rename(fn_note_tmp, fn_note_dat);
+ more(fn_note_ans, YEA);
+ return 0;
+}
+
+static void mail_sysop() {
+ FILE *fp;
+ char genbuf[200];
+
+ if((fp = fopen("etc/sysop", "r"))) {
+ int i, j;
+ char *ptr;
+
+ typedef struct sysoplist_t {
+ char userid[IDLEN + 1];
+ char duty[40];
+ } sysoplist_t;
+ sysoplist_t sysoplist[9];
+
+ j = 0;
+ while(fgets(genbuf, 128, fp)) {
+ if((ptr = strchr(genbuf, '\n'))) {
+ *ptr = '\0';
+ if((ptr = strchr(genbuf, ':'))) {
+ *ptr = '\0';
+ do {
+ i = *++ptr;
+ } while(i == ' ' || i == '\t');
+ if(i) {
+ strcpy(sysoplist[j].userid, genbuf);
+ strcpy(sysoplist[j++].duty, ptr);
+ }
+ }
+ }
+ }
+
+ move(12, 0);
+ clrtobot();
+ prints("%16s %-18sÅv³d¹º¤À\n\n", "½s¸¹", "¯¸ªø ID");
+
+ for(i = 0; i < j; i++)
+ prints("%15d. \033[1;%dm%-16s%s\033[0m\n",
+ i + 1, 31 + i % 7, sysoplist[i].userid, sysoplist[i].duty);
+ prints("%-14s0. \033[1;%dmÂ÷¶}\033[0m", "", 31 + j % 7);
+ getdata(b_lines - 1, 0, " ½Ð¿é¤J¥N½X[0]¡G",
+ genbuf, 4, DOECHO);
+ i = genbuf[0] - '0' - 1;
+ if(i >= 0 && i < j) {
+ clear();
+ do_send(sysoplist[i].userid, NULL);
+ }
+ }
+}
+
+int m_sysop() {
+ setutmpmode(MSYSOP);
+ mail_sysop();
+ return 0;
+}
+
+int Goodbye() {
+ extern void movie();
+ char genbuf[100];
+
+ getdata(b_lines - 1, 0, "±z½T©w­nÂ÷¶}¡i " BBSNAME " ¡j¶Ü(Y/N)¡H[N] ",
+ genbuf, 3, LCECHO);
+
+ if(*genbuf != 'y')
+ return 0;
+
+ movie(999);
+ if(cuser.userlevel) {
+ getdata(b_lines - 1, 0,
+ "(G)ÀH­·¦Ó³u (M)¦«¹Ú¯¸ªø (N)»Ä²¢­W»¶¬y¨¥ª©¡H[G] ",
+ genbuf, 3, LCECHO);
+ if(genbuf[0] == 'm')
+ mail_sysop();
+ else if(genbuf[0] == 'n')
+ note();
+ }
+
+ clear();
+ prints("\033[1;36m¿Ë·Rªº \033[33m%s(%s)\033[36m¡A§O§Ñ¤F¦A«×¥úÁ{\033[45;33m"
+ " %s \033[40;36m¡I\n¥H¤U¬O±z¦b¯¸¤ºªºµù¥U¸ê®Æ:\033[0m\n",
+ cuser.userid, cuser.username, BBSName);
+ user_display(&cuser, 0);
+ pressanykey();
+
+ more("etc/Logout",NA);
+ pressanykey();
+ u_exit("EXIT ");
+ return QUIT;
+}
+
+/* ¤ä´©¥~±¾µ{¦¡ : tin¡Bgopher¡Bwww¡Bbbsnet¡Bgame¡Bcsh */
+#define LOOKFIRST (0)
+#define LOOKLAST (1)
+#define QUOTEMODE (2)
+#define MAXCOMSZ (1024)
+#define MAXARGS (40)
+#define MAXENVS (20)
+#define BINDIR BBSHOME"/bin/"
+
+#define MAXPATHLEN 256
+
+#ifdef HAVE_TIN
+static int x_tin() {
+ clear();
+ return exec_cmd(NEWS, YEA, "bin/tin.sh", "TIN");
+}
+#endif
+
+#ifdef HAVE_GOPHER
+static int x_gopher() {
+ clear();
+ return exec_cmd(GOPHER, YEA, "bin/gopher.sh", "GOPHER");
+}
+#endif
+
+#ifdef HAVE_WWW
+static int x_www() {
+ return exec_cmd(WWW, NA, "bin/www.sh", "WWW");
+}
+#endif
+
+#ifdef HAVE_IRC
+static int x_irc() {
+ return exec_cmd(XMODE, NA, "bin/irc.sh", "IRC");
+}
+#endif
+
+#ifdef HAVE_ARCHIE
+static int x_archie() {
+ char buf[STRLEN], ans[4];
+ char genbuf1[100], genbuf2[200];
+ char *s;
+
+ setutmpmode(ARCHIE);
+ clear();
+ outs("\nÅwªï¥úÁ{¡i\033[1;33;44m" BBSNAME "\033[m¡j¨Ï¥Î "
+ "\033[32mARCHIE\033[m ¥\\¯à\n");
+ outs("\n¥»¥\\¯à±N¬°±z¦C¥X¦b­þ­Ó FTP ¯¸¦s¦³±z±ý´M§äªºÀÉ®×.\n");
+ outs("\n½Ð¿é¤J±ý·j´Mªº¦r¦ê, ©Îª½±µ«ö <ENTER> ¨ú®ø¡C\n");
+ outs("\n coder by Harimau\n");
+ outs(" modified by Leeym\n");
+ getdata(13,0,"·j´M¦r¦ê¡G",buf,20,DOECHO,0);
+ if(buf[0]=='\0') {
+ prints("\n¨ú®ø·j´M.....\n");
+ pressanykey();
+ return;
+ }
+
+ for(s = buf; *s != '\0'; s++) {
+ if(isspace(*s)) {
+ prints("\n¤@¦¸¥u¯à·j´M¤@­Ó¦r¦ê°Õ, ¤£¯à¤Ó³g¤ß³á!!");
+ pressanykey();
+ return;
+ }
+ }
+ bbssetenv("ARCHIESTRING", buf);
+ exec_cmd(ARCHIE, YEA, "bin/archie.sh", ARCHIE);
+ log_usies("ARCHIE", "");
+ strcpy(genbuf1, buf);
+ sprintf(buf, BBSHOME "/tmp/archie.%s", cuser.userid);
+ if(dashf(buf)) {
+ getdata(0, 0, "­n±Nµ²ªG±H¦^«H½c¶Ü(Y/N)¡H[N]", ans, 3, DOECHO,0);
+ if(*ans == 'y') {
+ fileheader_t mhdr;
+ char title[128], buf1[80];
+ FILE* fp;
+
+ sethomepath(buf1, cuser.userid);
+ stampfile(buf1, &mhdr);
+ strcpy(mhdr.owner, cuser.userid);
+ sprintf(genbuf2, "Archie ·j´MÀÉ®×: %s µ²ªG", genbuf1);
+ strcpy(mhdr.title, genbuf2);
+ mhdr.savemode = 0;
+ mhdr.filemode = 0;
+ sethomedir(title, cuser.userid);
+ append_record(title, &mhdr, sizeof(mhdr));
+ Link(buf, buf1);
+ }
+ more( buf, YEA);
+ unlink (buf);
+ }
+}
+#endif /* HAVE_ARCHIE */
diff --git a/sample/Makefile b/sample/Makefile
new file mode 100644
index 00000000..7ba47da6
--- /dev/null
+++ b/sample/Makefile
@@ -0,0 +1,11 @@
+SUBDIR=etc innd
+BBSHOME?=$(HOME)
+
+all:
+
+install:
+ @for i in $(SUBDIR); do\
+ cd $$i;\
+ make BBSHOME=$(BBSHOME) OSTYPE=$(OSTYPE) $@;\
+ cd ..;\
+ done
diff --git a/sample/crontab b/sample/crontab
new file mode 100644
index 00000000..5acc8403
--- /dev/null
+++ b/sample/crontab
@@ -0,0 +1,56 @@
+20 7 * * * bin/mailog.sh > /dev/null
+20 6 * * * rm -f out/*; rm -f out/.DIR
+
+# ¨C¤Ñ 12:00 17:00 20:00 00:00 ¶}¼ú¡C
+0 2,11,16,21 * * * bin/openticket.sh > /dev/null
+
+# ¨C¤Ñ¦­¤W²M°£¹L´Á¨Ï¥ÎªÌ
+10 7 * * * bin/reaper > /dev/null 2> /dev/null
+
+# ¨C­Ó¤p®É 1 ¤À°õ¦æ¤W¯¸¤H¦¸²Î­p
+1 * * * * bin/account > /dev/null 2> /dev/null
+
+# ¨C­Ó¤p®É 10 ¤À°õ¦æ¼öªù¸ÜÃD²Î­p
+50 * * * * bin/parse_news
+10 * * * * bin/poststat /home/bbs > /dev/null
+
+# ¨C¤Ñ5:30°õ¦æ¨Ï¥ÎªÌ±Æ¦æº]§ó·s
+30 5 * * * bin/topusr 10 etc/topusr > /dev/null
+30 3 * * * bin/topusr 100 etc/topusr100 > /dev/null
+30 5 * * * bin/yearsold > /dev/null
+30 5 * * * bin/horoscope
+
+# ¨C­Ó¤ë¤@, ¤Q¤­¸¹ÂIºq±Æ¦æº]
+20 6 1,15 * * bin/topsong.sh
+
+# ¨C¶g¤T,¤»²Î­pÂà«H©Ò¦³ªO
+35 6 * * 6 bin/showboard ~/.BOARDS > ~/etc/BOARD.rec
+
+# ¨C¶g¤@¦­¤W§âuser home²M¤@²M
+20 3 * * * (/bin/rm -f logins.bad; bin/expire ) > /dev/null
+1 7 * * 1 bin/deluserfile > /dev/null
+
+# ¨C¶g¤G¦­¤W 4:30 , ±N BBS boards ¤¤¶W¹L¤C¤Ñªº SR. ¨t¦CªºÀɮ׬屼
+30 4 * * 2 /usr/bin/find /home/bbs/boards/ -mtime +7 -name SR\* -exec rm -f {} ';'
+30 4 * * 2 /bin/rm -f ~/tmp/*
+
+# ¨C¤Ñ°õ¦æ¤@¦¸¥Í¤éµ{¦
+1 2 * * * bin/birth > /dev/null
+
+# ¨C¤ÑºëµØ°Ïindex¤@¦¸ index«e¬å±¼deletedªººëµØ°Ï
+15 6 * * * rm -rf man/boards/deleted
+20 6 * * * bin/mandex > /dev/null
+30 6 * * * bin/openvice > /dev/null
+
+# ¨C¤Ñ¬å±¼ÂIºq¶W¹L5¤ÑÀÉ®×
+40 6 * * * ( find /home/bbs/etc/SONGO/M* -mtime +5 -exec rm -f {} ';' )
+
+#¤Ñ®ðªÑ²¼
+0 5,11,17,23 * * * bin/weather.sh > /dev/null
+20 12 * * * bin/stock.sh > /dev/null
+
+# ¨C­Ó¤ë¤@¸¹¦­¤W 3:50 , ±N BBS ¨t²Î¤¤ªø«×¬°¹sªºÀɮ׬屼
+50 3 1 * * ( /usr/bin/find /home1/bbs -size 0 -exec rm -f {} ';' )
+
+#¨C¤Ñ¦­¤W 6:30 §âbbs¤¤ªºhome©Mpasswords³Æ¥÷
+30 6 * * * bin/backpasswd.sh > /dev/null
diff --git a/sample/etc/Logout b/sample/etc/Logout
new file mode 100644
index 00000000..c1552af8
--- /dev/null
+++ b/sample/etc/Logout
@@ -0,0 +1,20 @@
+
+¢g¢i ¢j  Á` ºÊ
+ ¢l ¢j¢n¢« ¢ª  (root)
+ ¢k ¢m¢m PTT   DavidYu
+  ¡Y ¢j¢o¢« ¢« I`ll  
+  ¢A ¢n¢m  be back!  °õ¦æ»s§@
+ ¢A ¢¨¡þ  ¢©   (bbsadm)
+ ¢o¢¨¢©¡´¢« ¢g¢d¢d¢© ¢¨   DavidYu
+ ¢n¢c¢i¢i  ¢¨ ¢«  ¾É ºt
+ ¢n   (sysop)
+   ¢w¢j   DomaDoma Ricas 
+ ¢e¢e¢c¢l ¢l   keelar stary
+ ¢n ¢ª ¢m 
+ ¢o¢f¢b ¢ª¡Z ¢k  ¬ü³N«ü¾É
+¢h¢e¢c¢ª¡Z¡Z¡Z¡þ¢ª¢e¢d¢b   Skyline(µøı¯¸ªø) Vica 
+ ¢¨¢i¢« ¢ª  ºë µØ °Ï
+ ¢¨¢«¢¨¢f¢c ¢h¢e¢c¢c¢b¢c  cbcdf
+ ¢n ¢g¢c ¢ª ¢«  ¯S§O·PÁÂ
+ ¢l ¢g¢c¢p ¢©  *s
+ ¡@¢á¢ó£B¢ò¢é¢ì¢í¢© ¢«  (¥»¯¸ªº³Ì¨Î¥D¨¤³á)
diff --git a/sample/etc/Makefile b/sample/etc/Makefile
new file mode 100644
index 00000000..8881af2a
--- /dev/null
+++ b/sample/etc/Makefile
@@ -0,0 +1,18 @@
+SUBDIR=chickens
+BBSHOME?=$(HOME)
+TARGET=$(BBSHOME)/etc/
+FILES= Welcome Welcome_login goodbye register registered ve.hlp Logout\
+ Welcome_birth domain_name_query feast today_boring
+
+all:
+
+install_sub:
+ @for i in $(SUBDIR); do\
+ cd $$i;\
+ make BBSHOME=$(BBSHOME) OSTYPE=$(OSTYPE) install;\
+ cd ..;\
+ done
+
+install: install_sub
+ install -d $(TARGET)
+ install -c -m 644 $(FILES) $(TARGET)
diff --git a/sample/etc/Welcome b/sample/etc/Welcome
new file mode 100644
index 00000000..c8abb5a0
--- /dev/null
+++ b/sample/etc/Welcome
@@ -0,0 +1,18 @@
+
+Welcome to ...
+
+
+
+
+
+ ____ _ _ ____ ____ ____
+| _ \| |_| |_ | __ )| __ ) ___|
+| |_) | __| __| | _ \| _ \___ \
+| __/| |_| |_ | |_) | |_) |__) |
+|_| \__|\__| |____/|____/____/
+
+
+
+
+
+Åwªï»YÁ{¡·PttBBS¡·¥Ø«e¯¸¤W¦³[*u]¤H
diff --git a/sample/etc/Welcome_birth b/sample/etc/Welcome_birth
new file mode 100644
index 00000000..c0496fed
--- /dev/null
+++ b/sample/etc/Welcome_birth
@@ -0,0 +1,23 @@
+ ¶Ù*s ¦£¶Ü? ¤£­n§Ñ°O¦Û¤vªº¥Í¤é³á!! °O±oµoªí·P¨¥­....
+
+  ¢~¢¡¢~¢¡¢~¢w¢w¢¡¢~¢w¢w¢¡¢~¢w¢w¢¡¢~¢¡¢~¢¡
+  ¢x¢¢¢£¢x¢x ¡¸ ¢x¢x ¡¸ ¢x¢x ¡¸ ¢x¢x¢¢¢£¢x
+  ¢x¢~¢¡¢x¢x¢~¢¡¢x¢x¢~¢w¢£¢x¢~¢w¢£¢¢¢¡¢~¢£
+  ¢¢¢£¢¢¢£¢¢¢£¢¢¢£¢¢¢£ ¢¢¢£ ¢¢¢£
+  ¢~¢¡
+ ¢~¢¡ ¡¸ ¢~¢w¢w¢¡¢~¢£¢¢¢¡¢~¢¡ ¢~¢¡¢~¢w¢w¢¡¢~¢¡¢~¢¡
+ ¢x¢¢¢w¢¡¢~¢¡¢x¢~¢w¢£¢¢¢¡¢~¢£¢x¢¢¢w¢¡¢~¢w¢£¢x¢x ¡¸ ¢x¢x¢¢¢£¢x
+ ¢x ¡¸ ¢x¢x¢x¢x¢x ¢x¢¢¢¡¢x¢~¢¡¢x¢x ¡¸ ¢x¢x¢~¢¡¢x¢¢¢¡¢~¢£
+ ¢¢¢w¢w¢£¢¢¢£¢¢¢£ ¢¢¢w¢£¢¢¢£¢¢¢£¢¢¢w¢w¢£¢¢¢£¢¢¢£ ¢¢¢£
+
+Ãظ֤@­º°e¨Î¤H,  ¡ó ¡ó ¡ó ¡ó §å½ð½ð¹ê·~§{¥þÅé­û¤u
+¤©®ÉÁ÷³·Ã¾¤ë¤Ñ;  ¢~¢¡¢~¢¡¢~¢¡¢~¢¡
+¯¬­µ»´§u¶ªF®ü, ¢~¢r¢r¢r¢r¢r¢r¢r¢r¢¡ ¸Û¤ßªº¯¬ºÖ!
+¦¼¼vÂܸñ²{«n¤s; ¢x¡¸¡¹¡¸¡¹¡¸¡¹¡¸¡¹¢x ¤@­Ó¤H¥Íªº¥t¤@­Ó¶¥¬q´N¦¹¶}©l
+¥Í¾÷½´«k¥V¤£Â_, ¢~¢r¢w¢w¢w¢w¢w¢w¢w¢w¢r¢¡ ±æ¯à¤@¦|­·¶¶.
+¤éÂà¬P²¾«Ý©ú¬K; ùéùûùúùûùúùûùúùûùúùûùúùë
+§Ö·NºZ¬¡¤H¶¡¦æ, ¢xùüùýùüùýùüùýùüùýùüùý¢x
+¼Ö­µÀô¨­¼Ö¦Û²K. ¢z¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢{
+ ¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}
+ ¡¹¡¹¯¬§A¥Í¤é§Ö¼Ö¡¹¯¬§A¥Í¤é§Ö¼Ö¡¹¯¬§A¥Í¤é§Ö¼Ö¡¹¯¬§A¥Í¤é§Ö¼Ö¡¹¯¬§A¥Í¤é§Ö¼Ö¡¹
+ ¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b¢b
diff --git a/sample/etc/Welcome_login b/sample/etc/Welcome_login
new file mode 100644
index 00000000..e5560602
--- /dev/null
+++ b/sample/etc/Welcome_login
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+ Åwªï¨Ï¥Î PttBBS ¡I
+
+
+ ¦³¥ô¦ó°ÝÃD½Ð¨ì ptt2.csie.ntu.edu.tw ªº PttSrc ªO°Q½×­ò!
diff --git a/sample/etc/chickens/Makefile b/sample/etc/chickens/Makefile
new file mode 100644
index 00000000..37d46a1b
--- /dev/null
+++ b/sample/etc/chickens/Makefile
@@ -0,0 +1,23 @@
+BBSHOME?=$(HOME)
+TARGET=$(BBSHOME)/etc/chickens/
+FILES= buymedicine buyoo clean deadth eat food hit kiss\
+ medicine nofood nohp nosatis oo read sell toofat tootired\
+ a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16\
+ b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16\
+ c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16\
+ d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 d10 d11 d12 d13 d14 d15 d16\
+ e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 e10 e11 e12 e13 e14 e15 e16\
+ f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13 f14 f15 f16\
+ g0 g1 g2 g3 g4 g5 g6 g7 g8 g9 g10 g11 g12 g13 g14 g15 g16\
+ h0 h1 h2 h3 h4 h5 h6 h7 h8 h9 h10 h11 h12 h13 h14 h15 h16\
+ i0 i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 i16\
+ j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j11 j12 j13 j14 j15 j16\
+ k0 k1 k2 k3 k4 k5 k6 k7 k8 k9 k10 k11 k12 k13 k14 k15 k16\
+ l0 l1 l2 l3 l4 l5 l6 l7 l8 l9 l10 l11 l12 l13 l14 l15 l16\
+ m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 m10 m11 m12 m13 m14 m15 m16
+
+all:
+
+install:
+ install -d $(TARGET)
+ install -c -m 644 $(FILES) $(TARGET)
diff --git a/sample/etc/chickens/a0 b/sample/etc/chickens/a0
new file mode 100644
index 00000000..db81a6e2
--- /dev/null
+++ b/sample/etc/chickens/a0
@@ -0,0 +1,11 @@
+
+
+  //¡þ
+  ¡¸ 
+  ¡´¡´ 
+  ¡´¡´¡´ 
+  ¡´¡´ 
+  
+
+
+
diff --git a/sample/etc/chickens/a1 b/sample/etc/chickens/a1
new file mode 100644
index 00000000..e0517a99
--- /dev/null
+++ b/sample/etc/chickens/a1
@@ -0,0 +1,11 @@
+
+
+
+ ¡H¡H
+ ¢c¢i¢i¢c ¡¹¡I¡I
+ ¡´ ¡´ ¢¬//
+ ¡´ ¡´ |/
+ ¡þ¡´¡´¡þ|
+ /|\
+
+
diff --git a/sample/etc/chickens/a10 b/sample/etc/chickens/a10
new file mode 100644
index 00000000..f57b0c1d
--- /dev/null
+++ b/sample/etc/chickens/a10
@@ -0,0 +1,15 @@
+  ¢¨¢¨
+  ¢« ¡´
+  ¡´ ¡´¡´ ¡´  ¡·¡´
+  ¡´ ¡´ ¡´ ¡´ ¡´  ¢©
+  ¡´  ¡´ ¡´ ¡´ ¡´¡´¡´ ¡´ ¡´
+  ¡´ ¡´  ¡´ ¡´ ¡´
+  ¡´ ¡´  ¡´ ¡´ ¡´
+  ¡´  ¡´ ¡´ ¡´ ¡´
+  ¡´  ¡´ ¡´ ¡´
+ ¡´¡´¡´¢­¡´¡´ ¡´¡´ ¡´¡´
+  ¢¬ ¢­ ¡´¡´¡´ ¡´¡´¡´
+  /\¢­ /\¢­ ¡´¡´ ¡´¡´
+
+
+
diff --git a/sample/etc/chickens/a11 b/sample/etc/chickens/a11
new file mode 100644
index 00000000..34c70f42
--- /dev/null
+++ b/sample/etc/chickens/a11
@@ -0,0 +1,15 @@
+  ¢¨¢¨
+  ¢« ¡´
+  ¡´ ¡´¡´ ¡´  ¡·¡´
+  ¡´ ¡´ ¡´ ¡´ ¡´  ¢©
+  ¡´  ¡´ ¡´ ¡´ ¡´¡´¡´ ¡´ ¡´  ¡´¡´ ¡´¡´
+  ¡´ ¡´  ¡´ ¡´ ¡´ ¡´ ¡ó¡´ ¡´ ¡ó¡´
+  ¡´ ¡´  ¡´ ¡´ ¡´ ¡´ ¢© ¡´  ¢©
+  ¡´  ¡´ ¡´ ¡´ ¡´ ¡´ ¡´ ¡´ ¡´
+  ¡´  ¡´ ¡´ ¡´ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´¡´¢­¡´¡´ ¡´¡´¡´ ¡´¡´¡´
+  ¢¬ ¢­  ¡þ ¢@ ¡þ ¢@
+  /\¢­ /\¢­ /|\ /|\ /|\ /|\
+
+
+
diff --git a/sample/etc/chickens/a12 b/sample/etc/chickens/a12
new file mode 100644
index 00000000..1f5a40e6
--- /dev/null
+++ b/sample/etc/chickens/a12
@@ -0,0 +1,13 @@
+  ¢¨¢¨
+ ¡´¡´  ¢« ¡´
+ ¡´ ¡´ ¡´¡´ ¡´  ¡·¡´
+ ¡´ ¡´ ¡´  ¡´ ¡´ ¡´  ¢©
+ ¡´ ¡´  ¡´ ¡´ ¡´ ¡´ ¡´¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´  ¡´ ¡´  ¡´ ¡´¡´
+  ¡´ ¡´  ¡´ ¡´  ¡´ ¡´ ¡´
+  ¡´  ¡´ ¡´ ¡´  ¡´ ¡´ ¡´
+  ¡´  ¡´ ¡´  ¡´¡´ ¡´
+ ¡´¡´¡´¢­¡´¡´
+  ¢¬ ¢­
+  /\¢­ /\¢­
+
diff --git a/sample/etc/chickens/a13 b/sample/etc/chickens/a13
new file mode 100644
index 00000000..2304849a
--- /dev/null
+++ b/sample/etc/chickens/a13
@@ -0,0 +1,14 @@
+
+  ¢¨¢¨
+  ¢« ¡´
+  ¡¯¡¯ ¡´ ¡´¡´ ¡´  ¡·¡´
+  ¡¯  ¡´ ¡´  ¡´ ¡´ ¡´  ¢©
+  ¡¯  ¡´  ¡´ ¡´ ¡´ ¡´ ¡´¡´ ¡´ ¡´
+ ¡¯  ¡´ ¡´ ¡´ ¡´  ¡´ ¡´¡´
+ ¡¯ ¡¯ ¡´ ¡´  ¡´ ¡´  ¡´ ¡´ ¡´
+  ¡¯ ¡¯  ¡´  ¡´ ¡´ ¡´  ¡´ ¡´ ¡´
+ ¡¯  ¡¯  ¡¯  ¡´ ¡´  ¡´¡´ ¡´
+  ¡¯ ¡¯ ¡´¡´¡´¢­¡´¡´
+  ¢¬ ¢­
+  /\¢­ /\¢­
+
diff --git a/sample/etc/chickens/a14 b/sample/etc/chickens/a14
new file mode 100644
index 00000000..c8fc7efa
--- /dev/null
+++ b/sample/etc/chickens/a14
@@ -0,0 +1,17 @@
+  ¢¨¢¨
+  ¢« ¡´
+  ¡¯¡´ ¡´¡´ ¡´  ¡´¡´
+  ¡¯  ¡´ ¡´  ¡´ ¡´ ¡´  ¢© ±þ®ð¡I¡I
+  ¡¯  ¡´  ¡´ ¡´ ¡´ ¡´ ¡´¡´ ¡´ ¡´
+ ¡¯ ¡´ ¡´ ¡´ ¡´  ¡´ ¡´¡´ °«®ð¡I¡I
+ ¡¯ ¡¯ ¡´ ¡´  ¡´ ¡´  ¡´ ¡´ ¡´  ¢ª
+  ¡¯ ¡¯  ¡´  ¡´ ¡´ ¡´  ¡´ ¡´ ¡´ ¢©¡´-
+ ¡¯  ¡¯  ¡¯  ¡´ ¡´  ¡´¡´ ¡´ |¡´-
+  ¡¯ ¡¯ ¡´¡´¡´¢­¡´¡´ |¡´/ / /
+  ¢¬ ¢­ | ¡´¡´¡´<
+  /\¢­ /\¢­ \ \ \
+
+
+
+
+
diff --git a/sample/etc/chickens/a15 b/sample/etc/chickens/a15
new file mode 100644
index 00000000..79457982
--- /dev/null
+++ b/sample/etc/chickens/a15
@@ -0,0 +1,15 @@
+
+ ¼K¼K¡II CATCH YOU¡I¡I ¢¨¢¨ /
+ ¢« ¡´ | ¡´<
+  ¡¯ ¡´ ¡´¡´ ¡´ ¡ä¡´ |¡´\ \
+  ¡¯  ¡´ ¡´  ¡´ ¡´ ¡´ ¢©¡´\
+  ¡¯  ¡´  ¡´ ¡´ ¡´ ¡´ ¡´¡´ ¡´ ¡´ /¡´\
+ ¡¯  ¡´ ¡´ ¡´ ¡´  ¡´ ¡´¡´ /¡´\
+ ¡¯ ¡¯ ¡´ ¡´  ¡´ ¡´  ¡´ ¡´ ¡´ ¡´¢ª
+  ¡¯ ¡¯  ¡´  ¡´ ¡´ ¡´  ¡´ ¡´ ¡´ ¢© ¡\help...
+ ¡¯  ¡¯  ¡¯  ¡´ ¡´  ¡´¡´ ¡´
+  ¡¯ ¡¯ ¡´¡´¡´¡´¢­¡´
+ ¢¬ ¢­
+  /\¢­ /\¢­
+
+
diff --git a/sample/etc/chickens/a16 b/sample/etc/chickens/a16
new file mode 100644
index 00000000..79457982
--- /dev/null
+++ b/sample/etc/chickens/a16
@@ -0,0 +1,15 @@
+
+ ¼K¼K¡II CATCH YOU¡I¡I ¢¨¢¨ /
+ ¢« ¡´ | ¡´<
+  ¡¯ ¡´ ¡´¡´ ¡´ ¡ä¡´ |¡´\ \
+  ¡¯  ¡´ ¡´  ¡´ ¡´ ¡´ ¢©¡´\
+  ¡¯  ¡´  ¡´ ¡´ ¡´ ¡´ ¡´¡´ ¡´ ¡´ /¡´\
+ ¡¯  ¡´ ¡´ ¡´ ¡´  ¡´ ¡´¡´ /¡´\
+ ¡¯ ¡¯ ¡´ ¡´  ¡´ ¡´  ¡´ ¡´ ¡´ ¡´¢ª
+  ¡¯ ¡¯  ¡´  ¡´ ¡´ ¡´  ¡´ ¡´ ¡´ ¢© ¡\help...
+ ¡¯  ¡¯  ¡¯  ¡´ ¡´  ¡´¡´ ¡´
+  ¡¯ ¡¯ ¡´¡´¡´¡´¢­¡´
+ ¢¬ ¢­
+  /\¢­ /\¢­
+
+
diff --git a/sample/etc/chickens/a2 b/sample/etc/chickens/a2
new file mode 100644
index 00000000..6308e505
--- /dev/null
+++ b/sample/etc/chickens/a2
@@ -0,0 +1,14 @@
+  ¡I¡I¡I  ¢­\\
+  ¡Ë  ¢k
+ ¡´¡´  ¢i¡[
+ ¡´ ¡´ ¢i
+ ¡¸ ¡´ ¢k
+ ¡ý\¢­ ¡´
+
+ ¡´ ¡´
+ ¡þ¡´ ¡´¢@
+ /|\ /|\  ¢­¡ý¢A ¢B¡ý¢A
+  ¡Ë¡Ë ¡Ë 
+
+
+
diff --git a/sample/etc/chickens/a3 b/sample/etc/chickens/a3
new file mode 100644
index 00000000..d076a956
--- /dev/null
+++ b/sample/etc/chickens/a3
@@ -0,0 +1,13 @@
+  ¡´¡´
+  ¡´ ¡´
+  ¡´ ¡Ö¡´
+  ¡´  ¢©
+  ¡´ ¡´
+  ¡´ ¡´  //¢¬
+  ¡´ ¡´  ¡¸
+  ¡´¡´¡´¡´¢­|/ ¡´
+ ¢¬  | ¡´ ¡´¡´
+ /|\  ¡´ ¡´ ¡´ ¡´
+  ¡´¡´ ¡´ ¡´ 
+ ¡Ë¡Ë
+
diff --git a/sample/etc/chickens/a4 b/sample/etc/chickens/a4
new file mode 100644
index 00000000..ea9d6535
--- /dev/null
+++ b/sample/etc/chickens/a4
@@ -0,0 +1,13 @@
+  ¡´¡´¡´
+  ¡´ ¡´  ¡H¡H¡H 
+  ¡´ ¡ó¡´
+  ¡´ ¢©
+  ¡´ ¡´  ¡H¡H
+  ¡´ ¡´ ¡´  ¡´  ¡å  ¡´
+  ¡´ ¡ ¡´ ¡´  ¡´¢y  ¡´
+  ¡´¡´¡´ ¡´  ¡´¡´
+  ¡´¡´¡´¡´¡´  ¢l
+ ¡þ ¢@  ¡¯ ¢l ¡¯
+ /|\ /|\  ¡¯ ¢l¡¯
+  ¡¯¡¯ 
+
diff --git a/sample/etc/chickens/a5 b/sample/etc/chickens/a5
new file mode 100644
index 00000000..9a014666
--- /dev/null
+++ b/sample/etc/chickens/a5
@@ -0,0 +1,15 @@
+  My Brother¡H¡H
+  ¡´¡´¡´
+  ¡´ ¡´  ¢n
+  ¡´ ¡´  ¡´¡´
+  ¡´  ¡ó ¡ó  ¡´  ¡´ ¡´
+  ¡´ ¡´  ¡´ ¡´
+  ¡´  ¢ª¢«  ¡´  ¡´ ¡´
+  ¡´ ¡´  ¡´ ¡´
+  ¡´ ¡´  ¡´  °s  ¡´
+ /  ¡´¡´¡´¡´¡´ \  ¡´ ¡´
+  /|\ /|\  ¡´¡´¡´¡´¡´
+
+
+
+
diff --git a/sample/etc/chickens/a6 b/sample/etc/chickens/a6
new file mode 100644
index 00000000..e85fba5a
--- /dev/null
+++ b/sample/etc/chickens/a6
@@ -0,0 +1,13 @@
+  ¡´¡´¡´
+  ¡´  ¡´ ¡´  ¡´
+  ¡´ ¡´ ¡´ ¡´ ¡´ ¡´
+  ¡´  ¡´  ¡ä ¡ä  ¡´  ¡´  ¡I¡I¡I¡I 
+  ¡´  ¡´ ¡´  ¡´
+  ¡´ ¡´  ¢ª¢«  ¡´ ¡´  ¢@¡þ
+  ¡´ ¡´  ¡·¡· .
+  ¡´ ¡´  ¡´¡´ . .
+  ¡´ ¡´ . .
+  ¢¬ ¡´¡´¡´¡´¡´ ¢­  . . .
+  / | \ / | \ . . . . .
+
+
diff --git a/sample/etc/chickens/a7 b/sample/etc/chickens/a7
new file mode 100644
index 00000000..6b245d46
--- /dev/null
+++ b/sample/etc/chickens/a7
@@ -0,0 +1,16 @@
+  ¢¨¢¨ 
+  ¢« ¡´  I see you¡I¡I
+ ¡´  ¡·¡´
+ ¡´  ¡û¢© 
+ ¡´¡´¡´ ¡´ ¡´¡û
+ ¡´ ¡´¡´¡´ ¡´ ¡´ ¡û
+ ¡´ ¡´ ¡û
+ ¡´ ¡´ ¡û
+ ¡´ ¡´ ¡û
+ ¡´¡´¡´¢­¡´¡´  .. ¡I¡I¡I¡I
+  ¢¬ ¢­   ¡ä
+  /\¢­ /\¢­  ¡è¡\
+
+
+
+
diff --git a/sample/etc/chickens/a8 b/sample/etc/chickens/a8
new file mode 100644
index 00000000..9482ca62
--- /dev/null
+++ b/sample/etc/chickens/a8
@@ -0,0 +1,13 @@
+  ¢¨¢¨
+  ¢« ¡´
+  ¡´ ¡´¡´ ¡´  ¡·¡´
+  ¡´ ¡´ ¡´ ¡´ ¡´  ¢©
+  ¡´  ¡´ ¡´ ¡´ ¡´¡´¡´ ¡´ ¡´
+  ¡´ ¡´  ¡´ ¡´ ¡´
+  ¡´ ¡´  ¡´ ¡´ ¡´
+  ¡´  ¡´ ¡´ ¡´ ¡´
+  ¡´  ¡´ ¡´ ¡´
+ ¡´¡´¡´¢­¡´¡´
+  ¢¬ ¢­
+  /\¢­ /\¢­
+
diff --git a/sample/etc/chickens/a9 b/sample/etc/chickens/a9
new file mode 100644
index 00000000..e2010a91
--- /dev/null
+++ b/sample/etc/chickens/a9
@@ -0,0 +1,14 @@
+  ¢¨¢¨  ¢©¢©
+  ¢« ¡´ ¡´  ¢ª
+  ¡´ ¡´¡´ ¡´  ¡·¡´ ¡´¡· ¡´
+  ¡´ ¡´ ¡´ ¡´ ¡´  ¢© ¢¨ ¡´
+  ¡´  ¡´ ¡´ ¡´ ¡´¡´¡´ ¡´ ¡´ ¡´ ¡´ ¡´¡´¡´
+  ¡´ ¡´  ¡´ ¡´ ¡´ ¡´ ¡´ ¡´¡´ ¡´
+  ¡´ ¡´  ¡´ ¡´ ¡´ ¡´ ¡´
+  ¡´  ¡´ ¡´ ¡´ ¡´ ¡´ ¡´
+  ¡´  ¡´ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´¡´¢­¡´¡´ ¡´¡´¢¬¡´¡´
+  ¢¬ ¢­  ¢¬ ¢­ 
+  /\¢­ /\¢­  ¢¬/\ ¢¬/\
+
+
diff --git a/sample/etc/chickens/b0 b/sample/etc/chickens/b0
new file mode 100644
index 00000000..5df42752
--- /dev/null
+++ b/sample/etc/chickens/b0
@@ -0,0 +1,9 @@
+
+
+
+
+  
+  ¢« ¢ª 
+   Ÿ  
+  ¢ª ¢« 
+  
diff --git a/sample/etc/chickens/b1 b/sample/etc/chickens/b1
new file mode 100644
index 00000000..0f6bb405
--- /dev/null
+++ b/sample/etc/chickens/b1
@@ -0,0 +1,9 @@
+
+
+  
+  ¢« ¢c¢ª 
+   ¢d ¢d  
+   ¢ªO¢«  
+   ¡´ ¡´  
+  ¢ª ¢« 
+  
diff --git a/sample/etc/chickens/b10 b/sample/etc/chickens/b10
new file mode 100644
index 00000000..920fd9a9
--- /dev/null
+++ b/sample/etc/chickens/b10
@@ -0,0 +1,14 @@
+
+  
+  ¢«¢c¢c ¢ª 
+   ¡_ ¡_  
+   ¡´ ¡o  ¡X¡¸ 
+   ¢ª ¡¿¢« 
+  ¢«¡¿¢ª 
+   ¤f¤f  
+      
+  ¢«/II\¢ª 
+    
+    
+   ¢e  
+  
diff --git a/sample/etc/chickens/b11 b/sample/etc/chickens/b11
new file mode 100644
index 00000000..920fd9a9
--- /dev/null
+++ b/sample/etc/chickens/b11
@@ -0,0 +1,14 @@
+
+  
+  ¢«¢c¢c ¢ª 
+   ¡_ ¡_  
+   ¡´ ¡o  ¡X¡¸ 
+   ¢ª ¡¿¢« 
+  ¢«¡¿¢ª 
+   ¤f¤f  
+      
+  ¢«/II\¢ª 
+    
+    
+   ¢e  
+  
diff --git a/sample/etc/chickens/b12 b/sample/etc/chickens/b12
new file mode 100644
index 00000000..0519b4ed
--- /dev/null
+++ b/sample/etc/chickens/b12
@@ -0,0 +1,15 @@
+
+  ¢«¢c¢c¢ª 
+   ¡_¡_  
+   ¡´¡´  
+   ¢ª¡¿¢«  
+   ¢«¡¿¢ª  
+    ¢ª¢«   
+        
+   IIII  
+  I¡´¡´I 
+  IIIIIIII 
+  IIIIIIII 
+  IIIIIIII 
+    
+   ¢e  
diff --git a/sample/etc/chickens/b13 b/sample/etc/chickens/b13
new file mode 100644
index 00000000..84f408bf
--- /dev/null
+++ b/sample/etc/chickens/b13
@@ -0,0 +1,17 @@
+  
+  ¢«¢c¢c¢ª e 
+   ¡_¡_  
+   ¡o¡o  
+  ¢ª¢ª¢«¢« 
+  ¢«¡¿¢ª 
+   ¡¿  
+   :  
+   :  
+   :  
+   ¡ü¡ü  
+  ¡ü¡ü 
+  ¡ü¡ü 
+  ¡ü¡ü 
+  ¡U 
+   ¢e  
+  
diff --git a/sample/etc/chickens/b14 b/sample/etc/chickens/b14
new file mode 100644
index 00000000..1c7cd389
--- /dev/null
+++ b/sample/etc/chickens/b14
@@ -0,0 +1,16 @@
+
+  ¡´¢f¢f¡´ 
+  ¢«  ¡_¡_  ¢ª 
+     ¡´¡´    
+  ¢ª ¢ª¡¿¢« ¢« 
+  ¢«¡¿¢ª 
+   ]  
+  ¢e     ¢e 
+  ¢e¢eIIII¢e¢e 
+  IIIIII 
+  IIIIIIII 
+  IIIIIIII 
+  IIIIIIII 
+  ¡U 
+   ¢e  
+  
diff --git a/sample/etc/chickens/b15 b/sample/etc/chickens/b15
new file mode 100644
index 00000000..0e325c1c
--- /dev/null
+++ b/sample/etc/chickens/b15
@@ -0,0 +1,17 @@
+
+  ¢« ¢ª 
+   ¡_  
+   ¢«¡´  
+   ¢ª¢« ¢m 
+  ¢m¢«¡¿¢ª¢m 
+  ¢m p ¢m 
+  ¢m   ¢m 
+    IIII  
+   IIIIII  
+  IIIIIIII 
+  IIIIIIII 
+  IIIIIIII 
+  IIIIIIII 
+    
+   ¢e  
+  
diff --git a/sample/etc/chickens/b16 b/sample/etc/chickens/b16
new file mode 100644
index 00000000..b25212a0
--- /dev/null
+++ b/sample/etc/chickens/b16
@@ -0,0 +1,18 @@
+  
+  ¢« ¢ª 
+   ¡_  
+   ¢«¡o  
+   ¢ª¢« ¢m 
+  ¢m¢«¡¿¢ª¢m 
+  ¢m W ¢m 
+  ¢m  ¡U  ¢m 
+  ¢m ¢«¢ª ¢m 
+  ¢m IIII¢i 
+  ¢m IIII¢i 
+  IIII 
+  IIII 
+  IIII 
+  ¡U 
+   ¢e  
+  
+
diff --git a/sample/etc/chickens/b2 b/sample/etc/chickens/b2
new file mode 100644
index 00000000..ffbe656a
--- /dev/null
+++ b/sample/etc/chickens/b2
@@ -0,0 +1,11 @@
+
+
+  
+  ¢« ¢ª 
+   . .  §r 
+  ¢ªO¢« 
+  ¡´ ¡´ 
+  ¢« ¢ª 
+  _ _ 
+  
+
diff --git a/sample/etc/chickens/b3 b/sample/etc/chickens/b3
new file mode 100644
index 00000000..68a81361
--- /dev/null
+++ b/sample/etc/chickens/b3
@@ -0,0 +1,10 @@
+
+
+  
+  ¢«¢c¢c¢ª 
+   ¡_¡_  
+   ¢ª¡¿¢«  
+  ¡´ ¡´ 
+  ¢« ¢ª 
+  ¢d 
+  
diff --git a/sample/etc/chickens/b4 b/sample/etc/chickens/b4
new file mode 100644
index 00000000..fde65f4c
--- /dev/null
+++ b/sample/etc/chickens/b4
@@ -0,0 +1,11 @@
+
+
+  
+  ¢«¢c¢c¢ª 
+   ¡_¡_  
+   ¢ª¡¿¢«  
+  ¡´ ¡´ 
+  ¢« ¢ª 
+    
+  ¢d 
+  
diff --git a/sample/etc/chickens/b5 b/sample/etc/chickens/b5
new file mode 100644
index 00000000..b74b0bfb
--- /dev/null
+++ b/sample/etc/chickens/b5
@@ -0,0 +1,12 @@
+
+
+  
+  ¢«¢c¢c¢ª 
+   ¡_¡_  
+   ¢ª¡¿¢«  
+   ¢ª¢«  
+      
+  ¢« ¢ª 
+    
+  ¢d 
+  
diff --git a/sample/etc/chickens/b6 b/sample/etc/chickens/b6
new file mode 100644
index 00000000..279b0c2a
--- /dev/null
+++ b/sample/etc/chickens/b6
@@ -0,0 +1,12 @@
+
+
+  
+  ¢«¢c¢c¢ª 
+   ¡_¡_  
+   ¢ª¡¿¢«  
+   ¢ª¢«  
+    :   
+  ¢« ¢ª 
+    
+  ¢d 
+  
diff --git a/sample/etc/chickens/b7 b/sample/etc/chickens/b7
new file mode 100644
index 00000000..279b0c2a
--- /dev/null
+++ b/sample/etc/chickens/b7
@@ -0,0 +1,12 @@
+
+
+  
+  ¢«¢c¢c¢ª 
+   ¡_¡_  
+   ¢ª¡¿¢«  
+   ¢ª¢«  
+    :   
+  ¢« ¢ª 
+    
+  ¢d 
+  
diff --git a/sample/etc/chickens/b8 b/sample/etc/chickens/b8
new file mode 100644
index 00000000..0b429152
--- /dev/null
+++ b/sample/etc/chickens/b8
@@ -0,0 +1,13 @@
+
+
+  
+  ¢«¢c¢c ¢ª 
+   ¡_ ¡_  
+   ¡´ ¡o  ¡X¡¸ 
+   ¢ª ¡¿¢« 
+  ¢«¡¿¢ª 
+   ¤f¤f  
+  ¢«/II\¢ª 
+    
+   ¢e  
+  
diff --git a/sample/etc/chickens/b9 b/sample/etc/chickens/b9
new file mode 100644
index 00000000..0b429152
--- /dev/null
+++ b/sample/etc/chickens/b9
@@ -0,0 +1,13 @@
+
+
+  
+  ¢«¢c¢c ¢ª 
+   ¡_ ¡_  
+   ¡´ ¡o  ¡X¡¸ 
+   ¢ª ¡¿¢« 
+  ¢«¡¿¢ª 
+   ¤f¤f  
+  ¢«/II\¢ª 
+    
+   ¢e  
+  
diff --git a/sample/etc/chickens/buymedicine b/sample/etc/chickens/buymedicine
new file mode 100644
index 00000000..5fe11de7
--- /dev/null
+++ b/sample/etc/chickens/buymedicine
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+  W R I G L E Y'S ¢ª
+  £r¡m¢Ò¢Ý¢ã¢Ð¢Ú¢Ó¢Û¢×¢Ü¢â¡n  ¢v¢v¢v¢v¢v¢l
+  CHEWING GUM  ¢×¢Ü¢â¡n ¢l
+ ¢ª ¢ª ¢l
+ ¢v¢v¢v¢v¢v¢v¢v¢v¢v¢v¢v¢v¢v¢v¢v
+
+
+ ¶R¤f­»¿}·í·P«_ÃÄ...
diff --git a/sample/etc/chickens/buyoo b/sample/etc/chickens/buyoo
new file mode 100644
index 00000000..21d5f32a
--- /dev/null
+++ b/sample/etc/chickens/buyoo
@@ -0,0 +1,14 @@
+
+ ¢x ¢x
+  ¡¶____________________¡¶
+ ¢» ¢¨¢© ¢q ¢¨¢© ¢»
+ ¡Ý ¥Ð¥Ð ¥Ð¥Ð ¡Ý
+ ¡¶ ¢i====¥Ð¥Ð====¥Ð¥Ð====¢i ¡¶
+ ¢i£Z£Z£Z£Z¢i£S£S£S£S£S£S£S£S£S£S¢i£Z£Z£Z£Z¢i
+ ¢y¢v¢v¢v¢ª¡·¢«¢v¢v¢v¢v¢v¢v¢v¢v¢ª¡·¢«¢v¢v¢v¢j
+ ¢y ¥Ð¥Ð ¢i ¥Ð¥Ð ¥Ð¥Ð ¥Ð¥Ð ¢i ¥Ð¥Ð ¢j
+  ¢y ¥Ð¥Ð ¢i ¥Ð¥Ð¡±¢p¢p¡±¥Ð¥Ð ¢i ¥Ð¥Ð ¢j
+  ¢y¡°¡°¡°¡°¡°¢i¡°¡°¡°¡°¢p¢p¡°¡°¡°¡°¢i¡°¡°¡°¡°¡°¢j
+ ¡½¢¤¢¤¢¤¢¤¢¤¢¤¢¤¢¤¢¤¢¤¢¨ùùùùùùùù¢©¢¤¢¤¢¤¢¤¢¤¢¤¢¤¢¤¢¤¢¤¡½
+
+ ¨ì±Ð°ó¨D±o¯«©_¤j¸É¤Y¤@Áû
diff --git a/sample/etc/chickens/c0 b/sample/etc/chickens/c0
new file mode 100644
index 00000000..388926ab
--- /dev/null
+++ b/sample/etc/chickens/c0
@@ -0,0 +1,8 @@
+
+
+ ¢¨¢i¢©
+  \¢i/  «z¡ã«z¡ã
+ ¢ª¢Ý¢«
+ ¡þ¢¬¢i
+ ¢¬¢i¢i
+ ¢ª¢i¢«
diff --git a/sample/etc/chickens/c1 b/sample/etc/chickens/c1
new file mode 100644
index 00000000..8311a4af
--- /dev/null
+++ b/sample/etc/chickens/c1
@@ -0,0 +1,9 @@
+
+ ¢¨
+ ¢i¢i¢i¢i ¤°»ò¬O«i¤h°Ú¡H
+ ¢i¢«¡_¢ª¢©
+ ¢ª¢i¢i¢i¢i
+ ¢ª¢i¢i¢«
+ ¢¨ ¡¿ ¢©
+ ¢i ¡· ¢i
+
diff --git a/sample/etc/chickens/c10 b/sample/etc/chickens/c10
new file mode 100644
index 00000000..bfafeffc
--- /dev/null
+++ b/sample/etc/chickens/c10
@@ -0,0 +1,11 @@
+ ¢©
+ ¢i¢i¢i¢i ´Â¯u¼Ç°°½Ö¯à¿ë
+ ¢i¢i¢«¢ª¢i
+ ¢i¢«¢m¢i¢i¢« ´¼·M¥Ã¬O¨â¤½¥­
+ ¢«¢ª¢i¢i¢«
+ ¢ª¢i¡·¢«¡¿¢ª¡·¢i¢«
+ ¢ª¢i ¢® ¢i¢«
+ ¢i¢ª è ¢«¢i
+ ¢ª¢i¢© ¢i¢¨ ¢i
+ ¢i¢i¢i¡´¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢«
+ ¢n¢ª
diff --git a/sample/etc/chickens/c11 b/sample/etc/chickens/c11
new file mode 100644
index 00000000..0170493b
--- /dev/null
+++ b/sample/etc/chickens/c11
@@ -0,0 +1,10 @@
+
+ ¢ª¢i¢© ¢¨
+ ¢i¢i¢i¢i ¤HºÙ¤@¬y¤M¤@¬y
+ ¢ª¢©¢l ¢i¢«¢ª¢i¢i
+¢¨¢i¢i¢i¢i¢i¢i¢i¢i¢i¢i¢i¢i¡´¢i¢i ¢ª¢i¢i¢m¢ª¢i ¤MºÙ¤@¬y¤H¤@¬y
+ ¢¨¢«¢i ¢ª¢i¢i¢«¢ª
+ ¢i¢i¢© ¢ª ¡¿ ¢« ¢¨¢i¢i¢i¢i¢f
+ ¢i¢© ¢ª¢« ¢¨¢i
+ ¢i¢i¢© ¢¨¢i¢i
+ ¢i¢i ªZ ¢i¢i
diff --git a/sample/etc/chickens/c12 b/sample/etc/chickens/c12
new file mode 100644
index 00000000..020ae4ca
--- /dev/null
+++ b/sample/etc/chickens/c12
@@ -0,0 +1,12 @@
+
+ ¢© ¢¨¢i¢«
+ ¢i¢i¢i¢i ªF­·§j¿ô­^¶¯¹Ú
+ ¢i¢i¢«¢ª¢i
+ ¢i¢«¢m¢i¢i¢« ¯º¹ï¤d¤s¸U­«¤Ñ
+ ¢«¢ª¢i¢i¢«
+ ¢©¢ª¢i¡·¢«¡¿¢ª¡·¢i¢«¢¨
+ ¢©¢ª¢i ¢® ¢i¢«¢¨
+¢¨¢i¢© ¢i¢ª ±þ ¢«¢i
+¢« ¢ª¢i¢© ¢i¢¨¢« ¢i
+ ¢i¢i¢i¡´¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢«
+ ¢n¢ª¢©
diff --git a/sample/etc/chickens/c13 b/sample/etc/chickens/c13
new file mode 100644
index 00000000..f842255c
--- /dev/null
+++ b/sample/etc/chickens/c13
@@ -0,0 +1,11 @@
+ ¢ª¢i¢© ¢¨
+ ¢i¢i¢i¢i ´H¼CÀqÅ¥§g¤l·N
+ ¢i¢«¢ª¢i¢i
+ ¢ª¢i¢i¢m¢ª¢i ¶Æµø¤H¶¡¯º¬õ¹Ð
+ ¢ª¢i¢i¢«¢ª
+ ¢ª¢ª ¡¾ ¢«¢«¡¿¢ª¢ª ¡¾ ¢«¢«
+ ¢ª¢ª¢«¢« ¡ý ¢ª¢ª¢«¢«
+  ¢ª¢«¢i ¤Ñ ¢i¢ª¢« 
+  ¢ª¢© ¢i¢¨¢« 
+  ¢ª¢i¢i¢i¡´¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢«
+   ¢n¢ª¢© 
diff --git a/sample/etc/chickens/c14 b/sample/etc/chickens/c14
new file mode 100644
index 00000000..35636ed9
--- /dev/null
+++ b/sample/etc/chickens/c14
@@ -0,0 +1,12 @@
+ ¢ª¢i¢© ¢¨
+ ¢i¢i¢i¢i ¤@­¤@¼C¥­¥Í·N
+ ¢i¢«¢ª¢i¢i ¢l
+ ¢ª¢i¢i¢m¢ª¢i ¢i ­tºÉ¨g¦W¤Q¤­¦~
+ ¢ª¢i¢i¢«¢ª ¢i
+ ¢©¢ª¢ª¢«¢«¡¿¢ª¢ª¢«¢«¢¨¢i
+ ¢©¢ª¢i¡¼¢®¡¼¢i¢«¢¨
+ ¢¨¢i¢©  ¢i¢ª¢©¢® ¢«¢¨ 
+ ¢« ¢ª¢i¢©  ¢i¢¨¢«®©  
+ ¢i¢i¢i¡´¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢«
+  ¢n¢ª¢©¡ý  
+  ¢«¡ý  
diff --git a/sample/etc/chickens/c15 b/sample/etc/chickens/c15
new file mode 100644
index 00000000..89822c4f
--- /dev/null
+++ b/sample/etc/chickens/c15
@@ -0,0 +1,12 @@
+  ¢© ¢© ¢¨
+ ¢ª ¢ª ¢« ¢¨ ­¤¤©¶­µÂìX±¡
+ ¢©¢ª¢i¢© ¢¨ ¢« ¼C¤U¸{¦å°O«ë¤³
+ ¢ª¢© ¢ª ¢i¢i¢i¢i ¢¨ ¢¨¢« ¢¨¢« ¨Ó¦ó¬¤´é»Ý´§¼C
+ ¢ª¢© ¢©  ¢i¢«¢ª¢i¢i ¢« ¢¨¢« ¢¨¢« ¥h¦VÄñºø¥i´_­
+ ¢ª  ¢ª¢i¢i¢m¢ª¢i ¢©
+ ¢ª¢© ¢©¢ª ¢ª¢i¢i¢«¢ª ¢«¢¨ ¢¨¢«
+ ¢©¢ª¢i¢i¢«¡¿¢ª¢i¢i¢«¢¨¢i¢i¢i¢i¡´¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢«
+ ¢¨¢©¢ª¡Ñ¡¼¢®¡¼¡Ñ¢«¢¨¢© ¢g¢ª¢©
+ ¢¨ ¢©¢ª ¢® ¢«¢¨ ¢© ¢«
+ ¢¨ ¢i¢© «ã ¢¨ ¢©
+ ¢¨ ¢i ¢i¢i¢i ¢©
diff --git a/sample/etc/chickens/c16 b/sample/etc/chickens/c16
new file mode 100644
index 00000000..93b54373
--- /dev/null
+++ b/sample/etc/chickens/c16
@@ -0,0 +1,11 @@
+
+ ·R¸¨¬õ¹Ð¤ß¤w¦º ¢¨
+ ¢¨¢i¢i¢i¢i
+ «ù¤M©ê¼C¤F¤@¥Í ¢i¢i¢«¢ª¢i¢i
+ ¢¨ ¢i¢i ¢m¢ª¢i
+ ¢ª¢© ¢©¢ª ¢¨¢i¢i¢i¢i¢«¢ª ¢«¢¨
+¢ª¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¡´¢i¢i¢i¢i¢©¢ª¢i¢i¢«¡¿¢ª¢i¢i¢«¢¨
+ ¢¨¢«¢g ¢©¢ª¢i ¢® ¢i¢«¢¨¢©
+ ¢ª ¢i¢©¢ª ¢® ¢«¢¨ ¢i¢©
+ ¡ã¤M¨g¼C·ö¡ã ¢i¢i¢© Áô ¢¨¢i ¢i¢i¢©
+ ¢i¢i¢i¢i¢i¢i ¢i ¢i¢i¢i¢©
diff --git a/sample/etc/chickens/c2 b/sample/etc/chickens/c2
new file mode 100644
index 00000000..19901098
--- /dev/null
+++ b/sample/etc/chickens/c2
@@ -0,0 +1,9 @@
+
+ ¢©
+ ¢i¢i¢i¢i
+ ¢¨¢«¡_¢ª¢i
+ ¢i¢i¢i¢i¢«
+ ¢ª¢i¢i¢«
+ ¢¨ ¡¿ ¢©
+ ¢¨¢« ¡· ¢ª¢©
+ ¢i ¢i
diff --git a/sample/etc/chickens/c3 b/sample/etc/chickens/c3
new file mode 100644
index 00000000..362d06f0
--- /dev/null
+++ b/sample/etc/chickens/c3
@@ -0,0 +1,8 @@
+
+ ¢©
+ ¢i¢i¢i¢i
+ ¢¨¢«¡_¢ª¢i
+ ¢i¢i¢i¢i¢«
+ ¢ª¢i¢i¢«
+ ¢i¢i¢i¢ª ¡¿ ¢«¢i¢i¢i
+  ¢ª¢« 
diff --git a/sample/etc/chickens/c4 b/sample/etc/chickens/c4
new file mode 100644
index 00000000..88095521
--- /dev/null
+++ b/sample/etc/chickens/c4
@@ -0,0 +1,11 @@
+
+ ¢¨
+ ¢i
+ ¢i ¢¨ §A¡I´±±µ¨ü§Úªº¬D¾Ô¶Ü¡H
+ ¢i ¢i¢i¢i¢i
+ ¢i ¢i¢«¡_¢ª¢i
+ ¢i ¢ª¢i¢i¢i¢i¢ª
+ ¢ª¡´¢« ¢ª¢i¢i¢«
+ ¢i¢i¢i¢ª¢i¡¿¢i¢«¢i¢i¢i¢f
+ ¢i ¢¨ ¢i¢i¢i ¢©
+ ¢¨ ¢i«i¢i ¢©
diff --git a/sample/etc/chickens/c5 b/sample/etc/chickens/c5
new file mode 100644
index 00000000..ad2311ba
--- /dev/null
+++ b/sample/etc/chickens/c5
@@ -0,0 +1,12 @@
+
+
+ ¢¨
+ ¢i
+ ¢i ¢¨ §A¡I´±±µ¨ü§Úªº¬D¾Ô¶Ü¡H
+ ¢i ¢i¢i¢i¢i
+ ¢i ¢i¢«¡_¢ª¢i
+ ¢i ¢ª¢i¢i¢i¢i¢ª
+ ¢ª¡´¢« ¢ª¢i¢i¢«
+ ¢i¢i¢i¢ª¢i¡¿¢i¢«¢i¢i¢i¢f
+ ¢i ¢¨ ¢i¢i¢i ¢©
+ ¢¨ ¢i«i¢i ¢©
diff --git a/sample/etc/chickens/c6 b/sample/etc/chickens/c6
new file mode 100644
index 00000000..ee018e38
--- /dev/null
+++ b/sample/etc/chickens/c6
@@ -0,0 +1,10 @@
+
+ ¢¨ ¢©
+ ¢i ¢i¢i¢i¢i ©ñ°¨¹L¨Ó¡I
+ ¢i ¢i¢«¡_¢i¢i
+ ¢i ¢«¢i¢i¢ª¢i¢«
+ ¢i ¢ª¢i¢i¢«
+ ¢i ¢¨¢i¢«¡¿¢ª¢i¢©
+  ¢ª¡´¢« ¢¨¢«¢i¢®¢i¢i¢©
+ ¢g¢i¢i¢i¢«¢i §Ô ¢i ¢©
+ ¢i ¢i ¢i ¢i
diff --git a/sample/etc/chickens/c7 b/sample/etc/chickens/c7
new file mode 100644
index 00000000..0db89687
--- /dev/null
+++ b/sample/etc/chickens/c7
@@ -0,0 +1,12 @@
+
+ ¢¨
+ ¢i §O ¤H ªº ¥¢ ±Ñ ´N ¬O §Ú ªº §Ö ¼Ö °Õ ¡I
+ ¢i ¢©
+ ¢i ¢i¢i¢i¢i
+ ¢i ¢i¢«¡_¢ª¢i
+ ¢i ¢«¢i¢i¢i¢i¢«
+ ¢i ¢ª¢i¢i¢«
+ ¢i ¢ª¢i¢©¡¿¢¨¢i¢«
+ ¢ª¡´¢« ¢¨¢«¢ª¢i¢«¢i¢©
+ ¢i¢i¢i¢«¢i ¢i ¢©
+ ¢i ¢i ©R ¢i ¢i
diff --git a/sample/etc/chickens/c8 b/sample/etc/chickens/c8
new file mode 100644
index 00000000..22be6bab
--- /dev/null
+++ b/sample/etc/chickens/c8
@@ -0,0 +1,12 @@
+ ¢¨
+ ¢i¢i¢i¢i Âù¸}½ð½¹Ð¥@®ö
+ ¢i¢«¢ª¢i¢i
+ ¢ª¢i¢i¢m¢ª¢i ¤@ªÓ¾áºÉ¥j¤µ·T
+ ¢ª¢i¢i¢«¢ª
+ ¢i¡Û¢«¡¿¢ª¡Û¢i
+ ¢i¢« ¢ª¢i
+ ¢«¢i ¨g ¢i¢ª
+ ¢ª¢© ¢i¢¨
+ ¢ª¢i¢i¢i¡´¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢e¢«
+ ¢¨ ¢n¢ª
+ ¢«
diff --git a/sample/etc/chickens/c9 b/sample/etc/chickens/c9
new file mode 100644
index 00000000..676a0da9
--- /dev/null
+++ b/sample/etc/chickens/c9
@@ -0,0 +1,11 @@
+ ¢©
+ ¢ª¢©
+ ¢ª¢© ¢©
+ ¢ª¢© ¢i¢i¢i¢i ©º¦ç¬õ¹Ð¤Æ¶³·Ï
+ ¢ª¢© ¢i¢i¢«¢ª¢i
+ ¢ª¢© ¢i¢«¢m¢i¢i¢« ¦¿´ò¸¨©Ý¤£ª¾¦~
+ ¢ª¢© ¢«¢ª¢i¢i¢«
+ ¢ª¢© ¢¨¢i¢i¢© ¡¿ ¢¨¢i¢i¢©
+ ¢ª¢© ¢¨¢«¢ª¢©¢¨¢«¢ª¢©
+ ¢ª¢i¢©¢¨¢« ¢©¢ª¢«¢¨ ¢i
+ ¢g¢i¢« ¢ª ¼C ¢« ¢i
diff --git a/sample/etc/chickens/clean b/sample/etc/chickens/clean
new file mode 100644
index 00000000..9d9118a3
--- /dev/null
+++ b/sample/etc/chickens/clean
@@ -0,0 +1,14 @@
+  ùúùùùáùý_____________________¢y¢v¢v¢j_______¢y¢@___
+  ùøùúùáùû______________ ¡þ¢j ¡´ ¡´_________¡´¢y___
+  ùøùüùøùø______________¢y ¡´ _________¢y ¡^____¡´___
+  ùüùùùáùý______________¡´_____________¡´____________
+ ùüùý ùúùùùùùùùû
+ ¡y¢i¢i¢i¢i
+ ¢i¢i¢i¢i
+ ¢b¢b¢b¢b¢b¢b¢b¢b¡·¢i¢i¢i¢i
+ ¢g¢g¢g¢g¢g¢g¢g¢g¢p¢i¢i¢i¢i
+ ¢ªùþùþùþùþùþùþùþùþ ùø
+ ¢ª¢i¢i¢i¢i¢iùùùý
+ ¢¨ùþùþùþùþùþ
+  ¢v¢v¢v¢v¢v¢v
+ ¬~¬~¾þ..²M°£«K«K..
diff --git a/sample/etc/chickens/d0 b/sample/etc/chickens/d0
new file mode 100644
index 00000000..ea818c4d
--- /dev/null
+++ b/sample/etc/chickens/d0
@@ -0,0 +1,10 @@
+
+ |/¢¬
+ ¡¸
+  
+  ¡´¡´ 
+  ¡´µï¡´ 
+  ¡´¡´ 
+  
+
+
diff --git a/sample/etc/chickens/d1 b/sample/etc/chickens/d1
new file mode 100644
index 00000000..91e04a2f
--- /dev/null
+++ b/sample/etc/chickens/d1
@@ -0,0 +1,9 @@
+
+ ¥Í©R¡H¡H
+ ¡\
+ ¢­\| ¡´¡´
+ ¡¹ ¡´¡[ ¡¹
+ ¡I¡I ¡´ ¢¨¢k
+ ¡´ ¡´ ¢©
+ ¡´¡´ \|/ ¢k\|/ \|/
+  ¡Ë 
diff --git a/sample/etc/chickens/d10 b/sample/etc/chickens/d10
new file mode 100644
index 00000000..714254ea
--- /dev/null
+++ b/sample/etc/chickens/d10
@@ -0,0 +1,11 @@
+
+ ¡´¡´ ¡´ ¡I¡I¡I¡I
+ ¡´ ¡´ ¡ä\
+ ¡´ ¡¸ ¡´ ¡´¡´\\ ¡I¡I¡I¡I ||¡ý
+ ¡´ ¡¹ ¡´ ¡ó ||¡ý
+ ¡´¡´ ¡´ ¡´ ¡´ ¢© ¡ó___________
+ ¡´/_¡´¡È¡´ ¡´\_ ¡l¡p ¡ó---¡`¡`¡`¡` . . . . . .
+ ¡´\ ¡´\ ¡´/ ¡´/ ||¡ý
+ ¢ª ¢ª ¡¿ ¢« ¡å/
+
+
diff --git a/sample/etc/chickens/d11 b/sample/etc/chickens/d11
new file mode 100644
index 00000000..b7e86634
--- /dev/null
+++ b/sample/etc/chickens/d11
@@ -0,0 +1,15 @@
+
+ µ¥µ¥§Ú¡I¡I ¢¨¢©¢¨¢©
+ ¢i¢i¢i¢i
+ ¢ª¢i¢i¢«
+ ¡´¡´ ¡´ ¢ª¢«
+ ¡´ ¡¸ ¡´
+ ¡´ ¡¹ ¡´ ¡´¡´\\ ¡´¡´
+ ¡´ ¡¸ ¡´ ¡ä ¡´ ¡´ ¡´¡´\
+ ¡´ ¡´ ¡´ ¡´¡´ ¢© ¡´ ¡´ ¡ä
+ ¡´¢f¡´¢f¡´¢f--¡´¢d¡l¡p ¢f¡´¢f¡´¢f ¡´¢d ¢©
+ ¡´/ ¡´/ ¡´/ \¡´ // // // \\
+ ¢ª\ ¢ª\ ¢ª\ |¢« \| \| \| |/
+  
+
+
diff --git a/sample/etc/chickens/d12 b/sample/etc/chickens/d12
new file mode 100644
index 00000000..ab421653
--- /dev/null
+++ b/sample/etc/chickens/d12
@@ -0,0 +1,13 @@
+ ¢c¢¨¢c ¢c¢¨¢c ¢c¢k
+ ¢ª . ¢ª ¢k
+ . ¢k
+ ¡´¡´ ¡´ . ¢k
+ ¡´ ¡¸ ¡´ ¡Ö¡´¡´¡ç ¢k
+ ¡´ ¡¹ ¡´ ¡´¡´\\ ¡X¡´¡´¡Ð ¢k
+ ¡´ ¡¸ ¡´ ¡ä / OO \ ¢k
+ ¡´ ¡´ ¡´ ¡´¡´ ¢© ¢k
+ ¡´¢f¡´¢f¡´¢f--¡´¢d¡l¡p ¢k
+ ¡´/ ¡´/ ¡´/ ¡´/ ¢k
+ ¢ª\ ¢ª\ ¢ª\ ¢«
+  
+
diff --git a/sample/etc/chickens/d13 b/sample/etc/chickens/d13
new file mode 100644
index 00000000..48cef654
--- /dev/null
+++ b/sample/etc/chickens/d13
@@ -0,0 +1,13 @@
+ ¤pÅ]¬P¡H¡H
+ ¡´ ¡´ ¡´
+ ¡´ ¡¯ ¡´
+ ¡´ ¡¯ ¡´ ¡´¡´\\
+ ¡´ ¡¯ ¡´¡´ ¡_¡´
+ ¡´ ¡¯ ¡ä ¡´
+ ¡´ ¡´¡¯ ¡´ ¡¯¡´¡´¡´ ¢©
+ ¡´ ¡´/ |¡´¢¬ ¡´\ ¡´ ¡´¡´¡l
+ ¡´/¡X¡´/¡X¡´\ ¡´\
+ ¡´\ ¡´\ ¡´\ ¡´\
+ ¢« ¢ª ¢ª ¢ª \|/ \|/
+  
+
diff --git a/sample/etc/chickens/d14 b/sample/etc/chickens/d14
new file mode 100644
index 00000000..02f91a47
--- /dev/null
+++ b/sample/etc/chickens/d14
@@ -0,0 +1,13 @@
+ ¡_ ¡_
+ °«¡I¡I ¢­¢¬ / |¢¬ | ¡[
+ ¡´ ¡´ ¡´ ¡·¡·/ ¢¬ / ¡[
+ ¡´ ¡¯ ¡´ ¡¿¡´¢¬ ¡þ/
+ ¡´¡¯ ¡¯ ¡¯ ¡¯ ¡´ ¡´¡´\\ / / ¡n_¢¬ ¢¬
+ ¡´ ¡¯ ¡¯ ¡´¡´ ¡_¡´ / /¡³ _¢¬
+ ¡´ ¡¯ ¡¯ ¡¯ ¡¯ ¡´ ¡´ /¡þ ¡´ ¡\
+ ¡´¡¯¡´ ¡¯¡´ ¡´¡´ ¢© ¡´ ¡´
+ ¡´ ¡´/ /¡´ ¡´\ ¢­¡´¡p¡l ¡´¡´
+ ¡´/¡X¡´/¡X\¡´¡Æ ¡´\ ¢¬
+ \¡´ \¡´ \¡´ \¡´ ¡¸
+ ¢ª ¢ª ¢ª ¢ª
+
diff --git a/sample/etc/chickens/d15 b/sample/etc/chickens/d15
new file mode 100644
index 00000000..2c305cb5
--- /dev/null
+++ b/sample/etc/chickens/d15
@@ -0,0 +1,11 @@
+ ¡´ ¡´ ¡´¡´\\
+ ¡´ ¡¯ ¡´¡´ ¡o¡´
+ ¡´ ¡¯ ¡¿ ¡´
+ ¡´ ¡¯ ¡´| ¡´ ¢©
+ ¡´ ¡¯ ¡´|¢¬ ¡´¡´¡l/
+ ¡´ ¡´¡¯ ¡´ ¡´ //¡´\ _______ ¢@¡þ
+ ¡´/ ¡´/ ¡´/_¡þ ¡´\ < ¡È/¡È/¢­\¡Ö¡Õ
+ ¡´/--¡´/--¡´\ ¢ª¡´\_\_ ¢¬¡³¡´¡¿/
+ ¡´\ ¡´\ ¡´\ ¡´¡´¡´£[ £[ £[
+ ¢ª ¢ª ¢ª ¢¬
+
diff --git a/sample/etc/chickens/d16 b/sample/etc/chickens/d16
new file mode 100644
index 00000000..2c305cb5
--- /dev/null
+++ b/sample/etc/chickens/d16
@@ -0,0 +1,11 @@
+ ¡´ ¡´ ¡´¡´\\
+ ¡´ ¡¯ ¡´¡´ ¡o¡´
+ ¡´ ¡¯ ¡¿ ¡´
+ ¡´ ¡¯ ¡´| ¡´ ¢©
+ ¡´ ¡¯ ¡´|¢¬ ¡´¡´¡l/
+ ¡´ ¡´¡¯ ¡´ ¡´ //¡´\ _______ ¢@¡þ
+ ¡´/ ¡´/ ¡´/_¡þ ¡´\ < ¡È/¡È/¢­\¡Ö¡Õ
+ ¡´/--¡´/--¡´\ ¢ª¡´\_\_ ¢¬¡³¡´¡¿/
+ ¡´\ ¡´\ ¡´\ ¡´¡´¡´£[ £[ £[
+ ¢ª ¢ª ¢ª ¢¬
+
diff --git a/sample/etc/chickens/d2 b/sample/etc/chickens/d2
new file mode 100644
index 00000000..b256f5e5
--- /dev/null
+++ b/sample/etc/chickens/d2
@@ -0,0 +1,11 @@
+ ¢g¢g¢g¢g¢g¢g¢g
+ .
+ .
+ .
+ .
+ ¡Ö¡´¡´¡ç \¡¹/ \¡¹/
+ ¡X¡´¡´¡Ð ³á¡H ¢¨¢k ¢¨¢k
+ / OO \ ¢© ¢©
+ \|/ ¢k\|/ ¢k \|/
+  
+
diff --git a/sample/etc/chickens/d3 b/sample/etc/chickens/d3
new file mode 100644
index 00000000..c0dacb46
--- /dev/null
+++ b/sample/etc/chickens/d3
@@ -0,0 +1,16 @@
+ ¢g¢g¢g¢g¢g¢g¢g¢g
+ .
+ .
+ .
+ . ¼K¼K¡Idinner¡H
+ ¡Ö¡´¡´¡Õ
+ ¡X¡´¡´¡X
+ /¡ó¡ó\
+ \/ ¡H¡H
+
+ >¡ò¡\¡\ \|/ \|/
+  
+
+
+
+
diff --git a/sample/etc/chickens/d4 b/sample/etc/chickens/d4
new file mode 100644
index 00000000..a11683f0
--- /dev/null
+++ b/sample/etc/chickens/d4
@@ -0,0 +1,12 @@
+ ¢g¢g¢g¢g¢g¢g¢g¢g
+ .
+ .
+ .
+ . ¼K¼K¡IBIG DINNER¡I¡I
+ ¡X¡´¡´¡X
+ ¡Ö ¡´ ¡Õ
+ ¡þ¡ä¡ä¢@ ¡H¡H¡H
+ ¡]¡^
+ >¡´O¡´ ¡\¡\
+  ^ ^ ^ 
+
diff --git a/sample/etc/chickens/d5 b/sample/etc/chickens/d5
new file mode 100644
index 00000000..30ca6a2c
--- /dev/null
+++ b/sample/etc/chickens/d5
@@ -0,0 +1,14 @@
+ ¢g¢g¢g¢g¢g¢g¢g¢g
+ .
+ .
+ .
+ \ . / ¡¸
+ ¢­¢¨¢©¢¬ ¡¹
+ \¡X¢i¢i¡X/
+ ¡¸ /¡X¢i¢i¡X\ ­Ë¦Q¤Ó¤[·|¤£·|¸£¥R¦å°Ú¡H¡H
+ ¢¬¡¯¡¯¢­
+ / ¡]¡^ \ ¡¸
+ ¡¹
+
+
+
diff --git a/sample/etc/chickens/d6 b/sample/etc/chickens/d6
new file mode 100644
index 00000000..7e30c6b6
--- /dev/null
+++ b/sample/etc/chickens/d6
@@ -0,0 +1,12 @@
+
+ ¡´¡´ ¥i©È¶Ü¡H¡H
+ \ ¡´ ¡´ /
+ ¢­¡Ä¡´ ¡´¡Ä¢¬ §Ö°{¡I¡I¡I
+ ¡Ä¡´ ¡´¡Ä
+ \¢¬ ¡Ä¡´ ¡´¡Ä ¢­/ ¡·¡´¡þ
+ ¢¬ ¡´ ¡´ ¢­ . . ¡´¡·¢@
+ ¢¬¡Â¡´¡_¡_¡´¡Â¢­ . .
+ / ¢ª¡·¡·¢« \ . .
+ ¡] ¡^ . .
+ . . .
+
diff --git a/sample/etc/chickens/d7 b/sample/etc/chickens/d7
new file mode 100644
index 00000000..535e5503
--- /dev/null
+++ b/sample/etc/chickens/d7
@@ -0,0 +1,16 @@
+ .
+ . ³´¨À¡H¡H¡H
+ ¡´¡´
+ \ ¡´ ¡´ /
+ ¢­¡Ä¡´ ¡´¡Ä¢¬ ¢d¢d¢¨¢d¢d¢d¢¨¢d
+ ¡Ä¡´ ¡´¡Ä ¢æ¢æ¢æ¢æ¢æ¢ª¢æ¢æ¢æ¢æ
+ \¢¬ ¡Ä¡´ ¡´¡Ä ¢­/¢æ¢æ¢æ¢æ¢æ \/ ¢æ¢æ help¡\
+ ¢¬ ¡´ ¡´ ¢­ ¢æ¢æ¢æ¢æ ¡·¡´¡[¢æ¢æ¢k
+ ¢¬¡Â¡´¡_¡_¡´¡Â¢­ ¢ª¢æ¢æ ¡´¡· ¢æ¢æ¢«
+ / ¢ª¡ä¡ä¢« \ ¢ª¢æ¢æ¡Ë ¢æ¢æ ¢k
+ ¡] ¡^ ¢ª¢æ¢æ¢æ¢æ¢æ¢ª
+ ¢ª¢æ¢æ¢æ ¢k¢­¡ý/ \|¢¬
+
+
+
+
diff --git a/sample/etc/chickens/d8 b/sample/etc/chickens/d8
new file mode 100644
index 00000000..ed46f5e9
--- /dev/null
+++ b/sample/etc/chickens/d8
@@ -0,0 +1,14 @@
+
+ //¢¬ ¬y¬P¡I¡I
+ ¡¸
+ ¡´ ¡´
+ ¡´ ¡´ ¡´¡´\\
+ ¡´ ¡´ ¡ä ³\­ÓÄ@§a¡I
+ ¡´ ¡´ ¢© §Ö§Öªø¤j¡I¡I
+ ¢f¡´¢f¡´¢f ¡´¢d¡p
+ // // // \\
+ \| \| \| |/ \|/ \|¢¬ \|¡þ
+  
+
+
+
diff --git a/sample/etc/chickens/d9 b/sample/etc/chickens/d9
new file mode 100644
index 00000000..409ae520
--- /dev/null
+++ b/sample/etc/chickens/d9
@@ -0,0 +1,13 @@
+
+ // ¢¬
+ ¡´¡´ ¡´ //¢¬ ¹k¥Û¡H¡H
+ ¡´ £Y ¡´ ¡¹
+ ¡´ £Y ¡´ ¡´¡´\\
+ ¡´ £Y ¡´ ¡Ö
+ ¡´ ¡´ ¡´ ¡´ ¢© ³\Ä@ªº¥N»ù¡H
+ ¡´/¢f¡´¢f¡´/¢f¡´ ¡l¡p
+ ¡´\ ¡´\ ¡´\ ¡´\
+ ¢ª ¢ª ¢ª ¢ª \|¡þ \|/ \|/
+  
+
+
diff --git a/sample/etc/chickens/deadth b/sample/etc/chickens/deadth
new file mode 100644
index 00000000..ff9b3687
--- /dev/null
+++ b/sample/etc/chickens/deadth
@@ -0,0 +1,15 @@
+
+
+
+ ¢~¢¡¡\¡\{{
+ ¢ª¢i¢i¢i¢«
+ @`@`¡©
+  "_ 
+ ¢e¢e
+ ÆТi¢i¢i 
+ ¢i 
+  
+  
+  ¢~¢} ¢x 
+ ¢|¢w-¢}
+ ¶ã ¦ºÂ¼Â¼¤F ¤U¦¸¦A¨Ó§a~~~~
diff --git a/sample/etc/chickens/e0 b/sample/etc/chickens/e0
new file mode 100644
index 00000000..b66f2972
--- /dev/null
+++ b/sample/etc/chickens/e0
@@ -0,0 +1,6 @@
+
+
+ ¡´¡´
+ ¡´¡´¡´
+ ¡´¡´
+
diff --git a/sample/etc/chickens/e1 b/sample/etc/chickens/e1
new file mode 100644
index 00000000..b66f2972
--- /dev/null
+++ b/sample/etc/chickens/e1
@@ -0,0 +1,6 @@
+
+
+ ¡´¡´
+ ¡´¡´¡´
+ ¡´¡´
+
diff --git a/sample/etc/chickens/e10 b/sample/etc/chickens/e10
new file mode 100644
index 00000000..72d37fd8
--- /dev/null
+++ b/sample/etc/chickens/e10
@@ -0,0 +1,12 @@
+
+ ¢©¢©¢¨¢¨
+ ¢©¢©¢©¢©¢©¢¨
+ ¡´¡´¡´¡´¡´¡´¡´¡´
+ ùü ¡´¡´¡´¢®¡´¡´¢®¡´¡´¡´ ùý
+ ùüùùùù  ¡´¡´¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡´¡´ ùùùùùý
+ ùúùù ¡´¡´ ¡´¡´ ùùùûû  ¢«
+ ¡´¡´¡¶¡¶¡¶¡¶¡¶¡´¡´ ùû¡´¢«¢«¢«
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¢«¡´¡´ ¢«
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¢«¢«
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¢«¢«¡´ «
+  ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/e11 b/sample/etc/chickens/e11
new file mode 100644
index 00000000..1579e557
--- /dev/null
+++ b/sample/etc/chickens/e11
@@ -0,0 +1,14 @@
+
+ ¢¨¢¨¢¨
+ ¢¨¢¨¢¨¢¨¢¨¢¨
+ ùúùû ¡´¡´¡´¡´¡´¡´¢¨¢¨¢¨  ¢¨
+ ùüùùùù ¡´¡´¢¨¢©¡´¡´¡´¢¨¢¨ ¡·¡·
+ ùú ¡´¡´¡´¡´¡´¡´¡´¡´¢¨¢¨¡·¡·¡·
+ ùúùû ùüùùùù ¡¿¡¿¡¿¡¿¡¿¡¿¡´¡´¢¨¡·¡·¡·¡·
+ ùü ùüùù  ¡´¡´¡´¡·¡·
+ ùúùùùùùù ¡´ ¡¶¡¶¡¶¡¶¡¶¡¶¡´¡´¡´¢¨¢¨¢¨
+ ùü ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¢¨¢¨ ¢¨
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¢¨¢¨ ¢¨¢¨
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¢©¢©¢©¢¨¢¨¢¨
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¢©¢©¢¨
+
diff --git a/sample/etc/chickens/e12 b/sample/etc/chickens/e12
new file mode 100644
index 00000000..0a05bc8a
--- /dev/null
+++ b/sample/etc/chickens/e12
@@ -0,0 +1,15 @@
+
+  ¡· ¡·  ¢©¢©  ¡·
+  ¢©¢©¢©¢©
+ ¢© ¢©¢©¡´¡´¡´¡´¡´  ¡· ¢¨¢¨
+ ¡·¡·  ¢©¡´¡´¡´¡´¡´¡´ ¢¨¢¨¢¨¢¨
+ ¡·¡·¡·¢©¢©¡´¡´¡´¡´ùúùû¡´ ¡´¡´¡´¡´¢¨
+ ¡·¡·¡·¡·¢©¡´¡´¡´¡´¡´¡´¡´¡´ ¡· ¡´ùúùû¡´¡´¢¨¢¨  ¢¨
+  ¡·  ¡·¡·¢©¢©¡´¡´¡´¡´¡´¢ª¢ª¢ª¢ª ¡´¡´¡´¡´¡´¡´¢¨  ¡·¡·
+ ¡·¢©¢©¢©¡´¡´¡´¡´¡´ ¢«¢«¡´¡´¡´¡´¢¨¢¨¡·¡·  ¡·
+ ¢©¢©¢©¡´¡´¡´¡´¡´¡´ ¡´¡´¡´¡´¢¨¢¨¡·
+ ¢© ¢©¢©¢©¡´¡´¡´¡´¡´¡´¡´¢¨ ¢©¡´¡´¡´¡´¡´¡´¢¨¢¨
+ ¢©¢© ¢¨¢¨¢¨¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¢¨¢¨ ¢¨
+ ¢©¢©¢¨¢¨¢¨¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¢©¢©¢¨¢¨
+
+
diff --git a/sample/etc/chickens/e13 b/sample/etc/chickens/e13
new file mode 100644
index 00000000..7fcee5e0
--- /dev/null
+++ b/sample/etc/chickens/e13
@@ -0,0 +1,14 @@
+
+ ¢¨¢¨¢¨  ¢¨
+ ¢¨¢¨¢¨¢¨¢¨¢¨  ¡·¡·¡·
+  ùúùû ¡´¡´¡´¡´¡´¡´¢¨¢¨¢¨ ¡·¡·¡·¡·
+ ùüùùùù  ¡´¡´¢®¡´¡´¡´¡´¢¨¢¨  ¡·¡·¡·¡·¡·
+ ùú  ¡´¡´¡´¡´¡´¡´¡´¡´¢¨¢¨¡·¡·¡·¡·¡·
+  ùúùû ùú ùüùùùù ¡¿¡¿¡¿¡¿¡¿¡¿¡´¡´¢¨¡·¡·¡·¡·¡·¡·
+ ùü ùüùù ¡´¡´¡´ ¡´¡´¡´¡·¡·¡·¡·¡·
+ ùúùùùùùù ¡´  ¡´¡´ ¡´¡´¡´¢¨¢¨¡·¡·
+ ùü ¡´¡´¡´ ¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡´¡´¡´¢¨¢¨
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¢¨¢¨ ¢¨¢¨
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¢©¢©¢©¢¨¢¨¢¨
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¢©¢©¢¨
+
diff --git a/sample/etc/chickens/e14 b/sample/etc/chickens/e14
new file mode 100644
index 00000000..5685534b
--- /dev/null
+++ b/sample/etc/chickens/e14
@@ -0,0 +1,13 @@
+
+ ¢¨¢¨¢¨ ¢¨
+  ¢¨¢¨¢¨¢¨¢¨  ¡·¡·
+ ¡´¡´¡´¡´¡´¡´¢¨¢¨  ¡·¡·¡·
+ ¡´¡´¡´¡´¡´¡´¡´¢¨ ¡ ¡·¡·¡·¡·
+ ¡´ùúùû¡´¡´¡´¡´¡´¢¨¢¨  ¡·¡·¡·¡·¡·
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¢¨¢¨ ¡·¡·¡·¡·¡·
+ ¢«¢«¢«¢«¢«¢«¡´¡´¡´¡´¢¨¢¨¡·¡·¡·¡·
+ ¡´¡´¡´  ¡´¡´¡´¡´¢¨¢¨¡·¡·¡·
+  ¡´¡´ ¡´ ¡´¡´  ¡´¡´¡´¡´¢¨¢¨¡·¡·
+ ¡´¡´¡´ ¡´¡´ ¡´ ¢©¢©¡´¡´¡´¡´¡´¡´¡´¡´¢¨¢¨¢¨ ¢¨
+ ¡´¡´ ¡´¡´¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¢©¢© ¢¨¢¨
+ ¡´¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¢©¢¨¢¨¢¨
diff --git a/sample/etc/chickens/e15 b/sample/etc/chickens/e15
new file mode 100644
index 00000000..b1c406be
--- /dev/null
+++ b/sample/etc/chickens/e15
@@ -0,0 +1,13 @@
+
+ ¢© ¢©¢©¢© ùúùû
+  ¡·¡·  ¢©¢©¢©¢©¢©  ùüùø ùúùû
+  ¡·¡·¡·¡·  ¢©¢©¡´¡´¡´¡´¡´¡´  ùø ùùùùùý
+  ¡·¡·¡·¡·¡·  ¢©¡´¡´¡´¡´¡´¡´¡´¡´ ùúùû
+  ¡·¡·¡·¡·¡· ¢©¢©¡´¡´¡´¡´¡´¡´¢®¡´¡´  ùùùùùùùý û
+ ¡·¡·¡·¡·  ¢©¡´¡´¡´¡´¢ª¢ª¢ª¢ª¢ª¢ª ¡´ ùû ùúùû
+ ·  ¡·¡· ¢©¢©¡´¡´¡´¡´¡´¡ ¡´¡´¡´¡´¡´ ùùùý ùý
+ ¡·¡·¢©¢©¢©¡´¡´¡´¡´ ¡´¡´  ùùùùùùùùùùùû
+  ¢©  ¡·¢©¢©¢©¡´¡´¡´¡´¡´¢¨¢¨¢¨¢¨¢¨  ¡´  ùüùý
+ ¢©¢© ¢©¢©¢©¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¡´  ùø ùùùû
+ ¢©¢© ¢¨¢¨¢¨¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ùúùø ùüùý
+  ¢©¢©¢¨¢¨¢¨¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ùüùý
diff --git a/sample/etc/chickens/e16 b/sample/etc/chickens/e16
new file mode 100644
index 00000000..c607a360
--- /dev/null
+++ b/sample/etc/chickens/e16
@@ -0,0 +1,14 @@
+
+ ¢¨¢¨¢¨ ¢¨
+  ¢¨¢¨¢¨¢¨¢¨ ¡´¡´¢¨  ¢¨
+ ¡´¡´¡´¡´¡´¡´¢¨¢¨¡´¡o¡´¢¨ ¡·¡·
+ ¡´¡´¡´¡´¡´¡´¡´¢¨ ¡´¡´¢¨  ¡·¡·¡·
+ ¡´ùúùû¡´¡´¡´¡´¡´¢¨¢¨ ¡´¢©  ¡·¡·¡·¡·
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¢¨¢¨ ¡´¢¨ ¡·¡·¡·¡·
+  ¢© ¢«¢«¢«¡´¡´¡´¡´¡´¡´¡´¢¨¢¨  ¡·¡·¡·
+  ¢©¡´¡´ ¡´ ¡´¡´¡´¡´¡´¡´¢¨¢¨  ¡·¡·¡·¡·
+  ¢©¡´¡´¡´ ¢© ¡´ ¡´¡´¡´¡´¡´¡´¢¨¢¨¡·¡·¡·
+¢¨¢¨¡´¡´¡´¡´ ¢©¡´¡´´ ¡´ ¡´ ¢©¡´¡´¡´¡´¡´¡´¡´¡´¡´¢¨¢¨¢¨
+ ¢©¡´¡o¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¢©¢© ¢¨
+ ¢¨¢¨¡´¡´¡´¡´ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¢©¢¨¢¨
+
diff --git a/sample/etc/chickens/e2 b/sample/etc/chickens/e2
new file mode 100644
index 00000000..d975147c
--- /dev/null
+++ b/sample/etc/chickens/e2
@@ -0,0 +1,6 @@
+
+
+ ¡´¡´¢¨
+ ¡´¡´¡´¢¨
+ ¡´¡´¡´¡´¢©¢©
+
diff --git a/sample/etc/chickens/e3 b/sample/etc/chickens/e3
new file mode 100644
index 00000000..244f71d2
--- /dev/null
+++ b/sample/etc/chickens/e3
@@ -0,0 +1,6 @@
+ ¢¨¢¨
+ ¡´¡´¡´¢¨
+ ¡´¡o¡o¡´¢¨
+ ¡´¡´¡´¡´¢¨¢¨
+ ¡´¡´¡´¡´¡´¢©¢©¢¨
+
diff --git a/sample/etc/chickens/e4 b/sample/etc/chickens/e4
new file mode 100644
index 00000000..d6b05b44
--- /dev/null
+++ b/sample/etc/chickens/e4
@@ -0,0 +1,8 @@
+
+ ¢¨¢¨¢¨
+ ¡´¡´¡´¡´¢¨
+ ¡´¡´¡´¡´¡´¢¨
+ ¡´¡´¡¿¡¿¡´¢¨¢¨
+ ¡´¡´¡¶¡´¡´¡´¢¨¢¨ ¢¨
+ ¡´¡´¡´¡´¡´¡´¡´¢©¢©¢¨
+
diff --git a/sample/etc/chickens/e5 b/sample/etc/chickens/e5
new file mode 100644
index 00000000..a78b2df8
--- /dev/null
+++ b/sample/etc/chickens/e5
@@ -0,0 +1,9 @@
+
+ ¢¨¢¨¢¨
+ ¡´¡´¡´¡´¢¨
+ ¡´¢©¡´¢¨¡´¢¨¢¨
+ ¡´¡´¡´¡´¡´¡´¢¨
+ ¡´¡´¡¿¡¿¡¿¡´¡´¢¨¢¨
+ ¡´¡´¡¶¡¶¡´¡´¡´¡´¢¨¢¨ ¢¨
+ ¡´¡´¡´¡´¡´¡´¡´¡´¢©¢©¢¨¢¨¢¨
+
diff --git a/sample/etc/chickens/e6 b/sample/etc/chickens/e6
new file mode 100644
index 00000000..66af6938
--- /dev/null
+++ b/sample/etc/chickens/e6
@@ -0,0 +1,9 @@
+
+  ¢¨¢¨¢¨¢¨
+ ¡´¡´¡´¡´¢¨¢¨
+ ¡´¡o¡´¡o¡´¡´¢¨¢¨
+ ¡´¡´¡´¡´¡´¡´¡´¢¨
+ ¡´¡¿¡¿¡¿¡¿¡´¡´¢¨¢¨¢¨
+ ¡´¡´¡¶¡¶¡´¡´¡´¡´¢¨ ¢¨
+ ¡´¡´¡´¡´¡´¡´¡´¡´¢©¢© ¢¨¢¨
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¢©¢¨¢¨
diff --git a/sample/etc/chickens/e7 b/sample/etc/chickens/e7
new file mode 100644
index 00000000..fc0b8270
--- /dev/null
+++ b/sample/etc/chickens/e7
@@ -0,0 +1,11 @@
+
+ ¢©¢©¢©¢©
+ ¢©¢©¡´¡´¡´¡´¡´  ùúùû
+ ¢©¢©¡´¡´¡´¡´ùúùû¡´ ùüùý ùúùû
+ ¢©¢©¡´¡´¡´¡´¡´¡´¡´  ùúùû ùüùý
+ ¢©¢©¢©¡´¡´¡´¡´¡´¡´¢ª¢ª  ùùùùùý ¡·
+ ¢©¢©¡´¡´¡´¡´¡´  ùùùùùùùùùû ¡·
+ ¢©¢©¡´¡´¡´¡´¡´¡´¡´¡´¢¨ ùùùû ùüùý
+ ¢© ¢©¢©¡´¡´¡´¡´¡´¡´¡´¡´¡´ ùüùý ¡·
+ ¢©¢©¢¨¢¨¡´¡´¡´¡´¡´¡´¡´¡´¡´
+
diff --git a/sample/etc/chickens/e8 b/sample/etc/chickens/e8
new file mode 100644
index 00000000..6841430c
--- /dev/null
+++ b/sample/etc/chickens/e8
@@ -0,0 +1,11 @@
+
+ ¢©¢©
+ ¢©¢©¢©¢©
+ ¢©¢©¡´¡´¡´¡´¡´
+ ¢©¡´¢©¡´¡´¢¨¡´
+ ¢©¢©¡´¡´¡´¡´¡´¡´¡´
+ ¢©¢©¡´¡¿¡¿¡¿¡¿¡¿¡´
+ ¢©¢©¢©¡´¡´¡¶¡¶¡¶¡¶¡´
+ ¢© ¢©¢©¡´¡´ùÝùá¡´¡´ùÝùá
+ ¢©¢©¢¨¢¨¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¢©¢¨¢¨¡´¡´¡´¡´¡´¡´¡´¡´¡´´
diff --git a/sample/etc/chickens/e9 b/sample/etc/chickens/e9
new file mode 100644
index 00000000..1c475487
--- /dev/null
+++ b/sample/etc/chickens/e9
@@ -0,0 +1,12 @@
+
+ ¢©¢©
+ ¢©¢©¢©¢©¢©
+ ¢©¡´¡´¡´¡´¡´
+ ¢©¡´¡´¡´¢ª¢«¡´¡´
+ ¢©¢©¡´¡´¡¿¡¿¡¿¢ª¢ª¢ª ùùùý
+ ¢©¢©¡´¡´ ùùùýùû
+ ¢© ¢©¢©¡´¡´¡´¡´¡¶¡¶¡¶¡¶¡¶¡¶ ùùùû
+ ¢© ¢©¢©¡´¡´¡´¡´¡´¡´¡´ùæùùùá
+ ¢©¢©¢©¢¨¢¨¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¢©¢©¢¨¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+
diff --git a/sample/etc/chickens/eat b/sample/etc/chickens/eat
new file mode 100644
index 00000000..03f3a578
--- /dev/null
+++ b/sample/etc/chickens/eat
@@ -0,0 +1,14 @@
+
+
+
+
+ _._ ¢A
+  ¢¡  ¢b  ¡» ¢¡ ¡¿  ¡@¢~
+  ¡]¡^ [¡Ý ###/  ¢x ¡]¡^
+  ¡ü  ¢y ¢v ¢v ¢j ¡ü
+ ¢x  ¢y¡o¡o¡o¡o¡o¡o¡o¡o¡o¡o¢j¡@  ¢x
+ ¢¢ùùùçùù  ùò|  ¡@ ùùùçùù¢£
+ ¡ü ¡Ý ¡@ ¡ü
+  ¢~¢r¢¡ ¢~¢r¢¡ ¡@ ¢~¢r¢¡
+  ¢v ¢v ¢v ¢v ¢v ¢v
+ ¦Y¶ºÅo~~~~~~~~
diff --git a/sample/etc/chickens/f0 b/sample/etc/chickens/f0
new file mode 100644
index 00000000..36f55c21
--- /dev/null
+++ b/sample/etc/chickens/f0
@@ -0,0 +1,9 @@
+
+
+ ¡´¡´¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´
diff --git a/sample/etc/chickens/f1 b/sample/etc/chickens/f1
new file mode 100644
index 00000000..36f55c21
--- /dev/null
+++ b/sample/etc/chickens/f1
@@ -0,0 +1,9 @@
+
+
+ ¡´¡´¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´
diff --git a/sample/etc/chickens/f10 b/sample/etc/chickens/f10
new file mode 100644
index 00000000..b5c8367f
--- /dev/null
+++ b/sample/etc/chickens/f10
@@ -0,0 +1,15 @@
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/f11 b/sample/etc/chickens/f11
new file mode 100644
index 00000000..8646bce2
--- /dev/null
+++ b/sample/etc/chickens/f11
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
diff --git a/sample/etc/chickens/f12 b/sample/etc/chickens/f12
new file mode 100644
index 00000000..8646bce2
--- /dev/null
+++ b/sample/etc/chickens/f12
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
diff --git a/sample/etc/chickens/f13 b/sample/etc/chickens/f13
new file mode 100644
index 00000000..ba9d1d34
--- /dev/null
+++ b/sample/etc/chickens/f13
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´ ¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´
diff --git a/sample/etc/chickens/f14 b/sample/etc/chickens/f14
new file mode 100644
index 00000000..ba9d1d34
--- /dev/null
+++ b/sample/etc/chickens/f14
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´ ¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´
diff --git a/sample/etc/chickens/f15 b/sample/etc/chickens/f15
new file mode 100644
index 00000000..df160353
--- /dev/null
+++ b/sample/etc/chickens/f15
@@ -0,0 +1,15 @@
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´
diff --git a/sample/etc/chickens/f16 b/sample/etc/chickens/f16
new file mode 100644
index 00000000..100d4260
--- /dev/null
+++ b/sample/etc/chickens/f16
@@ -0,0 +1,15 @@
+ ¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´ ¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´
diff --git a/sample/etc/chickens/f2 b/sample/etc/chickens/f2
new file mode 100644
index 00000000..6714c9d2
--- /dev/null
+++ b/sample/etc/chickens/f2
@@ -0,0 +1,12 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/f3 b/sample/etc/chickens/f3
new file mode 100644
index 00000000..6714c9d2
--- /dev/null
+++ b/sample/etc/chickens/f3
@@ -0,0 +1,12 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/f4 b/sample/etc/chickens/f4
new file mode 100644
index 00000000..723291ae
--- /dev/null
+++ b/sample/etc/chickens/f4
@@ -0,0 +1,13 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´ ¡´¡´ ¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/f5 b/sample/etc/chickens/f5
new file mode 100644
index 00000000..723291ae
--- /dev/null
+++ b/sample/etc/chickens/f5
@@ -0,0 +1,13 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´ ¡´¡´ ¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/f6 b/sample/etc/chickens/f6
new file mode 100644
index 00000000..d3edcf12
--- /dev/null
+++ b/sample/etc/chickens/f6
@@ -0,0 +1,14 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/f7 b/sample/etc/chickens/f7
new file mode 100644
index 00000000..d3edcf12
--- /dev/null
+++ b/sample/etc/chickens/f7
@@ -0,0 +1,14 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/f8 b/sample/etc/chickens/f8
new file mode 100644
index 00000000..b5c8367f
--- /dev/null
+++ b/sample/etc/chickens/f8
@@ -0,0 +1,15 @@
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/f9 b/sample/etc/chickens/f9
new file mode 100644
index 00000000..b5c8367f
--- /dev/null
+++ b/sample/etc/chickens/f9
@@ -0,0 +1,15 @@
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/food b/sample/etc/chickens/food
new file mode 100644
index 00000000..bb686d2f
--- /dev/null
+++ b/sample/etc/chickens/food
@@ -0,0 +1,14 @@
+
+  
+   ¢e¢e¢e  
+   ¢«¢«  
+   ELEVEN  
+   ¢i  
+ ¢i¢d¢d¢d¢d¢i
+ //////
+  ¡@  
+  ((((((  ¡´¡´- > ¢Ûa¢ús¢ða¢ót
+  ¢e¢e¢e¡Å ¢¢¡¿ ¢£  §®¤Ñ¤p¼p®v 
+ \¡Ð¡D >>
+ ¡G 
+ ¨Ó¶R­¹ª«°Õ....
diff --git a/sample/etc/chickens/g0 b/sample/etc/chickens/g0
new file mode 100644
index 00000000..1ed07519
--- /dev/null
+++ b/sample/etc/chickens/g0
@@ -0,0 +1,5 @@
+
+ ¡´¡´
+ ¡´¡´¡´
+ ¡´¡´¢££
+
diff --git a/sample/etc/chickens/g1 b/sample/etc/chickens/g1
new file mode 100644
index 00000000..1ed07519
--- /dev/null
+++ b/sample/etc/chickens/g1
@@ -0,0 +1,5 @@
+
+ ¡´¡´
+ ¡´¡´¡´
+ ¡´¡´¢££
+
diff --git a/sample/etc/chickens/g10 b/sample/etc/chickens/g10
new file mode 100644
index 00000000..cf4c0f14
--- /dev/null
+++ b/sample/etc/chickens/g10
@@ -0,0 +1,13 @@
+
+ ¢© ¢¨  ¢© ¢¨  ¢© ¢¨
+ ¡´¡´¡´¡´¡´  ¡´¡´¡´¡´¡´  ¡´¡´¡´¡´¡´
+ ¡ó¡¯¡ò¡¸ ¡´ ¡´  ¡´ ¡´  ¡´ ¡´
+ ¡¸¡¯¡ó¡¯¡¯ ¡´ ¢® ¢® ¡´  ¡´ ¡o ¡o ¡´  ¡´ ¢Ç ¢Ç ¡´
+ ¡¯¡ò¡¯¡ó¡¯ ùû ¡´ ¡´  ¡´ ¡´  ¡´ ¡´
+ ¡¯¡ò¡¯¡¸ ùø  ¡´ ¡´  ¡´ ¡´  ¡´ ¡´
+ ùüùùùÞùùùýý ùø ¡´ ¡´  ¡´ ¡´ ùúùáùû¡´ ¡´
+  ùø ý ùø¡´ ¡´  ¡´ ¡´ ùø ùø¡´´ ¡´
+  ùø ùü¡´ ¡´  ¡´ ¡´ùý ùü¡´ ¡´
+  ùùùäùù ¡´¡´¡´¡´¡´¡´  ¡´¡´¡´¡´¡´  ¡´¡´¡´¡´
+
+
diff --git a/sample/etc/chickens/g11 b/sample/etc/chickens/g11
new file mode 100644
index 00000000..0c6390f8
--- /dev/null
+++ b/sample/etc/chickens/g11
@@ -0,0 +1,15 @@
+
+  ¢© ¢¨
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ 
+  ¡´  ¡\ ¡\ ¡´
+ ¡´ ¢¤ ¡´ ¢¤ ¡´
+ ¡´ ¡Ë  ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ùúùûùúùûùúùûùúùû
+ ¡´ ¡´ùýùüùýùüùýùüùýùü
+  ¡´¡´¡´¡´¡´¡´¡´ 
+
+
diff --git a/sample/etc/chickens/g12 b/sample/etc/chickens/g12
new file mode 100644
index 00000000..326c650d
--- /dev/null
+++ b/sample/etc/chickens/g12
@@ -0,0 +1,15 @@
+
+  ¢© ¢¨  ¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´  ¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¢Ç ¢Ç ¡´  ¡´¡´¡´¡´¡´¡´
+ ¡´ ¢¤ ¡´ ¢¤ ¡´  ¡´ ¡´¡´¡´¡´
+ ¡´  ¡ã  ¡´ ¡´
+  ¡´ ¡´  ¡´
+  ¡´ ¡´  ¡´ùúø
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ùø
+ ¡´¡´¡´¡´¡´¡´¡´¡´ùúùý
+  ¡´  ¢®  ¡´ùý
+ ¡´¡´¡´¡´¡´¡´¡´
+
+
diff --git a/sample/etc/chickens/g13 b/sample/etc/chickens/g13
new file mode 100644
index 00000000..0b6e8b53
--- /dev/null
+++ b/sample/etc/chickens/g13
@@ -0,0 +1,14 @@
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´   ¢© ¢©
+  ¡´ ¡´  ¡´¡´¡´¡´¡´
+ ¡´  ¡o ¡o ¡´ ¡´ ¡´
+  ¡´ ¡Ö¡´¡Õ ¡´  ¡´ ¡o ¡o ¡´
+  ¡´ ¡´  ¡´¡Ö¡´¡Õ¡´
+  ¡´¡´¡½¡´¡´  ¡´¡´¡´¡´
+ ùúùû ¡´  ¡½  ¡´  ¡´´ ¡´
+  ùø ¡´  ¡½ ¡´  ¡´ ¡´ ùúùû
+  ùø¡´  ¡¿  ¡´  ¡´ ¡´ùø
+  ùü¡´ ¡´  ¡´ ¡´ùý
+  ¡´¡´¡´¡´¡´¡´¡´  ¡´¡´¡´¡´¡´¡´´
+
+
diff --git a/sample/etc/chickens/g14 b/sample/etc/chickens/g14
new file mode 100644
index 00000000..12c177ea
--- /dev/null
+++ b/sample/etc/chickens/g14
@@ -0,0 +1,14 @@
+
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´  ¢© ¢¨
+ ¡´ ¡´  ¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡Ö ¡´ ¡Õ ¡´ ¡´¡´¡´ ¢Ç ¢Ç ¡´
+¡ ¡´ ¡ã  ¡´ ¡´¡´ ¡´¢¤¡»¢¤¡´
+ ¢© ¢¨  ¢¤¡´¡´¢¤  ¡´¡´  ¡´¡´¡´
+  ¡´¡´¡´¡´  ¡´ ¡´ ¡´¡´ ¡´ý ¡´
+ ¡´ ¡ ¡´  ¡´ ¡´¡´¡´¡´ ¡´ ¢©¢¨
+ ¡´ ¡ó¡ó ¡´  ¡´ ¡´¡´¡´ ¡´¡´¢«¢ª´
+ ¡´ ¡´  ¡´ ¡´¡´¡´ ¡´ ¡ó¡ó¡´
+ ùü¡´¡´¡´¡´¡´  ¡´¡´¡´¡´¡´¡´¡´¡´  ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ùý
+
diff --git a/sample/etc/chickens/g15 b/sample/etc/chickens/g15
new file mode 100644
index 00000000..05757960
--- /dev/null
+++ b/sample/etc/chickens/g15
@@ -0,0 +1,14 @@
+
+
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´¡´
+  ¡´ ¡´¡´¡´¡´¡´  Âù¤U¤Ú³£¶]¥X¨Ó¤F©O¡I
+ ¡´ ¡­ ¡­  ¡´
+ ¡´ ¢¤¡´¢¤  ¡´
+ ¡´ ¡_  ¡´
+ ¡´ ¡´
+ ¡´  ¡p  ¡´
+ ¡´ ¡´¡´
+  ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´¡´¡´¡´¡´¡´
+
+
diff --git a/sample/etc/chickens/g16 b/sample/etc/chickens/g16
new file mode 100644
index 00000000..03e4ebaa
--- /dev/null
+++ b/sample/etc/chickens/g16
@@ -0,0 +1,14 @@
+
+ ¡´¡´
+ ¢¡ ¡´ ¡´ ¡´¡´
+ ¡´¡´¡´ ¢¢¢¡¡´ ¡´  ¡´ ¡´
+ ¡´¡´¡´¡´ ¡´ ¢¢¢¡  ¡´¡´ ¡´¡´¡´ ¡´
+ ¡´¡´  ¡]  ¡ü ¢« ¢¢¢w¢w¢¡ ¡´ ¡´ ¡´
+ ¡´  ¡´  ¡´¡´  ¢¢¢¡ ¡´ ¡´  ¡´
+ ¡´¡´¡´  ¡]  ¡ü ¢© ¡´ ¡´ ¢¢¢¡¡´ ¡´  ¡´  ¡´¡´¡´¡´
+ ¡´¡´  ¡´ ¡´  ¢¢¢¡ ¡´  ¡´  ¡´¡´¡´¡´¡´
+ ¡´  ¢x  ¡´  ¡´  ¡´¡´¡´¡´¡´¡´
+ ¡´  ¢¢¢¡¡´ ¡´¡´  ¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¢¢¢w¢w¢w¢w¢w¢w¢w¢w¢w¡´¡´¡´¡´
+
+
diff --git a/sample/etc/chickens/g2 b/sample/etc/chickens/g2
new file mode 100644
index 00000000..032a3e61
--- /dev/null
+++ b/sample/etc/chickens/g2
@@ -0,0 +1,5 @@
+
+ ¡´¡´¡´
+ ¡´¢Ý¢Ý¡´
+ ¡´¡´¡´ùý
+
diff --git a/sample/etc/chickens/g3 b/sample/etc/chickens/g3
new file mode 100644
index 00000000..5e65b34d
--- /dev/null
+++ b/sample/etc/chickens/g3
@@ -0,0 +1,6 @@
+
+ ¢© ¢¨
+ ¡´¡´¡´
+ ¡´¢Ý¢Ý¡´ùú
+ ¡´¡´¡´¡´ùýý
+
diff --git a/sample/etc/chickens/g4 b/sample/etc/chickens/g4
new file mode 100644
index 00000000..5e8a7520
--- /dev/null
+++ b/sample/etc/chickens/g4
@@ -0,0 +1,6 @@
+
+ ¢© ¢¨
+ ¡´¡´¡´¡´
+ ¡´£R £R¡´ùú
+ ¡´¡Ý¡»¡Ý¡´ùø
+ ¡´¡´¡´¡´ ùý
diff --git a/sample/etc/chickens/g5 b/sample/etc/chickens/g5
new file mode 100644
index 00000000..7bd2bea7
--- /dev/null
+++ b/sample/etc/chickens/g5
@@ -0,0 +1,8 @@
+
+ ¢© ¢¨
+ ¡´¡´¡´¡´¡´  ùú
+ ¡´ £[ £[ ¡´ ùø
+ ¡´ ¡Ù¡»¡Ø ¡´ùúùý
+ ¡´¡´¡´¡´¡´ ùý
+ ¡´ ¡´
+
diff --git a/sample/etc/chickens/g6 b/sample/etc/chickens/g6
new file mode 100644
index 00000000..87477217
--- /dev/null
+++ b/sample/etc/chickens/g6
@@ -0,0 +1,10 @@
+
+ ¢©´ ¢¨
+ ¡´¡´¡´¡´¡´¡´  ùúùûý
+ ¡´ ¢Ç ¢Ç ¡´  ùøùý
+ ¡´ ¡Ö ¡´ ¡Õ ¡´  ùø
+ ¡´  ¡t ¡´  ùø
+ ¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´
+
+
diff --git a/sample/etc/chickens/g7 b/sample/etc/chickens/g7
new file mode 100644
index 00000000..08e1a435
--- /dev/null
+++ b/sample/etc/chickens/g7
@@ -0,0 +1,11 @@
+
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´
+ ¡´ ¢Ç ¢Ç  ¡´  ¡´
+ ¡´ ¡Ö¡´¡Õ  ¡´  ¡´¡´ ¡´
+ ¡´  ¡å  ¡´ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´¡´¡´¡´¡´
+
diff --git a/sample/etc/chickens/g8 b/sample/etc/chickens/g8
new file mode 100644
index 00000000..3de22b49
--- /dev/null
+++ b/sample/etc/chickens/g8
@@ -0,0 +1,14 @@
+
+ ¡´
+ ¡´
+ ¢©¡ ¢© ¡ ¡´¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´¡´ ¡´ ¡´
+ ¡´ ¡´¡´
+ ¡´ ¢© ¢¨ ¡´¡´ ¡
+ ¡´ ¡Ö¡´¡Õ  ¡´¡´
+ ¡´ ¢« ¢ª ¡´¡´
+ ¡´ ¢© ¢¨ ¡´¡´¢«¢«
+ ¡´¡´¡´¡´¡´¡´¡´¢«¢«
+ ¢«¢« ¢«¢«
+
+
diff --git a/sample/etc/chickens/g9 b/sample/etc/chickens/g9
new file mode 100644
index 00000000..c0274032
--- /dev/null
+++ b/sample/etc/chickens/g9
@@ -0,0 +1,14 @@
+ ¢¨ ¢¨
+ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´  ¡´
+ ¡´ ¡´  ¡´ ¡´
+ ¡´¢¤  ¡´ ¡´
+ ¡´¡´¡´ ¡´  ¡´
+ ¡´¡´ ¡´¡´ ¡´ ¡´ ¡´
+ ¡´ ¢¨ ¡´  ¡´ ¡´¡´
+ ¡´ ¢¨¡½¢¨ ¡´ ¡´ ¡´
+ ¡´ ¡ ¢ª¡½¢ª ¡´  ¡´ ¡´
+ ¡´ ¢ª ¡´  ¡´  ¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´¡´
+
+
diff --git a/sample/etc/chickens/h0 b/sample/etc/chickens/h0
new file mode 100644
index 00000000..36f55c21
--- /dev/null
+++ b/sample/etc/chickens/h0
@@ -0,0 +1,9 @@
+
+
+ ¡´¡´¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´
diff --git a/sample/etc/chickens/h1 b/sample/etc/chickens/h1
new file mode 100644
index 00000000..36f55c21
--- /dev/null
+++ b/sample/etc/chickens/h1
@@ -0,0 +1,9 @@
+
+
+ ¡´¡´¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´
diff --git a/sample/etc/chickens/h10 b/sample/etc/chickens/h10
new file mode 100644
index 00000000..b5c8367f
--- /dev/null
+++ b/sample/etc/chickens/h10
@@ -0,0 +1,15 @@
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/h11 b/sample/etc/chickens/h11
new file mode 100644
index 00000000..8646bce2
--- /dev/null
+++ b/sample/etc/chickens/h11
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
diff --git a/sample/etc/chickens/h12 b/sample/etc/chickens/h12
new file mode 100644
index 00000000..8646bce2
--- /dev/null
+++ b/sample/etc/chickens/h12
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
diff --git a/sample/etc/chickens/h13 b/sample/etc/chickens/h13
new file mode 100644
index 00000000..ba9d1d34
--- /dev/null
+++ b/sample/etc/chickens/h13
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´ ¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´
diff --git a/sample/etc/chickens/h14 b/sample/etc/chickens/h14
new file mode 100644
index 00000000..ba9d1d34
--- /dev/null
+++ b/sample/etc/chickens/h14
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´ ¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´
diff --git a/sample/etc/chickens/h15 b/sample/etc/chickens/h15
new file mode 100644
index 00000000..df160353
--- /dev/null
+++ b/sample/etc/chickens/h15
@@ -0,0 +1,15 @@
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´
diff --git a/sample/etc/chickens/h16 b/sample/etc/chickens/h16
new file mode 100644
index 00000000..100d4260
--- /dev/null
+++ b/sample/etc/chickens/h16
@@ -0,0 +1,15 @@
+ ¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´ ¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´
diff --git a/sample/etc/chickens/h2 b/sample/etc/chickens/h2
new file mode 100644
index 00000000..6714c9d2
--- /dev/null
+++ b/sample/etc/chickens/h2
@@ -0,0 +1,12 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/h3 b/sample/etc/chickens/h3
new file mode 100644
index 00000000..6714c9d2
--- /dev/null
+++ b/sample/etc/chickens/h3
@@ -0,0 +1,12 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/h4 b/sample/etc/chickens/h4
new file mode 100644
index 00000000..723291ae
--- /dev/null
+++ b/sample/etc/chickens/h4
@@ -0,0 +1,13 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´ ¡´¡´ ¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/h5 b/sample/etc/chickens/h5
new file mode 100644
index 00000000..723291ae
--- /dev/null
+++ b/sample/etc/chickens/h5
@@ -0,0 +1,13 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´ ¡´¡´ ¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/h6 b/sample/etc/chickens/h6
new file mode 100644
index 00000000..d3edcf12
--- /dev/null
+++ b/sample/etc/chickens/h6
@@ -0,0 +1,14 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/h7 b/sample/etc/chickens/h7
new file mode 100644
index 00000000..d3edcf12
--- /dev/null
+++ b/sample/etc/chickens/h7
@@ -0,0 +1,14 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/h8 b/sample/etc/chickens/h8
new file mode 100644
index 00000000..b5c8367f
--- /dev/null
+++ b/sample/etc/chickens/h8
@@ -0,0 +1,15 @@
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/h9 b/sample/etc/chickens/h9
new file mode 100644
index 00000000..b5c8367f
--- /dev/null
+++ b/sample/etc/chickens/h9
@@ -0,0 +1,15 @@
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/hit b/sample/etc/chickens/hit
new file mode 100644
index 00000000..2fe4b736
--- /dev/null
+++ b/sample/etc/chickens/hit
@@ -0,0 +1,14 @@
+
+
+
+
+
+ ¢« "  >< 
+  ¢d¢d  ¢i  ¡Ë 
+  ¢i¢i¢i ¢i ¢i ¢f¢f ¢i
+  `` ¢o ¡´." ¢i ¢i ¢o ¢i
+  ¢¨¢h¢ª¢©  ¢¨ ¢h¢©
+ .¢o  .¢o ¢o, ¢o,
+
+
+ ¼K ¥´¬[½m¨­Åé..
diff --git a/sample/etc/chickens/i0 b/sample/etc/chickens/i0
new file mode 100644
index 00000000..36f55c21
--- /dev/null
+++ b/sample/etc/chickens/i0
@@ -0,0 +1,9 @@
+
+
+ ¡´¡´¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´
diff --git a/sample/etc/chickens/i1 b/sample/etc/chickens/i1
new file mode 100644
index 00000000..36f55c21
--- /dev/null
+++ b/sample/etc/chickens/i1
@@ -0,0 +1,9 @@
+
+
+ ¡´¡´¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´
diff --git a/sample/etc/chickens/i10 b/sample/etc/chickens/i10
new file mode 100644
index 00000000..b5c8367f
--- /dev/null
+++ b/sample/etc/chickens/i10
@@ -0,0 +1,15 @@
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/i11 b/sample/etc/chickens/i11
new file mode 100644
index 00000000..8646bce2
--- /dev/null
+++ b/sample/etc/chickens/i11
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
diff --git a/sample/etc/chickens/i12 b/sample/etc/chickens/i12
new file mode 100644
index 00000000..8646bce2
--- /dev/null
+++ b/sample/etc/chickens/i12
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
diff --git a/sample/etc/chickens/i13 b/sample/etc/chickens/i13
new file mode 100644
index 00000000..ba9d1d34
--- /dev/null
+++ b/sample/etc/chickens/i13
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´ ¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´
diff --git a/sample/etc/chickens/i14 b/sample/etc/chickens/i14
new file mode 100644
index 00000000..ba9d1d34
--- /dev/null
+++ b/sample/etc/chickens/i14
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´ ¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´
diff --git a/sample/etc/chickens/i15 b/sample/etc/chickens/i15
new file mode 100644
index 00000000..df160353
--- /dev/null
+++ b/sample/etc/chickens/i15
@@ -0,0 +1,15 @@
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´
diff --git a/sample/etc/chickens/i16 b/sample/etc/chickens/i16
new file mode 100644
index 00000000..100d4260
--- /dev/null
+++ b/sample/etc/chickens/i16
@@ -0,0 +1,15 @@
+ ¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´ ¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´
diff --git a/sample/etc/chickens/i2 b/sample/etc/chickens/i2
new file mode 100644
index 00000000..6714c9d2
--- /dev/null
+++ b/sample/etc/chickens/i2
@@ -0,0 +1,12 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/i3 b/sample/etc/chickens/i3
new file mode 100644
index 00000000..6714c9d2
--- /dev/null
+++ b/sample/etc/chickens/i3
@@ -0,0 +1,12 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/i4 b/sample/etc/chickens/i4
new file mode 100644
index 00000000..723291ae
--- /dev/null
+++ b/sample/etc/chickens/i4
@@ -0,0 +1,13 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´ ¡´¡´ ¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/i5 b/sample/etc/chickens/i5
new file mode 100644
index 00000000..723291ae
--- /dev/null
+++ b/sample/etc/chickens/i5
@@ -0,0 +1,13 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´ ¡´¡´ ¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/i6 b/sample/etc/chickens/i6
new file mode 100644
index 00000000..d3edcf12
--- /dev/null
+++ b/sample/etc/chickens/i6
@@ -0,0 +1,14 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/i7 b/sample/etc/chickens/i7
new file mode 100644
index 00000000..d3edcf12
--- /dev/null
+++ b/sample/etc/chickens/i7
@@ -0,0 +1,14 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/i8 b/sample/etc/chickens/i8
new file mode 100644
index 00000000..b5c8367f
--- /dev/null
+++ b/sample/etc/chickens/i8
@@ -0,0 +1,15 @@
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/i9 b/sample/etc/chickens/i9
new file mode 100644
index 00000000..b5c8367f
--- /dev/null
+++ b/sample/etc/chickens/i9
@@ -0,0 +1,15 @@
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/j0 b/sample/etc/chickens/j0
new file mode 100644
index 00000000..0aeb9433
--- /dev/null
+++ b/sample/etc/chickens/j0
@@ -0,0 +1,8 @@
+
+
+
+ ¡´¡´
+ ¡´¡´¡´ ¡¶
+ ¡´¡´ ¡´¡´¡´
+
+ ¦³§À¤Úªº´cÅ]§Z
diff --git a/sample/etc/chickens/j1 b/sample/etc/chickens/j1
new file mode 100644
index 00000000..2f5324a9
--- /dev/null
+++ b/sample/etc/chickens/j1
@@ -0,0 +1,9 @@
+
+
+
+ ¡¶
+ ¡¿¡´¡´¡´
+ ¡¶ ¡´¡´¡´¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´¡´¡´
+
diff --git a/sample/etc/chickens/j10 b/sample/etc/chickens/j10
new file mode 100644
index 00000000..ca0238c3
--- /dev/null
+++ b/sample/etc/chickens/j10
@@ -0,0 +1,12 @@
+ ¡¶
+ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡¿
+ ¡´¡´¢¨¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡¶
+ ¡¿ ¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´
+ ¡¶ ¡´¡´¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´¡´
diff --git a/sample/etc/chickens/j11 b/sample/etc/chickens/j11
new file mode 100644
index 00000000..67acda5c
--- /dev/null
+++ b/sample/etc/chickens/j11
@@ -0,0 +1,12 @@
+
+ §Ú¦³¤â¤F¡IÀ~¦º§A¡I
+ ¡¶ ¡¶
+ ¡´ ¡´¡´ ¡´¡´ ¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´ ¡¶
+ ¡´¡´¢©¡´¡´¡´¢¨¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´¡´
+ ¡´¡¿¡¿¡¿¡¿¡¿¡´ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´¡´
diff --git a/sample/etc/chickens/j12 b/sample/etc/chickens/j12
new file mode 100644
index 00000000..f5368760
--- /dev/null
+++ b/sample/etc/chickens/j12
@@ -0,0 +1,11 @@
+
+ ¡¶ ¡¶
+ ¡´ ¡´¡´ ¡´¡´ ¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´ ¡¶
+ ¡´¡´¢©¡´¡´¡´¢¨¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´¡´
+ ¡´¡¿¡¿¡¿¡¿¡¿¡´ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´¡´
diff --git a/sample/etc/chickens/j13 b/sample/etc/chickens/j13
new file mode 100644
index 00000000..22721b27
--- /dev/null
+++ b/sample/etc/chickens/j13
@@ -0,0 +1,12 @@
+ ¡´ ¡´ ¡¶ ¡¶
+ ¡´¡´ ¡´¡´ ¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¢©¡´¡´¡´¡´¡´¢¨¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡´¡´
+ ¡´¡´¡´¡´ ¡´ ¡´ ¡´
+¡¶¡´¡´ ¡´ ¡´¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡´ ¡´
+ ¡´¡´¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´¡´ ¡´¡´ ¡´ ¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
diff --git a/sample/etc/chickens/j14 b/sample/etc/chickens/j14
new file mode 100644
index 00000000..774d0ce2
--- /dev/null
+++ b/sample/etc/chickens/j14
@@ -0,0 +1,13 @@
+
+ ¡¶ ¡¶
+ ¡´¡´¡´ ¡´¡´ ¡´¡´ ¡´¡´¡´
+ ¡´¡´ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¡´ ¡´¡´
+ ¡¿¡¿ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¡¿¡¿
+ ¡´¡´¢©¡´¡´¡´¡´¡´¢¨¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´ ¡´¡´¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡´¡´
+ ¡´¡´¡´¡´ ¡´ ¡´
+ ¡¶¡´¡´ ¡´ ¡´¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡´
+ ¡´¡´¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
diff --git a/sample/etc/chickens/j15 b/sample/etc/chickens/j15
new file mode 100644
index 00000000..774d0ce2
--- /dev/null
+++ b/sample/etc/chickens/j15
@@ -0,0 +1,13 @@
+
+ ¡¶ ¡¶
+ ¡´¡´¡´ ¡´¡´ ¡´¡´ ¡´¡´¡´
+ ¡´¡´ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¡´ ¡´¡´
+ ¡¿¡¿ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¡¿¡¿
+ ¡´¡´¢©¡´¡´¡´¡´¡´¢¨¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´ ¡´¡´¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡´¡´
+ ¡´¡´¡´¡´ ¡´ ¡´
+ ¡¶¡´¡´ ¡´ ¡´¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡´
+ ¡´¡´¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
diff --git a/sample/etc/chickens/j16 b/sample/etc/chickens/j16
new file mode 100644
index 00000000..788ee97b
--- /dev/null
+++ b/sample/etc/chickens/j16
@@ -0,0 +1,13 @@
+ §q¡I¡I¡I§Ú¬O¤jÅ]¤ý¡I¡I¡I
+ ¡¶ ¡¶
+ ¡´¡´¡´¡´ ¡´¡´ ¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¡´ ¡´¡´¡´
+ ¡´¡´¡´ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¡´ ¡´¡´¡´
+ ¡¿¡¿¡¿ ¡´¡´¢©¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¢¨¡´¡´ ¡¿¡¿¡¿
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡¿¡´¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡¶¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´ ¡´¡´¡¿
+ ¡´¡´ ¡´¡´ ¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´ ¡´¡´¡´¡´¡´ ¡´
diff --git a/sample/etc/chickens/j2 b/sample/etc/chickens/j2
new file mode 100644
index 00000000..03ef58fc
--- /dev/null
+++ b/sample/etc/chickens/j2
@@ -0,0 +1,7 @@
+
+
+ ¡¶ ¡¶
+ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´¡´
+ ¡¶¡´¡´¡´
diff --git a/sample/etc/chickens/j3 b/sample/etc/chickens/j3
new file mode 100644
index 00000000..593a726b
--- /dev/null
+++ b/sample/etc/chickens/j3
@@ -0,0 +1,10 @@
+
+ ¡¶¡¶
+ ¡´¡´¡´
+ ¡´¡´¡´¡´ ¡¶
+ ¡´¢¨¡´¢©¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´ ¡´¡´¡´
+ ¡´¡´¡´¡´¡´ ¡´
+ ¡´¡´¡´¡´ ¡´ ¡´
+ ¡´¡´
+
diff --git a/sample/etc/chickens/j4 b/sample/etc/chickens/j4
new file mode 100644
index 00000000..e2e31934
--- /dev/null
+++ b/sample/etc/chickens/j4
@@ -0,0 +1,9 @@
+
+
+ ¡¶ ¡¶
+ ¡´¡´¡´¡´¡´ ¡¶
+ ¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´ ¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´ ¡´
+ ¡´¡´¡´¡´
diff --git a/sample/etc/chickens/j5 b/sample/etc/chickens/j5
new file mode 100644
index 00000000..2554d000
--- /dev/null
+++ b/sample/etc/chickens/j5
@@ -0,0 +1,12 @@
+ ¡¶ ¡¶
+ ¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡o¡´¡o¡´¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´
+ ¡´
+ ¡´
+ ¡´
+ ¡´¡´¡´
+ ¡´¡´
+ ¡¿
diff --git a/sample/etc/chickens/j6 b/sample/etc/chickens/j6
new file mode 100644
index 00000000..79484d50
--- /dev/null
+++ b/sample/etc/chickens/j6
@@ -0,0 +1,9 @@
+
+
+ ¡¶ ¡¶
+ ¡¶ ¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´ ¡´¡´¢©¡´¢¨¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´
diff --git a/sample/etc/chickens/j7 b/sample/etc/chickens/j7
new file mode 100644
index 00000000..93ffcac6
--- /dev/null
+++ b/sample/etc/chickens/j7
@@ -0,0 +1,10 @@
+
+
+ ¡¶ ¡¶ ¡¶
+ ¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´ ¡´¡´¡´
+ ¡´¡´¢©¡´¢¨¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´¡´
diff --git a/sample/etc/chickens/j8 b/sample/etc/chickens/j8
new file mode 100644
index 00000000..c86b6f4a
--- /dev/null
+++ b/sample/etc/chickens/j8
@@ -0,0 +1,10 @@
+
+
+ ¡¶ ¡¶
+ ¡´¡´¡´¡´¡´¡¿ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´ ¡´¡´¡´
+ ¡´¡´¢©¡´¢¨¡´¡´ ¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´¡´ ¡´¡´¡´¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´¡´¡´
diff --git a/sample/etc/chickens/j9 b/sample/etc/chickens/j9
new file mode 100644
index 00000000..a902e57c
--- /dev/null
+++ b/sample/etc/chickens/j9
@@ -0,0 +1,11 @@
+
+ ¡¶ ¡¶
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡¶ ¡´¡´¢©¡´¡´¡´¢¨¡´¡´
+ ¡´¡´ ¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´ ¡´¡¿¡¿¡¿¡¿¡¿¡´
+ ¡´ ¡´ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´¡´
diff --git a/sample/etc/chickens/k0 b/sample/etc/chickens/k0
new file mode 100644
index 00000000..2c1f12a0
--- /dev/null
+++ b/sample/etc/chickens/k0
@@ -0,0 +1,13 @@
+
+(1)§Ú­n¦¨¬°§ÔªÌ!
+ ¢¨
+ ¢¨¢¨¢i¢i¢©
+ ¢«¢ª¢«¢ª¢i
+  ¢m ¢m ¢ª
+ ¢© ¢¨
+ ¢© ¢ª¢« ¢¨
+ ¢i ¢i¢i ¢i
+ ¢i ¢i¢i ¢i
+ ¢i¢i
+ ¢¨¢«¢ª¢©
+
diff --git a/sample/etc/chickens/k1 b/sample/etc/chickens/k1
new file mode 100644
index 00000000..836976bd
--- /dev/null
+++ b/sample/etc/chickens/k1
@@ -0,0 +1,11 @@
+¤j®v!½Ð¦¬§Ú¬°®{§a!
+ ¢¨
+ ¢¨¢¨¢i¢i¢©
+ ¢«¢ª¢«¢ª¢i
+  ¢m ¢m ¢ª
+ ¢© ¢¨
+ ¢© ¢ª¢« ¢¨
+ ¢i¢i¢i¢i¢i
+ ¢i¢i
+ ¢i¢i
+ ¢¨¢«¢ª¢©
diff --git a/sample/etc/chickens/k10 b/sample/etc/chickens/k10
new file mode 100644
index 00000000..6bf8c59e
--- /dev/null
+++ b/sample/etc/chickens/k10
@@ -0,0 +1,13 @@
+§ÔªÌ¤­³N-¤ß
+ ¢¨
+ ¢¨¢¨¢i¢i¢©
+ ¢«¢ª¢«¢ª¢i
+  ¢© ¢¨ ¢«
+ ¢ª¢i¢i¢«
+ ¢© ¢ª¢« ¢¨
+ ¢i¢© ¢¨¢i
+ ¢i¢i¢i¢i
+ ¢i¢i¢i¢i
+
+ ¢¨¢i¢i¢©
+ ¢ª¢i¢i¢«
diff --git a/sample/etc/chickens/k11 b/sample/etc/chickens/k11
new file mode 100644
index 00000000..bc2a19cc
--- /dev/null
+++ b/sample/etc/chickens/k11
@@ -0,0 +1,13 @@
+¤ô¤g­·¤ô¤ß...¦XÅé!!
+ ¢¨ ¢©
+ ¢¨¢¨¢i¢i¢© ¢¨¢i¢i¢©¢©
+ ¢«¢ª¢«¢ª¢i ¢i¢«¢ª¢«¢ª
+  ¢© ¢¨ ¢ª ¢« ¢© ¢¨ 
+ ¢ª¢i¢i¢« ¢ª¢i¢i¢«
+ ¢i¢i ¢« ¢¨¢i¢i ¢i¢i¢© ¢ª ¢i¢i
+ ¢© ¢¨ ¢© ¢¨
+ ¢i¢i ¢i¢i
+ ¢i¢i¢i ¢i¢i¢i
+ ¢i¢m ¢i¢m
+ ¢¨ ¢ª ¢« ¢©
+ ¢¨ ¢©
diff --git a/sample/etc/chickens/k12 b/sample/etc/chickens/k12
new file mode 100644
index 00000000..4cf65887
--- /dev/null
+++ b/sample/etc/chickens/k12
@@ -0,0 +1,12 @@
+¦XÅé«á¦¨¬°°ª¯Å§ÔªÌ,®ð¶ÕÀb¤H!
+ ¢¨¢i¢«
+ ¢ª¢¨¢i¢i¢i¢©
+ ¢«¢ª¢«¢ª¢i¢©
+  ¢© ¢¨ ¢ª¢i
+ ¢ª¢i¢i¢« ¢«
+ ¢© ¢ª ¢ª¢« ¢« ¢¨
+ ¢ª ¢i¢© ¢¨¢i ¢«
+ ¢ª ¢i ¢i¢i ¢i ¢«
+ ¢ª¢ª ¢i ¢i¢i¢i ¢i ¢«¢«
+ ¢ª¢ª ¢i¢i¢i ¢«¢«
+ ¢ª¢ª¢ª ¢i¢i ¢«¢«¢«
diff --git a/sample/etc/chickens/k13 b/sample/etc/chickens/k13
new file mode 100644
index 00000000..faa26334
--- /dev/null
+++ b/sample/etc/chickens/k13
@@ -0,0 +1,12 @@
+³t«×¶W§Ö,§A¬Ý±o¨ì¶Ü?
+ ¢¨¢i¢«
+ ¢ª¢¨¢i¢i¢i¢i¢i¢i¢« ¢«
+ ¢«¢ª¢«¢ª¢i¢i¢« ¢«
+  ¢© ¢¨ ¢«
+ ¢ª¢i¢i¢«
+ ¢i¢i¢i¢ª¢ª¢« ¢«¢i¢i¢i ¢i
+ ¢© ¢¨
+ ¢i¢i
+ ¢i¢i ¢i ¢i
+ ¢i¢i ¢i ¢i
+ ¢i¢i ¢i ¢i
diff --git a/sample/etc/chickens/k14 b/sample/etc/chickens/k14
new file mode 100644
index 00000000..4d875ce4
--- /dev/null
+++ b/sample/etc/chickens/k14
@@ -0,0 +1,12 @@
+³o¬O§Ú¦Û³ÐªºªZ¾¹-¤Q¦r¤M!
+ ¢¨¢i¢«
+ ¢ª¢¨¢i¢i¢i¢©
+ ¢«¢ª¢«¢ª¢i¢©
+ ¢¨  ¢© ¢¨ ¢ª¢i ¢©
+ ¢i ¢ª¢i¢i¢« ¢« ¢i
+ ¢ª¢i¢i¢i¢©¢ª ¢ª ¢« ¢«¢¨¢i¢i¢i¢«
+ ¢i¢i¢i ¢© ¢ª¢« ¢¨ ¢i¢i¢i
+ ¢« ¢i¢i ¢ª
+ ¢i¢i¢i
+ ¢i¢i¢i
+ ¢i¢i
diff --git a/sample/etc/chickens/k15 b/sample/etc/chickens/k15
new file mode 100644
index 00000000..d2b7f59b
--- /dev/null
+++ b/sample/etc/chickens/k15
@@ -0,0 +1,14 @@
+¦¨¬°²×·¥¤§-¥Õ§Ô!
+ ¢¨¢i¢i¢i¢«
+ ¢© ¢i¢i¢i¢i¢© ¢¨
+ ¢¨ ¢¨¢«¢ª¢«¢ª¢i¢© ¢©
+ ¢©  ¢© ¢¨ ¢i¢i ¢¨
+ ¢©¢¨ ¢ª¢i¢i¢«¢i¢« ¢©¢¨
+ ¢ª ¢ª ¢« ¢«¢«
+ ¢i ¢i¢i¢i¢i ¢© ¢ª¢« ¢¨ ¢i¢i¢i¢i ¢i
+ ¢i ¢i¢i¢i ¢i
+ ¢i ¢i¢i¢i ¢i
+ ¢i ¢i¢i¢i¢i ¢i
+ ¢i¢i¢i¢i
+³Ð ¥@ ©_ «L ±Ñ ¸} ¤U ¾È ¦t ªZ ¨å ´¤ ¤â ¤¤
+ ¤Ñ ¤U µL ¼Ä ²Ä ¤@ ¤H «¢!
diff --git a/sample/etc/chickens/k16 b/sample/etc/chickens/k16
new file mode 100644
index 00000000..d2b7f59b
--- /dev/null
+++ b/sample/etc/chickens/k16
@@ -0,0 +1,14 @@
+¦¨¬°²×·¥¤§-¥Õ§Ô!
+ ¢¨¢i¢i¢i¢«
+ ¢© ¢i¢i¢i¢i¢© ¢¨
+ ¢¨ ¢¨¢«¢ª¢«¢ª¢i¢© ¢©
+ ¢©  ¢© ¢¨ ¢i¢i ¢¨
+ ¢©¢¨ ¢ª¢i¢i¢«¢i¢« ¢©¢¨
+ ¢ª ¢ª ¢« ¢«¢«
+ ¢i ¢i¢i¢i¢i ¢© ¢ª¢« ¢¨ ¢i¢i¢i¢i ¢i
+ ¢i ¢i¢i¢i ¢i
+ ¢i ¢i¢i¢i ¢i
+ ¢i ¢i¢i¢i¢i ¢i
+ ¢i¢i¢i¢i
+³Ð ¥@ ©_ «L ±Ñ ¸} ¤U ¾È ¦t ªZ ¨å ´¤ ¤â ¤¤
+ ¤Ñ ¤U µL ¼Ä ²Ä ¤@ ¤H «¢!
diff --git a/sample/etc/chickens/k2 b/sample/etc/chickens/k2
new file mode 100644
index 00000000..5ed4647f
--- /dev/null
+++ b/sample/etc/chickens/k2
@@ -0,0 +1,10 @@
+¬Ó«Ò¥l¨£,¦¨¬°¥¿¦¡§ÔªÌ!
+ ¢¨
+ ¢¨¢¨¢i¢i¢©
+ ¢«¢ª¢«¢ª¢i
+  ¢m ¢m ¢ª
+ ¢© ¢¨
+ ¢© ¢ª¢« ¢¨
+ ¢i ¢i ¢i¢i
+ ¢i ¢i ¢i
+ ¢«¢i ¢ª¢©
diff --git a/sample/etc/chickens/k3 b/sample/etc/chickens/k3
new file mode 100644
index 00000000..aa8a6519
--- /dev/null
+++ b/sample/etc/chickens/k3
@@ -0,0 +1,11 @@
+¤°»ò?¥u­n»X­±´N¥i¥H¤F?
+ ¢¨
+ ¢¨¢¨¢i¢i¢©
+ ¢«¢ª¢«¢ª¢i
+  ¢m ¢m ¢ª
+ ¢ª¢i¢i¢«
+ ¢© ¢ª¢« ¢¨
+ ¢i¢i ¢i¢i ¢i¢i
+ ¢i¢i
+ ¢i¢i
+ ¢¨¢«¢ª¢©
diff --git a/sample/etc/chickens/k4 b/sample/etc/chickens/k4
new file mode 100644
index 00000000..b7e0c1c8
--- /dev/null
+++ b/sample/etc/chickens/k4
@@ -0,0 +1,12 @@
+«¢!Åܦ¨¤¤¯Å§ÔªÌ¤F,¦n¯«®ð!
+ ¢¨
+ ¢¨¢¨¢i¢i¢©
+ ¢«¢ª¢«¢ª¢i
+  ¢© ¢¨ ¢ª
+ ¢i ¢ª¢i¢i¢« ¢i
+ ¢i¢© ¢ª¢« ¢¨¢i
+ ¢© ¢¨
+ ¢¨¢i¢i¢©
+ ¢i¢«¢ª¢i
+ ¢i ¢i
+ ¢¨ ¢©
diff --git a/sample/etc/chickens/k5 b/sample/etc/chickens/k5
new file mode 100644
index 00000000..120b52ac
--- /dev/null
+++ b/sample/etc/chickens/k5
@@ -0,0 +1,12 @@
+³Ì²³æªº-Áô¨­³N...
+  ¢¨
+ ¢¨¢¨¢i¢i¢©
+ ¢«¢ª¢«¢ª¢i
+  ¢© ¢¨ ¢ª
+ ¢ª¢i¢i¢«
+  ¢i ¢i 
+  ¢¨¢« 
+  ¢i ¢i¢« 
+  ¢i ¢i¢« 
+  ¢i ¡´ ¢i¢« ¢¨¢i¢« 
+  ¢i ¢i¢i¢i¢i¢« 
diff --git a/sample/etc/chickens/k6 b/sample/etc/chickens/k6
new file mode 100644
index 00000000..0d869ccc
--- /dev/null
+++ b/sample/etc/chickens/k6
@@ -0,0 +1,13 @@
+§ÔªÌ¤­³N-¤õ
+ ¢¨
+ ¢¨¢¨¢i¢i¢©
+ ¢«¢ª¢«¢ª¢i
+  ¢© ¢¨ ¢ª
+ ¢© ¢ª¢i¢i¢« ¢¨
+ ¢i¢i¢© ¢ª¢« ¢¨¢i¢i
+ ¢© ¢¨
+ ¢i¢i
+ ¢© ¢i¢i¢i ¢¨
+ ¢© ¢i¢i ¢¨
+ ¢© ¢©¢© ¢ª¢« ¢¨¢¨ ¢¨
+ ¢©¢©¢©¢¨¢©¢¨¢¨¢¨
diff --git a/sample/etc/chickens/k7 b/sample/etc/chickens/k7
new file mode 100644
index 00000000..fb24da23
--- /dev/null
+++ b/sample/etc/chickens/k7
@@ -0,0 +1,14 @@
+§ÔªÌ¤­³N-¤g
+ ¢¨
+ ¢¨¢¨¢i¢i¢©
+ ¢© ¢«¢ª¢«¢ª¢i¢¨
+ ¢© ¢© ¢¨ ¢ª
+ ¢i¢ª¢i¢i¢«¢i
+ ¢© ¢ª¢« ¢¨
+ ¢© ¢¨
+ ¢i¢i
+ ¢i¢i¢i
+ ¢i¢i
+ ¢© ¢ª¢« ¢¨
+ ¢©¢ª¢«¢¨
+ ¢©¢¨
diff --git a/sample/etc/chickens/k8 b/sample/etc/chickens/k8
new file mode 100644
index 00000000..4e73a12c
--- /dev/null
+++ b/sample/etc/chickens/k8
@@ -0,0 +1,10 @@
+§ÔªÌ¤­³N-­·
+ ¢¨
+ ¢¨¢¨¢i¢i¢©
+ ¢¨¢© ¢«¢ª¢«¢ª¢i ¢¨¢©
+ ¢¨¢i¢i¢©  ¢© ¢¨ ¢ª ¢¨¢i¢i¢©
+ ¢¨¢i¢i¢i¢i¢© ¢ª¢i¢i¢« ¢¨¢i¢i¢i¢i¢©
+ ¢ª¢i¢© ¢ª¢« ¢¨¢i¢«
+ ¢i ¢© ¢¨ ¢i
+ ¢i ¢i¢i ¢i
+ ¢« ¢ª
diff --git a/sample/etc/chickens/k9 b/sample/etc/chickens/k9
new file mode 100644
index 00000000..cda73fd8
--- /dev/null
+++ b/sample/etc/chickens/k9
@@ -0,0 +1,11 @@
+§ÔªÌ¤­³N-¤ô
+  ¡´ ¢¨ ¢w¢w¢w¢w 
+  ¡´ ¢¨¢¨¢i¢i¢© ¢w¢w 
+  ¡´ ¢«¢ª¢«¢ª¢i¢« ¢w¢w 
+  ¡´ ¢© ¢¨  ¢w¢w¢w 
+  ¢ª¢i¢i¢«¢i¢i ¢w¢w 
+  ¢i¢i¢©¢ª¢« ¢¨¢« ¢w¢w¢w¢w 
+  ¢© ¢¨¢i ¢¨¢i¢ª ¢w¢w¢w
+  ¢i¢i¢i¢i¢i ¢w¢w¢w 
+  ¢i¢i¢i ¢w¢w¢w¢w¢w 
+  ¢ª ¢w¢w¢w 
diff --git a/sample/etc/chickens/kiss b/sample/etc/chickens/kiss
new file mode 100644
index 00000000..fdf155ee
--- /dev/null
+++ b/sample/etc/chickens/kiss
@@ -0,0 +1,14 @@
+
+
+  oo$$$$oooo ooo$$$$$$oo
+  o$$$$$$$$$$$$$$$$$$$$$$$$$$o
+  o$$$$$$$$$$$$$$$$$$$$$$$$$$$$o
+  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$"
+  "$$$$$$$$$$$$$$$$$$$$$$$$$$$"
+  "$$$$$$$$$$$$$$$$$$$$$$$$$"
+  "$$$$$$$$$$$$$$$$$$$$$"
+  ""$$$$$$$$$$$$$$$$"
+  ""$$$$$$$$$""
+  ""$"" 
+ ¨Ó...¿Ë¤@­Ó!!
diff --git a/sample/etc/chickens/l0 b/sample/etc/chickens/l0
new file mode 100644
index 00000000..36f55c21
--- /dev/null
+++ b/sample/etc/chickens/l0
@@ -0,0 +1,9 @@
+
+
+ ¡´¡´¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´
diff --git a/sample/etc/chickens/l1 b/sample/etc/chickens/l1
new file mode 100644
index 00000000..36f55c21
--- /dev/null
+++ b/sample/etc/chickens/l1
@@ -0,0 +1,9 @@
+
+
+ ¡´¡´¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´
diff --git a/sample/etc/chickens/l10 b/sample/etc/chickens/l10
new file mode 100644
index 00000000..b5c8367f
--- /dev/null
+++ b/sample/etc/chickens/l10
@@ -0,0 +1,15 @@
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/l11 b/sample/etc/chickens/l11
new file mode 100644
index 00000000..8646bce2
--- /dev/null
+++ b/sample/etc/chickens/l11
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
diff --git a/sample/etc/chickens/l12 b/sample/etc/chickens/l12
new file mode 100644
index 00000000..8646bce2
--- /dev/null
+++ b/sample/etc/chickens/l12
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
diff --git a/sample/etc/chickens/l13 b/sample/etc/chickens/l13
new file mode 100644
index 00000000..ba9d1d34
--- /dev/null
+++ b/sample/etc/chickens/l13
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´ ¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´
diff --git a/sample/etc/chickens/l14 b/sample/etc/chickens/l14
new file mode 100644
index 00000000..ba9d1d34
--- /dev/null
+++ b/sample/etc/chickens/l14
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´ ¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´
diff --git a/sample/etc/chickens/l15 b/sample/etc/chickens/l15
new file mode 100644
index 00000000..df160353
--- /dev/null
+++ b/sample/etc/chickens/l15
@@ -0,0 +1,15 @@
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´
diff --git a/sample/etc/chickens/l16 b/sample/etc/chickens/l16
new file mode 100644
index 00000000..100d4260
--- /dev/null
+++ b/sample/etc/chickens/l16
@@ -0,0 +1,15 @@
+ ¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´ ¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´
diff --git a/sample/etc/chickens/l2 b/sample/etc/chickens/l2
new file mode 100644
index 00000000..6714c9d2
--- /dev/null
+++ b/sample/etc/chickens/l2
@@ -0,0 +1,12 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/l3 b/sample/etc/chickens/l3
new file mode 100644
index 00000000..6714c9d2
--- /dev/null
+++ b/sample/etc/chickens/l3
@@ -0,0 +1,12 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/l4 b/sample/etc/chickens/l4
new file mode 100644
index 00000000..723291ae
--- /dev/null
+++ b/sample/etc/chickens/l4
@@ -0,0 +1,13 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´ ¡´¡´ ¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/l5 b/sample/etc/chickens/l5
new file mode 100644
index 00000000..723291ae
--- /dev/null
+++ b/sample/etc/chickens/l5
@@ -0,0 +1,13 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´ ¡´¡´ ¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/l6 b/sample/etc/chickens/l6
new file mode 100644
index 00000000..d3edcf12
--- /dev/null
+++ b/sample/etc/chickens/l6
@@ -0,0 +1,14 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/l7 b/sample/etc/chickens/l7
new file mode 100644
index 00000000..d3edcf12
--- /dev/null
+++ b/sample/etc/chickens/l7
@@ -0,0 +1,14 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/l8 b/sample/etc/chickens/l8
new file mode 100644
index 00000000..b5c8367f
--- /dev/null
+++ b/sample/etc/chickens/l8
@@ -0,0 +1,15 @@
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/l9 b/sample/etc/chickens/l9
new file mode 100644
index 00000000..b5c8367f
--- /dev/null
+++ b/sample/etc/chickens/l9
@@ -0,0 +1,15 @@
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/m0 b/sample/etc/chickens/m0
new file mode 100644
index 00000000..36f55c21
--- /dev/null
+++ b/sample/etc/chickens/m0
@@ -0,0 +1,9 @@
+
+
+ ¡´¡´¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´
diff --git a/sample/etc/chickens/m1 b/sample/etc/chickens/m1
new file mode 100644
index 00000000..36f55c21
--- /dev/null
+++ b/sample/etc/chickens/m1
@@ -0,0 +1,9 @@
+
+
+ ¡´¡´¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´
diff --git a/sample/etc/chickens/m10 b/sample/etc/chickens/m10
new file mode 100644
index 00000000..b5c8367f
--- /dev/null
+++ b/sample/etc/chickens/m10
@@ -0,0 +1,15 @@
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/m11 b/sample/etc/chickens/m11
new file mode 100644
index 00000000..8646bce2
--- /dev/null
+++ b/sample/etc/chickens/m11
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
diff --git a/sample/etc/chickens/m12 b/sample/etc/chickens/m12
new file mode 100644
index 00000000..8646bce2
--- /dev/null
+++ b/sample/etc/chickens/m12
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
diff --git a/sample/etc/chickens/m13 b/sample/etc/chickens/m13
new file mode 100644
index 00000000..ba9d1d34
--- /dev/null
+++ b/sample/etc/chickens/m13
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´ ¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´
diff --git a/sample/etc/chickens/m14 b/sample/etc/chickens/m14
new file mode 100644
index 00000000..ba9d1d34
--- /dev/null
+++ b/sample/etc/chickens/m14
@@ -0,0 +1,14 @@
+ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´¡´ ¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´ ¡´¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´
diff --git a/sample/etc/chickens/m15 b/sample/etc/chickens/m15
new file mode 100644
index 00000000..df160353
--- /dev/null
+++ b/sample/etc/chickens/m15
@@ -0,0 +1,15 @@
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´
diff --git a/sample/etc/chickens/m16 b/sample/etc/chickens/m16
new file mode 100644
index 00000000..100d4260
--- /dev/null
+++ b/sample/etc/chickens/m16
@@ -0,0 +1,15 @@
+ ¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´¡´¡´
+ ¡´ ¡´ ¡´ ¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´¡´¡´ ¡´¡´
+ ¡´ ¡´
+ ¡´¡´¡´ ¡´¡´
diff --git a/sample/etc/chickens/m2 b/sample/etc/chickens/m2
new file mode 100644
index 00000000..6714c9d2
--- /dev/null
+++ b/sample/etc/chickens/m2
@@ -0,0 +1,12 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/m3 b/sample/etc/chickens/m3
new file mode 100644
index 00000000..6714c9d2
--- /dev/null
+++ b/sample/etc/chickens/m3
@@ -0,0 +1,12 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/m4 b/sample/etc/chickens/m4
new file mode 100644
index 00000000..723291ae
--- /dev/null
+++ b/sample/etc/chickens/m4
@@ -0,0 +1,13 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´ ¡´¡´ ¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/m5 b/sample/etc/chickens/m5
new file mode 100644
index 00000000..723291ae
--- /dev/null
+++ b/sample/etc/chickens/m5
@@ -0,0 +1,13 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´¡´¡´ ¡´¡´ ¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/m6 b/sample/etc/chickens/m6
new file mode 100644
index 00000000..d3edcf12
--- /dev/null
+++ b/sample/etc/chickens/m6
@@ -0,0 +1,14 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/m7 b/sample/etc/chickens/m7
new file mode 100644
index 00000000..d3edcf12
--- /dev/null
+++ b/sample/etc/chickens/m7
@@ -0,0 +1,14 @@
+
+
+
+ ¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´¡´¡´¡´¡´¡´
diff --git a/sample/etc/chickens/m8 b/sample/etc/chickens/m8
new file mode 100644
index 00000000..b5c8367f
--- /dev/null
+++ b/sample/etc/chickens/m8
@@ -0,0 +1,15 @@
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/m9 b/sample/etc/chickens/m9
new file mode 100644
index 00000000..b5c8367f
--- /dev/null
+++ b/sample/etc/chickens/m9
@@ -0,0 +1,15 @@
+ ¡´¡´ ¡´¡´
+ ¡´¡´¡´¡´ ¡´¡´¡´¡´
+ ¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´ ¡´ ¡´
+ ¡´¡´ ¡´¡´¡´
+ ¡´ ¡´
+ ¡´ ¡´
+ ¡´ ¡´¡´¡´ ¡´
+ ¡´ ¡´ ¡´
+ ¡´
diff --git a/sample/etc/chickens/medicine b/sample/etc/chickens/medicine
new file mode 100644
index 00000000..2bde35ed
--- /dev/null
+++ b/sample/etc/chickens/medicine
@@ -0,0 +1,14 @@
+
+
+
+[1;36 ùúùùùû
+ ùúùý
+  ¢b¢b¢b¢d ùø ¢b¢b¢b¢d
+ ¢¤¢¤¡ó ùø ¢¤¢¤¡·
+ ¢« ¢ª ùø ¢« ¢ª
+  ¢~¢w¢w¢w¢w¢wùó¢w¢w¢w¢w¢w¢¡
+  ¢x pepper  ùø  salt ¢x
+ ¢x¢ªùþùþ¢« ùø ¢ªùþùþ¢«¢x
+ \ùíùùùùùùùùùùùäùùùùùùùùùùùí/
+
+ ¦YÃÄÅo~~~
diff --git a/sample/etc/chickens/nofood b/sample/etc/chickens/nofood
new file mode 100644
index 00000000..d784c9e0
--- /dev/null
+++ b/sample/etc/chickens/nofood
@@ -0,0 +1,18 @@
+
+ ¢B ¢A ¢« ¡þ¢ª ¡´¡´¡´
+ ¡X ¡´ ¡X  ¢«¢ª  ¡´¡´¡´¡´
+ ¢A ¢B ¡´-¡´¢w  ¡´¡´¡´¡´
+ ¡Æ ¡Æ¡´¢i ¡´¡´¡´
+ ¢i ¢i¢i¢«  ¢i
+ ¢i ¢«¢ª¡Å¡þ¢«¢i¢ª
+ ¢i¢i¢i¢i ¢i¢i¢i ¢i 
+ ¢ª ¢ª¢i¢«
+ ¢ª ¢«¢ª ¢ª ¢i¢i¢i
+ ¢« ¢ª¢ª¢i¡´¢i¢i¢i
+ ¡ó ¡ó ¢ª¢ª¢«¢ª ¢«
+  ¢ª    ¢ª¢« ¡´¢b¢c¢d¢e
+     ¢d    
+   ¢«    
+  ùþ¢«¢i  
+  ¢i¢i¢i¢i ¢i¢i¢i¢i ,,.....
+ ¾j¹LÀY¤F Â÷®a¥X¨«...
diff --git a/sample/etc/chickens/nohp b/sample/etc/chickens/nohp
new file mode 100644
index 00000000..474f9c63
--- /dev/null
+++ b/sample/etc/chickens/nohp
@@ -0,0 +1,16 @@
+
+ ¢g¢i¢i¢i¢i¢i¢i¢i¢g
+ ¢i¢i¢i¢i¢i¢i¢i¢i¢i¢i¢i
+ ¢i¢i¢i¢i¢i¢i¢i¢i¢i¢i¢i¢i
+ ¢l ¢i¢i¢i ¢i¢i ¢i¢i¢i
+ ¢l¢l¢l ¢i¢i¢i ¢i ¢i¢i¢i
+¢l¢l¢l¢l¢l ¢i¢i ¢i ¢i¢i
+¢l¢l¢l¢l¢l ¢i¢b ¢X ¢i ¢X ¢b¢i
+¢i¢i¢i¢i¢i ¢f ¢i¢f¢i¢i¢f¢i ¢f
+¢i¢i¢i¢i¢i ¢i¢i¢i¢c¢i¢c¢i¢i¢i
+ ¢i¢i¢i¢i ¢i ¢n¢m¢n¢n¢m¢o ¢i
+ ¢i¢i¢i ¢i ¢i
+ ¢o¢m ¢i ¢i
+ ¢o¢m ¢d ¢m¢m¢m¢m¢m¢m¢i ¢c
+ ¢o¢m ¢d¢d¢d ¢i¢i¢i¢i¢i¢i ¢d¢d¢d
+ Åé¤O(HP)¯ÓºÉ ¦º±¼¤F :~~
diff --git a/sample/etc/chickens/nosatis b/sample/etc/chickens/nosatis
new file mode 100644
index 00000000..c8495275
--- /dev/null
+++ b/sample/etc/chickens/nosatis
@@ -0,0 +1,6 @@
+
+­ó
+
+§Ú¤£º¡·N§A³o­ÓÄê«O¥À
+
+Byebye
diff --git a/sample/etc/chickens/oo b/sample/etc/chickens/oo
new file mode 100644
index 00000000..e316b055
--- /dev/null
+++ b/sample/etc/chickens/oo
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+  £f
+  ¡´¡´
+ ¡´¡´¡´
+ ¡´¡´
+ ¡´ 
+
+ ¦Y¤j¸É¤Y¸Ñ°£¯h³Ò§a
diff --git a/sample/etc/chickens/read b/sample/etc/chickens/read
new file mode 100644
index 00000000..e4060357
--- /dev/null
+++ b/sample/etc/chickens/read
@@ -0,0 +1,14 @@
+
+
+
+
+
+ ¢d¢d¢d¢d
+  ùø |/ ¡Ä¡Ä
+  ¢b¢g¢c ¢h ¢y::::¢j
+  ùÝùùùùùùùùùùùùùÞùùùùùùùß
+  ¢x ¡× ¢x ¡× ¢x
+  ¢u¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢t
+  ¢x ¢x ¡×¡@¢x
+ ¢x¡@¡@¡@¡@¡@¡@¢u¢w¢w¢w¢t
+ ¥Î¥\®É¶¡Åo.....
diff --git a/sample/etc/chickens/sell b/sample/etc/chickens/sell
new file mode 100644
index 00000000..e253e3d0
--- /dev/null
+++ b/sample/etc/chickens/sell
@@ -0,0 +1,23 @@
+
+  *  ¡W  *
+ ¡@¢@ ¡W ¡þ¡@ 
+ ¡U  ¡@¢@ ¡U ¡þ¡@ ¡¯ 
+  ¢@¡U¡þ ¡@¢@ ¢x ¡@¡þ¡@ 
+  ¡Ð¡ÐÆæ¡Ð¡Ð¡@  ¢¨¢i¢i¢i¢i¢i¢© 
+  ¡þ¡U¢@  ¢i¢«¢@¢x¡þ¢ª¢i 
+  ¡U  - - ----¡Ð¢ª¡Ð¢w¡¯¢w¡Ð¢i¡Ð---- - - 
+  ¡þ¢x¢@ ¢i¡@ ¡¯ 
+ ¡¯  ¡þ ¡U ¢¨¢« 
+  ¡þ¡a¢P¡¹¢P¡b¢@ 
+  ¡þ  (¢e¢e)  ¢@ 
+  ¡¯  ¡þ  ¢g¢g  ¢@ 
+  ¢i¢i 
+  ¢x  ¢i¢i  *  ¡@ ¡U 
+  ¢@ ¢x ¡þ  ¢i¢i ¢@¡U¡þ 
+  ¡þ¡U¢@  ¢i¢i  -----¢q----- 
+  ¡K¡K¡]¡°¡^¡K¡K  ¢i¢i ¡þ¡U¢@ 
+ ¢@¡U¡þ  ¢i¢i  ¡U 
+ ¡þ ¢x ¢@  ¢i¢i 
+  *  ¢x  (ùùùù)  * 
+ ¢v¢v ²×©ó¸Ñ²æ¤F ^_^....
+
diff --git a/sample/etc/chickens/toofat b/sample/etc/chickens/toofat
new file mode 100644
index 00000000..b20a502e
--- /dev/null
+++ b/sample/etc/chickens/toofat
@@ -0,0 +1,17 @@
+
+
+
+
+ .-., ,.-.
+ '-. /:::\\ //:::\ .-'
+ '-.\|':':' `"` ':':'|/.-'
+ `-./`. .-=-. .-=-. .`\.-`
+ /=- / | \ -=\
+ ; | | | ;
+ |=-.|______|______|.-=|
+ |== \ 0 /_\ 0 / ==|
+ |= /'---( )---'\ =|
+ \ \: .'. :/ /
+ `\= '--` `--' =/'
+ `-=._ _.=-'
+ `"""`  ªÎ­D¹L«×..¼µ¦º¤F..
diff --git a/sample/etc/chickens/tootired b/sample/etc/chickens/tootired
new file mode 100644
index 00000000..a1f0429f
--- /dev/null
+++ b/sample/etc/chickens/tootired
@@ -0,0 +1,15 @@
+
+
+ ¢q¢q¢q¢q¢q¢q¢q¢q¢q ¢b¢c¢d ¢q¢q¢q¢q¢q
+ ¢q¢q¢q¢q¢q¢e¢i¢e ¡»¡»¢y ¢« ¢ª¢ª¢q
+ ¢q¢q¢q¢q/  ¡ó¡ó  ¢ªùþ¢«  ¢÷¢÷  \¢q
+ ¢d__¢« ¡ã¢ª¢g¢c¢m¢« o¢j  ¢ªùþ¢« ¢q
+  ¢v¢ª ¡ã¢«¢ª¢ª¢ª¢i¢yO¢k¢m ¢d¢d¢q
+ -------¢ª¢ª¢ª¢ª¢ª¢ª¢i¢÷¢« ¢i¡´ ¢«¢i
+  ¢ª____¢ª¢g¢g¢ª¢ª ¡Ý¡Ý¡Ý¡Ý¢m¢m¢m¢m¢m¢m
+ ¢¨ ¢ª¢iùÝùùùùùùùùùùùùùùùù¢« ¢g¢g¢o¢d 
+ ¢e¢e ¢ªùø¢ª ¢ª ¢g¢i ¢o¢i ¢i ¢o 
+ ¢m ¢ª¢ª ¢ª ¢i  ¢o ¢m¢i ¢o¢i 
+ ¢m ¢¨ùþ¢« ¢ª¢©¢« ¢o ¢m¢i ¢ª 
+
+ ¾Þ³Ò¹L«×.....²Ö­Ë¤F......
diff --git a/sample/etc/domain_name_query b/sample/etc/domain_name_query
new file mode 100644
index 00000000..cc3a05f2
--- /dev/null
+++ b/sample/etc/domain_name_query
@@ -0,0 +1,256 @@
+# '#'¦Û¤§«á¥i¥H¥[µù¸Ñ
+#
+# ¤U­±³o'@'¦æ¤£¥i®³±¼
+# ¬dµL˽¦í§}
+@@@@@@@@@@@@@@ ----------
+
+# 255.255.255.255 ¦U¤H±MÄݽЩñ³oÃä
+
+# ¾Ç®Õ ©Î ¹ÎÅé
+# ¸s²Õ½Ð¥Ñ¤p¨ì¤j±Æ¦C
+
+pclab&csie bcªºpclab
+.ee.ntu. ¥x¤j¹q¾÷¾Ç°|
+jan.csie.ntu ¥x¤j¸ê°T¦a¤U¤@¤ë
+feb.csie.ntu ¥x¤j¸ê°T¦a¤U¤G¤ë
+mar.csie.ntu ¥x¤j¸ê°T¦a¤U¤T¤ë
+apr.csie.ntu ¥x¤j¸ê°T¦a¤U¥|¤ë
+may.csie.ntu ¥x¤j¸ê°T¦a¤U¤­¤ë
+jun.csie.ntu ¥x¤j¸ê°T¦a¤U¤»¤ë
+sep.csie.ntu ¥x¤j¸ê°T¦a¤U¤E¤ë
+snoopy.csie ¥v¥£¤ñ¤u§@¯¸
+csie.ntu ¥x¤j¸ê°T¨t
+140.112.28. ¥x¤j¸ê°T¨t
+140.112.29. ¥x¤j¸ê°T¨t
+140.112.30. ¥x¤j¸ê°T¨t
+140.112.31. ¥x¤j¸ê°T¨t
+#140.112.4 ¥x¤j¸ê°T¨t
+phys.ntu ¥x¤jª«²z¨t
+scorpio.im.ntu ¥x¤j¸êºÞscorpio
+im.ntu ¥x¤jºÞ°|
+ccnet1.ntu ¥x¤j±JªÙDNS
+cc.ntu. ¥x¤j­pºâÂû¤¤¤ß
+140.112.3. ¥x¤j­pºâÂû¤¤¤ß
+
+140.112.10. ¥x¤j¤g¤ì¨t
+140.112.11. ¥x¤j¤g¤ì¨t
+140.112.12. ¥x¤j¤g¤ì¨t
+140.112.13. ¥x¤j¤g¤ì¨t
+ce.ntu ¥x¤j¤g¤ì¨t
+
+140.112.15. ¥x¤j§ÓÂEÀ]
+
+140.112.16. ¥x¤j·s¤u¾Ç°|¤j¼Ó
+140.112.17. ¥x¤j¹q¾÷¾Ç°|
+140.112.18. ¥x¤j¹q¾÷¾Ç°|
+140.112.19. ¥x¤j¹q¾÷¾Ç°|
+140.112.20. ¥x¤j¹q¾÷¾Ç°|
+140.112.21. ¥x¤j¹q¾÷¾Ç°|
+
+140.112.22. ¥x¤j¤Æ¤u¨t
+140.112.23. ¥x¤j¤Æ¤u¨t
+140.112.26. ¥x¤j³y²î¨t
+
+140.112.169. ¥x¤j¬ã¤G¤p®M©Ð
+140.112.174. ¥x¤j¤k¤E¯½´Ö§{
+140.112.216. ¥x¤j¤k¤T²¢»eºÛ
+140.112.220. ¥x¤j¤k¤@¤j»Ó©Ð
+140.112.221. ¥x¤j¤k¤@¤j»Ó©Ð
+140.112.224. ¥x¤j¤k¤C¦¨¦ç³õ
+140.112.225. ¥x¤j¤k¤­°w´«Ç
+140.112.239. ¥x¤j¨k¤@ºÛ
+140.112.240. ¥x¤j¨k¤@ºÛ
+140.112.241. ¥x¤j¨k¤@ºÛ
+140.112.242. ¥x¤j¨k¤@ºÛ
+140.112.243. ¥x¤j¨k¤T«Î
+140.112.244. ¥x¤j¨k¤T«Î
+140.112.245. ¥x¤j¨k¤­©Ð
+140.112.246. ¥x¤j¨k¤­©Ð
+140.112.247. ¥x¤j¨k¤»²²
+140.112.248. ¥x¤j¨k¤»²²
+140.112.249. ¥x¤j¨k¤C½`
+140.112.250. ¥x¤j¨k¤C½`
+140.112.251. ¥x¤j¨k¤K§O¹Ö
+140.112.252. ¥x¤j¨k¤K§O¹Ö
+140.112.253. ¥x¤j¨k¤K§O¹Ö
+
+.m1.ntu ¥x¤j¨k¤@ºÛ
+.m2.ntu ¥x¤j¨k¤GÀ]
+.m3.ntu ¥x¤j¨k¤T«Î
+.m4.ntu ¥x¤j¨k¥|©Ò
+.m5.ntu ¥x¤j¨k¤­©Ð
+.m6.ntu ¥x¤j¨k¤»²²
+.m7.ntu ¥x¤j¨k¤C½`
+.m8.ntu ¥x¤j¨k¤K²ø
+.g2.ntu ¥x¤j¬ã¤G¤p®M©Ð
+.f1.ntu ¥x¤j¤k¤@¤j»Ó©Ð
+.f2.ntu ¥x¤j¤k¤G»e¤ë«Î
+.f3.ntu ¥x¤j¤k¤T²¢»eºÛ
+.f4.ntu ¥x¤j¤k¥|°ª±^«Î
+.f5.ntu ¥x¤j¤k¤­°w´«Ç
+.f6.ntu ¥x¤j¤k¤»±B¯½´Y
+.f7.ntu ¥x¤j¤k¤C¦¨¦ç³õ
+.f8.ntu ¥x¤j¤k¤K¬V¦ç¶í
+.f9.ntu ¥x¤j¤k¤E¯½´Ö§{
+
+green.ev.ntu. ¥x¤jÀô¤u©Ò
+.ie.ntu.edu.tw ¥x¤j¤u¤u©Ò
+140.112.36. ¥x¤j¤u¤u©Ò(·s¤u¼Ó)
+140.112.38. ¥x¤jÀ³¤O©Ò
+140.112.39. ¥x¤j«°¶m©Ò
+140.112.40. ¥x¤j¤ô¤u©Ò(·s¤u¼Ó)
+140.112.42. ¥x¤j¹q¾÷ÂÂÀ]
+140.112.43. ¥x¤j¾÷±ñ¨t
+140.112.44. ¥x¤j¾÷±ñ¨t
+140.112.46. ¥x¤j¾÷±ñ¨t
+math.ntu ¥x¤j¼Æ¾Ç¨t
+140.112.50. ¥x¤j¼Æ¾ÇÀ]
+140.112.52. ¥x¤jª«²z¨t
+140.112.54. ¥x¤j¤Æ¾Ç¨t
+140.112.56. ¥x¤j¦a½è¨t
+140.112.58. ¥x¤j°Êª«¨t
+140.112.60. ¥x¤j´Óª«¨t
+140.112.61. ¥x¤j´Ó¬ã¤j¼Ó
+psy.ntu ¥x¤j¤ß²z¨t
+140.112.62. ¥x¤j¤ß²z¨t
+140.112.64. ¥x¤j¦a²z¨t
+140.112.65. ¥x¤j¥þ²yÅܾE/¾®ºA¤¤¤ß
+140.112.66. ¥x¤j¤j®ð¨t
+140.112.67. ¥x¤j¤j®ð¨t
+140.112.68. ¥x¤j®ü¬v©Ò
+140.112.69. ¥x¤j®ü¬v©Ò
+140.112.70. ¥x¤jº®¬ì©Ò
+140.112.72. ¥x¤j¥Í¤Æ©Ò
+140.112.74. ¥x¤j¹AÃÀ¨t
+140.112.75. ¥x¤j¥Í²Î±Ð«Ç
+140.112.76. ¥x¤j¹A¤u¨t
+140.112.78. ¥x¤j¹A¤Æ¨t
+140.112.80. ¥x¤j´Ó¯f¨t
+140.112.81. ¥x¤j©øÂÎÀ]
+140.112.82. ¥x¤j´ËªL¨t
+140.112.84. ¥x¤j¯b²£¨t
+140.112.86. ¥x¤j¹A¸g¨t
+140.112.88. ¥x¤j¶éÃÀ¨t
+140.112.89. ¥x¤j¤u¼t
+140.112.92. ¥x¤j¹A±À¨t
+140.112.94. ¥x¤j¹A¾÷¨t
+140.112.96. ¥x¤jÃ~Âå¨t
+140.112.99. ¥x¤j½Ã¥Í²Õ
+140.112.111. ¥x¤j¬¡°Ê¤¤¤ß
+140.112.120. ¥x¤j¬¡°Ê¤¤¤ß
+140.112.100. ¥x¤j´Ó¯f¨t¾iÂÎÀ]
+140.112.106. ¥x¤j¸êºÞ¨t
+140.112.108. ¥x¤jºÞ°|­p¤¤
+140.112.110. ¥x¤jºÞ°|­p¤¤
+140.112.120. ¥x¤jÂå¾Ç®Õ°Ï
+140.112.136. ¥x¤j¤½½Ã¨t
+140.112.141. ¥x¤j¤¤¤å¨t/¥~¤å¨t
+140.112.142. ¥x¤j¾ú¥v¨t/ÃÀ³N¥v©Ò
+140.112.143. ¥x¤j­õ¾Ç¨t/¹A·~³¯¦C¼s
+140.112.145. ¥x¤jÁò³õ¤Î´¶³q±Ð«Ç
+140.112.146. ¥x¤j¤é¤å¨t/À¸¨è©Ò/»y¨¥©Ò
+140.112.150. ¥x¤jªk¾Ç°|,ªk¹Ï
+140.112.153. ¥x¤j·s»D©Ò
+140.112.155. ¥x¤j¤T¬ã©Ò
+140.112.156. ¥x¤jªÀ·|¨t
+140.112.157. ¥x¤jªÀ·|¨t
+140.112.160. ¥x¤j¦æ¬F¤j¼Ó
+140.112.178. ¥x¤j¾Ç¥Í¦í±JªA°È²Õ
+140.112.181. ¥x¤jºÞ²z¾Ç°|
+140.112.182. ¥x¤j·s¤u¼Ó
+140.112.183. ¥x¤j¹A·~¦Û°Ê¤Æ±Ð«Ç
+lib.ntu. ¥x¤jÁ`¹Ï
+
+.admin.yzu ¤¸´¼ºô±À
+.dorm.ccu.e ¤¤¥¿¤j®ÈªÀ
+.mayju.com ±ö¦Ë¤s²ø
+as.ntu. ¥x¤j¤j®ð¨t
+csie.nctu. ¥æ¤j¸ê¤u
+www.nia. °ê¥ßÃÀ³N¾Ç°|www
+nia.edu.tw °ê¥ßÃÀ³N¾Ç°|
+163.18. °ª¶¯¥Ì½©¶é
+203.64.3. °ê¥ßÃÀ³N¾Ç°|
+140.119. ¬Fªv¤j¾Ç
+cc.ntnu. ®v¤j­p¤¤
+140.122. ®v½d¤j¾Ç
+k2.dorm.nc ¦¨¤j¥ú¤G8ªÙ
+cc.nctu. ¥æ¤j­p¤¤
+php&cc.nctu. ¥æ¤j­p¤¤
+nchu ¤¤¿³¤j¾Ç
+linux.na.ntu. ¥x¤j³y²î¤¤¤ß
+140.112.8. ¥x¤j­pºâÂû¤¤¤ß
+140.112.7. ¥x¤j­p¤¤PC«Ç
+cc.ncku. ¦¨¤j­p¤¤
+stmail.fju. »²¤j­p¤¤
+IP&dialup.ntu. ­p¤¤¼·±µ¨t²Î
+im.ntu.edu. ¥x¤j¸êºÞ
+med.mc.ntu. ¥x¤jÂå°|ºô¸ô³¡
+mc.ntu. ¥x¤jÂå°|ºô¸ô³¡
+139.175. SeedNet
+.seed.net.tw SeedNet
+210.64. HiNet
+168.95. Hinet
+.ts.hin HiNet
+.hinet. HiNet
+cc.chpi. ¤¤µØ¤u¾Ç°|
+.nctu. ¥æ³q¤j¾Ç
+.cc.nccu.edu.tw ¬F¤j­p¤¤
+.nccu.edu.tw ¬Fªv¤j¾Ç
+.AB. ²M¤j±JªÙ
+.ncku. ¦¨¤j
+.seeder. ªüªiù¸ê°Tºô
+iis. ¤¤¬ã°|¸ê°T©Ò
+sinica. ¤¤¥¡¬ã¨s°|
+ntust. ¥x¬ì¤j
+scu. ªF§d¤j¾Ç
+fju. »²¤¯¤j¾Ç
+nthu. ²MµØ¤j¾Ç
+thu. ªF®ü¤j¾Ç
+ntu.edu ¥xÆW¤j¾Ç
+ntut.edu ¥x¥_¬ì§Þ¤j¾Ç
+140.112 ¥xÆW¤j¾Ç
+cgu. ªø©°¤j¾Ç
+ntou. ®ü¬v¤j¾Ç
+NTOU. ®ü¬v¤j¾Ç
+NCTU. ¥æ³q±JªÙ
+140.125 ¶³ªL¬ì§Þ¤j¾Ç
+tpml.edu.tw ¥x¥_¥«¥ß¹Ï®ÑÀ]
+ntnu. ®v½d¤j¾Ç
+ficnet.net ¤j²³ºô¸ô
+tku. ²H¦¿¤j¾Ç
+shu. ¥@·s¤j¾Ç
+ncue. ¹ü¤Æ®v½d¤j¾Ç
+ncu. ¤¤¥¡¤j¾Ç
+ntnu. ®v½d¤j¾Ç
+140.115 ¤¤¥¡¤j¾Ç
+ndhu. ªFµØ¤j¾Ç
+iii ¸êµ¦·|
+nsysu. ¤¤¤s¤j¾Ç
+ethome ªF´Ë¼eÀW
+tmc.edu.tw ¥x¥_Âå¾Ç°|
+ym.edu.tw ¶§©ú¤j¾Ç
+chu.edu.tw ¤¤µØ¤j¾Ç
+140.138 ¤¸´¼¤j¾Ç
+140.128 ªF®ü¤j¾Ç
+140.120 ¤¤¿³¤j¾Ç
+ntpu. ¥x¥_¤j¾Ç
+yzu.edu.tw ¤¸´¼¤j¾Ç
+cyut.edu.tw ´Â¶§¬ì§Þ¤j¾Ç
+fg.tp. ¥_¤@¤k
+nhltc. ªá½¬®v½d¾Ç°|
+tceb. ¥x¤¤¥«©²±Ð¨|§½
+ntcic. ¥x¤¤§Þ³N¾Ç°|
+jhnc.tp. ¥_¥«¸Û¥¿°ê¤¤
+dyu. ¤j¸­¤j¾Ç
+ilc.edu. ©yÄõ¿¤±Ð¨|¸ê°Tºô
+ks.edu. °ª¶¯¿¤±Ð¨|ºô
+cma. ³°­x©x®Õ
+ssvs.tp. ªQ¤s®a°Ó
+csmc. ¤¤¤sÂå¾Ç°|
+ttu. ¤j¦P¤j¾Ç
+cmc. ¤¤°êÂåÃľǰ|
+kmu. °ª¶¯Âå¾Ç¤j¾Ç
+tmtc. ¥_¥«®v½d¾Ç°|
+140.117. ¤¤¤s¤j¾Ç
+210.208. SayHiNetµL­­¼·±µ
+ck.tp.edu.tw «Ø°ê¤¤¾Ç
diff --git a/sample/etc/feast b/sample/etc/feast
new file mode 100644
index 00000000..29473341
--- /dev/null
+++ b/sample/etc/feast
@@ -0,0 +1,47 @@
+01 01 ¤¸¥¹©ñ°²
+01 02 ¤¸¥¹¤S©ñ°²
+01 11 ¥qªk¸`
+01 23 ¦Û¥Ñ¤é
+02 14 ±¡¤H¸`
+02 28 ¤G¤G¤K¬ö©À
+03 01 §L§Ð¸`
+03 05 µ£­x¸`
+03 12 ´Ó¾ð¸`
+03 14 ¥Õ¦â±¡¤H¸`
+03 17 °êÂå¸`
+03 21 ®ð¶H¸`
+03 29 «C¦~¸`
+04 01 ·M¤H¸`
+04 04 °ü¥®¸`
+04 04 ¨àµ£¸`
+04 05 ²M©ú¸`
+05 01 ³Ò°Ê¸`
+05 04 ¤åÃÀ¸`
+06 03 ¸T·Ï¸`
+06 09 ÅK¸ô¸`
+06 06 ¤uµ{®v¸`
+06 15 ĵ¹î¸`
+07 01 ¤½¸ô¸`
+07 03 ¦X§@¸`
+07 04 ¬ü°ê¿W¥ß¬ö©À¤é
+07 11 ¯è®ü¸`
+07 14 ªk°ê°ê¼y
+08 08 ¤K¤K¤÷¿Ë¸`
+08 14 ªÅ­x¸`
+09 01 °OªÌ¸`
+09 03 ­x¤H¸`
+09 09 ª¯ª¯¸`
+09 18 ¤E¤@¤K¨ÆÅÜ
+09 28 ±Ð®v¸`
+10 10 °ê¼y¤é
+10 21 µØ¹´¸`
+10 25 ¥xÆW¥ú´_¸`
+10 31 ½±¤½½Ï¨°
+11 11 ¤u·~¸`
+11 12 °ê¤÷½Ï¨°
+11 15 ¥xÆW¤j¾Ç®Õ¼y
+12 01 ¥@¬É·R´þ¤é
+12 10 ¥@¬É¤HÅv¸`
+12 13 ¤T°Ó¶g¦~¼y
+12 24 X'masEve
+12 25 ¸t½Ï¸`
diff --git a/sample/etc/goodbye b/sample/etc/goodbye
new file mode 100644
index 00000000..38f8aac9
--- /dev/null
+++ b/sample/etc/goodbye
@@ -0,0 +1,19 @@
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¦A¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¦A¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¦A¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¦A¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¦A¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¦A¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{¦A¨£¦A¨£¦A¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¢x ½Ð¥J²Ó¦^¾Ð±zªº±K½X¡A  ¢x¢w¢{¦A¨£¦A¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¢x ¦pªG¯uªº§Ñ°O±K½X¤F¡A  ¢x ¢x¦A¨£¦A¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¢x ½Ð¥Î[new]­«·sµù¥U§a¡I ¢x ¢x¦A¨£¦A¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¢x ¶Ã¿å±K½X·|¯d¤U°O¿ý³á¡C ¢x ¢x¦A¨£¦A¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} ¢x¦A¨£¦A¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}¦A¨£¦A¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¦A¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¨£¦A¦A¦A¨£¦A¨£¦A¨£¦A¨£¦A
+¦pªG±zµo²{±zªºID¤£¨£¤F, ¦Ó¥B¤£¬O¦]¬°¤Ó¤[¨S¨Ó³Q¬åªÌ
+½Ð³qª¾¯¸°ÈºÞ²z­û, ¤Á¤Å­«·snew ­ì¨ÓªºID, §_«h©Ò¦³°O
+¿ý©Mª÷¿ú±N·|Âk¹s
diff --git a/sample/etc/register b/sample/etc/register
new file mode 100644
index 00000000..53b5e2d6
--- /dev/null
+++ b/sample/etc/register
@@ -0,0 +1,17 @@
+¢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¢{
+¢x ½Ð°Ñ¦Ò¤U¦Cªº½d¨Ò¶ñ¼g±zªºµù¥U¸ê®Æ¡G ¢x
+¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t
+¢x½Ð¿é¤J¥N¸¹: piggy ¢x ¿é¤J±z·Q¥Îªº­^¤å¥N¸¹ ¢x
+¢x½Ð³]©w±K½X: I'mPig ¢x ½Ð³]©w±K½X¡A¤£¹L¿Ã¹õ¤WÀ³¸Ó¬Ý¤£¨£ ¢x
+¢x½ÐÀˬd±K½X: I'mPig ¢x ½Ð¦A¦¸¿é¤J±K½X¡A¥H¥Ü½T©w ¢x
+¢x ¢x Kermit ¨Ï¥ÎªÌ½Ð¥´ vt320 ¢x
+¢x±zªº¼ÊºÙ: ½Þ¦~¥Íªº¬ü¬Ü ¢x ±zµoªí¤å³¹¥Îªºµ§¦W©Îºï¸¹ ¢x
+¢x¯u¹ê©m¦W: ¦¶¾å´A ¢x ±zªº¯u¹ê©m¦W ¢x
+¢x¥Ø«e¦í§}: ·s¦Ë¿¤¤lµê¶m¯Q¦³§ø543¸¹ ¢x ±z¥Ø«eªºÁpµ¸¦a§}(¸Ô²Ó¶ñ¼g) ¢x
+¢xºô¸ô¶l¥ó¦a§}: whoami@cs.ntnu.edu.tw ¢x ±zªº E-Mail address ¢x
+¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢}
+ ¡° ¦b¥»¯¸µù¥UªÌ¡A¥NªíÄ@·N´L±q¥»¯¸¨î«×»P¯¸³W¡A§_«h½ÐÂ÷¶}¡C
+ ¡° ¥N¸¹ [ID] ¦Ü¤Ö­n¨â­Ó¦r¡A¤£©y±Ä¥Î¼Æ¦r¡C
+ ¡° ±K½X ¦Ü¤Ö­n¥|­Ó¦r¡A¤£¥i»P [ID] ¹p¦P¡A¤£©y¥þ³¡¤p¼g¡C
+ ¡° ½Ð½T¹ê«ö·Ó³W©w¸Ô²Ó¶ñ¼g¡A§_«h¤£¤©³q¹L¡I
+ ¡° ¥H¤W¸ê®Æ¯Ê¤@¤£¥i¡A·q½Ð¦X§@¡I
diff --git a/sample/etc/registered b/sample/etc/registered
new file mode 100644
index 00000000..1b52a301
--- /dev/null
+++ b/sample/etc/registered
@@ -0,0 +1,21 @@
+ ùÝùùùûùÝùùùûùúùùùû
+ ùàùùùûùàùùùûùüùùùû ¼f®Ö³q¹L 
+¡º¢w¢w ùãùùùýùãùùùýùüùùùý¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¡º
+
+ ¶Ù¶Ù¡A*s§A¦n¡G
+
+ §Ú¿Ë¦ÛÀ°§A¼f®Ö³q¹LÅo ^o^
+
+ ­YÁÙ¤£¯àPost½Ð­«·slogin¤@¦¸ ^_^ (­n´«¨­¥÷Åo)
+
+
+
+ ¯¬ ¨Ï¥Î´r§Ö
+
+ °O±o±`±`¨Óª±³á.... ^_^
+
+
+
+
+ ¯¸ªø~~
+¡º¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¡º
diff --git a/sample/etc/today_boring b/sample/etc/today_boring
new file mode 100644
index 00000000..12e39ce2
--- /dev/null
+++ b/sample/etc/today_boring
@@ -0,0 +1,22 @@
+ [ ¨d¦Ï®É ]
+ [ ¨d¦Ï®É ]
+ [ ª÷¤û®É ]
+ [ ª÷¤û®É ]
+ [ Âù¤l®É ]
+ [ Âù¤l®É ]
+ [ ¥¨ÃÉ®É ]
+ [ ¥¨ÃÉ®É ]
+ [ ·à¤l®É ]
+ [ ·à¤l®É ]
+ [ ³B¤k®É ]
+ [ ³B¤k®É ]
+ [ ¤Ñ¯¯®É ]
+ [ ¤Ñ¯¯®É ]
+ [ Âù³½®É ]
+ [ Âù³½®É ]
+ [ ®g¤â®É ]
+ [ ®g¤â®É ]
+ [ Å]½~®É ]
+ [ Å]½~®É ]
+ [ ¤ô²~®É ]
+ [ ¤ô²~®É ]
diff --git a/sample/etc/ve.hlp b/sample/etc/ve.hlp
new file mode 100644
index 00000000..c1688bf2
--- /dev/null
+++ b/sample/etc/ve.hlp
@@ -0,0 +1,127 @@
+ ¡i¤@¯ë«ü¥O¡j
+ ^X Àɮ׳B²z ^L ­«·sÅã¥Üµe­±
+ ^V ¤Á´«ANSI¦â±m ^Z Åã¥Ü¥»¨D§Uµe­±
+ ^Q ¤£¦sÀÉÂ÷¶}  ^G ´¡¤J¹Ï¤ù¤å¦r®w
+ ¡i´å¼Ð²¾°Ê«ü¥O¡j
+ ¡ö ©¹«á²¾°Ê¤@®æ ^A,Home ²¾¨ì¦¹¦æ¶}ÀY
+ ¡÷ ©¹«e²¾°Ê¤@®æ ^E,End ²¾¨ì¦¹¦æµ²§À
+ ¡ô,^P ©¹¤W²¾°Ê¤@¦æ (ESC-,) ²¾¨ìÀɮ׶}ÀY
+ ¡õ ©¹¤U²¾°Ê¤@¦æ (ESC-.),^T ²¾¨ìÀÉ®×µ²§À
+ ^B,PgUp ©¹¤W²¾°Ê¤@­¶ ^F,PgDn ©¹¤U²¾°Ê¤@­¶
+ ^S ´M§ä¦r¦ê (ESC-L) ¸õ¦Ü«ü©w¦æ
+ (ESC-n) ¦A©¹«á§ä (ESC-p) ¦A©¹«e§ä
+ (ESC-]) ´M§ä¹ïºÙ¬A©· (ESC-x) ¦^¨ì«e¤@¦ì¸m
+ (ESC-f) ©¹«e¤@¦r (ESC-b) «á°h¤@¦r
+ ¡i§R°£´¡¤J«ü¥O¡j
+ ^D,Del §R°£¥Ø«eªº¦r¤¸ ^H,BS §R°£«e¤@­Ó¦r¤¸
+ ^K §R°£´å¼Ð¤§«á¦Ü¦æ§À ^Y §R°£¥Ø«e³o¦æ
+ ^O,Ins ¤Á´« ´¡¤J/Âл\
+ (ESC-d) §R°£¤@¦r (ESC-0~9) ¶K¤W¼È¦sÀÉ 0-9
+
+ ¡iANSI¢x¶Â¬õºñ¶ÀÂŵµÀQ¥Õ¡j
+
+ «e´º¢x3031323334353637
+ ­I´º¢x4041424344454647
+ Ctrl-V: ¤Á´« ANSI-color ¼Ò¦¡¡A¡u©Ò¨£§Y©Ò±o¡v¡A¥i¥ß§Y½s­×
+ Ctrl-C: ¡uª½Ä±¦¡¡v´¡¤J±m¦â½X¡A¥i»´©ö¬°¤å¦r¡uµÛ¦â¡v (in ANSI-color mode)
+ ¤ä´© ANSI color ½s¿è¼Ò¦¡... ¤£¥u¬O¹wÄý¦Ó¤w
+ ¦P®É, ctrl-C ¦b ANSI mode ¤U¥i¥H¿é¤JÃC¦â...
+ ¦³¤TºØ¼Ò¦¡....
+ w ¥Nªí ¥Õ¦r
+ wb ¥Nªí¥Õ¦r¶Â©³
+ 1wb ¥Nªí°ª«G¥Õ¦r¶Â©³..
+ ¤ä´© overwrite & insert , ¥i»´©ö½s¿èÃþ¦ü Welcome µe­±
+ ¦]¬YºØ­ì¦], ¨ú®ø¦b ansi editing ¤Uªº backspace¥\¯à:P
+ ¡i°Ï¶ô³B²z©R¥O¡j
+ (ESC-l), (ESC-SPACE) ³]©w¼Ð°O°Ï
+ ^W Cut, §â¼Ð°O°Ï°Å¦Ü¼È¦sÀÉ 0
+ (ESC-c) Copy, §â¼Ð°O°Ï«þ¨©¦Ü¼È¦sÀÉ 0
+ ©ÎªÌ¦A«ö¤@¦¸(ESC-SPACE)½T©w¼Ð°O°Ï½d³ò¡A½T©w½d³ò«á:
+ 0: Cut, §â¼Ð°O°Ï°Å¦Ü¼È¦sÀÉ 0
+ 5: Copy, §â¼Ð°O°Ï«þ¨©¦Ü¼È¦sÀÉ 5
+ 6-9: Cut or Copy
+ q: ¨ú®ø
+ ·í»Ý­n§R¡u«Ü¦h¡v¦æ®É¡A¸Õ¸Õ ESC-SPC §a :>
+ ­Y»Ý­n§â¤å³¹ùتº¡u³¡¤À¡v¨ú¥X®É¡AESC-SPC ¤]¾A¥Î¡C
+ (ESC-0/5) Paste, ª½±µ¶K¤W¼È¦sÀÉ 0/5
+ (ESC-6-9) ¶K¤W¼È¦sÀÉ 6-9 ¡A¶K¤W«e¥ý¹wÄý
+ (ESC-j) ±N¼Ð°O°Ï©¹¥ª²¾
+ (ESC-k) ±N¼Ð°O°Ï©¹¥k²¾
+ (ESC-u) ¨ú®ø¼Ð°O°Ï
+ ¡i¯S®í«ü¥O¡j
+ ^U ¿é¤J ESC ½X(¥H * ªí¥Ü) ^C ÁÙ­ì/³]©w ANSI ¦â±m
+ (ESC-y) ±Ï¦^»~§R¦æ ^_(Ctrl-/),(ESC--) ´_­ì¥Ø«e¦æ
+ (ESC-A) ¤Á´«ANSI±m¦â¼Ò¦¡ (ESC-I) ¤Á´«ÁY±Æ(indent)¼Ò¦¡
+ (ESC-P) ¤Á´«ª`­µª½±µ¥´¼Ò¦¡ (ESC-R) ¤Á´« modem ASCII ¤W¶Ç¼Ò¦¡
+ ^R Åã¥Ü¤W¦¸¦©À³°T®§ (ESC-U) ¨Ï¥ÎªÌ¦Cªí
+ (ESC-i) ¶i¤Jµo§b¼Ò¦¡
+
+
+> -------------------------------------------------------------------------- <
+
+ ASC¢º¤W¦â°ò¦±Ð¾Ç
+
+ <<<<<<<<<<<<<<<<<<<<<<<< $ ±Ð ¾Ç ¶} ©l $ >>>>>>>>>>>>>>>>>>>>>>>>>>>>
+  ­º¥ý¡A§i¶D§A¤@¥ó³Ì­«­nªº¨Æ¡A¦b©¹«áªº±Ð¾Ç¤¤©Ò¦³ªº * ¸¹³£¬O«ö Esc Áä
+  ¨â¦¸²£¥Íªº¡A¥H¨ä¥L¤è¦¡¡A¦p¡Gª½±µ«ö * ¸¹¡A©Ò²£¥Íªº³£µLªk°õ¦æ¡C
+  ¹ï¤F¡A * ¸¹²£¥Íªº¤è¦¡¦bÁp¤u¬O«ö Esc ¨â¦¸¡A¦ý¦b¨ä¥L¦a¤è¥i´N¤£¤@©w¤F
+  ¡A¥i¯à¬O Ctrl + U ²£¥Íªº¡AÁ`¤§¡A­Y¤£²M·¡¡A«ö Ctrl + Z ½u¤W»²§U»¡©ú¬Ý¬Ý
+  ´Nª¾¹D¤F¡A¤Ï¥¿¡A²{¦bªº§A¡AÀ³¸Ó¬O¥u¦³¦bÁp¤u¤Wª±§a¡I©Ò¥H¡A´N¥HÁp¤uªº¤è¦¡
+  ±Ð§A¡A¥H«á¦³¨ì§O¯¸®É¡A¦A±Ð§A§a¡I
+  ¥ý§i¶D§A¤@¨Ç°ò¥»ªº¦â±m±±¨î°Ñ¼Æ¡G(°O¦í¡Im ¤@©w¬O¤p¼g¡I¡I)
+ °Ñ ¼Æ ¦â±m Á| ¨Ò »¡ ©ú
+ --------- ------ ----------------------------------------------
+  ############ ¥H¤U¬°·t¦â¨t¦Cªº«e´º¦â±m ############
+ *[0;30m  ¶Â¦â  *[0;30;47m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[0;31m  ¬õ¦â  *[0;31m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[0;32m  ºñ¦â  *[0;32m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[0;33m  ¤g´Ä¦â *[0;33m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[0;34m  ²`ÂÅ  *[0;34m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[0;35m  µµ¦â  *[0;35m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[0;36m  ²LÂÅ  *[0;36m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[0;37m  ¥Õ¦â  *[0;37m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+  ############ ¥H¤U¬°«G¦â¨t¦Cªº«e´º¦â±m ############
+ *[1;30m  ²`¦Ç¦â *[1;30m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[1;31m  «G¬õ¦â *[1;31m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[1;32m  «Gºñ¦â *[1;32m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[1;33m  ¶À¦â  *[1;33m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[1;34m  «G²`ÂÅ *[1;34m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[1;35m  «Gµµ¦â *[1;35m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[1;36m  «G²LÂÅ *[1;36m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[1;37m  «G¥Õ¦â *[1;37m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+  ############## ¥H ¤U ¬° ­I ´º ¦â ±m ##############
+  ############# ©Ò¦³¤å¦rÃC¦â¬Ò¥H¶À¦âÅã¥Ü ###########
+ *[1;33;40m ¶Â¦â  *[1;33;40m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[1;33;41m ¬õ¦â  *[1;33;41m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[1;33;42m ºñ¦â  *[1;33;42m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[1;33;43m ´Ä¦â  *[1;33;43m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[1;33;44m ²`ÂÅ  *[1;33;44m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[1;33;45m µµ¦â  *[1;33;45m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[1;33;46m ²LÂÅ  *[1;33;46m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+ *[1;33;47m ¥Õ¦â  *[1;33;47m´ú¸Õ¤@¤U ==> ´ú¸Õ¤@¤U
+  ¥H¤Wªº©Ò¦³Á|¨Ò¬Ò¬O­×¹¢¹L«áªºµ²ªG¡A­Y¯u·ÓÁ|¨Ò¼g¡A¤£¦ý¨S¹F¨ì­ì¥ý¹w´Á
+  ®ÄªG¡A¤Ï¦Ó¥i¯à·|¾É­P¤Ñ¤U¤j¶Ã¡C«e´º(§Y¤å¦r³¡¥÷)©M­I´º(§Y©³¦â)ªº­×¹¢¤è¦¡
+  ¤£¤@¼Ë¡A¥ý»¡«e´ºªº­×¹¢¤è¦¡¡C
+  ¦AÁ|­Ó¨Ò§a¡I±N "´ú¸Õ¤@¤U" ¤W¦â¡A¤§«áªº³£¤£¤W¦â¡A­Y *[1;33m´ú¸Õ¤@¤U
+  ³oºØ¼gªk¡A¨ä«á­±©Ò¦³ªº¤å¦r³£·|Åܦ¨¶À¦â¡G
+ 
+ *[1;33m´ú¸Õ¤@¤Uxxxx ==> ´ú¸Õ¤@¤Uxxxx
+  ·|²£¥Í¦p¤Wµ²ªG¡A­Y­n±N xxxx Åܦ^­ì¦â¡A«h¥i¡G
+ 
+ *[1;33m´ú¸Õ¤@¤U*[mxxxx ==> ´ú¸Õ¤@¤Uxxxx
+  ¥[­Ó *[m ©Î *[0m ´N¥i¥H¸Ñ¨M¡A¦ý­Y·Q§â xxxx Åܦ¨¨ä¥LÃC¦â¡A«h¡G
+ 
+ *[1;33m´ú¸Õ¤@¤U*[0;36mxxxx ==> ´ú¸Õ¤@¤Uxxxx
+  Á`¤§¡A¦b·Q§ïÅܦâ±mªº³¡¥÷¥[¤W·Q§ïÅܪº¦â±m°Ñ¼Æ¡F¦b·Q°±¤î¤W¦âªº¦a¤è¥[
+  ¤W *[m ©Î *[0m §Y¥i¡I
+  ¥H¤W¡A¬°«e´º¦âªº­×¹¢¤è¦¡¡A±µµÛ¡A»¡»¡­I´º¦âªº­×¹¢¤è¦¡¡A»¡§¹´N¤U½Ò¤F
+  ­ò¡I
+  ­I´º¦âªº¼gªk«Ü©_©Ç¡A¥H¤UÁ|¨Ò»¡©ú¤@¤U¡G
+ 
+ *[1;33;43m´ú¸Õ¤@¤U*[m ==> ´ú¸Õ¤@¤U
+ *[1;33;43m ´ú¸Õ¤@¤U*[m ==>  ´ú¸Õ¤@¤U
+ *[1;33;43m ´ú¸Õ¤@¤U *[m ==>  ´ú¸Õ¤@¤U 
+  ¥¦·|¦]¬°§A°Ñ¼Æªº¦ì¸m¤£¦P¡A¦Ó²£¥Í¤£¦Pªºµ²ªG¡A¥H¦¹¯S©Ê¡A±N­I´º¦â¦h¥[¬¡
+  ¥Î¡A§A¤]¯à°µ¥X¥X¦âªºÃ±¦WÀÉ¡B­pµeÀÉ....µ¥¡C
+  ¦n°Õ¡I¤U½ÒÅo¡I¶}©l°µ¨Ç¸ÕÅç§a¡I¬Ý¬Ý¦³­þ¸ÌÁÙ¤£À´ªº¡A¦A§i¶D§Ú¡I^_^
+ <<<<<<<<<<<<<<<<<<<<<<<<<<<<< $ E N D $ >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
diff --git a/sample/innd/Makefile b/sample/innd/Makefile
new file mode 100644
index 00000000..853ba0db
--- /dev/null
+++ b/sample/innd/Makefile
@@ -0,0 +1,9 @@
+BBSHOME?=$(HOME)
+TARGET=$(BBSHOME)/innd/
+FILES=bbsname.bbs newsfeeds.bbs nodelist.bbs ntu.active
+
+all:
+
+install:
+ install -d $(TARGET)
+ install -c -m 644 $(FILES) $(TARGET)
diff --git a/sample/innd/bbsname.bbs b/sample/innd/bbsname.bbs
new file mode 100644
index 00000000..72db534d
--- /dev/null
+++ b/sample/innd/bbsname.bbs
@@ -0,0 +1 @@
+ptt2
diff --git a/sample/innd/newsfeeds.bbs b/sample/innd/newsfeeds.bbs
new file mode 100644
index 00000000..c32b8042
--- /dev/null
+++ b/sample/innd/newsfeeds.bbs
@@ -0,0 +1,3 @@
+# newsgroups board news server
+#------------------------------------- -------------- -----------
+#tw.bbs.test test ntu
diff --git a/sample/innd/nodelist.bbs b/sample/innd/nodelist.bbs
new file mode 100644
index 00000000..d5784970
--- /dev/null
+++ b/sample/innd/nodelist.bbs
@@ -0,0 +1,4 @@
+# name hostname & domainname full name
+#------- ---------------------------------- ------------
+#ptt2 ptt2.csie.ntu.edu.tw IHAVE(7777) Ptt2
+#ntu news.ntu.edu.tw POST(119) NTU News Server
diff --git a/sample/innd/ntu.active b/sample/innd/ntu.active
new file mode 100644
index 00000000..3825d9ea
--- /dev/null
+++ b/sample/innd/ntu.active
@@ -0,0 +1 @@
+tw.bbs.chat 0000000000 0000000000 y
diff --git a/sample/pttbbs.conf b/sample/pttbbs.conf
new file mode 100644
index 00000000..343c0299
--- /dev/null
+++ b/sample/pttbbs.conf
@@ -0,0 +1,10 @@
+/* ©w¸q BBS ¯¸¦W¦ì§} */
+
+#define BBSNAME "·s§å½ð½ð" /* ¤¤¤å¯¸¦W */
+#define MYHOSTNAME "ptt2.twbbs.org.tw" /* ºô¸ô¦ì§} */
+#define MYIP "140.112.8.192" /* IP¦ì§} */
+#define BBSUSER "bbs"
+#define BBSUID 9999
+#define BBSGID 99
+
+#define MAX_USERS 10000
diff --git a/sample/rc.local b/sample/rc.local
new file mode 100644
index 00000000..8fd6c714
--- /dev/null
+++ b/sample/rc.local
@@ -0,0 +1,4 @@
+#!/bin/sh
+/usr/bin/su bbsadm -c /home/bbs/bin/uhash_loader
+/usr/bin/su bbsadm -c /home/bbs/bin/outmail&
+/usr/bin/su bbsadm -c /home/bbs/innd/innbbsd 7777
diff --git a/util/.cvsignore b/util/.cvsignore
new file mode 100644
index 00000000..e7408563
--- /dev/null
+++ b/util/.cvsignore
@@ -0,0 +1,42 @@
+bbsmail
+BM_money
+post
+account
+birth
+deluserfile
+expire
+mandex
+horoscope
+openvice
+parse_news
+openticket
+bmda
+uhash_loader
+poststat
+showboard
+topusr
+yearsold
+cutpasswd
+inndBM
+antispam
+countalldice
+webgrep
+bbsrf
+initbbs
+outmail
+xchatd
+userlist
+tunepasswd
+buildir
+reaper
+shmsweep
+merge_passwd
+merge_board
+cpdeadbrd
+rmuid
+buildAnnounce
+toplazyBBM
+toplazyBM
+jungo
+bbsctl
+daymandex
diff --git a/util/BM_money.c b/util/BM_money.c
new file mode 100644
index 00000000..51e24c38
--- /dev/null
+++ b/util/BM_money.c
@@ -0,0 +1,117 @@
+/* $Id: BM_money.c,v 1.1 2002/03/07 15:13:45 in2 Exp $ */
+
+/* µ¹ª©¥D¿úªºµ{¦¡ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+#include "common.h"
+
+#define FUNCTION (2100 - c*5)
+
+extern int numboards;
+extern boardheader_t *bcache;
+extern struct UCACHE *uidshm;
+
+int c, n;
+extern userec_t xuser;
+
+
+
+int Link(char *src, char *dst) {
+ char cmd[200];
+
+ if (link(src, dst) == 0)
+ return 0;
+
+ sprintf(cmd, "/bin/cp -R %s %s", src, dst);
+ return system(cmd);
+}
+
+
+int main() {
+ FILE *fp = fopen(BBSHOME "/etc/topboardman", "r");
+ char buf[201], bname[20], BM[90], *ch;
+ boardheader_t *bptr = NULL;
+ int nBM;
+
+ resolve_boards();
+ if(passwd_mmap())
+ exit(1);
+ if (!fp)
+ return 0;
+
+ c = 0;
+ fgets(buf, 200, fp); /* ²Ä¤@¦æ®³±¼ */
+
+ printf(
+ " \033[1;44m ¼úÀyÀu¨}ª©¥D ¨C¶gªáÁ~ ¨ÌºëµØ°Ï±Æ¦W¤À°t \033[m\n\n"
+ "\033[33m (±Æ¦W¤Ó«á­±©Î´X¥G¨S¦³ºëµØ°ÏªÌ¤£¦C¤J)\033[m\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¢w\n"
+ "\n\n");
+
+ while (fgets(buf, 200, fp) != NULL)
+ {
+ buf[24] = 0;
+ sscanf(&buf[9], "%s", bname);
+ for (n = 0; n < numboards; n++)
+ {
+ bptr = &bcache[n];
+ if (!strcmp(bptr->brdname, bname))
+ break;
+ }
+ if (n == numboards)
+ continue;
+ strcpy(BM, bptr->BM);
+ printf(" (%d) %-15.15s %s \n", c + 1, bptr->brdname, bptr->title);
+
+ if (BM[0] == 0 || BM[0] == ' ')
+ continue;
+
+ ch = BM;
+ for (nBM = 1; (ch = strchr(ch, '/')) != NULL; nBM++)
+ {
+ ch++;
+ };
+ ch = BM;
+
+ if (FUNCTION <= 0)
+ break;
+
+ printf(" ¼úª÷ \033[32m%6d \033[m ¤Àµ¹ \033[33m%s\033[m \n",
+ FUNCTION, bptr->BM);
+
+ for (n = 0; n < nBM; n++)
+ {
+ fileheader_t mymail;
+ char *ch1,uid ;
+ if((ch1 = strchr(ch, '/')))
+ *ch1 = 0;
+ if ((uid=getuser(ch))!=0)
+ {
+
+ char genbuf[200];
+ deumoney(uid,FUNCTION / nBM);
+ sprintf(genbuf, BBSHOME "/home/%c/%s", ch[0], ch);
+ stampfile(genbuf, &mymail);
+
+ strcpy(mymail.owner, "[Á~¤ô³U]");
+ sprintf(mymail.title,
+ "\033[32m %s \033[mª©ªºÁ~¤ô ¢C\033[33m%d\033![m", bptr->brdname, FUNCTION / nBM);
+ mymail.savemode = 0;
+ unlink(genbuf);
+ Link(BBSHOME "/etc/BM_money", genbuf);
+ sprintf(genbuf, BBSHOME "/home/%c/%s/.DIR", ch[0], ch);
+ append_record(genbuf, &mymail, sizeof(mymail));
+ }
+ ch = ch1 + 1;
+ }
+ c++;
+ }
+ return 0;
+}
diff --git a/util/BM_money.sh b/util/BM_money.sh
new file mode 100644
index 00000000..8bef4fc9
--- /dev/null
+++ b/util/BM_money.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# $Id: BM_money.sh,v 1.1 2002/03/07 15:13:45 in2 Exp $
+
+bin/BM_money > etc/BM_money
+bin/post Record ¬P´Á¤­' 'ª©¥DµoÁ~¤é [°]ª÷®ø®§] etc/BM_money
diff --git a/util/BOARDS.bid b/util/BOARDS.bid
new file mode 100644
index 00000000..8d0312e5
--- /dev/null
+++ b/util/BOARDS.bid
Binary files differ
diff --git a/util/DEADJOE b/util/DEADJOE
new file mode 100644
index 00000000..a0793f05
--- /dev/null
+++ b/util/DEADJOE
@@ -0,0 +1,9 @@
+
+*** Modified files in JOE when it aborted on Thu Nov 22 19:30:21 2001
+*** JOE was aborted by signal 1
+
+*** Modified files in JOE when it aborted on Mon Nov 26 09:50:15 2001
+*** JOE was aborted because the terminal closed
+
+*** File '(Unnamed)'
+BBSNAME
diff --git a/util/LocalVars.pm.sample b/util/LocalVars.pm.sample
new file mode 100644
index 00000000..67157009
--- /dev/null
+++ b/util/LocalVars.pm.sample
@@ -0,0 +1,22 @@
+#!/usr/bin/perl
+package LocalVars;
+require Exporter;
+@ISA = qw/Exporter/;
+@EXPORT = qw/
+ $hostname $FQDN $SMTPSERVER
+ $BBSHOME $JOBSPOOL $TMP
+ $TAR/;
+
+# host
+$hostname = 'ptt';
+$FQDN = 'ptt.csie.ntu.edu.tw';
+$SMTPSERVER = 'ptt2.csie.ntu.edu.tw';
+
+# dir
+$BBSHOME = '/home/bbs';
+$JOBSPOOL = "$BBSHOME/jobspool";
+$TMP = '/tmp';
+
+# program
+$TAR = '/bin/tar';
+
diff --git a/util/Makefile b/util/Makefile
new file mode 100644
index 00000000..eeacad38
--- /dev/null
+++ b/util/Makefile
@@ -0,0 +1,167 @@
+# $Id: Makefile,v 1.1 2002/03/07 15:13:45 in2 Exp $
+
+BBSHOME?=$(HOME)
+OSTYPE=linux
+
+# FreeBSD
+CC_FreeBSD= gcc
+CFLAGS_FreeBSD= -pipe -Wall -g -O3 -DHAVE_SETPROCTITLE -DBBSHOME='"$(BBSHOME)"' -I../include
+LIBS_FreeBSD=
+LIBMAIL_FreeBSD=-lutil
+LIBCHAT_FreeBSD=
+
+# Linux
+CC_linux= gcc
+CFLAGS_linux= -pipe -Wall -g -O3 -DHAVE_DES_CRYPT -DBBSHOME='"$(BBSHOME)"' -I../include
+LIBS_linux= -lresolv
+LIBMAIL_linux=
+LIBCHAT_linux= -lcrypt
+
+CC= $(CC_$(OSTYPE))
+CFLAGS= $(CFLAGS_$(OSTYPE))
+LDFLAGS=$(LDFLAGS_$(OSTYPE))
+LIBMAIL=$(LIBMAIL_$(OSTYPE))
+LIBCHAT=$(LIBCHAT_$(OSTYPE))
+
+OBJS= util_cache.o util_record.o util_passwd.o
+
+CPROGS= bbsmail BM_money post account birth deluserfile expire mandex\
+ horoscope openvice parse_news openticket topusr yearsold uhash_loader\
+ poststat showboard antispam countalldice webgrep bbsrf\
+ initbbs outmail xchatd userlist tunepasswd buildir reaper shmsweep\
+ merge_passwd merge_board inndBM buildAnnounce rmuid cpdeadbrd \
+ toplazyBM jungo toplazyBBM daymandex
+
+PROGS= $(CPROGS) BM_money.sh backpasswd.sh mailog.sh opendice.sh\
+ openticket.sh stock.sh topsong.sh weather.sh stock.perl weather.perl\
+ toplazyBM.sh toplazyBBM.sh dailybackup.pl tarqueue.pl waterball.pl
+
+all: $(PROGS)
+
+bbsmail: bbsmail.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+BM_money: BM_money.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+post: post.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+jungo: jungo.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+account: account.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+birth: birth.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+deluserfile: deluserfile.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+expire: expire.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+mandex: mandex.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+daymandex: daymandex.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+rmuid: rmuid.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+cpdeadbrd: cpdeadbrd.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+horoscope: horoscope.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+openvice: openvice.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+parse_news: parse_news.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+openticket: openticket.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+topusr: topusr.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+yearsold: yearsold.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+xchatd: xchatd.c $(OBJS) descrypt.c
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS) descrypt.c $(LIBCHAT)
+
+toplazyBM: toplazyBM.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+toplazyBBM: toplazyBBM.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+smtest: smtest.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+reaper: reaper.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+buildAnnounce: buildAnnounce.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+inndBM: inndBM.c $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.c $(OBJS)
+
+shmsweep: shmsweep.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+uhash_loader: uhash_loader.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+showboard: showboard.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+antispam: antispam.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+countalldice: countalldice.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+webgrep: webgrep.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+bbsrf: bbsrf.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+initbbs: initbbs.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+outmail: outmail.c
+ $(CC) $(CFLAGS) -o $@ $@.c $(LIBMAIL)
+
+userlist: userlist.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+tunepasswd: tunepasswd.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+buildir: buildir.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+merge_passwd: merge_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+merge_board : merge_board.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+bbsctl: bbsctl.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+install: $(PROGS)
+ install -d $(BBSHOME)/bin/
+ install -c -m 755 $(PROGS) $(BBSHOME)/bin/
+ chmod 4755 $(BBSHOME)/bin/post
+
+clean:
+ rm -f *.o $(CPROGS)
diff --git a/util/Makefile.save b/util/Makefile.save
new file mode 100644
index 00000000..2d0651b1
--- /dev/null
+++ b/util/Makefile.save
@@ -0,0 +1,152 @@
+# $Id: Makefile.save,v 1.1 2002/03/07 15:13:45 in2 Exp $
+
+BBSHOME?=$(HOME)
+OSTYPE=linux
+
+# FreeBSD
+CC_FreeBSD= gcc
+CFLAGS_FreeBSD= -pipe -Wall -g -O3 -DHAVE_SETPROCTITLE -DBBSHOME='"$(BBSHOME)"' -I../include
+LIBS_FreeBSD=
+LIBMAIL_FreeBSD=-lutil
+LIBCHAT_FreeBSD=
+
+# Linux
+CC_linux= gcc
+CFLAGS_linux= -pipe -Wall -g -O3 -DHAVE_DES_CRYPT -DBBSHOME='"$(BBSHOME)"' -I../include
+LIBS_linux= -lresolv
+LIBMAIL_linux=
+LIBCHAT_linux= -lcrypt
+
+CC= $(CC_$(OSTYPE))
+CFLAGS= $(CFLAGS_$(OSTYPE))
+LDFLAGS=$(LDFLAGS_$(OSTYPE))
+LIBMAIL=$(LIBMAIL_$(OSTYPE))
+LIBCHAT=$(LIBCHAT_$(OSTYPE))
+
+CPROGS= bbsmail BM_money post account birth deluserfile expire mandex\
+ horoscope openvice parse_news openticket topusr yearsold uhash_loader\
+ poststat showboard antispam countalldice webgrep bbsrf\
+ initbbs outmail xchatd userlist tunepasswd buildir reaper shmsweep\
+ merge_passwd merge_board inndBM buildAnnounce cpdeadbrd toplazyBM\
+ jungo
+PROGS= $(CPROGS) BM_money.sh backpasswd.sh mailog.sh opendice.sh\
+ openticket.sh stock.sh topsong.sh weather.sh stock.perl weather.perl\
+ cvslog.sh toplazyBM.sh
+
+all: $(PROGS)
+
+bbsmail: bbsmail.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+BM_money: BM_money.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+post: post.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+account: account.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+birth: birth.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+deluserfile: deluserfile.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+expire: expire.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+mandex: mandex.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+cpdeadbrd: cpdeadbrd.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+horoscope: horoscope.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+openvice: openvice.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+parse_news: parse_news.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+openticket: openticket.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+topusr: topusr.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+yearsold: yearsold.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+xchatd: xchatd.c util_cache.c util_record.c util_passwd.c descrypt.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c descrypt.c $(LIBCHAT)
+
+toplazyBM: toplazyBM.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+jungo: jungo.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+smtest: smtest.c util_cache.c util_record.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_cache.c util_record.c util_passwd.c
+
+reaper: reaper.c util_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_passwd.c util_cache.c util_passwd.c
+
+buildAnnounce: buildAnnounce.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_record.c util_cache.c util_passwd.c
+
+inndBM: inndBM.c
+ $(CC) $(CFLAGS) -o $@ $@.c util_record.c util_cache.c util_passwd.c
+
+shmsweep: shmsweep.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+uhash_loader: uhash_loader.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+showboard: showboard.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+antispam: antispam.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+countalldice: countalldice.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+webgrep: webgrep.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+bbsrf: bbsrf.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+initbbs: initbbs.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+outmail: outmail.c
+ $(CC) $(CFLAGS) -o $@ $@.c $(LIBMAIL)
+
+userlist: userlist.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+tunepasswd: tunepasswd.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+buildir: buildir.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+merge_passwd: merge_passwd.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+merge_board : merge_board.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+install: $(PROGS)
+ install -d $(BBSHOME)/bin/
+ install -c -m 755 $(PROGS) $(BBSHOME)/bin/
+ chmod 4755 $(BBSHOME)/bin/post
+
+clean:
+ rm -f $(CPROGS)
diff --git a/util/a.out b/util/a.out
new file mode 100644
index 00000000..f4032dc4
--- /dev/null
+++ b/util/a.out
Binary files differ
diff --git a/util/account.c b/util/account.c
new file mode 100644
index 00000000..e4166092
--- /dev/null
+++ b/util/account.c
@@ -0,0 +1,414 @@
+/* $Id: account.c,v 1.1 2002/03/07 15:13:45 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+
+#define MAX_LINE 16
+#define ADJUST_M 6 /* adjust back 5 minutes */
+
+extern struct pttcache_t *ptt;
+
+void
+ reset_garbage()
+{
+ if (ptt == NULL)
+ {
+ ptt = attach_shm(PTTSHM_KEY, sizeof(*ptt));
+ if (ptt->touchtime == 0)
+ ptt->touchtime = 1;
+ }
+
+/* ¤£¾ã­Óreload?
+ for(n=0;n<=ptt->max_film;n++)
+ printf("\n**%d**\n %s \n",n,ptt->notes[n]);
+ */
+ ptt->uptime = 0;
+ reload_pttcache();
+
+ printf("\n°ÊºA¬ÝªO¼Æ[%d]\n", ptt->max_film);
+/*
+ for(n=0; n<MAX_MOVIE_SECTION; n++)
+ printf("sec%d=> °_ÂI:%d ¤U¦¸­n´«ªº:%d\n ",n,ptt->n_notes[n],
+ ptt->next_refresh[n]);
+ printf("\n");
+*/
+}
+
+void
+keeplog(fpath, board, title)
+ char *fpath;
+ char *board;
+ char *title;
+{
+ fileheader_t fhdr;
+ int bid;
+ char genbuf[256], buf[256];
+
+ if (!board)
+ board = "Record";
+
+
+ sprintf(genbuf, "boards/%s", board);
+ stampfile(genbuf, &fhdr);
+ sprintf(buf, "mv %s %s", fpath, genbuf);
+ system(buf);
+/*
+ printf("keep record:[%s][%s][%s][%s]\n",fpath, board, title,genbuf);
+*/
+ strcpy(fhdr.title, title);
+ strcpy(fhdr.owner, "[¾ú¥v¦Ñ®v]");
+ sprintf(genbuf, "boards/%s/.DIR", board);
+ append_record(genbuf, &fhdr, sizeof(fhdr));
+ if((bid = getbnum(board)) > 0)touchbtotal(bid);
+
+}
+
+
+static void
+my_outs(fp, buf, mode)
+ FILE *fp;
+ char buf[], mode;
+{
+ static char state = '0';
+
+ if (state != mode)
+ fprintf(fp, "[3%cm", state = mode);
+ if (buf[0])
+ {
+ fprintf(fp, buf);
+ buf[0] = 0;
+ }
+}
+
+
+void gzip(source, target, stamp)
+ char *source, *target, *stamp;
+{
+ char buf[128];
+ sprintf(buf, "gzip -f9n adm/%s%s", target, stamp);
+ rename(source, &buf[14]);
+ system(buf);
+}
+
+extern struct fromcache_t *fcache;
+extern uhash_t *uhash;
+
+int main() {
+ int hour, max, item, total, i, j, mo, da, max_user = 0, max_login = 0,
+ max_reg = 0, mahour = 0, k;
+ char *act_file = ".act";
+ char *log_file = "usies";
+ char buf[256], buf1[256], *p;
+ FILE *fp, *fp1;
+ int act[27]; /* ¦¸¼Æ/²Ö­p®É¶¡/pointer */
+ time_t now;
+ struct tm *ptime;
+
+ now = time(NULL) - ADJUST_M * 60; /* back to ancent */
+ ptime = localtime(&now);
+
+ memset(act, 0, sizeof(act));
+ printf("¦¸¼Æ/²Ö­p®É¶¡\n");
+ if ((ptime->tm_hour != 0) && (fp = fopen(act_file, "r")))
+ {
+ fread(act, sizeof(act), 1, fp);
+ fclose(fp);
+ }
+ if ((fp = fopen(log_file, "r")) == NULL)
+ {
+ printf("cann't open usies\n");
+ return 1;
+ }
+ if (act[26])
+ fseek(fp, act[26], 0);
+ while (fgets(buf, 256, fp))
+ {
+ buf[11+2]=0;
+ hour = atoi(buf + 11);
+ if (hour < 0 || hour > 23)
+ {
+ continue;
+ }
+//"09/06/1999 17:44:58 Mon "
+// 012345678901234567890123
+ if (strstr(buf + 20, "ENTER"))
+ {
+ act[hour]++;
+ continue;
+ }
+ if ((p = (char *) strstr(buf + 40, "Stay:")))
+ {
+ if((hour = atoi(p + 5))) {
+ act[24] += hour;
+ act[25]++;
+ }
+ continue;
+ }
+ }
+ act[26] = ftell(fp);
+ fclose(fp);
+ for (i = max = total = 0; i < 24; i++)
+ {
+ total += act[i];
+ if (act[i] > max)
+ {
+ max_user = max = act[i];
+ mahour = i;
+ }
+ }
+ item = max / MAX_LINE + 1;
+
+ if (!ptime->tm_hour)
+ {
+ keeplog("etc/today", "Record", "¤W¯¸¤H¦¸²Î­p");
+ keeplog("etc/money", "Security", "¥»¤éª÷¿ú©¹¨Ó°O¿ý");
+ keeplog("etc/illegal_money", "Security", "¥»¤é¹HªkÁÈ¿ú°O¿ý");
+ keeplog("etc/chicken", "Record", "Âû³õ³ø§i");
+ }
+
+ printf("¤W¯¸¤H¦¸²Î­p\n");
+ if ((fp = fopen("etc/today", "w")) == NULL)
+ {
+ printf("cann't open etc/today\n");
+ return 1;
+ }
+ fprintf(fp, "\t\t\t ¨C¤p®É¤W¯¸¤H¦¸²Î­p [%02d/%02d/%02d] \n\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))
+ {
+ my_outs(fp, buf, '3');
+ fprintf(fp, "%-3d", hour / 10);
+ }
+ else if (max <= hour)
+ {
+ my_outs(fp, buf, '4');
+ fprintf(fp, "¢i ");
+ }
+ else
+ strcat(buf, " ");
+ }
+ fprintf(fp, "\n");
+ }
+ fprintf(fp, " "
+ "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 ³æ¦ì: 10 ¤H");
+ fprintf(fp, " Á`¦@¤W¯¸¤H¦¸¡G%-7d¥­§¡¨Ï¥Î¤H¼Æ¡G%d\n", total, total / 24);
+ fclose(fp);
+
+ if((fp = fopen(act_file, "w"))) {
+ fwrite(act, sizeof(act), 1, fp);
+ fclose(fp);
+ }
+
+/* -------------------------------------------------------------- */
+
+ sprintf(buf, "-%02d%02d%02d",
+ ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday);
+
+ now += ADJUST_M * 60; /* back to future */
+
+
+ printf("¾ú¥v¨Æ¥ó³B²z\n");
+/* Ptt ¾ú¥v¨Æ¥ó³B²z */
+ if((fp = fopen("etc/history.data", "r"))) { /*³Ì¦h¦P®É¤W½u */
+ if (fscanf(fp, "%d %d %d %d", &max_login, &max, &max_reg, &k))
+ {
+ int a;
+ resolve_fcache();
+ printf("¦¹®É¬q³Ì¦h¦P®É¤W½u:%d ¹L¥h:%d\n", a = fcache->max_user, k);
+ fclose(fp);
+ if (a > k)
+ {
+ ptime = localtime(&fcache->max_time);
+ if((fp1 = fopen("etc/history", "a")))
+ {
+ fprintf(fp1,
+ "¡· ¡i%02d/%02d/%02d %02d:%02d¡j"
+ "¦P®É¦b§{¤º¤H¼Æ­º¦¸¹F¨ì %d ¤H¦¸\n",
+ ptime->tm_mon + 1, ptime->tm_mday, ptime->tm_year % 100,
+ ptime->tm_hour, ptime->tm_min, a);
+ fclose(fp1);
+ }
+ if((fp = fopen("etc/history.data", "w")))
+ {
+ fprintf(fp, "%d %d %d %d", max_login, max, max_reg, a);
+ fclose(fp);
+ }
+ }
+ }
+ else
+ fclose(fp);
+ }
+ ptime = localtime(&now);
+
+ if (ptime->tm_hour)
+ {
+ /* rotate one line in today_is */
+ puts("¦h­Ó¸`¤é³B²z");
+ if((fp1 = fopen("etc/today_is", "r"))) {
+ char tod[100][20];
+
+ i = 0;
+ while(i < 100 && fgets(tod[i], sizeof(tod[0]), fp1))
+ i++;
+ fclose(fp1);
+
+ fp1 = fopen("etc/today_is", "w");
+ for(j = 0; j < i; j++)
+ fputs(tod[j + 1 < i ? j + 1 : 0], fp1);
+ fclose(fp1);
+ }
+ }
+
+
+ if (!ptime->tm_hour)
+ {
+ keeplog(".note", "Record", "¤ß±¡¯d¨¥ª©");
+ system("/bin/cp etc/today etc/yesterday");
+/* system("rm -f note.dat"); */
+/* Ptt */
+ sprintf(buf1, "[¤½¦w³ø§i] ¨Ï¥ÎªÌ¤W½uºÊ±± [%02d/%02d:%02d]"
+ ,ptime->tm_mon + 1, ptime->tm_mday, ptime->tm_hour);
+ keeplog("usies", "Security", buf1);
+ printf("[¤½¦w³ø§i] ¨Ï¥ÎªÌ¤W½uºÊ±±\n");
+ gzip(log_file, "usies", buf);
+ printf("À£ÁY¨Ï¥ÎªÌ¤W½uºÊ±±\n");
+/* Ptt ¾ú¥v¨Æ¥ó³B²z */
+ now = time(NULL) - ADJUST_M * 60; /* back to ancent */
+ ptime = localtime(&now);
+
+ attach_uhash();
+ if((fp = fopen("etc/history.data", "r")))
+ { /* ³æ¤é³Ì¦h¦¸¤H¦¸,¦P®É¤W½u,µù¥U */
+ if (fscanf(fp, "%d %d %d %d", &max_login, &max, &max_reg, &k))
+ {
+ fp1 = fopen("etc/history", "r+");
+ fseek(fp1, 0, 2);
+ if (max_user > max)
+ {
+ fprintf(fp1, "¡º ¡i%02d/%02d/%02d %02d¡j "
+ "³æ¤@¤p®É¤W½u¤H¦¸­º¦¸¹F¨ì %d ¤H¦¸ \n"
+ ,ptime->tm_mon + 1, ptime->tm_mday, ptime->tm_year % 100, mahour, max_user);
+ max = max_user;
+ }
+ if (total > max_login)
+ {
+ fprintf(fp1, "¡» ¡i%02d/%02d/%02d¡j "
+ "³æ¤é¤W½u¤H¦¸­º¦¸¹F¨ì %d ¤H¦¸ \n"
+ ,ptime->tm_mon + 1, ptime->tm_mday, ptime->tm_year % 100, total);
+ max_login = total;
+ }
+
+ if (uhash->number > max_reg + max_reg / 10)
+ {
+ fprintf(fp1, "¡¹ ¡i%02d/%02d/%02d¡j "
+ "Á`µù¥U¤H¼Æ´£¤É¨ì %d ¤H \n"
+ ,ptime->tm_mon + 1, ptime->tm_mday, ptime->tm_year % 100, uhash->number);
+ max_reg = uhash->number;
+ }
+
+ fclose(fp1);
+ }
+ fclose(fp);
+ fp = fopen("etc/history.data", "w");
+ fprintf(fp, "%d %d %d %d", max_login, max, max_reg, k);
+ fclose(fp);
+ }
+ now += ADJUST_M * 60; /* back to future */
+ ptime = localtime(&now);
+
+ /* Ptt ¸`¤é³B²z */
+ printf("¸`¤é³B²z\n");
+ if((fp1 = fopen("etc/today_is", "w"))) {
+ i = 0;
+ if((fp = fopen("etc/feast", "r"))) {
+ while(fgets(buf1, sizeof(buf1), fp)) {
+ if(buf[0] != '#' &&
+ sscanf(buf1, "%d %d ", &mo, &da) == 2) {
+ if(ptime->tm_mday == da && ptime->tm_mon + 1 == mo) {
+ i = 1;
+ fprintf(fp1, "%-14.14s", &buf1[6]);
+ }
+ }
+ }
+ fclose(fp);
+ }
+ printf("¸`¤é³B²z1\n");
+ if(i == 0) {
+ if((fp = fopen("etc/today_boring", "r"))) {
+ while(fgets(buf1, sizeof(buf1), fp))
+ if(strlen(buf) > 3)
+ fprintf(fp1, "%s", buf1);
+ fclose(fp);
+ } else
+ fprintf(fp1, "¥»¤é¸`¤é¼x¨D¤¤");
+ }
+ fclose(fp1);
+ }
+
+ /* Ptt Åwªïµe­±³B²z */
+ printf("Åwªïµe­±³B²z\n");
+
+ if((fp = fopen("etc/Welcome.date", "r")))
+ {
+ char temp[50];
+ while (fscanf(fp, "%d %d %s\n", &mo, &da, buf1) != EOF)
+ {
+ if (ptime->tm_mday == da && ptime->tm_mon + 1 == mo)
+ {
+ strcpy(temp, buf1);
+ sprintf(buf1, "cp -f etc/Welcomes/%s etc/Welcome", temp);
+ system(buf1);
+ break;
+ }
+ }
+ fclose(fp);
+ }
+ printf("Åwªïµe­±³B²z\n");
+ if (ptime->tm_wday == 0)
+ {
+ keeplog("etc/week", "Record", "¥»¶g¼öªù¸ÜÃD");
+
+ gzip("bbslog", "bntplink", buf);
+ gzip("innd/bbslog", "innbbsd", buf);
+ gzip("etc/mailog", "mailog", buf);
+ }
+
+ if (ptime->tm_mday == 1)
+ keeplog("etc/month", "Record", "¥»¤ë¼öªù¸ÜÃD");
+
+ if (ptime->tm_yday == 1)
+ keeplog("etc/year", "Record", "¦~«×¼öªù¸ÜÃD");
+ }
+ else if (ptime->tm_hour == 3 && ptime->tm_wday == 6)
+ {
+ char *fn1 = "tmp";
+ char *fn2 = "suicide";
+ rename(fn1, fn2);
+ mkdir(fn1, 0755);
+ sprintf(buf, "tar cfz adm/%s-%02d%02d%02d.tgz %s",
+ fn2, ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday, fn2);
+ system(buf);
+ sprintf(buf, "/bin/rm -fr %s", fn2);
+ system(buf);
+ }
+/* Ptt reset Ptt's share memory */
+ printf("­«³]Pttcache »Pfcache\n");
+
+ fcache->uptime = 0;
+ resolve_fcache();
+ reset_garbage();
+ return 0;
+}
diff --git a/util/antispam.c b/util/antispam.c
new file mode 100644
index 00000000..f7b77569
--- /dev/null
+++ b/util/antispam.c
@@ -0,0 +1,122 @@
+/* $Id: antispam.c,v 1.1 2002/03/07 15:13:45 in2 Exp $ */
+/* §ì¼s§i«Hªºµ{¦¡ */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "config.h"
+
+#define WINDOW 100 /* ¤@¦¸window¦h¤Ö­Óserver */
+#define LEVEL 21 /* ­Y´X¦¸­«´_´Nºâ¼s§i«H */
+
+#define mailog BBSHOME "/etc/mailog"
+#define spamlog BBSHOME "/etc/spam"
+
+typedef struct sendinfo
+{
+ char time[18];
+ char from[50];
+ char userid[20];
+ int count;
+}
+sendinfo;
+
+int
+ main()
+{
+ char buf[200], *from, *userid;
+ int num = -1, numb = -1, n, nb;
+ FILE *fp = fopen(mailog, "r"), *fo;
+ sendinfo data[WINDOW];
+ sendinfo bad[WINDOW];
+
+ unlink(spamlog);
+ fo = fopen(spamlog, "a");
+ memset(data, 0, sizeof(data));
+ memset(bad, 0, sizeof(bad));
+
+ if (!fp || !fo)
+ return 0;
+
+ while (fgets(buf, 200, fp))
+ {
+ strtok(buf, "\r\n");
+ from = strchr(buf, '>') + 2;
+ userid = strstr(buf, " =>");
+
+ if (!from || !userid)
+ continue;
+
+ *userid = 0;
+ userid += 4;
+
+ if (strstr(from, "MAILER-DAEMON")
+ || strstr(from, userid))
+ continue; /* °h«H³qª¾¤£ºÞ */
+ /* ¬O§_¤w¬Obadhost */
+
+ for (nb = 0; nb < WINDOW && bad[nb].from[0]; nb++)
+ if (!strcmp(bad[nb].from, from))
+ break;
+
+ if (nb < WINDOW && bad[nb].from[0])
+ {
+ bad[nb].count++;
+ continue;
+ }
+
+ /* ²¬d¹L¥h°O¿ý */
+
+ for (n = 0; n < WINDOW && data[n].from[0]; n++)
+ if (!strcmp(data[n].from, from))
+ break;
+
+ if (n < WINDOW && data[n].from[0])
+ {
+ if (!strncmp(data[n].userid, userid, 20))
+ continue;
+ /* Â൹¦P¤@­Ó¤H´N¤£ºÞ */
+ strncpy(data[n].userid, userid, 20);
+ if (++data[n].count >= LEVEL)
+ {
+ /* Åܦ¨bad ²¾data¨ìbad ªÅ¯Ê¥Ñ«á¤@µ§¸ê®Æ¸É¤W */
+ if (nb >= WINDOW)
+ {
+ numb = (numb + 1) % WINDOW;
+ nb = numb;
+ fprintf(fo, "%s %s ­«ÂбH %d ¦¸\n",
+ bad[nb].time, bad[nb].from, bad[nb].count);
+/* printf(" %s send %d times\n",
+ bad[nb].from, bad[nb].count); */
+ }
+ memcpy(&bad[nb], &data[n], sizeof(sendinfo));
+ memcpy(&data[n], &data[n + 1], sizeof(sendinfo) * (WINDOW - n - 1));
+ if (num > n)
+ num--;
+ }
+ }
+ else
+ {
+ if (n >= WINDOW)
+ {
+ num = (num + 1) % WINDOW;
+ n = num;
+ }
+/* printf("[%s] to [%s]\n", from, userid); */
+ buf[17] = 0;
+ strncpy(data[n].time, buf, 17);
+ strncpy(data[n].from, from, 50);
+ strncpy(data[n].userid, userid, 20);
+ }
+ }
+
+ for (nb = 0; nb < WINDOW && bad[nb].from[0]; nb++)
+ {
+ fprintf(fo, "%s %s ­«ÂбH %d ¦¸\n", bad[nb].time,
+ bad[nb].from, bad[nb].count);
+/* printf(" %s send %d times\n", bad[nb].from, bad[nb].count); */
+ }
+ fclose(fp);
+ fclose(fo);
+ return 0;
+}
diff --git a/util/backpasswd.sh b/util/backpasswd.sh
new file mode 100644
index 00000000..5ec11abd
--- /dev/null
+++ b/util/backpasswd.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+# $Id: backpasswd.sh,v 1.1 2002/03/07 15:13:45 in2 Exp $
+
+mv PASSWDS.NEW5 PASSWDS.NEW6
+mv PASSWDS.NEW4 PASSWDS.NEW5
+mv PASSWDS.NEW3 PASSWDS.NEW4
+mv PASSWDS.NEW2 PASSWDS.NEW3
+mv PASSWDS.NEW1 PASSWDS.NEW2
+mv PASSWDS.NEW PASSWDS.NEW1
+cp .PASSWDS PASSWDS.NEW
+
diff --git a/util/bbsctl.c b/util/bbsctl.c
new file mode 100644
index 00000000..bf66df35
--- /dev/null
+++ b/util/bbsctl.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+void usage(void)
+{
+ printf("usage: bbsctl [start|stop|restart]\n");
+ exit(0);
+}
+
+void startbbs(void)
+{
+ if( setuid(0) < 0 ){
+ perror("setuid(0)");
+ exit(1);
+ }
+ puts("starting mbbsd: 23"); system("/home/bbs/bin/mbbsd 23");
+ puts("starting mbbsd:3000"); system("/home/bbs/bin/mbbsd 3000");
+ puts("starting mbbsd:3001"); system("/home/bbs/bin/mbbsd 3001");
+ puts("starting mbbsd:3002"); system("/home/bbs/bin/mbbsd 3002");
+ puts("starting mbbsd:3003"); system("/home/bbs/bin/mbbsd 3003");
+ puts("starting mbbsd:3004"); system("/home/bbs/bin/mbbsd 3004");
+ puts("starting mbbsd:3005"); system("/home/bbs/bin/mbbsd 3005");
+ puts("starting mbbsd:3006"); system("/home/bbs/bin/mbbsd 3006");
+ puts("starting mbbsd:3007"); system("/home/bbs/bin/mbbsd 3007");
+ puts("starting mbbsd:3008"); system("/home/bbs/bin/mbbsd 3008");
+ puts("starting mbbsd:3009"); system("/home/bbs/bin/mbbsd 3009");
+ puts("starting mbbsd:3010"); system("/home/bbs/bin/mbbsd 3010");
+}
+
+void stopbbs(void)
+{
+ char buf[1024];
+ int pid;
+ FILE *fp = popen("/bin/ps -ax | /usr/bin/grep mbbsd | "
+ "/usr/bin/grep listen", "r");
+ while( fgets(buf, sizeof(buf), fp) != NULL ){
+ sscanf(buf, "%d", &pid);
+ printf("stopping %d\n", pid);
+ kill(pid, 1);
+ }
+}
+
+void restartbbs(void)
+{
+ stopbbs();
+ startbbs();
+}
+
+int main(int argc, char **argv)
+{
+ if( argc == 1 )
+ usage();
+ if( strcmp(argv[1], "start") == 0 )
+ startbbs();
+ else if( strcmp(argv[1], "stop") == 0 )
+ stopbbs();
+ else if( strcmp(argv[1], "restart") == 0 )
+ restartbbs();
+ return 0;
+}
diff --git a/util/bbsmail.c b/util/bbsmail.c
new file mode 100644
index 00000000..48f74c63
--- /dev/null
+++ b/util/bbsmail.c
@@ -0,0 +1,239 @@
+/* $Id: bbsmail.c,v 1.1 2002/03/07 15:13:45 in2 Exp $ */
+
+#define _BBS_UTIL_C_
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+#include "perm.h"
+#include "common.h"
+
+#define LOG_FILE (BBSHOME "/etc/mailog")
+
+#ifdef HMM_USE_ANTI_SPAM
+extern char *notitle[], *nofrom[], *nocont[];
+#endif
+
+extern userec_t xuser;
+
+int mailalertuid(int tuid)
+{
+ userinfo_t *uentp=NULL;
+ if(tuid>0 && (uentp = (userinfo_t *)search_ulist(tuid)) )
+ uentp->mailalert=1;
+ return 0;
+}
+
+void
+mailog(msg)
+ char *msg;
+{
+ FILE *fp;
+
+ if ((fp = fopen(LOG_FILE, "a")))
+ {
+ time_t now;
+ struct tm *p;
+
+ time(&now);
+ p = localtime(&now);
+ fprintf(fp, "%02d/%02d/%02d %02d:%02d:%02d <bbsmail> %s\n",
+ p->tm_year % 100, p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec,
+ msg);
+ fclose(fp);
+ }
+}
+
+
+int
+mail2bbs(userid)
+ char *userid;
+{
+ int uid;
+ fileheader_t mymail;
+ char genbuf[256], title[80], sender[80], filename[80], *ip, *ptr;
+ time_t tmp_time;
+ struct stat st;
+ FILE *fout;
+/* check if the userid is in our bbs now */
+ if (!(uid=getuser(userid)) )
+ {
+ sprintf(genbuf, "BBS user <%s> not existed", userid);
+ puts(genbuf);
+ mailog(genbuf);
+ return -1;//EX_NOUSER;
+ }
+
+ if(xuser.userlevel&PERM_NOOUTMAIL)
+ return -1;
+
+ sprintf(filename, BBSHOME "/home/%c/%s", userid[0], userid);
+
+ if (stat(filename, &st) == -1)
+ {
+ if (mkdir(filename, 0755) == -1)
+ {
+ printf("mail box create error %s \n", filename);
+ return -1;
+ }
+ }
+ else if (!(st.st_mode & S_IFDIR))
+ {
+ printf("mail box error\n");
+ return -1;
+ }
+
+ // printf("dir: %s\n", filename);
+
+/* allocate a file for the new mail */
+
+ stampfile(filename, &mymail);
+ // printf("file: %s\n", filename);
+
+/* copy the stdin to the specified file */
+
+/* parse header */
+
+ while (fgets(genbuf, 255, stdin))
+ {
+ if (!strncmp(genbuf, "From", 4))
+ {
+ if ((ip = strchr(genbuf, '<')) && (ptr = strrchr(ip, '>')))
+ {
+ *ptr = '\0';
+ if (ip[-1] == ' ')
+ ip[-1] = '\0';
+ ptr = (char *) strchr(genbuf, ' ');
+ while (*ptr == ' ') ptr++;
+ sprintf(sender, "%s (%s)", ip + 1, ptr);
+ }
+ else
+ {
+ strtok(genbuf, " \t\n\r");
+ ptr= strtok(NULL, " \t\n\r");
+ if(ptr)
+ strcpy(sender, ptr);
+ }
+ continue;
+ }
+ if (!strncmp(genbuf, "Subject: ", 9))
+ {
+ strcpy(title, genbuf + 9);
+ continue;
+ }
+ if (genbuf[0] == '\n')
+ break;
+ }
+
+ if ((ptr = strchr(sender, '\n')))
+ *ptr = '\0';
+
+ if ((ptr = strchr(title, '\n')))
+ *ptr = '\0';
+
+ if (strchr(sender, '@') == NULL) /* ¥Ñ local host ±H«H */
+ {
+ strcat(sender, "@" MYHOSTNAME);
+ }
+
+ time(&tmp_time);
+
+#ifdef HMM_USE_ANTI_SPAM
+ for (n = 0; notitle[n]; n++)
+ if (strstr(title, notitle[n]))
+ {
+ sprintf(genbuf, "Title <%s> not accepted", title);
+ puts(genbuf);
+ mailog(genbuf);
+ return -1;
+ }
+ for (n = 0; nofrom[n]; n++)
+ if (strstr(sender, nofrom[n]))
+ {
+ sprintf(genbuf, "From <%s> not accepted", sender);
+ puts(genbuf);
+ mailog(genbuf);
+ return -1;
+ }
+#endif
+
+ if ((fout = fopen(filename, "w")) == NULL)
+ {
+ printf("Cannot open %s\n", filename);
+ return -1;
+ }
+
+ if (!title[0])
+ sprintf(title, "¨Ó¦Û %.64s", sender);
+ title[TTLEN] = 0;
+ fprintf(fout, "§@ªÌ: %s\n¼ÐÃD: %s\n®É¶¡: %s\n",
+ sender, title, ctime(&tmp_time));
+
+ while (fgets(genbuf, 255, stdin))
+ {
+#ifdef HMM_USE_ANTI_SPAM
+ for (n = 0; nocont[n]; n++)
+ if (strstr(genbuf, nocont[n]))
+ {
+ fclose(fout);
+ unlink(filename);
+ sprintf(genbuf, "Content <%s> not accepted", nocont[n]);
+ puts(genbuf);
+ mailog(genbuf);
+ return -1;
+ }
+#endif
+ fputs(genbuf, fout);
+ }
+ fclose(fout);
+
+ sprintf(genbuf, "%s => %s", sender, userid);
+ mailog(genbuf);
+
+/* append the record to the MAIL control file */
+
+ strcpy(mymail.title, title);
+
+ if (strtok(sender, " .@\t\n\r"))
+ strcat(sender, ".");
+ sender[IDLEN + 1] = '\0';
+ strcpy(mymail.owner, sender);
+
+ sprintf(genbuf, BBSHOME "/home/%c/%s/.DIR", userid[0], userid);
+ mailalertuid(uid);
+ return append_record(genbuf, &mymail, sizeof(mymail));
+}
+
+
+int
+main(int argc, char* argv[])
+{
+ char receiver[256];
+
+/* argv[1] is userid in bbs */
+
+ if (argc < 2)
+ {
+ printf("Usage:\t%s <bbs_uid>\n", argv[0]);
+ exit(-1);
+ }
+ (void) setgid(BBSGID);
+ (void) setuid(BBSUID);
+
+ if(passwd_mmap()) exit(-1);
+ strcpy(receiver, argv[1]);
+
+ strtok(receiver,".");
+ if (mail2bbs(receiver))
+ {
+ /* eat mail queue */
+ while (fgets(receiver, sizeof(receiver), stdin)) ;
+ }
+ return 0;
+}
diff --git a/util/bbsrf.c b/util/bbsrf.c
new file mode 100644
index 00000000..66f6cee0
--- /dev/null
+++ b/util/bbsrf.c
@@ -0,0 +1,148 @@
+/* $Id: bbsrf.c,v 1.1 2002/03/07 15:13:45 in2 Exp $ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <utmp.h>
+#include <pwd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include "config.h"
+
+/* fill the hid with from hostname */
+void gethid(char *hid, char *tty)
+{
+ int fd;
+ char *tp;
+ struct utmp data;
+
+ gethostname(hid, MAXHOSTNAMELEN);
+ hid[MAXHOSTNAMELEN] = '\0';
+ tp = strrchr(tty, '/') + 1;
+ if (tp && strlen(tp) == 5)
+ {
+ fd = open(_PATH_UTMP, O_RDONLY);
+ if (fd < 0)
+ syslog(LOG_ERR, "%s: %m", _PATH_UTMP);
+ else
+ {
+ while (read(fd, &data, sizeof(data)) == sizeof(data))
+ if (strcmp(data.ut_line, tp) == 0)
+ {
+ if (data.ut_host[0]) {
+#if MAXHOSTNAMELEN < UT_HOSTSIZE
+ strncpy(hid, data.ut_host, MAXHOSTNAMELEN);
+ hid[MAXHOSTNAMELEN] = '\0';
+#else
+ strncpy(hid, data.ut_host, UT_HOSTSIZE);
+ hid[UT_HOSTSIZE] = '\0';
+#endif
+ }
+ break;
+ }
+ close(fd);
+ }
+ }
+}
+
+/*
+ get system load averages
+ return 0 if success; otherwise, return -1.
+ */
+int getload(double load[3])
+{
+ int rtv = -1;
+#if defined(linux)
+ FILE *fp;
+
+ fp = fopen(LOAD_FILE, "r");
+ if (fp)
+ {
+ if (fscanf(fp, "%lf %lf %lf", &load[0], &load[1], &load[2]) == 3)
+ rtv = 0;
+ fclose(fp);
+ }
+#elif defined(__FreeBSD__)
+ if (getloadavg(load, 3) == 3)
+ rtv = 0;
+#endif
+ return rtv;
+}
+
+/*
+ show ban file
+ if filename exist, print it out, sleep 1 second, and return 0;
+ otherwise, return -1.
+ */
+int showbanfile(char *filename)
+{
+ FILE *fp;
+ char buf[256];
+
+ fp = fopen(filename, "r");
+ if (fp)
+ {
+ while (fgets(buf, sizeof(buf), fp))
+ fputs(buf, stdout);
+ printf("\n============================="
+ "=============================\n");
+ fclose(fp);
+ sleep(1);
+ }
+ return fp ? 0 : -1;
+}
+
+int main(void)
+{
+ int uid, rtv = 0;
+ char *tty, ttybuf[32], hid[MAXHOSTNAMELEN + 1];
+
+ openlog("bbsrf", LOG_PID | LOG_PERROR, LOG_USER);
+ chdir(BBSHOME);
+ uid = getuid();
+
+ while (1)
+ {
+ if (!showbanfile(BAN_FILE))
+ {
+ rtv = 1;
+ break;
+ }
+ else if (uid != BBSUID)
+ {
+ syslog(LOG_ERR, "UID DOES NOT MATCH");
+ rtv = -1;
+ break;
+ }
+ else if (!getpwuid(uid))
+ {
+ syslog(LOG_ERR, "YOU DONT EXIST");
+ rtv = -1;
+ break;
+ }
+ else
+ {
+ tty = ttyname(0);
+ if (tty)
+ {
+ strcpy(ttybuf, tty);
+ gethid(hid, ttybuf);
+ }
+ else
+ {
+ strcpy(ttybuf, "notty");
+ strcpy(hid, "unknown");
+ }
+ execl(BBSPROG, "mbbsd", hid, ttybuf, NULL);
+ syslog(LOG_ERR, "execl(): %m");
+ rtv = -1;
+ }
+ break;
+ }
+ return rtv;
+}
diff --git a/util/birth.c b/util/birth.c
new file mode 100644
index 00000000..899bf9ee
--- /dev/null
+++ b/util/birth.c
@@ -0,0 +1,99 @@
+/* ¹Ø¬Pµ{¦¡ 96 10/11 */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+#include "common.h"
+
+#define OUTFILE BBSHOME "/etc/birth.today"
+
+struct userec_t cuser;
+
+int bad_user_id() {
+ register char ch;
+ int j;
+ if (strlen(cuser.userid) < 2 || !isalpha(cuser.userid[0]))
+ return 1;
+ if (cuser.numlogins == 0 || cuser.numlogins > 15000)
+ return 1;
+ if (cuser.numposts > 15000)
+ return 1;
+ for (j = 1; (ch = cuser.userid[j]); j++)
+ {
+ if (!isalnum(ch))
+ return 1;
+ }
+ return 0;
+}
+
+int Link(char *src, char *dst) {
+ char cmd[200];
+
+ if (link(src, dst) == 0)
+ return 0;
+
+ sprintf(cmd, "/bin/cp -R %s %s", src, dst);
+ return system(cmd);
+}
+
+int main(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *fp1;
+ fileheader_t mymail;
+ int i, day = 0;
+ time_t now;
+ struct tm *ptime;
+ int j;
+
+ now = time(NULL); /* back to ancent */
+ ptime = localtime(&now);
+
+ if(passwd_mmap())
+ exit(1);
+
+ printf("*»sªí\n");
+ fp1 = fopen(OUTFILE, "w");
+
+ fprintf(fp1, "\n "
+ "¡¹¡¹¡¹¡¹¡¹¡¹ ¹Ø¬P¤jÆ[ "
+ "¡¹¡¹¡¹¡¹¡¹¡¹ \n\n");
+ fprintf(fp1, "¡i¥»¤é¹Ø¬P¡j \n");
+ for(j = 1; j <= MAX_USERS; j++) {
+ passwd_query(j, &cuser);
+ if (bad_user_id())
+ continue;
+ if (cuser.month == ptime->tm_mon + 1)
+ {
+ if (cuser.day == ptime->tm_mday)
+ {
+ char genbuf[200];
+ sprintf(genbuf, BBSHOME "/home/%c/%s", cuser.userid[0], cuser.userid);
+ stampfile(genbuf, &mymail);
+ strcpy(mymail.owner, BBSNAME);
+ strcpy(mymail.title, "!! ¥Í¤é§Ö¼Ö !!");
+ mymail.savemode = 0;
+ unlink(genbuf);
+ Link(BBSHOME "/etc/Welcome_birth", genbuf);
+ sprintf(genbuf, BBSHOME "/home/%c/%s/.DIR", cuser.userid[0], cuser.userid);
+ append_record(genbuf, &mymail, sizeof(mymail));
+ if ((cuser.numlogins + cuser.numposts) < 20)
+ continue;
+
+ fprintf(fp1,
+ " [%2d/%-2d] %-14s %-24s login:%-5d post:%-5d\n",
+ ptime->tm_mon + 1, ptime->tm_mday, cuser.userid,
+ cuser.username, cuser.numlogins, cuser.numposts);
+ }
+ }
+ }
+ fclose(fp1);
+ return 0;
+}
diff --git a/util/buildAnnounce.c b/util/buildAnnounce.c
new file mode 100644
index 00000000..0e754f22
--- /dev/null
+++ b/util/buildAnnounce.c
@@ -0,0 +1,69 @@
+/* «Ø¥ß©Ò¦³¬ÝªOºëµØ°Ïªº³sµ² */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include "config.h"
+#include "pttstruct.h"
+#define GROUPROOT BBSHOME"/man/group"
+
+extern bcache_t *brdshm;
+extern boardheader_t *bcache;
+extern void resolve_boards();
+
+void buildchilds(int level,char *path,boardheader_t *bptr)
+{
+ char newpath[512];
+ boardheader_t *ptr;
+ fileheader_t item;
+
+ if(bptr->firstchild[1]==(boardheader_t*)~0 || bptr->firstchild[1]==NULL)
+ return;
+ for(ptr =(void*) bptr->firstchild[1];
+ ptr!=(boardheader_t*)~0 ;ptr=ptr->next[1])
+ {
+
+ if(
+ (ptr->brdattr&(BRD_BAD | BRD_GROUPBOARD | BRD_NOCOUNT | BRD_HIDE))!=0
+ ||
+ (ptr->level && !(ptr->brdattr & BRD_POSTMASK))) continue;
+ printf("%*.*s+-%-14s %-s \n",level*2,level*2,"| | | | | | | | |",
+ ptr->brdname, ptr->title);
+ if(ptr->brdattr & BRD_GROUPBOARD)
+ {
+ sprintf(newpath,"%s/%s",path,ptr->brdname);
+ mkdir(newpath,0766);
+ buildchilds(level+1,newpath,ptr);
+ }
+ else
+ {
+ printf("%s4\n",ptr->brdname);
+ sprintf(newpath,"/bin/ln -s "BBSHOME"/man/boards/%s %s/%s",
+ ptr->brdname,path,ptr->brdname);
+ system(newpath);
+ }
+ printf("%s5\n",ptr->brdname);
+ sprintf(newpath,"%s/.DIR",path);
+ strcpy(item.owner,ptr->BM);
+ strtok(item.owner,"/");
+ strcpy(item.title,ptr->title+7);
+ item.savemode = 'D';
+ sprintf(item.filename,ptr->brdname);
+ append_record(newpath, &item, sizeof(item));
+ }
+}
+
+
+int main()
+{
+ char path[512];
+ setsid();
+ strcpy(path,GROUPROOT);
+ system("rm -rf "GROUPROOT);
+ mkdir(GROUPROOT,0766);
+ resolve_boards();
+ buildchilds(0,path,&bcache[0]);
+ return 0;
+}
diff --git a/util/buildAnnounce.sh b/util/buildAnnounce.sh
new file mode 100644
index 00000000..d43f420b
--- /dev/null
+++ b/util/buildAnnounce.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# $Id: buildAnnounce.sh,v 1.1 2002/03/07 15:13:45 in2 Exp $
+#
+bin/buildAnnounce > etc/ALLBRDLIST
+bin/post Record ¥þ¯¸¬ÝªO¦Cªí [¦Û°Ê¯¸ªø] etc/ALLBRDLIST
diff --git a/util/buildir.c b/util/buildir.c
new file mode 100644
index 00000000..381a657d
--- /dev/null
+++ b/util/buildir.c
@@ -0,0 +1,124 @@
+/* $Id: buildir.c,v 1.1 2002/03/07 15:13:45 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <time.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "pttstruct.h"
+
+int dirselect(struct dirent *dir) {
+ return strchr("MDSGH", dir->d_name[0]) && dir->d_name[1] == '.';
+}
+
+int mysort(const struct dirent **a,const struct dirent **b)
+{
+ return atoi(((*a)->d_name+2))-atoi(((*b)->d_name+2));
+}
+
+int main(int argc, char **argv) {
+ int k;
+
+ if(argc < 2) {
+ fprintf(stderr, "Usage: %s <path1> [<path2> ...]\n", argv[0]);
+ return 1;
+ }
+
+ for(k = 1; k < argc; k++) {
+ int fdir, count, total;
+ char *ptr, path[MAXPATHLEN];
+ struct dirent **dirlist;
+
+ sprintf(path, "%s/.DIR", argv[k]);
+ if((fdir = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) {
+ perror(path);
+ continue;
+ }
+
+ if((total = scandir(argv[k], &dirlist, dirselect, mysort)) == -1) {
+ fprintf(stderr, "scandir failed!\n");
+ close(fdir);
+ continue;
+ }
+
+ ptr = strrchr(path, '.');
+ for(count = 0; count < total; count++) {
+ FILE *fp;
+ struct stat st;
+
+ strcpy(ptr, dirlist[count]->d_name);
+ if(stat(path, &st) == 0 && st.st_size > 0 &&
+ (fp = fopen(path, "r")) != NULL) {
+ char buf[512];
+ time_t filetime;
+ fileheader_t fhdr;
+
+ memset(&fhdr, 0, sizeof(fhdr));
+ /* set file name */
+ strcpy(fhdr.filename, dirlist[count]->d_name);
+
+ /* set file time */
+ filetime = atoi(dirlist[count]->d_name + 2);
+ if(filetime > 740000000) {
+ struct tm *ptime = localtime(&filetime);
+ sprintf(fhdr.date, "%2d/%02d", ptime->tm_mon + 1,
+ ptime->tm_mday);
+ } else
+ strcpy(fhdr.date, " ");
+
+ /* set file mode */
+ fhdr.filemode = FILE_READ;
+
+ /* set article owner */
+ fgets(buf, sizeof(buf), fp);
+ if(strncmp(buf, "§@ªÌ: ", 6) == 0 ||
+ strncmp(buf, "µo«H¤H: ", 8) == 0) {
+ int i, j;
+
+ for(i = 5; buf[i] != ' '; i++);
+ for(; buf[i] == ' '; i++);
+ for(j = i + 1; buf[j] != ' '; j++);
+ j -= i;
+ if(j > IDLEN + 1)
+ j = IDLEN + 1;
+ strncpy(fhdr.owner, buf + i, j);
+ fhdr.owner[IDLEN + 1] = '\0';
+ strtok(fhdr.owner, " .@\t\n\r");
+ if(strtok(NULL, " .@\t\n\r"))
+ strcat(fhdr.owner, ".");
+
+ /* set article title */
+ while(fgets(buf, sizeof(buf), fp))
+ if(strncmp(buf, "¼ÐÃD: ", 6) == 0 ||
+ strncmp(buf, "¼Ð ÃD: ", 8) == 0) {
+ for(i = 5; buf[i] != ' '; i++);
+ for(; buf[i] == ' '; i++);
+ strtok(buf + i-1, "\n");
+ strncpy(fhdr.title, buf + i, TTLEN);
+ fhdr.title[TTLEN] = '\0';
+ break;
+ }
+ } else if(strncmp(buf, "¡ó Åwªï¥úÁ{", 11) == 0) {
+ strcpy(fhdr.title, "·|ij°O¿ý");
+ } else if(strncmp(buf, "\33[1;33;46m¡¹", 12) == 0||
+ strncmp(buf, "To", 2) == 0) {
+ strcpy(fhdr.title, "¼ö½u°O¿ý");
+ }
+// if(!fhdr.title[0])
+// strcpy(fhdr.title, dirlist[count]->d_name);
+ fclose(fp);
+ write(fdir, &fhdr, sizeof(fhdr));
+ }
+ }
+ close(fdir);
+ for(total--; total >= 0; total--)
+ free(dirlist[total]);
+ free(dirlist);
+ }
+ return 0;
+}
diff --git a/util/countalldice.c b/util/countalldice.c
new file mode 100644
index 00000000..badd4bad
--- /dev/null
+++ b/util/countalldice.c
@@ -0,0 +1,95 @@
+/* $Id: countalldice.c,v 1.1 2002/03/07 15:13:45 in2 Exp $ */
+
+/**********************************************/
+/*³o­Óµ{¦¡¬O¥Î¨Ó­pºâ½ä»ë¤lÁȱo¿ú¸ò½ßªº¿úªºµ{¦¡ */
+/*¥Îªk´N¬Oª½±µ¥´ countalldice ´N¥i¥H°w¹ï©Ò¦³¤H */
+/*¨Ó­pºâ¥LÁ`¦@ÁȤF¦h¤Ö ½ß¤F¦h¤Ö............... */
+/*§@ªÌ:Heat ©ó1997/10/2 */
+/**********************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "config.h"
+
+#define DICE_WIN BBSHOME "/etc/windice.log"
+#define DICE_LOST BBSHOME "/etc/lostdice.log"
+
+int total = 0;
+
+typedef struct dice
+{
+ char id[14];
+ int win;
+ int lost;
+}
+dice;
+
+dice table[1024];
+
+int find(char *name)
+{
+ int i = 0;
+ if (total == 0)
+ {
+ total++;
+ return 0;
+ }
+ for (i = 0; i < total; i++)
+ if (!strcmp(name, table[i].id))
+ return i;
+ memset(&table[total++], 0, sizeof(dice));
+ return total - 1;
+}
+
+int main() {
+ int index, win = 0, lost = 0;
+ FILE *fpwin, *fplost;
+ char buf[256], *ptr, buf0[256], *name = (char *) malloc(15), *mon = (char *) malloc(5);
+
+ fpwin = fopen(DICE_WIN, "r");
+ fplost = fopen(DICE_LOST, "r");
+
+ if (!fpwin || !fplost)
+ perror("error open file");
+
+ while (fgets(buf, 255, fpwin))
+ {
+ strcpy(buf0, buf);
+ name = strtok(buf, " ");
+ mon = strstr(buf0, "²bÁÈ:");
+ if ((ptr = strchr(mon, '\n')))
+ *ptr = 0;
+ index = find(name);
+ strcpy(table[index].id, name);
+ table[index].win += atoi(mon + 5);
+ }
+ fclose(fpwin);
+
+ while (fgets(buf, 255, fplost))
+ {
+ strcpy(buf0, buf);
+ name = strtok(buf, " ");
+ mon = strstr(buf0, "¿é¤F ");
+ if ((ptr = strchr(mon, '\n')))
+ *ptr = 0;
+ if ((index = find(name)) == total - 1)
+ strcpy(table[index].id, name);
+ table[index].lost += atoi(mon + 5);
+ }
+
+ for (index = 0; index < total; index++)
+ {
+ printf("%-15s ŤF %-8d ¶ô¿ú¡A ¿é±¼ %-8d ¶ô¿ú\n", table[index].id
+ ,table[index].win, table[index].lost);
+ win += table[index].win;
+ lost += table[index].lost;
+ }
+ index = win + lost;
+ printf("\n¤H¼Æ: %d\nÁ`Ĺ¿ú=%d Á`¿é¿ú=%d Á`ª÷ÃB:%d\n", total, win, lost, index);
+ printf("Ĺªº¤ñ¨Ò:%f ¿éªº¤ñ¨Ò:%f\n", (float) win / index, (float) lost / index);
+ printf("\n³Æµù¡G¿éŬO¥H¨Ï¥ÎªÌªºÆ[ÂI¨Ó¬Ý\n");
+ fclose(fplost);
+ return 0;
+}
diff --git a/util/cpdeadbrd.c b/util/cpdeadbrd.c
new file mode 100644
index 00000000..12c5827e
--- /dev/null
+++ b/util/cpdeadbrd.c
@@ -0,0 +1,41 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+
+extern int numboards;
+extern boardheader_t *bcache;
+int main(int argc, char* argv[]){
+struct stat st;
+boardheader_t *bptr;
+ int n;
+ char pathname[1024];
+
+ resolve_boards();
+ for (n=numboards-1;n>0;n--)
+ {
+
+ bptr = &bcache[n];
+ if(!strcmp(bptr->brdname,"ck53rd316"))continue;
+ sprintf(pathname,"/home/bbs/boards/%s/.DIR",bptr->brdname);
+ if(stat(pathname, &st) == -1)
+ {
+ printf("%s is dead\n",pathname);
+ sprintf (pathname,"cp -R /mnt/bbs/boards/%s /home/bbs/boards/%s",bptr->brdname,bptr->brdname);
+ }
+ }
+}
+
+
+
+
+
+
+
diff --git a/util/dailybackup.pl b/util/dailybackup.pl
new file mode 100644
index 00000000..76943887
--- /dev/null
+++ b/util/dailybackup.pl
@@ -0,0 +1,48 @@
+#!/usr/bin/perl
+use lib '/home/bbs/bin/';
+use LocalVars;
+use strict;
+use vars qw/$BACKHOME $MANROOT $HOMEROOT $BOARDROOT/;
+
+$BACKHOME = "$BBSHOME/backup";
+$MANROOT = "man/boards";
+$HOMEROOT = "home";
+$BOARDROOT= "boards";
+
+chdir $BBSHOME;
+my @baktable = (['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', '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']);
+my (undef,undef,undef,undef,undef,undef,$wday) = localtime(time);
+my $week = defined($ARGV[0]) ? $ARGV[0] : $wday;
+
+no strict 'subs';
+setpriority(PRIO_PROCESS, $$, 20);
+use strict subs;
+
+my($orig, $to);
+foreach $orig ( <$BACKHOME/*new*> ){
+ $to = $orig;
+ $to =~ s/\.new//g;
+ docmd("mv $orig $to");
+}
+
+foreach( @{$baktable[$week]} ){
+ docmd("$TAR zcf $BACKHOME/man.$_.new.tgz $MANROOT/$_*");
+ docmd("$TAR zcf $BACKHOME/home.$_.new.tgz $HOMEROOT/$_/*");
+ docmd("$TAR zcf $BACKHOME/board.$_.new.tgz $BOARDROOT/$_*");
+}
+
+if( $week == 0 ){
+ docmd("$TAR zcf $BACKHOME/general.new.tgz .act .crontab .note .polling .post bin cron etc innd note.ans note.dat out out.going pttbbs pttbbs.conf upgrade.sh usies ussong");
+}
+
+sub docmd
+{
+ print "@_\n";
+ `@_`;
+}
diff --git a/util/daymandex.c b/util/daymandex.c
new file mode 100644
index 00000000..d2921d07
--- /dev/null
+++ b/util/daymandex.c
@@ -0,0 +1,269 @@
+/* $Id: daymandex.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+
+/*
+ target : ºëµØ°Ï¯Á¤Þµ{¦¡ (man index)
+
+ syntax : mandex [board]
+ [board] ¦³­È ==> ¥u¶]¸Ó board
+ ªÅªº ==> ©Ò¦³ªº boards ³£¶]
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+extern int numboards;
+extern boardheader_t *bcache;
+
+char color[4][10] =
+{"", "", "", ""};
+char fn_index[] = ".index";
+char fn_new[] = ".index.new";
+char index_title[] = "¡· ºëµØ°Ï¥Ø¿ý¯Á¤Þ";
+FILE *fndx;
+int ndir;
+int nfile;
+int index_pos;
+char topdir[128], pgem[512], pndx[512];
+
+int nb = 0; /* board ¼Æ */
+
+struct boardinfo
+{
+ char bname[40];
+ int ndir;
+ int nfile;
+ int k;
+};
+typedef struct boardinfo boardinfo;
+
+boardinfo
+board[MAX_BOARD];
+
+int k_cmp(b, a)
+ boardinfo *b, *a;
+{
+ return ((a->k / 100 + a->ndir + a->nfile) - (b->k / 100 + b->ndir + b->nfile));
+}
+
+int dashd(fname)
+ char *fname;
+{
+ struct stat st;
+
+ return (stat(fname, &st) == 0 && S_ISDIR(st.st_mode));
+}
+
+
+/* visit the hierarchy recursively */
+
+void
+mandex(level, num_header, fpath)
+ int level;
+ char *fpath, *num_header;
+{
+ FILE *fgem;
+ char *fname, buf[256];
+ struct stat st;
+ int count;
+ fileheader_t fhdr;
+
+ fgem = fopen(fpath, "r+");
+ if (fgem == NULL)
+ return;
+
+ fname = strrchr(fpath, '.');
+ if (!level)
+ {
+
+ printf("%s\r\n",fpath);
+ strcpy(pgem, fpath);
+
+ strcpy(fname, fn_new);
+ fndx = fopen(fpath, "w");
+ if (fndx == NULL)
+ {
+ fclose(fgem);
+ return;
+ }
+ fprintf(fndx, "§Ç¸¹\t\t\tºëµØ°Ï¥DÃD\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¢w¢w\n");
+ strcpy(pndx, fpath);
+ ndir = nfile = 0;
+ index_pos = -1;
+ }
+
+ count = 0;
+ while (fread(&fhdr, sizeof(fhdr), 1, fgem) == 1)
+ {
+ strcpy(fname, fhdr.filename);
+ if (!fname[0]) continue;
+ if (!level && !strncmp(fhdr.title, index_title, strlen(index_title))
+ && index_pos < 0)
+ {
+ index_pos = count;
+ unlink(fpath);
+ }
+ st.st_size = 0;
+ stat(fpath, &st);
+
+ sprintf(buf, "%.*s%s%3d. %s \n",
+
+ 11 * level, num_header, color[level % 4], ++count, fhdr.title); /* Ptt */
+ fputs(buf, fndx);
+ if (dashd(fpath))
+ {
+ ++ndir;
+ if (*fhdr.title != '#' && level < 10)
+ {
+ strcat(fpath, "/.DIR");
+ mandex(level + 1, buf, fpath);
+ }
+ }
+ else
+ ++nfile;
+ }
+
+ if (!level)
+ {
+ char lpath[MAXPATHLEN];
+
+ fclose(fndx);
+ strcpy(fname, fn_index);
+ rename(pndx, fpath);
+ strcpy(pndx, fpath);
+
+ sprintf(buf, "%s.new", pgem);
+ if (index_pos >= 0 || (fndx = fopen(buf, "w")))
+ {
+ fname[-1] = 0;
+ stamplink(fpath, &fhdr);
+ unlink(fpath);
+ strcpy(fhdr.owner, "¨C¤Ñ¦Û°Ê§ó·s");
+ sprintf(lpath, "%s/%s", topdir, pndx);
+ st.st_size = 0;
+ stat(lpath, &st);
+ sprintf(fhdr.title, "%s (%.1fk)", index_title, st.st_size / 1024.);
+ board[nb].k = st.st_size; /* Ptt */
+ printf("(%d)[%dK]", nb, board[nb].k);
+ symlink(lpath, fpath);
+ if (index_pos < 0)
+ {
+ fwrite(&fhdr, sizeof(fhdr), 1, fndx);
+ rewind(fgem);
+ while (fread(&fhdr, sizeof(fhdr), 1, fgem) == 1)
+ fwrite(&fhdr, sizeof(fhdr), 1, fndx);
+ fclose(fndx);
+ fclose(fgem);
+ rename(buf, pgem);
+ }
+ else
+ {
+ fseek(fgem, index_pos * sizeof(fhdr), 0);
+ fwrite(&fhdr, sizeof(fhdr), 1, fgem);
+ fclose(fgem);
+ }
+ return;
+ }
+ }
+ fclose(fgem);
+}
+
+
+int main(int argc, char* argv[]){
+ boardheader_t *bptr;
+ DIR *dirp;
+ struct dirent *de;
+ int ch, n;
+ int place = 0;
+ char *fname, fpath[MAXPATHLEN];
+
+ resolve_boards();
+ nb = 0;
+ if(argc == 1){
+ puts("Creating the whole index...");
+ chdir(strcpy(topdir, BBSHOME));
+ strcpy(fpath, "man/.DIR");
+ mandex(0, "", fpath);
+ }
+
+
+ chdir(strcpy(topdir, BBSHOME "/man/boards"));
+
+ if(argc > 1) {
+ sprintf(fpath, "%s/.DIR", argv[1]);
+ mandex(0, "", fpath);
+ exit(0);
+ }
+
+ /* process all boards */
+
+ if(!(dirp = opendir(topdir))) {
+ printf("## unable to enter [man/boards]\n");
+ exit(-1);
+ }
+
+ while((de = readdir(dirp))){
+ fname = de->d_name;
+ ch = fname[0];
+ if (ch != '.'){
+ board[nb].k = 0;
+ strcpy(board[nb].bname, fname);
+ sprintf(fpath, "%s/.rebuild", fname);
+ if( access(fpath, 0) >= 0 ){
+ unlink(fpath);
+
+ sprintf(fpath, "%s/.DIR", fname);
+ mandex(0, "", fpath);
+ printf("%-14sd: %d\tf: %d\n", fname, ndir, nfile);
+ /* report */
+ board[nb].ndir = ndir;
+ board[nb].nfile = nfile;
+ if (board[nb].k)
+ nb++;
+ }
+ }
+ }
+ closedir(dirp);
+
+ qsort(board, nb, sizeof(boardinfo), k_cmp);
+
+ if (!(fndx = fopen(BBSHOME "/etc/topboardman", "w")))
+ exit(0);
+
+ fprintf(fndx, "±Æ¦W ¬Ý ª© ¥Ø¿ý¼Æ ÀÉ®×¼Æ"
+ " byte¼Æ  Á` ¤À ª© ¥D \n");
+
+ for (ch = 0; ch < nb; ch++){
+ for (n = 0; n < numboards; n++){
+ bptr = &bcache[n];
+ if (!strcmp(bptr->brdname, board[ch].bname))
+ break;
+ }
+ if (n >= numboards ||
+ (bptr->brdattr & (BRD_BAD | BRD_NOCOUNT | BRD_HIDE)))
+ continue;
+ if (board[ch].ndir + board[ch].nfile < 5)
+ break;
+ fprintf(fndx, "%3d.%15s %5d %7d %10d %6d %-24.24s\n",
+ ++place,
+ board[ch].bname,
+ board[ch].ndir, board[ch].nfile, board[ch].k
+ ,board[ch].k / 100 + board[ch].nfile + board[ch].ndir
+ ,bptr->BM);
+ }
+ fclose(fndx);
+ exit(0);
+}
diff --git a/util/deluserfile.c b/util/deluserfile.c
new file mode 100644
index 00000000..63cfefba
--- /dev/null
+++ b/util/deluserfile.c
@@ -0,0 +1,147 @@
+/* $Id: deluserfile.c,v 1.1 2002/03/07 15:13:45 in2 Exp $ */
+/* ¦Û°Ê¬åuser¥Ø¿ýÀÉ®×µ{¦¡ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+
+#define HOLDWRITELOG
+#define DELZEROFILE
+#define USERHOME BBSHOME "/home"
+
+int bad_user_id(char *userid)
+{
+ register char ch;
+
+ if (strlen(userid) < 2)
+ return 1;
+
+ if (!isalpha(*userid))
+ return 1;
+
+ if (!strcasecmp(userid, "new"))
+ return 1;
+
+ while ((ch = *(++userid)))
+ if (!isalnum(ch))
+ return 1;
+ return 0;
+}
+
+void del_file(char *userid)
+{
+ char buf[200], buf1[200];
+ struct dirent *de;
+ DIR *dirp;
+ char *ptr;
+
+ sprintf(buf, BBSHOME "/home/%c/%s", userid[0], userid);
+
+ if (chdir(buf) == -1)
+ return;
+
+ if (!(dirp = opendir(buf)))
+ return;
+
+ while ((de = readdir(dirp)))
+ {
+ ptr = de->d_name;
+ if (ptr[0] > ' ' && ptr[0] != '.')
+ {
+ if (strstr(ptr, "writelog"))
+#ifdef HOLDWRITELOG
+ {
+ fileheader_t mymail;
+
+ stampfile(buf, &mymail);
+ mymail.savemode = 'H'; /* hold-mail flag */
+ mymail.filemode = FILE_READ;
+ strcpy(mymail.owner, userid);
+ strcpy(mymail.title, "¼ö½u°O¿ý");
+ sprintf(buf1, BBSHOME "/home/%c/%s/writelog",
+ userid[0], userid);
+ rename(buf1, buf);
+ sprintf(buf1, BBSHOME "/home/%c/%s/.DIR", userid[0], userid);
+ append_record(buf1, &mymail, sizeof(mymail));
+ }
+#else
+ unlink(ptr);
+#endif
+ else if (strstr(ptr, "chat_"))
+ unlink(ptr);
+ else if (strstr(ptr, "ve_"))
+ unlink(ptr);
+ else if (strstr(ptr, "SR."))
+ unlink(ptr);
+ else if (strstr(ptr, ".old"))
+ unlink(ptr);
+ else if (strstr(ptr, "talk_"))
+ unlink(ptr);
+ }
+ }
+ closedir(dirp);
+}
+
+void mv_user_home(char *ptr)
+{
+ char buf[200];
+
+ printf("move user %s to tmp\n", ptr);
+ sprintf(buf, "cp -R " BBSHOME "/home/%c/%s " BBSHOME "/tmp", ptr[0], ptr);
+// sprintf(buf,"rm -rf " BBSHOME "/home/%c/%s",ptr[0],ptr);
+ if (!system(buf))
+ { //Copy success
+
+ sprintf(buf, "rm -rf " BBSHOME "/home/%c/%s", ptr[0], ptr);
+ system(buf);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ struct dirent *de;
+ DIR *dirp;
+ char *ptr, buf[200], ch;
+ int count = 0;
+/* visit all users */
+
+ printf("new version, deleting\n");
+
+ for (ch = 'A'; ch <= 'z'; ch++)
+ {
+ if(ch > 'Z' && ch < 'a')
+ continue;
+ printf("Cleaning %c\n", ch);
+ sprintf(buf, USERHOME "/%c", ch);
+ if (!(dirp = opendir(buf)))
+ {
+ printf("unable to open %s\n", buf);
+ continue;
+ }
+
+ while ((de = readdir(dirp)))
+ {
+ ptr = de->d_name;
+
+ /* ¹w¨¾¿ù»~ */
+ if (!bad_user_id(ptr))
+ {
+ if (!(count++ % 300))
+ printf(".\n");
+ if (!searchuser(ptr))
+ mv_user_home(ptr);
+ else
+ del_file(ptr);
+ }
+ }
+ closedir(dirp);
+ }
+ return 0;
+}
diff --git a/util/descrypt.c b/util/descrypt.c
new file mode 100644
index 00000000..97475c1a
--- /dev/null
+++ b/util/descrypt.c
@@ -0,0 +1,616 @@
+/* $Id: descrypt.c,v 1.1 2002/03/07 15:13:45 in2 Exp $ */
+
+/*
+ * FreeSec: libcrypt for NetBSD
+ *
+ * Copyright (c) 1994 David Burren
+ * All rights reserved.
+ *
+ * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet
+ * crypt.c should now *only* export crypt(), in order to make
+ * binaries of libcrypt exportable from the USA
+ *
+ * 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.
+ * 4. Neither the name of the author nor the names of other contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: src/secure/lib/libcrypt/crypt.c,v 1.11 1999/08/28 01:30:24 peter Exp $
+ *
+ * This is an original implementation of the DES and the crypt(3) interfaces
+ * by David Burren <davidb@werj.com.au>.
+ *
+ * An excellent reference on the underlying algorithm (and related
+ * algorithms) is:
+ *
+ * B. Schneier, Applied Cryptography: protocols, algorithms,
+ * and source code in C, John Wiley & Sons, 1994.
+ *
+ * Note that in that book's description of DES the lookups for the initial,
+ * pbox, and final permutations are inverted (this has been brought to the
+ * attention of the author). A list of errata for this book has been
+ * posted to the sci.crypt newsgroup by the author and is available for FTP.
+ *
+ * ARCHITECTURE ASSUMPTIONS:
+ * This code assumes that u_longs are 32 bits. It will probably not
+ * operate on 64-bit machines without modifications.
+ * It is assumed that the 8-byte arrays passed by reference can be
+ * addressed as arrays of u_longs (ie. the CPU is not picky about
+ * alignment).
+ */
+
+#ifndef HAVE_DES_CRYPT
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <pwd.h>
+#include <string.h>
+
+static unsigned char IP[64] = {
+ 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
+};
+
+static unsigned char inv_key_perm[64];
+static unsigned char u_key_perm[56];
+static unsigned char key_perm[56] = {
+ 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
+};
+
+static unsigned char key_shifts[16] = {
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+static unsigned char inv_comp_perm[56];
+static unsigned char comp_perm[48] = {
+ 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
+};
+
+/*
+ * No E box is used, as it's replaced by some ANDs, shifts, and ORs.
+ */
+
+static unsigned char u_sbox[8][64];
+static unsigned char sbox[8][64] = {
+ {
+ 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
+ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
+ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
+ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13
+ },
+ {
+ 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
+ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
+ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
+ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
+ },
+ {
+ 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
+ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
+ 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
+ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12
+ },
+ {
+ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
+ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
+ 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
+ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
+ },
+ {
+ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
+ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
+ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
+ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3
+ },
+ {
+ 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
+ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
+ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
+ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
+ },
+ {
+ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
+ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
+ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
+ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
+ },
+ {
+ 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
+ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
+ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
+ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
+ }
+};
+
+static unsigned char un_pbox[32];
+static unsigned char pbox[32] = {
+ 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
+ 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
+};
+
+static unsigned long bits32[32] = {
+ 0x80000000, 0x40000000, 0x20000000, 0x10000000,
+ 0x08000000, 0x04000000, 0x02000000, 0x01000000,
+ 0x00800000, 0x00400000, 0x00200000, 0x00100000,
+ 0x00080000, 0x00040000, 0x00020000, 0x00010000,
+ 0x00008000, 0x00004000, 0x00002000, 0x00001000,
+ 0x00000800, 0x00000400, 0x00000200, 0x00000100,
+ 0x00000080, 0x00000040, 0x00000020, 0x00000010,
+ 0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+static unsigned char bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+
+static unsigned long saltbits;
+static long old_salt;
+static unsigned long *bits28, *bits24;
+static unsigned char init_perm[64], final_perm[64];
+static unsigned long en_keysl[16], en_keysr[16];
+static unsigned long de_keysl[16], de_keysr[16];
+static int des_initialised = 0;
+static unsigned char m_sbox[4][4096];
+static unsigned long psbox[4][256];
+static unsigned long ip_maskl[8][256], ip_maskr[8][256];
+static unsigned long fp_maskl[8][256], fp_maskr[8][256];
+static unsigned long key_perm_maskl[8][128], key_perm_maskr[8][128];
+static unsigned long comp_maskl[8][128], comp_maskr[8][128];
+static unsigned long old_rawkey0, old_rawkey1;
+
+static unsigned char ascii64[] =
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+/* 0000000000111111111122222222223333333333444444444455555555556666 */
+/* 0123456789012345678901234567890123456789012345678901234567890123 */
+
+static int ascii_to_bin(char ch) {
+ if(ch > 'z')
+ return 0;
+ if(ch >= 'a')
+ return ch - 'a' + 38;
+ if(ch > 'Z')
+ return 0;
+ if(ch >= 'A')
+ return ch - 'A' + 12;
+ if(ch > '9')
+ return 0;
+ if(ch >= '.')
+ return ch - '.';
+ return 0;
+}
+
+static void des_init() {
+ int i, j, b, k, inbit, obit;
+ unsigned long *p, *il, *ir, *fl, *fr;
+
+ old_rawkey0 = old_rawkey1 = 0L;
+ saltbits = 0L;
+ old_salt = 0L;
+ bits24 = (bits28 = bits32 + 4) + 4;
+
+ /*
+ * Invert the S-boxes, reordering the input bits.
+ */
+ for(i = 0; i < 8; i++)
+ for(j = 0; j < 64; j++) {
+ b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf);
+ u_sbox[i][j] = sbox[i][b];
+ }
+
+ /*
+ * Convert the inverted S-boxes into 4 arrays of 8 bits.
+ * Each will handle 12 bits of the S-box input.
+ */
+ for(b = 0; b < 4; b++)
+ for(i = 0; i < 64; i++)
+ for(j = 0; j < 64; j++)
+ m_sbox[b][(i << 6) | j] =
+ (u_sbox[(b << 1)][i] << 4) |
+ u_sbox[(b << 1) + 1][j];
+
+ /*
+ * Set up the initial & final permutations into a useful form, and
+ * initialise the inverted key permutation.
+ */
+ for(i = 0; i < 64; i++) {
+ init_perm[final_perm[i] = IP[i] - 1] = i;
+ inv_key_perm[i] = 255;
+ }
+
+ /*
+ * Invert the key permutation and initialise the inverted key
+ * compression permutation.
+ */
+ for(i = 0; i < 56; i++) {
+ u_key_perm[i] = key_perm[i] - 1;
+ inv_key_perm[key_perm[i] - 1] = i;
+ inv_comp_perm[i] = 255;
+ }
+
+ /*
+ * Invert the key compression permutation.
+ */
+ for(i = 0; i < 48; i++) {
+ inv_comp_perm[comp_perm[i] - 1] = i;
+ }
+
+ /*
+ * Set up the OR-mask arrays for the initial and final permutations,
+ * and for the key initial and compression permutations.
+ */
+ for(k = 0; k < 8; k++) {
+ for(i = 0; i < 256; i++) {
+ *(il = &ip_maskl[k][i]) = 0L;
+ *(ir = &ip_maskr[k][i]) = 0L;
+ *(fl = &fp_maskl[k][i]) = 0L;
+ *(fr = &fp_maskr[k][i]) = 0L;
+ for(j = 0; j < 8; j++) {
+ inbit = 8 * k + j;
+ if(i & bits8[j]) {
+ if((obit = init_perm[inbit]) < 32)
+ *il |= bits32[obit];
+ else
+ *ir |= bits32[obit-32];
+ if ((obit = final_perm[inbit]) < 32)
+ *fl |= bits32[obit];
+ else
+ *fr |= bits32[obit - 32];
+ }
+ }
+ }
+ for(i = 0; i < 128; i++) {
+ *(il = &key_perm_maskl[k][i]) = 0L;
+ *(ir = &key_perm_maskr[k][i]) = 0L;
+ for(j = 0; j < 7; j++) {
+ inbit = 8 * k + j;
+ if(i & bits8[j + 1]) {
+ if((obit = inv_key_perm[inbit]) == 255)
+ continue;
+ if(obit < 28)
+ *il |= bits28[obit];
+ else
+ *ir |= bits28[obit - 28];
+ }
+ }
+ *(il = &comp_maskl[k][i]) = 0L;
+ *(ir = &comp_maskr[k][i]) = 0L;
+ for(j = 0; j < 7; j++) {
+ inbit = 7 * k + j;
+ if(i & bits8[j + 1]) {
+ if((obit=inv_comp_perm[inbit]) == 255)
+ continue;
+ if(obit < 24)
+ *il |= bits24[obit];
+ else
+ *ir |= bits24[obit - 24];
+ }
+ }
+ }
+ }
+
+ /*
+ * Invert the P-box permutation, and convert into OR-masks for
+ * handling the output of the S-box arrays setup above.
+ */
+ for(i = 0; i < 32; i++)
+ un_pbox[pbox[i] - 1] = i;
+
+ for(b = 0; b < 4; b++)
+ for(i = 0; i < 256; i++) {
+ *(p = &psbox[b][i]) = 0L;
+ for (j = 0; j < 8; j++) {
+ if (i & bits8[j])
+ *p |= bits32[un_pbox[8 * b + j]];
+ }
+ }
+
+ des_initialised = 1;
+}
+
+static void setup_salt(long salt) {
+ unsigned long obit, saltbit;
+ int i;
+
+ if (salt == old_salt)
+ return;
+ old_salt = salt;
+
+ saltbits = 0L;
+ saltbit = 1;
+ obit = 0x800000;
+ for (i = 0; i < 24; i++) {
+ if (salt & saltbit)
+ saltbits |= obit;
+ saltbit <<= 1;
+ obit >>= 1;
+ }
+}
+
+static int des_setkey(const char *key) {
+ unsigned long k0, k1, rawkey0, rawkey1;
+ int shifts, round;
+
+ if(!des_initialised)
+ des_init();
+
+ rawkey0 = ntohl(*(unsigned long *) key);
+ rawkey1 = ntohl(*(unsigned long *) (key + 4));
+
+ if((rawkey0 | rawkey1)
+ && rawkey0 == old_rawkey0
+ && rawkey1 == old_rawkey1) {
+ /*
+ * Already setup for this key.
+ * This optimisation fails on a zero key (which is weak and
+ * has bad parity anyway) in order to simplify the starting
+ * conditions.
+ */
+ return 0;
+ }
+ old_rawkey0 = rawkey0;
+ old_rawkey1 = rawkey1;
+
+ /*
+ * Do key permutation and split into two 28-bit subkeys.
+ */
+ k0 = key_perm_maskl[0][rawkey0 >> 25]
+ | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f]
+ | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f]
+ | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f]
+ | key_perm_maskl[4][rawkey1 >> 25]
+ | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f]
+ | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f]
+ | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f];
+ k1 = key_perm_maskr[0][rawkey0 >> 25]
+ | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f]
+ | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f]
+ | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f]
+ | key_perm_maskr[4][rawkey1 >> 25]
+ | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f]
+ | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f]
+ | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f];
+ /*
+ * Rotate subkeys and do compression permutation.
+ */
+ shifts = 0;
+ for(round = 0; round < 16; round++) {
+ unsigned long t0, t1;
+
+ shifts += key_shifts[round];
+
+ t0 = (k0 << shifts) | (k0 >> (28 - shifts));
+ t1 = (k1 << shifts) | (k1 >> (28 - shifts));
+
+ de_keysl[15 - round] =
+ en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f]
+ | comp_maskl[1][(t0 >> 14) & 0x7f]
+ | comp_maskl[2][(t0 >> 7) & 0x7f]
+ | comp_maskl[3][t0 & 0x7f]
+ | comp_maskl[4][(t1 >> 21) & 0x7f]
+ | comp_maskl[5][(t1 >> 14) & 0x7f]
+ | comp_maskl[6][(t1 >> 7) & 0x7f]
+ | comp_maskl[7][t1 & 0x7f];
+
+ de_keysr[15 - round] = en_keysr[round] =
+ comp_maskr[0][(t0 >> 21) & 0x7f]
+ | comp_maskr[1][(t0 >> 14) & 0x7f]
+ | comp_maskr[2][(t0 >> 7) & 0x7f]
+ | comp_maskr[3][t0 & 0x7f]
+ | comp_maskr[4][(t1 >> 21) & 0x7f]
+ | comp_maskr[5][(t1 >> 14) & 0x7f]
+ | comp_maskr[6][(t1 >> 7) & 0x7f]
+ | comp_maskr[7][t1 & 0x7f];
+ }
+ return 0;
+}
+
+static int do_des(unsigned long l_in, unsigned long r_in, unsigned long *l_out,
+ unsigned long *r_out, int count) {
+ /*
+ * l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format.
+ */
+ unsigned long l, r, *kl, *kr, *kl1, *kr1;
+ unsigned long f, r48l, r48r;
+ int round;
+
+ if(count == 0) {
+ return 1;
+ } else if(count > 0) {
+ /*
+ * Encrypting
+ */
+ kl1 = en_keysl;
+ kr1 = en_keysr;
+ } else {
+ /*
+ * Decrypting
+ */
+ count = -count;
+ kl1 = de_keysl;
+ kr1 = de_keysr;
+ }
+
+ /*
+ * Do initial permutation (IP).
+ */
+ l = ip_maskl[0][l_in >> 24]
+ | ip_maskl[1][(l_in >> 16) & 0xff]
+ | ip_maskl[2][(l_in >> 8) & 0xff]
+ | ip_maskl[3][l_in & 0xff]
+ | ip_maskl[4][r_in >> 24]
+ | ip_maskl[5][(r_in >> 16) & 0xff]
+ | ip_maskl[6][(r_in >> 8) & 0xff]
+ | ip_maskl[7][r_in & 0xff];
+ r = ip_maskr[0][l_in >> 24]
+ | ip_maskr[1][(l_in >> 16) & 0xff]
+ | ip_maskr[2][(l_in >> 8) & 0xff]
+ | ip_maskr[3][l_in & 0xff]
+ | ip_maskr[4][r_in >> 24]
+ | ip_maskr[5][(r_in >> 16) & 0xff]
+ | ip_maskr[6][(r_in >> 8) & 0xff]
+ | ip_maskr[7][r_in & 0xff];
+
+ while(count--) {
+ /*
+ * Do each round.
+ */
+ kl = kl1;
+ kr = kr1;
+ round = 16;
+ while(round--) {
+ /*
+ * Expand R to 48 bits (simulate the E-box).
+ */
+ r48l = ((r & 0x00000001) << 23)
+ | ((r & 0xf8000000) >> 9)
+ | ((r & 0x1f800000) >> 11)
+ | ((r & 0x01f80000) >> 13)
+ | ((r & 0x001f8000) >> 15);
+
+ r48r = ((r & 0x0001f800) << 7)
+ | ((r & 0x00001f80) << 5)
+ | ((r & 0x000001f8) << 3)
+ | ((r & 0x0000001f) << 1)
+ | ((r & 0x80000000) >> 31);
+ /*
+ * Do salting for crypt() and friends, and
+ * XOR with the permuted key.
+ */
+ f = (r48l ^ r48r) & saltbits;
+ r48l ^= f ^ *kl++;
+ r48r ^= f ^ *kr++;
+ /*
+ * Do sbox lookups (which shrink it back to 32 bits)
+ * and do the pbox permutation at the same time.
+ */
+ f = psbox[0][m_sbox[0][r48l >> 12]]
+ | psbox[1][m_sbox[1][r48l & 0xfff]]
+ | psbox[2][m_sbox[2][r48r >> 12]]
+ | psbox[3][m_sbox[3][r48r & 0xfff]];
+ /*
+ * Now that we've permuted things, complete f().
+ */
+ f ^= l;
+ l = r;
+ r = f;
+ }
+ r = l;
+ l = f;
+ }
+ /*
+ * Do final permutation (inverse of IP).
+ */
+ *l_out = fp_maskl[0][l >> 24]
+ | fp_maskl[1][(l >> 16) & 0xff]
+ | fp_maskl[2][(l >> 8) & 0xff]
+ | fp_maskl[3][l & 0xff]
+ | fp_maskl[4][r >> 24]
+ | fp_maskl[5][(r >> 16) & 0xff]
+ | fp_maskl[6][(r >> 8) & 0xff]
+ | fp_maskl[7][r & 0xff];
+ *r_out = fp_maskr[0][l >> 24]
+ | fp_maskr[1][(l >> 16) & 0xff]
+ | fp_maskr[2][(l >> 8) & 0xff]
+ | fp_maskr[3][l & 0xff]
+ | fp_maskr[4][r >> 24]
+ | fp_maskr[5][(r >> 16) & 0xff]
+ | fp_maskr[6][(r >> 8) & 0xff]
+ | fp_maskr[7][r & 0xff];
+ return 0;
+}
+
+char *crypt(char *key, char *setting) {
+ unsigned long count, salt, l, r0, r1, keybuf[2];
+ unsigned char *p, *q;
+ static unsigned char output[21];
+
+ if(!des_initialised)
+ des_init();
+ /*
+ * Copy the key, shifting each character up by one bit
+ * and padding with zeros.
+ */
+ q = (unsigned char *)keybuf;
+ while(q - (unsigned char *)keybuf - 8) {
+ if((*q++ = *key << 1))
+ key++;
+ }
+ if(des_setkey((unsigned char *)keybuf))
+ return NULL;
+
+ /*
+ * "old"-style:
+ * setting - 2 bytes of salt
+ * key - up to 8 characters
+ */
+ count = 25;
+
+ salt = (ascii_to_bin(setting[1]) << 6)
+ | ascii_to_bin(setting[0]);
+
+ output[0] = setting[0];
+ /*
+ * If the encrypted password that the salt was extracted from
+ * is only 1 character long, the salt will be corrupted. We
+ * need to ensure that the output string doesn't have an extra
+ * NUL in it!
+ */
+ output[1] = setting[1] ? setting[1] : output[0];
+
+ p = output + 2;
+
+ setup_salt(salt);
+ /*
+ * Do it.
+ */
+ if(do_des(0L, 0L, &r0, &r1, count))
+ return NULL;
+ /*
+ * Now encode the result...
+ */
+ l = (r0 >> 8);
+ *p++ = ascii64[(l >> 18) & 0x3f];
+ *p++ = ascii64[(l >> 12) & 0x3f];
+ *p++ = ascii64[(l >> 6) & 0x3f];
+ *p++ = ascii64[l & 0x3f];
+
+ l = (r0 << 16) | ((r1 >> 16) & 0xffff);
+ *p++ = ascii64[(l >> 18) & 0x3f];
+ *p++ = ascii64[(l >> 12) & 0x3f];
+ *p++ = ascii64[(l >> 6) & 0x3f];
+ *p++ = ascii64[l & 0x3f];
+
+ l = r1 << 2;
+ *p++ = ascii64[(l >> 12) & 0x3f];
+ *p++ = ascii64[(l >> 6) & 0x3f];
+ *p++ = ascii64[l & 0x3f];
+ *p = 0;
+
+ return output;
+}
+#endif
diff --git a/util/expire.c b/util/expire.c
new file mode 100644
index 00000000..d6f3e2b9
--- /dev/null
+++ b/util/expire.c
@@ -0,0 +1,226 @@
+/* $Id: expire.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+/* ¦Û°Ê¬å«H¤u¨ãµ{¦¡ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+
+#define QCAST int (*)(const void *, const void *)
+
+#define DEF_DAYS 50
+#define DEF_MAXP 2000
+#define DEF_MINP 300
+
+#define EXPIRE_CONF BBSHOME "/etc/expire.conf"
+extern boardheader_t *bcache;
+char *bpath = BBSHOME "/boards";
+
+struct life
+{
+ char bname[16]; /* board ID */
+ int days; /* expired days */
+ int maxp; /* max post */
+ int minp; /* min post */
+};
+typedef struct life life;
+
+
+void
+ expire(brd)
+life *brd;
+{
+ fileheader_t head;
+ struct stat state;
+ char lockfile[128], tmpfile[128], bakfile[128];
+ char fpath[128], index[128], *fname;
+ int total, bid;
+ int fd, fdr, fdw, done, keep;
+ int duetime, ftime;
+
+ printf("%s\n", brd->bname);
+ if((bid = getbnum(brd->bname)) == 0 ||
+ strcmp(brd->bname, bcache[bid-1].brdname))
+ {
+ printf("no such board?: %s\n", brd->bname);
+ return;
+ }
+#ifdef VERBOSE
+ if (brd->days < 1)
+ {
+ printf(":Err: expire time must more than 1 day.\n");
+ return;
+ }
+ else if (brd->maxp < 100)
+ {
+ printf(":Err: maxmum posts number must more than 100.\n");
+ return;
+ }
+#endif
+
+ sprintf(index, "%s/%s/.DIR", bpath, brd->bname);
+ sprintf(lockfile, "%s.lock", index);
+ if ((fd = open(lockfile, O_RDWR | O_CREAT | O_APPEND, 0644)) == -1)
+ return;
+ flock(fd, LOCK_EX);
+
+ strcpy(fpath, index);
+ fname = (char *) strrchr(fpath, '.');
+
+ duetime = time(NULL) - brd->days * 24 * 60 * 60;
+ done = 0;
+ if ((fdr = open(index, O_RDONLY, 0)) > 0)
+ {
+ fstat(fdr, &state);
+ total = state.st_size / sizeof(head);
+ sprintf(tmpfile, "%s.new", index);
+ unlink(tmpfile);
+ if ((fdw = open(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0644)) > 0)
+ {
+ while (read(fdr, &head, sizeof head) == sizeof head)
+ {
+ done = 1;
+ ftime = atoi(head.filename + 2);
+ if (head.owner[0] == '-')
+ keep = 0;
+ else if (head.filemode & FILE_MARKED || total <= brd->minp)
+ keep = 1;
+ else if (ftime < duetime || total > brd->maxp)
+ keep = 0;
+ else
+ keep = 1;
+
+ if (keep)
+ {
+ if (write(fdw, (char *)&head, sizeof head) == -1)
+ {
+ done = 0;
+ break;
+ }
+ }
+ else
+ {
+ strcpy(fname, head.filename);
+ unlink(fpath);
+ printf("\t%s\n", fname);
+ total--;
+ }
+ }
+ close(fdw);
+ }
+ close(fdr);
+ }
+
+ if (done)
+ {
+ sprintf(bakfile, "%s.old", index);
+ if (rename(index, bakfile) != -1)
+ {
+ rename(tmpfile, index);
+ touchbtotal(bid);
+ }
+ }
+ flock(fd, LOCK_UN);
+ close(fd);
+}
+
+
+int main(argc, argv)
+char *argv[];
+{
+ FILE *fin;
+ int number, count;
+ life db, table[MAX_BOARD], *key;
+ struct dirent *de;
+ DIR *dirp;
+ char *ptr, *bname, buf[256];
+
+ resolve_boards();
+ db.days = ((argc > 1) && (number = atoi(argv[1])) > 0) ? number : DEF_DAYS;
+ db.maxp = ((argc > 2) && (number = atoi(argv[2])) > 0) ? number : DEF_MAXP;
+ db.minp = ((argc > 3) && (number = atoi(argv[3])) > 0) ? number : DEF_MINP;
+
+/* --------------- */
+/* load expire.ctl */
+/* --------------- */
+
+ count = 0;
+ if((fin = fopen(EXPIRE_CONF, "r")))
+ {
+ while (fgets(buf, 256, fin))
+ {
+ 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;
+ }
+ }
+ }
+ }
+ }
+ fclose(fin);
+ }
+
+ if (count > 1)
+ {
+ qsort(table, count, sizeof(life), (QCAST)strcasecmp);
+ }
+
+/* ---------------- */
+/* visit all boards */
+/* ---------------- */
+
+ if (!(dirp = opendir(bpath)))
+ {
+ printf(":Err: unable to open %s\n", bpath);
+ return -1;
+ }
+
+ while((de = readdir(dirp)))
+ {
+ ptr = de->d_name;
+ if (ptr[0] > ' ' && ptr[0] != '.')
+ {
+ if (count)
+ key = (life *) bsearch(ptr, table, count, sizeof(life), (QCAST)strcasecmp);
+ else
+ key = NULL;
+ if (!key)
+ key = &db;
+ strcpy(key->bname, ptr);
+ expire(key);
+ }
+ }
+ closedir(dirp);
+ return 0;
+}
diff --git a/util/horoscope.c b/util/horoscope.c
new file mode 100644
index 00000000..c91db7cd
--- /dev/null
+++ b/util/horoscope.c
@@ -0,0 +1,157 @@
+/* $Id: horoscope.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+#include <stdio.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+#include "common.h"
+
+struct userec_t cuser;
+
+int main() {
+ int i, j, k;
+ FILE *fp;
+ int max, item, maxhoroscope;
+
+ int act[12];
+
+ char *name[13] =
+ {"¨d¦Ï",
+ "ª÷¤û",
+ "Âù¤l",
+ "¥¨ÃÉ",
+ "·à¤l",
+ "³B¤k",
+ "¤Ñ¯¯",
+ "¤ÑÃÈ",
+ "®g¤â",
+ "¼¯½~",
+ "¤ô²~",
+ "Âù³½",
+ ""
+ };
+ char *blk[10] =
+ {
+ " ", "¢j", "¢k", "¢l", "¢m",
+ "¢n", "¢o", "¢p", "¢i", "¢i",
+ };
+
+ memset(act, 0, sizeof(act));
+ if(passwd_mmap())
+ exit(1);
+ for(k = 1; k <= MAX_USERS; k++) {
+ passwd_query(k, &cuser);
+ if(!cuser.userid[0])
+ continue;
+ switch (cuser.month)
+ {
+ case 1:
+ if (cuser.day <= 19)
+ act[9]++;
+ else
+ act[10]++;
+ break;
+ case 2:
+ if (cuser.day <= 18)
+ act[10]++;
+ else
+ act[11]++;
+ break;
+ case 3:
+ if (cuser.day <= 20)
+ act[11]++;
+ else
+ act[0]++;
+ break;
+ case 4:
+ if (cuser.day <= 19)
+ act[0]++;
+ else
+ act[1]++;
+ break;
+ case 5:
+ if (cuser.day <= 20)
+ act[1]++;
+ else
+ act[2]++;
+ break;
+ case 6:
+ if (cuser.day <= 21)
+ act[2]++;
+ else
+ act[3]++;
+ break;
+ case 7:
+ if (cuser.day <= 22)
+ act[3]++;
+ else
+ act[4]++;
+ break;
+ case 8:
+ if (cuser.day <= 22)
+ act[4]++;
+ else
+ act[5]++;
+ break;
+ case 9:
+ if (cuser.day <= 22)
+ act[5]++;
+ else
+ act[6]++;
+ break;
+ case 10:
+ if (cuser.day <= 23)
+ act[6]++;
+ else
+ act[7]++;
+ break;
+ case 11:
+ if (cuser.day <= 22)
+ act[7]++;
+ else
+ act[8]++;
+ break;
+ case 12:
+ if (cuser.day <= 21)
+ act[8]++;
+ else
+ act[9]++;
+ break;
+ }
+ }
+
+ for (i = max = maxhoroscope = 0; i < 12; i++)
+ {
+ if (act[i] > max)
+ {
+ max = act[i];
+ maxhoroscope = i;
+ }
+ }
+
+ item = max / 30 + 1;
+
+ if ((fp = fopen(BBSHOME"/etc/horoscope", "w")) == NULL)
+ {
+ printf("cann't open etc/horoscope\n");
+ return 1;
+ }
+
+ for (i = 0; i < 12; i++)
+ {
+ fprintf(fp, " %s®y ", name[i]);
+ for (j = 0; j < act[i] / item; j++)
+ {
+ fprintf(fp, "%2s", blk[9]);
+ }
+ /* ¬°¤F­è¦n¤@­¶ */
+ if (i != 11)
+ fprintf(fp, "%2s %d\n\n", blk[(act[i] % item) * 10 / item],
+ act[i]);
+ else
+ fprintf(fp, "%2s %d\n", blk[(act[i] % item) * 10 / item],
+ act[i]);
+ }
+ fclose(fp);
+ return 0;
+}
diff --git a/util/in2outmail b/util/in2outmail
new file mode 100644
index 00000000..686944c1
--- /dev/null
+++ b/util/in2outmail
Binary files differ
diff --git a/util/in2outmail.c b/util/in2outmail.c
new file mode 100644
index 00000000..fce9cc59
--- /dev/null
+++ b/util/in2outmail.c
@@ -0,0 +1,288 @@
+/* $Id: in2outmail.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "config.h"
+#include "pttstruct.h"
+
+
+#ifdef HAVE_SETPROCTITLE
+
+#include <sys/types.h>
+#include <libutil.h>
+
+void initsetproctitle(int argc, char **argv, char **envp) {
+}
+
+#else
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+char **Argv = NULL; /* pointer to argument vector */
+char *LastArgv = NULL; /* end of argv */
+extern char **environ;
+
+void initsetproctitle(int argc, char **argv, char **envp) {
+ register int i;
+
+ /* Move the environment so setproctitle can use the space at
+ the top of memory. */
+ for(i = 0; envp[i]; i++);
+ environ = malloc(sizeof(char *) * (i + 1));
+ for(i = 0; envp[i]; i++)
+ environ[i] = strdup(envp[i]);
+ environ[i] = NULL;
+
+ /* Save start and extent of argv for setproctitle. */
+ Argv = argv;
+ if(i > 0)
+ LastArgv = envp[i - 1] + strlen(envp[i - 1]);
+ else
+ LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
+}
+
+static void do_setproctitle(const char *cmdline) {
+ char buf[256], *p;
+ int i;
+
+ strncpy(buf, cmdline, 256);
+ buf[255] = '\0';
+ i = strlen(buf);
+ if(i > LastArgv - Argv[0] - 2) {
+ i = LastArgv - Argv[0] - 2;
+ }
+ strcpy(Argv[0], buf);
+ p = &Argv[0][i];
+ while(p < LastArgv)
+ *p++='\0';
+ Argv[1] = NULL;
+}
+
+void setproctitle(const char* format, ...) {
+ char buf[256];
+
+ va_list args;
+ va_start(args, format);
+ vsprintf(buf, format,args);
+ do_setproctitle(buf);
+ va_end(args);
+}
+#endif
+
+
+
+
+
+#define SPOOL BBSHOME "/out"
+#define INDEX SPOOL "/.DIR"
+#define NEWINDEX SPOOL "/.DIR.sending"
+#define FROM ".bbs@" MYHOSTNAME
+#define SMTPPORT 25
+
+int waitReply(int sock) {
+ char buf[256];
+
+ if(read(sock, buf, sizeof(buf)) <= 0)
+ return -1;
+ else
+ return buf[0] - '0';
+}
+
+int sendRequest(int sock, char *request) {
+ return write(sock, request, strlen(request)) < 0 ? -1 : 0;
+}
+
+int connectMailServer(char *host) {
+ int sock;
+ struct sockaddr_in addr;
+
+ if((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+#ifdef FreeBSD
+ addr.sin_len = sizeof(addr);
+#endif
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(SMTPPORT);
+ addr.sin_addr.s_addr = inet_addr(host);
+
+ if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ perror(RELAY_SERVER_IP);
+ close(sock);
+ return -1;
+ }
+
+ if(waitReply(sock) != 2) {
+ close(sock);
+ return -1;
+ }
+
+ if(sendRequest(sock, "helo " MYHOSTNAME "\n") || waitReply(sock) != 2) {
+ close(sock);
+ return -1;
+ } else
+ return sock;
+}
+
+void disconnectMailServer(int sock) {
+ sendRequest(sock, "quit\n");
+ /* drop the reply :p */
+ close(sock);
+}
+
+void doSendBody(int sock, FILE *fp, char *from, char *to, char *subject) {
+ int n;
+ char buf[2048];
+
+ n = snprintf(buf, sizeof(buf), "From: %s\nTo: %s\nSubject: %s\n\n",
+ from, to, subject);
+ write(sock, buf, n);
+
+ while(fgets(buf, sizeof(buf), fp)) {
+ if(buf[0] == '.' && buf[1] == '\n')
+ strcpy(buf, "..\n");
+ write(sock, buf, strlen(buf));
+ }
+}
+
+void doSendMail(int sock, FILE *fp, char *from, char *to, char *subject) {
+ char buf[256];
+
+ snprintf(buf, sizeof(buf), "mail from: %s\n", from);
+ if(sendRequest(sock, buf) || waitReply(sock) != 2)
+ return;
+
+ snprintf(buf, sizeof(buf), "rcpt to: %s\n", to);
+ if(sendRequest(sock, buf) || waitReply(sock) != 2)
+ return;
+
+ if(sendRequest(sock, "data\n") || waitReply(sock) != 3)
+ return;
+
+ doSendBody(sock, fp, from, to, subject);
+
+ if(sendRequest(sock, "\n.\n") || waitReply(sock) != 2)
+ return;
+}
+
+void sendMail() {
+ int fd, sockPTT2, sockHinet;
+ MailQueue mq;
+
+ if(access(NEWINDEX, R_OK | W_OK)) {
+ if(link(INDEX, NEWINDEX) || unlink(INDEX))
+ /* nothing to do */
+ return;
+ }
+
+ if( (sockPTT2 = connectMailServer("140.112.30.143")) < 0 ){
+ fprintf(stderr, "connect server failed...\n");
+ return;
+ }
+ sockHinet = connectMailServer("61.218.59.183");
+
+ fd = open(NEWINDEX, O_RDONLY);
+ flock(fd, LOCK_EX);
+ while(read(fd, &mq, sizeof(mq)) > 0) {
+ FILE *fp;
+ char buf[256];
+
+ snprintf(buf, sizeof(buf), "%s%s", mq.sender, FROM);
+ if((fp = fopen(mq.filepath, "r"))) {
+ setproctitle("outmail: sending %s", mq.filepath);
+ if( strstr(mq.rcpt, ".edu.tw") ||
+ strstr(mq.rcpt, ".twbbs.org") ||
+ strstr(mq.rcpt, "ptt.cc") ||
+ strstr(mq.rcpt, "ptt2.cc") ){
+ printf("relay server: ptt2, to %s\n", mq.rcpt);
+ doSendMail(sockPTT2, fp, buf, mq.rcpt, mq.subject);
+ }
+ else{
+ printf("relay server: ezmain, to %s\n", mq.rcpt);
+ doSendMail( (sockHinet > 0) ? sockHinet : sockPTT2,
+ fp, buf, mq.rcpt, mq.subject);
+ }
+ fclose(fp);
+ unlink(mq.filepath);
+ } else {
+ perror(mq.filepath);
+ }
+ }
+ flock(fd, LOCK_UN);
+ close(fd);
+ unlink(NEWINDEX);
+
+ if( sockHinet > 0 )
+ disconnectMailServer(sockHinet);
+ disconnectMailServer(sockPTT2);
+}
+
+void listQueue() {
+ int fd;
+
+ if((fd = open(INDEX, O_RDONLY)) >= 0) {
+ int counter = 0;
+ MailQueue mq;
+
+ flock(fd, LOCK_EX);
+ while(read(fd, &mq, sizeof(mq)) > 0) {
+ printf("%s:%s -> %s:%s\n", mq.filepath, mq.username, mq.rcpt,
+ mq.subject);
+ counter++;
+ }
+ flock(fd, LOCK_UN);
+ close(fd);
+ printf("\nTotal: %d mails in queue\n", counter);
+ } else {
+ perror(INDEX);
+ }
+}
+
+void usage() {
+ fprintf(stderr, "usage: outmail [-qh]\n");
+}
+
+void wakeup(int s) {
+}
+
+int main(int argc, char **argv, char **envp) {
+ int ch;
+
+ signal(SIGHUP, wakeup);
+ initsetproctitle(argc, argv, envp);
+
+ if(chdir(BBSHOME))
+ return 1;
+ while((ch = getopt(argc, argv, "qh")) != -1) {
+ switch(ch) {
+ case 'q':
+ listQueue();
+ return 0;
+ default:
+ usage();
+ return 0;
+ }
+ }
+ for(;;) {
+ sendMail();
+ setproctitle("outmail: sleeping");
+ sleep(60 * 3); /* send mail every 3 minute */
+ }
+ return 0;
+}
diff --git a/util/initbbs.c b/util/initbbs.c
new file mode 100644
index 00000000..ce6c4361
--- /dev/null
+++ b/util/initbbs.c
@@ -0,0 +1,223 @@
+/* $Id: initbbs.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "perm.h"
+
+static void initDir() {
+ mkdir("adm", 0755);
+ mkdir("boards", 0755);
+ mkdir("etc", 0755);
+ mkdir("man", 0755);
+ mkdir("man/boards", 0755);
+ mkdir("out", 0755);
+ mkdir("tmp", 0755);
+}
+
+static void initHome() {
+ int i;
+ char buf[256];
+
+ mkdir("home", 0755);
+ strcpy(buf, "home/?");
+ for(i = 0; i < 26; i++) {
+ buf[5] = 'A' + i;
+ mkdir(buf, 0755);
+ buf[5] = 'a' + i;
+ mkdir(buf, 0755);
+ }
+}
+
+static void initPasswds() {
+ int i;
+ userec_t u;
+ FILE *fp = fopen(".PASSWDS", "w");
+
+ memset(&u, 0, sizeof(u));
+ if(fp) {
+ for(i = 0; i < MAX_USERS; i++)
+ fwrite(&u, sizeof(u), 1, fp);
+ fclose(fp);
+ }
+}
+
+static void newboard(FILE *fp, boardheader_t *b) {
+ char buf[256];
+
+ fwrite(b, sizeof(boardheader_t), 1, fp);
+ sprintf(buf, "boards/%s", b->brdname);
+ mkdir(buf, 0755);
+ sprintf(buf, "man/boards/%s", b->brdname);
+ mkdir(buf, 0755);
+}
+
+static void initBoards() {
+ FILE *fp = fopen(".BOARDS", "w");
+ boardheader_t b;
+
+ if(fp) {
+ memset(&b, 0, sizeof(b));
+
+ strcpy(b.brdname, "SYSOP");
+ strcpy(b.title, "¼T­ù ¡·¯¸ªø¦n!");
+ b.brdattr = BRD_POSTMASK | BRD_NOTRAN | BRD_NOZAP;
+ b.level = 0;
+ b.gid = 2;
+
+ newboard(fp, &b);
+ strcpy(b.brdname, "1...........");
+ strcpy(b.title, ".... £U¤¤¥¡¬F©² ¡m°ªÀ£¦MÀI,«D¤H¥i¼Ä¡n");
+ b.brdattr = BRD_GROUPBOARD;
+ b.level = PERM_SYSOP;
+ b.gid = 1;
+ newboard(fp, &b);
+
+ strcpy(b.brdname, "junk");
+ strcpy(b.title, "µo¹q ¡·Âø¤CÂø¤Kªº©U§£");
+ b.brdattr = BRD_NOTRAN;
+ b.level = PERM_SYSOP;
+ b.gid = 2;
+ newboard(fp, &b);
+
+ strcpy(b.brdname, "Security");
+ strcpy(b.title, "µo¹q ¡·¯¸¤º¨t²Î¦w¥þ");
+ b.brdattr = BRD_NOTRAN;
+ b.level = PERM_SYSOP;
+ b.gid = 2;
+ newboard(fp, &b);
+
+ strcpy(b.brdname, "2...........");
+ strcpy(b.title, ".... £U¥«¥Á¼s³õ ³ø§i ¯¸ªø £­¡I");
+ b.brdattr = BRD_GROUPBOARD;
+ b.level = 0;
+ b.gid = 1;
+ newboard(fp, &b);
+
+ strcpy(b.brdname, "ALLPOST");
+ strcpy(b.title, "¼T­ù ¡·¸óªO¦¡LOCAL·s¤å³¹");
+ b.brdattr = BRD_POSTMASK | BRD_NOTRAN;
+ b.level = PERM_SYSOP;
+ b.gid = 5;
+ newboard(fp, &b);
+
+ strcpy(b.brdname, "deleted");
+ strcpy(b.title, "¼T­ù ¡·¸ê·½¦^¦¬µ©");
+ b.brdattr = BRD_NOTRAN;
+ b.level = PERM_BM;
+ b.gid = 5;
+ newboard(fp, &b);
+
+ strcpy(b.brdname, "Note");
+ strcpy(b.title, "¼T­ù ¡·°ÊºA¬ÝªO¤Îºq¦±§ë½Z");
+ b.brdattr = BRD_NOTRAN;
+ b.level = 0;
+ b.gid = 5;
+ newboard(fp, &b);
+
+ strcpy(b.brdname, "Record");
+ strcpy(b.title, "¼T­ù ¡·§Ú­Ìªº¦¨ªG");
+ b.brdattr = BRD_NOTRAN | BRD_POSTMASK;
+ b.level = 0;
+ b.gid = 5;
+ newboard(fp, &b);
+
+
+ strcpy(b.brdname, "WhoAmI");
+ strcpy(b.title, "¼T­ù ¡·¨þ¨þ¡A²q²q§Ú¬O½Ö¡I");
+ b.brdattr = BRD_NOTRAN;
+ b.level = 0;
+ b.gid = 5;
+ newboard(fp, &b);
+
+ strcpy(b.brdname, "EditExp");
+ strcpy(b.title, "¼T­ù ¡·½d¥»ºëÆF§ë½Z°Ï");
+ b.brdattr = BRD_NOTRAN;
+ b.level = 0;
+ b.gid = 5;
+ newboard(fp, &b);
+
+ fclose(fp);
+ }
+}
+
+static void initMan() {
+ FILE *fp;
+ fileheader_t f;
+ time_t t = time(NULL);
+ struct tm *tm = localtime(&t);
+
+ memset(&f, 0, sizeof(f));
+ f.savemode = 0;
+ strcpy(f.owner, "SYSOP");
+ sprintf(f.date, "%2d/%02d", tm->tm_mon + 1, tm->tm_mday);
+ f.money = 0;
+ f.filemode = 0;
+
+ if((fp = fopen("man/boards/Note/.DIR", "w"))) {
+ strcpy(f.filename, "SONGBOOK");
+ strcpy(f.title, "¡» ¡iÂI ºq ºq ¥»¡j");
+ fwrite(&f, sizeof(f), 1, fp);
+ mkdir("man/boards/Note/SONGBOOK", 0755);
+
+ strcpy(f.filename, "SONGO");
+ strcpy(f.title, "¡» <ÂIºq> °ÊºA¬ÝªO");
+ fwrite(&f, sizeof(f), 1, fp);
+ mkdir("man/boards/Note/SONGO", 0755);
+
+ strcpy(f.filename, "SYS");
+ strcpy(f.title, "¡» <¨t²Î> °ÊºA¬ÝªO");
+ fwrite(&f, sizeof(f), 1, fp);
+ mkdir("man/boards/Note/SYS", 0755);
+
+ strcpy(f.filename, "AD");
+ strcpy(f.title, "¡» <¼s§i> °ÊºA¬ÝªO");
+ fwrite(&f, sizeof(f), 1, fp);
+ mkdir("man/boards/Note/AD", 0755);
+
+ strcpy(f.filename, "NEWS");
+ strcpy(f.title, "¡» <·s»D> °ÊºA¬ÝªO");
+ fwrite(&f, sizeof(f), 1, fp);
+ mkdir("man/boards/Note/NEWS", 0755);
+
+ fclose(fp);
+ }
+
+}
+
+static void initSymLink() {
+ symlink(BBSHOME "/man/boards/Note/SONGBOOK", BBSHOME "/etc/SONGBOOK");
+ symlink(BBSHOME "/man/boards/Note/SONGO", BBSHOME "/etc/SONGO");
+ symlink(BBSHOME "/man/boards/EditExp", BBSHOME "/etc/editexp");
+}
+
+static void initHistory() {
+ FILE *fp = fopen("etc/history.data", "w");
+
+ if(fp) {
+ fprintf(fp, "0 0 0 0");
+ fclose(fp);
+ }
+}
+
+int main() {
+ if(chdir(BBSHOME)) {
+ perror(BBSHOME);
+ exit(1);
+ }
+
+ initDir();
+ initHome();
+ initPasswds();
+ initBoards();
+ initMan();
+ initSymLink();
+ initHistory();
+
+ return 0;
+}
diff --git a/util/inndBM.c b/util/inndBM.c
new file mode 100644
index 00000000..426fa6f5
--- /dev/null
+++ b/util/inndBM.c
@@ -0,0 +1,194 @@
+/* ¨Ì¾Ú .BOARDÀÉ & newsfeeds.bbs ¦C¥X°Ñ»PÂà«Hªº©Ò¦³ªO¸ê®Æ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include "config.h"
+#include "pttstruct.h"
+#define INNDHOME BBSHOME"/innd"
+
+#define INND_NEWSFEED INNDHOME "/newsfeeds.bbs"
+#define INND_NODELIST INNDHOME "/nodelist.bbs"
+#define INND_SCRIPT INNDHOME "/bbsnnrpall.auto.sh"
+
+extern bcache_t *brdshm;
+extern boardheader_t *bcache;
+extern int numboards;
+int istran[MAX_BOARD];
+
+typedef
+struct newssvr_t
+{
+ char name[30];
+ char address[256];
+ char type[10];
+}newssvr_t;
+
+typedef
+struct newsfeed_t
+{
+ char group[128];
+ char board[15];
+ char server[30];
+}newsfeed_t;
+
+newssvr_t server[128];
+newsfeed_t feedline[MAX_BOARD];
+int servercount;
+int feedcount;
+
+int newsfeed_cmp(newsfeed_t *a,newsfeed_t *b)
+{
+ int i;
+ i=strcasecmp(a->server,b->server);
+ if(i) return i;
+ return strcasecmp(a->board,b->board);
+}
+
+int get_server(char *name)
+{
+ int i;
+ for(i=0;i<servercount;i++)
+ if(!strcasecmp(server[i].name,name))
+ {return i;}
+ return -1;
+}
+
+int load_server()
+{
+ FILE *fp;
+ char str[128];
+
+ if (!(fp = fopen(INND_NODELIST, "r")))
+ {
+ return 0;
+ }
+
+ for(servercount=0; fgets(str, 128, fp); servercount++)
+ {
+ if(str[0]=='#') continue;
+ sscanf(str,"%s %s %s",server[servercount].name,
+ server[servercount].address,
+ server[servercount].type);
+ }
+ fclose(fp);
+ return servercount;
+}
+
+int load_newsfeeds()
+{
+ int bid;
+ FILE *fp;
+ char str[128];
+ if (!(fp = fopen(INND_NEWSFEED, "r")))
+ {
+ return 0;
+ }
+
+ for(feedcount=0; fgets(str, 128, fp); feedcount++)
+ {
+ if(str[0]=='#') continue;
+ sscanf(str,"%s %s %s",
+ feedline[feedcount].group,feedline[feedcount].board,
+ feedline[feedcount].server);
+ bid=getbnum(feedline[feedcount].board);
+ if(!bid) {feedcount--;continue; /*²¾°£¨S¦³ªº¬ÝªOi*/}
+ strcpy(feedline[feedcount].board,bcache[bid-1].brdname);
+ /*®Õ¥¿¤j¤p¼g */
+
+ istran[bid-1]=1;
+
+ }
+ fclose(fp);
+ qsort(feedline, feedcount, sizeof(newsfeed_t), newsfeed_cmp);
+ return feedcount;
+}
+int dobbsnnrp(char *serverstr, int serverid,FILE *fpscript)
+{
+ char buf[256];
+ printf("set %s\r\n",serverstr);
+ strtok(serverstr,";\r\n");
+ strtok(server[serverid].address,";\r\n"); //¨¾hack
+ sprintf(buf,INNDHOME"/bbsnnrp -c %s "
+ INNDHOME"/active/%s.auto.active >>"
+ INNDHOME"/log/inndBM.log 2>>"
+ INNDHOME"/log/inndBM.log.err &\r\n",
+ server[serverid].address,
+ serverstr);
+ system(buf);
+ if(fpscript)
+ fprintf(fpscript,INNDHOME"/bbsnnrp %s "
+ INNDHOME"/active/%s.auto.active >>"
+ INNDHOME"/log/inndBM.log 2>>"
+ INNDHOME"/log/inndBM.log.err &\r\n",
+ server[serverid].address,serverstr);
+ return 0;
+}
+int main()
+{
+ int i,serverid=0;
+ FILE *fp=NULL,*fpscript=fopen(INND_SCRIPT,"w");
+ char buf[256],serverstr[30]="";
+ resolve_boards();
+ memset(istran,0,sizeof(int)*MAX_BOARD);
+ load_server();
+ load_newsfeeds();
+
+ for(i=0;i<feedcount;i++)
+ {
+ if(strcasecmp(serverstr,feedline[i].server))
+ {
+ if(get_server(feedline[i].server)==-1) continue;
+ if(fp) {
+ fclose(fp);
+ dobbsnnrp(serverstr,serverid,fpscript);
+ }
+ strcpy(serverstr,feedline[i].server);
+ serverid=get_server(feedline[i].server);
+ sprintf(buf,INNDHOME"/active/%s.auto.active",serverstr);
+ fp=fopen(buf,"w");
+ }
+ if(fp)
+ fprintf(fp,"%-35s 0000000000 0000000000 y\r\n",feedline[i].group);
+ }
+ if(fp)
+ {
+ dobbsnnrp(serverstr,serverid,fpscript);
+ fclose(fp);
+ }
+ if(fpscript)
+ {
+ fclose(fpscript);
+ chmod(INND_SCRIPT,0700);
+ }
+
+ // ­«³]Âà«H»P¤£Âà«Hª©¼Ð°O
+ for(i=0;i<numboards;i++)
+ {
+ if(bcache[i].brdname[0]=='\0' ||
+ (bcache[i].brdattr & BRD_GROUPBOARD) ) continue;
+ if((bcache[i].brdattr & BRD_NOTRAN )&& istran[i])
+ {
+ while(brdshm->busystate) {safe_sleep(1);}
+ brdshm->busystate = 1;
+ bcache[i].brdattr = bcache[i].brdattr & ~BRD_NOTRAN;
+ strncpy(bcache[i].title + 5, "¡´", 2);
+ brdshm->busystate = 0;
+
+ substitute_record(BBSHOME"/.BOARDS", &bcache[i],sizeof(boardheader_t),i+1);
+ }
+ else if(!(bcache[i].brdattr & BRD_NOTRAN) && !istran[i])
+ {
+ while(brdshm->busystate) {safe_sleep(1);}
+ brdshm->busystate = 1;
+ bcache[i].brdattr = bcache[i].brdattr | BRD_NOTRAN;
+ strncpy(bcache[i].title + 5, "¡·", 2);
+ brdshm->busystate = 0;
+ substitute_record(BBSHOME"/.BOARDS", &bcache[i],sizeof(boardheader_t),i+1);
+ }
+
+ }
+ return 0;
+}
diff --git a/util/jungo.c b/util/jungo.c
new file mode 100644
index 00000000..15096b30
--- /dev/null
+++ b/util/jungo.c
@@ -0,0 +1,202 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+#include "perm.h"
+#include "common.h"
+
+#define OUTFILE BBSHOME "/etc/toplazyBBM"
+#define FIREFILE BBSHOME "/etc/topfireBBM"
+
+extern boardheader_t *bcache;
+extern int numboards;
+
+boardheader_t allbrd[MAX_BOARD];
+extern userec_t xuser;
+typedef struct lostbm {
+ char *bmname;
+ char *title;
+ char *ctitle;
+ int lostdays;
+} lostbm;
+lostbm lostbms[MAX_BOARD];
+
+typedef struct BMarray{
+ char *bmname;
+ int flag;
+} BMArray;
+BMArray bms[3];
+
+int bmlostdays_cmp(const void *va, const void *vb)
+{
+ lostbm *a=(lostbm *)va, *b=(lostbm *)vb;
+ if (a->lostdays > b->lostdays) return -1;
+ else if (a->lostdays == b->lostdays) return 0;
+ else return 1;
+}
+
+int LINK(char* src, char* dst){
+ char cmd[200];
+ if(symlink(src,dst) == -1)
+ {
+ sprintf(cmd, "/bin/cp -R %s %s", src, dst);
+ return system(cmd);
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int bmid, i, j=0;
+ FILE *inf, *firef;
+
+ resolve_boards();
+
+ if(passwd_mmap())
+ exit(1);
+
+ memcpy(allbrd,bcache,numboards*sizeof(boardheader_t));
+
+ /* write out the target file */
+
+ inf = fopen(OUTFILE, "w+");
+ if(inf == NULL){
+ printf("open file error : %s\n", OUTFILE);
+ exit(1);
+ }
+ firef = fopen(FIREFILE, "w+");
+ if(firef == NULL){
+ printf("open file error : %s\n", FIREFILE);
+ fclose(inf);
+ exit(1);
+ }
+
+ fprintf(inf, "ĵ§i: ¤p²Õªø­Y©ó¤@­Ó¤ë¥¼¤W¯¸,±N¤©©ó§K¾\n");
+ fprintf(inf,
+ "¬ÝªO¦WºÙ "
+ " ¤p²Õªø ´X¤Ñ¨S¨Ó°Õ\n"
+ "---------------------------------------------------"
+ "-------------------\n");
+
+ fprintf(firef, "§K¾¤p²Õªø\n");
+ fprintf(firef,
+ "¬ÝªO¦WºÙ "
+ " ¤p²Õªø ´X¤Ñ¨S¨Ó°Õ\n"
+ "---------------------------------------------------"
+ "-------------------\n");
+
+
+ j = 0 ;
+ for (i = 0; i < numboards; i++) {
+ char *p, bmbuf[IDLEN * 3 + 3];
+ int index = 0, flag = 0, k, n;
+ p=strtok(allbrd[i].BM,"/ ");
+ if(p)
+ do
+ {
+ if(allbrd[i].brdname[0] == '\0' || (allbrd[i].brdattr & BRD_GROUPBOARD) ==0 ) continue;
+ if (*p == '[' ){p[strlen(p)-1]='\0'; p++;}
+ bmid=getuser(p);
+ bms[index].bmname = p;
+ bms[index].flag = 0;
+ if (((((int)time(NULL)-(int)xuser.lastlogin)/(60*60*24))>=7)
+ //&& isalpha(allbrd[i].brdname[0])
+ && isalpha(allbrd[i].BM[0])
+ && !(xuser.userlevel & PERM_SYSOP))
+ {
+ lostbms[j].bmname = p;
+ lostbms[j].title = allbrd[i].brdname;
+ lostbms[j].ctitle = allbrd[i].title;
+ lostbms[j].lostdays =
+ ((int)time(NULL)-(int)xuser.lastlogin)/(60*60*24);
+
+ printf("%s\n", lostbms[j].title);
+ //¶W¹L¤»¤Q¤Ñ §K¾
+ if(lostbms[j].lostdays > 30){
+ xuser.userlevel &= ~PERM_BM;
+ bms[index].flag = 1;
+ flag = 1;
+ }
+ j++;
+ }
+ index++;
+ } while((p=strtok(NULL,"/ "))!=NULL);
+
+ //±qª©¥D¦W³æ®³±¼¦W¦r
+
+ if(flag == 1){
+ bmbuf[0] = '\0';
+ for(k = 0 , n = 0; k < index; k++){
+ if(!bms[k].flag){
+ if( n++ != 0) strcat(bmbuf, "/");
+ strcat(bmbuf, bms[k].bmname);
+ }
+ }
+ strcpy(bcache[i].BM, bmbuf);
+ }
+
+ }
+ qsort(lostbms, j, sizeof(lostbm), bmlostdays_cmp);
+
+ //write to the etc/toplazyBBM
+ for ( i=0; i<j; i++)
+ {
+ if( lostbms[i].lostdays > 7){
+ fprintf(firef, "%-*.*s%-*.*s%-*.*s%3d¤Ñ¨S¤W¯¸\n", IDLEN, IDLEN, lostbms[i].title,
+ BTLEN-10, BTLEN-10, lostbms[i].ctitle, IDLEN,IDLEN,
+ lostbms[i].bmname,lostbms[i].lostdays);
+ }else{
+ fprintf(inf, "%-*.*s%-*.*s%-*.*s%3d¤Ñ¨S¤W¯¸\n", IDLEN, IDLEN, lostbms[i].title,
+ BTLEN-10, BTLEN-10, lostbms[i].ctitle, IDLEN,IDLEN,
+ lostbms[i].bmname,lostbms[i].lostdays);
+ }
+ }
+ fclose(inf);
+ fclose(firef);
+
+ //printf("Total %d boards.\n", count);
+
+ //mail to the users
+ for( i=0; i<j; i++)
+ {
+ fileheader_t mymail;
+ char genbuf[200];
+ int lostdays;
+
+ lostdays = lostbms[i].lostdays;
+
+ if( (lostdays != 14) || (lostdays != 21) ) // 14 21 ¤Ñ¤£µo«H
+ continue;
+
+ sprintf(genbuf, BBSHOME "/home/%c/%s", lostbms[i].bmname[0], lostbms[i].bmname);
+ stampfile(genbuf, &mymail);
+
+ strcpy(mymail.owner, "[PTTĵ¹î§½]");
+
+ if(lostdays <= 60){
+ sprintf(mymail.title,
+ "\033[32m [¤p²Õªø§K¾ĵ§i³qª¾] \033[m %s BM %s", lostbms[i].title, lostbms[i].bmname);
+ }else{
+ sprintf(mymail.title,
+ "\033[32m [¤p²Õªø§K¾³qª¾] \033[m %s BM %s", lostbms[i].title, lostbms[i].bmname);
+ }
+ mymail.savemode = 0 ;
+ unlink(genbuf);
+ if(lostdays <= 60){
+ LINK(OUTFILE, genbuf);
+ }else{
+ LINK(FIREFILE, genbuf);
+ }
+
+ sprintf(genbuf, BBSHOME "/home/%c/%s/.DIR", lostbms[i].bmname[0], lostbms[i].bmname);
+ append_record(genbuf, &mymail, sizeof(mymail));
+ }
+
+ return 0;
+}
diff --git a/util/kenben.c b/util/kenben.c
new file mode 100644
index 00000000..5733f4da
--- /dev/null
+++ b/util/kenben.c
@@ -0,0 +1,44 @@
+#include <stdio.h>
+
+
+void main()
+{
+ FILE * fin, * fout;
+ char line[255], line2[255];
+ int i;
+ char genbuf[255], tok[20];
+ fin = fopen("M.1006277896.A","r");
+ while(!feof(fin))
+ {
+ fgets(line,255,fin);
+ line[12] = '\0';
+
+ sprintf(genbuf, "cd ~/boards/%s;grep "
+ "¶W¹L¤@­Ó¤ëµL¼s§i¥H¥~ªº¥»¯¸¤å³¹µoªí¡C"
+ " *.A > ~/pttbbs/util/kenken.txt",line);
+ system(genbuf);
+
+ fout = fopen("kenken.txt","r");
+ while(!feof(fout))
+ {
+ line2[0] = '\0';
+ fgets(line2,255,fout);
+ if(strlen(line2) <= 10) break;
+ sscanf(line2,"%s:",tok);
+ for(i = 0; i < 20;i++)
+ {
+ if(tok[i] == ':')
+ {
+ tok[i] = '\0';
+ break;
+ }
+ }
+ sprintf(genbuf, "cd ~/boards/%s;rm %s",line, tok);
+// printf("%s \n", genbuf);
+ system(genbuf);
+ }
+ }
+
+ fclose(fin);
+
+}
diff --git a/util/mailog.sh b/util/mailog.sh
new file mode 100644
index 00000000..da89ae3d
--- /dev/null
+++ b/util/mailog.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+# $Id: mailog.sh,v 1.1 2002/03/07 15:13:46 in2 Exp $
+#
+# ¾ã²z¥X¼s§i«H¦W³æ
+
+bin/antispam
+bin/post Record ¤µ¤é¹Hªk¼s§i«H¦W³æ [Pttĵ¹î§½] etc/spam
+bin/post Security ¯¸¥~¨Ó«H¬ö¿ýmailog [¨t²Î¦w¥þ§½] etc/mailog
+rm etc/mailog
diff --git a/util/mandex.c b/util/mandex.c
new file mode 100644
index 00000000..9373f814
--- /dev/null
+++ b/util/mandex.c
@@ -0,0 +1,263 @@
+/* $Id: mandex.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+
+/*
+ target : ºëµØ°Ï¯Á¤Þµ{¦¡ (man index)
+
+ syntax : mandex [board]
+ [board] ¦³­È ==> ¥u¶]¸Ó board
+ ªÅªº ==> ©Ò¦³ªº boards ³£¶]
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+extern int numboards;
+extern boardheader_t *bcache;
+
+char color[4][10] =
+{"", "", "", ""};
+char fn_index[] = ".index";
+char fn_new[] = ".index.new";
+char index_title[] = "¡· ºëµØ°Ï¥Ø¿ý¯Á¤Þ";
+FILE *fndx;
+int ndir;
+int nfile;
+int index_pos;
+char topdir[128], pgem[512], pndx[512];
+
+int nb = 0; /* board ¼Æ */
+
+struct boardinfo
+{
+ char bname[40];
+ int ndir;
+ int nfile;
+ int k;
+};
+typedef struct boardinfo boardinfo;
+
+boardinfo
+board[MAX_BOARD];
+
+int k_cmp(b, a)
+ boardinfo *b, *a;
+{
+ return ((a->k / 100 + a->ndir + a->nfile) - (b->k / 100 + b->ndir + b->nfile));
+}
+
+int dashd(fname)
+ char *fname;
+{
+ struct stat st;
+
+ return (stat(fname, &st) == 0 && S_ISDIR(st.st_mode));
+}
+
+
+/* visit the hierarchy recursively */
+
+void
+mandex(level, num_header, fpath)
+ int level;
+ char *fpath, *num_header;
+{
+ FILE *fgem;
+ char *fname, buf[256];
+ struct stat st;
+ int count;
+ fileheader_t fhdr;
+
+ fgem = fopen(fpath, "r+");
+ if (fgem == NULL)
+ return;
+
+ fname = strrchr(fpath, '.');
+ if (!level)
+ {
+
+ printf("%s\r\n",fpath);
+ strcpy(pgem, fpath);
+
+ strcpy(fname, fn_new);
+ fndx = fopen(fpath, "w");
+ if (fndx == NULL)
+ {
+ fclose(fgem);
+ return;
+ }
+ fprintf(fndx, "§Ç¸¹\t\t\tºëµØ°Ï¥DÃD\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¢w¢w\n");
+ strcpy(pndx, fpath);
+ ndir = nfile = 0;
+ index_pos = -1;
+ }
+
+ count = 0;
+ while (fread(&fhdr, sizeof(fhdr), 1, fgem) == 1)
+ {
+ strcpy(fname, fhdr.filename);
+ if (!fname[0]) continue;
+ if (!level && !strncmp(fhdr.title, index_title, strlen(index_title))
+ && index_pos < 0)
+ {
+ index_pos = count;
+ unlink(fpath);
+ }
+ st.st_size = 0;
+ stat(fpath, &st);
+
+ sprintf(buf, "%.*s%s%3d. %s \n",
+
+ 11 * level, num_header, color[level % 4], ++count, fhdr.title); /* Ptt */
+ fputs(buf, fndx);
+ if (dashd(fpath))
+ {
+ ++ndir;
+ if (*fhdr.title != '#' && level < 10)
+ {
+ strcat(fpath, "/.DIR");
+ mandex(level + 1, buf, fpath);
+ }
+ }
+ else
+ ++nfile;
+ }
+
+ if (!level)
+ {
+ char lpath[MAXPATHLEN];
+
+ fclose(fndx);
+ strcpy(fname, fn_index);
+ rename(pndx, fpath);
+ strcpy(pndx, fpath);
+
+ sprintf(buf, "%s.new", pgem);
+ if (index_pos >= 0 || (fndx = fopen(buf, "w")))
+ {
+ fname[-1] = 0;
+ stamplink(fpath, &fhdr);
+ unlink(fpath);
+ strcpy(fhdr.owner, "¨C¤Ñ¦Û°Ê§ó·s");
+ sprintf(lpath, "%s/%s", topdir, pndx);
+ st.st_size = 0;
+ stat(lpath, &st);
+ sprintf(fhdr.title, "%s (%.1fk)", index_title, st.st_size / 1024.);
+ board[nb].k = st.st_size; /* Ptt */
+ printf("(%d)[%dK]", nb, board[nb].k);
+ symlink(lpath, fpath);
+ if (index_pos < 0)
+ {
+ fwrite(&fhdr, sizeof(fhdr), 1, fndx);
+ rewind(fgem);
+ while (fread(&fhdr, sizeof(fhdr), 1, fgem) == 1)
+ fwrite(&fhdr, sizeof(fhdr), 1, fndx);
+ fclose(fndx);
+ fclose(fgem);
+ rename(buf, pgem);
+ }
+ else
+ {
+ fseek(fgem, index_pos * sizeof(fhdr), 0);
+ fwrite(&fhdr, sizeof(fhdr), 1, fgem);
+ fclose(fgem);
+ }
+ return;
+ }
+ }
+ fclose(fgem);
+}
+
+
+int main(int argc, char* argv[]){
+ boardheader_t *bptr;
+ DIR *dirp;
+ struct dirent *de;
+ int ch, n;
+ int place = 0;
+ char *fname, fpath[MAXPATHLEN];
+
+ resolve_boards();
+ nb = 0;
+ if(argc == 1){
+ puts("Creating the whole index...");
+ chdir(strcpy(topdir, BBSHOME));
+ strcpy(fpath, "man/.DIR");
+ mandex(0, "", fpath);
+ }
+
+
+ chdir(strcpy(topdir, BBSHOME "/man/boards"));
+
+ if(argc > 1) {
+ sprintf(fpath, "%s/.DIR", argv[1]);
+ mandex(0, "", fpath);
+ exit(0);
+ }
+
+ /* process all boards */
+
+ if(!(dirp = opendir(topdir))) {
+ printf("## unable to enter [man/boards]\n");
+ exit(-1);
+ }
+
+ while((de = readdir(dirp))){
+ fname = de->d_name;
+ ch = fname[0];
+ if (ch != '.'){
+ board[nb].k = 0;
+ strcpy(board[nb].bname, fname);
+ sprintf(fpath, "%s/.DIR", fname);
+ mandex(0, "", fpath);
+ printf("%-14sd: %d\tf: %d\n", fname, ndir, nfile); /* report */
+ board[nb].ndir = ndir;
+ board[nb].nfile = nfile;
+ if (board[nb].k)
+ nb++;
+ }
+ }
+ closedir(dirp);
+
+ qsort(board, nb, sizeof(boardinfo), k_cmp);
+
+ if (!(fndx = fopen(BBSHOME "/etc/topboardman", "w")))
+ exit(0);
+
+ fprintf(fndx, "±Æ¦W ¬Ý ª© ¥Ø¿ý¼Æ ÀÉ®×¼Æ"
+ " byte¼Æ  Á` ¤À ª© ¥D \n");
+
+ for (ch = 0; ch < nb; ch++){
+ for (n = 0; n < numboards; n++){
+ bptr = &bcache[n];
+ if (!strcmp(bptr->brdname, board[ch].bname))
+ break;
+ }
+ if (n >= numboards ||
+ (bptr->brdattr & (BRD_BAD | BRD_NOCOUNT | BRD_HIDE)))
+ continue;
+ if (board[ch].ndir + board[ch].nfile < 5)
+ break;
+ fprintf(fndx, "%3d.%15s %5d %7d %10d %6d %-24.24s\n",
+ ++place,
+ board[ch].bname,
+ board[ch].ndir, board[ch].nfile, board[ch].k
+ ,board[ch].k / 100 + board[ch].nfile + board[ch].ndir
+ ,bptr->BM);
+ }
+ fclose(fndx);
+ exit(0);
+}
diff --git a/util/merge_board.c b/util/merge_board.c
new file mode 100644
index 00000000..743ffc14
--- /dev/null
+++ b/util/merge_board.c
@@ -0,0 +1,106 @@
+/* $Id: merge_board.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+
+typedef struct hash_t {
+ char *brdname;
+ struct hash_t *next;
+} hash_t;
+
+FILE *fout;
+hash_t *hash_tbl[65536];
+int counter;
+
+void usage() {
+ fprintf(stderr, "Usage:\n\n"
+ "merge_board <output file> [input file1] [input file2] ...\n");
+}
+
+unsigned int string_hash(unsigned char *s) {
+ unsigned int v=0;
+
+ while(*s) {
+ v = (v << 8) | (v >> 24);
+ v ^= toupper(*s++); /* note this is case insensitive */
+ }
+ return (v * 2654435769UL) >> (32 - 16);
+}
+
+int is_exist(char *brdname) {
+ int i;
+ hash_t *n;
+
+ i = string_hash(brdname);
+ for(n = hash_tbl[i]; n != NULL; n = n->next)
+ if(strcasecmp(brdname, n->brdname) == 0)
+ return 1;
+ return 0;
+}
+
+void add_hash(char *brdname) {
+ int i;
+ hash_t *n;
+
+ i = string_hash(brdname);
+
+ n = malloc(sizeof(*n));
+ n->brdname = strdup(brdname);
+ n->next = hash_tbl[i];
+ hash_tbl[i] = n;
+}
+
+void merge_board(boardheader_t *b) {
+ if(!is_exist(b->brdname)) {
+ fwrite(b, sizeof(*b), 1, fout);
+ add_hash(b->brdname);
+ ++counter;
+ }
+}
+
+void merge_file(char *fname) {
+ FILE *fin;
+ boardheader_t b;
+
+ if((fin = fopen(fname, "r")) == NULL) {
+ perror(fname);
+ return;
+ }
+
+ counter = 0;
+ while(fread(&b, sizeof(b), 1, fin) == 1)
+ if(b.brdname[0])
+ merge_board(&b);
+
+ printf("merge from %s: %d boards\n", fname, counter);
+
+ fclose(fin);
+}
+
+int main(int argc, char **argv) {
+ int i;
+
+ if(argc < 2) {
+ usage();
+ return 1;
+ }
+
+ bzero(hash_tbl, sizeof(hash_tbl));
+
+ if((fout = fopen(argv[1], "w")) == NULL) {
+ perror(argv[1]);
+ return 2;
+ }
+
+ for(i = 2; i < argc; ++i)
+ merge_file(argv[i]);
+
+ fclose(fout);
+ printf("Done\n");
+
+ return 0;
+}
diff --git a/util/merge_passwd.c b/util/merge_passwd.c
new file mode 100644
index 00000000..d27c473b
--- /dev/null
+++ b/util/merge_passwd.c
@@ -0,0 +1,106 @@
+/* $Id: merge_passwd.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+
+typedef struct hash_t {
+ char *userid;
+ struct hash_t *next;
+} hash_t;
+
+FILE *fout;
+hash_t *hash_tbl[65536];
+int counter;
+
+void usage() {
+ fprintf(stderr, "Usage:\n\n"
+ "merge_passwd <output file> [input file1] [input file2] ...\n");
+}
+
+unsigned int string_hash(unsigned char *s) {
+ unsigned int v=0;
+
+ while(*s) {
+ v = (v << 8) | (v >> 24);
+ v ^= toupper(*s++); /* note this is case insensitive */
+ }
+ return (v * 2654435769UL) >> (32 - 16);
+}
+
+int is_exist(char *userid) {
+ int i;
+ hash_t *n;
+
+ i = string_hash(userid);
+ for(n = hash_tbl[i]; n != NULL; n = n->next)
+ if(strcasecmp(userid, n->userid) == 0)
+ return 1;
+ return 0;
+}
+
+void add_hash(char *userid) {
+ int i;
+ hash_t *n;
+
+ i = string_hash(userid);
+
+ n = malloc(sizeof(*n));
+ n->userid = strdup(userid);
+ n->next = hash_tbl[i];
+ hash_tbl[i] = n;
+}
+
+void merge_user(userec_t *u) {
+ if(!is_exist(u->userid)) {
+ fwrite(u, sizeof(*u), 1, fout);
+ add_hash(u->userid);
+ ++counter;
+ }
+}
+
+void merge_file(char *fname) {
+ FILE *fin;
+ userec_t u;
+
+ if((fin = fopen(fname, "r")) == NULL) {
+ perror(fname);
+ return;
+ }
+
+ counter = 0;
+ while(fread(&u, sizeof(u), 1, fin) == 1)
+ if(u.userid[0])
+ merge_user(&u);
+
+ printf("merge from %s: %d users\n", fname, counter);
+
+ fclose(fin);
+}
+
+int main(int argc, char **argv) {
+ int i;
+
+ if(argc < 2) {
+ usage();
+ return 1;
+ }
+
+ bzero(hash_tbl, sizeof(hash_tbl));
+
+ if((fout = fopen(argv[1], "w")) == NULL) {
+ perror(argv[1]);
+ return 2;
+ }
+
+ for(i = 2; i < argc; ++i)
+ merge_file(argv[i]);
+
+ fclose(fout);
+ printf("Done\n");
+
+ return 0;
+}
diff --git a/util/opendice.sh b/util/opendice.sh
new file mode 100644
index 00000000..767e213a
--- /dev/null
+++ b/util/opendice.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+# $Id: opendice.sh,v 1.1 2002/03/07 15:13:46 in2 Exp $
+
+bin/countalldice > etc/dice.dis
+bin/post Record "»ë¤l¤¤¼ú¦W³æ" "[»ë¤l³ø§i]" etc/windice.log
+bin/post Security "»ë¤l¥¢±Ñ¦W³æ" "[»ë¤l³ø§i]" etc/lostdice.log
+bin/post Security "»ë¤l´Á±æ­È" "[»ë¤l³ø§i]" etc/dice.dis
+rm -f etc/windice.log
+rm -f etc/lostdice.log
+rm -f etc/dice.dis
diff --git a/util/openticket.c b/util/openticket.c
new file mode 100644
index 00000000..69b9ab2a
--- /dev/null
+++ b/util/openticket.c
@@ -0,0 +1,198 @@
+/* $Id: openticket.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+/* ¶}¼úªº utility */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "util.h"
+
+
+static char *betname[8] = {"Ptt", "Jaky", "Action", "Heat",
+ "DUNK", "Jungo", "waiting", "wofe"};
+
+#define MAX_DES 7 /* ³Ì¤j«O¯d¼ú¼Æ */
+
+extern userec_t xuser;
+
+int Link(char *src, char *dst)
+{
+ char cmd[200];
+
+ if (link(src, dst) == 0)
+ return 0;
+
+ sprintf(cmd, "/bin/cp -R %s %s", src, dst);
+ return system(cmd);
+}
+
+char *
+ Cdatelite(clock)
+time_t *clock;
+{
+ static char foo[18];
+ struct tm *mytm = localtime(clock);
+
+ strftime(foo, 18, "%D %T", mytm);
+ return (foo);
+}
+
+
+int main()
+{
+ int money, bet, n, total = 0, ticket[8] =
+ {0, 0, 0, 0, 0, 0, 0, 0};
+ FILE *fp;
+ time_t now = time(NULL);
+ char des[MAX_DES][200] =
+ {"", "", "", ""};
+ extern struct utmpfile_t *utmpshm;
+
+ if(passwd_mmap())
+ exit(1);
+
+ rename(BBSHOME "/etc/" FN_TICKET_RECORD,
+ BBSHOME "/etc/" FN_TICKET_RECORD ".tmp");
+ rename(BBSHOME "/etc/" FN_TICKET_USER,
+ BBSHOME "/etc/" FN_TICKET_USER ".tmp");
+
+ if (!(fp = fopen(BBSHOME "/etc/"FN_TICKET_RECORD ".tmp", "r")))
+ return 0;
+ fscanf(fp, "%9d %9d %9d %9d %9d %9d %9d %9d\n",
+ &ticket[0], &ticket[1], &ticket[2], &ticket[3],
+ &ticket[4], &ticket[5], &ticket[6], &ticket[7]);
+ for (n = 0; n < 8; n++)
+ total += ticket[n];
+ fclose(fp);
+
+ if (!total)
+ return 0;
+
+ if((fp = fopen(BBSHOME "/etc/" FN_TICKET , "r")))
+ {
+ for (n = 0; n < MAX_DES && fgets(des[n], 200, fp); n++) ;
+ fclose(fp);
+ }
+
+/*
+ *srandom(33); // ©T©w¤@­Ó seed ¦ýºÉ¶q­nÁקK¸ò§O¤Hªºseed¦P
+ *
+ *for( n = (now / (60*60*3)) - 62820; n >0; n--) random();
+ */
+
+/*
+ * ¥¿½Tªºrandom number generatorªº¥Îªk
+ * ¬O¥Î¦P¤@­Ó seed«á¨ú ²Ä¤@­Ó ²Ä¤G­Ó ¦a¤T­Ó.... ¼Æ
+ * srand() ³]§¹seed«á
+ * ¨C©I¥s¤@¦¸rand()´N¨ú¤U¤@­Ó¼Æ
+ *
+ * ¦ý¦]¬°§Ú­Ì¨S¦³°O¿ý¤W¦¸¨ú¨ì²Ä´X­Ó
+ * ©Ò¥H¥Î¨C¼W¥|¤p®É()´N¦h¨ú¤@¦¸ => now / (60*60*4) (¨C¤­¤p®É¶}¤@¦¸¼ú)
+ * (´î 61820 ¬O´î¤Ö loop ¼Æ)
+ *
+ * ¥»¨Ó¬O¥Îsrand(time(0)) ¤£¬O¥¿½Tªº¥Îªk
+ * ¦]¬°¶}¼ú®É¶¡¦³³W²v ©Ò¥H·|³Q§ä¥X³W«ß
+ *
+ * ~Ptt
+ */
+/*
+ *bet=random() % 8;
+ */
+
+ resolve_utmp();
+ bet = utmpshm->number % 8;
+
+/*
+
+ * ¦bC¤¤ srand ¸ò srandom ¤@¼Ë rand ¸ò random ¤@¼Ë
+ * ¤£¦Pªº¬O rand ¬O¶Ç¦^¤@­Ó double µ¹«D¾ã¼Æªº¶Ã¼Æ¥Î
+ * random ¬O¶Ç¦^¤@­Ó int µ¹¾ã¼Æªº¶Ã¼Æ¥Î
+ *
+ * ­Y­n¥Hrand inplement ¾ã¼Æªº¶Ã¼Æ ­nª`·N¥H¤U (man page¤¤¦³)
+ *
+ * In Numerical Recipes in C: The Art of Scientific Computing
+ * (William H. Press, Brian P. Flannery, Saul A. Teukolsky,
+ * William T. Vetterling; New York: Cambridge University
+ * Press, 1990 (1st ed, p. 207)), the following comments are
+ * made:
+ * "If you want to generate a random integer between 1
+ * and 10, you should always do it by
+ *
+ * j=1+(int) (10.0*rand()/(RAND_MAX+1.0));
+ *
+ * and never by anything resembling
+ *
+ * j=1+((int) (1000000.0*rand()) % 10);
+ *
+ * (which uses lower-order bits)."
+ *
+ * Random-number generation is a complex topic. The Numeri-
+ * cal Recipes in C book (see reference above) provides an
+ * excellent discussion of practical random-number generation
+ * issues in Chapter 7 (Random Numbers).
+ * ~ Ptt
+ */
+
+
+ money = ticket[bet] ? total * 95 / ticket[bet] : 9999999;
+
+ if((fp = fopen(BBSHOME "/etc/" FN_TICKET, "w")))
+ {
+ if (des[MAX_DES - 1][0])
+ n = 1;
+ else
+ n = 0;
+
+ for (; n < MAX_DES && des[n][0] != 0; n++)
+ {
+ fprintf(fp, des[n]);
+ }
+
+ printf("\n\n¶}¼ú®É¶¡¡G %s \n\n"
+ "¶}¼úµ²ªG¡G %s \n\n"
+ "¤Uª`Á`ª÷ÃB¡G %d00 ¤¸ \n"
+ "¤¤¼ú¤ñ¨Ò¡G %d±i/%d±i (%f)\n"
+ "¨C±i¤¤¼ú±m²¼¥i±o %d ªT¢Þ¹ô \n\n",
+ Cdatelite(&now), betname[bet], total, ticket[bet], total,
+ (float) ticket[bet] / total, money);
+
+ fprintf(fp, "%s ½ä½L¶}¥X:%s Á`ª÷ÃB:%d00 ¤¸ ¼úª÷/±i:%d ¤¸ ¾÷²v:%1.2f\n",
+ Cdatelite(&now), betname[bet], total, money,
+ (float) ticket[bet] / total);
+ fclose(fp);
+
+ }
+
+ if (ticket[bet] && (fp = fopen(BBSHOME "/etc/" FN_TICKET_USER ".tmp", "r")))
+ {
+ int mybet, num, uid;
+ char userid[20], genbuf[200];
+ fileheader_t mymail;
+
+ while (fscanf(fp, "%s %d %d\n", userid, &mybet, &num) != EOF)
+ {
+ if (mybet == bet)
+ {
+ printf("®¥³ß %-15s¶R¤F%9d ±i %s, Àò±o %d ªT¢Þ¹ô\n"
+ ,userid, num, betname[mybet], money * num);
+ if((uid=getuser(userid))==0) continue;
+ deumoney(uid, money * num);
+ sprintf(genbuf, BBSHOME "/home/%c/%s", userid[0], userid);
+ stampfile(genbuf, &mymail);
+ strcpy(mymail.owner, BBSNAME);
+ sprintf(mymail.title, "[%s] ¤¤¼úÅo! $ %d", Cdatelite(&now), money * num);
+ mymail.savemode = 0;
+ unlink(genbuf);
+ Link(BBSHOME "/etc/ticket", genbuf);
+ sprintf(genbuf, BBSHOME "/home/%c/%s/.DIR", userid[0], userid);
+ append_record(genbuf, &mymail, sizeof(mymail));
+ }
+ }
+ }
+ unlink(BBSHOME "/etc/" FN_TICKET_RECORD ".tmp");
+ unlink(BBSHOME "/etc/" FN_TICKET_USER ".tmp");
+ return 0;
+}
diff --git a/util/openticket.sh b/util/openticket.sh
new file mode 100644
index 00000000..8274e5c3
--- /dev/null
+++ b/util/openticket.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+# $Id: openticket.sh,v 1.1 2002/03/07 15:13:46 in2 Exp $
+
+bin/openticket > etc/jackpot
+bin/post Record "±m¨é¤¤¼ú¦W³æ" "[½ä³õ³ø§i]" etc/jackpot
+bin/post Record "²q¼Æ¦r¤¤¼ú¦W³æ" "[²q¼Æ¦r³ø§i]" etc/winguess.log
+bin/post Record "¶Â¥Õ´Ñ¹ï¾Ô°O¿ý" "[²q¼Æ¦r³ø§i]" etc/othello.log
+rm -f etc/winguess.log
+rm -f etc/loseguess.log
+rm -f etc/othello.log
diff --git a/util/openvice.c b/util/openvice.c
new file mode 100644
index 00000000..9b5e438f
--- /dev/null
+++ b/util/openvice.c
@@ -0,0 +1,54 @@
+/* $Id: openvice.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+/* µo²¼¶}¼ú¤pµ{¦¡ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+
+#define VICE_SHOW BBSHOME "/etc/vice.show1"
+#define VICE_BINGO BBSHOME "/etc/vice.bingo"
+#define VICE_NEW "vice.new"
+#define VICE_DATA "vice.data"
+#define MAX_BINGO 99999999
+
+int main()
+{
+ char TABLE[5][3] =
+ {"¤@", "¤G", "¤T", "¥|", "¤­"};
+
+ int i = 0, bingo, base = 0;
+
+
+ FILE *fp = fopen(VICE_SHOW, "w"), *fb = fopen(VICE_BINGO, "w");
+
+ extern struct utmpfile_t *utmpshm;
+ resolve_utmp();
+
+ srand(utmpshm->number);
+
+ if (!fp || !fb )
+ perror("error open file");
+
+
+ bingo = rand() % MAX_BINGO;
+ fprintf(fp, "%1c²Î¤@µo²¼¤¤¼ú¸¹½X\n", ' ');
+ fprintf(fp, "%1c================\n", ' ');
+ fprintf(fp, "%1c¯S§O¼ú: %08d\n\n", ' ', bingo);
+ fprintf(fb, "%d\n", bingo);
+
+ while (i < 5)
+ {
+ bingo = (base + rand()) % MAX_BINGO;
+ fprintf(fp, "%1c²Ä%s¼ú: %08d\n", ' ', TABLE[i], bingo);
+ fprintf(fb, "%08d\n", bingo);
+ i++;
+ }
+ fclose(fp);
+ fclose(fb);
+ return 0;
+}
diff --git a/util/outmail.c b/util/outmail.c
new file mode 100644
index 00000000..d6b19bb4
--- /dev/null
+++ b/util/outmail.c
@@ -0,0 +1,274 @@
+/* $Id: outmail.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "config.h"
+#include "pttstruct.h"
+
+
+#ifdef HAVE_SETPROCTITLE
+
+#include <sys/types.h>
+#include <libutil.h>
+
+void initsetproctitle(int argc, char **argv, char **envp) {
+}
+
+#else
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+char **Argv = NULL; /* pointer to argument vector */
+char *LastArgv = NULL; /* end of argv */
+extern char **environ;
+
+void initsetproctitle(int argc, char **argv, char **envp) {
+ register int i;
+
+ /* Move the environment so setproctitle can use the space at
+ the top of memory. */
+ for(i = 0; envp[i]; i++);
+ environ = malloc(sizeof(char *) * (i + 1));
+ for(i = 0; envp[i]; i++)
+ environ[i] = strdup(envp[i]);
+ environ[i] = NULL;
+
+ /* Save start and extent of argv for setproctitle. */
+ Argv = argv;
+ if(i > 0)
+ LastArgv = envp[i - 1] + strlen(envp[i - 1]);
+ else
+ LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
+}
+
+static void do_setproctitle(const char *cmdline) {
+ char buf[256], *p;
+ int i;
+
+ strncpy(buf, cmdline, 256);
+ buf[255] = '\0';
+ i = strlen(buf);
+ if(i > LastArgv - Argv[0] - 2) {
+ i = LastArgv - Argv[0] - 2;
+ }
+ strcpy(Argv[0], buf);
+ p = &Argv[0][i];
+ while(p < LastArgv)
+ *p++='\0';
+ Argv[1] = NULL;
+}
+
+void setproctitle(const char* format, ...) {
+ char buf[256];
+
+ va_list args;
+ va_start(args, format);
+ vsprintf(buf, format,args);
+ do_setproctitle(buf);
+ va_end(args);
+}
+#endif
+
+
+
+
+
+#define SPOOL BBSHOME "/out"
+#define INDEX SPOOL "/.DIR"
+#define NEWINDEX SPOOL "/.DIR.sending"
+#define FROM ".bbs@" MYHOSTNAME
+#define SMTPPORT 25
+
+int waitReply(int sock) {
+ char buf[256];
+
+ if(read(sock, buf, sizeof(buf)) <= 0)
+ return -1;
+ else
+ return buf[0] - '0';
+}
+
+int sendRequest(int sock, char *request) {
+ return write(sock, request, strlen(request)) < 0 ? -1 : 0;
+}
+
+int connectMailServer() {
+ int sock;
+ struct sockaddr_in addr;
+
+ if((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+#ifdef FreeBSD
+ addr.sin_len = sizeof(addr);
+#endif
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(SMTPPORT);
+ addr.sin_addr.s_addr = inet_addr(RELAY_SERVER_IP);
+
+ if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ perror(RELAY_SERVER_IP);
+ close(sock);
+ return -1;
+ }
+
+ if(waitReply(sock) != 2) {
+ close(sock);
+ return -1;
+ }
+
+ if(sendRequest(sock, "helo " MYHOSTNAME "\n") || waitReply(sock) != 2) {
+ close(sock);
+ return -1;
+ } else
+ return sock;
+}
+
+void disconnectMailServer(int sock) {
+ sendRequest(sock, "quit\n");
+ /* drop the reply :p */
+ close(sock);
+}
+
+void doSendBody(int sock, FILE *fp, char *from, char *to, char *subject) {
+ int n;
+ char buf[2048];
+
+ n = snprintf(buf, sizeof(buf), "From: %s\nTo: %s\nSubject: %s\n\n",
+ from, to, subject);
+ write(sock, buf, n);
+
+ while(fgets(buf, sizeof(buf), fp)) {
+ if(buf[0] == '.' && buf[1] == '\n')
+ strcpy(buf, "..\n");
+ write(sock, buf, strlen(buf));
+ }
+}
+
+void doSendMail(int sock, FILE *fp, char *from, char *to, char *subject) {
+ char buf[256];
+
+ snprintf(buf, sizeof(buf), "mail from: %s\n", from);
+ if(sendRequest(sock, buf) || waitReply(sock) != 2)
+ return;
+
+ snprintf(buf, sizeof(buf), "rcpt to: %s\n", to);
+ if(sendRequest(sock, buf) || waitReply(sock) != 2)
+ return;
+
+ if(sendRequest(sock, "data\n") || waitReply(sock) != 3)
+ return;
+
+ doSendBody(sock, fp, from, to, subject);
+
+ if(sendRequest(sock, "\n.\n") || waitReply(sock) != 2)
+ return;
+}
+
+void sendMail() {
+ int fd, sock;
+ MailQueue mq;
+
+ if(access(NEWINDEX, R_OK | W_OK)) {
+ if(link(INDEX, NEWINDEX) || unlink(INDEX))
+ /* nothing to do */
+ return;
+ }
+
+ if((sock = connectMailServer()) < 0) {
+ fprintf(stderr, "connect server failed...\n");
+ return;
+ }
+
+ fd = open(NEWINDEX, O_RDONLY);
+ flock(fd, LOCK_EX);
+ while(read(fd, &mq, sizeof(mq)) > 0) {
+ FILE *fp;
+ char buf[256];
+
+ snprintf(buf, sizeof(buf), "%s%s", mq.sender, FROM);
+ if((fp = fopen(mq.filepath, "r"))) {
+ setproctitle("outmail: sending %s", mq.filepath);
+ doSendMail(sock, fp, buf, mq.rcpt, mq.subject);
+ fclose(fp);
+ unlink(mq.filepath);
+ } else {
+ perror(mq.filepath);
+ }
+ }
+ flock(fd, LOCK_UN);
+ close(fd);
+ unlink(NEWINDEX);
+
+ disconnectMailServer(sock);
+}
+
+void listQueue() {
+ int fd;
+
+ if((fd = open(INDEX, O_RDONLY)) >= 0) {
+ int counter = 0;
+ MailQueue mq;
+
+ flock(fd, LOCK_EX);
+ while(read(fd, &mq, sizeof(mq)) > 0) {
+ printf("%s:%s -> %s:%s\n", mq.filepath, mq.username, mq.rcpt,
+ mq.subject);
+ counter++;
+ }
+ flock(fd, LOCK_UN);
+ close(fd);
+ printf("\nTotal: %d mails in queue\n", counter);
+ } else {
+ perror(INDEX);
+ }
+}
+
+void usage() {
+ fprintf(stderr, "usage: outmail [-qh]\n");
+}
+
+void wakeup(int s) {
+}
+
+int main(int argc, char **argv, char **envp) {
+ int ch;
+
+ signal(SIGHUP, wakeup);
+ initsetproctitle(argc, argv, envp);
+
+ if(chdir(BBSHOME))
+ return 1;
+ while((ch = getopt(argc, argv, "qh")) != -1) {
+ switch(ch) {
+ case 'q':
+ listQueue();
+ return 0;
+ default:
+ usage();
+ return 0;
+ }
+ }
+ for(;;) {
+ sendMail();
+ setproctitle("outmail: sleeping");
+ sleep(60 * 3); /* send mail every 3 minute */
+ }
+ return 0;
+}
diff --git a/util/parse_news.c b/util/parse_news.c
new file mode 100644
index 00000000..bebed3f4
--- /dev/null
+++ b/util/parse_news.c
@@ -0,0 +1,78 @@
+/* $Id: parse_news.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+
+#define NEWSDIRECT BBSHOME "/boards/newspaper"
+#define MOVIEDIRECT BBSHOME "/etc/NEWS"
+
+int main() {
+ int fd;
+ fileheader_t fh, news;
+ struct stat st;
+ register int numfiles, n;
+ FILE *fp = NULL;
+ char buf[200];
+
+ if (stat(NEWSDIRECT "/.DIR", &st) < 0)
+ return 0;
+
+ system("rm -f " MOVIEDIRECT "/*");
+ system("rm -f " MOVIEDIRECT "/.DIR");
+
+ numfiles = st.st_size / sizeof(fileheader_t);
+ n = 0;
+ if ((fd = open(NEWSDIRECT "/.DIR", O_RDONLY)) > 0)
+ {
+ lseek(fd, st.st_size - sizeof(fileheader_t), SEEK_SET);
+ while (numfiles-- && n < 100)
+ {
+ read(fd, &fh, sizeof(fileheader_t));
+ if (!strcmp(fh.owner, "CNA-News."))
+ {
+ if (!strstr(fh.title, "¬¡°Ê¹w§i") && !strstr(fh.title, "¤¤¥¡®ð¶H§½")
+ && !strstr(fh.title, "¾ú¥v¤Wªº¤µ¤Ñ") && !strstr(fh.title, "ÀY±ø·s»D¼ÐÃD")
+ && !strstr(fh.title, "Summary") && !strstr(fh.title, "¥þ²y®ð¶H¤@Äý")
+ && !strstr(fh.title, "®Õ¥¿¤½¹q"))
+ {
+ if (!(n % 10))
+ {
+ if (n)
+ {
+ fclose(fp);
+ append_record(MOVIEDIRECT "/.DIR", &news, sizeof(news));
+ }
+ strcpy(buf, MOVIEDIRECT);
+ stampfile(buf, &news);
+ sprintf(news.title, "¤¤¥¡ªÀ§Y®É·s»D %s", fh.date);
+ strcpy(news.owner, "CNA-News.");
+ news.savemode = 0;
+ if (!(fp = fopen(buf, "w")))
+ return (0);
+ fprintf(fp, " ¢w¢w¢w¢w¢w¢w¢w¢w¢w ¤¤¥¡ªÀ§Y®É·s»D (%s)¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w\n",
+ fh.date);
+ }
+ fprintf(fp, " ¢w¢w¢w¢w¢w¡º [1;3%dm%s %.*s\n",
+ (n % 6 + 4) % 7 + 1, fh.title,
+ (int)(46 - strlen(fh.title)),
+ "¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w");
+ n++;
+ printf("[%d]\n", n);
+
+ }
+ }
+ lseek(fd, -(off_t) 2 * sizeof(fileheader_t), SEEK_CUR);
+ }
+ close(fd);
+ fclose(fp);
+ append_record(MOVIEDIRECT "/.DIR", &news, sizeof(news));
+ }
+ return 0;
+}
diff --git a/util/post.c b/util/post.c
new file mode 100644
index 00000000..efec797f
--- /dev/null
+++ b/util/post.c
@@ -0,0 +1,61 @@
+/* $Id: post.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+
+void keeplog(FILE *fin, char *fpath, char *board, char *title, char *owner) {
+ fileheader_t fhdr;
+ char genbuf[256], buf[512];
+ FILE *fout;
+ int bid;
+
+ sprintf(genbuf, BBSHOME "/boards/%s", board);
+ stampfile(genbuf, &fhdr);
+
+ if(!(fout = fopen(genbuf, "w"))) {
+ perror(genbuf);
+ return;
+ }
+
+ while(fgets(buf, 512, fin))
+ fputs(buf, fout);
+
+ fclose(fin);
+ fclose(fout);
+
+ strncpy(fhdr.title, title, sizeof(fhdr.title) - 1);
+ fhdr.title[sizeof(fhdr.title) - 1] = '\0';
+
+ strcpy(fhdr.owner, owner);
+ sprintf(genbuf, BBSHOME "/boards/%s/.DIR", board);
+ append_record(genbuf, &fhdr, sizeof(fhdr));
+ if((bid = getbnum(board)) > 0)
+ touchbtotal(bid);
+
+}
+
+int main(int argc, char **argv) {
+ FILE *fp;
+
+ resolve_boards();
+ if(argc != 5) {
+ printf("usage: %s <board name> <title> <owner> <file>\n", argv[0]);
+ return 0;
+ }
+
+ if(strcmp(argv[4], "-") == 0)
+ fp = stdin;
+ else {
+ fp = fopen(argv[4], "r");
+ if(!fp) {
+ perror(argv[4]);
+ return 1;
+ }
+ }
+ keeplog(fp, argv[4], argv[1], argv[2], argv[3]);
+ return 0;
+}
diff --git a/util/poststat.c b/util/poststat.c
new file mode 100644
index 00000000..3aa3cc94
--- /dev/null
+++ b/util/poststat.c
@@ -0,0 +1,497 @@
+/* $Id: poststat.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+/* ²Î­p¤µ¤é¡B¶g¡B¤ë¡B¦~¼öªù¸ÜÃD */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#ifdef __FreeBSD__
+#include <machine/param.h>
+#endif
+
+#include "config.h"
+#include "pttstruct.h"
+
+char *myfile[] =
+{"day", "week", "month", "year"};
+int mycount[4] =
+{7, 4, 12};
+int mytop[] =
+{10, 50, 100, 100};
+char *mytitle[] =
+{"¤é¤Q", "¶g¤­¤Q", "¤ë¦Ê", "¦~«×¦Ê"};
+
+
+#define HASHSIZE 1024
+#define TOPCOUNT 200
+
+
+struct postrec
+{
+ char author[13]; /* author name */
+ char board[13]; /* 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];
+
+
+/* 100 bytes */
+struct posttop
+{
+ char author[13]; /* author name */
+ char board[13]; /* board name */
+ char title[66]; /* title name */
+ time_t date; /* last post's date */
+ int number; /* post number */
+}
+top[TOPCOUNT], *tp;
+
+
+
+/*
+ woju
+ Cross-fs rename()
+ */
+
+int Rename(char *src, char *dst)
+{
+
+ if (rename(src, dst) == 0)
+ return 0;
+/*
+ sprintf(cmd, "/bin/mv %s %s", src, dst);
+ return system(cmd);
+*/
+ return 0;
+}
+
+
+
+/*-------------------------------------------------------*/
+/* .BOARDS cache */
+/*-------------------------------------------------------*/
+
+struct bcache_t *brdshm;
+boardheader_t *bcache;
+int numboards = -1;
+
+
+static void
+attach_err(shmkey, name)
+ int shmkey;
+ char *name;
+{
+ fprintf(stderr, "[%s error] key = %x\n", name, shmkey);
+ exit(1);
+}
+
+
+static void *
+attach_shm(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)
+ attach_err(shmkey, "shmget");
+ shmptr = (void *) shmat(shmid, NULL, 0);
+ if (shmptr == (void *) -1)
+ attach_err(shmkey, "shmat");
+ memset(shmptr, 0, shmsize);
+ }
+ else
+ {
+ shmptr = (void *) shmat(shmid, NULL, 0);
+ if (shmptr == (void *) -1)
+ attach_err(shmkey, "shmat");
+ }
+ return shmptr;
+}
+
+
+
+void
+resolve_boards()
+{
+ if (brdshm == NULL)
+ {
+ brdshm = attach_shm(BRDSHM_KEY, sizeof(*brdshm));
+ if (brdshm->touchtime == 0)
+ brdshm->touchtime = 1;
+ bcache = brdshm->bcache;
+ }
+
+ while (brdshm->uptime < brdshm->touchtime)
+ {
+ if (brdshm->busystate)
+ {
+ sleep(1);
+ }
+ else
+ {
+ int fd;
+
+ brdshm->busystate = 1;
+
+ if ((fd = open(".BOARDS", O_RDONLY)) > 0)
+ {
+ brdshm->number = read(fd, bcache, MAX_BOARD * sizeof(boardheader_t))
+ / sizeof(boardheader_t);
+ close(fd);
+ }
+
+ /* µ¥©Ò¦³ boards ¸ê®Æ§ó·s«á¦A³]©w uptime */
+
+ brdshm->uptime = brdshm->touchtime;
+ brdshm->busystate = 0;
+ }
+ }
+ numboards = brdshm->number;
+}
+
+
+int
+ci_strcmp(s1, s2)
+ register char *s1, *s2;
+{
+ register int c1, c2, diff;
+
+ do
+ {
+ c1 = *s1++;
+ c2 = *s2++;
+ if (c1 >= 'A' && c1 <= 'Z')
+ c1 |= 32;
+ if (c2 >= 'A' && c2 <= 'Z')
+ c2 |= 32;
+ if((diff = c1 - c2))
+ return (diff);
+ }
+ while (c1);
+ return 0;
+}
+
+int
+get_record(fpath, rptr, size, id)
+ char *fpath;
+ char *rptr;
+ int size, id;
+{
+ int fd;
+
+ if ((fd = open(fpath, O_RDONLY, 0)) != -1)
+ {
+ if (lseek(fd, size * (id - 1), SEEK_SET) != -1)
+ {
+ if (read(fd, rptr, size) == size)
+ {
+ close(fd);
+ return 0;
+ }
+ }
+ close(fd);
+ }
+ return -1;
+}
+
+
+int
+getbnum(bname)
+ char *bname;
+{
+ register int i;
+ register boardheader_t *bhdr;
+
+ resolve_boards();
+ for (i = 0, bhdr = bcache; i++ < numboards; bhdr++)
+ /* if (Ben_Perm(bhdr)) */
+ if (!ci_strcmp(bname, bhdr->brdname))
+ return i;
+ return 0;
+}
+
+
+int
+hash(key)
+ char *key;
+{
+ int i, value = 0;
+
+ for (i = 0; key[i] && i < 80; i++)
+ value += key[i] < 0 ? -key[i] : key[i];
+
+ value = value % HASHSIZE;
+ return value;
+}
+
+
+/* ---------------------------------- */
+/* hash structure : array + link list */
+/* ---------------------------------- */
+
+
+void
+search(t)
+ struct posttop *t;
+{
+ struct postrec *p, *q, *s;
+ int i, found = 0;
+
+ i = hash(t->title);
+ 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(struct posttop));
+ s->next = NULL;
+ if (q == NULL)
+ bucket[i] = s;
+ else
+ q->next = s;
+ }
+}
+
+
+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(struct posttop));
+
+ memcpy(&top[i], pp, sizeof(struct posttop));
+ break;
+ }
+ }
+ return count;
+}
+
+
+void
+load_stat(fname)
+ char *fname;
+{
+ FILE *fp;
+
+ if((fp = fopen(fname, "r")))
+ {
+ int count = fread(top, sizeof(struct posttop), TOPCOUNT, fp);
+ fclose(fp);
+ while (count)
+ search(&top[--count]);
+ }
+}
+
+
+int
+filter(board)
+ char *board;
+{
+ boardheader_t bh;
+ int bid;
+
+ bid = getbnum(board);
+ if (get_record(".BOARDS", &bh, sizeof(bh), bid) == -1)
+ return 1;
+ if (bh.brdattr & BRD_NOCOUNT)
+ return 1;
+/*
+ if (bh.brdattr & BRD_POSTMASK)
+ return 0;
+ return (bh.brdattr & ~BRD_POSTMASK) ||
+ >= 32;
+*/
+ return 0;
+}
+
+
+void
+poststat(mytype)
+ int mytype;
+{
+ static char *logfile = ".post";
+ static char *oldfile = ".post.old";
+
+ FILE *fp;
+ char buf[40], curfile[40] = "etc/day.0", *p;
+ struct postrec *pp;
+ int i, j;
+
+ if (mytype < 0)
+ {
+ /* --------------------------------------- */
+ /* load .post and statictic processing */
+ /* --------------------------------------- */
+
+ remove(oldfile);
+ Rename(logfile, oldfile);
+ if ((fp = fopen(oldfile, "r")) == NULL)
+ return;
+ mytype = 0;
+ load_stat(curfile);
+
+ while (fread(top, sizeof(struct posttop), 1, fp))
+ search(top);
+ fclose(fp);
+ }
+ else
+ {
+ /* ---------------------------------------------- */
+ /* load previous results and statictic processing */
+ /* ---------------------------------------------- */
+
+ i = mycount[mytype];
+ p = myfile[mytype];
+ while (i)
+ {
+ sprintf(buf, "etc/%s.%d", p, i);
+ sprintf(curfile, "etc/%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, "etc/%s.0", p);
+ if((fp = fopen(curfile, "w")))
+ {
+ fwrite(top, sizeof(struct posttop), j, fp);
+ fclose(fp);
+ }
+
+ sprintf(curfile, "etc/%s", p);
+ if((fp = fopen(curfile, "w")))
+ {
+ int max, cnt;
+
+ fprintf(fp, "\t\t-----===== ¥»%s¤j¼öªù¸ÜÃD =====-----\n\n", mytitle[mytype]);
+
+ max = mytop[mytype];
+ p = buf + 4;
+ for (i = cnt = 0; (cnt < max) && (i < j); i++)
+ {
+ tp = &top[i];
+ if (filter(tp->board))
+ continue;
+
+ strcpy(buf, ctime(&(tp->date)));
+ buf[20] = 0;
+ fprintf(fp,
+ "%3d. ¬ÝªO : %-16s¡m %s¡n%4d ½g%16s\n"
+ " ¼ÐÃD : %-60.60s\n"
+ ,++cnt, tp->board, p, tp->number, tp->author, tp->title);
+ }
+ fclose(fp);
+ }
+
+/* free statistics */
+
+ for (i = 0; i < HASHSIZE; i++)
+ {
+ struct postrec *pp0;
+
+ pp = bucket[i];
+ while (pp)
+ {
+ pp0 = pp;
+ pp = pp->next;
+ free(pp0);
+ }
+
+ bucket[i] = NULL;
+ }
+}
+
+
+int main(argc, argv)
+ char *argv[];
+{
+ time_t now;
+ struct tm *ptime;
+
+ if (argc < 2)
+ {
+ printf("Usage:\t%s bbshome [day]\n", argv[0]);
+ return (-1);
+ }
+ chdir(argv[1]);
+
+ if (argc == 3)
+ {
+ poststat(atoi(argv[2]));
+ return (0);
+ }
+ time(&now);
+ ptime = localtime(&now);
+ if (ptime->tm_hour == 0)
+ {
+ if (ptime->tm_mday == 1)
+ poststat(2);
+
+ if (ptime->tm_wday == 0)
+ poststat(1);
+ poststat(0);
+ }
+ poststat(-1);
+ return 0;
+}
diff --git a/util/reaper.c b/util/reaper.c
new file mode 100644
index 00000000..925ea11b
--- /dev/null
+++ b/util/reaper.c
@@ -0,0 +1,69 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "perm.h"
+#include "util.h"
+
+time_t now;
+
+int invalid(char *userid) {
+ int i;
+
+ if(!isalpha(userid[0]))
+ return 1;
+
+ for(i = 1; i < IDLEN && userid[i]; i++)
+ if(!isalpha(userid[i]) && !isdigit(userid[i]))
+ return 1;
+ return 0;
+}
+
+int check(int n, userec_t *u) {
+ time_t d;
+ char buf[256];
+
+ if(u->userid[0] != '\0') {
+ if(invalid(u->userid)) {
+ syslog(LOG_ERR, "bad userid(%d): %s", n, u->userid);
+ u->userid[0] = '\0';
+ } else {
+ d = now - u->lastlogin;
+ if((d > MAX_GUEST_LIFE && (u->userlevel & PERM_LOGINOK) == 0) ||
+ (d > MAX_LIFE && (u->userlevel & PERM_XEMPT) == 0)) {
+ /* expired */
+ int unum;
+
+ unum = searchuser(u->userid);
+ strcpy(buf, ctime(&u->lastlogin));
+ strtok(buf, "\n");
+ syslog(LOG_NOTICE, "kill user(%d): %s %s", unum, u->userid, buf);
+ sprintf(buf, "mv home/%c/%s tmp/", u->userid[0], u->userid);
+ if(system(buf))
+ syslog(LOG_ERR, "can't move user home: %s", u->userid);
+ u->userid[0] = '\0';
+ setuserid(unum, u->userid);
+ }
+ }
+ }
+ return 0;
+}
+
+int main() {
+ now = time(NULL);
+ openlog("reaper", LOG_PID | LOG_PERROR, SYSLOG_FACILITY);
+ chdir(BBSHOME);
+
+ if(passwd_mmap())
+ exit(1);
+ passwd_apply2(check);
+
+ return 0;
+}
diff --git a/util/rmuid.c b/util/rmuid.c
new file mode 100644
index 00000000..cc6e12cb
--- /dev/null
+++ b/util/rmuid.c
@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+
+extern int numboards;
+extern boardheader_t *bcache;
+
+int getbidofuid(int uid)
+{
+ register int n; boardheader_t *bh;
+ if(!uid) return 1;
+ for (n=0;n<numboards;n++)
+ {
+ bh = &bcache[n];
+ if(bh->unused == uid)
+ return n+1;
+ }
+ return 1;
+}
+
+int main(int argc, char* argv[]){
+struct stat st;
+ int n;
+ boardheader_t bh;
+ char pathname[1024];
+
+ resolve_boards();
+ for (n=0;n<numboards;n++)
+ {
+ memcpy( &bh, &bcache[n], sizeof(bh));
+ bh.gid=getbidofuid(bh.gid);
+ //printf("%14.14s%14.14s \r\n",bh.brdname, bh.title);
+ substitute_record("BOARDS.bid", &bh, sizeof(bh), n+1);
+ }
+}
+
+
+
+
+
+
+
diff --git a/util/shmsweep.c b/util/shmsweep.c
new file mode 100644
index 00000000..01acb26b
--- /dev/null
+++ b/util/shmsweep.c
@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "pttstruct.h"
+
+int main() {
+ int i, shm, counter;
+ struct utmpfile_t *utmpshm;
+
+
+ shm = shmget(UTMPSHM_KEY, USHM_SIZE, SHM_R | SHM_W);
+ if(shm == -1) {
+ perror("shmget");
+ exit(0);
+ }
+
+ utmpshm = shmat(shm, NULL, 0);
+ if(utmpshm == (struct utmpfile_t *)-1) {
+ perror("shmat");
+ exit(0);
+ }
+
+ for(i = counter = 0; i < USHM_SIZE; i++)
+ if(utmpshm->uinfo[i].pid) {
+ char buf[256];
+ userinfo_t *f;
+ struct stat sb;
+
+ f = &utmpshm->uinfo[i];
+ sprintf(buf, "/proc/%d", f->pid);
+ if(stat(buf, &sb)) {
+ f->pid = 0;
+ utmpshm->number--;
+ counter++;
+ }
+ }
+ printf("clear %d slots\n", counter);
+ return 0;
+}
diff --git a/util/showboard.c b/util/showboard.c
new file mode 100644
index 00000000..3801dbb1
--- /dev/null
+++ b/util/showboard.c
@@ -0,0 +1,70 @@
+/* $Id: showboard.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+/* ¬ÝªO¤@Äýªí(sorted) */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "config.h"
+#include "pttstruct.h"
+
+boardheader_t allbrd[MAX_BOARD];
+
+int
+board_cmp(a, b)
+ boardheader_t *a, *b;
+{
+ return (strcasecmp(a->brdname, b->brdname));
+}
+
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int inf, i, count;
+
+ if (argc < 2)
+ {
+ printf("Usage:\t%s .BOARDS [MAXUSERS]\n", argv[0]);
+ exit(1);
+ }
+
+
+ inf = open(argv[1], O_RDONLY);
+ if (inf == -1)
+ {
+ printf("error open file\n");
+ exit(1);
+ }
+
+/* read in all boards */
+
+ i = 0;
+ memset(allbrd, 0, MAX_BOARD * sizeof(boardheader_t));
+ while (read(inf, &allbrd[i], sizeof(boardheader_t)) == sizeof(boardheader_t))
+ {
+ if (allbrd[i].brdname[0] )
+ {
+ i++;
+ }
+ }
+ close(inf);
+
+/* sort them by name */
+ count = i;
+ qsort(allbrd, count, sizeof(boardheader_t), board_cmp);
+
+/* write out the target file */
+
+ printf(
+ "¬ÝªO¦WºÙ ªO¥D Ãþ§O ¤¤¤å±Ô­z\n"
+ "----------------------------------------------------------------------\n");
+ for (i = 0; i < count; i++)
+ {
+ printf("%-13s%-25.25s%s\n", allbrd[i].brdname, allbrd[i].BM, allbrd[i].title);
+ }
+ return 0;
+}
diff --git a/util/smtest.c b/util/smtest.c
new file mode 100644
index 00000000..16a2360d
--- /dev/null
+++ b/util/smtest.c
@@ -0,0 +1,296 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+#include "perm.h"
+#include "common.h"
+#include "proto.h"
+
+#define WARNFILE BBSHOME "/etc/DeleteBoard.warn"
+#define EXECFILE BBSHOME"/etc/DeleteBoard.exec"
+#define WARNLIST BBSHOME"/etc/DeleteBoardList.warn"
+#define EXECLIST BBSHOME"/etc/DeleteBoardList.exec"
+
+extern boardheader_t *bcache;
+extern int numboards;
+
+boardheader_t allbrd[MAX_BOARD];
+extern userec_t xuser;
+
+
+int LINK(char* src, char* dst){
+ char cmd[200];
+
+ if( link(src, dst) == 0){
+ return 0;
+ }
+
+ sprintf(cmd, "/bin/cp -R %s %s", src, dst);
+ return system(cmd);
+}
+
+int outofdate(char *hdrdate, char thedate[], int *zf)
+{
+ int k = 0;
+ char *dd;
+ char latestdate[6];
+ int date1[2], date2[2],datetemp;
+ *zf = 0;
+
+ strcpy(latestdate, thedate);
+
+ dd = strtok(hdrdate,"/");
+ if(dd == NULL) return 2;
+ if(dd)
+ k = 0;
+ do{
+ if (*dd == '[' ){dd[strlen(dd)-1]='\0'; dd++;}
+ date1[k] = atoi(dd);
+ k++;
+ } while((dd=strtok(NULL,"/ "))!=NULL);
+
+ dd = strtok(latestdate,"/");
+ if(dd)
+ k = 0;
+ do{
+ if (*dd == '[' ){dd[strlen(dd)-1]='\0'; dd++;}
+ date2[k] = atoi(dd);
+ k++;
+ } while((dd=strtok(NULL,"/ "))!=NULL);
+
+ if(date2[0] == date1[0] && date2[1] >= date1[1])
+ return 0;
+
+ datetemp = date2[0];
+
+ for(k = 1;k <= 5;k++)
+ {
+ datetemp -= 1;
+ if((datetemp) <= 0){
+ datetemp = 12;
+ }
+ if(k < 3 && datetemp == date1[0]) return 0;
+ if(k == 3 && datetemp == date1[0] && date2[1] <= date1[1]) return 0;
+ if(k == 3 && datetemp == date1[0] && date2[1] > date1[1]) return 1;
+ if(k == 4 && datetemp == date1[0] && date2[1] > date1[1]) return 1;
+ }
+ *zf = 1;
+ return 1;
+}
+
+void mailtouser(char *bmname, char *bname, int zf)
+{
+ fileheader_t mymail;
+ char genbuf[200];
+
+ sprintf(genbuf, BBSHOME "/home/%c/%s", bmname[0], bmname);
+ stampfile(genbuf, &mymail);
+ strcpy(mymail.owner, "[PTTĵ¹î§½]");
+
+ if(zf == 0){
+ sprintf(mymail.title,"\033[32m [¼oª©Äµ§i³qª¾]"
+ "\033[m %sª©(BM:%s)",bname, bmname);
+ }else{
+ sprintf(mymail.title,"\033[32m [¼oª©³qª¾] "
+ "\033[m %sª©(BM:%s)",bname, bmname);
+ }
+ mymail.savemode = 0 ;
+ unlink(genbuf);
+ if(zf == 0){
+ LINK(WARNFILE, genbuf);
+ }else{
+ LINK(EXECFILE, genbuf);
+ }
+
+ sprintf(genbuf, BBSHOME "/home/%c/%s/.DIR", bmname[0], bmname);
+ append_record(genbuf, &mymail, sizeof(mymail));
+}
+
+int main()
+{
+ int bmid, i, j, k, rd, ood, flag, zapflag = 0,warncount = 0,execcount = 0;
+ char *p, *bmsname[3], fname[256], hdrdatetemp[6],thedate[6];
+ char bname[32],genbuf[200];
+ fileheader_t hdr;
+ FILE *inf, *def;
+
+ ///// set date //////
+ time_t t = time(NULL);
+ struct tm *tm = localtime(&t);
+ sprintf(thedate, "%2d/%02d", tm->tm_mon + 1, tm->tm_mday);
+
+ ////// board //////
+
+ resolve_boards();
+ if(passwd_mmap())
+ exit(1);
+ memcpy(allbrd,bcache,numboards*sizeof(boardheader_t));
+
+ ////// write out the target file //////
+ inf = fopen(WARNLIST, "w+");
+ if(inf == NULL){
+ printf("open file error : %s\n", WARNLIST);
+ exit(1);
+ }
+
+ def = fopen(EXECLIST, "w+");
+ if(def == NULL)
+ {
+ printf("open file error : %s\n", EXECLIST);
+ exit(1);
+ }
+
+ ////// fprint table title /////
+ fprintf(inf,"\n[¼oª©Äµ§i]§Y¤é°_¤@­Ó¤ë¤º­Y¬ÝªO"
+ "¨Ï¥Î²v¤´µM¹L§C¡A«h¤©¥H¼o°£¡C\n\n"
+ "­^¤åª©¦W Ãþ§O ¤¤¤åª©¦W ¤é´Á "
+ " ª©¥D¦W³æ\n\n");
+
+ fprintf(def,"\n[¼oª©¤½§i]¤U¦C¬ÝªO¦]¨Ï¥Î²v¤´µM¹L§C¡A¬G¤©¥H¼o°£¡C\n\n"
+ "­^¤åª©¦W Ãþ§O ¤¤¤åª©¦W ¤é´Á "
+ " ª©¥D¦W³æ\n\n");
+
+ ////// start process /////
+ j = 0 ;
+ for (i = 0; i < numboards; i++) {
+ rd = 0;
+ if(allbrd[i].brdname[0] == '\0') continue;
+ if((allbrd[i].brdattr & BRD_NOZAP) ||
+ (allbrd[i].brdattr & BRD_GROUPBOARD) ||
+ (allbrd[i].brdattr & BRD_WARNDEL) ||
+ (allbrd[i].brdattr & BRD_HIDE) ||
+ (allbrd[i].brdattr & BRD_POSTMASK) ||
+ (allbrd[i].brdattr & BRD_VOTEBOARD) ||
+ (allbrd[i].brdattr & BRD_BAD) ||
+ (allbrd[i].level != 0)) continue;
+
+ sprintf(fname, BBSHOME "/boards/%s/.DIR",allbrd[i].brdname);
+
+ /* get date to choose junk board */
+ /* exception when ood == 2 */
+ flag = 30;
+ rd = get_num_records(fname, sizeof(fileheader_t));
+ if(rd <= 30)
+ {
+ get_record(fname, &hdr, sizeof (hdr), 1);
+ strcpy(hdrdatetemp, hdr.date);
+ ood = outofdate(hdrdatetemp,thedate, &zapflag);
+ }
+ else
+ {
+ do{
+ if(rd == 0)
+ {
+ ood = 0;
+ break;
+ }
+ get_record(fname, &hdr, sizeof (hdr), rd - flag);
+ strcpy(hdrdatetemp, hdr.date);
+ ood = outofdate(hdrdatetemp,thedate, &zapflag);
+ flag += 5;
+ }while(ood == 2 && flag < 60);
+ }
+ if(ood == 0) continue;
+
+ warncount++;
+ /* print to file */
+ fprintf(inf,"%-*.*s%-*.*s %-*.*s%-*.*s\n", IDLEN, IDLEN,
+ allbrd[i].brdname, BTLEN-26, BTLEN-26, allbrd[i].title,
+ IDLEN - 5, IDLEN-5,hdr.date, IDLEN * 3, IDLEN * 3, allbrd[i].BM);
+
+ /* post warn file to each board */
+ sprintf(genbuf,"~/bin/post %s [¼oª©Äµ§i³qª¾]"
+ " [PTTĵ¹î§½] %s",allbrd[i].brdname,WARNFILE);
+ system(genbuf);
+
+ /* user extract to mail */
+ p=strtok(allbrd[i].BM,"/ ");
+ if(p){
+ k = 0;
+ do
+ {
+ if (*p == '[' ){p[strlen(p)-1]='\0'; p++;}
+ bmid=getuser(p);
+ bmsname[k] = p;
+ if(isalpha(allbrd[i].BM[0])&& !(xuser.userlevel &PERM_SYSOP))
+ {
+ mailtouser(bmsname[k],allbrd[i].title, zapflag);
+ }
+ k++;
+ } while((p=strtok(NULL,"/ "))!=NULL);
+ }
+ /* set attribute of DeleteBoardWarn Flag */
+ bcache[i].brdattr = allbrd[i].brdattr | BRD_WARNDEL;
+
+ /* zap boards */
+ if (zapflag == 1)
+ {
+ execcount++;
+ /* print to file */
+ fprintf(def,"%-*.*s%-*.*s %-*.*s%-*.*s\n", IDLEN, IDLEN,
+ allbrd[i].brdname, BTLEN-26, BTLEN-26, allbrd[i].title,
+ IDLEN - 5, IDLEN-5,hdr.date, IDLEN * 3, IDLEN * 3, allbrd[i].BM);
+
+// strcpy(bname, allbrd[i].brdname);
+// sprintf(genbuf,
+// "/bin/tar zcvf ~/tmp/board_%s.tgz boards/%s man/%s>/dev/null 2>&1;"
+// "/bin/rm -fr ~/boards/%s man/%s",bname, bname, bname, bname,bname);
+// system(genbuf);
+
+// memset(&allbrd[i], 0, sizeof(allbrd[i]));
+// sprintf(allbrd[i].title, "[%s] deleted by System", bname);
+// substitute_record(fn_board, &bh, sizeof(allbrd[i]), bid);
+// reset_board(bid);
+ }
+
+ }
+
+ /* post to Record, ViolateLaw */
+ if(warncount > 0){
+ sprintf(genbuf,"~/bin/post Record [¼oª©Äµ§i³qª¾]"
+ " [PTTĵ¹î§½] %s",WARNLIST);
+ system(genbuf);
+ sprintf(genbuf,"~/bin/post ViolateLaw [¼oª©Äµ§i³qª¾]"
+ " [PTTĵ¹î§½] %s",WARNLIST);
+ system(genbuf);
+ }
+ if(execcount > 0){
+ sprintf(genbuf,"~/bin/post Record [¼oª©¤½§i]"
+ " [PTTĵ¹î§½] %s",EXECLIST);
+ system(genbuf);
+ sprintf(genbuf,"~/bin/post ViolateLaw [¼oª©¤½§i]"
+ " [PTTĵ¹î§½] %s",EXECLIST);
+ system(genbuf);
+ }
+
+
+/* Below is for test only */
+/*
+ mailtouser("Smile","test", 1);
+ mailtouser("Smile","test", 0);
+
+ strcpy(bname, "Test");
+ sprintf(genbuf,"~/bin/post %s test Smile ~/etc/test.fileaaa",bname);
+ system(genbuf);
+
+
+ bid = getbnum(bname);
+ strcpy(bname,"jourslamdunk");
+ sprintf(genbuf,
+ "/bin/tar zcvf ~/tmp/board_%s.tgz boards/%s man/%s>/dev/null 2>&1;"
+ "/bin/rm -fr ~/boards/%s man/%s",bname, bname, bname,bname,bname);
+ system(genbuf);
+
+ memset(&bh, 0, sizeof(bh));
+ sprintf(bh.title, "[%s] deleted by %s", bname,cuser.userid);
+ substitute_record(fn_board, &bh, sizeof(bh), bid);
+ reset_board(bid);
+*/
+ return 0;
+}
diff --git a/util/smtest.c.save b/util/smtest.c.save
new file mode 100644
index 00000000..7e678881
--- /dev/null
+++ b/util/smtest.c.save
@@ -0,0 +1,172 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+#include "perm.h"
+#include "common.h"
+#include "proto.h"
+
+#define OUTFILE BBSHOME "/pttbbs/util/smtest.result1"
+#define FIREFILE BBSHOME "/pttbbs/util/smtest.result2"
+
+extern boardheader_t *bcache;
+extern int numboards;
+
+boardheader_t allbrd[MAX_BOARD];
+struct userec_t xuser;
+
+int getuser(char *userid) {
+ int uid;
+ if((uid = searchuser(userid)))
+ passwd_query(uid, &xuser);
+ return uid;
+}
+
+int LINK(char* src, char* dst){
+ char cmd[200];
+
+ if( link(src, dst) == 0){
+ return 0;
+ }
+
+ sprintf(cmd, "/bin/cp -R %s %s", src, dst);
+ return system(cmd);
+}
+
+int main()
+{
+ int bmid, i, j, k, rd;
+ char *p, *bmsname[3], bmbuf[IDLEN * 3 + 3], fname[256];
+ fileheader_t hdr;
+ FILE *inf;
+
+ resolve_boards();
+ if(passwd_mmap())
+ exit(1);
+ memcpy(allbrd,bcache,numboards*sizeof(boardheader_t));
+
+ /* write out the target file */
+ inf = fopen(OUTFILE, "w+");
+ if(inf == NULL){
+ printf("open file error : %s\n", OUTFILE);
+ exit(1);
+ }
+
+ /*the ouput table title*/
+ fprintf(inf,"­^¤åª©¦W Ãþ§O ¤¤¤åª©¦W ª©¥D¦W³æ"
+ " ¤é´Á ³Æµù \n");
+
+ j = 0 ;
+ for (i = 0; i < 30; i++) {
+ rd = 0;
+ if(allbrd[i].brdname[0] == '\0') continue;
+
+ sprintf(fname, BBSHOME "/boards/%s/.DIR",allbrd[i].brdname);
+
+ rd = get_num_records(fname, sizeof(fileheader_t));
+ get_record(fname, &hdr, sizeof (hdr), rd - 30);
+// printf(" %s %s\n",hdr.title,hdr.date);
+
+ printf("%-*.*s%-*s%s", IDLEN, IDLEN, allbrd[i].brdname, BTLEN,
+ allbrd[i].title,allbrd[i].BM);
+
+ p=strtok(allbrd[i].BM,"/ ");
+ if(p){
+ int k = 0;
+ do
+ {
+ if (*p == '[' ){p[strlen(p)-1]='\0'; p++;}
+ bmid=getuser(p);
+ bmsname[k] = p;
+ if(isalpha(allbrd[i].BM[0])&& !(xuser.userlevel &PERM_SYSOP))
+ {
+ // printf("%s", bmsname[k]);
+ }
+ k++;
+ } while((p=strtok(NULL,"/ "))!=NULL);
+ }
+
+ printf("\n");
+
+}
+
+
+/*
+
+
+
+ if(flag == 1){
+ bmbuf[0] = '\0';
+ for(k = 0 , n = 0; k < index; k++){
+ if(!bms[k].flag){
+ if( n++ != 0) strcat(bmbuf, "/");
+ strcat(bmbuf, bms[k].bmname);
+ }
+ }
+ strcpy(bcache[i].BM, bmbuf);
+ }
+ }
+ qsort(lostbms, j, sizeof(lostbm), bmlostdays_cmp);
+
+ //write to the etc/toplazyBM
+ for ( i=0; i<j; i++)
+ {
+ if( lostbms[i].lostdays > 60){
+ fprintf(firef, "%-*.*s%-*.*s%-*.*s%3d¤Ñ¨S¤W¯¸\n", IDLEN, IDLEN,
+ lostbms[i].title, BTLEN-10, BTLEN-10, lostbms[i].ctitle, IDLEN,IDLEN,
+ lostbms[i].bmname,lostbms[i].lostdays);
+ }else{
+ fprintf(inf, "%-*.*s%-*.*s%-*.*s%3d¤Ñ¨S¤W¯¸\n", IDLEN, IDLEN, lostbms[i].title,
+ BTLEN-10, BTLEN-10, lostbms[i].ctitle, IDLEN,IDLEN,
+ lostbms[i].bmname,lostbms[i].lostdays);
+ }
+ }
+ fclose(inf);
+ fclose(firef);
+
+ //printf("Total %d boards.\n", count);
+
+ //mail to the users
+ for( i=0; i<j; i++)
+ {
+ fileheader_t mymail;
+ char genbuf[200];
+ int lostdays;
+
+ lostdays = lostbms[i].lostdays;
+
+ if( (lostdays != 30) && (lostdays != 45) && (lostdays <= 60))
+ continue;
+
+ sprintf(genbuf, BBSHOME "/home/%c/%s", lostbms[i].bmname[0], lostbms[i].bmname);
+ stampfile(genbuf, &mymail);
+
+ strcpy(mymail.owner, "[PTTĵ¹î§½]");
+
+ if(lostdays <= 60){
+ sprintf(mymail.title,
+ "\033[32m [ª©¥D§K¾ĵ§i³qª¾] \033[m %s BM %s", lostbms[i].title, lostbms[i].bmname);
+ }else{
+ sprintf(mymail.title,
+ "\033[32m [ª©¥D§K¾³qª¾] \033[m %s BM %s", lostbms[i].title, lostbms[i].bmname);
+ }
+ mymail.savemode = 0 ;
+ unlink(genbuf);
+ if(lostdays <= 60){
+ LINK(OUTFILE, genbuf);
+ }else{
+ LINK(FIREFILE, genbuf);
+ }
+
+ sprintf(genbuf, BBSHOME "/home/%c/%s/.DIR", lostbms[i].bmname[0], lostbms[i].bmname);
+ append_record(genbuf, &mymail, sizeof(mymail));
+ }
+*/
+ return 0;
+}
diff --git a/util/smtest.result1 b/util/smtest.result1
new file mode 100644
index 00000000..6dee45ff
--- /dev/null
+++ b/util/smtest.result1
@@ -0,0 +1,191 @@
+­^¤åª©¦W Ãþ§O ¤¤¤åª©¦W ¤é´Á ª©¥D¦W³æ
+ck48th301 «Ø¤¤ ¡·¤jºjÀ°¤§§Ö¼Ö¤Ñ° 3/21 ching/carl/Prosecuted
+Bowling ¹B°Ê ¡´¨«¹L2000,ÁÚ¦V30 7/18 Genson/chiche
+NTUCH-89 ¤Æ¾Ç ¡·²¦·~°Õ¡I¡I 7/10 badora/furtwangler
+SetupBBS BBS ¡·TEST://140.112. 8/08 Libra
+Fei-cat ¹Ï¤å ¡·23:56 ·L»Ä¨ý 8/07 tears
+CKAWE «Ø¤¤ ¡´«Ø¤¤®Õ¤ÍºÞ¼Ö¹Îª 7/04 ckb/papl/trumpet
+jourslamdunk«Ý¼o ¡·¬F¤j·s»D¨tÄx²y¶ 7/04 ¼x¨D¤¤
+ck48th308 «Ø¤¤ ¡·¤S­n²¦·~¤F¡I 7/15 honest
+CS84Her ¤¤¤s ¡·¦U©bªF¦è ¤]­n©M 7/20
+VM ¬P°¨ ¡´¯k¥ú¨}«~«aªº³d¥ 7/20 zoo
+E-Diagrams ®Õ¶é ¡·¤@°_¤K¨ö¤­¤d¦~. 6/29 Benjamin
+ck48th313 «Ø¤¤ ¡´ª©¥D¤£ºÞ¤F,¨ÓÄé 6/08 fantastic
+ck48th324 «Ø¤¤ ¡·«¢«¢«¢... 7/10
+B853023XX ¬Fªv ¡·¤½¦æ·s¥@¬ö 8/15 FireKing
+ck48th303 «Ø¤¤ ¡·§Lªº¥@¬É 6/05 Roses999/henrry/flyingdog
+CS85ee ¤¤¤s ¡·¤j®a¸q°_©¯ºÖ 8/08 admin/MVPgirl
+CS85simple ¤¤¤s ¡·Â²¯Z¤H-¤£Â²³æ 3/29 bbeellaa
+TFG95TRUE ¥_¤@ ¡·¯u¯ZªGµæ¶é 3/29 deceanna
+ck46th318 «Ø¤¤ ¡· ¯¬ ºÖ ¤j ® 3/16 FengX/barkjor
+PTGS50th301 ¤¤¤k ¡·¤Ñ¤U²Ä¤@¯Z--¤¤¤ 8/09 cocoduck/youki
+CS85ming ¤¤¤s ¡·"©ú"¤ß¤p¶é 8/08 shan/lovehook/JWR
+ck47th333 «Ø¤¤ ¡·³o¼Ë·|¤£·|¼oª©? 7/17 diezoo/Express
+TFG97SHOT ¥_¤@ ¡·¦Ì¨º®á¡@¾¾¥Ì°_¤ 8/07 chili/atlantis
+Taichung ªA°È ¡·³Ì³Ì²M·s¥i·R°·± 8/09 Jahon
+southdoor «nªù ¡·«nªù¤»¥Òªºµ£¨¥µ 8/09 happyjoy
+ck47th301 «Ø¤¤ ¡·ÁٳѽְڡH¡H 5/22 huskie/flutii
+hsntu ªþ¤¤ ¡´¥x¤jªþ¤Í·| ¨Ó 11/29 koku/Crony
+JH23th301 °ê¤¤ ¡·§AÁÙ¬¡µÛ¶Ü? 7/25 momi/mvpman
+money ¾Ç³N ¡´Show me the 5/02 kagh
+HSNU_807 ªþ¤¤ ¡·®Ã¨Õ¹s¬m¯Z 7/16 yijean/joj
+ntubbsops µo¹q ¡´¥x¤j³s½u¯¸°ÈªO 3/23 Ptt
+ntuACCT90 ·|­p ¡´³o¬O¥Ã»·ªº¥x¤j· 7/19 blackman/aathena
+geography90 ¦a²z ¡· 5/23 cog/uray
+TFG97Juang ¥_¤@ ¡·§Ú­Ì·|¤£·|ª½¨ì± 8/09 seabreeze/notorious/Ving
+JHArt10th °ê¤¤ ¡·¶Â¦âªº©ñ®ö­x 8/14 sadness/noyes
+ChanAn26-303ªø¦w ¡·¥s§Ú²Ä¤@¦W 8/07 HunterX
+FashionClub ¶h½ì ¡´¶W«lÃz¤§--¥x¤j¦ 1/17 demure/Woodywang/wiki
+TFG97KIND ¥_¤@ ¡·³o¸Ì¥i¬O¤¯¶¡¤Ñ° 1/17 Channy
+AADIA ¥xÆW ¡·¿Nºuºuªº³Ì¨Î¨kº 8/13 CATHYSHU/dyw
+Sunrise12 ¹ÎÅé ¡·´Â¶§¦P¾Ç·|¤Q¤G© 8/14 waiting/doggy
+cksh75th09 ¦¨¥\ ¡·¤Í½Ë¾ú"¤E"¤@¼Ë¿ 8/08 chiahei/WeThree/berserk
+Evangelion ¤é¥» ¡´¸Û¼xª©¥D:) 6/15 ¼x¨D¤¤
+NTUba87 ¤uºÞ ¡·¤uºÞ¤@¥X ½Ö»P 8/09 ukj/littlewin
+ck49th109 «Ø¤¤ ¡·ª©¥D­n¤W¤s«ô®v¥ 3/24 edvi
+CS86Honest ¤¤¤s ¡·³o¸Ì¬O¸Û¯Z¡I¸Û¯ 5/24 Nakai/vicke
+YP86-307 ©µ¥­ ¡·¨È¬w²Ä¤@°Õ! 8/08 DRAGONS/longman
+jackstudio ­µ¼Ö ¡·ªN§J·nºu­µ¼Ö¾Ç­ 8/13 gigimusic
+CS85MadWiser¤¤¤s ¡··¬¨g´¼¼z¤H 12/06 NED
+LiZin ¸É²ß ¡·¥ß¤H¸É²ß¯Z 6/10 success/adket/foster
+HP_86_310 ©M¥­ ¡·©M¥­°ª¤¤²Ä¤@©¡ 11/26 beautyegg/oops/kyte
+Terry ¥xÆW ¡·ªL§Ó¬¯¡uÀ¿Án¦Ó¹ 8/10 jane
+Julia ¥xÆW ¡· ¤@¥Í³Ì·Rªº´^¨Î 8/07 esa
+PTGS50th305 ¤¤¤k ¡·¦³¹Ú¦³ªB¤Í---¤¤ 8/07 gm
+ck49th111 «Ø¤¤ ¡´¥´À»§Å±C¯S§ð¶¤ 3/15 ERWILSON/firebat
+ck49th131 «Ø¤¤ ¡·§Ú­Ì¤S²¦·~¤F... 12/26 lanzi/Cliche
+Wallace ­»´ä ¡·¤p¤Ó¶§Áéº~¨}--¥ 8/07 karencc
+KJ25MC ¥ú¤¯ ¡·¥ú¤¯«lÃz¬ü¤kª© 7/09 pm
+ADS ¨ä¥L ¡´¼s§i¯S°Ï 7/09 chwang/sourit/elixirs
+TFSHS57th310¤@¤¤ ¡´§Ú­Ì¤@®a³£¬O¤H 7/09 difficult/lpp/juwu
+B84305XXX ªÀ·| ¡·84¯ÅªÀ·|¤H 7/12 ridley
+Jeff ¥xÆW ¡·¤Q¤G¤ëªì--±¡ºq¤ 7/24 MisaTanaca/gambol
+EricMoo ¬P°¨ ¡·§Å±Ò½åªº·P°Ê 11/27 piercec
+NTUIB-PHD °ê¥ø ¡·¥x¤j°ê¥ø©Ò³Õ¤h¯ 5/22 yi03
+cksh75th19 ¦¨¥\ ¡·¤µ¤Ñªº§A,¹L±o¦n 8/17 shiii/eegg
+MINGDAO ©ú¹D ¡·ªï±µ·s¥@¬öªº¨ì¨ 3/10 apache/kaening
+NTUMBA-87 °Ó¬ã ¡·¥ø·~®aªººÛ 8/13 jonah
+ck49th324 «Ø¤¤ ¡´¤@©u®L©]ªº¤ß°Ê 4/03 jase/uuuuuu/brita
+TFG96Chung ¥_¤@ ¡·²{¦bµ²±B«Ü¤£¦Eº 8/12 astroboy
+Kinmen ÒO¤Í ¡·¥x¤jÒO¤Í·| 4/26 spurs
+BANYAN ¥_ªù ¡·¥_ªù°ª¤¤46TH 30 7/09 lusa/wangstar
+BADTWINS ¤¤¤Í ¡·¤j¼w°ê¤¤ 7/16 Chilong/ggn/xlight
+TFG96WILL ¥_¤@ ¡·¼Ý°ê­·±¡ 8/17 because/Galong
+HSNU_924 ªþ¤¤ ¡´ºÆ¨g´c¶Õ¤O 7/16 Dukedream
+Cyndi ¥xÆW ¡·¨S¦³"¾ÖµØ"¡A´N¥ 1/11 Melinda
+test2
+CS86Smile ¤¤¤s ¡´¯º¶Æ¤¤¤s 12/20 HsinYu/sunspring
+JI3thN3-3 ¥¿¸q ¡·¥¿¸q°ª¤¤´¶¤T¤T 7/13 screamer/stingypig
+CS87KUNG ¤¤¤s ¡·¤½¤§­·¶³ 8/12 hayashi/yjiou
+NTUBA-837011¥øºÞ ¡·ª©½Þ¬O°¦¤jÃi½Þ 3/10 eemil
+TW-explorer ¼v¶° ¡·¤p¤ß³QÅQ¤ýÀs«r³ 8/06 honu
+NTUIMA ªZ³N ¡·¤º®a®±ªÀ ³¯¤ó¤Ó 8/16 shadowpen/fu6xjp6
+NthuPhi ­õ¾Ç ¡·®µ²ø©P¥H¾C¹C 8/07 cerberus
+FreeNight ¥xÆW ¡·TROUBLE ±i¾_À® 5/24 gonna/holybell
+GlobalECON «Ý¼o ¡·¬F¸g¤K¦Ê(°]¸g°Ý 12/12 ali8/martinboy
+cvslog µo¹q ¡·cvs commit mess 4/16
+Momentum «Ý¼o ¡·°Ê¶q¥\³õ¤u§@«Ç 12/03 adnova/chestnut
+chess ®T¼Ö ¡·¤]¹ï ³£¬O³s±N 2/01 miserable
+ChthoniC ¥xÆW ¡´°{ÆF¼Ö¹Îª© 8/07 Iverigma
+shisong304 ¦èªQ ¡·¦èªQ304 5/15 JawTing/JSmoltz
+NCCU97_MAT ·|¬ã ¡·¨Ó§a.....¦P¾Ç·| 5/15 kemling/A1997
+ck49th331 «Ø¤¤ ¡·¨g¨F³¥±æ¡C 7/12 MDP/den
+HCGH-306 ¦Ë¤k ¡·¦³¤K¨ö¡I¡I¡I 4/19 jennywen/molly
+Foolshome ¹ÎÅé ¡·­C­C­C~~~¤dÁH¦~ 1/06 truth/citizen/nathon
+MARIAH ¬ü°ê ¡· ¡¹¡¹DON'T STOP 8/11 woowa
+KHCHS-87-306·s²ø ¡·³£¶]¨ì­þ¸Ì¥h¤F­ 6/10
+Delphi µ{³] ¡·Delphi¨g·Q¦± 2/13 cying
+ciacia_Her ¥xÆW ¡·ciacia¥Î¤å¦r¬D³ 7/26 sherbet
+KS86-323 ¶¯¤¤ ¡´§Ú­Ì¬O¥Ã»·ªºªüµ 7/05 fayemimi/hanawa
+test2
+KS86-322 ¶¯¤¤ ¡·¤j®a¦^¨ÓÄé¤ô§a¡ 8/10 Vygotsky/SpermTiger
+35WHOteam ¹ÎÅé ¡·ÂåÀø¥~¥æÀç¤T¤­¤ 5/12 winonamars
+test2
+ck49th306 «Ø¤¤ ¡·ernesto¡G 306ª 7/18 pongo/dearyou
+WuLing40-301«Ý¼o ¡·¦³¹Ú¦³ªB¤Í 10/ 8/11 quert
+NTUACCT88 ·|­p ¡·¤Ñ ¹D ¹S ¶Ô 6/12 Abbado/yenjui
+NTUDRC ¬ã¨s ¡·©Î³\©p¬O¹ïªº 8/10 Kymco/plockock/Jimmyplus
+NTUWRC ³°¤W ¡·¥x¤jºL¨¤¬ã¨sªÀ 8/07 BigRed
+TFSHS59th318¤@¤¤ ¡´¹L¤F¤@¤Ñ¤S¤@¤Ñ 8/07 prodigy/kinoo/frisk
+86literarts ¤å¾Ç ¡·86®v¤j¤åÃÀÀç 8/07 stupidbear/bengthek
+NTPU-SOC87 ªÀ·| ¡·«z«¨...·sª©¦¨¥ß 8/12 nettaigyo
+NTU94FLLD ¥~¤å ¡·B83102's Wonder 3/27 poppet
+ToriAmos ¬ü°ê ¡·SLG¼ö½æ¤¤ 8/14 CornflakeBoy
+Bjork ¬ü°ê ¡·¤å³¹³£¤£¨£¤F § 8/09 lunaticlace/sjon
+SCU-BM-87C Æ[¹î ¡· ¤Í½Ë¾ú¤[¤@¼Ë¿@ 4/17 joeyoung/linging/YADY
+CC-304 ¤¤¥¿ ¡·¤¤¥¿¶W´Î 304 8/14 betty0804/daystar
+Robin-Willia«Ý¼o ¡·¥Ã»·¤£¦ÑªºÃ¹»«« 8/09 ¼x¨D¤¤
+NTUEEice ¹ÎÅé ¡·­á -- µ² 8/10 hiei81/shouhou
+tu-tuoz ¹ÎÅé ¡·¦R¼Ñ°ê¥Á¤p¾Ç 8/10 galilei/seethesky
+WesleyS3H-32½Ã²z ¡·³Ì«á¤@­Ó´»°²°Õ¡ 8/15 esm
+Romi ¥xÆW ¡·§Qºö¡ã¡ãÅé¶K 8/16 flyawayhome/holina
+EEacademic ¹q¾÷ ¡´­n´Á¤¤¦ÒÅo¡I¡I 5/11 ccchen
+ck-newboard ¥Ó½Ð ¡·«Ø¤¤²Õ±M¥Î³s¸pª 2/09 Pets
+NTUspecial µLê ¡·¡¸¥xÆW¤j¾ÇµL»Ùà 4/28 t6768
+chienchen §@®a ¡·¤å¦rºëÆF¡X¡XÂ²Ø 8/09 curioussoul/ECOSEED
+test2
+test2
+test2
+NTUmed-SC Âå¾Ç ¡·¡¸¤È¶¡­µ¼Ö·|µ¥§ 8/13 Evan/boo24
+Visual_Basicµ{³] ¡·«z«z..§A¤£¯à¦Û¤ 8/14 glans
+test2
+test2
+AngelicaLee ¬P°¨ ¡·¶W¥i·R§õ¤ß¼ä *^ 8/11 CaptainL
+Jackie_Lui ­»´ä ¡´«L°©¤¯¤ß--§f¹|½ 8/14 pipo/YCJ
+HSNU_888 ªþ¤¤ ¡´888¬¾¨ß²Ä¤G¸] 8/10 Viggeran/cidi
+ClassicMusic­µ¼Ö ¡´§Ú­Ì£x°ê¼Ö 8/13 kuger/mml
+CM34th03 ´º¬ü ¡·:) 8/13 Snorkel
+CS88Jang ¤¤¤s ¡·§Ú­Ì³£¬O¥¿ÂI¬ü¤ 8/08 YANIYANI/cfchien
+TFG99JUANG ¥_¤@ ¡·µM«á¤S¬O¬î¤Ñ°Õ. 8/11 yumeko
+SrcDiscuss ¯¸ªø ¡·PTT ¥¼¨Óµ{¦¡µo® 5/13 CharlieL/DavidYu
+WL-AFFAIRS ¨Æ°È ¡·½Ð¦UªO¥Dª`·N¸s² 6/09 PaiBingTran
+SMGJS-80-302¾å©ú ¡·¥Ã»·ªºªì¤T¤A 8/09 chifang
+ck51st332 «Ø¤¤ ¡·±¥ Â÷§Ú­Ì¦Ó¥hªº 8/13 JeffreyS/jimmycat/Kampuchea/JIROO
+HORT-90 ¶éÃÀ ¡´²¦·~¤F... 8/16 sorng
+NCHUPPSB ¨tÂS ¡·«s«s«s «áÄ~µL¤H 4/14 LCUTE/AMDKX
+TAE ®õ°ê ¡·¦A¨£,¥[¦{®üÅy 4/14 TulipChiu
+LePoete ¥xÆW ¡·¥Ð¶é¸Ö¤H³¯©ú³¹( 4/14 doomcat
+NTUPOD ¬ã¨s ¡· 8/16 Galong
+ck53rd211 «Ø¤¤ ¡·´«­Ó¦W¦r§a.. 8/07 shanvic/BBD
+NCHU-SES ¤gÀô ¡·¤j®a¨Óªï·s³á~~ 4/18 yenjan
+Tin-Tin ¥xÆW ¡´´@´@·Rªº³Ó§Q 8/09 shinoo
+PTGS48th318 ¤¤¤k ¡·ºñ¦âÁ­½¸ºÛ 8/15 yungfang
+KF302 ¥ú´_ ¡·¶ë¨®¤¤ 8/15 ingela/cadillac
+HuangLei ¤j³° ¡·¶À½U¤å¾Ç­µ¼Ö¤jº 8/09 ssr
+NCCU99_EDU «Ý¼o ¡·~±Ð¨|Ä_Ä_ªº­_§§ 8/14 ¼x¨D¤¤
+NCHU_zoo °Êª« ¡´¤£¨}¤û¤H¤ñ¸û¦h 4/24 sengir/GENETICS/velella
+Bull ¾´Î ¡´¤G¤Q¤@¥@¬ö³Ì«i² 4/24 Nicky41/georgey
+KS88-309 ¶¯¤¤ ¡´°¸§i¶D§A...§Ú§@ 4/24 daviy
+cksh77th20 ¦¨¥\ ¡·§A§Ú³£¬O·Ï¤õ¤¤ª 8/06 bergee
+TFG99Dance ¥_¤@ ¡·µL­­¬×Jazz«a­x 8/07 Tinabear/hee
+TFG99Love ¥_¤@ ¡· ¨ä ¹ê 8/07 kelala/SpiceB
+Nedio ´CÅé ¡·§Ö¤Whttp://nedi 8/08 SpiceB/Sophia33
+TYHS88-306 ¥ªÀç ¡´¤T¤Ñ¤T©]¨ì¤T§ó¥ 8/09 niniway/Jey
+BCT-88 ¬ì§Þ ¡·¤@¸s¦b¥Íª«§Þ³N¤ 8/15 physik/avkao
+CARNEGIE0917¹ÎÅé ¡·***ªï±µ°{«Gªº21 8/07 blackmail/mistletoe/tsg
+NCCU_PT ªÀ¹Î ¡·¨S¦³¬¡°Êªº«Ì¤Í· 8/11 mib345/randying
+NCHU-SKATING·È¦B ¡·¨Ó¥h...¨Ó¥h...¤ 3/18 kaoasaki/littlehome
+Tun-Hua-Elem´°¤Æ ¡·TunHua_²Ä32©¡_6 8/07 pup
+CS88jing ¤¤¤s ¡·§Ö²¦·~¤F­C ·Q 8/08 yianne
+LeneMarlin ¬ü°ê ¡·­µ¼ÖºëÆF--µY®¦º 8/08 janetwang
+KS88-304 ¶¯¤¤ ¡·¤j®a¨ÓÄé¤ô³á~ 8/12 ahwa/oldya/BabyHam
+Summer ¥xÆW ¡·§â¼v¤l¯d¤U¡A¦b® 8/08 powerpeople/FINNCHE
+Slayers ¤é¥» ¡·¨q³rÅ]¾É¤h ²ú® 8/07 Zelgandes/marcal/Naga
+NTU-SwimCamp¤ô¤W ¡·¥x¤j´åªaÀç 6/22 sunnyl
+red-sun ªÀ¹Î ¡·¸¨¥Û¨ÓÅo 8/09 renaissance
+1995-JH-325 ª÷µØ ¡·ª÷µØ°ê¤¤¤T¦~¤G¤ 8/13 ThisWayIn/Raistlin/ifq
+X-game ¹B°Ê ¡··¥­­¹B°Ê 8/08 rbaggio
+88leadercamp¹ÎÅé ¡´ ²×©ó¶}ª©ªº88ªÀ 8/12 elbert/aaati
+Curse ¥xÆW ¡·¶A©G¼Ö¹Î(¤Q¤K¤~ 8/07 anticrist
+Joi ¬P°¨ ¡·²E²b¨Î­µ 8/08 leon19/crazykiller
+SHENA-RINGO ¤é¥» ¡·´Õ¦WªLìþ ³Ó¶Dªº 8/08 MayMV
+CCJH-FS-27th¤¤¥¿ ¡·£¯ §N²M²M..... 8/12 Ariyari/YehMay
+PH-Service ¤½½Ã ¡·¥ÃÄò¸gÀ窺¤½½Ãª 8/07 piayyc/yuskay
+1995-JH-309 «Ý¼o ¡·ª÷µØ309°ê¤¤¦P¾Ç 2/11 ¼x¨D¤¤
+Peter ¥xÆW ¡·¨C¦¸·Q¨ì"¦ó¼íªF 3/05 Haas
+IPIS µá°ê ¡·Á­½¸-§Ñ¤F§Ú¬O½Ö 5/30
+cksh76th22 ¦¨¥\ ¡·¦a²y«Ü¦MÀIªº!©p 8/15 lunasoul
+Stella ¬P°¨ ¡·­µ¼Ö²¢¤ß-¶À´ð©É 7/12 gutai309/crazykiller
+Law-Skate ªk«ß ¡·ªk­bª½±Æ½üªÀ ·È 6/12 Rainsalt/gwenlin
+cksh78th08 ¦¨¥\ ¡·¤»¦rÀY 308 3/17 smilefacer
+ntucomga ºÞ·| ¡·ºÞ°|¬ã¨s¥Í¾Ç¥Í· 5/08 handsome
diff --git a/util/smtest.result2 b/util/smtest.result2
new file mode 100644
index 00000000..b84133c2
--- /dev/null
+++ b/util/smtest.result2
@@ -0,0 +1,3 @@
+§K¾ª©¥D
+¬ÝªO¦WºÙ ªO¥D ´X¤Ñ¨S¨Ó°Õ
+----------------------------------------------------------------------
diff --git a/util/smtest.temp b/util/smtest.temp
new file mode 100644
index 00000000..7daa12ce
--- /dev/null
+++ b/util/smtest.temp
@@ -0,0 +1,231 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+#include "perm.h"
+#include "common.h"
+#include "proto.h"
+
+#define OUTFILE BBSHOME "/pttbbs/util/smtest.result1"
+#define FIREFILE BBSHOME "/pttbbs/util/smtest.result2"
+
+extern boardheader_t *bcache;
+extern int numboards;
+
+boardheader_t allbrd[MAX_BOARD];
+struct userec_t xuser;
+
+int getuser(char *userid) {
+ int uid;
+ if((uid = searchuser(userid)))
+ passwd_query(uid, &xuser);
+ return uid;
+}
+
+int LINK(char* src, char* dst){
+ char cmd[200];
+
+ if( link(src, dst) == 0){
+ return 0;
+ }
+
+ sprintf(cmd, "/bin/cp -R %s %s", src, dst);
+ return system(cmd);
+}
+
+int outofdate(char *hdrdate, char latestdate[])
+{
+ int k,rr;
+ char *dd;
+
+ dd = strtok(hdrdate,"/");
+
+ if(dd){
+ k = 0;
+ do
+ {
+ if (*dd == '[' ){dd[strlen(dd)-1]='\0'; dd++;}
+ rr = atoi(dd);
+ printf("%d/", rr);
+ } while((dd = strtok(NULL,"/")) != NULL);
+ }
+
+ printf("\n");
+
+ if(1)
+ return 1;
+ else
+ return 0;
+}
+
+int main()
+{
+ int bmid, i, j, k, rd,rr;
+ char *p, *bmsname[3], fname[256], *dd;
+ fileheader_t hdr;
+ FILE *inf;
+
+ /* set date */
+ char thedate[5];
+ time_t t = time(NULL);
+ struct tm *tm = localtime(&t);
+
+ sprintf(thedate, "%2d/%02d", tm->tm_mon + 1, tm->tm_mday);
+
+ resolve_boards();
+ if(passwd_mmap())
+ exit(1);
+ memcpy(allbrd,bcache,numboards*sizeof(boardheader_t));
+ /* write out the target file */
+ inf = fopen(OUTFILE, "w+");
+ if(inf == NULL){
+ printf("open file error : %s\n", OUTFILE);
+ exit(1);
+ }
+
+ /*the ouput table title*/
+ fprintf(inf,"­^¤åª©¦W Ãþ§O ¤¤¤åª©¦W ª©¥D¦W³æ"
+ " ¤é´Á ³Æµù \n");
+
+ j = 0 ;
+ for (i = 0; i < 30; i++) {
+ rd = 0;
+ if(allbrd[i].brdname[0] == '\0') continue;
+ if((allbrd[i].brdattr & BRD_NOZAP) == 1) continue;
+
+ sprintf(fname, BBSHOME "/boards/%s/.DIR",allbrd[i].brdname);
+
+ /* get date to choose junk board */
+
+ rd = get_num_records(fname, sizeof(fileheader_t));
+ get_record(fname, &hdr, sizeof (hdr), rd - 30);
+
+
+ if(outofdate(hdr.date,thedate)) printf("yest\n");
+
+/*
+ dd = strtok(hdr.date,"/");
+
+ if(dd){
+ k = 0;
+ do
+ {
+ if (*dd == '[' ){dd[strlen(dd)-1]='\0'; dd++;}
+ rr = atoi(dd);
+ printf("%d/", rr);
+
+ } while((dd = strtok(NULL,"/")) != NULL);
+ }
+ printf("\n");
+*/
+ /* print to file */
+ printf("%-*.*s%-*.*s%-*.*s%-*.*s", IDLEN, IDLEN, allbrd[i].brdname,
+ BTLEN-24, BTLEN-26, allbrd[i].title, IDLEN - 5, IDLEN-5,hdr.date,
+ IDLEN * 3, IDLEN * 3, allbrd[i].BM);
+
+ /* post to board */
+
+
+
+ /* user extract to mail */
+
+ p=strtok(allbrd[i].BM,"/ ");
+ if(p){
+ k = 0;
+ do
+ {
+ if (*p == '[' ){p[strlen(p)-1]='\0'; p++;}
+ bmid=getuser(p);
+ bmsname[k] = p;
+ if(isalpha(allbrd[i].BM[0])&& !(xuser.userlevel &PERM_SYSOP))
+ {
+ // printf("%s", bmsname[k]);
+ }
+ k++;
+ } while((p=strtok(NULL,"/ "))!=NULL);
+ }
+
+ printf("\n");
+
+}
+
+
+/*
+
+
+
+ if(flag == 1){
+ bmbuf[0] = '\0';
+ for(k = 0 , n = 0; k < index; k++){
+ if(!bms[k].flag){
+ if( n++ != 0) strcat(bmbuf, "/");
+ strcat(bmbuf, bms[k].bmname);
+ }
+ }
+ strcpy(bcache[i].BM, bmbuf);
+ }
+ }
+ qsort(lostbms, j, sizeof(lostbm), bmlostdays_cmp);
+
+ //write to the etc/toplazyBM
+ for ( i=0; i<j; i++)
+ {
+ if( lostbms[i].lostdays > 60){
+ fprintf(firef, "%-*.*s%-*.*s%-*.*s%3d¤Ñ¨S¤W¯¸\n", IDLEN, IDLEN, lostbms[i].title,
+ BTLEN-10, BTLEN-10, lostbms[i].ctitle, IDLEN,IDLEN,
+ lostbms[i].bmname,lostbms[i].lostdays);
+ }else{
+ fprintf(inf, "%-*.*s%-*.*s%-*.*s%3d¤Ñ¨S¤W¯¸\n", IDLEN, IDLEN, lostbms[i].title,
+ BTLEN-10, BTLEN-10, lostbms[i].ctitle, IDLEN,IDLEN,
+ lostbms[i].bmname,lostbms[i].lostdays);
+ }
+ }
+ fclose(inf);
+ fclose(firef);
+
+ //printf("Total %d boards.\n", count);
+
+ //mail to the users
+ for( i=0; i<j; i++)
+ {
+ fileheader_t mymail;
+ char genbuf[200];
+ int lostdays;
+
+ lostdays = lostbms[i].lostdays;
+
+ if( (lostdays != 30) && (lostdays != 45) && (lostdays <= 60))
+ continue;
+
+ sprintf(genbuf, BBSHOME "/home/%c/%s", lostbms[i].bmname[0], lostbms[i].bmname);
+ stampfile(genbuf, &mymail);
+
+ strcpy(mymail.owner, "[PTTĵ¹î§½]");
+
+ if(lostdays <= 60){
+ sprintf(mymail.title,
+ "\033[32m [ª©¥D§K¾ĵ§i³qª¾] \033[m %s BM %s", lostbms[i].title, lostbms[i].bmname);
+ }else{
+ sprintf(mymail.title,
+ "\033[32m [ª©¥D§K¾³qª¾] \033[m %s BM %s", lostbms[i].title, lostbms[i].bmname);
+ }
+ mymail.savemode = 0 ;
+ unlink(genbuf);
+ if(lostdays <= 60){
+ LINK(OUTFILE, genbuf);
+ }else{
+ LINK(FIREFILE, genbuf);
+ }
+
+ sprintf(genbuf, BBSHOME "/home/%c/%s/.DIR", lostbms[i].bmname[0], lostbms[i].bmname);
+ append_record(genbuf, &mymail, sizeof(mymail));
+ }
+*/
+ return 0;
+}
diff --git a/util/stock.perl b/util/stock.perl
new file mode 100644
index 00000000..568c2d86
--- /dev/null
+++ b/util/stock.perl
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+# $Id: stock.perl,v 1.1 2002/03/07 15:13:46 in2 Exp $
+#
+# ¤£¯à¶]ªº¸Ü¡A¬Ý¬Ý bbspost ªº¸ô®|¬O§_¥¿½T¡C
+# ¦pªGµo¥Xªº post ¨S¦³®ð¶H³ø§i¦Ó¬O»¡ URL §ä¤£¨ì¡A«h½T©w¤@¤U¯à¤£¯à¬Ý¨ì
+# ¤¤¥¡®ð¶H§½ªº WWW ¤Î URL ¬O§_¥¿½T¡C
+# ²z½×¤W¾A¥Î©Ò¦³ Eagle BBS ¨t¦C¡C
+# -- Beagle Apr 13 1997
+open(BBSPOST, "| bin/webgrep >etc/stock.tmp");
+# ¤é´Á
+open(DATE, "date +'%a %b %d %T %Y' |");
+$date = <DATE>;
+chop $date;
+close DATE;
+
+# Header
+# ¤º®e
+#open(WEATHER, "/usr/local/bin/lynx -dump http://www.dashin.com.tw/bulletin_board/today_stock_price.htm |"); while (<WEATHER>) {
+open(WEATHER, "/usr/bin/lynx -dump http://quotecenter.jpc.com.tw/today_stock_price.htm |"); while(<WEATHER>) {
+ print BBSPOST if ($_ ne "\n");
+}
+close WEATHER;
+
+# ñ¦WÀÉ
+print BBSPOST "\n--\n";
+print BBSPOST "§Ú¬Obeagle©Ò¦³¥i·Rªº¤p»æ°®...¸ó®ü¬°PttªA°È\n";
+print BBSPOST "--\n";
+print BBSPOST "¡¸ [Origin: ¡·ªGÂæ¤p¯¸¡·] [From: [ÂŲùÃP»æ«Î] ] ";
+
+close BBSPOST;
+
diff --git a/util/stock.sh b/util/stock.sh
new file mode 100644
index 00000000..907ddb73
--- /dev/null
+++ b/util/stock.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# $Id: stock.sh,v 1.1 2002/03/07 15:13:46 in2 Exp $
+#
+bin/stock.perl
+bin/post Record ¤µ¤éªÑ²¼¦¬½L»ù [ªÑ¥«¤p©j] etc/stock.tmp
diff --git a/util/tarqueue.pl b/util/tarqueue.pl
new file mode 100644
index 00000000..20bda9f1
--- /dev/null
+++ b/util/tarqueue.pl
@@ -0,0 +1,75 @@
+#!/usr/bin/perl
+use lib '/home/bbs/bin/';
+use LocalVars;
+use strict;
+use Mail::Sender;
+use POSIX;
+
+no strict 'subs';
+setpriority(PRIO_PROCESS, $$, 20);
+use strict subs;
+chdir $BBSHOME;
+open LOG, ">> log/tarqueue.log";
+
+foreach my $board ( <$JOBSPOOL/tarqueue.*> ){
+ $board =~ s/.*tarqueue\.//;
+ ProcessBoard($board);
+ unlink "$JOBSPOOL/tarqueue.$board";
+}
+close DIR;
+close LOG;
+
+sub ProcessBoard
+{
+ my($board)= @_;
+ my($cmd, $owner, $email, $bakboard, $bakman, $now);
+
+ $now = substr(POSIX::ctime(time()), 0, -1);
+ open FH, "< $JOBSPOOL/tarqueue.$board";
+ chomp($owner = <FH>);
+ chomp($email = <FH>);
+ chomp(($bakboard, $bakman) = split(/,/, <FH>));
+ close FH;
+
+ print LOG sprintf("%-28s %-12s %-12s %d %d %s\n",
+ $now, $owner, $board, $bakboard, $bakman, $email);
+
+ MakeMail({tartarget => "$TMP/$board.tgz",
+ tarsource => "boards/$board/* boards/$board/.DIR",
+ mailto => "$boardªºª©¥D$owner <$email>",
+ subject => "$boardªº¬Ýª©³Æ¥÷",
+ body =>
+ "\n\n\t $owner ±z¦n¡A¦¬¨ì³o«Ê«H¡Aªí¥Ü±z¤w¸g¦¬¨ì¬ÝªO³Æ¥÷¡C\n\n".
+ "\tÁÂÁ±zªº­@¤ßµ¥«Ý¡A¥H¤Î¨Ï¥Î $hostnameªº¬ÝªO³Æ¥÷¨t²Î¡A\n\n".
+ "\t¦p¦³¥ô¦óºÃ°Ý¡AÅwªï±H«Hµ¹¯¸ªø¡A§Ú­Ì·|«Ü¼Ö©óµ¹¤©¨ó§U¡C\n\n\n".
+ "\t³Ì«á¡A¯¬ $owner ¥­¦w§Ö¼Ö¡I ^_^\n\n\n".
+ "\t $hostname¯¸ªø¸s. \n\t$now"
+ }) if( $bakboard );
+
+ MakeMail({tartarget => "$TMP/man.$board.tgz",
+ tarsource => "man/boards/$board/* man/boards/$board/.DIR",
+ mailto => "$boardªºª©¥D$owner <$email>",
+ subject => "$boardªººëµØ°Ï³Æ¥÷",
+ body =>
+ "\n\n\t $owner ±z¦n¡A¦¬¨ì³o«Ê«H¡Aªí¥Ü±z¤w¸g¦¬¨ìºëµØ°Ï³Æ¥÷¡C\n\n".
+ "\tÁÂÁ±zªº­@¤ßµ¥«Ý¡A¥H¤Î¨Ï¥Î $hostnameªº¬ÝªO³Æ¥÷¨t²Î¡A\n\n".
+ "\t¦p¦³¥ô¦óºÃ°Ý¡AÅwªï±H«Hµ¹¯¸ªø¡A§Ú­Ì·|«Ü¼Ö©óµ¹¤©¨ó§U¡C\n\n\n".
+ "\t³Ì«á¡A¯¬ $owner ¥­¦w§Ö¼Ö¡I ^_^\n\n\n".
+ "\t $hostname¯¸ªø¸s. \n\t$now"
+ }) if( $bakman );
+
+}
+
+sub MakeMail
+{
+ my($arg) = @_;
+ my $sender;
+ `$TAR zcf $arg->{tartarget} $arg->{tarsource}`;
+ $sender = new Mail::Sender{smtp => $SMTPSERVER,
+ from => 'pttadmin <in2@ptt2.csie.ntu.edu.tw>'};
+ $sender->MailFile({to => $arg->{mailto},
+ subject => $arg->{subject},
+ msg => $arg->{body},
+ file => $arg->{tartarget}});
+ unlink $arg->{tartarget};
+}
diff --git a/util/testkenben.txt b/util/testkenben.txt
new file mode 100644
index 00000000..df3893d3
--- /dev/null
+++ b/util/testkenben.txt
@@ -0,0 +1,11 @@
+HCGH-306 ¦Ë¤k ¡·¦³¤K¨ö¡I¡I¡I 7/24 jennywen/molly
+Foolshome ¹ÎÅé ¡·­C­C­C~~~¤dÁH¦~ 1/14 truth/citizen/nathon
+KHCHS-87-306·s²ø ¡·³£¶]¨ì­þ¸Ì¥h¤F­ 6/12
+TGHS8714 «n¤k ¡·²z©Ê¤Ñ®ð¡F·P©Ê¥ 8/07 grassflying/EPOCH
+PttDoc ¼T­ù ¡·Ptt Document Pr 8/07
+Delphi µ{³] ¡·Delphi¨g·Q¦± 3/09 cying
+ciacia_Her ¥xÆW ¡·ciacia¥Î¤å¦r¬D³ 8/16 sherbet
+CS87Love ¤¤¤s ¡··R©O! 8/08 sylna/fancydream
+Wanfang ¥xÆW ¡·´N­È±o¤F·R¸UªÚ 8/07 zkkk
+KS87-308 ¶¯¤¤ ¡´¶¯¤¤¤K±¾¯Z¡m¤@¤ 8/07 SBT/shouhou
+
diff --git a/util/toplazyBBM.c b/util/toplazyBBM.c
new file mode 100644
index 00000000..08c07448
--- /dev/null
+++ b/util/toplazyBBM.c
@@ -0,0 +1,203 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+#include "perm.h"
+#include "common.h"
+
+#define OUTFILE BBSHOME "/etc/toplazyBBM"
+#define FIREFILE BBSHOME "/etc/topfireBBM"
+
+extern boardheader_t *bcache;
+extern int numboards;
+
+boardheader_t allbrd[MAX_BOARD];
+extern userec_t xuser;
+typedef struct lostbm {
+ char *bmname;
+ char *title;
+ char *ctitle;
+ int lostdays;
+} lostbm;
+lostbm lostbms[MAX_BOARD];
+
+typedef struct BMarray{
+ char *bmname;
+ int flag;
+} BMArray;
+BMArray bms[3];
+
+int bmlostdays_cmp(const void *va, const void *vb)
+{
+ lostbm *a=(lostbm *)va, *b=(lostbm *)vb;
+ if (a->lostdays > b->lostdays) return -1;
+ else if (a->lostdays == b->lostdays) return 0;
+ else return 1;
+}
+
+
+int LINK(char* src, char* dst){
+ char cmd[200];
+ if(symlink(src,dst) == -1)
+ {
+ sprintf(cmd, "/bin/cp -R %s %s", src, dst);
+ return system(cmd);
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int bmid, i, j=0;
+ FILE *inf, *firef;
+
+ resolve_boards();
+
+ if(passwd_mmap())
+ exit(1);
+
+ memcpy(allbrd,bcache,numboards*sizeof(boardheader_t));
+
+ /* write out the target file */
+ printf("Starting Checking\n");
+ inf = fopen(OUTFILE, "w+");
+ if(inf == NULL){
+ printf("open file error : %s\n", OUTFILE);
+ exit(1);
+ }
+ firef = fopen(FIREFILE, "w+");
+ if(firef == NULL){
+ printf("open file error : %s\n", FIREFILE);
+ exit(1);
+ }
+
+ fprintf(inf, "ĵ§i: ª©¥D­Y©ó¨â­Ó¤ë¥¼¤W¯¸,±N¤©©ó§K¾\n");
+ fprintf(inf,
+ "¬ÝªO¦WºÙ "
+ " ªO¥D ´X¤Ñ¨S¨Ó°Õ\n"
+ "---------------------------------------------------"
+ "-------------------\n");
+
+ fprintf(firef, "§K¾ª©¥D\n");
+ fprintf(firef,
+ "¬ÝªO¦WºÙ "
+ " ªO¥D ´X¤Ñ¨S¨Ó°Õ\n"
+ "---------------------------------------------------"
+ "-------------------\n");
+
+
+ j = 0 ;
+ for (i = 0; i < numboards; i++) {
+ char *p, bmbuf[IDLEN * 3 + 3];
+ int index = 0, flag = 0, k, n;
+ p=strtok(allbrd[i].BM,"/ ");
+ if(p)
+ do
+ {
+ if(allbrd[i].brdname[0] == '\0' || (allbrd[i].brdattr & BRD_GROUPBOARD) ==0 ) continue;
+ if (*p == '[' ){p[strlen(p)-1]='\0'; p++;}
+ bmid=getuser(p);
+ bms[index].bmname = p;
+ bms[index].flag = 0;
+ if (((((int)time(NULL)-(int)xuser.lastlogin)/(60*60*24))>=7)
+ //&& isalpha(allbrd[i].brdname[0])
+ //&& isalpha(allbrd[i].BM[0])
+ && !(xuser.userlevel & PERM_SYSOP))
+ {
+ lostbms[j].bmname = p;
+ lostbms[j].title = allbrd[i].brdname;
+ lostbms[j].ctitle = allbrd[i].title;
+ lostbms[j].lostdays =
+ ((int)time(NULL)-(int)xuser.lastlogin)/(60*60*24);
+
+ printf("%s\n", lostbms[j].title);
+ //¶W¹L¤»¤Q¤Ñ §K¾
+ if(lostbms[j].lostdays > 30){
+ xuser.userlevel &= ~PERM_BM;
+ bms[index].flag = 1;
+ flag = 1;
+ }
+ j++;
+ }
+ index++;
+ } while((p=strtok(NULL,"/ "))!=NULL);
+
+ //±qª©¥D¦W³æ®³±¼¦W¦r
+
+ if(flag == 1){
+ bmbuf[0] = '\0';
+ for(k = 0 , n = 0; k < index; k++){
+ if(!bms[k].flag){
+ if( n++ != 0) strcat(bmbuf, "/");
+ strcat(bmbuf, bms[k].bmname);
+ }
+ }
+ strcpy(allbrd[i].BM, bmbuf);
+ }
+
+ }
+ qsort(lostbms, j, sizeof(lostbm), bmlostdays_cmp);
+
+ printf("Starting to mail\n");
+ //write to the etc/toplazyBBM
+ for ( i=0; i<j; i++)
+ {
+ if( lostbms[i].lostdays > 30){
+ fprintf(firef, "%-*.*s%-*.*s%-*.*s%3d¤Ñ¨S¤W¯¸\n", IDLEN, IDLEN, lostbms[i].title,
+ BTLEN-10, BTLEN-10, lostbms[i].ctitle, IDLEN,IDLEN,
+ lostbms[i].bmname,lostbms[i].lostdays);
+ }else{
+ fprintf(inf, "%-*.*s%-*.*s%-*.*s%3d¤Ñ¨S¤W¯¸\n", IDLEN, IDLEN, lostbms[i].title,
+ BTLEN-10, BTLEN-10, lostbms[i].ctitle, IDLEN,IDLEN,
+ lostbms[i].bmname,lostbms[i].lostdays);
+ }
+ }
+ fclose(inf);
+ fclose(firef);
+
+ printf("Total %d boards.\n", j);
+
+ //mail to the users
+ for( i=0; i<j; i++)
+ {
+ fileheader_t mymail;
+ char genbuf[200];
+ int lostdays;
+
+ lostdays = lostbms[i].lostdays;
+
+ if( (lostdays != 14) || (lostdays != 21) ) // 14 21 ¤Ñ¤£µo«H
+ continue;
+
+ sprintf(genbuf, BBSHOME "/home/%c/%s", lostbms[i].bmname[0], lostbms[i].bmname);
+ stampfile(genbuf, &mymail);
+
+ strcpy(mymail.owner, "[PTTĵ¹î§½]");
+
+ if(lostdays <= 30){
+ sprintf(mymail.title,
+ "\033[32m [¤p²Õªø§K¾ĵ§i³qª¾] \033[m %s BM %s", lostbms[i].title, lostbms[i].bmname);
+ }else{
+ sprintf(mymail.title,
+ "\033[32m [¤p²Õªø§K¾³qª¾] \033[m %s BM %s", lostbms[i].title, lostbms[i].bmname);
+ }
+ mymail.savemode = 0 ;
+ unlink(genbuf);
+ if(lostdays <= 30){
+ LINK(OUTFILE, genbuf);
+ }else{
+ LINK(FIREFILE, genbuf);
+ }
+
+ sprintf(genbuf, BBSHOME "/home/%c/%s/.DIR", lostbms[i].bmname[0], lostbms[i].bmname);
+ append_record(genbuf, &mymail, sizeof(mymail));
+ }
+
+ return 0;
+}
diff --git a/util/toplazyBBM.sh b/util/toplazyBBM.sh
new file mode 100644
index 00000000..d1d94229
--- /dev/null
+++ b/util/toplazyBBM.sh
@@ -0,0 +1,3 @@
+bin/toplazyBBM
+bin/post Record Ãi´k¤p²Õªø±Æ¦æº] [Pttĵ¹î§½] etc/toplazyBBM
+bin/post ViolateLaw ¤µ¤é§K¾¤p²Õªø [Pttªk°|] etc/firelazyBBM
diff --git a/util/toplazyBM.c b/util/toplazyBM.c
new file mode 100644
index 00000000..ec9319c2
--- /dev/null
+++ b/util/toplazyBM.c
@@ -0,0 +1,211 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+#include "perm.h"
+#include "common.h"
+#include "proto.h"
+#include "modes.h"
+
+
+#define OUTFILE BBSHOME "/etc/toplazyBM"
+#define FIREFILE BBSHOME "/etc/firelazyBM"
+
+extern boardheader_t *bcache;
+extern int numboards;
+
+boardheader_t allbrd[MAX_BOARD];
+extern userec_t xuser;
+typedef struct lostbm {
+ char *bmname;
+ char *title;
+ char *ctitle;
+ int lostdays;
+} lostbm;
+lostbm lostbms[MAX_BOARD];
+
+typedef struct BMarray{
+ char *bmname;
+ int flag;
+} BMArray;
+BMArray bms[3];
+
+
+int bmlostdays_cmp(const void *va, const void *vb)
+{
+ lostbm *a=(lostbm *)va, *b=(lostbm *)vb;
+ if (a->lostdays > b->lostdays) return -1;
+ else if (a->lostdays == b->lostdays) return 0;
+ else return 1;
+}
+
+int LINK(char* src, char* dst){
+ char cmd[200];
+ if(symlink(src,dst) == -1)
+ {
+ sprintf(cmd, "/bin/cp -R %s %s", src, dst);
+ return system(cmd);
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int bmid, i, j=0;
+ FILE *inf, *firef;
+
+ resolve_boards();
+
+ if(passwd_mmap())
+ exit(1);
+
+ memcpy(allbrd,bcache,numboards*sizeof(boardheader_t));
+
+ /* write out the target file */
+ inf = fopen(OUTFILE, "w+");
+ if(inf == NULL){
+ printf("open file error : %s\n", OUTFILE);
+ exit(1);
+ }
+
+ firef = fopen(FIREFILE, "w+");
+ if(firef == NULL){
+ printf("open file error : %s\n", FIREFILE);
+ exit(1);
+ }
+
+ fprintf(inf, "ĵ§i: ª©¥D­Y©ó¨â­Ó¤ë¥¼¤W¯¸,±N¤©©ó§K¾\n");
+ fprintf(inf,
+ "¬ÝªO¦WºÙ "
+ " ªO¥D ´X¤Ñ¨S¨Ó°Õ\n"
+ "---------------------------------------------------"
+ "-------------------\n");
+
+ fprintf(firef, "§K¾ª©¥D\n");
+ fprintf(firef,
+ "¬ÝªO¦WºÙ "
+ " ªO¥D ´X¤Ñ¨S¨Ó°Õ\n"
+ "---------------------------------------------------"
+ "-------------------\n");
+
+
+ j = 0 ;
+ for (i = 0; i < numboards; i++) {
+ char *p, bmbuf[IDLEN * 3 + 3];
+ int index = 0, flag = 0, k, n;
+ p=strtok(allbrd[i].BM,"/ ");
+ if(p)
+ do
+ {
+ if(allbrd[i].brdname[0] == '\0') continue;
+ if (*p == '[' ){p[strlen(p)-1]='\0'; p++;}
+ bmid=getuser(p);
+ bms[index].bmname = p;
+ bms[index].flag = 0;
+ if (((((int)time(NULL)-(int)xuser.lastlogin)/(60*60*24))>=31)
+ && isalpha(allbrd[i].brdname[0])
+ && isalpha(allbrd[i].BM[0])
+ && !(xuser.userlevel & PERM_SYSOP))
+ {
+ lostbms[j].bmname = p;
+ lostbms[j].title = allbrd[i].brdname;
+ lostbms[j].ctitle = allbrd[i].title;
+ lostbms[j].lostdays =
+ ((int)time(NULL)-(int)xuser.lastlogin)/(60*60*24);
+
+
+ //¶W¹L¤»¤Q¤Ñ §K¾
+ if(lostbms[j].lostdays > 60){
+ xuser.userlevel &= ~PERM_BM;
+ bms[index].flag = 1;
+ flag = 1;
+ passwd_update(bmid, &xuser);
+ }
+ j++;
+ }
+ index++;
+ } while((p=strtok(NULL,"/ "))!=NULL);
+
+ if(flag == 1){
+ boardheader_t *fhp = 0;
+ printf("%s %s\n", lostbms[j-1].title, lostbms[j-1].bmname);
+ bmbuf[0] = '\0';
+ for(k = 0 , n = 0; k < index; k++){
+ if(!bms[k].flag){
+ if( n++ != 0) strcat(bmbuf, "/");
+ strcat(bmbuf, bms[k].bmname);
+ }
+ }
+
+ strcpy(allbrd[i].BM, bmbuf);
+ if( substitute_record(FN_BOARD, &allbrd[i], sizeof(boardheader_t), i) == -1){
+ printf("Update Board Faile : %s\n", allbrd[i].brdname);
+ }
+ reset_board(i);
+ }
+ }
+
+ qsort(lostbms, j, sizeof(lostbm), bmlostdays_cmp);
+
+ //write to the etc/toplazyBM
+ for ( i=0; i<j; i++)
+ {
+ if( lostbms[i].lostdays > 60){
+ fprintf(firef, "%-*.*s%-*.*s%-*.*s%3d¤Ñ¨S¤W¯¸\n", IDLEN, IDLEN, lostbms[i].title,
+ BTLEN-10, BTLEN-10, lostbms[i].ctitle, IDLEN,IDLEN,
+ lostbms[i].bmname,lostbms[i].lostdays);
+ }else{
+ fprintf(inf, "%-*.*s%-*.*s%-*.*s%3d¤Ñ¨S¤W¯¸\n", IDLEN, IDLEN, lostbms[i].title,
+ BTLEN-10, BTLEN-10, lostbms[i].ctitle, IDLEN,IDLEN,
+ lostbms[i].bmname,lostbms[i].lostdays);
+ }
+ }
+ fclose(inf);
+ fclose(firef);
+
+ //printf("Total %d boards.\n", count);
+
+ //mail to the users
+ for( i=0; i<j; i++)
+ {
+ fileheader_t mymail;
+ char genbuf[200];
+ int lostdays;
+
+ lostdays = lostbms[i].lostdays;
+
+ if( (lostdays != 30) && (lostdays != 45) && (lostdays <= 60))
+ continue;
+
+ sprintf(genbuf, BBSHOME "/home/%c/%s", lostbms[i].bmname[0], lostbms[i].bmname);
+ stampfile(genbuf, &mymail);
+
+ strcpy(mymail.owner, "[PTTĵ¹î§½]");
+
+ if(lostdays <= 60){
+ sprintf(mymail.title,
+ "\033[32m [ª©¥D§K¾ĵ§i³qª¾] \033[m %s BM %s", lostbms[i].title, lostbms[i].bmname);
+ }else{
+ sprintf(mymail.title,
+ "\033[32m [ª©¥D§K¾³qª¾] \033[m %s BM %s", lostbms[i].title, lostbms[i].bmname);
+ }
+ mymail.savemode = 0 ;
+ unlink(genbuf);
+ if(lostdays <= 60){
+ LINK(OUTFILE, genbuf);
+ }else{
+ LINK(FIREFILE, genbuf);
+ }
+
+ sprintf(genbuf, BBSHOME "/home/%c/%s/.DIR", lostbms[i].bmname[0], lostbms[i].bmname);
+ append_record(genbuf, &mymail, sizeof(mymail));
+ }
+
+ return 0;
+}
diff --git a/util/toplazyBM.sh b/util/toplazyBM.sh
new file mode 100644
index 00000000..033e545f
--- /dev/null
+++ b/util/toplazyBM.sh
@@ -0,0 +1,3 @@
+bin/toplazyBM
+bin/post Record Ãi´kª©¥D±Æ¦æº] [Pttĵ¹î§½] etc/toplazyBM
+bin/post ViolateLaw ¤µ¤é§K¾ª©¥D [Pttªk°'|'] etc/firelazyBM
diff --git a/util/topsong.sh b/util/topsong.sh
new file mode 100644
index 00000000..19e9663a
--- /dev/null
+++ b/util/topsong.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# $Id: topsong.sh,v 1.1 2002/03/07 15:13:46 in2 Exp $
+#
+bin/post Record "¤W¥b­Ó¤ëÂIºq±Æ¦æº]" "[Ptt¬y¦æºô]" etc/topsong
+mv ussong tmp
diff --git a/util/topusr.c b/util/topusr.c
new file mode 100644
index 00000000..22b95e94
--- /dev/null
+++ b/util/topusr.c
@@ -0,0 +1,205 @@
+/* $Id: topusr.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+/* ¨Ï¥ÎªÌ ¤W¯¸°O¿ý/¤å³¹½g¼Æ ±Æ¦æº] */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "perm.h"
+#include "common.h"
+#include "util.h"
+
+#define REAL_INFO
+struct manrec
+{
+ char userid[IDLEN + 1];
+ char username[23];
+ int values[3];
+};
+typedef struct manrec manrec;
+struct manrec *allman[3];
+
+userec_t aman;
+manrec theman;
+int num;
+FILE *fp;
+
+#define TYPE_POST 0
+#define TYPE_LOGIN 1
+#define TYPE_MONEY 2
+
+
+void
+ top(type)
+{
+ static char *str_type[3] =
+ {"µoªí¦¸¼Æ", "¶i¯¸¦¸¼Æ", " ¤j´I¯Î "};
+ int i, j, rows = (num + 1) / 2;
+ char buf1[80], buf2[80];
+
+ if (type != 2)
+ fprintf(fp, "\n\n");
+
+ fprintf(fp, "\
+ ¢~¢w¢w¢w¢w¢w¢¡ [%dm %8.8s±Æ¦æº]  ¢~¢w¢w¢w¢w¢w¢¡\n\
+ ¦W¦¸¢w¥N¸¹¢w¢w¢w¼ÊºÙ¢w¢w¢w¢w¢w¢w¼Æ¥Ø¢w¢w¦W¦¸¢w¥N¸¹¢w¢w¢w¼ÊºÙ¢w¢w¢w¢w¢w¢w¼Æ¥Ø\
+", type + 44, str_type[type]);
+ for (i = 0; i < rows; i++)
+ {
+ char ch=' ';
+ int value;
+
+ if(allman[type][i].values[type] > 1000000000)
+ { value=allman[type][i].values[type]/1000000; ch='M';}
+ else if(allman[type][i].values[type] > 1000000)
+ { value=allman[type][i].values[type]/1000; ch='K';}
+ else {value=allman[type][i].values[type]; ch=' ';}
+ sprintf(buf1, "[%2d] %-11.11s%-16.16s%5d%c",
+ i + 1, allman[type][i].userid, allman[type][i].username,
+ value, ch);
+ j = i + rows;
+ if(allman[type][j].values[type] > 1000000000)
+ { value=allman[type][j].values[type]/1000000; ch='M';}
+ else if(allman[type][j].values[type] > 1000000)
+ { value=allman[type][j].values[type]/1000; ch='K';}
+ else {value=allman[type][j].values[type]; ch=' ';}
+
+ sprintf(buf2, "[%2d] %-11.11s%-16.16s%4d%c",
+ j + 1, allman[type][j].userid, allman[type][j].username,
+ value, ch);
+ if (i < 3)
+ fprintf(fp, "\n [1;%dm%-40s%s", 31 + i, buf1, buf2);
+ else
+ fprintf(fp, "\n %-40s%s", buf1, buf2);
+ }
+}
+
+
+#ifdef HAVE_TIN
+int
+ post_in_tin(char *name)
+{
+ char buf[256];
+ FILE *fh;
+ int counter = 0;
+
+ sprintf(buf, "%s/home/%c/%s/.tin/posted", home_path, name[0], name);
+ fh = fopen(buf, "r");
+ if (fh == NULL)
+ return 0;
+ else
+ {
+ while (fgets(buf, 255, fh) != NULL)
+ counter++;
+ fclose(fh);
+ return counter;
+ }
+}
+#endif /* HAVE_TIN */
+int
+ not_alpha(ch)
+register char ch;
+{
+ return (ch < 'A' || (ch > 'Z' && ch < 'a') || ch > 'z');
+}
+
+int
+ not_alnum(ch)
+register char ch;
+{
+ return (ch < '0' || (ch > '9' && ch < 'A') ||
+ (ch > 'Z' && ch < 'a') || ch > 'z');
+}
+
+int
+ bad_user_id(userid)
+char *userid;
+{
+ register char ch;
+ if (strlen(userid) < 2)
+ return 1;
+ if (not_alpha(*userid))
+ return 1;
+ while((ch = *(++userid)))
+ {
+ if (not_alnum(ch))
+ return 1;
+ }
+ return 0;
+}
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ int i, j;
+
+ if (argc < 3)
+ {
+ printf("Usage: %s <num_top> <out-file>\n", argv[0]);
+ exit(1);
+ }
+
+ num = atoi(argv[1]);
+ if (num == 0)
+ num = 30;
+
+ if(passwd_mmap())
+ {
+ printf("Sorry, the data is not ready.\n");
+ exit(0);
+ }
+ for(i=0; i<3; i++)
+ {
+ allman[i]=malloc(sizeof(manrec) * num);
+ memset(allman[i],0,sizeof(manrec) * num);
+ }
+ for(j = 1; j <= MAX_USERS; j++) {
+ passwd_query(j, &aman);
+ aman.userid[IDLEN]=0;
+ aman.username[22]=0;
+ if((aman.userlevel & PERM_NOTOP) || !aman.userid[0] ||
+ bad_user_id(aman.userid) ||
+ strchr(aman.userid, '.'))
+ {
+ continue;
+ }
+ else {
+ strcpy(theman.userid, aman.userid);
+ strcpy(theman.username, aman.username);
+ theman.values[TYPE_LOGIN] = aman.numlogins;
+ theman.values[TYPE_POST] = aman.numposts;
+ theman.values[TYPE_MONEY] = aman.money;
+ for(i=0; i<3; i++)
+ {
+ int k,l;
+ for(k=num-1; k>=0 && allman[i][k].values[i]<theman.values[i];
+ k--);
+ k++;
+ if(k<num)
+ {
+ for(l=num-1; l>k; l--)
+ memcpy(&allman[i][l], &allman[i][l-1],
+ sizeof(manrec));
+ memcpy(&allman[i][k], &theman, sizeof(manrec));
+ }
+ }
+ }
+ }
+
+
+ if ((fp = fopen(argv[2], "w")) == NULL)
+ {
+ printf("cann't open topusr\n");
+ return 0;
+ }
+
+ top(TYPE_MONEY);
+ top(TYPE_POST);
+ top(TYPE_LOGIN);
+
+ fclose(fp);
+ return 0;
+}
diff --git a/util/tunepasswd.c b/util/tunepasswd.c
new file mode 100644
index 00000000..15a3fe1f
--- /dev/null
+++ b/util/tunepasswd.c
@@ -0,0 +1,77 @@
+/* $Id: tunepasswd.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+
+int tune(int num) {
+ int i, j, fin, fout;
+ userec_t u;
+
+ if((fin = open(FN_PASSWD, O_RDONLY)) == -1) {
+ perror(FN_PASSWD);
+ return 1;
+ }
+ if(flock(fin, LOCK_EX)) {
+ printf("Lock failed!\n");
+ return 1;
+ }
+ if((fout = open(FN_PASSWD ".tune" , O_WRONLY | O_CREAT, 0600)) == -1) {
+ perror(FN_PASSWD ".tune");
+ flock(fin, LOCK_UN);
+ close(fin);
+ return 1;
+ }
+
+ for(i = j = 0; i < num; i++) {
+ read(fin, &u, sizeof(u));
+ if(u.userid[0]) {
+ if(j == MAX_USERS) {
+ printf("MAX_USERS is too small!\n");
+ close(fout);
+ unlink(FN_PASSWD ".tune");
+ flock(fin, LOCK_UN);
+ close(fin);
+ return 1;
+ }
+ write(fout, &u, sizeof(u));
+ j++;
+ }
+ }
+ for(memset(&u, 0, sizeof(u)); j < MAX_USERS; j++) {
+ write(fout, &u, sizeof(u));
+ }
+ close(fout);
+
+ /* backup */
+ unlink(FN_PASSWD "~");
+ link(FN_PASSWD, FN_PASSWD "~");
+ unlink(FN_PASSWD);
+ link(FN_PASSWD ".tune", FN_PASSWD);
+ unlink(FN_PASSWD ".tune");
+
+ flock(fin, LOCK_UN);
+ close(fin);
+ return 0;
+}
+
+int main() {
+ struct stat sb;
+
+ if(stat(FN_PASSWD, &sb)) {
+ perror("stat");
+ return 1;
+ }
+ if(sb.st_size != sizeof(userec_t) * MAX_USERS) {
+ printf("size and MAX_USERS do not match!\n");
+ if(tune(sb.st_size / sizeof(userec_t)) == 0)
+ printf(FN_PASSWD " has been tuned successfully!\n");
+ } else
+ printf("Nothing to do.\n");
+ return 0;
+}
diff --git a/util/uhash_loader.c b/util/uhash_loader.c
new file mode 100644
index 00000000..2d88dd06
--- /dev/null
+++ b/util/uhash_loader.c
@@ -0,0 +1,129 @@
+/* $Id: uhash_loader.c,v 1.1 2002/03/07 15:13:47 in2 Exp $ */
+/* standalone uhash loader -- jochang */
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#ifdef __FreeBSD__
+#include <machine/param.h>
+#endif
+
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+
+unsigned string_hash(unsigned char *s);
+void add_to_uhash(int n, userec_t *id);
+void fill_uhash(void);
+void load_uhash(void);
+
+uhash_t *uhash;
+
+int main() {
+ setgid(BBSGID);
+ setuid(BBSUID);
+ chdir(BBSHOME);
+ load_uhash();
+ return 0;
+}
+
+void load_uhash(void) {
+ int shmid;
+ shmid = shmget(UHASH_KEY, sizeof(uhash_t), IPC_CREAT | 0600);
+/* note we didn't use IPC_EXCL here.
+ so if the loading fails,
+ (like .PASSWD doesn't exist)
+ we may try again later.
+*/
+ if (shmid < 0)
+ {
+ perror("shmget");
+ exit(1);
+ }
+
+ uhash = (void *) shmat(shmid, NULL, 0);
+ if (uhash == (void *) -1)
+ {
+ perror("shmat");
+ exit(1);
+ }
+
+/* in case it's not assumed zero, this becomes a race... */
+ uhash->loaded = 0;
+
+ fill_uhash();
+
+/* ok... */
+ uhash->loaded = 1;
+}
+
+void fill_uhash(void)
+{
+ int fd, usernumber;
+ usernumber = 0;
+
+ for (fd = 0; fd < (1 << HASH_BITS); fd++)
+ uhash->hash_head[fd] = -1;
+
+ if ((fd = open(FN_PASSWD, O_RDONLY)) > 0)
+ {
+ struct stat stbuf;
+ caddr_t fimage, mimage;
+
+ fstat(fd, &stbuf);
+ fimage = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (fimage == (char *) -1)
+ {
+ perror("mmap");
+ exit(1);
+ }
+ close(fd);
+ fd = stbuf.st_size / sizeof(userec_t);
+ if (fd > MAX_USERS)
+ fd = MAX_USERS;
+
+ for (mimage = fimage; usernumber < fd; mimage += sizeof(userec_t))
+ {
+ add_to_uhash(usernumber, mimage);
+ usernumber++;
+ }
+ munmap(fimage, stbuf.st_size);
+ }
+ else
+ {
+ perror("open");
+ exit(1);
+ }
+ uhash->number = usernumber;
+ printf("total %d names loaded.\n", usernumber);
+}
+unsigned string_hash(unsigned char *s)
+{
+ unsigned int v = 0;
+ while (*s)
+ {
+ v = (v << 8) | (v >> 24);
+ v ^= toupper(*s++); /* note this is case insensitive */
+ }
+ return (v * 2654435769UL) >> (32 - HASH_BITS);
+}
+
+void add_to_uhash(int n, userec_t *user)
+{
+ int *p, h = string_hash(user->userid);
+ strcpy(uhash->userid[n], user->userid);
+ uhash->money[n] = user->money;
+ p = &(uhash->hash_head[h]);
+
+ while (*p != -1)
+ p = &(uhash->next_in_hash[*p]);
+
+ uhash->next_in_hash[*p = n] = -1;
+}
diff --git a/util/userlist.c b/util/userlist.c
new file mode 100644
index 00000000..9a142926
--- /dev/null
+++ b/util/userlist.c
@@ -0,0 +1,48 @@
+/* $id:$ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include "config.h"
+#include "pttstruct.h"
+
+struct utmpfile_t *u;
+
+int main(int argc, char **argv) {
+ int i, shm, counter;
+
+ shm = shmget(UTMPSHM_KEY, USHM_SIZE, SHM_R | SHM_W);
+ if(shm == -1) {
+ perror("shmget");
+ exit(0);
+ }
+
+ u = shmat(shm, NULL, 0);
+ if(u == (struct utmpfile_t *)-1) {
+ perror("shmat");
+ exit(0);
+ }
+
+ if(argc > 1) {
+ for(i = 1; i < argc; i++)
+ u->uinfo[atoi(argv[i])].pid = 0;
+ } else {
+ for(i = counter = 0; i < USHM_SIZE; i++)
+ if(u->uinfo[i].pid) {
+ userinfo_t *f;
+
+ f = &u->uinfo[i];
+ printf(
+ "%4d(%d) p[%d] i[%d] u[%s] n[%s] f[%s] m[%d] d[%d] t[%ld]\n",
+ ++counter, i, f->pager, f->invisible, f->userid,
+ f->username, f->from, f->mode, f->mind, f->lastact);
+ }
+ printf("\nTotal: %d(%d)\n", counter, u->number);
+ if(counter != u->number) {
+ u->number = counter;
+ printf("adjust user number!\n");
+ }
+ }
+ return 0;
+}
diff --git a/util/util.h b/util/util.h
new file mode 100644
index 00000000..9128e575
--- /dev/null
+++ b/util/util.h
@@ -0,0 +1,31 @@
+/* $Id: util.h,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+#ifndef INCLUDE_UTIL_H
+#define INCLUDE_UTIL_H
+
+int searchuser(char *userid);
+int stampfile(char *fpath, fileheader_t *fh);
+int append_record(char *fpath, fileheader_t *record, int size);
+int get_record(char *fpath, void *rptr, int size, int id);
+int substitute_record(char *fpath, void *rptr, int size, int id);
+void resolve_boards();
+int getbnum(char *bname);
+void inbtotal(int bid, int add);
+void *attach_shm(int shmkey, int shmsize);
+void reload_pttcache();
+void resolve_fcache();
+void attach_uhash();
+void stamplink(char *fpath, fileheader_t *fh);
+void resolve_utmp();
+void remove_from_uhash(int n);
+void setuserid(int num, char *userid);
+
+int passwd_mmap();
+int passwd_update(int num, userec_t *buf);
+int passwd_query(int num, userec_t *buf);
+int passwd_apply(int (*fptr)(userec_t *));
+int passwd_apply2(int (*fptr)(int, userec_t *));
+void passwd_lock();
+void passwd_unlock();
+
+#endif
+
diff --git a/util/util_cache.c b/util/util_cache.c
new file mode 100644
index 00000000..12a01994
--- /dev/null
+++ b/util/util_cache.c
@@ -0,0 +1,518 @@
+/* $Id: util_cache.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+
+#ifdef __FreeBSD__
+#include <machine/param.h>
+#endif
+
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "perm.h"
+#include "modes.h"
+#include "proto.h"
+
+int fcache_semid;
+
+/* the reason for "safe_sleep" is that we may call sleep during
+ SIGALRM handler routine, while SIGALRM is blocked.
+ if we use the original sleep, we'll never wake up. */
+unsigned int safe_sleep(unsigned int seconds) {
+ /* jochang sleep¦³°ÝÃD®É¥Î*/
+ sigset_t set,oldset;
+
+ sigemptyset(&set);
+ sigprocmask(SIG_BLOCK, &set, &oldset);
+ if(sigismember(&oldset, SIGALRM)) {
+ unsigned long retv;
+ sigemptyset(&set);
+ sigaddset(&set,SIGALRM);
+ sigprocmask(SIG_UNBLOCK,&set,NULL);
+ retv=sleep(seconds);
+ sigprocmask(SIG_BLOCK,&set,NULL);
+ return retv;
+ }
+ return sleep(seconds);
+}
+
+void setapath(char *buf, char *boardname) {
+ sprintf(buf, "man/boards/%s", boardname);
+}
+
+static char *str_dotdir = ".DIR";
+
+void setadir(char *buf, char *path) {
+ sprintf(buf, "%s/%s", path, str_dotdir);
+}
+
+static void attach_err(int shmkey, char *name) {
+ fprintf(stderr, "[%s error] key = %x\n", name, shmkey);
+ fprintf(stderr, "errno = %d: %s\n", errno, strerror(errno));
+ exit(1);
+}
+
+void *attach_shm(int shmkey, int shmsize) {
+ void *shmptr;
+ int shmid;
+
+ char *empty_addr;
+ /* set up one page in-accessible -- jochang */
+ {
+ int fd = open("/dev/zero",O_RDONLY);
+ int size = ((shmsize + 4095) / 4096) * 4096;
+
+ munmap(
+ (empty_addr=mmap(0,4096+size,PROT_NONE,MAP_PRIVATE,fd,0))+4096
+ ,size);
+
+ close(fd);
+ }
+
+ shmid = shmget(shmkey, shmsize, 0);
+ if(shmid < 0) {
+ shmid = shmget(shmkey, shmsize, IPC_CREAT | 0600);
+ if(shmid < 0)
+ attach_err(shmkey, "shmget");
+ shmptr = (void *)shmat(shmid, NULL, 0);
+ if(shmptr == (void *)-1)
+ attach_err(shmkey, "shmat");
+ } else {
+ shmptr = (void *)shmat(shmid, NULL, 0);
+ if(shmptr == (void *)-1)
+ attach_err(shmkey, "shmat");
+ }
+
+ /* unmap the page -- jochang */
+ {
+ munmap(empty_addr,4096);
+ }
+ return shmptr;
+}
+
+#ifndef __FreeBSD__
+/* according to X/OPEN we have to define it ourselves */
+union semun {
+ int val; /* value for SETVAL */
+ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
+ unsigned short int *array; /* array for GETALL, SETALL */
+ struct seminfo *__buf; /* buffer for IPC_INFO */
+};
+#endif
+
+#define SEM_FLG 0600 /* semaphore mode */
+
+/* ----------------------------------------------------- */
+/* semaphore : for critical section */
+/* ----------------------------------------------------- */
+void sem_init(int semkey,int *semid) {
+ union semun s;
+
+ s.val=1;
+ *semid = semget(semkey, 1, 0);
+ if(*semid == -1) {
+ *semid = semget(semkey, 1, IPC_CREAT | SEM_FLG);
+ if(*semid == -1)
+ attach_err(semkey, "semget");
+ semctl(*semid, 0, SETVAL, s);
+ }
+}
+
+void sem_lock(int op,int semid) {
+ struct sembuf sops;
+
+ sops.sem_num = 0;
+ sops.sem_flg = SEM_UNDO;
+ sops.sem_op = op;
+ semop(semid, &sops, 1);
+}
+
+/* uhash *******************************************/
+/* the design is this:
+ we use another stand-alone program to create and load data into the hash.
+ (that program could be run in rc-scripts or something like that)
+ after loading completes, the stand-alone program sets loaded to 1 and exits.
+
+ the bbs exits if it can't attach to the shared memory or
+ the hash is not loaded yet.
+*/
+uhash_t *uhash;
+
+int setumoney(int uid, int money) {
+ uhash->money[uid-1]=money;
+ passwd_update_money(uid);
+ return uhash->money[uid-1];
+}
+
+int deumoney(int uid, int money) {
+ if(money<0 && uhash->money[uid-1]<-money)
+ return setumoney(uid,0);
+ else
+ return setumoney(uid,uhash->money[uid-1]+money);
+}
+int moneyof(int uid){ /* ptt §ï¶iª÷¿ú³B²z®Ä²v */
+ return uhash->money[uid-1];
+}
+/* attach_uhash should be called before using uhash */
+void attach_uhash() {
+ uhash = attach_shm(UHASH_KEY, sizeof(*uhash));
+ if(!uhash->loaded) /* assume fresh shared memory is zeroed */
+ exit(1);
+}
+
+
+static unsigned string_hash(unsigned char *s) {
+ unsigned int v=0;
+ while(*s) {
+ v = (v << 8) | (v >> 24);
+ v ^= toupper(*s++); /* note this is case insensitive */
+ }
+ return (v * 2654435769UL) >> (32 - HASH_BITS);
+}
+
+void add_to_uhash(int n, char *id) {
+ int *p, h = string_hash(id);
+ strcpy(uhash->userid[n], id);
+
+ p = &(uhash->hash_head[h]);
+
+ while(*p != -1)
+ p = &(uhash->next_in_hash[*p]);
+
+ uhash->next_in_hash[*p = n] = -1;
+}
+
+/* note: after remove_from_uhash(), you should add_to_uhash()
+ (likely with a different name) */
+void remove_from_uhash(int n) {
+ int h = string_hash(uhash->userid[n]);
+ int *p = &(uhash->hash_head[h]);
+
+ while(*p != -1 && *p != n)
+ p = &(uhash->next_in_hash[*p]);
+ if(*p == n)
+ *p = uhash->next_in_hash[n];
+}
+
+int searchuser(char *userid) {
+ int h,p;
+
+ if(uhash == NULL)
+ attach_uhash(); /* for sloopy util programs */
+
+ h = string_hash(userid);
+ p = uhash->hash_head[h];
+
+ while(p != -1) {
+ if(strcasecmp(uhash->userid[p],userid) == 0) {
+ strcpy(userid,uhash->userid[p]);
+ return p + 1;
+ }
+ p = uhash->next_in_hash[p];
+ }
+ return 0;
+}
+userec_t xuser;
+
+int getuser(char *userid) {
+ int uid;
+ if((uid = searchuser(userid)))
+ passwd_query(uid, &xuser);
+ return uid;
+}
+void setuserid(int num, char *userid) {
+ if(num > 0 && num <= MAX_USERS) {
+ if(num > uhash->number)
+ uhash->number = num;
+ else
+ remove_from_uhash(num-1);
+ add_to_uhash(num-1,userid);
+ }
+}
+
+/*-------------------------------------------------------*/
+/* .UTMP cache */
+/*-------------------------------------------------------*/
+struct utmpfile_t *utmpshm=NULL;
+
+void resolve_utmp() {
+ if(utmpshm == NULL) {
+ utmpshm = attach_shm(UTMPSHM_KEY, sizeof(*utmpshm));
+ if(utmpshm->uptime == 0)
+ utmpshm->uptime = utmpshm->number = 1;
+ }
+}
+
+userinfo_t *currutmp = NULL;
+
+void getnewutmpent(userinfo_t *up) {
+ extern int errno;
+ register int i;
+ register userinfo_t *uentp;
+
+ resolve_utmp();
+
+ for(i = 0; i < USHM_SIZE; i++) {
+ uentp = &(utmpshm->uinfo[i]);
+ if(!(uentp->pid)) {
+ memcpy(uentp, up, sizeof(userinfo_t));
+ currutmp = uentp;
+ utmpshm->number++;
+ return;
+ }
+ }
+ exit(1);
+}
+
+int apply_ulist(int (*fptr)(userinfo_t *)) {
+ register userinfo_t *uentp;
+ register int i, state;
+
+ resolve_utmp();
+ for(i = 0; i < USHM_SIZE; i++) {
+ uentp = &(utmpshm->uinfo[i]);
+ if(uentp->pid && (PERM_HIDE(currutmp) || !PERM_HIDE(uentp)))
+ if((state = (*fptr) (uentp)))
+ return state;
+ }
+ return 0;
+}
+
+userinfo_t *search_ulist(int uid) {
+ register int i;
+ register userinfo_t *uentp;
+
+ resolve_utmp();
+ for(i = 0; i < USHM_SIZE; i++) {
+ uentp = &(utmpshm->uinfo[i]);
+ if(uid==uentp->uid)
+ return uentp;
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------*/
+/* .BOARDS cache */
+/*-------------------------------------------------------*/
+char *fn_board=FN_BOARD;
+bcache_t *brdshm;
+boardheader_t *bcache;
+
+static void reload_bcache() {
+ if(brdshm->busystate) {
+ safe_sleep(1);
+ }
+}
+
+int numboards = -1;
+
+void resolve_boards() {
+ if(brdshm == NULL) {
+ brdshm = attach_shm(BRDSHM_KEY, sizeof(*brdshm));
+ if(brdshm->touchtime == 0)
+ brdshm->touchtime = 1;
+ bcache = brdshm->bcache;
+ }
+
+ while(brdshm->uptime < brdshm->touchtime)
+ reload_bcache();
+ numboards = brdshm->number;
+}
+
+void touch_boards() {
+ time(&(brdshm->touchtime));
+ numboards = -1;
+ resolve_boards();
+}
+void reset_board(int bid)
+{
+ int fd;
+ if(--bid<0)return;
+ if(brdshm->busystate==0)
+ {
+ brdshm->busystate = 1;
+ if((fd = open(fn_board, O_RDONLY)) > 0) {
+ lseek(fd, (off_t)(bid * sizeof(boardheader_t)), SEEK_SET);
+ read(fd, &bcache[bid], sizeof(boardheader_t));
+ close(fd);
+ }
+ brdshm->busystate = 0;
+ }
+}
+boardheader_t *getbcache(int bid) { /* Ptt§ï¼g */
+ return bcache + bid - 1;
+}
+
+void touchbtotal(int bid) {
+ brdshm->total[bid - 1] = 0;
+ brdshm->lastposttime[bid - 1] = 0;
+}
+
+
+int getbnum(char *bname) {
+ register int i;
+ register boardheader_t *bhdr;
+
+ for(i = 0, bhdr = bcache; i++ < numboards; bhdr++)
+ if(
+ !strcasecmp(bname, bhdr->brdname))
+ return i;
+ return 0;
+}
+
+/*-------------------------------------------------------*/
+/* PTT cache */
+/*-------------------------------------------------------*/
+/* cachefor °ÊºA¬Ýª© */
+struct pttcache_t *ptt;
+
+void reload_pttcache() {
+ if(ptt->busystate)
+ safe_sleep(1);
+ else { /* jochang: temporary workaround */
+ fileheader_t item, subitem;
+ char pbuf[256], buf[256], *chr;
+ FILE *fp, *fp1, *fp2;
+ int id, section = 0;
+
+ ptt->busystate = 1;
+ ptt->max_film = 0;
+ bzero(ptt->notes, sizeof ptt->notes);
+ setapath(pbuf, "Note");
+ setadir(buf, pbuf);
+ id = 0;
+ if((fp = fopen(buf, "r"))) {
+ while(fread(&item, sizeof(item), 1, fp)) {
+ if(item.title[3]=='<' && item.title[8]=='>') {
+ sprintf(buf,"%s/%s", pbuf, item.filename);
+ setadir(buf, buf);
+ if(!(fp1 = fopen(buf, "r")))
+ continue;
+ ptt->next_refresh[section] = ptt->n_notes[section] = id;
+ section ++;
+ while(fread(&subitem, sizeof(subitem), 1, fp1)) {
+ sprintf(buf,"%s/%s/%s", pbuf, item.filename ,
+ subitem.filename);
+ if(!(fp2=fopen(buf,"r")))
+ continue;
+ fread(ptt->notes[id],sizeof(char), 200*11, fp2);
+ ptt->notes[id][200*11 - 1]=0;
+ id++;
+ fclose(fp2);
+ if(id >= MAX_MOVIE)
+ break;
+ }
+ fclose(fp1);
+ if(id >= MAX_MOVIE || section >= MAX_MOVIE_SECTION)
+ break;
+ }
+ }
+ fclose(fp);
+ }
+ ptt->next_refresh[section] = -1;
+ ptt->n_notes[section] = ptt->max_film = id-1;
+ ptt->max_history = ptt->max_film - 2;
+ if(ptt->max_history > MAX_HISTORY - 1)
+ ptt->max_history = MAX_HISTORY - 1;
+ if(ptt->max_history <0) ptt->max_history=0;
+
+ fp = fopen("etc/today_is","r");
+ if(fp) {
+ fgets(ptt->today_is,15,fp);
+ if((chr = strchr(ptt->today_is,'\n')))
+ *chr = 0;
+ ptt->today_is[15] = 0;
+ fclose(fp);
+ }
+
+ /* µ¥©Ò¦³¸ê®Æ§ó·s«á¦A³]©w uptime */
+
+ ptt->uptime = ptt->touchtime ;
+ ptt->busystate = 0;
+ }
+}
+
+void resolve_garbage() {
+ int count=0;
+
+ if(ptt == NULL) {
+ ptt = attach_shm(PTTSHM_KEY, sizeof(*ptt));
+ if(ptt->touchtime == 0)
+ ptt->touchtime = 1;
+ }
+ while(ptt->uptime < ptt->touchtime) { /* ¤£¥Îwhileµ¥ */
+ reload_pttcache();
+ if(count ++ > 10 && ptt->busystate) {
+/* Ptt: ³oÃä·|¦³°ÝÃD load¶W¹L10 ¬í·|©Ò¦³¶iloopªºprocess³£Åý busystate = 0
+ ³o¼Ë·|©Ò¦³prcosee³£·|¦bload °ÊºA¬ÝªO ·|³y¦¨load¤j¼W
+ ¦ý¨S¦³¥Î³o­Ófunctionªº¸Ü ¸U¤@load passwdÀɪºprocess¦º¤F ¤S¨S¦³¤H§â¥L
+ ¸Ñ¶} ¦P¼Ëªº°ÝÃDµo¥Í¦breload passwd
+*/
+ ptt->busystate = 0;
+ }
+ }
+}
+
+/*-------------------------------------------------------*/
+/* PTT's cache */
+/*-------------------------------------------------------*/
+/* cachefor from host »P³Ì¦h¤W½u¤H¼Æ */
+struct fromcache_t *fcache;
+
+static void reload_fcache() {
+ if(fcache->busystate)
+ safe_sleep(1);
+ else {
+ FILE *fp;
+
+ fcache->busystate = 1;
+ bzero(fcache->domain, sizeof fcache->domain);
+ if((fp = fopen("etc/domain_name_query","r"))) {
+ char buf[101],*po;
+
+ fcache->top=0;
+ while(fgets(buf,100,fp)) {
+ if(buf[0] && buf[0] != '#' && buf[0] != ' ' &&
+ buf[0] != '\n') {
+ sscanf(buf,"%s",fcache->domain[fcache->top]);
+ po = buf + strlen(fcache->domain[fcache->top]);
+ while(*po == ' ')
+ po++;
+ strncpy(fcache->replace[fcache->top],po,49);
+ fcache->replace[fcache->top]
+ [strlen(fcache->replace[fcache->top])-1] = 0;
+ (fcache->top)++;
+ }
+ }
+ }
+
+ fcache->max_user=0;
+
+ /* µ¥©Ò¦³¸ê®Æ§ó·s«á¦A³]©w uptime */
+ fcache->uptime = fcache->touchtime;
+ fcache->busystate = 0;
+ }
+}
+
+void resolve_fcache() {
+ if(fcache == NULL) {
+ fcache = attach_shm(FROMSHM_KEY, sizeof(*fcache));
+ if(fcache->touchtime == 0)
+ fcache->touchtime = 1;
+ }
+ while(fcache->uptime < fcache->touchtime)
+ reload_fcache();
+}
diff --git a/util/util_passwd.c b/util/util_passwd.c
new file mode 100644
index 00000000..07a79351
--- /dev/null
+++ b/util/util_passwd.c
@@ -0,0 +1,139 @@
+/* $Id: util_passwd.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "modes.h"
+#include "common.h"
+
+#ifndef SEM_R
+#define SEM_R 0400
+#endif
+
+#ifndef SEM_A
+#define SEM_A 0200
+#endif
+
+#ifndef __FreeBSD__
+union semun {
+ int val; /* value for SETVAL */
+ struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
+ u_short *array; /* array for GETALL & SETALL */
+ struct seminfo *__buf; /* buffer for IPC_INFO */
+};
+#endif
+
+static userec_t *passwd_image = NULL;
+static int passwd_image_size;
+static int semid = -1;
+
+int passwd_mmap() {
+ int fd;
+
+ if(passwd_image!=NULL) return 0;
+ fd = open(FN_PASSWD, O_RDWR);
+ if(fd > 0) {
+ struct stat st;
+
+ fstat(fd, &st);
+ passwd_image_size = st.st_size;
+ passwd_image = mmap(NULL, passwd_image_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if(passwd_image == (userec_t *)-1) {
+ perror("mmap");
+ return -1;
+ }
+ close(fd);
+ semid = semget(PASSWDSEM_KEY, 1, SEM_R | SEM_A | IPC_CREAT | IPC_EXCL);
+ if(semid == -1) {
+ if(errno == EEXIST) {
+ semid = semget(PASSWDSEM_KEY, 1, SEM_R | SEM_A);
+ if(semid == -1) {
+ perror("semget");
+ exit(1);
+ }
+ } else {
+ perror("semget");
+ exit(1);
+ }
+ } else {
+ union semun s;
+
+ s.val = 1;
+ if(semctl(semid, 0, SETVAL, s) == -1) {
+ perror("semctl");
+ exit(1);
+ }
+ }
+ } else {
+ perror(FN_PASSWD);
+ return -1;
+ }
+ return 0;
+}
+int passwd_update_money(int num) {
+ int money;
+ if(num < 1 || num > MAX_USERS)
+ return -1;
+ money = moneyof(num);
+ memcpy(&passwd_image[num - 1].money, &money, sizeof(int));
+ return 0;
+}
+
+int passwd_update(int num, userec_t *buf) {
+ if(num < 1 || num > MAX_USERS)
+ return -1;
+ buf->money = moneyof(num);
+ memcpy(&passwd_image[num - 1], buf, sizeof(userec_t));
+ return 0;
+}
+
+int passwd_query(int num, userec_t *buf) {
+ if(num < 1 || num > MAX_USERS)
+ return -1;
+ memcpy(buf, &passwd_image[num - 1], sizeof(userec_t));
+ return 0;
+}
+
+int passwd_apply(int (*fptr)(userec_t *)) {
+ int i;
+
+ for(i = 0; i < MAX_USERS; i++)
+ if((*fptr)(&passwd_image[i]) == QUIT)
+ return QUIT;
+ return 0;
+}
+
+int passwd_apply2(int (*fptr)(int, userec_t *)) {
+ int i;
+
+ for(i = 0; i < MAX_USERS; i++)
+ if((*fptr)(i, &passwd_image[i]) == QUIT)
+ return QUIT;
+ return 0;
+}
+
+void passwd_lock() {
+ struct sembuf buf = { 0, -1, SEM_UNDO };
+
+ if(semop(semid, &buf, 1)) {
+ perror("semop");
+ exit(1);
+ }
+}
+
+void passwd_unlock() {
+ struct sembuf buf = { 0, 1, SEM_UNDO };
+
+ if(semop(semid, &buf, 1)) {
+ perror("semop");
+ exit(1);
+ }
+}
diff --git a/util/util_record.c b/util/util_record.c
new file mode 100644
index 00000000..ad129638
--- /dev/null
+++ b/util/util_record.c
@@ -0,0 +1,245 @@
+/* $Id: util_record.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "modes.h"
+#include "proto.h"
+
+#undef HAVE_MMAP
+#define BUFSIZE 512
+
+extern char *str_reply;
+
+static void PttLock(int fd, int size, int mode) {
+ static struct flock lock_it;
+ int ret;
+
+ lock_it.l_whence = SEEK_CUR; /* from current point */
+ lock_it.l_start = 0; /* -"- */
+ lock_it.l_len = size; /* length of data */
+ lock_it.l_type = mode; /* set exclusive/write lock */
+ lock_it.l_pid = 0; /* pid not actually interesting */
+ while((ret = fcntl(fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR);
+}
+
+#define safewrite write
+
+int get_num_records(char *fpath, int size) {
+ struct stat st;
+ if(stat(fpath, &st) == -1)
+ return 0;
+ return st.st_size / size;
+}
+
+int get_sum_records(char* fpath, int size) {
+ struct stat st;
+ long ans = 0;
+ FILE* fp;
+ fileheader_t fhdr;
+ char buf[200], *p;
+
+ if(!(fp = fopen(fpath, "r")))
+ return -1;
+
+ strcpy(buf, fpath);
+ p = strrchr(buf, '/') + 1;
+
+ while(fread(&fhdr, size, 1, fp) == 1) {
+ strcpy(p, fhdr.filename);
+ if(stat(buf, &st) == 0 && S_ISREG(st.st_mode) && st.st_nlink == 1)
+ ans += st.st_size;
+ }
+ fclose(fp);
+ return ans / 1024;
+}
+
+int get_record(char *fpath, void *rptr, int size, int id) {
+ int fd = -1;
+
+ if(id < 1 || (fd = open(fpath, O_RDONLY, 0)) != -1) {
+ if(lseek(fd, (off_t)(size * (id - 1)), SEEK_SET) != -1) {
+ if(read(fd, rptr, size) == size) {
+ close(fd);
+ return 0;
+ }
+ }
+ close(fd);
+ }
+ return -1;
+}
+
+int get_records(char *fpath, void *rptr, int size, int id, int number) {
+ int fd;
+
+ if(id < 1 || (fd = open(fpath, O_RDONLY, 0)) == -1)
+ return -1;
+
+ if(lseek(fd, (off_t)(size * (id - 1)), SEEK_SET) == -1) {
+ close(fd);
+ return 0;
+ }
+ if((id = read(fd, rptr, size * number)) == -1) {
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ return id / size;
+}
+
+int substitute_record(char *fpath, void *rptr, int size, int id) {
+ int fd;
+
+#ifdef POSTBUG
+ if(size == sizeof(fileheader) && (id > 1) && ((id - 1) % 4 == 0))
+ saverecords(fpath, size, id);
+#endif
+
+ if(id < 1 || (fd = open(fpath, O_WRONLY | O_CREAT, 0644)) == -1)
+ return -1;
+
+#ifdef HAVE_REPORT
+ if(lseek(fd, (off_t)(size * (id - 1)), SEEK_SET) == -1)
+ report("substitute_record failed!!! (lseek)");
+ PttLock(fd, size, F_WRLCK);
+ if(safewrite(fd, rptr, size) != size)
+ report("substitute_record failed!!! (safewrite)");
+ PttLock(fd, size, F_UNLCK);
+#else
+ lseek(fd, (off_t) (size * (id - 1)), SEEK_SET);
+ PttLock(fd, size, F_WRLCK);
+ safewrite(fd, rptr, size);
+ PttLock(fd, size, F_UNLCK);
+#endif
+ close(fd);
+
+#ifdef POSTBUG
+ if(size == sizeof(fileheader) && (id > 1) && ((id - 1) % 4 == 0))
+ restorerecords(fpath, size, id);
+#endif
+
+ return 0;
+}
+
+int apply_record(char *fpath, int (*fptr)(), int size) {
+ char abuf[BUFSIZE];
+ FILE* fp;
+
+ if(!(fp = fopen(fpath, "r")))
+ return -1;
+
+ while(fread(abuf, 1, size, fp) == size)
+ if((*fptr) (abuf) == QUIT) {
+ fclose(fp);
+ return QUIT;
+ }
+ fclose(fp);
+ return 0;
+}
+
+/* mail / post ®É¡A¨Ì¾Ú®É¶¡«Ø¥ßÀɮסA¥[¤W¶lÂW */
+int stampfile(char *fpath, fileheader_t *fh) {
+ register char *ip = fpath;
+ time_t dtime;
+ struct tm *ptime;
+ int fp = 0;
+
+ if(access(fpath, X_OK | R_OK | W_OK))
+ mkdir(fpath, 0755);
+
+ time(&dtime);
+ while (*(++ip));
+ *ip++ = '/';
+ do {
+ sprintf(ip, "M.%ld.A", ++dtime );
+ if(fp == -1 && errno != EEXIST)
+ return -1;
+ } while((fp = open(fpath, O_CREAT | O_EXCL | O_WRONLY, 0644)) == -1);
+ close(fp);
+ memset(fh, 0, sizeof(fileheader_t));
+ strcpy(fh->filename, ip);
+ ptime = localtime(&dtime);
+ sprintf(fh->date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday);
+ return 0;
+}
+
+void stampdir(char *fpath, fileheader_t *fh) {
+ register char *ip = fpath;
+ time_t dtime;
+ struct tm *ptime;
+
+ if(access(fpath, X_OK | R_OK | W_OK))
+ mkdir(fpath, 0755);
+
+ time(&dtime);
+ while(*(++ip));
+ *ip++ = '/';
+ do {
+ sprintf(ip, "D%lX", ++dtime & 07777);
+ } while(mkdir(fpath, 0755) == -1);
+ memset(fh, 0, sizeof(fileheader_t));
+ strcpy(fh->filename, ip);
+ ptime = localtime(&dtime);
+ sprintf(fh->date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday);
+}
+
+void stamplink(char *fpath, fileheader_t *fh) {
+ register char *ip = fpath;
+ time_t dtime;
+ struct tm *ptime;
+
+ if(access(fpath, X_OK | R_OK | W_OK))
+ mkdir(fpath, 0755);
+
+ time(&dtime);
+ while(*(++ip));
+ *ip++ = '/';
+ do {
+ sprintf(ip, "S%lX", ++dtime );
+ } while(symlink("temp", fpath) == -1);
+ memset(fh, 0, sizeof(fileheader_t));
+ strcpy(fh->filename, ip);
+ ptime = localtime(&dtime);
+ sprintf(fh->date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday);
+}
+
+int do_append(char *fpath, fileheader_t *record, int size) {
+ int fd;
+
+ if((fd = open(fpath, O_WRONLY | O_CREAT, 0644)) == -1) {
+ perror("open");
+ return -1;
+ }
+ flock(fd, LOCK_EX);
+ lseek(fd, 0, SEEK_END);
+
+ safewrite(fd, record, size);
+
+ flock(fd, LOCK_UN);
+ close(fd);
+ return 0;
+}
+
+int append_record(char *fpath, fileheader_t *record, int size) {
+#ifdef POSTBUG
+ int numrecs = (int)get_num_records(fpath, size);
+
+ bug_possible = 1;
+ if(size == sizeof(fileheader) && numrecs && (numrecs % 4 == 0))
+ saverecords(fpath, size, numrecs + 1);
+#endif
+ do_append(fpath,record,size);
+
+#ifdef POSTBUG
+ if(size == sizeof(fileheader) && numrecs && (numrecs % 4 == 0))
+ restorerecords(fpath, size, numrecs + 1);
+ bug_possible = 0;
+#endif
+ return 0;
+}
diff --git a/util/waterball.pl b/util/waterball.pl
new file mode 100644
index 00000000..7f49d3c5
--- /dev/null
+++ b/util/waterball.pl
@@ -0,0 +1,149 @@
+#!/usr/bin/perl
+use lib '/home/bbs/bin/';
+use LocalVars;
+use Time::Local;
+use POSIX;
+use FileHandle;
+use strict;
+use Mail::Sender;
+
+my($fndes, $fnsrc, $userid, $mailto, $outmode);
+foreach $fndes ( <$JOBSPOOL/water.des.*> ){ #des: userid, mailto, outmode
+ (open FH, "< $fndes") or next;
+ chomp($userid = <FH>);
+ chomp($mailto = <FH>);
+ chomp($outmode= <FH>);
+ close FH;
+ next if( !$userid );
+ print "$userid, $mailto, $outmode\n";
+ `rm -Rf $TMP/water`;
+ `mkdir $TMP/water`;
+
+ $fnsrc = $fndes;
+ $fnsrc =~ s/\.des\./\.src\./;
+ eval{
+ process($fnsrc, "$TMP/water/", $outmode, $userid);
+ };
+ if( $@ ){
+ print "$@\n";
+ }
+ else{
+ chdir "$TMP/water";
+ if( $mailto eq '.' || $mailto =~ /\.bbs/ ){
+ $mailto = "$userid.bbs\@$hostname" if( $mailto eq '.' );
+ foreach my $fn ( <$TMP/water/*> ){
+ my $who = substr($fn, rindex($fn, '/') + 1);
+ my $content = '';
+ open FH, "< $fn";while( <FH> ){chomp;$content .= "$_\n";}
+ if( !MakeMail({mailto => $mailto,
+ subject => "©M $who ªº¤ô²y°O¿ý",
+ body => $content,
+ }) ){ print "fault\n"; }
+ }
+ unlink $fnsrc;
+ unlink $fndes;
+ }
+ else{
+ if( MakeMail({tartarget => "$TMP/$userid.waterball.tgz",
+ tarsource => "*",
+ mailto => "$userid <$mailto>",
+ subject => "¤ô²y¬ö¿ý",
+ body =>
+ "\n ptt2 ¯¸ªø¸s ". POSIX::ctime(time())}
+ ) ){
+ unlink $fnsrc;
+ unlink $fndes;
+ }
+ }
+ }
+}
+
+sub process
+{
+ my($fn, $outdir, $outmode, $me) = @_;
+ my($cmode, $who, $time, $say, $orig, %FH, %LAST, $len);
+ open DIN, "< $fn";
+ while( <DIN> ){
+ chomp;
+ next if( !(($cmode, $who, $time, $say, $orig) = parse($_)) );
+ next if( !$who );
+
+ if( ! $FH{$who} ){
+ $FH{$who} = new FileHandle "> $outdir/$who";
+ }
+ if( $outmode == 0 ){
+ next if( $say =~ /<<¤U¯¸³qª¾>> -- §Ú¨«Åo¡I/ ||
+ $say =~ /<<¤W¯¸³qª¾>> -- §Ú¨Ó°Õ¡I/ );
+ if( $time - $LAST{$who} > 1800 ){
+ if( $LAST{$who} != 0 ){
+ ($FH{$who})->print( POSIX::ctime($LAST{$who}) , "\n");
+ }
+ ($FH{$who})->print( POSIX::ctime($time) );
+ $LAST{$who} = $time;
+ }
+ $len = (length($who) > length($me) ? length($who) : length($me))+1;
+ ($FH{$who})->printf("%-${len}s %s\n", ($cmode?$who:$me).':', $say);
+ }
+ elsif( $outmode == 1 ){
+ ($FH{$who})->print("$orig\n");
+ }
+ }
+ if( $outmode == 0 ){
+ foreach( keys %FH ){
+ ($FH{$_})->print( POSIX::ctime($LAST{$_}) );
+ }
+ }
+ foreach( keys %FH ){
+ ($FH{$_})->close();
+ }
+ close DIN;
+}
+
+sub parse
+{
+ my $dat = $_[0];
+ my($cmode, $who, $year, $month, $day, $hour, $min, $sec, $say);
+ if( $dat =~ /^To/ ){
+ $cmode = 0;
+ ($who, $say, $month, $day, $year, $hour, $min, $sec) =
+ $dat =~ m|^To (\w+):\s*(.*)\[(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+)\]|;
+ }
+ else{
+ $cmode = 1;
+ ($who, $say, $month, $day, $year, $hour, $min, $sec) =
+ $dat =~ m|¡¹(\w+?)\[37;45m\s*(.*)\[m \[0m\[(\w+)/(\w+)/(\w+) (\w+):(\w+):(\w+)\]|;
+
+ }
+# $time = timelocal($sec,$min,$hours,$mday,$mon,$year);
+
+ return undef if( $month == 0 );
+ return ($cmode, $who, timelocal($sec, $min, $hour, $day, $month - 1, $year), $say, $_[0]);
+}
+
+sub MakeMail
+{
+ my($arg) = @_;
+ my $sender;
+ `$TAR zcf $arg->{tartarget} $arg->{tarsource}`
+ if( $arg->{tarsource} );
+ $sender = new Mail::Sender{smtp => $SMTPSERVER,
+ from => "$hostname¤ô²y¾ã²zµ{¦¡ <in2\@ptt2.csie.ntu.edu.tw>"};
+ foreach( 0..3 ){
+ if( (!$arg->{tartarget} &&
+ $sender->MailMsg({to => $arg->{mailto},
+ subject => $arg->{subject},
+ msg => $arg->{body}
+ }) ) ||
+ ($arg->{tartarget} &&
+ $sender->MailFile({to => $arg->{mailto},
+ subject => $arg->{subject},
+ msg => $arg->{body},
+ file => $arg->{tartarget}})) ){
+ unlink $arg->{tartarget} if( $arg->{tartarget} );
+ return 1;
+ }
+ }
+ print "fault\n";
+ unlink $arg->{tartarget} if( $arg->{tartarget} );
+ return 0;
+}
diff --git a/util/weather.perl b/util/weather.perl
new file mode 100644
index 00000000..c9a35406
--- /dev/null
+++ b/util/weather.perl
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+# $Id: weather.perl,v 1.1 2002/03/07 15:13:46 in2 Exp $
+#
+# ¤£¯à¶]ªº¸Ü¡A¬Ý¬Ý bbspost ªº¸ô®|¬O§_¥¿½T¡C
+# ¦pªGµo¥Xªº post ¨S¦³®ð¶H³ø§i¦Ó¬O»¡ URL §ä¤£¨ì¡A«h½T©w¤@¤U¯à¤£¯à¬Ý¨ì
+# ¤¤¥¡®ð¶H§½ªº WWW ¤Î URL ¬O§_¥¿½T¡C
+# ²z½×¤W¾A¥Î©Ò¦³ Eagle BBS ¨t¦C¡C
+# -- Beagle Apr 13 1997
+open(BBSPOST, "| bin/webgrep>etc/weather.tmp");
+# ¤é´Á
+open(DATE, "date +'%a %b %d %T %Y' |");
+$date = <DATE>;
+chop $date;
+close DATE;
+
+# Header
+# ¤º®e
+open(WEATHER, "/usr/bin/lynx -dump http://www.cwb.gov.tw/V3.0/weather/text/Data/W03.txt |");
+while (<WEATHER>) {
+ print BBSPOST if ($_ ne "\n");
+}
+close WEATHER;
+
+# ñ¦WÀÉ
+print BBSPOST "\n--\n";
+print BBSPOST "§Ú¬Obeagle©Ò¦³¥i·Rªº¤p»æ°®...¸ó®ü¬°PttªA°È\n";
+print BBSPOST "--\n";
+print BBSPOST "¡¸ [Origin: ¡·ªGÂæ¤p¯¸¡·] [From: [ÂŲùÃP»æ«Î] ] ";
+
+close BBSPOST;
+
diff --git a/util/weather.sh b/util/weather.sh
new file mode 100644
index 00000000..315b0ec3
--- /dev/null
+++ b/util/weather.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# $Id: weather.sh,v 1.1 2002/03/07 15:13:46 in2 Exp $
+#
+bin/weather.perl
+bin/post Record ¥þ¬Ù¦U¦a¤Ñ®ð¹w³ø [®ð¶H¤p©j] etc/weather.tmp
diff --git a/util/webgrep.c b/util/webgrep.c
new file mode 100644
index 00000000..07089bb6
--- /dev/null
+++ b/util/webgrep.c
@@ -0,0 +1,46 @@
+/* $Id: webgrep.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+int main()
+{
+ char genbuf[256], *str, *buf;
+ while (fgets(genbuf, 255, stdin))
+ {
+ register int ansi;
+ if (!strncmp(genbuf, "References", 10))
+ break;
+ str = genbuf;
+ buf = genbuf;
+ if (!strncmp(genbuf, "lynx: Can't access", 18))
+ {
+ printf("®ð¶H³ø¾É¤p©j¥ð°²¤¤,½Ð¨ìRecordª©Â½¹L¥h¸ê®Æ.");
+ break;
+ }
+ for (ansi = 0; *str; str++)
+ {
+ if (*str == '[' && strchr("0123456789", *(str + 1)))
+ {
+ ansi = 1;
+ }
+ else if (ansi)
+ {
+ if (!strchr("0123456789]", *str))
+ {
+ ansi = 0;
+ if (str)
+ *buf++ = *str;
+ }
+ }
+ else
+ {
+ if (str)
+ *buf++ = *str;
+ }
+ }
+ *buf = 0;
+ printf(genbuf);
+ }
+ return 0;
+}
diff --git a/util/xchatd.c b/util/xchatd.c
new file mode 100644
index 00000000..46fba147
--- /dev/null
+++ b/util/xchatd.c
@@ -0,0 +1,3504 @@
+/* $Id: xchatd.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <sys/resource.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "util.h"
+#include "perm.h"
+#include "common.h"
+#include "xchatd.h"
+
+#define SERVER_USAGE
+#define WATCH_DOG
+#undef MONITOR /* ºÊ·þ chatroom ¬¡°Ê¥H¸Ñ¨MªÈ¯É */
+#undef DEBUG /* µ{¦¡°£¿ù¤§¥Î */
+
+#ifdef DEBUG
+#define MONITOR
+#endif
+
+static int gline;
+
+#ifdef WATCH_DOG
+#define MYDOG gline = __LINE__
+#else
+#define MYDOG /* NOOP */
+#endif
+
+
+
+#define CHAT_PIDFILE "log/chat.pid"
+#define CHAT_LOGFILE "log/chat.log"
+#define CHAT_INTERVAL (60 * 30)
+#define SOCK_QLEN 1
+
+
+/* name of the main room (always exists) */
+
+
+#define MAIN_NAME "main"
+#define MAIN_TOPIC "²i¯ù¥i°^¦è¤Ñ¦ò"
+
+
+#define ROOM_LOCKED 1
+#define ROOM_SECRET 2
+#define ROOM_OPENTOPIC 4
+#define ROOM_HANDUP 8
+#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 RHANDUP(room) (room->rflag & ROOM_HANDUP)
+
+#define RESTRICTED(usr) (usr->uflag == 0) /* guest */
+#define CHATSYSOP(usr) (usr->uflag & ( PERM_SYSOP | PERM_CHATROOM))
+/* Thor: SYSOP »P CHATROOM³£¬O chatÁ`ºÞ */
+#define PERM_ROOMOP PERM_CHAT /* Thor: ­É PERM_CHAT¬° PERM_ROOMOP */
+#define PERM_HANDUP PERM_BM /* ­É PERM_BM ¬°¦³¨S¦³Á|¤â¹L */
+#define PERM_SAY PERM_NOTOP /* ­É PERM_NOTOP ¬°¦³¨S¦³µoªíÅv */
+
+/* ¶i¤J®É»Ý²MªÅ */
+/* Thor: ROOMOP¬°©Ð¶¡ºÞ²z­û */
+#define ROOMOP(usr) (usr->uflag & ( PERM_ROOMOP | PERM_SYSOP | PERM_CHATROOM))
+#define CLOAK(usr) (usr->uflag & PERM_CLOAK)
+#define HANDUP(usr) (usr->uflag & PERM_HANDUP)
+#define SAY(usr) (usr->uflag & PERM_SAY)
+/* Thor: ²á¤Ñ«ÇÁô¨­³N */
+
+
+/* ----------------------------------------------------- */
+/* 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
+{
+ struct ChatUser *unext;
+ int sock; /* user socket */
+ int talksock; /* talk socket */
+ ChatRoom *room;
+ UserList *ignore;
+ int userno;
+ int uflag;
+ int clitype; /* Xshadow: client type. 1 for common client,
+ * 0 for bbs only client */
+ time_t uptime; /* Thor: unused */
+ char userid[IDLEN + 1]; /* real userid */
+ char chatid[9]; /* chat id */
+ char lasthost[30]; /* host address */
+ char ibuf[80]; /* buffer for non-blocking receiving */
+ int isize; /* current size of ibuf */
+};
+
+
+struct ChatRoom
+{
+ struct ChatRoom *next, *prev;
+ char name[IDLEN];
+ 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 */
+ UserList *invite;
+};
+
+
+struct UserList
+{
+ struct UserList *next;
+ int userno;
+ char userid[IDLEN + 1];
+};
+
+
+struct ChatCmd
+{
+ char *cmdstr;
+ void (*cmdfunc) ();
+ int exact;
+};
+
+
+static ChatRoom mainroom;
+static ChatUser *mainuser;
+static fd_set mainfds;
+static int maxfds; /* number of sockets to select on */
+static int totaluser; /* current number of connections */
+static struct timeval zerotv; /* timeval for selecting */
+static char chatbuf[256]; /* general purpose buffer */
+static int common_client_command;
+
+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)
+
+
+typedef struct userec_t ACCT;
+
+/* ----------------------------------------------------- */
+/* acct_load for check acct */
+/* ----------------------------------------------------- */
+
+int
+acct_load(acct, userid)
+ ACCT *acct;
+ char *userid;
+{
+ int id;
+ if((id=searchuser(userid))<0)
+ {
+ return -1;
+ }
+ else
+ {
+ return get_record(FN_PASSWD, acct, sizeof(ACCT), id);
+ }
+}
+
+
+/* ----------------------------------------------------- */
+/* str_lower for check acct */
+/* ----------------------------------------------------- */
+void
+str_lower(dst, src)
+ char *dst, *src;
+{
+ register int ch;
+
+ do
+ {
+ ch = *src++;
+ if (ch >= 'A' && ch <= 'Z')
+ ch |= 0x20;
+ *dst++ = ch;
+ } while (ch);
+}
+
+/*
+ * 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;
+
+ do
+ {
+ n = (dst == end) ? 0 : *src++;
+ *dst++ = n;
+ } while (n);
+}
+
+
+/* ----------------------------------------------------- */
+/* usr_fpath for check acct */
+/* ----------------------------------------------------- */
+char *str_home_file = "home/%c/%s/%s";
+
+void
+usr_fpath(buf, userid, fname)
+ char *buf, *userid, *fname;
+{
+ sprintf(buf, str_home_file, userid[0], userid, fname);
+}
+
+/* ----------------------------------------------------- */
+/* chkpasswd for check passwd */
+/* ----------------------------------------------------- */
+char *crypt();
+static char pwbuf[PASSLEN];
+
+int
+chkpasswd(passwd, test)
+ char *passwd, *test;
+{
+ char *pw;
+
+ str_ncpy(pwbuf, test, PASSLEN);
+ pw = crypt(pwbuf, passwd);
+ return (!strncmp(pw, passwd, PASSLEN));
+}
+
+/* ----------------------------------------------------- */
+/* operation log and debug information */
+/* ----------------------------------------------------- */
+
+
+static int flog; /* log file descriptor */
+
+
+static void
+logit(key, msg)
+ char *key;
+ char *msg;
+{
+ time_t now;
+ struct tm *p;
+ char buf[512];
+
+ time(&now);
+ p = localtime(&now);
+ sprintf(buf, "%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);
+ write(flog, buf, strlen(buf));
+}
+
+
+static void
+log_init()
+{
+ flog = open(CHAT_LOGFILE, O_WRONLY | O_CREAT | O_APPEND, 0644);
+ logit("START", "chat daemon");
+}
+
+
+static void
+log_close()
+{
+ close(flog);
+}
+
+
+#ifdef DEBUG
+static void
+debug_user()
+{
+ register ChatUser *user;
+ int i;
+ char buf[80];
+
+ i = 0;
+ for (user = mainuser; user; user = user->unext)
+ {
+ sprintf(buf, "%d) %s %s", ++i, user->userid, user->chatid);
+ logit("DEBUG_U", buf);
+ }
+}
+
+
+static void
+debug_room()
+{
+ register ChatRoom *room;
+ int i;
+ char buf[80];
+
+ i = 0;
+ room = &mainroom;
+
+ do
+ {
+ sprintf(buf, "%d) %s %d", ++i, room->name, room->occupants);
+ logit("DEBUG_R", buf);
+ } while (room = room->next);
+}
+#endif /* DEBUG */
+
+
+/* ----------------------------------------------------- */
+/* string routines */
+/* ----------------------------------------------------- */
+
+
+static int valid_chatid(register char *id) {
+ register int ch, len;
+
+ for(len = 0; (ch = *id); id++) {
+ /* Thor: check for endless */
+ MYDOG;
+
+ if(ch == '/' || ch == '*' || ch == ':')
+ return 0;
+ if(++len > 8)
+ return 0;
+ }
+ return len;
+}
+
+/* Case Independent strcmp : 1 ==> euqal */
+
+
+static int
+str_equal(s1, s2)
+ register unsigned char *s1, *s2; /* Thor: ¥[¤W unsigned,
+ * ÁקK¤¤¤åªº°ÝÃD */
+{
+ register int c1, c2;
+
+ for (;;)
+ { /* Thor: check for endless */
+ MYDOG;
+
+ c1 = *s1;
+ if (c1 >= 'A' && c1 <= 'Z')
+ c1 |= 32;
+
+ c2 = *s2;
+ if (c2 >= 'A' && c2 <= 'Z')
+ c2 |= 32;
+
+ if (c1 != c2)
+ return 0;
+
+ if (!c1)
+ return 1;
+
+ s1++;
+ s2++;
+ }
+}
+
+
+/* ----------------------------------------------------- */
+/* 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)
+ register unsigned char *s1, *s2; /* Thor: ¥[¤W unsigned,
+ * ÁקK¤¤¤åªº°ÝÃD */
+{
+ register int c1, c2;
+
+ for (;;)
+ { /* Thor: check for endless */
+ MYDOG;
+
+ c2 = *s2;
+ c1 = *s1;
+ if (!c1)
+ {
+ return c2;
+ }
+
+ if (c1 >= 'A' && c1 <= 'Z')
+ c1 |= 32;
+
+ if (c2 >= 'A' && c2 <= 'Z')
+ c2 |= 32;
+
+ if (c1 != c2)
+ return -1;
+
+ s1++;
+ s2++;
+ }
+}
+
+
+/* ----------------------------------------------------- */
+/* search user/room by its ID */
+/* ----------------------------------------------------- */
+
+
+static ChatUser *
+cuser_by_userid(userid)
+ char *userid;
+{
+ register ChatUser *cu;
+
+ for (cu = mainuser; cu; cu = cu->unext)
+ {
+ MYDOG;
+
+ if (str_equal(userid, cu->userid))
+ break;
+ }
+ return cu;
+}
+
+
+static ChatUser *
+cuser_by_chatid(chatid)
+ char *chatid;
+{
+ register ChatUser *cu;
+
+ for (cu = mainuser; cu; cu = cu->unext)
+ {
+ MYDOG;
+
+ if (str_equal(chatid, cu->chatid))
+ break;
+ }
+ return cu;
+}
+
+
+static ChatUser *
+fuzzy_cuser_by_chatid(chatid)
+ char *chatid;
+{
+ register ChatUser *cu, *xuser;
+ int mode;
+
+ xuser = NULL;
+
+ for (cu = mainuser; cu; cu = cu->unext)
+ {
+ MYDOG;
+
+ mode = str_match(chatid, cu->chatid);
+ if (mode == 0)
+ return cu;
+
+ if (mode > 0)
+ {
+ if (xuser == NULL)
+ xuser = cu;
+ else
+ return FUZZY_USER; /* ²Å¦XªÌ¤j©ó 2 ¤H */
+ }
+ }
+ return xuser;
+}
+
+
+static ChatRoom *croom_by_roomid(char *roomid) {
+ register ChatRoom *room;
+
+ room = &mainroom;
+ do {
+ MYDOG;
+
+ if(str_equal(roomid, room->name))
+ break;
+ } while((room = room->next));
+ return room;
+}
+
+
+/* ----------------------------------------------------- */
+/* UserList routines */
+/* ----------------------------------------------------- */
+
+
+static void
+list_free(list)
+ UserList *list;
+{
+ UserList *tmp;
+
+ while (list)
+ {
+ MYDOG;
+
+ tmp = list->next;
+
+ free(list);
+ MYDOG;
+ list = tmp;
+ }
+}
+
+
+static void
+list_add(list, user)
+ UserList **list;
+ ChatUser *user;
+{
+ UserList *node;
+
+ MYDOG;
+
+ if((node = (UserList *) malloc(sizeof(UserList)))) {
+ /* Thor: ¨¾¤îªÅ¶¡¤£°÷ */
+ strcpy(node->userid, user->userid);
+ node->userno = user->userno;
+ node->next = *list;
+ *list = node;
+ }
+ MYDOG;
+}
+
+
+static int
+list_delete(list, userid)
+ UserList **list;
+ char *userid;
+{
+ UserList *node;
+
+ while((node = *list)) {
+ MYDOG;
+
+ if (str_equal(node->userid, userid))
+ {
+ *list = node->next;
+ MYDOG;
+ free(node);
+ MYDOG;
+ return 1;
+ }
+ list = &node->next; /* Thor: list­n¸òµÛ«e¶i */
+ }
+
+ return 0;
+}
+
+
+static int
+list_belong(list, userno)
+ UserList *list;
+ int userno;
+{
+ while (list)
+ {
+ MYDOG;
+
+ 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, number)
+ int nfds;
+ fd_set *wset;
+ char *msg;
+ int number;
+{
+ int sr;
+
+ /* Thor: for future reservation bug */
+
+ zerotv.tv_sec = 0;
+ zerotv.tv_usec = 16384; /* Ptt: §ï¦¨16384 ÁקK¤£«ö®Éfor loop¦Ycpu time
+ 16384 ¬ù¨C¬í64¦¸ */
+
+ MYDOG;
+
+ sr = select(nfds + 1, NULL, wset, NULL, &zerotv);
+
+ MYDOG;
+
+ if (sr > 0)
+ {
+ register int len;
+
+ len = strlen(msg) + 1;
+ while (nfds >= 0)
+ {
+ MYDOG;
+
+ if (FD_ISSET(nfds, wset))
+ {
+ MYDOG;
+ send(nfds, msg, len, 0);/* Thor: ¦pªGbufferº¡¤F, ¤´·| block */
+ MYDOG;
+ if (--sr <= 0)
+ return;
+ }
+ nfds--;
+ }
+ }
+}
+
+
+static void
+send_to_room(room, msg, userno, number)
+ ChatRoom *room;
+ char *msg;
+ int userno;
+ int number;
+{
+ ChatUser *cu;
+ fd_set wset, *wptr;
+ int sock, max;
+ static char sendbuf[256];
+ int clitype; /* ¤À¬° bbs client ¤Î common client ¨â¦¸³B²z */
+
+ for (clitype = (number == MSG_MESSAGE || !number) ? 0 : 1; clitype < 2; clitype++)
+ {
+
+ FD_ZERO(wptr = &wset);
+ max = -1;
+
+ for (cu = mainuser; cu; cu = cu->unext)
+ {
+ MYDOG;
+
+ if (room == cu->room || room == ROOM_ALL)
+ {
+ if (cu->clitype == clitype && (!userno || !list_belong(cu->ignore, userno)))
+ {
+ sock = cu->sock;
+ FD_SET(sock, wptr);
+ if (max < sock)
+ max = sock;
+ }
+ }
+ }
+
+ if (max < 0)
+ continue;
+
+ if (clitype)
+ {
+ if (strlen(msg))
+ sprintf(sendbuf, "%3d %s", number, msg);
+ else
+ sprintf(sendbuf, "%3d", number);
+
+ do_send(max, wptr, sendbuf);
+ }
+ else
+ do_send(max, wptr, msg);
+ }
+}
+
+
+static void
+send_to_user(user, msg, userno, number)
+ ChatUser *user;
+ char *msg;
+ int userno;
+ int number;
+{
+ if (!user->clitype && number && number != MSG_MESSAGE)
+ return;
+
+ if (!userno || !list_belong(user->ignore, userno))
+ {
+ fd_set wset, *wptr;
+ int sock;
+ static char sendbuf[256];
+
+ sock = user->sock;
+ FD_ZERO(wptr = &wset);
+ FD_SET(sock, wptr);
+
+ if (user->clitype)
+ {
+ if (strlen(msg))
+ sprintf(sendbuf, "%3d %s", number, msg);
+ else
+ sprintf(sendbuf, "%3d", number);
+ do_send(sock, wptr, sendbuf);
+ }
+ else
+ do_send(sock, wptr, msg);
+ }
+}
+
+#if 0
+static void
+send_to_sock(sock, msg) /* Thor: unused */
+ int sock;
+ char *msg;
+{
+ fd_set wset, *wptr;
+
+ FD_ZERO(wptr = &wset);
+ FD_SET(sock, wptr);
+ do_send(sock, wptr, msg);
+}
+#endif
+
+/* ----------------------------------------------------- */
+
+static void
+room_changed(room)
+ ChatRoom *room;
+{
+ if (!room)
+ return;
+
+ sprintf(chatbuf, "= %s %d %d %s", room->name, room->occupants, room->rflag, room->topic);
+ send_to_room(ROOM_ALL, chatbuf, 0, MSG_ROOMNOTIFY);
+}
+
+static void
+user_changed(cu)
+ ChatUser *cu;
+{
+ if (!cu)
+ return;
+
+ sprintf(chatbuf, "= %s %s %s %s", cu->userid, cu->chatid, cu->room->name, cu->lasthost);
+ if (ROOMOP(cu))
+ strcat(chatbuf, " Op");
+ send_to_room(cu->room, chatbuf, 0, MSG_USERNOTIFY);
+}
+
+static void
+exit_room(user, mode, msg)
+ ChatUser *user;
+ int mode;
+ char *msg;
+{
+ ChatRoom *room;
+
+ if((room = user->room)) {
+ user->room = NULL;
+ user->uflag &= ~PERM_ROOMOP;
+
+ if (--room->occupants > 0)
+ {
+ char *chatid;
+
+ chatid = user->chatid;
+ switch (mode)
+ {
+ case EXIT_LOGOUT:
+
+ sprintf(chatbuf, "¡» %s Â÷¶}¤F ...", chatid);
+ if (msg && *msg)
+ {
+ strcat(chatbuf, ": ");
+ msg[79] = 0; /* Thor:¨¾¤î¤Óªø */
+ strncat(chatbuf, msg, 80);
+ }
+ break;
+
+ case EXIT_LOSTCONN:
+
+ sprintf(chatbuf, "¡» %s ¦¨¤FÂ_½uªº­·ºåÅo", chatid);
+ break;
+
+ case EXIT_KICK:
+
+ sprintf(chatbuf, "¡» «¢«¢¡I%s ³Q½ð¥X¥h¤F", chatid);
+ break;
+ }
+ if (!CLOAK(user)) /* Thor: ²á¤Ñ«ÇÁô¨­³N */
+ send_to_room(room, chatbuf, 0, MSG_MESSAGE);
+
+ sprintf(chatbuf, "- %s", user->userid);
+ send_to_room(room, chatbuf, 0, MSG_USERNOTIFY);
+ room_changed(room);
+
+ return;
+ }
+
+ else if (room != &mainroom)
+ { /* Thor: ¤H¼Æ¬°0®É,¤£¬Omainroom¤~free */
+ register ChatRoom *next;
+
+#ifdef DEBUG
+ debug_room();
+#endif
+
+ sprintf(chatbuf, "- %s", room->name);
+ send_to_room(ROOM_ALL, chatbuf, 0, MSG_ROOMNOTIFY);
+
+ room->prev->next = room->next;
+ if((next = room->next))
+ next->prev = room->prev;
+ list_free(room->invite);
+
+ MYDOG;
+ free(room);
+ MYDOG;
+
+#ifdef DEBUG
+ debug_room();
+#endif
+ }
+ }
+}
+
+
+/* ----------------------------------------------------- */
+/* chat commands */
+/* ----------------------------------------------------- */
+
+/* ----------------------------------------------------- */
+/* (.ACCT) ¨Ï¥ÎªÌ±b¸¹ (account) subroutines */
+/* ----------------------------------------------------- */
+
+static char datemsg[32];
+
+char *
+Ctime(clock)
+ time_t *clock;
+{
+ struct tm *t = localtime(clock);
+ static char week[] = "¤é¤@¤G¤T¥|¤­¤»";
+
+ sprintf(datemsg, "%d¦~%2d¤ë%2d¤é%3d:%02d:%02d ¬P´Á%.2s",
+ t->tm_year - 11, t->tm_mon + 1, t->tm_mday,
+ t->tm_hour, t->tm_min, t->tm_sec, &week[t->tm_wday << 1]);
+ return (datemsg);
+}
+
+static void
+chat_query(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ char str[256];
+ int i;
+ ACCT xuser;
+ FILE *fp;
+
+ if (acct_load(&xuser, msg) >= 0)
+ {
+ sprintf(chatbuf, "%s(%s) ¦@¤W¯¸ %d ¦¸¡A¤å³¹ %d ½g",
+ xuser.userid, xuser.username, xuser.numlogins, xuser.numposts);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+
+ sprintf(chatbuf, "³Ìªñ(%s)±q(%s)¤W¯¸", Ctime(&xuser.lastlogin),
+ (xuser.lasthost[0] ? xuser.lasthost : "¥~¤ÓªÅ"));
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+
+ usr_fpath(chatbuf, xuser.userid, "plans");
+ fp = fopen(chatbuf, "rt");
+ i = 0;
+ while (fp && fgets(str, 256, fp))
+ {
+ if (!strlen(str))
+ continue;
+
+ str[strlen(str) - 1] = 0;
+ send_to_user(cu, str, 0, MSG_MESSAGE);
+ if (++i >= MAX_QUERYLINES)
+ break;
+ }
+ fclose(fp);
+ }
+ else
+ {
+ sprintf(chatbuf, msg_no_such_id, msg);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ }
+}
+
+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;
+{
+ time_t thetime;
+
+ time(&thetime);
+ sprintf(chatbuf, "¡» ¼Ð·Ç®É¶¡: %s", Ctime(&thetime));
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+}
+
+
+static void
+chat_topic(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ ChatRoom *room;
+ char *topic;
+
+ if (!ROOMOP(cu) && !OPENTOPIC(cu->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;
+ }
+
+ room = cu->room;
+ topic = room->topic; /* Thor: room ¦³¥i¯à NULL¶Ü?? */
+ strncpy(topic, msg, 47);
+ topic[47] = '\0';
+
+ if (cu->clitype)
+ send_to_room(room, topic, 0, MSG_TOPIC);
+ else
+ {
+ sprintf(chatbuf, "/t%s", topic);
+ send_to_room(room, chatbuf, 0, 0);
+ }
+
+ room_changed(room);
+
+ sprintf(chatbuf, "¡» %s ±N¸ÜÃD§ï¬° %s", cu->chatid, topic);
+ if (!CLOAK(cu)) /* Thor: ²á¤Ñ«ÇÁô¨­³N */
+ send_to_room(room, chatbuf, 0, MSG_MESSAGE);
+}
+
+
+static void
+chat_version(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ sprintf(chatbuf, "%d %d", XCHAT_VERSION_MAJOR, XCHAT_VERSION_MINOR);
+ send_to_user(cu, chatbuf, 0, MSG_VERSION);
+}
+
+static void
+chat_nick(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ char *chatid, *str;
+ 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;
+ }
+
+ str = cu->chatid;
+
+ sprintf(chatbuf, "¡° %s ±N²á¤Ñ¥N¸¹§ï¬° %s", str, chatid);
+ if (!CLOAK(cu)) /* Thor: ²á¤Ñ«ÇÁô¨­³N */
+ send_to_room(cu->room, chatbuf, cu->userno, MSG_MESSAGE);
+
+ strcpy(str, chatid);
+
+ user_changed(cu);
+
+ if (cu->clitype)
+ send_to_user(cu, chatid, 0, MSG_NICK);
+ else
+ {
+ sprintf(chatbuf, "/n%s", chatid);
+ send_to_user(cu, chatbuf, 0, 0);
+ }
+}
+
+static void
+chat_list_rooms(cuser, msg)
+ ChatUser *cuser;
+ char *msg;
+{
+ ChatRoom *cr, *room;
+
+ if (RESTRICTED(cuser))
+ {
+ send_to_user(cuser, "¡° ±z¨S¦³Åv­­¦C¥X²{¦³ªº²á¤Ñ«Ç", 0, MSG_MESSAGE);
+ return;
+ }
+
+ if (common_client_command)
+ send_to_user(cuser, "", 0, MSG_ROOMLISTSTART);
+ else
+ send_to_user(cuser, " ½Í¤Ñ«Ç¦WºÙ ¢x¤H¼Æ¢x¸ÜÃD ", 0, MSG_MESSAGE);
+
+ room = cuser->room;
+ cr = &mainroom;
+ do
+ {
+ MYDOG;
+
+
+ if (!SECRET(cr) || CHATSYSOP(cuser) || (cr == room && ROOMOP(cuser)))
+ {
+ if (common_client_command)
+ {
+ sprintf(chatbuf, "%s %d %d %s", cr->name, cr->occupants, cr->rflag, cr->topic);
+ send_to_user(cuser, chatbuf, 0, MSG_ROOMLIST);
+ }
+ else
+ {
+ sprintf(chatbuf, " %-12s¢x%4d¢x%s", cr->name, cr->occupants, cr->topic);
+ if (LOCKED(cr))
+ strcat(chatbuf, " [Âê¦í]");
+ if (SECRET(cr))
+ strcat(chatbuf, " [¯µ±K]");
+ if (OPENTOPIC(cr))
+ strcat(chatbuf, " [¸ÜÃD]");
+ send_to_user(cuser, chatbuf, 0, MSG_MESSAGE);
+ }
+
+ }
+ } while((cr = cr->next));
+
+ if (common_client_command)
+ 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 = 0;
+ start = atoi(nextword(&msg));
+ stop = atoi(nextword(&msg));
+
+ myroom = cu->room;
+
+#ifdef DEBUG
+ logit(cu->chatid, "do user list");
+#endif
+
+ if (common_client_command)
+ send_to_user(cu, "", 0, MSG_USERLISTSTART);
+ else
+ send_to_user(cu, " ²á¤Ñ¥N¸¹¢x¨Ï¥ÎªÌ¥N¸¹ ¢x²á¤Ñ«Ç ", 0, MSG_MESSAGE);
+
+ for (user = mainuser; user; user = user->unext)
+ {
+ MYDOG;
+
+
+ room = user->room;
+ if ((theroom != ROOM_ALL) && (theroom != room))
+ continue;
+
+ if (myroom != room)
+ {
+ if (RESTRICTED(cu) ||
+ (room && SECRET(room) && !CHATSYSOP(cu)))
+ continue;
+ }
+
+ if (CLOAK(user)) /* Thor: Áô¨­³N */
+ continue;
+
+
+ curr++;
+ if (start && curr < start)
+ continue;
+ else if (stop && (curr > stop))
+ break;
+
+ if (common_client_command)
+ {
+ if (!room)
+ continue; /* Xshadow: ÁÙ¨S¶i¤J¥ô¦ó©Ð¶¡ªº´N¤£¦C¥X */
+
+ sprintf(chatbuf, "%s %s %s %s", user->chatid, user->userid, room->name, user->lasthost);
+ if (ROOMOP(user))
+ strcat(chatbuf, " Op");
+ }
+ else
+ {
+ sprintf(chatbuf, " %-8s¢x%-12s¢x%s", user->chatid, user->userid, room ? room->name : "[¦bªù¤f±r«Þ]");
+ if (ROOMOP(user))
+ strcat(chatbuf, " [Op]");
+ }
+
+#ifdef DEBUG
+ logit("list_U", chatbuf);
+#endif
+
+ send_to_user(cu, chatbuf, 0, common_client_command ? MSG_USERLIST : MSG_MESSAGE);
+ }
+ if (common_client_command)
+ send_to_user(cu, "", 0, MSG_USERLISTEND);
+}
+
+static void
+chat_list_by_room(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ ChatRoom *whichroom;
+ char *roomstr;
+
+ roomstr = nextword(&msg);
+ if (*roomstr == '\0')
+ whichroom = cu->room;
+ else
+ {
+ if ((whichroom = croom_by_roomid(roomstr)) == NULL)
+ {
+ sprintf(chatbuf, "¡° ¨S¦³ [%s] ³o­Ó²á¤Ñ«Ç", roomstr);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ return;
+ }
+
+ if (whichroom != cu->room && SECRET(whichroom) && !CHATSYSOP(cu))
+ { /* Thor: ­n¤£­n´ú¦P¤@roomÁöSECRET¦ý¥i¥H¦C?
+ * Xshadow: §Ú§ï¦¨¦P¤@ room ´N¥i¥H¦C */
+ 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, "§å½ð½ð¯ùÃÀÀ] 4 21", 0, MSG_CHATROOM);
+}
+
+static void
+chat_map_chatids(cu, whichroom)
+ ChatUser *cu; /* Thor: ÁÙ¨S¦³§@¤£¦P¶¡ªº */
+ ChatRoom *whichroom;
+{
+ int c;
+ ChatRoom *myroom, *room;
+ ChatUser *user;
+
+ /* myroom = cu->room; */
+ myroom = whichroom;
+ send_to_user(cu,
+ " ²á¤Ñ¥N¸¹ ¨Ï¥ÎªÌ¥N¸¹ ¢x ²á¤Ñ¥N¸¹ ¨Ï¥ÎªÌ¥N¸¹ ¢x ²á¤Ñ¥N¸¹ ¨Ï¥ÎªÌ¥N¸¹ ", 0, MSG_MESSAGE);
+
+ c = 0;
+
+ for (user = mainuser; user; user = user->unext)
+ {
+ MYDOG;
+
+ room = user->room;
+ MYDOG;
+ if (whichroom != ROOM_ALL && whichroom != room)
+ continue;
+ MYDOG;
+ if (myroom != room)
+ {
+ if (RESTRICTED(cu) || /* Thor: ­n¥ýcheck room ¬O¤£¬OªÅªº */
+ (room && SECRET(room) && !CHATSYSOP(cu)))
+ continue;
+ }
+ MYDOG;
+ if (CLOAK(user)) /* Thor:Áô¨­³N */
+ continue;
+ sprintf(chatbuf + (c * 24), " %-8s%c%-12s%s",
+ user->chatid, ROOMOP(user) ? '*' : ' ',
+ user->userid, (c < 2 ? "¢x" : " "));
+ MYDOG;
+ if (++c == 3)
+ {
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ c = 0;
+ }
+ MYDOG;
+ }
+ if (c > 0)
+ send_to_user(cu, chatbuf, 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;
+ int flag;
+ char *fstr = NULL;
+
+ 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;
+ case 'h':
+ case 'H':
+ flag = ROOM_OPENTOPIC;
+ fstr = "Á|¤âµo¨¥";
+ break;
+
+ default:
+ sprintf(chatbuf, "¡° ª¬ºA¿ù»~¡G[%c]", *modestr);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ }
+
+ /* Thor: check room ¬O¤£¬OªÅªº, À³¸Ó¤£¬OªÅªº */
+ if (flag && (room->rflag & flag) != sign * flag)
+ {
+ room->rflag ^= flag;
+ sprintf(chatbuf, "¡° ¥»²á¤Ñ«Ç³Q %s %s [%s] ª¬ºA",
+ chatid, sign ? "³]©w¬°" : "¨ú®ø", fstr);
+ if (!CLOAK(cu)) /* Thor: ²á¤Ñ«ÇÁô¨­³N */
+ send_to_room(room, chatbuf, 0, MSG_MESSAGE);
+ }
+ modestr++;
+ }
+ 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®É¶¡",
+ /* "[/d]ate", "¥Ø«e®É¶¡", *//* Thor: «ü¥O¤Ó¦h */
+
+#if 0
+ "[/f]ire <user> <msg>", "µo°e¼ö°T", /* Thor.0727: ©M flag ½Äkey */
+#endif
+
+ "[/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¸ßºô¤Í",
+ "[/r]oom", "¦C¥X¤@¯ë½Í¤Ñ«Ç",
+ "[/t]ape", "¶}Ãö¿ý­µ¾÷",
+ "[/u]nignore <user>", "¨ú®ø©¿²¤",
+
+#if 0
+ "[/u]sers", "¦C¥X¯¸¤W¨Ï¥ÎªÌ",
+#endif
+
+ "[/w]ho", "¦C¥X¥»½Í¤Ñ«Ç¨Ï¥ÎªÌ",
+ "[/w]hoin <room>", "¦C¥X½Í¤Ñ«Ç<room> ªº¨Ï¥ÎªÌ",
+ NULL
+};
+
+
+static char *room_msg[] =
+{
+ "[/f]lag [+-][lsth]", "³]©wÂê©w¡B¯µ±K¡B¶}©ñ¸ÜÃD¡BÁ|¤âµo¨¥",
+ "[/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;
+
+ if (str_equal(nextword(&msg), "op"))
+ {
+ send_to_user(cu, "½Í¤Ñ«ÇºÞ²z­û±M¥Î«ü¥O", 0, MSG_MESSAGE);
+ table = room_msg;
+ }
+ else
+ {
+ table = chat_msg;
+ }
+
+ while((str = *table++)) {
+ sprintf(chatbuf, " %-20s- %s", str, *table++);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ }
+}
+
+
+static void
+chat_private(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ char *recipient;
+ ChatUser *xuser;
+ int userno;
+
+ userno = 0;
+ recipient = nextword(&msg);
+ xuser = (ChatUser *) fuzzy_cuser_by_chatid(recipient);
+ if (xuser == NULL)
+ { /* Thor.0724: ¥Î userid¤]¥i¶Ç®¨®¨¸Ü */
+ xuser = cuser_by_userid(recipient);
+ }
+ if (xuser == NULL)
+ {
+ sprintf(chatbuf, msg_no_such_id, recipient);
+ }
+ else if (xuser == FUZZY_USER)
+ { /* ambiguous */
+ strcpy(chatbuf, "¡° ½Ð«ü©ú²á¤Ñ¥N¸¹");
+ }
+ else if (*msg)
+ {
+ userno = cu->userno;
+ sprintf(chatbuf, "*%s* ", cu->chatid);
+ msg[79] = 0; /* Thor:¨¾¤î¤Óªø */
+ strncat(chatbuf, msg, 80);
+ send_to_user(xuser, chatbuf, userno, MSG_MESSAGE);
+
+ if (xuser->clitype)
+ { /* Xshadow: ¦pªG¹ï¤è¬O¥Î client ¤W¨Óªº */
+ sprintf(chatbuf, "%s %s ", cu->userid, cu->chatid);
+ msg[79] = 0;
+ strncat(chatbuf, msg, 80);
+ send_to_user(xuser, chatbuf, userno, MSG_PRIVMSG);
+ }
+ if (cu->clitype)
+ {
+ sprintf(chatbuf, "%s %s ", xuser->userid, xuser->chatid);
+ msg[79] = 0;
+ strncat(chatbuf, msg, 80);
+ send_to_user(cu, chatbuf, 0, MSG_MYPRIVMSG);
+ }
+
+ sprintf(chatbuf, "%s> ", xuser->chatid);
+ strncat(chatbuf, msg, 80);
+ }
+ else
+ {
+ sprintf(chatbuf, "¡° ±z·Q¹ï %s »¡¤°»ò¸Ü©O¡H", xuser->chatid);
+ }
+ send_to_user(cu, chatbuf, userno, MSG_MESSAGE); /* Thor: userno ­n§ï¦¨ 0
+ * ¶Ü? */
+}
+
+
+static void
+chat_cloak(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ if (CHATSYSOP(cu))
+ {
+ cu->uflag ^= PERM_CLOAK;
+ sprintf(chatbuf, "¡» %s", CLOAK(cu) ? MSG_CLOAKED : MSG_UNCLOAK);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ }
+}
+
+
+
+/* ----------------------------------------------------- */
+
+
+static void
+arrive_room(cuser, room)
+ ChatUser *cuser;
+ ChatRoom *room;
+{
+ char *rname;
+
+ /* Xshadow: ¤£¥²°eµ¹¦Û¤v, ¤Ï¥¿´«©Ð¶¡´N·|­«·s build user list */
+ sprintf(chatbuf, "+ %s %s %s %s", cuser->userid, cuser->chatid, room->name, cuser->lasthost);
+ if (ROOMOP(cuser))
+ strcat(chatbuf, " Op");
+ send_to_room(room, chatbuf, 0, MSG_USERNOTIFY);
+
+ cuser->room = room;
+ room->occupants++;
+ rname = room->name;
+
+ room_changed(room);
+
+ if (cuser->clitype)
+ {
+ send_to_user(cuser, rname, 0, MSG_ROOM);
+ send_to_user(cuser, room->topic, 0, MSG_TOPIC);
+ }
+ else
+ {
+ sprintf(chatbuf, "/r%s", rname);
+ send_to_user(cuser, chatbuf, 0, 0);
+ sprintf(chatbuf, "/t%s", room->topic);
+ send_to_user(cuser, chatbuf, 0, 0);
+ }
+
+ sprintf(chatbuf, "¡° %s ¶i¤J [%s] ¥]´[",
+ cuser->chatid, rname);
+ if (!CLOAK(cuser)) /* Thor: ²á¤Ñ«ÇÁô¨­³N */
+ send_to_room(room, chatbuf, cuser->userno, MSG_MESSAGE);
+}
+
+
+static int
+enter_room(cuser, rname, msg)
+ ChatUser *cuser;
+ char *rname;
+ char *msg;
+{
+ ChatRoom *room;
+ int create;
+
+ create = 0;
+ room = croom_by_roomid(rname);
+ if (room == NULL)
+ {
+ /* new room */
+
+#ifdef MONITOR
+ logit(cuser->userid, "create new room");
+#endif
+
+ MYDOG;
+
+ room = (ChatRoom *) malloc(sizeof(ChatRoom));
+ MYDOG;
+ if (room == NULL)
+ {
+ send_to_user(cuser, "¡° µLªk¦A·sÅP¥]´[¤F", 0, MSG_MESSAGE);
+ return 0;
+ }
+
+ memset(room, 0, sizeof(ChatRoom));
+ memcpy(room->name, rname, IDLEN - 1);
+ strcpy(room->topic, "³o¬O¤@­Ó·s¤Ñ¦a");
+
+ sprintf(chatbuf, "+ %s 1 0 %s", room->name, room->topic);
+ send_to_room(ROOM_ALL, chatbuf, 0, MSG_ROOMNOTIFY);
+
+ if (mainroom.next != NULL)
+ mainroom.next->prev = room;
+ room->next = mainroom.next;
+ mainroom.next = room;
+ room->prev = &mainroom;
+
+ create = 1;
+ }
+ else
+ {
+ if (cuser->room == room)
+ {
+ sprintf(chatbuf, "¡° ±z¥»¨Ó´N¦b [%s] ²á¤Ñ«ÇÅo :)", rname);
+ send_to_user(cuser, chatbuf, 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
+logout_user(cuser)
+ ChatUser *cuser;
+{
+ int sock;
+ ChatUser *xuser, *prev;
+
+#ifdef DEBUG
+ logit("before", "logout");
+ debug_user();
+#endif
+
+ sock = cuser->sock;
+ shutdown(sock, 2);
+ close(sock);
+
+ MYDOG;
+
+ FD_CLR(sock, &mainfds);
+
+#if 0 /* Thor: ¤]³\¤£®t³o¤@­Ó */
+ if (sock >= maxfds)
+ maxfds = sock - 1;
+#endif
+
+ list_free(cuser->ignore);
+
+#ifdef DEBUG
+ debug_user();
+#endif
+
+ xuser = mainuser;
+ if (xuser == cuser)
+ {
+ mainuser = cuser->unext;
+ }
+ else
+ {
+ do
+ {
+ prev = xuser;
+ xuser = xuser->unext;
+ if (xuser == cuser)
+ {
+ prev->unext = cuser->unext;
+ break;
+ }
+ } while (xuser);
+ }
+
+ MYDOG;
+
+#ifdef DEBUG
+ sprintf(chatbuf, "%p", cuser);
+ logit("free cuser", chatbuf);
+#endif
+
+ free(cuser);
+
+#ifdef DEBUG
+ logit("after", "logout");
+ debug_user();
+#endif
+
+#if 0
+ next = cuser->next;
+ prev = cuser->prev;
+ prev->next = next;
+ if (next)
+ next->prev = prev;
+
+ if (cuser)
+ free(cuser);
+ MYDOG;
+
+#endif
+
+ totaluser--;
+}
+
+
+static void
+print_user_counts(cuser)
+ ChatUser *cuser;
+{
+ ChatRoom *room;
+ int num, userc, suserc, roomc, number;
+
+ userc = suserc = roomc = 0;
+
+ room = &mainroom;
+ do
+ {
+ MYDOG;
+
+ 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(chatbuf,
+ "¡ó Åwªï¥úÁ{¡i§å½ð½ð¯ùÃÀÀ]¡j¡A¥Ø«e¶}¤F %d ¶¡¥]´[", roomc);
+ send_to_user(cuser, chatbuf, 0, number);
+
+ sprintf(chatbuf, "¡ó ¦@¦³ %d ¤H¨ÓÂ\\Àsªù°}", userc);
+ if (suserc)
+ sprintf(chatbuf + strlen(chatbuf), " [%d ¤H¦b¯µ±K²á¤Ñ«Ç]", suserc);
+ send_to_user(cuser, chatbuf, 0, number);
+}
+
+
+static int
+login_user(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ int utent;
+
+ char *level;
+ char *userid;
+ char *chatid;
+ struct sockaddr_in from;
+ int fromlen;
+ struct hostent *hp;
+
+
+ ACCT acct;
+ char buf[20];
+
+ /*
+ * Thor.0819: SECURED_CHATROOM : /! userid chatid passwd , userno
+ * el ¦bcheck§¹passwd«á¨ú±o
+ */
+ /* Xshadow.0915: common client support : /-! userid chatid password */
+
+ /* ¶Ç°Ñ¼Æ¡Guserlevel, userid, chatid */
+
+ /* client/server ª©¥»¨Ì¾Ú userid §ì .PASSWDS §PÂ_ userlevel */
+
+ userid = nextword(&msg);
+ chatid = nextword(&msg);
+
+
+#ifdef DEBUG
+ logit("ENTER", userid);
+#endif
+ /* Thor.0730: parse space before passwd */
+ level = msg;
+
+ /* Thor.0813: ¸õ¹L¤@ªÅ®æ§Y¥i, ¦]¬°¤Ï¥¿¦pªGchatid¦³ªÅ®æ, ±K½X¤]¤£¹ï */
+ /* ´Nºâ±K½X¹ï, ¤]¤£·|«ç»ò¼Ë:p */
+ /* ¥i¬O¦pªG±K½X²Ä¤@­Ó¦r¬OªÅ®æ, ¨º¸õ¤Ó¦hªÅ®æ·|¶i¤£¨Ó... */
+ if (*level == ' ')
+ level++;
+
+ /* Thor.0729: load acct */
+ if (!*userid || (acct_load(&acct, userid) < 0))
+ {
+
+#ifdef DEBUG
+ logit("noexist", chatid);
+#endif
+
+ if (cu->clitype)
+ send_to_user(cu, "¿ù»~ªº¨Ï¥ÎªÌ¥N¸¹", 0, ERR_LOGIN_NOSUCHUSER);
+ else
+ send_to_user(cu, CHAT_LOGIN_INVALID, 0, 0);
+
+ return -1;
+ }
+ else if(strncmp(level, acct.passwd, PASSLEN) &&
+ !chkpasswd(acct.passwd, level))
+ {
+
+#ifdef DEBUG
+ logit("fake", chatid);
+#endif
+
+ if (cu->clitype)
+ send_to_user(cu, "±K½X¿ù»~", 0, ERR_LOGIN_PASSERROR);
+ else
+ send_to_user(cu, CHAT_LOGIN_INVALID, 0, 0);
+ return -1;
+ }
+ else
+ {
+ /* Thor.0729: if ok, read level. */
+ sprintf(buf, "%d", acct.userlevel);
+ level = buf;
+ /* Thor.0819: read userno for client/server bbs */
+ utent = searchuser(acct.userid);
+ }
+
+ /* Thor.0819: for client/server bbs */
+/*
+ for (xuser = mainuser; xuser; xuser = xuser->unext)
+ {
+ MYDOG;
+
+ if (xuser->userno == utent)
+ {
+
+ #ifdef DEBUG
+ logit("enter", "bogus");
+ #endif
+ if (cu->clitype)
+ send_to_user(cu, "½Ð¤Å¬£»º¤À¨­¶i¤J²á¤Ñ«Ç !!", 0, ERR_LOGIN_USERONLINE);
+ else
+ send_to_user(cu, CHAT_LOGIN_BOGUS, 0, 0);
+ return -1;
+ }
+ }
+*/
+ if (!valid_chatid(chatid))
+ {
+
+#ifdef DEBUG
+ logit("enter", chatid);
+#endif
+
+ if (cu->clitype)
+ send_to_user(cu, "¤£¦Xªkªº²á¤Ñ«Ç¥N¸¹ !!", 0, ERR_LOGIN_NICKERROR);
+ else
+ send_to_user(cu, CHAT_LOGIN_INVALID, 0, 0);
+ return 0;
+ }
+
+#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, 0);
+ return 0;
+ }
+
+ cu->userno = utent;
+ cu->uflag = atoi(level) & ~(PERM_ROOMOP | PERM_CLOAK | PERM_HANDUP | PERM_SAY);
+ /* Thor: ¶i¨Ó¥ý²MªÅROOMOP(¦PPERM_CHAT), CLOAK */
+ strcpy(cu->userid, userid);
+ memcpy(cu->chatid, chatid, 8);
+ cu->chatid[8] = '\0';
+
+ /* Xshadow: ¨ú±o client ªº¨Ó·½ */
+ fromlen = sizeof(from);
+ if (!getpeername(cu->sock, (struct sockaddr *) & from, &fromlen))
+ {
+ if ((hp = gethostbyaddr((char *) &from.sin_addr, sizeof(struct in_addr), from.sin_family)))
+ {
+ strcpy(cu->lasthost, hp->h_name);
+ }
+ else
+ strcpy(cu->lasthost, (char *) inet_ntoa(from.sin_addr));
+
+ }
+ else
+ {
+ strcpy(cu->lasthost, "[¥~¤ÓªÅ]");
+ }
+
+ if (cu->clitype)
+ send_to_user(cu, "¶¶§Q", 0, MSG_LOGINOK);
+ else
+ send_to_user(cu, CHAT_LOGIN_OK, 0, 0);
+
+ 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 && (!RHANDUP(cu->room) || SAY(cu) || ROOMOP(cu)))
+ {
+ sprintf(chatbuf, "%s %s", cu->chatid, msg);
+ send_to_room(cu->room, chatbuf, cu->userno, MSG_MESSAGE);
+ }
+}
+
+
+static void
+chat_ignore(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+
+ if (RESTRICTED(cu))
+ {
+ strcpy(chatbuf, "¡° ±z¨S¦³ ignore §O¤HªºÅv§Q");
+ }
+ else
+ {
+ char *ignoree;
+
+ ignoree = nextword(&msg);
+ if (*ignoree)
+ {
+ ChatUser *xuser;
+
+ xuser = cuser_by_userid(ignoree);
+
+ if (xuser == NULL)
+ {
+
+ sprintf(chatbuf, msg_no_such_id, ignoree);
+
+#if 0
+ sprintf(chatbuf, "¡» ½Í¤Ñ«Ç²{¦b¨S¦³ [%s] ³o¸¹¤Hª«", ignoree);
+#endif
+ }
+ else if (xuser == cu || CHATSYSOP(xuser) ||
+ (ROOMOP(xuser) && (xuser->room == cu->room)))
+ {
+ sprintf(chatbuf, "¡» ¤£¥i¥H ignore [%s]", ignoree);
+ }
+ else
+ {
+
+ if (list_belong(cu->ignore, xuser->userno))
+ {
+ sprintf(chatbuf, "¡° %s ¤w¸g³Q­áµ²¤F", xuser->chatid);
+ }
+ else
+ {
+ list_add(&(cu->ignore), xuser);
+ sprintf(chatbuf, "¡» ±N [%s] ¥´¤J§N®c¤F :p", xuser->chatid);
+ }
+ }
+ }
+ else
+ {
+ UserList *list;
+
+ if((list = cu->ignore))
+ {
+ int len;
+ char buf[16];
+
+ send_to_user(cu, "¡» ³o¨Ç¤H³Q¥´¤J§N®c¤F¡G", 0, MSG_MESSAGE);
+ len = 0;
+ do
+ {
+ sprintf(buf, "%-13s", list->userid);
+ strcpy(chatbuf + len, buf);
+ len += 13;
+ if (len >= 78)
+ {
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ len = 0;
+ }
+ } while((list = list->next));
+
+ if (len == 0)
+ return;
+ }
+ else
+ {
+ strcpy(chatbuf, "¡» ±z¥Ø«e¨Ã¨S¦³ ignore ¥ô¦ó¤H");
+ }
+ }
+ }
+
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+}
+
+
+static void
+chat_unignore(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ char *ignoree;
+
+ ignoree = nextword(&msg);
+
+ if (*ignoree)
+ {
+ sprintf(chatbuf, (list_delete(&(cu->ignore), ignoree)) ?
+ "¡» [%s] ¤£¦A³Q§A§N¸¨¤F" :
+ "¡» ±z¨Ã¥¼ ignore [%s] ³o¸¹¤Hª«", ignoree);
+ }
+ else
+ {
+ strcpy(chatbuf, "¡» ½Ð«ü©ú user ID");
+ }
+ send_to_user(cu, chatbuf, 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²á¤Ñ«Çªº¦W¦r", 0, MSG_MESSAGE);
+ }
+}
+
+
+static void
+chat_kick(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ char *twit;
+ 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)
+ {
+ sprintf(chatbuf, msg_no_such_id, twit);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ return;
+ }
+
+ room = cu->room;
+ if (room != xuser->room || CLOAK(xuser))
+ { /* Thor: ²á¤Ñ«ÇÁô¨­³N */
+ sprintf(chatbuf, msg_not_here, twit);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ return;
+ }
+
+ if (CHATSYSOP(xuser))
+ { /* Thor: ½ð¤£¨« CHATSYSOP */
+ sprintf(chatbuf, "¡» ¤£¥i¥H kick [%s]", twit);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ return;
+ }
+
+ exit_room(xuser, EXIT_KICK, (char *) NULL);
+
+ if (room == &mainroom)
+ logout_user(xuser);
+ else
+ enter_room(xuser, MAIN_NAME, (char *) NULL);
+}
+
+
+static void
+chat_makeop(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ char *newop;
+ ChatUser *xuser;
+ ChatRoom *room;
+
+ if (!ROOMOP(cu))
+ {
+ send_to_user(cu, msg_not_op, 0, MSG_MESSAGE);
+ return;
+ }
+
+ newop = nextword(&msg);
+ xuser = cuser_by_chatid(newop);
+
+ if (xuser == NULL)
+ {
+ sprintf(chatbuf, msg_no_such_id, newop);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ return;
+ }
+
+ if (cu == xuser)
+ {
+ sprintf(chatbuf, "¡° ±z¦­´N¤w¸g¬O Op ¤F°Ú");
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ return;
+ }
+
+ room = cu->room;
+
+ if (room != xuser->room || CLOAK(xuser))
+ { /* Thor: ²á¤Ñ«ÇÁô¨­³N */
+ sprintf(chatbuf, msg_not_here, xuser->chatid);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ return;
+ }
+
+ cu->uflag &= ~PERM_ROOMOP;
+ xuser->uflag |= PERM_ROOMOP;
+
+ user_changed(cu);
+ user_changed(xuser);
+
+ sprintf(chatbuf, "¡° %s ±N Op Åv¤OÂಾµ¹ %s",
+ cu->chatid, xuser->chatid);
+ if (!CLOAK(cu)) /* Thor: ²á¤Ñ«ÇÁô¨­³N */
+ send_to_room(room, chatbuf, 0, MSG_MESSAGE, MSG_MESSAGE);
+}
+
+
+
+static void
+chat_invite(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ char *invitee;
+ 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 (xuser == NULL)
+ {
+ sprintf(chatbuf, msg_no_such_id, invitee);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ return;
+ }
+
+ room = cu->room; /* Thor: ¬O§_­n check room ¬O§_ NULL ? */
+ list = &(room->invite);
+
+ if (list_belong(*list, xuser->userno))
+ {
+ sprintf(chatbuf, "¡° %s ¤w¸g±µ¨ü¹LÁܽФF", xuser->chatid);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ return;
+ }
+ list_add(list, xuser);
+
+ sprintf(chatbuf, "¡° %s Áܽбz¨ì [%s] ²á¤Ñ«Ç",
+ cu->chatid, room->name);
+ send_to_user(xuser, chatbuf, 0, MSG_MESSAGE); /* Thor: ­n¤£­n¥i¥H ignore? */
+ sprintf(chatbuf, "¡° %s ¦¬¨ì±zªºÁܽФF", xuser->chatid);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+}
+
+
+static void
+chat_broadcast(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ 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(chatbuf, "¡° " BBSNAME "½Í¤Ñ«Ç¼s¼½¤¤ [%s].....",
+ cu->chatid);
+ send_to_room(ROOM_ALL, chatbuf, 0, MSG_MESSAGE);
+ sprintf(chatbuf, "¡» %s", msg);
+ send_to_room(ROOM_ALL, chatbuf, 0, MSG_MESSAGE);
+}
+
+
+static void
+chat_goodbye(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ exit_room(cu, EXIT_LOGOUT, msg);
+ /* Thor: ­n¤£­n¥[ logout_user(cu) ? */
+}
+
+
+/* --------------------------------------------- */
+/* MUD-like social commands : action */
+/* --------------------------------------------- */
+
+struct ChatAction
+{
+ char *verb; /* °Êµü */
+ char *chinese; /* ¤¤¤å½Ķ */
+ char *part1_msg; /* ¤¶µü */
+ char *part2_msg; /* °Ê§@ */
+};
+
+
+static ChatAction party_data[] =
+{
+ {"aluba", "ªü¾|¤Ú", "§â", "¬[¤W¬W¤lªü¾|¤Ú!!"},
+ {"aodre", "´º¥õ", "¹ï", "ªº´º¥õ¦³¦p·Ê·Ê¦¿¤ô,³sºø¤£µ´¡K¡K"},
+ {"bearhug", "¼ö¾Ö", "¼ö±¡ªº¾Ö©ê", ""},
+ {"blade", "¤@¤M", "¤@¤M±Òµ{§â", "°e¤W¦è¤Ñ"},
+ {"bless", "¯¬ºÖ", "¯¬ºÖ", "¤ß·Q¨Æ¦¨"},
+ {"board", "¥D¾÷ªO", "§â", "§ì¥h¸÷¥D¾÷ªO"},
+ {"bokan", "®ð¥\\", "Âù´x·L¦X¡A»W¶Õ«Ýµo¡K¡K¬ðµM¶¡¡A¹q¥ú¥E²{¡A¹ï", "¨Ï¥X¤F¢Ðo--¢Ùan¡I"},
+ {"bow", "Áù°`", "²¦°`²¦·qªº¦V", "Áù°`"},
+ {"box", "¹õ¤§¤º", "¶}©l½üÂ\\¦¡²¾¦ì¡A¹ï", "§@¨xŦ§ðÀ»"},
+ {"boy", "¥­©³Áç", "±q­I«á®³¥X¤F¥­©³Áç¡A§â", "ºV©ü¤F"},
+ {"bye", "ÙTÙT", "¦V", "»¡ÙTÙT!!"},
+ {"call", "©I³ê", "¤jÁnªº©I³ê,°Ú~~", "°Ú~~~§A¦b­þ¸Ì°Ú°Ú°Ú°Ú~~~~"},
+ {"caress", "»´¼¾", "»´»´ªº¼¾ºNµÛ", ""},
+ {"clap", "¹ª´x", "¦V", "¼ö¯P¹ª´x"},
+ {"claw", "§ì§ì", "±q¿ß«}¼Ö¶é­É¤F°¦¿ß¤ö¡A§â", "§ì±o¦º¥h¬¡¨Ó"},
+ {"comfort", "¦w¼¢", "·Å¨¥¦w¼¢", ""},
+ {"cong", "®¥³ß", "±q­I«á®³¥X¤F©Ô¬¶¡AËé¡IËé¡I®¥³ß", ""},
+ {"cpr", "¤f¹ï¤f", "¹ïµÛ", "°µ¤f¹ï¤f¤H¤u©I§l"},
+ {"cringe", "¤^¼¦", "¦V", "¨õ°`©}½¥¡A·n§À¤^¼¦"},
+ {"cry", "¤j­ú", "¦V", "Àz°Þ¤j­ú"},
+ {"dance", "¸õ»R", "©Ô¤F", "ªº¤â½¡½¡°_»R" },
+ {"destroy", "·´·À", "²½°_¤F¡y·¥¤j·´·À©G¤å¡z¡AÅF¦V", ""},
+ {"dogleg", "ª¯»L", "¹ï", "ª¯»L"},
+ {"drivel", "¬y¤f¤ô", "¹ïµÛ", "¬y¤f¤ô"},
+ {"envy", "¸r¼}", "¦V", "¬yÅS¥X¸r¼}ªº²´¥ú"},
+ {"eye", "°e¬îªi", "¹ï", "ÀW°e¬îªi"},
+ {"fire", "¾R°Ý", "®³µÛ¤õ¬õªºÅK´Î¨«¦V", ""},
+ {"forgive", "­ì½Ì", "±µ¨ü¹Dºp¡A­ì½Ì¤F", ""},
+ {"french", "ªk¦¡§k", "§â¦ÞÀY¦ù¨ì", "³ïÄV¸Ì¡ã¡ã¡ã«z¡I¤@­Ó®öº©ªºªk°ê¤ó²`§k"},
+ {"giggle", "¶Ì¯º", "¹ïµÛ", "¶Ì¶Ìªº§b¯º"},
+ {"glue", "¸É¤ß", "¥Î¤T¬í½¦¡A§â", "ªº¤ßÂH¤F°_¨Ó"},
+ {"goodbye", "§i§O", "²\\²´¨L¨Lªº¦V", "§i§O"},
+ {"grin", "¦l¯º", "¹ï", "ÅS¥X¨¸´cªº¯º®e"},
+ {"growl", "©H­ý", "¹ï", "©H­ý¤£¤w"},
+ {"hand", "´¤¤â", "¸ò", "´¤¤â"},
+ {"hide", "¸ú", "¸ú¦b", "­I«á"},
+ {"hospitl", "°eÂå°|", "§â", "°e¶iÂå°|"},
+ {"hug", "¾Ö©ê", "»´»´¦a¾Ö©ê", ""},
+ {"hrk", "ª@Às®±", "¨Ií¤F¨­§Î¡A¶×»E¤F¤º«l¡A¹ï", "¨Ï¥X¤F¤@°O¢Öo--¢àyu--¢Ùan¡I¡I¡I"},
+ {"jab", "ÂW¤H", "·Å¬XªºÂWµÛ", ""},
+ {"judo", "¹LªÓºL", "§ì¦í¤F", "ªº¦çÃÌ¡AÂਭ¡K¡K°Ú¡A¬O¤@°O¹LªÓºL¡I"},
+ {"kickout", "½ð", "¥Î¤j¸}§â", "½ð¨ì¤s¤U¥h¤F"},
+ {"kick", "½ð¤H", "§â", "½ðªº¦º¥h¬¡¨Ó"},
+ {"kiss", "»´§k", "»´§k", "ªºÁyÀU"},
+ {"laugh", "¼J¯º", "¤jÁn¼J¯º", ""},
+ {"levis", "µ¹§Ú", "»¡¡Gµ¹§Ú", "¡I¨ä¾l§K½Í¡I"},
+ {"lick", "»Q", "¨g»Q", ""},
+ {"lobster", "À£¨î", "¬I®i°f½¼§Î©T©w¡A§â", "À£¨î¦b¦aªO¤W"},
+ {"love", "ªí¥Õ", "¹ï", "²`±¡ªºªí¥Õ"},
+ {"marry", "¨D±B", "±·µÛ¤E¦Ê¤E¤Q¤E¦·ª´ºÀ¦V", "¨D±B"},
+ {"no", "¤£­n°Ú", "«÷©R¹ïµÛ", "·nÀY~~~~¤£­n°Ú~~~~"},
+ {"nod", "ÂIÀY", "¦V", "ÂIÀYºÙ¬O"},
+ {"nudge", "³»¨{¤l", "¥Î¤â¨y³»", "ªºªÎ¨{¤l"},
+ {"pad", "©çªÓ»H", "»´©ç", "ªºªÓ»H"},
+ {"pettish", "¼»¼b", "¸ò", "ÜÝÁnÜÝ®ð¦a¼»¼b"},
+ {"pili", "ÅRÆE", "¨Ï¥X §g¤l­· ¤Ñ¦a®Ú ¯ë­YÄb ¤T¦¡¦X¤@¥´¦V", "~~~~~~"},
+ {"pinch", "À¾¤H", "¥Î¤Oªº§â", "À¾ªº¶Â«C"},
+ {"roll", "¥´ºu", "©ñ¥X¦hº¸³Oªº­µ¼Ö,", "¦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"},
+ {"respond", "­t³d", "¦w¼¢", "»¡¡G¡y¤£­n­ú¡A§Ú·|­t³dªº¡K¡K¡z"},
+ {"shrug", "ÁqªÓ", "µL©`¦a¦V", "Áq¤FÁqªÓ»H"},
+ {"sigh", "¼Û®ð", "¹ï", "¼Û¤F¤@¤f®ð"},
+ {"slap", "¥´¦Õ¥ú", "°Ô°Ôªº¤Ú¤F", "¤@¹y¦Õ¥ú"},
+ {"smooch", "¾Ö§k", "¾Ö§kµÛ", ""},
+ {"snicker", "Åѯº", "¼K¼K¼K..ªº¹ï", "Åѯº"},
+ {"sniff", "¤£®h", "¹ï", "¶á¤§¥H»ó"},
+ {"spank", "¥´§¾§¾", "¥Î¤Ú´x¥´", "ªºÁv³¡"},
+ {"squeeze", "ºò¾Ö", "ºòºò¦a¾Ö©êµÛ", ""},
+ {"sysop", "¥l³ê", "¥s¥X¤F§å½ð½ð¡A§â", "½ò«ó¤F¡I"},
+ {"thank", "·PÁÂ", "¦V", "·PÁ±o¤­Åé§ë¦a"},
+ {"tickle", "·kÄo", "©B¼T!©B¼T!·k", "ªºÄo"},
+ {"wake", "·n¿ô", "»´»´¦a§â", "·n¿ô"},
+ {"wave", "´§¤â", "¹ïµÛ", "«÷©Rªº·n¤â"},
+ {"welcome", "Åwªï", "Åwªï", "¶i¨Ó¤K¨ö¤@¤U"},
+ {"what", "¤°»ò", "»¡¡G¡y", "­ù¤½½M±K«zÃ÷Å¥¬Y?¡H?¡S?¡z"},
+ {"whip", "Ã@¤l", "¤â¤W®³µÛÄúÀë¡A¥ÎÃ@¤lµh¥´", ""},
+ {"wink", "¯w²´", "¹ï", "¯«¯µªº¯w¯w²´·ú"},
+ {"zap", "²r§ð", "¹ï", "ºÆ¨gªº§ðÀ»"},
+ {NULL, NULL, NULL, NULL}
+};
+
+static int
+chicken_action(cu, cmd, party)
+ ChatUser *cu;
+ char *cmd;
+ char *party;
+{
+return 0;
+}
+static int
+party_action(cu, cmd, party)
+ ChatUser *cu;
+ char *cmd;
+ char *party;
+{
+ ChatAction *cap;
+ char *verb;
+
+ for (cap = party_data; (verb = cap->verb); cap++)
+ {
+ MYDOG;
+
+ if (str_equal(cmd, verb))
+ {
+ if (*party == '\0')
+ {
+ party = "¤j®a";
+ }
+ else
+ {
+ ChatUser *xuser;
+
+ xuser = fuzzy_cuser_by_chatid(party);
+ if (xuser == NULL)
+ { /* Thor.0724: ¥Î userid¤]¹À³q */
+ xuser = cuser_by_userid(party);
+ }
+
+ if (xuser == NULL)
+ {
+ sprintf(chatbuf, msg_no_such_id, party);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ return 0;
+ }
+ else if (xuser == FUZZY_USER)
+ {
+ sprintf(chatbuf, "¡° ½Ð«ü©ú²á¤Ñ¥N¸¹");
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ return 0;
+ }
+ else if (cu->room != xuser->room || CLOAK(xuser))
+ {
+ sprintf(chatbuf, msg_not_here, party);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ return 0;
+ }
+ else
+ {
+ party = xuser->chatid;
+ }
+ }
+ sprintf(chatbuf, "%s %s %s %s",
+ cu->chatid, cap->part1_msg, party, cap->part2_msg);
+ send_to_room(cu->room, chatbuf, cu->userno, MSG_MESSAGE);
+ return 0; /* Thor: cu->room ¬O§_¬° NULL? */
+ }
+ }
+ return 1;
+}
+
+
+/* --------------------------------------------- */
+/* MUD-like social commands : speak */
+/* --------------------------------------------- */
+
+
+static ChatAction speak_data[] =
+{
+
+ {
+ "ask", "¸ß°Ý", "°Ý", NULL
+ },
+ {
+ "chant", "ºq¹|", "°ªÁnºq¹|", NULL
+ },
+ {
+ "cheer", "³Üªö", "³Üªö", NULL
+ },
+ {
+ "chuckle", "»´¯º", "»´¯º", NULL
+ },
+ {
+ "curse", "·t·F", "·t·F", NULL
+ },
+ /* {"curse", "©G½|", NULL}, */
+ {
+ "demand", "­n¨D", "­n¨D", NULL
+ },
+ {
+ "frown", "½K¬ÜÀY", "ÂÙ¬Ü", NULL
+ },
+ {
+ "groan", "©D§u", "©D§u", NULL
+ },
+ {
+ "grumble", "µo¨cÄÌ", "µo¨cÄÌ", NULL
+ },
+ {
+ "guitar", "¼u°Û", "Ãä¼uµÛ¦N¥L¡AÃä°ÛµÛ", NULL
+ },
+ /* {"helpme", "©I±Ï","¤jÁn©I±Ï",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 *verb;
+
+ for (cap = speak_data; (verb = cap->verb); cap++)
+ {
+ MYDOG;
+
+ if (str_equal(cmd, verb))
+ {
+ sprintf(chatbuf, "%s %s¡G %s",
+ cu->chatid, cap->part1_msg, msg);
+ send_to_room(cu->room, chatbuf, cu->userno, MSG_MESSAGE);
+ return 0; /* Thor: cu->room ¬O§_¬° NULL? */
+ }
+ }
+ return 1;
+}
+
+
+/* -------------------------------------------- */
+/* MUD-like social commands : condition */
+/* -------------------------------------------- */
+
+
+static ChatAction condition_data[] =
+{
+ {
+ "applaud", "©ç¤â", "°Ô°Ô°Ô°Ô°Ô°Ô°Ô....", NULL
+ },
+ {
+ "ayo", "­üËç³Þ", "­üËç³Þ~~~", NULL
+ },
+ {
+ "back", "§¤¦^¨Ó", "¦^¨Ó§¤¥¿Ä~Äò¾Ä¾Ô", NULL
+ },
+ {
+ "blood", "¦b¦å¤¤", "­Ë¦b¦åªy¤§¤¤", NULL
+ },
+ {
+ "blush", "Áy¬õ", "Áy³£¬õ¤F", NULL
+ },
+ {
+ "broke", "¤ß¸H", "ªº¤ß¯}¸H¦¨¤@¤ù¤@¤ùªº", NULL
+ }, /* Thor.0731:À³Æ[²³­n¨D */
+ /* {"bokan", "Bo Kan! Bo Kan!", NULL}, */
+ {
+ "careles", "¨S¤H²z", "¶ã¡ã¡ã³£¨S¦³¤H²z§Ú :~~~~", NULL
+ },
+ {
+ "chew", "¶ß¥Ê¤l", "«Ü±y¶¢ªº¶ß°_¥Ê¤l¨Ó¤F", NULL
+ },
+ {
+ "climb", "ª¦¤s", "¦Û¤vºCºCª¦¤W¤s¨Ó¡K¡K", NULL
+ },
+ {
+ "cold", "·P«_¤F", "·P«_¤F,¶ý¶ý¤£Åý§Ú¥X¥hª± :~~~(", NULL
+ },
+ {
+ "cough", "«y¹Â", "«y¤F´XÁn", NULL
+ },
+ {
+ "die", "¼ÉÀÅ", "·í³õ¼ÉÀÅ", NULL
+ },
+ {
+ "faint", "©ü­Ë", "·í³õ©ü­Ë", NULL
+ },
+ {
+ "flop", "­»¿¼¥Ö", "½ò¨ì­»¿¼¥Ö... ·Æ­Ë¡I", NULL
+ },
+ {
+ "fly", "ÄÆÄƵM", "ÄÆÄƵM", NULL
+ },
+ {
+ "frown", "ÂÙ¬Ü", "ÂÙ¬Ü", NULL
+ },
+ {
+ "gold", "®³ª÷µP", "°ÛµÛ¡G¡yª÷£|£±£½ª÷£|£±£½ ¥X°ê¤ñÁÉ! ±o«a­x¡A®³ª÷µP¡A¥úºa­Ë¾H¨Ó¡I¡z", NULL
+ },
+ {
+ "gulu", "¨{¤l¾j", "ªº¨{¤lµo¥X©BÂP~~~©BÂP~~~ªºÁn­µ", NULL
+ },
+ {
+ "haha", "«z«¢«¢", "«z«¢«¢«¢.....^o^", NULL
+ },
+ /* {"haha", "¤j¯º","«z«¢«¢«¢«¢«¢«¢«¢«¢~~~~!!!!!", NULL}, */
+ {
+ "helpme", "¨D±Ï", "¤j³Û~~~±Ï©R°Ú~~~~", NULL
+ },
+ {
+ "hoho", "¨þ¨þ¯º", "¨þ¨þ¨þ¯º­Ó¤£°±", NULL
+ },
+ {
+ "happy", "°ª¿³", "°ª¿³±o¦b¦a¤W¥´ºu", NULL
+ },
+ /* {"happy", "°ª¿³", "¢ç¢Ï¡I *^_^*", NULL}, */
+ /* {"happy", "", "r-o-O-m....Å¥¤F¯u²n¡I", NULL}, */
+ /* {"hurricane", "¢Ö¢÷---¢à£B¢ý--¢Ù¢é¢ö¡I¡I¡I", NULL}, */
+ {
+ "idle", "§b¦í¤F", "§b¦í¤F", NULL
+ },
+ {
+ "jacky", "®Ì®Ì", "µl¤l¯ëªº®Ì¨Ó®Ì¥h", NULL
+ },
+
+#if 0
+ /* Thor.0729: ¤£ª¾¨ä·N */
+ {
+ "lag", "ºô¸ôºC", "lllllllaaaaaaaaaaaagggggggggggggg.................", NULL
+ },
+#endif
+
+ {
+ "luck", "©¯¹B", "«z¡IºÖ®ð°Õ¡I", NULL
+ },
+ {
+ "macarn", "¤@ºØ»R", "¶}©l¸õ°_¤F¢Ûa¢Ña¢àe¢Üa¡ã¡ã¡ã¡ã", NULL
+ },
+ {
+ "miou", "ØpØp", "ØpØp¤f­]¤f­]¡ã¡ã¡ã¡ã¡ã", NULL
+ },
+ {
+ "mouth", "«ó¼L", "«ó¼L¤¤!!", NULL
+ },
+ {
+ "nani", "«ç»ò·|", "¡G©`£®°Ú®º??", NULL
+ },
+ {
+ "nose", "¬y»ó¦å", "¬y»ó¦å", NULL
+ },
+ {
+ "puke", "¹Ã¦R", "¹Ã¦R¤¤", NULL
+ },
+ /* {"puke", "¯uäú¤ß¡A§ÚÅ¥¤F³£·Q¦R", NULL}, */
+ {
+ "rest", "¥ð®§", "¥ð®§¤¤¡A½Ð¤Å¥´ÂZ", NULL
+ },
+ {
+ "reverse", "½¨{", "½¨{", NULL
+ },
+ {
+ "room", "¶}©Ð¶¡", "r-o-O-m-r-O-¢Ý-Mmm-rR¢à........", NULL
+ },
+ {
+ "shake", "·nÀY", "·n¤F·nÀY", NULL
+ },
+ {
+ "sleep", "ºÎµÛ", "­w¦bÁä½L¤WºÎµÛ¤F¡A¤f¤ô¬y¶iÁä½L¡A³y¦¨·í¾÷¡I", NULL
+ },
+ /* {"sleep", "Zzzzzzzzzz¡A¯uµL²á¡A³£§ÖºÎµÛ¤F", NULL}, */
+ {
+ "so", "´NÂæ¤l", "´NÂæ¤l!!", NULL
+ },
+ {
+ "sorry", "¹Dºp", "¶ã°Ú!!§Ú¹ï¤£°_¤j®a,§Ú¹ï¤£°_°ê®aªÀ·|~~~~~~¶ã°Ú~~~~~", NULL
+ },
+ {
+ "story", "Á¿¥j", "¶}©lÁ¿¥j¤F", NULL
+ },
+ {
+ "strut", "·nÂ\\¨«", "¤j·n¤jÂ\\¦a¨«", NULL
+ },
+ {
+ "suicide", "¦Û±þ", "¦Û±þ", NULL
+ },
+ {
+ "tea", "ªw¯ù", "ªw¤F³ý¦n¯ù", 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
+ },
+ /* {"wawa","«z«z«z......>_<",NULL}, */
+ {
+ "www", "¨L¨L", "¨L¨L¨L!!!", 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 *verb;
+
+ for (cap = condition_data; (verb = cap->verb); cap++)
+ {
+ MYDOG;
+
+ if (str_equal(cmd, verb))
+ {
+ sprintf(chatbuf, "%s %s",
+ cu->chatid, cap->part1_msg);
+ send_to_room(cu->room, chatbuf, cu->userno, MSG_MESSAGE);
+ return 1; /* Thor: cu->room ¬O§_¬° NULL? */
+ }
+ }
+ return 0;
+}
+
+
+/* --------------------------------------------- */
+/* MUD-like social commands : help */
+/* --------------------------------------------- */
+
+
+static char *dscrb[] =
+{
+ "¡i Verb + Nick¡G °Êµü + ¹ï¤è¦W¦r ¡j ¨Ò¡G//kick piggy",
+ "¡i Verb + Message¡G°Êµü + ­n»¡ªº¸Ü ¡j ¨Ò¡G//sing ¤Ñ¤Ñ¤ÑÂÅ",
+ "¡i Verb¡G°Êµü ¡j ¡ô¡õ¡G¸ܭ«´£", NULL
+};
+ChatAction *catbl[] =
+{
+ party_data, speak_data, condition_data, NULL
+};
+
+static void
+chat_partyinfo(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ if (!common_client_command)
+ return; /* only allow common client to retrieve it */
+
+ sprintf(chatbuf, "3 °Ê§@ ¥æ½Í ª¬ºA");
+ send_to_user(cu, chatbuf, 0, MSG_PARTYINFO);
+}
+
+static void
+chat_party(cu, msg)
+ ChatUser *cu;
+ char *msg;
+{
+ int kind, i;
+ ChatAction *cap;
+
+ if (!common_client_command)
+ return;
+
+ kind = atoi(nextword(&msg));
+ if (kind < 0 || kind > 2)
+ return;
+
+ sprintf(chatbuf, "%d %s", kind, kind == 2 ? "I" : "");
+
+ /* Xshadow: ¥u¦³ condition ¤~¬O immediate mode */
+ send_to_user(cu, chatbuf, 0, MSG_PARTYLISTSTART);
+
+ cap = catbl[kind];
+ for (i = 0; cap[i].verb; i++)
+ {
+ sprintf(chatbuf, "%-10s %-20s", cap[i].verb, cap[i].chinese);
+ /* for (j=0;j<1000000;j++); */
+ send_to_user(cu, chatbuf, 0, MSG_PARTYLIST);
+ }
+
+ sprintf(chatbuf, "%d", kind);
+ send_to_user(cu, chatbuf, 0, MSG_PARTYLISTEND);
+}
+
+
+#define SCREEN_WIDTH 80
+#define MAX_VERB_LEN 8
+#define VERB_NO 10
+
+static void
+view_action_verb(cu, cmd) /* Thor.0726: ·s¥[°Êµü¤ÀÃþÅã¥Ü */
+ register ChatUser *cu;
+ char cmd;
+{
+ register int i;
+ register char *p, *q, *data, *expn;
+ register ChatAction *cap;
+
+ send_to_user(cu, "/c", 0, MSG_CLRSCR);
+
+ data = chatbuf;
+
+ if (cmd < '1' || cmd > '3')
+ { /* Thor.0726: ¼g±o¤£¦n, ·Q¿ìªk§ï¶i... */
+ for (i = 0; (p = dscrb[i]); i++)
+ {
+ sprintf(data, " [//]help %d - MUD-like ªÀ¥æ°Êµü ²Ä %d Ãþ", i + 1, i + 1);
+ MYDOG;
+ send_to_user(cu, data, 0, MSG_MESSAGE);
+ send_to_user(cu, p, 0, MSG_MESSAGE);
+ send_to_user(cu, " ", 0, MSG_MESSAGE); /* Thor.0726: ´«¦æ, »Ý­n " "
+ * ¶Ü? */
+ }
+ }
+ else
+ {
+ i = cmd - '1';
+
+ send_to_user(cu, dscrb[i], 0, MSG_MESSAGE);
+
+ expn = chatbuf + 100; /* Thor.0726: À³¸Ó¤£·|overlap§a? */
+
+ *data = '\0';
+ *expn = '\0';
+
+ cap = catbl[i];
+
+ for (i = 0; (p = cap[i].verb); i++)
+ {
+ MYDOG;
+ 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.0726: Åã¥Ü¤¤¤åµù¸Ñ */
+ *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.0726: Åã¥Ü¤¤¤åµù¸Ñ */
+ }
+ }
+ /* send_to_user(cu, " ",0); *//* Thor.0726: ´«¦æ, »Ý­n " " ¶Ü? */
+}
+
+void view_chicken_help(cu) /* Ptt: °«Âûµ{¦¡ ªºhelp */
+ register ChatUser *cu;
+{
+
+}
+
+/* ----------------------------------------------------- */
+/* chat user service routines */
+/* ----------------------------------------------------- */
+
+
+static ChatCmd chatcmdlist[] =
+{
+ {"act", chat_act, 0},
+ {"bye", chat_goodbye, 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 */
+
+ {"query", chat_query, 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;
+ 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] == '!')))
+ {
+ 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)
+ {
+ char buf[16];
+
+ sprintf(buf, "%s:", cu->chatid);
+ sprintf(chatbuf, "%-10s%s", buf, msg);
+ if (!CLOAK(cu)) /* Thor: ²á¤Ñ«ÇÁô¨­³N */
+ send_to_room(cu->room, chatbuf, cu->userno, MSG_MESSAGE);
+ /* Thor: ­n check cu->room NULL¶Ü? */
+
+ }
+ return 0;
+ }
+
+ msg++;
+ cmd = nextword(&msg);
+ match = 0;
+
+ if (*cmd == '/')
+ {
+ cmd++;
+ if (!*cmd || str_equal(cmd, "help"))
+ {
+ /* Thor.0726: °Êµü¤ÀÃþ */
+ cmd = nextword(&msg);
+ view_action_verb(cu, *cmd);
+ match = 1;
+ }
+ else if (party_action(cu, cmd, msg) == 0)
+ match = 1;
+ else if (speak_action(cu, cmd, msg) == 0)
+ match = 1;
+ else
+ match = condition_action(cu, cmd);
+ }
+ else if(*cmd == '.')
+ {
+ cmd++;
+ if (!*cmd || str_equal(cmd, "help"))
+ {
+ view_chicken_help(cu);
+ match = 1;
+ }
+ else match = chicken_action(cu, cmd, msg);
+ }
+ else
+ {
+ char *str;
+
+ common_client_command = 0;
+ if((*cmd == '-')) {
+ if(cu->clitype) {
+ cmd++; /* Xshadow: «ü¥O±q¤U¤@­Ó¦r¤¸¤~¶}©l */
+ common_client_command = 1;
+ }
+ }
+ for(cmdrec = chatcmdlist; (str = cmdrec->cmdstr); cmdrec++)
+ {
+ MYDOG;
+
+ switch (cmdrec->exact)
+ {
+ case 1: /* exactly equal */
+ match = str_equal(cmd, str);
+ break;
+ case 2: /* Thor: secret command */
+ if (CHATSYSOP(cu))
+ match = str_equal(cmd, str);
+ break;
+ default: /* not necessary equal */
+ match = str_match(cmd, str) >= 0;
+ break;
+ }
+
+ if (match)
+ {
+ cmdrec->cmdfunc(cu, msg);
+ break;
+ }
+ }
+ }
+
+ if (!match)
+ {
+ sprintf(chatbuf, "¡» «ü¥O¿ù»~¡G/%s", cmd);
+ send_to_user(cu, chatbuf, 0, MSG_MESSAGE);
+ }
+ return 0;
+}
+
+
+/* ----------------------------------------------------- */
+/* serve chat_user's connection */
+/* ----------------------------------------------------- */
+
+
+static int
+cuser_serve(cu)
+ ChatUser *cu;
+{
+ register int ch, len, isize;
+ register char *str, *cmd;
+ static char buf[80];
+
+ str = buf;
+ len = recv(cu->sock, str, sizeof(buf) - 1, 0);
+ if (len <= 0)
+ {
+ /* disconnected */
+
+ exit_room(cu, EXIT_LOSTCONN, (char *) NULL);
+ return -1;
+ }
+
+#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
+
+ isize = cu->isize;
+ cmd = cu->ibuf + isize;
+ while (len--)
+ {
+ MYDOG;
+
+ ch = *str++;
+
+ if (ch == '\r' || !ch)
+ continue;
+ if (ch == '\n')
+ {
+ *cmd = '\0';
+
+ isize = 0;
+ cmd = cu->ibuf;
+
+ if (command_execute(cu) < 0)
+ return -1;
+
+ continue;
+ }
+ if (isize < 79)
+ {
+ *cmd++ = ch;
+ isize++;
+ }
+ }
+ cu->isize = isize;
+ return 0;
+}
+
+
+/* ----------------------------------------------------- */
+/* chatroom server core routines */
+/* ----------------------------------------------------- */
+
+static int
+start_daemon()
+{
+ int fd, value;
+ char buf[80];
+ struct sockaddr_in fsin;
+ struct linger ld;
+ struct rlimit limit;
+ time_t dummy;
+ struct tm *dummy_time;
+
+ /*
+ * 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(&dummy);
+ dummy_time = gmtime(&dummy);
+ dummy_time = localtime(&dummy);
+ strftime(buf, 80, "%d/%b/%Y:%H:%M:%S", dummy_time);
+
+ /* --------------------------------------------------- */
+ /* speed-hacking DNS resolve */
+ /* --------------------------------------------------- */
+
+ gethostname(buf, sizeof(buf));
+
+ /* Thor: ¸U¤@server©|¥¼±µ¨üconnection, ´N¦^¥hªº¸Ü, client ²Ä¤@¦¸·|¶i¤J¥¢±Ñ */
+ /* ©Ò¥H²¾¦Ü listen «á */
+
+ /* --------------------------------------------------- */
+ /* detach daemon process */
+ /* --------------------------------------------------- */
+
+ close(0);
+ close(1);
+ close(2);
+
+ if (fork())
+ exit(0);
+
+ chdir(BBSHOME);
+
+ setsid();
+
+ /* --------------------------------------------------- */
+ /* adjust the resource limit */
+ /* --------------------------------------------------- */
+
+ getrlimit(RLIMIT_NOFILE, &limit);
+ limit.rlim_cur = limit.rlim_max;
+ setrlimit(RLIMIT_NOFILE, &limit);
+
+#if 0
+ while (fd)
+ {
+ close(--fd);
+ }
+
+ value = getpid();
+ setpgrp(0, value);
+
+ if ((fd = open("/dev/tty", O_RDWR)) >= 0)
+ {
+ ioctl(fd, TIOCNOTTY, 0); /* Thor : ¬°¤°»òÁÙ­n¥Î tty? */
+ close(fd);
+ }
+#endif
+
+ fd = open(CHAT_PIDFILE, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (fd >= 0)
+ {
+ /* sprintf(buf, "%5d\n", value); */
+ sprintf(buf, "%5d\n", getpid());
+ write(fd, buf, 6);
+ close(fd);
+ }
+
+#if 0
+ /* ------------------------------ */
+ /* trap signals */
+ /* ------------------------------ */
+
+ for (fd = 1; fd < NSIG; fd++)
+ {
+
+ signal(fd, SIG_IGN);
+ }
+#endif
+
+ fd = socket(PF_INET, SOCK_STREAM, 0);
+
+#if 0
+ value = fcntl(fd, F_GETFL, 0);
+ fcntl(fd, F_SETFL, value | O_NDELAY);
+#endif
+
+ value = 1;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value, sizeof(value));
+
+#if 0
+ setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &value, sizeof(value));
+
+ value = 81920;
+ setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (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(NEW_CHATPORT);
+ fsin.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if (bind(fd, (struct sockaddr *) & fsin, sizeof(fsin)) < 0)
+ exit(1);
+
+ listen(fd, SOCK_QLEN);
+
+ return fd;
+}
+
+
+static void
+free_resource(fd)
+ int fd;
+{
+ static int loop = 0;
+ register ChatUser *user;
+ register int sock, num;
+
+ num = 0;
+ for (user = mainuser; user; user = user->unext)
+ {
+ MYDOG;
+
+ num++;
+ sock = user->sock;
+ if (fd < sock)
+ fd = sock;
+ }
+
+ sprintf(chatbuf, "%d, %d user (%d -> %d)", ++loop, num, maxfds, fd);
+ logit("LOOP", chatbuf);
+
+ maxfds = fd + 1;
+}
+
+
+#ifdef SERVER_USAGE
+static void
+server_usage()
+{
+ struct rusage ru;
+ char buf[2048];
+
+ if (getrusage(RUSAGE_SELF, &ru))
+ return;
+
+ sprintf(buf, "\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: %ld\n"
+ "page faults requiring physical I/O: %ld\n"
+ "swaps: %ld\n"
+ "block input operations: %ld\n"
+ "block output operations: %ld\n"
+ "messages sent: %ld\n"
+ "messages received: %ld\n"
+ "signals received: %ld\n"
+ "voluntary context switches: %ld\n"
+ "involuntary context switches: %ld\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);
+
+ write(flog, buf, strlen(buf));
+}
+#endif
+
+
+static void
+abort_server()
+{
+ log_close();
+ exit(1);
+}
+
+
+static void
+reaper()
+{
+ int state;
+
+ while (waitpid(-1, &state, WNOHANG | WUNTRACED) > 0)
+ {
+ MYDOG;
+ }
+}
+
+
+int
+main()
+{
+ register int msock, csock, nfds;
+ register ChatUser *cu;
+ register fd_set *rptr, *xptr;
+ fd_set rset, xset;
+ struct timeval tv;
+ time_t uptime, tmaintain;
+
+ msock = start_daemon();
+
+ setgid(BBSGID);
+ setuid(BBSUID);
+
+ log_init();
+
+ signal(SIGBUS, SIG_IGN);
+ signal(SIGSEGV, SIG_IGN);
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGURG, SIG_IGN);
+
+ signal(SIGCHLD, reaper);
+ signal(SIGTERM, abort_server);
+
+#ifdef SERVER_USAGE
+ signal(SIGPROF, server_usage);
+#endif
+
+ /* ----------------------------- */
+ /* init variable : rooms & users */
+ /* ----------------------------- */
+
+ mainuser = NULL;
+ memset(&mainroom, 0, sizeof(mainroom));
+ strcpy(mainroom.name, MAIN_NAME);
+ strcpy(mainroom.topic, MAIN_TOPIC);
+
+ /* ----------------------------------- */
+ /* main loop */
+ /* ----------------------------------- */
+
+#if 0
+ /* Thor: ¦blisten «á¤~¦^client, ¨C¦¸¶i¨Ó´N·|¦¨¥\ */
+ if (fork())
+ exit(0);
+#endif
+
+ FD_ZERO(&mainfds);
+ FD_SET(msock, &mainfds);
+ rptr = &rset;
+ xptr = &xset;
+ maxfds = msock + 1;
+
+ tmaintain = time(0) + CHAT_INTERVAL;
+
+ for (;;)
+ {
+ uptime = time(0);
+ if (tmaintain < uptime)
+ {
+ tmaintain = uptime + CHAT_INTERVAL;
+
+ /* client/server ª©¥»§Q¥Î ping-pong ¤èªk§PÂ_ user ¬O¤£¬OÁÙ¬¡µÛ */
+ /* ¦pªG client ¤w¸gµ²§ô¤F¡A´NÄÀ©ñ¨ä resource */
+
+ free_resource(msock);
+ }
+
+ MYDOG;
+
+ memcpy(rptr, &mainfds, sizeof(fd_set));
+ memcpy(xptr, &mainfds, sizeof(fd_set));
+
+ /* Thor: for future reservation bug */
+
+ tv.tv_sec = CHAT_INTERVAL;
+ tv.tv_usec = 0;
+
+ MYDOG;
+
+ nfds = select(maxfds, rptr, NULL, xptr, &tv);
+
+ MYDOG;
+ /* free idle user & chatroom's resource when no traffic */
+
+ if (nfds == 0)
+ {
+ continue;
+ }
+
+ /* check error condition */
+
+ if (nfds < 0)
+ {
+ csock = errno;
+ continue;
+ }
+
+ /* accept new connection */
+
+ if (FD_ISSET(msock, rptr))
+ {
+ for (;;)
+ {
+ MYDOG; /* Thor: check for endless */
+ csock = accept(msock, NULL, NULL);
+
+ if (csock >= 0)
+ {
+ MYDOG;
+ if((cu = (ChatUser *) malloc(sizeof(ChatUser))))
+ {
+ memset(cu, 0, sizeof(ChatUser));
+ cu->sock = csock;
+
+ cu->unext = mainuser;
+ mainuser = cu;
+
+#if 0
+ if (mainuser.next)
+ mainuser.next->prev = cu;
+ cu->next = mainuser.next;
+ mainuser.next = cu;
+ cu->prev = &mainuser;
+#endif
+
+ totaluser++;
+ FD_SET(csock, &mainfds);
+ if (csock >= maxfds)
+ maxfds = csock + 1;
+
+#ifdef DEBUG
+ logit("accept", "OK");
+#endif
+ }
+ else
+ {
+ close(csock);
+ logit("accept", "malloc fail");
+ }
+ MYDOG;
+
+ break;
+ }
+
+ csock = errno;
+ if (csock != EINTR)
+ {
+ break;
+ }
+ }
+
+ FD_CLR(msock, rptr);
+
+ if (--nfds <= 0)
+ continue;
+ }
+
+ for (cu = mainuser; cu; cu = cu->unext)
+ {
+ MYDOG;
+
+ csock = cu->sock;
+
+ if (FD_ISSET(csock, xptr))
+ {
+ logout_user(cu);
+ FD_CLR(csock, xptr);
+ }
+ else if (FD_ISSET(csock, rptr))
+ {
+ if (cuser_serve(cu) < 0)
+ logout_user(cu);
+ }
+ else
+ {
+ continue;
+ }
+
+ FD_CLR(csock, rptr);
+ if (--nfds <= 0)
+ break;
+ }
+
+ /* end of main loop */
+ }
+}
diff --git a/util/xchatd.h b/util/xchatd.h
new file mode 100644
index 00000000..d0a6e1e4
--- /dev/null
+++ b/util/xchatd.h
@@ -0,0 +1,111 @@
+/* $Id: xchatd.h,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+
+#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;
+}
+
+#endif /* _XCHAT_H_ */
diff --git a/util/yearsold.c b/util/yearsold.c
new file mode 100644
index 00000000..74e711ee
--- /dev/null
+++ b/util/yearsold.c
@@ -0,0 +1,112 @@
+/* $Id: yearsold.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */
+/* ¯¸¤W¦~Äֲέp */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "util.h"
+
+#define MAX_LINE 16
+
+struct userec_t cuser;
+
+void
+ outs(fp, buf, mode)
+FILE *fp;
+char buf[], mode;
+{
+ static char state = '0';
+
+ if (state != mode)
+ fprintf(fp, "[3%cm", state = mode);
+ if (buf[0])
+ {
+ fprintf(fp, buf);
+ buf[0] = 0;
+ }
+}
+
+int main()
+{
+ int i, j, k;
+ char buf[256];
+ FILE *fp;
+ int year, max, item, maxyear;
+ long totalyear;
+ int act[25];
+ time_t now;
+ struct tm *ptime;
+
+ now = time(NULL);
+ ptime = localtime(&now);
+
+ if(passwd_mmap())
+ exit(1);
+
+ memset(act, 0, sizeof(act));
+ for(k = 1; k <= MAX_USERS; k++) {
+ passwd_query(k, &cuser);
+ if (((ptime->tm_year - cuser.year) < 10) || ((ptime->tm_year - cuser.year) >
+ 33))
+ continue;
+
+ act[ptime->tm_year - cuser.year - 10]++;
+ act[24]++;
+ }
+
+ for (i = max = totalyear = maxyear = 0; i < 24; i++)
+ {
+ totalyear += act[i] * (i + 10);
+ if (act[i] > max)
+ {
+ max = act[i];
+ maxyear = i;
+ }
+ }
+
+ item = max / MAX_LINE + 1;
+
+ if ((fp = fopen(BBSHOME"/etc/yearsold", "w")) == NULL)
+ {
+ printf("cann't open etc/yearsold\n");
+ return 1;
+ }
+
+ fprintf(fp, "\t\t\t  " BBSNAME
+ " ¦~Äֲέp [%02d/%02d/%02d] \n\n",
+ ptime->tm_year % 100, ptime->tm_mon, ptime->tm_mday);
+ for (i = MAX_LINE + 1; i > 0; i--)
+ {
+ strcpy(buf, " ");
+ for (j = 0; j < 24; j++)
+ {
+ max = item * i;
+ year = act[j];
+ if (year && (max > year) && (max - item <= year))
+ {
+ outs(fp, buf, '7');
+ fprintf(fp, "%-3d", year);
+ }
+ else if (max <= year)
+ {
+ outs(fp, buf, '4');
+ fprintf(fp, "¢i ");
+ }
+ else
+ strcat(buf, " ");
+ }
+ fprintf(fp, "\n");
+ }
+
+
+ fprintf(fp, " "
+ "10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33\n\n"
+ "\t\t ¦³®Ä²Î­p¤H¦¸¡G%-9d¥­§¡¦~ÄÖ¡G%d\n"
+ ,act[24], (int)totalyear / act[24]);
+ fclose(fp);
+ return 0;
+}