Skip to content

Instantly share code, notes, and snippets.

@holishing
Last active September 19, 2018 03:59
Show Gist options
  • Save holishing/1034aeec4c0a0d1ac552ab1c8cb5a721 to your computer and use it in GitHub Desktop.
Save holishing/1034aeec4c0a0d1ac552ab1c8cb5a721 to your computer and use it in GitHub Desktop.
test gist
diff --git a/.gitignore b/.gitignore
index 4f16b7c5..8881b143 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,10 +5,10 @@
.clang_complete
tags
var.h
-/pttbbs.conf
/local.h
common/sys/big5.c
mbbsd/mbbsd
mbbsd/testmbbsd
mbbsd/testsz
mbbsd/vers.c
+pttbbs.conf
diff --git a/README b/README
index 2fb683f2..28e1c744 100644
--- a/README
+++ b/README
@@ -1,53 +1,11 @@
-快速安裝請參考 docs/INSTALL 以及 docs/FAQ
-詳細文件請見 docs/ 或是 http://github.com/ptt/pttbbs/wiki
-
-若有任何問題, 請到批踢踢實業坊 (telnet://ptt.cc) 的 PttCurrent 看板.
-或線上瀏覽 PttCurrent 的看板於 http://www.ptt.cc/bbs/PttCurrent/
-及精華區 http://www.ptt.cc/man/PttCurrent/
-
-目錄結構:
-
- LICENSE 本軟體各檔案在未另外指定時的授權方式
- 請注意部份檔案使用不同的授權 (如 BSD License)
- 由於 GPL 的限制,授權不相容的程式碼已預設為不使用
- 並有提供 GPL 相容版本的替代用程式碼以維持功能完整
- 詳情與設定請參見各檔案內文。
-
- docs/ 文件
+程式是以PTT(批踢踢實業坊 telnet://ptt.cc)所開發釋出的PttBBS(https://github.com/ptt/pttbbs)為基礎,由BunnyBBS(大兔的神密世界 telnet://bunnybbs.tk)工程局長my1938進行程式調校、修改及新增功能後,重新以BRsBBS編列版本後公開釋出並運用於BunnyBBS。
+使用時請遵守PTT(批踢踢實業坊)的規定。
- ADVANCE 進階功能
- ANCESTOR 沿承歷史
- DONATE 贊助方式
- FAQ 常見的問題, sendmail.cf的設定方法等等
- INSTALL 快速安裝方式
- proto/ mbbsd/ 裡面各個檔案的說明,詳見該目錄的 README
- z6ibbs.[12].txt in2 隨筆
+若有任何問題,歡迎與我聯繫。
+通訊地址:70099 台南水交社郵局第70號信箱
+Address:P.O.BOX 70 Tainan Shueijiaoshe, Tainan City 70099, Taiwan (R.O.C.)
+E-mail:[email protected]
+PTT.cc ID:my1938
- sample/ 範例
-
- crontab 提供 bbs執行時須透過 crontab 定時跑的設定
- pttbbs.sh FreeBSD rc 自動執行範例 (/usr/local/etc/rc.d)
- rc.local Linux rc 自動執行範例 (/etc/rc.local)
- pttbbs.conf 範例設定檔 (完整)
- pttbbs_minimal.conf 最小設定檔
-
- daemon/ 背景服務伺服程式
-
- angelbeats/ 小天使相關服務
- banipd/ 判斷是否 IP 已被 ban 掉 (experimental)
- barebone/ 伺服程式骨架
- boardd/ 看板文章服務 (for web)
- bpop3d/ POP3 mail (deprecated)
- brcstored/ BRC 儲存服務 (failed experimental)
- commentd/ 推文記錄服務 (experimental)
- fromd/ 故鄉查詢
- logind/ 海量登入前導程式
- mand/ 精華區文章服務 (for web)
- postd/ 文章記錄服務 (experimental)
- regmaild/ 註冊 email 相關服務
- utmpd/ utmp cache server (experimental)
- wsproxy/ websocket to telnet bbs proxy (experimental)
-
- include/ include 檔
- common/ 共用程式庫
- mbbsd/ bbs 文字模式 (terminal) 主程式
+快速安裝請參考 docs/INSTALL 以及 docs/FAQ
+詳細文件請見 docs/ 或是 http://github.com/ptt/pttbbs/wiki
\ No newline at end of file
diff --git a/common/bbs/Makefile b/common/bbs/Makefile
index 72347584..2c461fdd 100644
--- a/common/bbs/Makefile
+++ b/common/bbs/Makefile
@@ -4,7 +4,7 @@ SRCROOT:= ../..
.include "$(SRCROOT)/pttbbs.mk"
SRCS:= log.c money.c names.c path.c time.c string.c fhdr_stamp.c cache.c \
- passwd.c filehdr.c banip.c search.c
+ passwd.c filehdr.c banip.c
LIB:= cmbbs
install:
diff --git a/common/bbs/cache.c b/common/bbs/cache.c
index b0379bd0..962d28c2 100644
--- a/common/bbs/cache.c
+++ b/common/bbs/cache.c
@@ -615,7 +615,7 @@ setbtotal(int bid)
assert(0<=bid-1 && bid-1<MAX_BOARD);
setbfile(genbuf, bh->brdname, FN_DIR);
- if ((fd = open(genbuf, O_RDONLY)) < 0)
+ if ((fd = open(genbuf, O_RDWR)) < 0)
return; /* .DIR掛了 */
fstat(fd, &st);
num = st.st_size / sizeof(fileheader_t);
diff --git a/common/bbs/fhdr_stamp.c b/common/bbs/fhdr_stamp.c
index f902267b..d5c7f4a6 100644
--- a/common/bbs/fhdr_stamp.c
+++ b/common/bbs/fhdr_stamp.c
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
+#include <time.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
@@ -46,6 +47,7 @@ fhdr_stamp(char *fpath, fileheader_t *fh, int type)
switch (type) {
case STAMP_FILE:
do {
+ srand(time(NULL));
sprintf(ip, "M.%d.A.%3.3X", (int)(++dtime),
(unsigned int)(random() & 0xFFF));
} while ((res = OpenCreate(fpath, O_EXCL | O_WRONLY)) == -1 &&
diff --git a/common/bbs/string.c b/common/bbs/string.c
index b7a48dc5..5f8e1c9f 100644
--- a/common/bbs/string.c
+++ b/common/bbs/string.c
@@ -4,8 +4,6 @@
#include <assert.h>
#include <ctype.h>
#include "cmbbs.h"
-#include "common.h"
-#include "var.h"
void obfuscate_ipstr(char *s)
{
@@ -42,44 +40,3 @@ is_valid_brdname(const char *brdname)
return true;
}
-static int *
-_set_ptype(int *ptype, int type) {
- if (ptype) {
- *ptype = type;
- }
- return NULL;
-}
-
-/**
- * 蝯血���璅� title嚗���唬蜓憿��典���璅€�
- * @param title
- */
-const char *
-subject_ex(const char *title, int *ptype)
-{
- do {
- if (str_case_starts_with(title, str_reply)) {
- title += strlen(str_reply);
- ptype = _set_ptype(ptype, SUBJECT_REPLY);
- } else if (str_case_starts_with(title, str_forward)) {
- title += strlen(str_forward);
- ptype = _set_ptype(ptype, SUBJECT_FORWARD);
-#ifdef USE_LEGACY_FORWARD
- } else if (str_starts_with(title, str_legacy_forward)) {
- title += strlen(str_legacy_forward);
- ptype = _set_ptype(ptype, SUBJECT_FORWARD);
-#endif
- } else {
- ptype = _set_ptype(ptype, SUBJECT_NORMAL);
- break;
- }
- if (*title == ' ')
- title ++;
- } while (1);
- return title;
-}
-
-const char *
-subject(const char *title) {
- return subject_ex(title, NULL);
-}
diff --git a/common/sys/big5_gen.py b/common/sys/big5_gen.py
index 1abe44c5..0119db84 100755
--- a/common/sys/big5_gen.py
+++ b/common/sys/big5_gen.py
@@ -1,7 +1,6 @@
#!/usr/bin/env python
# Usage: ./big5_gen.py > big5.c
-from __future__ import print_function
import sys
import tarfile
@@ -13,37 +12,37 @@ AMBCJK_FILE = BIG5_DATA.extractfile('ambcjk.big5.txt')
# b2u
sys.stderr.write('Generating B2U data...\n')
b2u = B2U_FILE.readlines()
-b2u = [line.strip().split(b' ')
+b2u = [line.strip().split(' ')
for line in b2u
- if line.strip().startswith(b'0x')]
+ if line.strip().startswith('0x')]
b2u = dict((int(b, 0), int(u, 0)) for (b, u) in b2u)
-print("""#include <stdint.h>
+print """#include <stdint.h>
extern const uint16_t b2u_table[];
extern const uint16_t u2b_table[];
extern const uint8_t b2u_ambiguous_width[];
-""")
-print("const uint16_t b2u_table[0x10000] = {")
+"""
+print "const uint16_t b2u_table[0x10000] = {"
for i in range(0x10000):
- print( '0x%04x,' % (i if i not in b2u else b2u[i]), end=' ')
+ print '0x%04x,' % (i if i not in b2u else b2u[i]),
if i % 10 == 9:
- print('')
-print("};\n")
+ print ''
+print "};\n"
# u2b
sys.stderr.write('Generating U2B data...\n')
u2b = U2B_FILE.readlines()
-u2b = [line.strip().split()
+u2b = [line.strip().split(' ')
for line in u2b
- if line.strip().startswith(b'0x')]
+ if line.strip().startswith('0x')]
u2b = dict((int(u, 0), int(b, 0)) for (b, u) in u2b)
-print("const uint16_t u2b_table[0x10000] = {")
+print "const uint16_t u2b_table[0x10000] = {"
for i in range(0x10000):
- print( '0x%04x,' % (i if i not in u2b else u2b[i]), end=' ')
+ print '0x%04x,' % (i if i not in u2b else u2b[i]),
if i % 10 == 9:
- print('')
-print("};\n")
+ print ''
+print "};\n"
# ambiguous cjk width
sys.stderr.write('Generating AMBCJK data...\n')
@@ -53,14 +52,14 @@ for entry in ambcjk_data:
(a, b) = entry.strip().split()
a = int(a, 0)
b = int(b, 0)
- ambcjk = ambcjk + list( range(a, b+1) )
-print("const uint8_t b2u_ambiguous_width[0x10000] = {")
+ ambcjk = ambcjk + range(a, b+1)
+print "const uint8_t b2u_ambiguous_width[0x10000] = {"
for i in range(0, 0x10000):
if i in b2u and b2u[i] in ambcjk:
- print("1,",end=' '),
+ print "1,",
else:
- print("0,",end=' '),
+ print "0,",
if i % 25 == 24:
- print('')
+ print ''
-print("};\n")
+print "};\n"
diff --git a/common/sys/record.c b/common/sys/record.c
index b38f8ed5..9bc1f452 100644
--- a/common/sys/record.c
+++ b/common/sys/record.c
@@ -332,44 +332,3 @@ int bsearch_record(const char *fpath, const void *key,
close(fd);
return found ? (found - addr) / size : -1;
}
-
-// Find the first record that is greater than key.
-//
-// Number of records is returned in *num. The found record is copied to buffer
-// if 0 <= retval < *num. Returns -1 on error.
-ssize_t upper_bound_record(const char *fpath, const void *key,
- int (*compar)(const void *item1, const void *item2),
- size_t size, void *buffer, size_t *num) {
- int fd;
- size_t sz = dashs(fpath);
- void *addr = NULL;
-
- if((fd = open(fpath, O_RDONLY, 0)) < 0)
- return -1;
- addr = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
- if (!addr) {
- close(fd);
- return -1;
- }
-
- const uint8_t *left = (const uint8_t *) addr;
- size_t count = sz / size;
- *num = count;
- while (count > 0) {
- size_t i = count >> 1;
- const uint8_t *mid = left + i * size;
- if (compar(key, mid) < 0)
- count = i;
- else {
- left = mid + size;
- count -= i + 1;
- }
- }
- size_t offset = left - (const uint8_t *)addr;
- if (offset < sz)
- memcpy(buffer, left, size);
-
- munmap(addr, sz);
- close(fd);
- return offset / size;
-}
diff --git a/common/sys/string.c b/common/sys/string.c
index 96733a88..0a4d68de 100644
--- a/common/sys/string.c
+++ b/common/sys/string.c
@@ -471,12 +471,6 @@ DBCS_strncasecmp(const char *s1, const char *s2, size_t len) {
return 0;
}
-unsigned
-DBCS_StringHash(const char *s)
-{
- return fnv1a_32_dbcs_strcase(s, FNV1_32_INIT);
-}
-
/* ----------------------------------------------------- */
/* 字串檢查函數:英文、數字、檔名、E-mail address */
/* ----------------------------------------------------- */
diff --git a/common/sys/thttp.c b/common/sys/thttp.c
index 73c5115a..926ca250 100644
--- a/common/sys/thttp.c
+++ b/common/sys/thttp.c
@@ -33,7 +33,7 @@ static int request(THTTP *t, const char *meth, const char *uri,
write_string(t, meth);
write_string(t, " ");
write_string(t, uri);
- write_string(t, " HTTP/1.0\r\n");
+ write_string(t, " HTTP/1.1\r\n");
va_list va;
va_start(va, headers);
@@ -136,7 +136,7 @@ void thttp_set_io_timeout(THTTP *t, int microsecond) {
t->timeout_read = microsecond;
}
-int thttp_get(THTTP *t, const char *addr, const char *uri, const char *host) {
+int thttp_get(THTTP *t, const char *addr, const char *uri, const char *host, const char *bearer) {
t->fd = toconnect3(addr, 0, t->timeout_connect);
if (t->fd < 0)
return -1;
@@ -152,11 +152,12 @@ int thttp_get(THTTP *t, const char *addr, const char *uri, const char *host) {
t->read = _read;
t->write = _write;
- request(t, "GET", uri, "ssss",
+ request(t, "GET", uri, "sssss",
"Accept", "text/plain",
"Host", host,
"Connection", "close",
- "User-Agent", "pttbbs");
+ "User-Agent", "Mozilla/5.0 (BRsBBS) THTTP/1.1",
+ "Authorization", bearer);
if (t->failed || read_response(t) < 0) {
close(t->fd);
diff --git a/common/sys/utf8.c b/common/sys/utf8.c
index 947d6bc8..795f8c8f 100644
--- a/common/sys/utf8.c
+++ b/common/sys/utf8.c
@@ -26,7 +26,7 @@ int ucs2utf(uint16_t ucs2, uint8_t *utf8) {
}
}
-int utf2ucs(const uint8_t *utf8, uint16_t *pucs) {
+int utf2ucs(uint8_t *utf8, uint16_t *pucs) {
uint16_t c;
c = *utf8++;
if ((c & 0x80) == 0) {
diff --git a/daemon/boardd/bbs++.cpp b/daemon/boardd/bbs++.cpp
index f15a1e21..7dc2624c 100644
--- a/daemon/boardd/bbs++.cpp
+++ b/daemon/boardd/bbs++.cpp
@@ -3,10 +3,8 @@
#include <vector>
#include "daemon/boardd/bbs++.hpp"
extern "C" {
-#include <string.h>
#include "var.h"
#include "cmbbs.h"
-#include "pttstruct.h"
#include "daemon/boardd/boardd.h"
}
@@ -85,36 +83,4 @@ std::vector<bid_t> Children(bid_t bid) {
return bids;
}
-boost::optional<std::string> Search(bid_t bid, const std::string &base_name,
- const fileheader_predicate_t &pred) {
- auto bp = Get(bid);
- if (!bp) {
- return {};
- }
-
- char genbuf[PATHLEN];
- bool first_select = strncmp(base_name.c_str(), "SR.", 3) != 0;
- select_read_name(genbuf, sizeof(genbuf),
- first_select ? nullptr : base_name.c_str(), &pred);
-
- const size_t kMaxLen = 64; // sizeof(currdirect)
- std::string src_direct = paths::bfile(bp.value()->brdname, base_name);
- std::string dst_direct = paths::bfile(bp.value()->brdname, genbuf);
- if (dst_direct.size() >= kMaxLen) {
- return {};
- }
-
- int force_full_build = pred.mode & (RS_MARK | RS_RECOMMEND | RS_SOLVED);
- time4_t resume_from;
- int count;
- if (select_read_should_build(dst_direct.c_str(), bid, &resume_from, &count) &&
- (count = select_read_build(
- src_direct.c_str(), dst_direct.c_str(), !first_select,
- force_full_build ? 0 : resume_from, count,
- match_fileheader_predicate, (void *)&pred)) < 0) {
- return {};
- }
- return std::string(genbuf);
-}
-
} // namespace boards
diff --git a/daemon/boardd/bbs++.hpp b/daemon/boardd/bbs++.hpp
index 0dde994a..9b096c45 100644
--- a/daemon/boardd/bbs++.hpp
+++ b/daemon/boardd/bbs++.hpp
@@ -4,9 +4,8 @@
#include <vector>
#include <boost/optional.hpp>
extern "C" {
-#include "cmbbs.h"
-#include "pttstruct.h"
#include "daemon/boardd/boardd.h"
+#include "pttstruct.h"
}
namespace paths {
@@ -33,12 +32,13 @@ size_t Get(const std::string &fn, ssize_t offset, ssize_t length,
std::vector<T> *dst) {
dst->clear();
ssize_t total = Count<T>(fn);
- if (total <= 0)
+ if (total <= 0) {
return 0;
- if (offset < 0)
+ }
+ offset %= total;
+ if (offset < 0) {
offset += total;
- if (offset < 0)
- offset = 0;
+ }
ssize_t start_offset = offset;
int fd = -1;
while (length < 0 || length-- > 0) {
@@ -73,10 +73,6 @@ boost::optional<bid_t> Resolve(const std::string &name);
// Resolve the children of the board. It may modify SHM.
std::vector<bid_t> Children(bid_t bid);
-// Search by predicate.
-boost::optional<std::string> Search(bid_t bid, const std::string &base_name,
- const fileheader_predicate_t &pred);
-
} // namespace boards
#endif
diff --git a/daemon/boardd/board.proto b/daemon/boardd/board.proto
index c57ee219..324a1861 100644
--- a/daemon/boardd/board.proto
+++ b/daemon/boardd/board.proto
@@ -12,7 +12,6 @@ service BoardService {
rpc List (ListRequest) returns (ListReply) {}
rpc Hotboard (HotboardRequest) returns (HotboardReply) {}
rpc Content (ContentRequest) returns (ContentReply) {}
- rpc Search (SearchRequest) returns (SearchReply) {}
}
message BoardRequest {
@@ -104,31 +103,3 @@ message Content {
int64 length = 4;
int64 total_length = 5;
}
-
-message SearchFilter {
- enum Type {
- TYPE_UNKNOWN = 0;
- TYPE_EXACT_TITLE = 1;
- TYPE_TITLE = 2;
- TYPE_AUTHOR = 3;
- TYPE_RECOMMEND = 4;
- TYPE_MONEY = 5;
- TYPE_MARK = 6;
- TYPE_SOLVED = 7;
- }
- Type type = 1;
- int64 number_data = 2;
- string string_data = 3;
-}
-
-message SearchRequest {
- BoardRef ref = 1;
- repeated SearchFilter filter = 2;
- int32 offset = 3;
- int32 length = 4;
-}
-
-message SearchReply {
- repeated Post posts = 1;
- int32 total_posts = 2;
-}
diff --git a/daemon/boardd/board_service_impl.cpp b/daemon/boardd/board_service_impl.cpp
index 6cc13c9e..a62a7715 100644
--- a/daemon/boardd/board_service_impl.cpp
+++ b/daemon/boardd/board_service_impl.cpp
@@ -32,9 +32,6 @@ using pttbbs::api::ListReply;
using pttbbs::api::ListRequest;
using pttbbs::api::PartialOptions;
using pttbbs::api::Post;
-using pttbbs::api::SearchFilter;
-using pttbbs::api::SearchReply;
-using pttbbs::api::SearchRequest;
namespace {
@@ -54,9 +51,6 @@ class BoardServiceImpl final : public pttbbs::api::BoardService::Service {
Status Content(ServerContext *context, const ContentRequest *req,
ContentReply *rep) override;
- Status Search(ServerContext *context, const SearchRequest *req,
- SearchReply *rep) override;
-
private:
DISABLE_COPY_AND_ASSIGN(BoardServiceImpl);
};
@@ -236,87 +230,6 @@ Status BoardServiceImpl::Content(ServerContext *context,
return Status::OK;
}
-void SetPredicateKeyword(fileheader_predicate_t *pred,
- const std::string &utf8_str) {
- strlcpy(pred->keyword, strings::u2b(utf8_str).c_str(), sizeof(pred->keyword));
-}
-
-Status SetPredicate(const SearchFilter &filter, fileheader_predicate_t *pred) {
- memset(pred, 0, sizeof(*pred));
- switch (filter.type()) {
- case SearchFilter::TYPE_EXACT_TITLE:
- pred->mode = RS_TITLE;
- SetPredicateKeyword(pred, filter.string_data());
- break;
-
- case SearchFilter::TYPE_TITLE:
- pred->mode = RS_KEYWORD;
- SetPredicateKeyword(pred, filter.string_data());
- break;
-
- case SearchFilter::TYPE_AUTHOR:
- pred->mode = RS_AUTHOR;
- SetPredicateKeyword(pred, filter.string_data());
- break;
-
- case SearchFilter::TYPE_RECOMMEND:
- pred->mode = RS_RECOMMEND;
- pred->recommend = filter.number_data();
- SetPredicateKeyword(pred, std::to_string(pred->recommend));
- break;
-
- case SearchFilter::TYPE_MONEY:
- pred->mode = RS_MONEY;
- pred->money = filter.number_data();
- SetPredicateKeyword(pred, std::to_string(pred->money) + "M");
- break;
-
- case SearchFilter::TYPE_MARK:
- pred->mode = RS_MARK;
- break;
-
- case SearchFilter::TYPE_SOLVED:
- pred->mode = RS_SOLVED;
- break;
-
- default:
- return Status(StatusCode::UNIMPLEMENTED, "Unimplemented");
- }
- return Status::OK;
-}
-
-Status BoardServiceImpl::Search(ServerContext *context,
- const SearchRequest *req, SearchReply *rep) {
- int bid;
- const boardheader_t *bp;
- RETURN_ON_FAIL(ResolveRef(req->ref(), &bid, &bp));
-
- if (req->filter().empty()) {
- return Status(StatusCode::INVALID_ARGUMENT, "No search filters specified.");
- }
- std::string base_name = FN_DIR;
- for (const auto &filter : req->filter()) {
- fileheader_predicate_t pred;
- RETURN_ON_FAIL(SetPredicate(filter, &pred));
- auto dst_name = boards::Search(bid, base_name, pred);
- if (!dst_name) {
- return Status(StatusCode::UNKNOWN, "Search failed");
- }
- base_name = dst_name.value();
- }
-
- std::vector<fileheader_t> fhs;
- size_t offset = records::Get<fileheader_t>(
- paths::bfile(bp->brdname, base_name), req->offset(), req->length(), &fhs);
- for (auto &fh : fhs) {
- DBCS_safe_trim(fh.title);
- AsPost(offset++, fh).Swap(rep->add_posts());
- }
- rep->set_total_posts(
- records::Count<fileheader_t>(paths::bfile(bp->brdname, base_name)));
- return Status::OK;
-}
-
} // namespace
std::unique_ptr<BoardService::Service> CreateBoardService() {
diff --git a/daemon/boardd/boardc.cpp b/daemon/boardd/boardc.cpp
index 49510852..bcaad47d 100644
--- a/daemon/boardd/boardc.cpp
+++ b/daemon/boardd/boardc.cpp
@@ -23,8 +23,6 @@ using pttbbs::api::HotboardReply;
using pttbbs::api::HotboardRequest;
using pttbbs::api::ListReply;
using pttbbs::api::ListRequest;
-using pttbbs::api::SearchReply;
-using pttbbs::api::SearchRequest;
template <class Service, class Request, class Reply>
struct MakeRPC {
@@ -70,8 +68,6 @@ int main(int argc, char *argv[]) {
{"Content",
MakeRPC<BoardService, ContentRequest, ContentReply>::BindMethod(
&BoardService::Stub::Content)},
- {"Search", MakeRPC<BoardService, SearchRequest, SearchReply>::BindMethod(
- &BoardService::Stub::Search)},
};
for (const auto &m : methods) {
if (m.first == FLAGS_method) {
diff --git a/daemon/boardd/strings.cpp b/daemon/boardd/strings.cpp
index 3ad0649c..fce66cf9 100644
--- a/daemon/boardd/strings.cpp
+++ b/daemon/boardd/strings.cpp
@@ -34,26 +34,4 @@ void b2u(std::string *utf8, const char *big5) {
}
}
-std::string u2b(const std::string &utf8) {
- return u2b(utf8.c_str());
-}
-
-std::string u2b(const char *utf8) {
- std::string big5;
- u2b(&big5, utf8);
- return big5;
-}
-
-void u2b(std::string *big5, const char *utf8) {
- const uint8_t *p = reinterpret_cast<const uint8_t *>(utf8);
- while (*p) {
- uint16_t ucs;
- p += utf2ucs(p, &ucs);
- ucs = u2b_table[ucs];
- if (ucs >> 8)
- big5->push_back(ucs >> 8);
- big5->push_back(ucs & 0xFF);
- }
-}
-
} // namespace strings
diff --git a/daemon/boardd/strings.hpp b/daemon/boardd/strings.hpp
index f60537c4..1bb524a6 100644
--- a/daemon/boardd/strings.hpp
+++ b/daemon/boardd/strings.hpp
@@ -8,10 +8,6 @@ std::string b2u(const std::string &big5);
std::string b2u(const char *big5);
void b2u(std::string *utf8, const char *big5);
-std::string u2b(const std::string &utf8);
-std::string u2b(const char *utf8);
-void u2b(std::string *big5, const char *utf8);
-
} // namespace strings
#endif
diff --git a/daemon/logind/logind.c b/daemon/logind/logind.c
index 156f7168..17cef2c3 100644
--- a/daemon/logind/logind.c
+++ b/daemon/logind/logind.c
@@ -771,19 +771,19 @@ DEBUG_IO(int fd, const char *msg) {
#endif
#ifdef STR_GUEST
-# define MSG_GUEST ",或以 " STR_GUEST " 參觀"
+# define MSG_GUEST ""
#else
# define MSG_GUEST ""
#endif
#ifdef STR_REGNEW
-# define MSG_REGNEW ",或以 new 註冊"
+# define MSG_REGNEW "或以 new 註冊"
#else
# define MSG_REGNEW
#endif
#define BOTTOM_YX "24;1"
-#define LOGIN_PROMPT_MSG ANSI_RESET "請輸入代號" MSG_GUEST MSG_REGNEW ": " ANSI_REVERSE
+#define LOGIN_PROMPT_MSG ANSI_RESET "請輸入帳號" MSG_GUEST MSG_REGNEW ": " ANSI_REVERSE
#define LOGIN_PROMPT_YX "21;1"
#define LOGIN_PROMPT_END ANSI_RESET
#define PASSWD_PROMPT_MSG ANSI_RESET MSG_PASSWD
diff --git a/include/cmbbs.h b/include/cmbbs.h
index 450bc14b..fe698fd2 100644
--- a/include/cmbbs.h
+++ b/include/cmbbs.h
@@ -28,8 +28,6 @@ const char* money_level(int money);
/* string.c */
void obfuscate_ipstr(char *s);
bool is_valid_brdname(const char *brdname);
-const char *subject_ex(const char *title, int *ptype);
-const char *subject(const char *title);
/* time.c */
const char *Now(void); // m3 flavor time string
@@ -119,26 +117,5 @@ char*genpasswd (char *pw);
int substitute_fileheader(const char *dir_path, const void *srcptr, const void *destptr, int id);
int delete_fileheader(const char *dir_path, const void *rptr, int id);
-/* search.c */
-typedef struct fileheader_predicate_t {
- int mode;
- char keyword[TTLEN + 1];
- int recommend;
- int money;
-} fileheader_predicate_t;
-
-void select_read_name(char *buf, size_t size, const char *base,
- const fileheader_predicate_t *pred);
-
-int match_fileheader_predicate(const fileheader_t *fh, void *arg);
-
-int select_read_build(const char *src_direct, const char *dst_direct,
- int src_direct_has_reference, time4_t resume_from,
- int dst_count,
- int (*match)(const fileheader_t *fh, void *arg),
- void *arg);
-
-int select_read_should_build(const char *dst_direct, int bid,
- time4_t *resume_from, int *count);
#endif
diff --git a/include/cmsys.h b/include/cmsys.h
index 4ca17a97..dde25d83 100644
--- a/include/cmsys.h
+++ b/include/cmsys.h
@@ -122,7 +122,6 @@ char * DBCS_strcasestr(const char* pool, const char *ptr);
int DBCS_strncasecmp(const char *s1, const char *s2, size_t len);
#define HAVE_DBCS_STRCASESTR
#define HAVE_DBCS_STRNCASECMP
-unsigned DBCS_StringHash(const char *s);
size_t str_iconv(
const char *fromcode, /* charset of source string */
const char *tocode, /* charset of destination string */
@@ -180,9 +179,6 @@ int delete_record2(const char *fpath, const void *rptr, size_t size,
int bsearch_record(const char *fpath, const void *key,
int (*compar)(const void *item1, const void *item2),
size_t size, void *buffer);
-ssize_t upper_bound_record(const char *fpath, const void *key,
- int (*compar)(const void *item1, const void *item2),
- size_t size, void *buffer, size_t *num);
/* vector.c */
struct Vector {
@@ -310,7 +306,7 @@ ssize_t telnet_process (TelnetCtx *ctx, unsigned char *buf, ssize_t size)
/* utf8.c */
int ucs2utf(uint16_t ucs2, uint8_t *utf8);
-int utf2ucs(const uint8_t *utf8, uint16_t *pucs);
+int utf2ucs(uint8_t *utf8, uint16_t *pucs);
/* big5.c */
extern const uint16_t b2u_table[];
diff --git a/include/perm.h b/include/perm.h
index f40c5d50..7693a547 100644
--- a/include/perm.h
+++ b/include/perm.h
@@ -42,9 +42,10 @@
#define NUMPERMS 32
#define PERM_DEFAULT (PERM_BASIC | PERM_CHAT | PERM_PAGE )
-#define PERM_MANAGER (PERM_ACCTREG | PERM_ACTION | PERM_PAINT)
-#define PERM_ADMIN (PERM_ACCOUNTS | PERM_BOARD | PERM_SYSOP | \
- PERM_SYSSUBOP | PERM_SYSSUPERSUBOP | PERM_MANAGER)
+#define PERM_MANAGER (PERM_ACCTREG | PERM_ACTION | PERM_PAINT | PERM_PRG)
+#define PERM_ADMIN (PERM_SYSOP | PERM_ACCOUNTS | PERM_BOARD | \
+ PERM_VIEWSYSOP | PERM_ACCTREG|PERM_POLICE_MAN | \
+ PERM_BBSADM | PERM_SYSSUBOP | PERM_SYSSUPERSUBOP | PERM_MANAGER)
#define PERM_ALLBOARD (PERM_SYSOP | PERM_BOARD)
#define PERM_LOGINCLOAK (PERM_SYSOP | PERM_ACCOUNTS)
#define PERM_SEEULEVELS (PERM_SYSOP)
diff --git a/include/proto.h b/include/proto.h
index 7eea2f17..74ff2008 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -657,6 +657,7 @@ int str_checksum(const char *str);
int userid_is_BM(const char *userid, const char *list);
int is_uBM(const char *list, const char *id);
time4_t gettime(int line, time4_t dt, const char* head);
+unsigned DBCS_StringHash(const char *s);
// vgets/getdata utilities
int getdata(int line, int col, const char *prompt, char *buf, int len, int echo);
int getdata_str(int line, int col, const char *prompt, char *buf, int len, int echo, const char *defaultstr);
@@ -861,6 +862,5 @@ void pwcuInitGuestInfo (void);
int pwcuInitAdminPerm (void);
int verify_captcha(const char *reason);
-const char *remote_captcha();
#endif
diff --git a/include/pttstruct.h b/include/pttstruct.h
index 002f5e7e..8a94c87f 100644
--- a/include/pttstruct.h
+++ b/include/pttstruct.h
@@ -302,14 +302,6 @@ typedef struct fileheader_t { /* 128 bytes */
#define FILE_VOTE 0x40 /* for vote, in non-announce */
#define FILE_ANONYMOUS 0x80 /* anonymous file */
-/* TODO multi.money is a mess.
- * please help verify and finish these.
- */
-/* modes to invalid multi.money */
-#define INVALIDMONEY_MODES (FILE_ANONYMOUS | FILE_BOTTOM | FILE_DIGEST | \
- FILE_VOTE | FILE_BID)
-
-
#define STRLEN 80 /* Length of most string data */
#define FAVMAX 1024 /* Max boards of Myfavorite */
diff --git a/include/thttp.h b/include/thttp.h
index 29b9b6ff..d5797db9 100644
--- a/include/thttp.h
+++ b/include/thttp.h
@@ -19,7 +19,7 @@ int thttp_init(THTTP *t);
int thttp_cleanup(THTTP *t);
void thttp_set_connect_timeout(THTTP *t, int microsecond);
void thttp_set_io_timeout(THTTP *t, int microsecond);
-int thttp_get(THTTP *t, const char *addr, const char *uri, const char *host);
+int thttp_get(THTTP *t, const char *addr, const char *uri, const char *host, const char *bearer);
int thttp_code(THTTP *t);
void *thttp_get_content(THTTP *t);
int thttp_content_length(THTTP *t);
diff --git a/include/uflags.h b/include/uflags.h
index 35edfe33..bd916b3d 100644
--- a/include/uflags.h
+++ b/include/uflags.h
@@ -33,8 +33,15 @@
// #define UF_COUNTRY_??? 0x00800000 // reserved
#define UF_MENU_LIGHTBAR 0x01000000 // true to use lightbar-based menu
#define UF_CURSOR_ASCII 0x02000000 // true to enable ASCII-safe cursor.
-// #define UF_??? 0x04000000 // reserved
-// #define UF_??? 0x08000000 // reserved
+
+#ifdef USE_NOTILOGIN
+#define UF_NOTIFY_LOGIN 0x04000000 // notify new login activity to ibunny.
+#endif
+
+#ifdef USE_2FALOGIN
+#define UF_TWOFA_LOGIN 0x08000000 // two factor authentication.
+#endif
+
// #define UF_??? 0x10000000 // reserved
// #define UF_??? 0x20000000 // reserved
// #define UF_??? 0x40000000 // reserved
diff --git a/mbbsd/Makefile b/mbbsd/Makefile
index 2fcf708d..56d4fb8c 100644
--- a/mbbsd/Makefile
+++ b/mbbsd/Makefile
@@ -10,15 +10,15 @@ SRCROOT= ..
PROG= mbbsd
COREOBJS = bbs.o announce.o read.o board.o brc.o mail.o record.o fav.o
ABUSEOBJS = captcha.o
-ACCOBJS = user.o acl.o register.o passwd.o emaildb.o
+ACCOBJS = user.o acl.o register.o passwd.o emaildb.o twofa.o
NETOBJS = mbbsd.o io.o term.o telnet.o nios.o
TALKOBJS = friend.o talk.o ccw.o
-UTILOBJS = stuff.o kaede.o convert.o name.o syspost.o cache.o cal.o
+UTILOBJS = stuff.o kaede.o convert.o name.o syspost.o cache.o cal.o boardtax.o
UIOBJS = menu.o vtuikit.o psb.o
PAGEROBJS= more.o pmore.o
PLUGOBJS = ordersong.o angel.o timecap.o
CHESSOBJS= chess.o chc.o chc_tab.o ch_go.o ch_gomo.o ch_dark.o ch_reversi.o ch_conn6.o
-GAMEOBJS = chicken.o gamble.o
+GAMEOBJS = chicken.o gamble.o mission.o
OBJS:= admin.o assess.o edit.o xyz.o var.o vote.o voteboard.o comments.o \
$(COREOBJS) $(ABUSEOBJS) $(ACCOBJS) $(NETOBJS) $(TALKOBJS) $(UTILOBJS) \
$(UIOBJS) $(PAGEROBJS) $(PLUGOBJS) \
diff --git a/mbbsd/admin.c b/mbbsd/admin.c
index 8e9d7cb5..aa363304 100644
--- a/mbbsd/admin.c
+++ b/mbbsd/admin.c
@@ -261,7 +261,6 @@ search_key_user(const char *passwdfile, int mode)
uf->type = 1;
uf->filter = userec_filter_keyword_filter;
uf->desc = userec_filter_keyword_desc;
- uf->keyword.field = 1;
getdata(0, 0, "請輸入id :", uf->keyword.key, sizeof(uf->keyword.key),
DOECHO);
num_ufs++;
@@ -718,7 +717,7 @@ m_mod_board(char *bname)
else {
strlcpy(bname, bh.brdname, sizeof(bh.brdname));
snprintf(genbuf, sizeof(genbuf),
- "/bin/tar zcvf tmp/board_%s.tgz boards/%c/%s man/boards/%c/%s >/dev/null 2>&1;"
+ "/bin/tar zcvf backup/board_%s.tgz boards/%c/%s man/boards/%c/%s >/dev/null 2>&1;"
"/bin/rm -fr boards/%c/%s man/boards/%c/%s",
bname, bname[0], bname, bname[0],
bname, bname[0], bname, bname[0], bname);
@@ -1271,7 +1270,8 @@ give_money(void)
fclose(fp2);
sprintf(buf, "%s 紅包機: %s", cuser.userid, reason);
- post_file(BN_SECURITY, buf, "etc/givemoney.log", "[紅包機報告]");
+ post_file(BN_SECURITY, buf, "etc/givemoney.log", "[發錢報告]");
+ post_file(BN_FINANC, buf, "etc/givemoney.log", "[發錢報告]");
pressanykey();
return FULLUPDATE;
}
diff --git a/mbbsd/bbs.c b/mbbsd/bbs.c
index 1c4e0843..f855772e 100644
--- a/mbbsd/bbs.c
+++ b/mbbsd/bbs.c
@@ -37,6 +37,13 @@ enum {
RECTYPE_DEFAULT = RECTYPE_GOOD, // match traditional user behavior
};
+/* TODO multi.money is a mess.
+ * please help verify and finish these.
+ */
+/* modes to invalid multi.money */
+#define INVALIDMONEY_MODES (FILE_ANONYMOUS | FILE_BOTTOM | FILE_DIGEST | \
+ FILE_VOTE | FILE_BID)
+
/**
* Test if the fhdr looks like really belong to user
*/
@@ -326,14 +333,53 @@ set_board(void)
boardheader_t *bp;
bp = getbcache(currbid);
- if (!HasBoardPerm(bp)) {
+ if( !HasBoardPerm(bp) ){
vmsg("access control violation, exit");
u_exit("access control violation!");
exit(-1);
}
- if (BoardPermNeedsSysopOverride(bp))
- vmsg("進入未經授權看板");
+ /*站長進入隱板警訊系統*/
+ if (BoardPermNeedsSysopOverride(bp)){
+ char genbuf[3];
+ clear();
+ move(b_lines-3, 0); clrtobot();
+ outs("\n" ANSI_COLOR(1;31) "注意: "ANSI_COLOR(1)"您將使用站長權限進入隱板,若無合理理由請勿任意進入隱板。" ANSI_RESET);
+ getdata(b_lines - 1, 0, "您確定要繼續操作?[y/N] ",
+ genbuf, 3, LCECHO);
+ if (genbuf[0] != 'y') {
+ vmsg("顧及使用者的隱私,請您重新登入;下次請您看清楚再進入。");
+ sleep(1);
+ abort_bbs(0);
+ } else {
+ FILE *fp, *fp2;
+ char reason[100];
+ char * bmStr = bp->BM;
+ char * bmArr;
+ int i;
+ struct tm ptime;
+ char *myweek = "日一二三四五六";
+ localtime4_r(&now, &ptime);
+ i = ptime.tm_wday << 1;
+
+ clear();
+
+ unlink("etc/intoHide.log");
+ fp2 = fopen("etc/intoHide.log", "w");
+
+ getdata(0, 0, "進入隱藏看板,請輸入正當理由:", reason, 40, DOECHO);
+ fprintf(fp2,"\n國家安全局通知\n站長%s進入您的隱藏看板:%s,\n時間是%03d/%02d/%02d (%c%c) %02d:%02d:%02d,\n理由是%s\n如果您認為該站長的行為不當請立即至總統室(看板SYSOP)提報。\n若無其他異況可直接略過本通知。", cuser.userid, bp->brdname,ptime.tm_year - 11, ptime.tm_mon + 1, ptime.tm_mday, myweek[i], myweek[i + 1],ptime.tm_hour, ptime.tm_min, ptime.tm_sec, reason);
+ fclose(fp2);
+ if(does_board_have_public_bm(bp)) {
+ bmArr = strtok(bmStr,"/");
+ while(bmArr != NULL){
+ mail_id(bp->BM, "[通知] 有站長進入您的看版", "etc/intoHide.log", "[國家安全局]");
+ bmArr = strtok(NULL,"/");
+ }
+ }
+ post_file(BN_SECURITY, "[通知] 有站長進入隱藏看版", "etc/intoHide.log", "[國家安全局]");
+ }
+ }
board_note_time = &bp->bupdate;
@@ -383,21 +429,11 @@ set_board(void)
#ifdef QUERY_ARTICLE_URL
-
-static int
-IsBoardForWeb(const boardheader_t *bp) {
- if (!bp || !IS_OPENBRD(bp))
- return 0;
- if (strcmp(bp->brdname, BN_ALLPOST) == 0)
- return 0;
- return 1;
-}
-
static int
GetWebUrl(const boardheader_t *bp, const fileheader_t *fhdr, char *buf,
size_t szbuf)
{
- const char *folder = bp->brdname, *fn = fhdr->filename, *ext = ".html";
+ const char *folder = bp->brdname, *fn = fhdr->filename;
#ifdef USE_AID_URL
char aidc[32] = "";
@@ -407,14 +443,13 @@ GetWebUrl(const boardheader_t *bp, const fileheader_t *fhdr, char *buf,
aidu2aidc(aidc, aidu);
fn = aidc;
- ext = "";
#endif
if (!fhdr || !*fhdr->filename || *fhdr->filename == 'L' ||
*fhdr->filename == '.')
return 0;
- return snprintf(buf, szbuf, URL_PREFIX "/%s/%s%s", folder, fn, ext);
+ return snprintf(buf, szbuf, URL_PREFIX "/%s", fn);
}
#endif // QUERY_ARTICLE_URL
@@ -1301,20 +1336,6 @@ do_post_article(int edflags)
#endif
clear();
-#ifdef USE_POST_CAPTCHA_FOR_NOREG
-#ifndef USE_REMOTE_CAPTCHA
-#error "To use USE_POST_CAPTCHA_FOR_NOREG, you must also set USE_REMOTE_CAPTCHA"
-#endif
- if (!HasUserPerm(PERM_LOGINOK)) {
- const char *errmsg = remote_captcha();
- if (errmsg) {
- vmsg(errmsg);
- return FULLUPDATE;
- }
- clear();
- }
-#endif
-
setbfile(genbuf, currboard, FN_POST_NOTE);
if (more(genbuf, NA) == -1) {
@@ -1484,13 +1505,11 @@ do_post_article(int edflags)
stampfile_u(fpath, &postfile);
#ifdef QUERY_ARTICLE_URL
- if (IsBoardForWeb(bp)) {
- char url[STRLEN];
- if (GetWebUrl(bp, &postfile, url, sizeof(url))) {
- log_filef(genbuf, LOG_CREAT,
- "※ " URL_DISPLAYNAME ": %s\n", url);
- }
- }
+ char url[STRLEN];
+ if (GetWebUrl(bp, &postfile, url, sizeof(url))) {
+ log_filef(genbuf, LOG_CREAT,
+ "※ " URL_DISPLAYNAME ": %s\n", url);
+ }
#endif
if (append_record(buf, &postfile, sizeof(postfile)) == -1)
@@ -1515,40 +1534,14 @@ do_post_article(int edflags)
if (IS_OPENBRD(bp)) {
if (cuser.numlogindays < NEWIDPOST_LIMIT_DAYS)
do_crosspost(BN_NEWIDPOST, &postfile, fpath);
-
- if (currbrdattr & BRD_HIDE)
- do_crosspost(BN_ALLHIDPOST, &postfile, fpath);
- else {
- do_crosspost(BN_ALLPOST, &postfile, fpath);
- }
}
outs("順利貼出佈告,");
-
- // Freeboard/BRD_NOCREDIT check was already done.
- if (!ifuseanony)
- {
- if (money > 0)
- {
- pay(-money, "%s 看板發文稿酬: %s", currboard, postfile.title);
- pwcuIncNumPost();
- prints("這是您的第 %d 篇有效文章,獲得稿酬 %d "
+ pay(-money, "%s 看板發文稿酬: %s", currboard, postfile.title);
+ pwcuIncNumPost();
+ prints("這是您的第 %d 篇有效文章,獲得稿酬 %d "
MONEYNAME "\n", cuser.numposts, money);
- prints("\n (若之後自行或被板主刪文"
+ prints("\n (若之後自行或被板主刪文"
"則此次獲得的有效文章數及稿酬可能會被回收)\n\n");
- } else {
-#ifdef USE_HIDDEN_BOARD_NOCREDIT
- if (currbrdattr & BRD_HIDE)
- outs("由於本看板為隱板,為避免遭濫用,發文無任何獎勵。");
- else
-#endif
- // no money, no record.
- outs("本篇文章不列入記錄,敬請包涵。");
- }
- }
- else
- {
- outs("不列入記錄,敬請包涵。");
- }
clrtobot();
/* 回應到原作者信箱 */
@@ -2037,7 +2030,7 @@ forward_post(int ent GCC_UNUSED, fileheader_t * fhdr, const char *direct) {
if (currbid) {
char buf[STRLEN];
const boardheader_t *bp = getbcache(currbid);
- if (bp && IsBoardForWeb(bp) &&
+ if (bp &&
GetWebUrl(bp, fhdr, buf, sizeof(buf))) {
move(b_lines - 4, 0); clrtobot();
prints("\n" URL_DISPLAYNAME ": " ANSI_COLOR(1)
@@ -2085,7 +2078,7 @@ cross_post(int ent, fileheader_t * fhdr, const char *direct)
if (violatecp++ >= MAX_CROSSNUM)
return DONOTHING;
}
-
+
if (!HasUserPerm(PERM_LOGINOK)) {
vmsg("您無轉錄權限。");
return FULLUPDATE;
@@ -2166,7 +2159,7 @@ cross_post(int ent, fileheader_t * fhdr, const char *direct)
// 反正本來就只是想解決「不小心」或是「假裝不小心」用到的情形。
// tn_safe_strip_board(xtitle, xboard);
- getdata(2, 0, "(S/L)發文 (Q)取消?[Q] ", genbuf, 3, LCECHO);
+ getdata(2, 0, "(S)存檔 (Q)取消?[Q] ", genbuf, 3, LCECHO);
if (genbuf[0] != 'l' && genbuf[0] != 's')
return FULLUPDATE;
@@ -2837,7 +2830,7 @@ recommend(int ent, fileheader_t * fhdr, const char *direct)
#ifndef DEBUG
if (get_board_restriction_reason(currbid, sizeof(msg), msg))
{
- vmsgf("未達看板發文限制: %s", msg);
+ vmsgf("未達看板發文限制 %s", msg);
return FULLUPDATE;
}
#endif
@@ -2878,14 +2871,14 @@ recommend(int ent, fileheader_t * fhdr, const char *direct)
setdirpath(path, direct, fhdr->filename);
size = dashs(path);
if (size > 5*1024*1024) {
- vmsg("檔案太大, 無法繼續推文, 請另撰文發表");
+ vmsg("檔案太大,無法繼續推文,請另撰文發表");
return FULLUPDATE;
}
if (size > 100*1024) {
int d = 10 - (now - lastrecommend);
if (d > 0) {
- vmsgf("本文已過長, 禁止快速連續推文, 請再等 %d 秒", d);
+ vmsgf("本文已過長,禁止快速連續推文,請再等 %d 秒", d);
return FULLUPDATE;
}
}
@@ -2899,33 +2892,8 @@ recommend(int ent, fileheader_t * fhdr, const char *direct)
type = RECTYPE_GOOD;
- // why "recommend == 0" here?
- // some users are complaining that they like to fxck up system
- // with lots of recommend one-line text.
- // since we don't support recognizing update of recommends now,
- // they tend to use the counter to identify whether an arcitle
- // has new recommends or not.
- // so, make them happy here.
-#ifndef OLDRECOMMEND
- // no matter it is first time or not.
- if (is_file_owner(fhdr, &cuser))
-#else
- // old format is one way counter, so let's relax.
- if (fhdr->recommend == 0 && is_file_owner(fhdr, &cuser))
-#endif
- {
- // owner recommend
- type = RECTYPE_ARROW;
- move(ymsg--, 0); clrtoeol();
-#ifndef OLDRECOMMEND
- outs("作者本人, 使用 → 加註方式\n");
-#else
- outs("作者本人首推, 使用 → 加註方式\n");
-#endif
-
- }
#ifndef DEBUG
- else if (!(currmode & MODE_BOARD) &&
+ if (/*!(currmode & MODE_BOARD) &&*/
(now - lastrecommend) < (
#if 0
/* i'm not sure whether this is better or not */
@@ -2937,7 +2905,7 @@ recommend(int ent, fileheader_t * fhdr, const char *direct)
// too close
type = RECTYPE_ARROW;
move(ymsg--, 0); clrtoeol();
- outs("時間太近, 使用 → 加註方式\n");
+ outs("時間太近,使用 → 加註方式\n");
}
#endif
@@ -3784,8 +3752,6 @@ view_postinfo(int ent GCC_UNUSED, const fileheader_t * fhdr,
if (!bp) {
prints("│\n");
- } else if (!IsBoardForWeb(bp)) {
- prints("│ 本看板目前不提供" URL_DISPLAYNAME " \n");
} else if (!GetWebUrl(bp, fhdr, url, sizeof(url))) {
prints("│ 本文章不提供" URL_DISPLAYNAME " \n");
} else {
diff --git a/mbbsd/board.c b/mbbsd/board.c
index 092094f3..d799843e 100644
--- a/mbbsd/board.c
+++ b/mbbsd/board.c
@@ -1313,10 +1313,10 @@ brdlist_foot(void)
{
vs_footer(" 選擇看板 ",
IS_LISTING_FAV() ?
- " (a)增加看板 (s)進入已知板名 (y)列出全部 (v/V)已讀/未讀" :
+ " (a)增加看板 (s)進入已知板名 "/*(y)列出全部 */"(v/V)已讀/未讀" :
IN_CLASS() ?
" (m)加入/移出最愛 (s)進入已知板名 (v/V)已讀/未讀 " :
- " (m)加入/移出最愛 (y)只列最愛 (v/V)已讀/未讀 ");
+ " (m)加入/移出最愛 "/*(y)只列最愛 */"(v/V)已讀/未讀 ");
}
@@ -1394,7 +1394,7 @@ show_brdlist(int head, int clsflag, int newflag)
} else {
// normal user. tell him what to do.
mvouts(3, 10,
- "--- 空目錄,請按 a 新增或用 y 列出全部看板後按 z 增刪 ---");
+ "--- 空目錄,請按 a 新增"/*或用 y 列出全部看板後按 z 增刪*/" ---");
}
return;
}
@@ -1510,7 +1510,7 @@ show_brdlist(int head, int clsflag, int newflag)
prints("%7s", "");
else
prints("%7d", head);
- prints("X%s", (ptr->myattr & NBRD_TAG) ? "D " : unread[0]);
+ prints(ANSI_COLOR(1;31)"X"ANSI_RESET"%s", (ptr->myattr & NBRD_TAG) ? "D " : unread[0]);
}
if (!IN_CLASSROOT()) {
@@ -2013,14 +2013,14 @@ choose_board(int newflag)
///////////////////////////////////////////////////////
// MyFav Functionality (Require PERM_BASIC)
///////////////////////////////////////////////////////
- case 'y':
+ /*case 'y':
if (HasFavEditPerm() && !(IN_CLASS())) {
if (get_current_fav() != NULL || !IS_LISTING_FAV()){
- yank_flag ^= 1; /* FAV <=> BRD */
+ yank_flag ^= 1;
}
brdnum = -1;
}
- break;
+ break;*/
case Ctrl('D'):
if (HasFavEditPerm()) {
if (vans("刪除所有標記[N]?") == 'y'){
@@ -2346,3 +2346,4 @@ New(void)
currstat = stat0;
return 0;
}
+
diff --git a/mbbsd/boardtax.c b/mbbsd/boardtax.c
new file mode 100644
index 00000000..96232bf6
--- /dev/null
+++ b/mbbsd/boardtax.c
@@ -0,0 +1,471 @@
+#include "bbs.h"
+
+#ifdef USE_BOARDTAX
+
+#define BOARD_TAX_DEADLINE (15)
+#define BOARD_TAX_DISDATE (25)
+
+#if defined(BOARD_TAX_DEADLINE) && !defined(BOARD_TAX_LATEPAYRATE)
+#define BOARD_TAX_LATEPAYRATE (25)
+#endif
+
+int
+getBoardTax(char *userid){
+ struct tm ptime;
+ FILE *fp;
+ char *ptr, *id, *mn;
+ char buf[200] = "";
+ int i, tax=0, money = 0, count=0;
+
+ fp = fopen("etc/boardtax.txt", "r+");
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (!(ptr = strchr(buf, ':')))
+ continue;
+ *ptr = '\0';
+ id = buf;
+ mn = ptr + 1;
+ money = atoi(mn);
+ if(strcmp(id, userid) == 0){
+ tax = money;
+ }
+ count++;
+ }
+ fclose(fp);
+
+ if(tax == 0){
+ return 0;
+ }else{
+ return tax;
+ }
+}
+
+char *
+isBrdTaxPaid(char *userid){
+ struct tm ptime;
+ FILE *fp;
+ char *ptr, *id, *mn;
+ char buf[200] = "", buf2[200] = "";
+ int i, tax=0, money = 0, count=0, paid=0;
+
+ localtime4_r(&now, &ptime);
+ i = ptime.tm_wday << 1;
+
+ snprintf(buf, sizeof(buf), "log/taxpaid/board_%03d_%02d.log", ptime.tm_year - 11, ptime.tm_mon + 1);
+ if(fp = fopen(buf, "r+")){
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (!(ptr = strchr(buf, ':')))
+ continue;
+ *ptr = '\0';
+ id = buf;
+ mn = ptr + 1;
+ if(strcmp(id, userid) == 0){
+ snprintf(buf2, sizeof(buf2), "%s", mn);
+ paid = 1;
+ }
+ count++;
+ }
+ fclose(fp);
+ }
+ if(paid == 0){
+ return 0;
+ }else if(paid == 1){
+ return buf2;
+ }
+ return 0;
+}
+
+int
+pay_board_tax(void)
+{
+ FILE *fp;
+ char *ptr, *id, *mn;
+ char buf[200] = "", buf2[200] = "", genbuf[3];
+ int i, money = 0, count=0;
+ int lateDay=0, latePay=0;
+ int tax=0, shouldpay=0, paid=0;
+ struct tm ptime;
+
+ localtime4_r(&now, &ptime);
+ i = ptime.tm_wday << 1;
+
+ if(isFileExist("etc/boardtax.txt") == false){
+ vmsg("尚未設定稅額檔案");
+ return 0;
+ }else{
+ vs_hdr2(" " BBSMNAME2 "銀行 ", " 看板稅繳納");
+ tax = getBoardTax(cuser.userid);
+
+ if(tax == 0){
+ vmsg("您不須繳稅");
+ return 0;
+ }else{
+ move(1,0);clrtobot();
+ snprintf(buf, sizeof(buf), "log/taxpaid/board_%03d_%02d.log", ptime.tm_year - 11, ptime.tm_mon + 1);
+ if(isBrdTaxPaid(cuser.userid) != 0){
+ vmsg("本期已繳款");
+ return 0;
+ }
+ outs("\n依據規定持有非公務看板的板主應於每月10日前支付當月看板稅,\n"
+ "未於規定期間內繳納看板將被暫時扣留於違規看板扣留區。\n"
+ "如果您的稅額有誤或有任何疑問請向土地管理局局長洽詢。\n\n"
+ "稅額計算公式:非教育類看板採累進稅額,第一個看板200、第二個300以此累加。\n"
+ " 教育類看板數採固定稅額,第一個看板免稅、第二個起每看板50。\n"
+ " 非教育類看板數=X;教育類看板數=Y\n"
+ " TAX = 50X^2+150X+50Y (若Y>0,則TAX-50)\n\n");
+#ifdef BOARD_TAX_DEADLINE
+ prints("滯納金說明:當月%d日起繳納者,每天加收%d元。\n",BOARD_TAX_DEADLINE,BOARD_TAX_LATEPAYRATE);
+#endif
+#ifdef BOARD_TAX_DISDATE
+ prints("為使土地管理局便於設定下期稅款檔案,當月%d日起至次月1日前不開放繳納。\n",BOARD_TAX_DISDATE);
+ if((int)ptime.tm_mday > BOARD_TAX_DISDATE){
+ vmsg("本期已不可繳納");
+ return 0;
+ }else{
+#endif
+#ifdef BOARD_TAX_DEADLINE
+ if((int)ptime.tm_mday > BOARD_TAX_DEADLINE){
+ lateDay = (int)ptime.tm_mday - BOARD_TAX_DEADLINE;
+ latePay = lateDay * BOARD_TAX_LATEPAYRATE;
+ move(b_lines-6, 0);
+ prints("%03d年%02d月看板稅\n", ptime.tm_year - 11, ptime.tm_mon + 1);
+ prints("應繳看板稅 %d\n", tax);
+ prints("應繳滯納金 %d\n", latePay);
+ shouldpay = tax + latePay;
+ prints("總計應繳稅金 %d\n", shouldpay);
+ }else{
+#endif
+ move(b_lines-4, 0);
+ prints("%03d年%02d月看板稅\n", ptime.tm_year - 11, ptime.tm_mon + 1);
+ prints("應付看板稅 %d\n", tax);
+ shouldpay = tax;
+#ifdef BOARD_TAX_DEADLINE
+ }
+#endif
+ getdata(b_lines - 1, 0, "您想支付本月的看板稅了嗎? (y/N)",genbuf, 3, LCECHO);
+ if (genbuf[0] != 'y') {
+ vmsg("取消支付");
+ return 0;
+ }else{
+ reload_money();
+ if (cuser.money < shouldpay){
+ vmsg(MONEYNAME "不夠繳納稅額...");
+ return 0;
+ }else{
+#ifdef BOARD_TAX_DEADLINE
+ if(latePay > 0){
+ snprintf(buf2, sizeof(buf2), "(含滯納金%d)", latePay);
+ }
+#endif
+ pay(shouldpay, "繳納%03d年%02d月看板稅%d元%s。", ptime.tm_year - 11, ptime.tm_mon + 1, shouldpay, buf2);
+ log_filef(buf, LOG_CREAT,"%s:%02d/%02d %02d:%02d已繳納%03d年%02d月看板稅%d%s%s。\n",
+ cuser.userid, ptime.tm_mon + 1, ptime.tm_mday,
+ ptime.tm_hour, ptime.tm_min,
+ ptime.tm_year - 11, ptime.tm_mon + 1,
+ shouldpay, buf2, MONEYNAME);
+ clear();
+ move(b_lines-2, 0);
+ prints("已繳納%03d年%02d月看板稅。\n", ptime.tm_year - 11, ptime.tm_mon + 1);
+ pressanykey();
+ return 0;
+ }
+ }
+#ifdef BOARD_TAX_DISDATE
+ }
+#endif
+ }
+ }
+}
+
+int
+brdTaxCalcFunc(int x,int y)
+{
+ int tax;
+ tax = (50*x*x)+(150*x)+(50*y);
+ if(y > 0){
+ tax = tax - 50;
+ }
+ return tax;
+}
+
+int
+set_board_tax(void)
+{
+ FILE *fp, *fp2;
+ char *ptr, *id, *mn;
+ char buf[200] = "", genbuf[3];
+ int money = 0, count=0, shouldpay=0, lateDay=0, latePay=0, change=0;
+ int i, x, y;
+ char userid[IDLEN+1];
+ struct tm ptime;
+
+ localtime4_r(&now, &ptime);
+ i = ptime.tm_wday << 1;
+
+ if(isFileExist("etc/boardtax.txt") == false){
+ vmsg("尚未設定稅額檔案,請聯繫工程業務處。");
+ return 0;
+ }else{
+ vs_hdr2(" " BBSMNAME2 "銀行 ", " 看板稅設定");
+ getdata(1, 0, "查詢 (Q) 新增/修改 (A) 刪除 (D) 取消 [C] ",genbuf, 3, LCECHO);
+ if (genbuf[0] == 'q' || genbuf[0] == 'a' || genbuf[0] == 'd'){
+ move(1,0);
+ usercomplete("請輸入要設定的ID ", userid);
+ if (!is_validuserid(userid)){
+ vmsg("查無ID");
+ return 0;
+ }
+ if (genbuf[0] == 'q'){
+ move(b_lines-5, 0);clrtobot();
+ prints("查詢ID:%s\n", userid);
+ shouldpay = getBoardTax(userid);
+ if(shouldpay == 0)
+ outs("不須繳納");
+ else{
+ char *paid = isBrdTaxPaid(userid);
+ if(paid == 0){
+ prints(ANSI_COLOR(1;31) "本月尚未繳納" ANSI_RESET "\n應繳看板稅 %d\n", shouldpay);
+#ifdef BOARD_TAX_DEADLINE
+ if((int)ptime.tm_mday > BOARD_TAX_DEADLINE){
+ lateDay = (int)ptime.tm_mday - BOARD_TAX_DEADLINE;
+ latePay = lateDay * BOARD_TAX_LATEPAYRATE;
+ prints("應繳滯納金 %d\n", latePay);
+ prints("總計應繳稅金 %d\n", shouldpay + latePay);
+ }
+#endif
+ }else{
+ prints(ANSI_COLOR(1;32) "本月已經繳納看板稅" ANSI_RESET "\n%s\n", paid);
+ }
+ }
+ pressanykey();
+ }else if (genbuf[0] == 'a'){
+ getdata(2, 0, "非教育類看板數 ", buf, 20, DOECHO);
+ x = atoi(buf);
+ if (x < 0) {
+ vmsg("輸入錯誤!!");
+ return 0;
+ }
+
+ getdata(3, 0, "教育類看板數 ", buf, 20, DOECHO);
+ y = atoi(buf);
+ if (y < 0) {
+ vmsg("輸入錯誤!!");
+ return 0;
+ }
+
+ shouldpay = brdTaxCalcFunc(x,y);
+
+ system("cp etc/boardtax.txt etc/boardtax.tmp");
+ fp = fopen("etc/boardtax.tmp", "r+");
+ fp2 = fopen("etc/boardtax.txt", "w");
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (!(ptr = strchr(buf, ':')))
+ continue;
+ *ptr = '\0';
+ id = buf;
+ mn = ptr + 1;
+ money = atoi(mn);
+ if(strcmp(id, userid) == 0){
+ if(shouldpay > 0){
+ fprintf(fp2,"%s:%d\n", id, shouldpay);
+ }
+ change = 1;
+ }else{
+ fprintf(fp2,"%s:%d\n", id, money);
+ }
+ count++;
+ }
+ if(change == 0 && shouldpay > 0){
+ fprintf(fp2,"%s:%d\n", userid, shouldpay);
+ }
+ fclose(fp);
+ fclose(fp2);
+
+ move(b_lines-6, 0);clrtobot();
+ prints("已完成設定!\n設定ID:%s\n非教育類看板數:%d\n教育類看板數 :%d\n應付看板稅 $%d", userid, x, y, shouldpay);
+ pressanykey();
+ }else if (genbuf[0] == 'd'){
+ system("cp etc/boardtax.txt etc/boardtax.tmp");
+ fp = fopen("etc/boardtax.tmp", "r+");
+ fp2 = fopen("etc/boardtax.txt", "w");
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (!(ptr = strchr(buf, ':')))
+ continue;
+ *ptr = '\0';
+ id = buf;
+ mn = ptr + 1;
+ money = atoi(mn);
+ if(strcmp(id, userid) == 0){
+ change = 1;
+ }else{
+ fprintf(fp2,"%s:%d\n", id, money);
+ }
+ count++;
+ }
+ fclose(fp);
+ fclose(fp2);
+
+ vmsg("刪除完成");
+ }
+ return 0;
+ }else{
+ return 0;
+ }
+ }
+}
+
+int
+board_tax_calc(void)
+{
+ int x, y, tax;
+ char buf[200] = "";
+
+ clear();
+ vs_hdr2(" " BBSMNAME2 "銀行 ", " 看板稅試算");
+
+ move(2,0);
+ prints("歡迎使用看板稅稅額試算系統。\n");
+ prints("輸入您的看板數量後,系統會自動試算您的稅額。\n");
+ prints("非教育類看板數:指設立於帝寶大廈、市區公寓、郊區別墅與高山營地的看板。\n教育類看板數 :指設立於教育特區並以開放教育為目的的看板。");
+
+ getdata(7, 0, "非教育類看板數 ", buf, 20, DOECHO);
+ x = atoi(buf);
+ if (x < 0) {
+ vmsg("輸入錯誤!!");
+ return 0;
+ }
+
+ getdata(8, 0, "教育類看板數 ", buf, 20, DOECHO);
+ y = atoi(buf);
+ if (y < 0) {
+ vmsg("輸入錯誤!!");
+ return 0;
+ }
+
+ tax = brdTaxCalcFunc(x,y);
+
+ move(b_lines-4, 0);clrtobot();
+ prints("非教育類看板數:%d\n教育類看板數 :%d\n應付看板稅 $%d/月", x, y, tax);
+ pressanykey();
+ return 0;
+}
+
+int
+board_tax_log(void)
+{
+ char buf[200] = "", genbuf[3];
+ int i, year, month;
+ struct tm ptime;
+
+ localtime4_r(&now, &ptime);
+ i = ptime.tm_wday << 1;
+
+ clear();
+ vs_hdr2(" " BBSMNAME2 "銀行 ", " 看板稅檔案");
+ getdata(2, 0, "本月 [T] 指定月份 (D) 取消 (Q) ",genbuf, 3, LCECHO);
+ if(genbuf[0] == 'q'){
+ return 0;
+ }else if(genbuf[0] == 'd'){
+ getdata(3, 0, "欲查看的民國年份 ", buf, 20, DOECHO);
+ year = atoi(buf);
+ if (year < 0) {
+ vmsg("輸入錯誤!!");
+ return 0;
+ }
+ getdata(4, 0, "欲查看的月份 ", buf, 20, DOECHO);
+ month = atoi(buf);
+ if (month < 0) {
+ vmsg("輸入錯誤!!");
+ return 0;
+ }
+ }else{
+ year = ptime.tm_year - 11;
+ month = ptime.tm_mon + 1;
+ }
+
+ snprintf(buf, sizeof(buf), "log/taxpaid/board_%03d_%02d.log", year, month);
+
+ if(isFileExist(buf) == false){
+ vmsgf("%03d年%02d月沒有繳納紀錄", year, month);
+ return 0;
+ }else{
+ if(HasUserPerm(PERM_SYSOP)){
+ getdata(b_lines-2, 0, "檢視 [V] 編修 (E) 取消 (Q) ",genbuf, 3, LCECHO);
+ if(genbuf[0] == 'r'){
+ return 0;
+ }else if(genbuf[0] == 'e'){
+ veditfile(buf);
+ }else{
+ more(buf, YEA);
+ }
+ }else{
+ more(buf, YEA);
+ }
+ }
+ return 0;
+}
+
+int
+set_tax_file(void)
+{
+ char genbuf[3];
+ clear();
+ vs_hdr2(" " BBSMNAME2 "銀行 ", " 看板稅稅額檔案");
+ getdata(b_lines-2, 0, "檢視 [V] 編修 (E) 取消 (Q) ",genbuf, 3, LCECHO);
+ if(genbuf[0] == 'q'){
+ return 0;
+ }else if(genbuf[0] == 'e'){
+ veditfile("etc/boardtax.txt");
+ }else{
+ more("etc/boardtax.txt", YEA);
+ }
+ return 0;
+}
+
+int
+list_unpay(void)
+{
+ FILE *fp, *fp2;
+ char *ptr, *id, *mn;
+ char buf[200] = "";
+ int money = 0, count=0, exist=0;
+
+ if(isFileExist("etc/boardtax.txt") == false){
+ vmsg("尚未設定稅額檔案");
+ return 0;
+ }else{
+ vs_hdr2(" " BBSMNAME2 "銀行 ", " 看板稅未繳納名單");
+
+ move(4, 0);
+ prints("名單整理中...");
+
+ fp = fopen("etc/boardtax.txt", "r+");
+ fp2 = fopen("etc/boardtaxunpay", "w");
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (!(ptr = strchr(buf, ':')))
+ continue;
+ *ptr = '\0';
+ id = buf;
+ mn = ptr + 1;
+ money = atoi(mn);
+ if(isBrdTaxPaid(id) == 0){
+ fprintf(fp2,"%s:%d\n", id, money);
+ exist = 1;
+ }
+ count++;
+ }
+ fclose(fp);
+ fclose(fp2);
+
+ if(exist == 1){
+ clear();
+ more("etc/boardtaxunpay", YEA);
+ }else{
+ move(1,0);clrtobot();
+ mvouts(b_lines-2, 0, "所有人都繳款了。");
+ pressanykey();
+ }
+ return 0;
+ }
+}
+
+#endif //USE_BOARDTAX
\ No newline at end of file
diff --git a/mbbsd/cal.c b/mbbsd/cal.c
index 6a8fc4ce..343b2546 100644
--- a/mbbsd/cal.c
+++ b/mbbsd/cal.c
@@ -212,22 +212,28 @@ mail_redenvelop(const char *from, const char *to, int money, char *fpath)
/* 給錢與贈與稅 */
+float
+calc_rate(int money)
+{
+ return 0;
+}
+
int
give_tax(int money)
{
- int tax = money * 0.1;
- assert (money >= 0);
- if (money % 10)
- tax ++;
- return (tax < 1) ? 1 : tax;
+ float rate = calc_rate(money);
+ int tax;
+ tax = money * rate;
+ return tax;
}
int
cal_before_givetax(int taxed_money)
{
- int m = taxed_money / 9.0f * 10 + 1;
+ /*int m = taxed_money / 9.0f * 10 + 1;
if (m > 1 && taxed_money % 9 == 0)
m--;
- return m;
+ return m;*/
+ return taxed_money;
}
int
@@ -369,7 +375,8 @@ give_money_ui(const char *userid)
return -1;
}
- mvouts(15, 0, alert_trade);
+ move(13,0);
+ outs(alert_trade);
m = 0;
money_buf[0] = 0;
@@ -563,9 +570,13 @@ p_sysinfo(void)
#endif
Cdatelite(&start_time),
build_time);
+ prints("\n程式是以批踢踢實業坊PTT所開發釋出的PttBBS(https://github.com/ptt/pttbbs)為\n"
+ "基礎,由大兔的神密世界BunnyBBS.tk工程業務處開發與修改重新以BRsBBS編列發行版本\n"
+ "號後公開釋出於https://github.com/my1938/BRsBBS並運用於BunnyBBS。\n\n");
if (*build_remote) {
- prints("編譯版本: %s %s %s\n", build_remote, build_origin, build_hash);
+ prints("基礎版本: %s %s %s\n", build_remote, build_origin, build_hash);
}
+ prints("發行版本號與更新紀錄請參考(X)yz系統資訊區→(L)Updates更新紀錄。\n\n");
#ifdef REPORT_PIAIP_MODULES
outs("\n" ANSI_COLOR(1;30)
@@ -616,5 +627,4 @@ p_sysinfo(void)
}
pressanykey();
return 0;
-}
-
+}
\ No newline at end of file
diff --git a/mbbsd/captcha.c b/mbbsd/captcha.c
index b6b0063c..839af676 100644
--- a/mbbsd/captcha.c
+++ b/mbbsd/captcha.c
@@ -151,88 +151,3 @@ verify_captcha(const char *reason)
#endif // !USE_FIGLET_CAPTCHA
-////////////////////////////////////////////////////////////////////////////
-// Remote Captcha System
-////////////////////////////////////////////////////////////////////////////
-#ifdef USE_REMOTE_CAPTCHA
-
-static void captcha_random(char *buf, size_t len)
-{
- // prevent ambigious characters: oOlI
- const char * const chars = "qwertyuipasdfghjkzxcvbnmoQWERTYUPASDFGHJKLZXCVBNM";
-
- for (int i = 0; i < len; i++)
- buf[i] = chars[random() % strlen(chars)];
- buf[len] = '\0';
-}
-
-static const char *
-captcha_insert_remote(const char *handle, const char *verify)
-{
- int ret, code = 0;
- char uri[320];
- snprintf(uri, sizeof(uri), "%s?secret=%s&handle=%s&verify=%s",
- CAPTCHA_INSERT_URI, CAPTCHA_INSERT_SECRET, handle, verify);
- THTTP t;
- thttp_init(&t);
- ret = thttp_get(&t, CAPTCHA_INSERT_SERVER_ADDR, uri, CAPTCHA_INSERT_HOST);
- if (!ret)
- code = thttp_code(&t);
- thttp_cleanup(&t);
-
- if (ret)
- return "伺服器連線失敗, 請稍後再試.";
- if (code != 200)
- return "內部伺服器錯誤, 請稍後再試.";
- return NULL;
-}
-
-const char *
-remote_captcha()
-{
- const char *msg = NULL;
- char handle[CAPTCHA_CODE_LENGTH + 1];
- char verify[CAPTCHA_CODE_LENGTH + 1];
- char verify_input[CAPTCHA_CODE_LENGTH + 1];
-
- vs_hdr("取得驗證碼");
-
- captcha_random(handle, CAPTCHA_CODE_LENGTH);
- captcha_random(verify, CAPTCHA_CODE_LENGTH);
-
- msg = captcha_insert_remote(handle, verify);
- if (msg)
- return msg;
-
- move(2, 0);
- outs("請先至以下連結取得認證碼:\n");
- outs(CAPTCHA_URL_PREFIX "?handle=");
- outs(handle);
- outs("\n");
-
- for (int i = 3; i > 0; i--) {
- if (i < 3) {
- char buf[80];
- snprintf(buf, sizeof(buf), ANSI_COLOR(1;31)
- "驗證碼錯誤, 您還有 %d 次機會." ANSI_RESET, i);
- move(6, 0);
- outs(buf);
- }
- verify_input[0] = '\0';
- getdata(5, 0, "請輸入驗證碼: ", verify_input,
- sizeof(verify_input), DOECHO);
- if (!strcmp(verify, verify_input))
- return NULL;
- }
- return "驗證碼輸入錯誤次數太多, 請重新操作!";
-}
-
-#else
-
-const char *
-remote_captcha()
-{
- return NULL;
-}
-
-#endif // !USE_REMOTE_CAPTCHA
diff --git a/mbbsd/mail.c b/mbbsd/mail.c
index bfeb46af..8b02b353 100644
--- a/mbbsd/mail.c
+++ b/mbbsd/mail.c
@@ -125,7 +125,7 @@ load_mailalert(const char *userid)
fileheader_t my_mail;
sethomedir(maildir, userid);
- if (!HasUserPerm(PERM_BASIC))
+ if (!HasUserPerm(PERM_LOGINOK))
return 0;
if (stat(maildir, &st) < 0)
return 0;
@@ -654,7 +654,7 @@ built_mail_index(void)
char command[1024];
char homepath[PATHLEN];
- if (!HasUserPerm(PERM_BASIC))
+ if (!HasUserPerm(PERM_LOGINOK))
return DONOTHING;
move(b_lines - 4, 0);
@@ -1064,7 +1064,7 @@ mailbox_reply(int ent, fileheader_t * fhdr, const char *direct)
int use_multi = 0;
// do not allow guest to use this
- if (!HasUserPerm(PERM_BASIC))
+ if (!HasUserPerm(PERM_LOGINOK))
return DONOTHING;
if (!fhdr || !fhdr->filename[0])
@@ -1774,7 +1774,7 @@ mail_reply(int ent, fileheader_t * fhdr, const char *direct)
char save_title[STRLEN];
// do not allow guest to use this
- if (!HasUserPerm(PERM_BASIC))
+ if (!HasUserPerm(PERM_LOGINOK))
return DONOTHING;
if (!fhdr || !fhdr->filename[0])
@@ -2035,7 +2035,7 @@ mail_cross_post(int unused_arg GCC_UNUSED, fileheader_t * fhdr,
do_reply_title(2, fhdr->title, str_forward, xtitle, sizeof(xtitle));
strip_ansi(xtitle, xtitle, STRIP_ALL);
- getdata(2, 0, "(S/L)發文 (Q)取消?[Q] ", genbuf, 3, LCECHO);
+ getdata(2, 0, "(S)存檔 (Q)取消?[Q] ", genbuf, 3, LCECHO);
if (genbuf[0] == 'l' || genbuf[0] == 's') {
int currmode0 = currmode;
@@ -2120,7 +2120,7 @@ mail_cite(int ent GCC_UNUSED, fileheader_t * fhdr, const char *direct GCC_UNUSED
char buf[20];
int bid;
- if (!HasUserPerm(PERM_BASIC))
+ if (!HasUserPerm(PERM_LOGINOK))
return DONOTHING;
setuserfile(fpath, fhdr->filename);
@@ -2315,7 +2315,7 @@ mail_waterball(int ent GCC_UNUSED, fileheader_t * fhdr,
static int
mail_recycle_bin(int ent GCC_UNUSED, fileheader_t * fhdr GCC_UNUSED,
const char *direct) {
- if (!HasUserPerm(PERM_BASIC))
+ if (!HasUserPerm(PERM_LOGINOK))
return DONOTHING;
return psb_recycle_bin(direct, "個人信箱");
}
diff --git a/mbbsd/mbbsd.c b/mbbsd/mbbsd.c
index 19a336b1..614da64e 100644
--- a/mbbsd/mbbsd.c
+++ b/mbbsd/mbbsd.c
@@ -625,10 +625,6 @@ multi_user_check(void)
{
register userinfo_t *ui;
char genbuf[3];
-
- if (HasUserPerm(PERM_SYSOP))
- return; /* don't check sysops */
-
srandom(getpid());
// race condition here, sleep may help..?
if (cuser.userlevel) {
@@ -637,43 +633,50 @@ multi_user_check(void)
if(ui == NULL)
return;
- move(b_lines-3, 0); clrtobot();
- outs("\n" ANSI_COLOR(1) "注意: 您有其它連線已登入此帳號。" ANSI_RESET);
- getdata(b_lines - 1, 0, "您想刪除其他重複登入的連線嗎?[Y/n] ",
- genbuf, 3, LCECHO);
-
- usleep(random()%5000000); // 0~5s
- if (genbuf[0] != 'n') {
- do {
- // scan again, old ui may be invalid
- ui = getotherlogin(1);
- if(ui==NULL)
- return;
- if (ui->pid > 0) {
- if(kill(ui->pid, SIGHUP)<0) {
- perror("kill SIGHUP fail");
- break;
- }
- log_usies("KICK ", cuser.nickname);
- } else {
- fprintf(stderr, "id=%s ui->pid=0\n", cuser.userid);
+ if (HasUserPerm(PERM_SYSOP)){
+ move(b_lines-3, 0); clrtobot();
+ outs("\n" ANSI_COLOR(1) "注意: 您有其它連線已登入此帳號。" ANSI_RESET);
+ pressanykey();
+ return;
+ }else{
+ move(b_lines-3, 0); clrtobot();
+ outs("\n" ANSI_COLOR(1) "注意: 您有其它連線已登入此帳號。" ANSI_RESET);
+ getdata(b_lines - 1, 0, "您想刪除其他重複登入的連線嗎?[Y/n] ",
+ genbuf, 3, LCECHO);
+
+ usleep(random()%5000000); // 0~5s
+ if (genbuf[0] != 'n') {
+ do {
+ // scan again, old ui may be invalid
+ ui = getotherlogin(1);
+ if(ui==NULL)
+ return;
+ if (ui->pid > 0) {
+ if(kill(ui->pid, SIGHUP)<0) {
+ perror("kill SIGHUP fail");
+ break;
+ }
+ log_usies("KICK ", cuser.nickname);
+ } else {
+ fprintf(stderr, "id=%s ui->pid=0\n", cuser.userid);
+ }
+ usleep(random()%2000000+1000000); // 1~3s
+ } while(getotherlogin(3) != NULL);
+ } else {
+ /* deny login if still have 3 */
+ if (getotherlogin(3) != NULL) {
+ sleep(1);
+ abort_bbs(0); /* Goodbye(); */
+ }
+ }
}
- usleep(random()%2000000+1000000); // 1~3s
- } while(getotherlogin(3) != NULL);
- } else {
- /* deny login if still have 3 */
- if (getotherlogin(3) != NULL) {
- sleep(1);
- abort_bbs(0); /* Goodbye(); */
- }
- }
} else {
/* allow multiple guest user */
- if (search_ulistn(usernum, MAX_GUEST) != NULL) {
+ /*if (search_ulistn(usernum, MAX_GUEST) != NULL) {*/
+ prints("抱歉,本站不提供 guest 訪問,請以 new 註冊新帳號。");
sleep(1);
- vmsg("抱歉,目前已有太多 guest 在站上, 請用new註冊。");
- exit(1);
- }
+ abort_bbs(0);
+ /*}*/
}
}
@@ -762,148 +765,198 @@ load_current_user(const char *uid)
return 1;
}
+bool isFileExist(char *filedir){
+ FILE *file;
+
+ if(file = fopen(filedir, "r")){
+ fclose(file);
+ return true;
+ }
+ return false;
+}
+
+#ifdef USE_2FALOGIN
+/* Two Factor Auth in twofa.c */
+int twoFA_main();
+#endif
+
static void
login_query(char *ruid)
{
#ifdef CONVERT
/* uid 加一位, for gb login */
char uid[IDLEN + 2];
- int len;
+ int len;
#else
char uid[IDLEN + 1];
#endif
- char passbuf[PASSLEN];
- int attempts;
+ char passbuf[PASSLEN], buf[200];
+ int attempts, twofa;
resolve_garbage();
+ if(isFileExist("etc/maintainConfig") == true){
+ more("etc/Maintain", NA);
+ pressanykey();
+ sleep(3);
+ exit(1);
+ }else{
#ifdef DEBUG
- move(1, 0);
- prints("debugging mode\ncurrent pid: %d\n", getpid());
+ move(1, 0);
+ prints("debugging mode\ncurrent pid: %d\n", getpid());
#else
- show_file("etc/Welcome", 1, -1, SHOWFILE_ALLOW_ALL);
+ show_file("etc/Welcome", 1, -1, SHOWFILE_ALLOW_ALL);
#endif
-
- attempts = 0;
- while (1) {
- if (attempts++ >= LOGINATTEMPTS) {
- more("etc/goodbye", NA);
- pressanykey();
- sleep(3);
- exit(1);
- }
- pwcuInitZero();
+
+#ifdef BETA
+ /*大兔:當系統運用於測試機時,編譯時加上BETA=1的參數,並且在適當處加上可識別的文字,避免不小心在測試操作時誤動到正式系統*/
+ move(1, 69);
+ outs(ANSI_COLOR(1;31) "測試" ANSI_RESET);
+#endif
+ if(is_secure_connection){
+ move(1, 75);
+ outs(ANSI_COLOR(1;32) "安全" ANSI_RESET);
+ }
+
+ attempts = 0;
+ while (1) {
+ if (attempts++ >= LOGINATTEMPTS) {
+ more("etc/goodbye", NA);
+ pressanykey();
+ sleep(3);
+ exit(1);
+ }
+ pwcuInitZero();
#ifdef DEBUG
- move(19, 0);
- prints("current pid: %d ", getpid());
+ move(19, 0);
+ prints("current pid: %d ", getpid());
#endif
- if (getdata(20, 0, "請輸入代號,或以 guest 參觀,或以 new 註冊: ",
- uid, sizeof(uid), DOECHO) < 1)
- {
- // got nothing
- outs("請重新輸入。\n");
- continue;
- }
- telnet_turnoff_client_detect();
+ if (getdata(20, 0, "請輸入帳號或以 new 註冊:",
+ uid, sizeof(uid), DOECHO) < 1)
+ {
+ // got nothing
+ outs("請重新輸入。\n");
+ continue;
+ }
+ telnet_turnoff_client_detect();
#ifdef CONVERT
- /* switch to gb mode if uid end with '.' */
- len = strlen(uid);
- if (uid[0] && uid[len - 1] == ',') {
- set_converting_type(CONV_UTF8);
- uid[len - 1] = 0;
- redrawwin();
- }
- else if (uid[0] && uid[len - 1] == '.') {
- outs("Sorry, GB encoding is not supported anymore. Please use UTF-8 (id,)");
- continue;
- }
- else if (len >= IDLEN + 1)
- uid[IDLEN] = 0;
+ /* switch to gb mode if uid end with '.' */
+ len = strlen(uid);
+ if (uid[0] && uid[len - 1] == ',') {
+ set_converting_type(CONV_UTF8);
+ uid[len - 1] = 0;
+ redrawwin();
+ }
+ else if (uid[0] && uid[len - 1] == '.') {
+ outs("Sorry, GB encoding is not supported anymore. Please use UTF-8 (id,)");
+ continue;
+ }
+ else if (len >= IDLEN + 1)
+ uid[IDLEN] = 0;
#endif
- if (!is_validuserid(uid)) {
+ if (!is_validuserid(uid)) {
- outs(err_uid);
+ outs(err_uid);
#ifdef STR_GUEST
- } else if (strcasecmp(uid, STR_GUEST) == 0) { /* guest */
+ } else if (strcasecmp(uid, STR_GUEST) == 0) { /* guest */
- strlcpy(ruid, STR_GUEST, IDLEN+1);
- break;
+ strlcpy(ruid, STR_GUEST, IDLEN+1);
+ break;
#endif
#ifdef STR_REGNEW
- } else if (strcasecmp(uid, STR_REGNEW) == 0) {
+ } else if (strcasecmp(uid, STR_REGNEW) == 0) {
# ifndef LOGINASNEW
- outs("本系統目前無法以 " STR_REGNEW " 註冊"
-# ifdef STR_GUEST
- ", 請用 " STR_GUEST " 進入"
-# endif // STR_GUEST
- "\n");
- continue;
+ outs("本系統目前無法以 " STR_REGNEW " 註冊");
+ continue;
# endif // !LOGINASNEW
- strlcpy(ruid, STR_REGNEW, IDLEN+1);
- break;
+ strlcpy(ruid, STR_REGNEW, IDLEN+1);
+ break;
#endif // STR_REGNEW
- } else {
- /* normal user */
-
- int valid_user = 1;
-
- /* load the user record */
- if (initcuser(uid) < 1 || !cuser.userid[0])
- valid_user = 0;
-
- /* check if the user is forced to login via secure connection. */
- if (valid_user &&
- (passwd_require_secure_connection(&cuser) && !is_secure_connection)) {
- outs("抱歉,此帳號已設定為只能使用安全連線(如ssh)登入。\n");
- doupdate();
- sleep(5);
- continue;
- }
-
- /* ask user for password, even the user does not exists. */
- getdata(21, 0, MSG_PASSWD,
- passbuf, sizeof(passbuf), NOECHO);
- passbuf[8] = '\0';
-
- move (22, 0); clrtoeol();
- outs("正在檢查密碼...");
- move(22, 0); refresh();
-
- /* prepare for later */
- clrtoeol();
-
- if (!valid_user || !checkpasswd(cuser.passwd, passbuf)) {
-
- if(is_validuserid(cuser.userid))
- logattempt(cuser.userid , '-', login_start_time, fromhost);
- sleep(1);
- outs(ERR_PASSWD);
-
- } else {
-
- strlcpy(ruid, cuser.userid, IDLEN+1);
- outs("密碼正確! 開始登入系統...");
- move(22, 0); refresh();
- clrtoeol();
- break;
- }
- }
- }
+ } else {
+ /* normal user */
+
+ int valid_user = 1;
+
+ /* load the user record */
+ if (initcuser(uid) < 1 || !cuser.userid[0])
+ valid_user = 0;
+
+ /* check if the user is forced to login via secure connection. */
+ if (valid_user &&
+ (passwd_require_secure_connection(&cuser) && !is_secure_connection)) {
+ outs("抱歉,此帳號已設定為只能使用安全連線(如ssh)登入。\n");
+ doupdate();
+ sleep(5);
+ continue;
+ }
+
+ /* ask user for password, even the user does not exists. */
+ getdata(21, 0, MSG_PASSWD,
+ passbuf, sizeof(passbuf), NOECHO);
+ passbuf[8] = '\0';
+
+ move (22, 0); clrtoeol();
+ outs("正在檢查密碼...");
+ move(22, 0); refresh();
+
+ /* prepare for later */
+ clrtoeol();
+
+ if (!valid_user || !checkpasswd(cuser.passwd, passbuf)) {
+ if(is_validuserid(cuser.userid))
+ logattempt(cuser.userid , '-', login_start_time, fromhost);
+ sleep(1);
+ outs(ERR_PASSWD);
+ }else{
+ outs("密碼正確,");
+#ifdef USE_2FALOGIN
+ if(HasUserFlag(UF_TWOFA_LOGIN)){
+ outs("請稍候...");
+ move(22, 0); refresh();
+ twofa = twoFA_main(cuser.userid);
+ move (22, 0); clrtoeol();
+ if(twofa != NULL){
+ outs("兩步驟認證失敗。");
+ move(22, 0); refresh();
+ pressanykey();
+ sleep(2);
+ exit(1);
+ }else{
+ outs("驗證完成,開始登入系統...");
+ move(22, 0); refresh();
+ strlcpy(ruid, cuser.userid, IDLEN+1);
+ clrtoeol();
+ break;
+ }
+ }else{
+#endif
+ strlcpy(ruid, cuser.userid, IDLEN+1);
+ outs("開始登入系統...");
+ move(22, 0); refresh();
+ clrtoeol();
+ break;
+#ifdef USE_2FALOGIN
+ }
+#endif
+ }
+ }
+ }
// auth ok.
#ifdef DETECT_CLIENT
LogClientCode();
#endif
+ }
}
static void
@@ -1000,9 +1053,7 @@ setup_utmp(int mode)
inline static void welcome_msg(void)
{
- prints(ANSI_RESET " 歡迎您再度拜訪,上次您是從 "
- ANSI_COLOR(1;33) "%s" ANSI_COLOR(0;37) " 連往本站。"
- ANSI_CLRTOEND "\n", cuser.lasthost);
+ prints(ANSI_RESET " 歡迎您再度拜訪 "BBSNAME "。");
pressanykey();
}
@@ -1012,12 +1063,21 @@ inline static void check_bad_login(void)
setuserfile(genbuf, FN_BADLOGIN);
if (more(genbuf, NA) != -1) {
move(b_lines - 3, 0);
- outs("通常並沒有辦法知道該ip是誰所有, "
- "以及其意圖(是不小心按錯或有意測您密碼)\n"
- "若您有帳號被盜用疑慮, 請經常更改您的密碼或使用加密連線");
+ outs("通常並沒有辦法知道該ip是誰所有,\n"
+ "若您有帳號被盜用疑慮,請經常更改您的密碼或使用加密連線。");
if (vans("您要刪除以上錯誤嘗試的記錄嗎? [Y/n] ") != 'n')
unlink(genbuf);
}
+#ifdef USE_2FALOGIN
+ setuserfile(genbuf, "2fa.bad");
+ if (more(genbuf, NA) != -1) {
+ move(b_lines - 3, 0);
+ outs("通常並沒有辦法知道該ip是誰所有,\n"
+ "若您有帳號被盜用疑慮,請經常更改您的密碼或使用加密連線。");
+ if (vans("您要刪除以上錯誤嘗試的記錄嗎? [Y/n] ") != 'n')
+ unlink(genbuf);
+ }
+#endif
}
void
@@ -1140,6 +1200,7 @@ user_login(void)
{
struct tm ptime, lasttime;
int nowusers, i;
+ char buf[200];
/* NOTE! 在 setup_utmp 之前, 不應該有任何 blocking/slow function,
* 否則可藉機 race condition 達到 multi-login */
@@ -1216,7 +1277,7 @@ user_login(void)
if (!HasUserPerm(PERM_BASIC)) {
vs_hdr2(" 停權通知 ", " 部份功\能已被暫停使用");
outs(ANSI_COLOR(1;31) "\n\n\t抱歉,你的帳號已被停權。\n"
- "\t詳情請至 ViolateLaw 看板搜尋你的 ID。\n" ANSI_RESET);
+ "\t詳情請至 " BN_POLICELOG " 看板搜尋你的 ID。\n" ANSI_RESET);
pressanykey();
}
@@ -1281,7 +1342,7 @@ user_login(void)
foreign_warning();
#endif
- if(HasUserFlag(UF_FAV_ADDNEW)) {
+ if(HasUserFlag(UF_FAV_ADDNEW) && HasUserPerm(PERM_LOGINOK)){
fav_load();
if (get_fav_root() != NULL) {
int num;
@@ -1294,6 +1355,21 @@ user_login(void)
}
}
+#ifdef USE_2FALOGIN
+ setuserfile(buf, "2fa.recov");
+ if(HasUserFlag(UF_TWOFA_LOGIN) && isFileExist(buf) == false){
+ clear();
+ move(14,0);
+ outs("復原碼是當您無法使用兩步驟認證時,\n");
+ outs("可以在輸入驗證碼時輸入復原碼取回帳戶存取權。\n");
+ outs("您開啟了兩步驟認證,但尚未設定復原碼,\n");
+ outs("若無法使用兩步驟認證時您將無法存取您的帳戶。\n");
+ if (vans("要現在進行設定嗎? [y/N]") == 'y') {
+ twoFA_genRecovCode();
+ }
+ }
+#endif
+
for (i = 0; i < NUMVIEWFILE; i++)
{
if ((cuser.loginview >> i) & 1)
diff --git a/mbbsd/menu.c b/mbbsd/menu.c
index 992db5ae..e7ca17a5 100644
--- a/mbbsd/menu.c
+++ b/mbbsd/menu.c
@@ -107,24 +107,25 @@ showtitle(const char *title, const char *mid)
/* prepare mid */
#ifdef DEBUG
{
+ if(!(HasUserPerm(PERM_SYSOP))) {
+ printf(ANSI_RESET "系統進行檢修維護,非站長禁止進入!");
+ sleep(1);
+ abort_bbs(0);
+ }
sprintf(buf, " current pid: %6d ", getpid());
mid = buf;
mid_attr = ANSI_COLOR(41;5);
}
-#else
- if (ISNEWMAIL(currutmp)) {
- mid = " 你有新信件 ";
- mid_attr = ANSI_COLOR(41;5);
- } else if ( HasUserPerm(PERM_ACCTREG) ) {
- // TODO cache this value?
- int nreg = regform_estimate_queuesize();
- if(nreg > 100)
+#elif defined BETA
+ /*大兔:當系統運用於測試機時,編譯時加上BETA=1的參數,並且在適當處加上可識別的文字,避免不小心在測試操作時誤動到正式系統*/
{
- nreg -= (nreg % 10);
- sprintf(buf, " 超過 %03d 篇未審核 ", nreg);
- mid_attr = ANSI_COLOR(41;5);
- mid = buf;
+ mid = " 測試版 ";
+ mid_attr = ANSI_COLOR(41;5);
}
+#else
+ if (ISNEWMAIL(currutmp)) {
+ mid = " 新信件來囉 ";
+ mid_attr = ANSI_COLOR(41;5);
}
#endif
@@ -212,15 +213,18 @@ int
ZA_Select(void)
{
int k;
+ struct tm ptime;
if (!is_login_ready ||
!HasUserPerm(PERM_BASIC) ||
HasUserPerm(PERM_VIOLATELAW))
return 0;
+ localtime4_r(&now, &ptime);
// TODO refresh status bar?
- vs_footer(VCLR_ZA_CAPTION " ★快速切換: ",
- " (b)文章列表 (c)分類 (t)熱門 (f)我的最愛 (m)信箱 (u)使用者名單");
+ move(b_lines-2, 0); clrtobot();
+ vbarf(ANSI_COLOR(1;33;42)"\n 快速選單 "ANSI_COLOR(0;30;42)"|"ANSI_COLOR(1;37;42)" %02d"ANSI_COLOR(1;5;37;42)":"ANSI_COLOR(0;1;37;42)"%02d \t "ANSI_COLOR(1;37;42)"呼叫器["ANSI_COLOR(1;33;42)"%s"ANSI_COLOR(1;37;42)"] ",ptime.tm_hour, ptime.tm_min,str_pager_modes[currutmp->pager % PAGER_MODES]);
+ vbarf(ANSI_COLOR(0;31;47)"\n (b)"ANSI_COLOR(0;30;47)"文章列表" ANSI_COLOR(0;31;47)" (c)"ANSI_COLOR(0;30;47)"分類 " ANSI_COLOR(0;31;47)"(f)"ANSI_COLOR(0;30;47)"我的最愛 " ANSI_COLOR(0;31;47)"(m)"ANSI_COLOR(0;30;47)"信箱 " ANSI_COLOR(0;31;47)"(u)"ANSI_COLOR(0;30;47)"使用者名單 \t" ANSI_COLOR(0;31;47)"(x)"ANSI_COLOR(0;30;47)"關閉選單 "ANSI_RESET);
k = vkey();
if (k < ' ' || k >= 'z') return 0;
@@ -251,17 +255,18 @@ ZA_Enter(void)
case 'c':
Class();
break;
- case 't':
- TopBoards();
- break;
case 'f':
Favorite();
break;
case 'm':
- m_read();
+ if (HasUserPerm(PERM_LOGINOK)){
+ m_read();
+ }
break;
case 'u':
- t_users();
+ if (HasUserPerm(PERM_LOGINOK)){
+ t_users();
+ }
break;
}
// if user exit with new ZA assignment,
@@ -294,20 +299,49 @@ show_status(void)
{
int i;
struct tm ptime;
- char *myweek = "天一二三四五六";
-
+ char *myweek = "日一二三四五六";
localtime4_r(&now, &ptime);
i = ptime.tm_wday << 1;
+#ifdef USE_TIANGANDIZHI
+ char *tian[]={"癸","甲","乙","丙","丁","戊","己","庚","辛","壬"};
+ char *di[]={"亥","子","丑","寅","卯","辰","巳","午","未","申","酉","戌"};
+ int t = (ptime.tm_year + 1897) % 10;
+ int d = (ptime.tm_year + 1897) % 12;
+#endif
+ char *greeting[]={"早安","午安","晚安"};
+ int g = 0;
+ if(ptime.tm_hour >= 0 && ptime.tm_hour < 6)
+ g = 2;
+ if(ptime.tm_hour >= 6 && ptime.tm_hour < 12)
+ g = 0;
+ if(ptime.tm_hour >= 12 && ptime.tm_hour < 19)
+ g = 1;
+ if(ptime.tm_hour >= 19 && ptime.tm_hour < 24)
+ g = 2;
+
move(b_lines, 0);
- vbarf(ANSI_COLOR(34;46) "[%d/%d 星期%c%c %d:%02d]"
- ANSI_COLOR(1;33;45) "%-14s"
- ANSI_COLOR(30;47) " 線上" ANSI_COLOR(31)
- "%d" ANSI_COLOR(30) "人, 我是" ANSI_COLOR(31) "%s"
- ANSI_COLOR(30) "\t[呼叫器]" ANSI_COLOR(31) "%s ",
+ vbarf(ANSI_COLOR(1;33;45) " "
+#ifdef USE_MINGGUO_CALENDAR
+ "民國%03d年"
+#ifdef USE_TIANGANDIZHI
+ " 歲次%s%s "
+#endif //USE_TIANGANDIZHI
+#else //USE_MINGGUO_CALENDAR
+ "西元%04d年"
+#endif //USE_MINGGUO_CALENDAR
+ "%02d月%02d日 週%c%c "
+ ANSI_COLOR(0;30;47) " " ANSI_COLOR(1;31;47) "%s" ANSI_COLOR(0;30;47) " %s!"
+ ANSI_COLOR(1;31;47) "\t%d" ANSI_COLOR(0;30;47) " 人在線 "ANSI_RESET,
+#ifdef USE_MINGGUO_CALENDAR
+ ptime.tm_year - 11,
+#ifdef USE_TIANGANDIZHI
+ tian[t], di[d],
+#endif //USE_TIANGANDIZHI
+#else //USE_MINGGUO_CALENDAR
+ ptime.tm_year + 1900,
+#endif //USE_MINGGUO_CALENDAR
ptime.tm_mon + 1, ptime.tm_mday, myweek[i], myweek[i + 1],
- ptime.tm_hour, ptime.tm_min, SHM->today_is,
- SHM->UTMPnumber, cuser.userid,
- str_pager_modes[currutmp->pager % PAGER_MODES]);
+ cuser.userid, greeting[g], SHM->UTMPnumber);
}
/*
@@ -610,9 +644,6 @@ view_user_login_log() {
return 0;
}
-static int x_admin_money(void);
-static int x_admin_user(void);
-
static int deprecate_userlist() {
vs_hdr2(" " BBSNAME " ", " 已移至使用者名單");
outs("\n"
@@ -626,59 +657,421 @@ static int deprecate_userlist() {
return 0;
}
-// ----------------------------------------------------------- MENU DEFINITION
-// 注意每個 menu 最多不能同時顯示超過 11 項 (80x24 標準大小的限制)
+void Customize(); // user.c
+static int
+u_customize()
+{
+ Customize();
+ return 0;
+}
-static const commands_t m_admin_money[] = {
- {view_user_money_log, PERM_SYSOP|PERM_ACCOUNTS,
- "View Log 檢視交易記錄"},
- {give_money, PERM_SYSOP|PERM_VIEWSYSOP, "Givemoney 紅包雞"},
- {NULL, 0, NULL}
-};
+static int u_view_recentlogin()
+{
+ char fn[PATHLEN];
+ setuserfile(fn, FN_RECENTLOGIN);
+ return more(fn, YEA);
+}
-static const commands_t m_admin_user[] = {
- {view_user_money_log, PERM_SYSOP|PERM_ACCOUNTS,
- "Money Log 最近交易記錄"},
- {view_user_login_log, PERM_SYSOP|PERM_ACCOUNTS|PERM_BOARD,
- "OLogin Log 最近上線記錄"},
- {u_list, PERM_SYSOP, "Users List 列出註冊名單"},
- {search_user_bybakpwd, PERM_SYSOP|PERM_ACCOUNTS,
- "DOld User data 查閱\備份使用者資料"},
- {NULL, 0, NULL}
-};
+#ifdef USE_RECENTPAY
+static int u_view_recentpay()
+{
+ char fn[PATHLEN];
+ clear();
+ mvouts(10, 5, "注意: 此處內容僅供參考,實際" MONEYNAME
+ "異動以站方內部資料為準");
+ pressanykey();
+ setuserfile(fn, FN_RECENTPAY);
+ return more(fn, YEA);
+}
+#endif
-/* administrator's maintain menu */
-static const commands_t adminlist[] = {
- {m_user, PERM_SYSOP, "User 使用者資料"},
- {m_board, PERM_SYSOP|PERM_BOARD, "Board 設定看板"},
- {m_register,
- PERM_ACCOUNTS|PERM_ACCTREG, "Register 審核註冊表單"},
- {x_file, PERM_SYSOP|PERM_VIEWSYSOP, "Xfile 編輯系統檔案"},
- {x_admin_money, PERM_SYSOP|PERM_ACCOUNTS|PERM_VIEWSYSOP,
- "Money 【" MONEYNAME "相關】"},
- {x_admin_user, PERM_SYSOP|PERM_ACCOUNTS|PERM_BOARD|PERM_POLICE_MAN,
- "LUser Log 【使用者資料記錄】"},
- {search_user_bypwd,
- PERM_ACCOUNTS|PERM_POLICE_MAN, "Search User 特殊搜尋使用者"},
- {m_loginmsg, PERM_SYSOP, "GMessage Login 進站水球"},
- {NULL, 0, NULL}
-};
+static int t_aloha() {
+ friend_edit(FRIEND_ALOHA);
+ return 0;
+}
+
+static int t_special() {
+ friend_edit(FRIEND_SPECIAL);
+ return 0;
+}
+
+#ifdef HAVE_USERAGREEMENT
+static int
+x_agreement(void)
+{
+ more(HAVE_USERAGREEMENT, YEA);
+ return 0;
+}
+#endif
+
+#ifdef HAVE_INFO
+static int
+x_program(void)
+{
+ more("etc/version", YEA);
+ return 0;
+}
+#endif
+
+#ifdef HAVE_LICENSE
+static int
+x_gpl(void)
+{
+ more("etc/GPL", YEA);
+ return 0;
+}
+#endif
+
+#ifdef HAVE_SYSUPDATES
+static int
+x_sys_updates(void)
+{
+ more("etc/sysupdates", YEA);
+ return 0;
+}
+#endif
-/* mail menu */
-static const commands_t maillist[] = {
- {m_read, PERM_READMAIL, "Read 我的信箱"},
- {m_send, PERM_LOGINOK, "Send 站內寄信"},
- {mail_list, PERM_LOGINOK, "Mail List 群組寄信"},
- {setforward, PERM_LOGINOK, "Forward 設定信箱自動轉寄" },
- {mail_mbox, PERM_INTERNET, "Zip UserHome 把所有私人資料打包回去"},
- {built_mail_index,
- PERM_LOGINOK, "Savemail 重建信箱索引"},
- {mail_all, PERM_SYSOP, "All 寄信給所有使用者"},
+#ifdef DEBUG
+int _debug_reportstruct()
+{
+ clear();
+ prints("boardheader_t:\t%d\n", sizeof(boardheader_t));
+ prints("fileheader_t:\t%d\n", sizeof(fileheader_t));
+ prints("userinfo_t:\t%d\n", sizeof(userinfo_t));
+ prints("screenline_t:\t%d\n", sizeof(screenline_t));
+ prints("SHM_t:\t%d\n", sizeof(SHM_t));
+ prints("userec_t:\t%d\n", sizeof(userec_t));
+ pressanykey();
+ return 0;
+}
+#endif
+
+#ifdef USE_BOARDTAX
+// in boardtax.c
+int pay_board_tax();
+int set_board_tax();
+int board_tax_calc();
+int board_tax_log();
+int set_tax_file();
+int list_unpay();
+#endif
+
+int list_user_board();
+
+/* Two Factor Auth in twofa.c */
+#ifdef USE_2FALOGIN
+int twoFA_genRecovCode();
+#endif
+#if defined(DETECT_CLIENT) && defined(USE_TRUSTDEV)
+int twoFA_RemoveTrust();
+#endif
+
+/* Password change in user.c */
+int userPass_change();
+static int
+u_pass_change()
+{
+ userPass_change(cuser, 0, usernum);
+ return 0;
+}
+
+/* Mission in mission.c */
+#ifdef USE_MISSION
+int mission();
+static int
+p_mission()
+{
+ mission_main();
+ return 0;
+}
+#endif
+
+// ----------------------------------------------------------- MENU DEFINITION
+// 注意每個 menu 最多不能同時顯示超過 11 項 (80x24 標準大小的限制)
+// 107.08.03 整理程式碼架構
+
+static int x_admin_board(void);
+static int x_admin_brdtax(void);
+static int x_admin_money(void);
+static int x_admin_user(void);
+static int x_admin_usermenu(void);
+
+static const commands_t cmdlist[] = {
+ {admin, PERM_SYSOP|PERM_BBSADM|PERM_ACCOUNTS|PERM_BOARD,
+ "0Admin 〉 系統維護區 〈"},
+ {Announce, 0, "Announce 〉 精華公佈欄 〈"},
+ {Favorite, 0, "Favorite 〉 我的最愛 〈"},
+ {Class, 0, "Class 〉 分組討論區 〈"},
+
+ {Mail, PERM_LOGINOK, "Mail 〉 私人信件區 〈"},
+ /*大兔:這個目錄的功能用ctrl-u都能辦到,至於多人聊天室效益不大,也沒有啟用天使功能,因此這個選單整個停用*/
+ //{Talk, PERM_LOGINOK, "Talk 〉 休閒聊天區 〈"},
+ {Play_Play, PERM_LOGINOK, "Play 〉 娛樂與休閒 〈"},
+ {Name_Menu, PERM_LOGINOK, "Namelist 〉 編特別名單 〈"},
+
+ {u_register, MENU_UNREGONLY, "Register 〉 填寫註冊單 〈"},
#ifdef USE_MAIL_ACCOUNT_SYSOP
- {mail_account_sysop, 0, "Contact AM 寄信給帳號站長"},
+ {mail_account_sysop,MENU_UNREGONLY, "Mail Admin 〉寄給帳號站長〈"},
#endif
+
+ {User, PERM_BASIC, "User 〉 個人設定區 〈"},
+ {Xyz, 0, "Xyz 〉 系統資訊區 〈"},
+ {Goodbye, 0, "Goodbye 〉 秘境出口 〈"},
{NULL, 0, NULL}
};
+int main_menu(void) {
+ char init = 'C';
+
+ if (ISNEWMAIL(currutmp))
+ init = 'M';
+
+ if (!(HasUserPerm(PERM_LOGINOK)))
+ init = 'R';
+
+ domenu(M_MMENU, "主功\能表", init, cmdlist);
+ return 0;
+}
+ /* 0Admin Menu */
+ /* 大兔:權限劃分備註:有關使用者資料的項目只能讓SYSOP與ACCOUNT操作;BBSADM計畫作為輔助SYSOP之用,因此其他非敏感操作得讓BBSADM使用;BOARD可以直接在這裡設定看板。*/
+ static const commands_t adminlist[] = {
+ {x_admin_board, PERM_SYSOP|PERM_BBSADM|PERM_BOARD, "Board Admin 〉 土地管理局 〈"},
+ {x_admin_usermenu, PERM_SYSOP|PERM_ACCOUNTS|PERM_BOARD,"User Admin 〉 民政事務局 〈"},
+ {x_admin_money, PERM_SYSOP|PERM_BBSADM, "FinancAdmin 〉 金融監管署 〈"},
+ {x_file, PERM_SYSOP|PERM_BBSADM, "SystemFile 〉 系統檔案 〈"},
+ {m_loginmsg, PERM_SYSOP|PERM_BBSADM, "LoginMsg 〉 進站水球 〈"},
+ {NULL, 0, NULL}
+ };
+ int
+ admin(void)
+ {
+ char init = 'B';
+
+ if (HasUserPerm(PERM_ACCOUNTS))
+ init = 'U';
+
+ domenu(M_ADMIN, "站長維護系統", init, adminlist);
+ return 0;
+ }
+ static const commands_t m_admin_board[] = {
+ {m_board, PERM_SYSOP|PERM_BBSADM|PERM_BOARD, "Set Board 〉 設定看板 〈"},
+ #ifdef USE_BOARDTAX
+ {x_admin_brdtax,PERM_SYSOP|PERM_BBSADM|PERM_BOARD, "TBoard Tax 〉 看板稅管理 〈"},
+ #endif
+ {list_user_board,PERM_SYSOP|PERM_BBSADM|PERM_BOARD, "ListUserMod 〉 查擔任板主 〈"},
+ {NULL, 0, NULL}
+ };
+ static int x_admin_board(void)
+ {
+ char init = 'S';
+ domenu(M_XMENU, "土地管理局", init, m_admin_board);
+ return 0;
+ }
+ #ifdef USE_BOARDTAX
+ static const commands_t m_admin_brdtax[] = {
+ {board_tax_calc,PERM_SYSOP|PERM_BBSADM|PERM_BOARD, "CTax Calc 〉 試算稅額 〈"},
+ {set_board_tax, PERM_SYSOP|PERM_BBSADM|PERM_BOARD, "STax Set 〉 查詢與增刪 〈"},
+ {set_tax_file, PERM_SYSOP|PERM_BBSADM|PERM_BOARD, "FTax File 〉 稅額檔案 〈"},
+ {board_tax_log, PERM_SYSOP|PERM_BBSADM|PERM_BOARD, "LTax PayLog 〉 繳納紀錄 〈"},
+ {list_unpay, PERM_SYSOP|PERM_BBSADM|PERM_BOARD, "UnPay List 〉 未繳納名單 〈"},
+ {NULL, 0, NULL}
+ };
+ static int x_admin_brdtax(void)
+ {
+ char init = 'S';
+ domenu(M_XMENU, "看板稅管理", init, m_admin_brdtax);
+ return 0;
+ }
+ #endif
+ static const commands_t m_admin_money[] = {
+ {view_user_money_log, PERM_SYSOP|PERM_BBSADM, "View Log 〉 交易記錄 〈"},
+ {give_money, PERM_SYSOP|PERM_BBSADM,"Givemoney 〉 發放"MONEYNAME" 〈"},
+ {NULL, 0, NULL}
+ };
+ static int x_admin_money(void)
+ {
+ char init = 'V';
+ domenu(M_XMENU, "金融監管署", init, m_admin_money);
+ return 0;
+ }
+ static const commands_t m_admin_usermenu[] = {
+ {m_register, PERM_SYSOP|PERM_ACCOUNTS, "Register 〉 審核註冊單 〈"},
+ {m_user, PERM_SYSOP|PERM_ACCOUNTS|PERM_BOARD,"User Data 〉 使用者資料 〈"},
+ {x_admin_user, PERM_SYSOP|PERM_ACCOUNTS, "LUser Log 〉 使用者記錄 〈"},
+ {search_user_bypwd, PERM_SYSOP|PERM_ACCOUNTS, "Search User 〉 搜尋使用者 〈"},
+ {NULL, 0, NULL}
+ };
+ static int x_admin_usermenu(void)
+ {
+ char init = 'U';
+ domenu(M_XMENU, "民政事務局", init, m_admin_usermenu);
+ return 0;
+ }
+ static const commands_t m_admin_user[] = {
+ {view_user_money_log, PERM_SYSOP|PERM_ACCOUNTS, "Money Log 〉 交易記錄 〈"},
+ {view_user_login_log, PERM_SYSOP|PERM_ACCOUNTS, "Login Log 〉 上線記錄 〈"},
+ {u_list, PERM_SYSOP|PERM_ACCOUNTS, "Users List 〉 註冊名冊 〈"},
+ {search_user_bybakpwd, PERM_SYSOP|PERM_ACCOUNTS, "Old Data 〉 查備份資料 〈"},
+ {NULL, 0, NULL}
+ };
+ static int x_admin_user(void)
+ {
+ domenu(M_XMENU, "使用者記錄", 'L', m_admin_user);
+ return 0;
+ }
+ /* Mail Menu */
+ static const commands_t maillist[] = {
+ {m_read, PERM_LOGINOK, "Read 〉 我的信箱 〈"},
+ {m_send, PERM_LOGINOK, "Send 〉 站內寄信 〈"},
+ {mail_list, PERM_LOGINOK, "Group Mail 〉 群組寄信 〈"},
+ {setforward, PERM_LOGINOK, "Forward 〉設定自動轉寄〈"},
+ {mail_mbox, PERM_INTERNET, "Zip Data 〉打包私人資料〈"},
+ {built_mail_index, PERM_LOGINOK, "VSavemail 〉重建信箱索引〈"},
+ {mail_all, PERM_SYSOP|PERM_BBSADM, "Mail All 〉 寄給所有人 〈"},
+ #ifdef USE_MAIL_ACCOUNT_SYSOP
+ {mail_account_sysop,PERM_LOGINOK, "AMail Admin 〉寄給帳號站長〈"},
+ #endif
+ {NULL, 0, NULL}
+ };
+ int
+ Mail(void)
+ {
+ domenu(M_MAIL, "電子郵件", (ISNEWMAIL(currutmp) ? 'R' : 'S'), maillist);
+ return 0;
+ }
+ /* Play Menu */
+ static const commands_t moneylist[] = {
+ {p_from, 0, "Edit From 〉 修改故鄉 〈"},
+ {ordersong, 0, "Order Song 〉點播心情動態〈"},
+ {NULL, 0, NULL}
+ };
+ static int p_money() {
+ domenu(M_PSALE, BBSMNAME2 "超市", 'O', moneylist);
+ return 0;
+ };
+ static const commands_t banklist[] = {
+ {p_give, 0, "Give Money 〉 給別人" MONEYNAME" 〈"},
+ {save_violatelaw, 0, "Pay Ticket 〉 繳納罰單 〈"},
+ #ifdef USE_BOARDTAX
+ {board_tax_calc, PERM_LOGINOK, "CTax Calc 〉 試算稅額 〈"},
+ {pay_board_tax, PERM_LOGINOK, "Board Tax 〉 繳納看板稅 〈"},
+ #endif
+ {NULL, 0, NULL}
+ };
+ static int p_bank() {
+ domenu(M_PSALE, BBSMNAME2 "銀行", 'G', banklist);
+ return 0;
+ };
+ static const commands_t playlist[] = {
+ #ifdef USE_MISSION
+ {p_mission, 0, "IMission 〉 任務中心 〈"},
+ #endif
+ {p_bank, 0, "Bank 〉 " BBSMNAME2 "銀行 〈"},
+ {p_money, PERM_LOGINOK, "Market 〉 " BBSMNAME2 "超市 〈"},
+ {chicken_main, PERM_LOGINOK, "Chicken 〉 " BBSMNAME2 "養雞場 〈"},
+ #ifndef NO_GAMBLE
+ {ticket_main, PERM_LOGINOK, "Gamble 〉 " BBSMNAME2 "彩券 〈"},
+ #endif
+ //{chessroom, PERM_LOGINOK, "BChess 【 " BBSMNAME2 "棋院 】"}, /*大兔:效益低,停用,未來可能整個拔除*/
+ {NULL, 0, NULL}
+ };
+ int
+ Play_Play(void)
+ {
+ domenu(M_PMENU, "娛樂與休閒", 'M', playlist);
+ return 0;
+ }
+ /* Name menu */
+ static const commands_t namelist[] = {
+ {t_override, PERM_LOGINOK, "OverRide 〉 好友名單 〈"},
+ {t_reject, PERM_LOGINOK, "Black 〉 壞人名單 〈"},
+ {t_aloha, PERM_LOGINOK, "ALOHA 〉上站通知名單〈"},
+ {t_fix_aloha, PERM_LOGINOK, "XFixALOHA 〉修正上站通知〈"},
+ {t_special, PERM_LOGINOK, "Special 〉 特別名單 〈"},
+ {NULL, 0, NULL}
+ };
+ int
+ Name_Menu(void)
+ {
+ domenu(M_NMENU, "名單編輯", 'O', namelist);
+ return 0;
+ }
+ /* User menu */
+ static const commands_t seculist[] = {
+ {u_pass_change, PERM_BASIC, "Password 〉 修改密碼 〈"},
+ #ifdef USE_2FALOGIN
+ {twoFA_genRecovCode,PERM_BASIC, "RecoverCode 〉 產生復原碼 〈"},
+ #endif
+ #if defined(DETECT_CLIENT) && defined(USE_TRUSTDEV)
+ {twoFA_RemoveTrust ,PERM_BASIC, "TRemoveTrust 〉撤銷信任裝置〈"},
+ #endif
+ {NULL, 0, NULL}
+ };
+ static int u_security() {
+ domenu(M_UMENU, "密碼與安全", 'P', seculist);
+ return 0;
+ };
+ static const commands_t userlist[] = {
+ /*{u_loginview, PERM_BASIC, "VLogin View 選擇進站畫面"},
+ {u_myfiles, PERM_LOGINOK, "My Files 【個人檔案】 (名片,簽名檔...)"},
+ {u_mylogs, PERM_LOGINOK, "LMy Logs 【個人記錄】 (最近上線...)"},*/
+ {u_info, PERM_BASIC, "Info 〉個人資料設定〈"},
+ {u_security, PERM_BASIC, "Security 〉 密碼與安全 〈"},
+ {u_customize, PERM_BASIC, "Customize 〉 個人化設定 〈"},
+ {u_editplan, PERM_LOGINOK, "QueryEdit 〉 編輯名片檔 〈"},
+ {u_editsig, PERM_LOGINOK, "NSignature 〉 編輯簽名檔 〈"},
+ {u_view_recentlogin,0, "Login Log 〉 上站記錄 〈"},
+ #ifdef USE_RECENTPAY
+ {u_view_recentpay, 0, "Pay Log 〉 交易記錄 〈"},
+ #endif
+ #ifdef ASSESS
+ {u_cancelbadpost, PERM_LOGINOK, "Bye BadPost 〉 刪除退文 〈"},
+ #endif
+ {NULL, 0, NULL}
+ };
+ int
+ User(void)
+ {
+ domenu(M_UMENU, "個人設定", 'I', userlist);
+ return 0;
+ }
+ /* XYZ tool menu */
+ static const commands_t xyzlist[] = {
+ /*{x_hot, 0, "THot Topics 〉 熱門看板 〈"},
+ {x_users, 0, "Users 〉 使用者統計 〈"},*/
+ #ifndef DEBUG
+ /* All these are useless in debug mode. */
+ #ifdef HAVE_USERAGREEMENT
+ {x_agreement, 0, "Agreement 〉 使用者條款 〈"},
+ #endif
+ #ifdef HAVE_LICENSE
+ {x_gpl, 0, "ILicense 〉 GNU 執照 〈"},
+ #endif
+ #ifdef HAVE_INFO
+ {x_program, 0, "Program 〉 程式版本 〈"},
+ #endif
+ {x_history, 0, "History 〉 我們的成長 〈"},
+ {x_login, 0, "System 〉 重要公告 〈"},
+ #ifdef HAVE_SYSUPDATES
+ {x_sys_updates, 0, "LUpdates 〉程式更新紀錄〈"},
+ #endif
+
+ #else // !DEBUG
+ {_debug_reportstruct, 0, "Report 〉 結構報告 〈"},
+ #endif // !DEBUG
+
+ {p_sysinfo, 0, "Xinfo 〉 系統資訊 〈"},
+ {NULL, 0, NULL}
+ };
+ int
+ Xyz(void)
+ {
+ domenu(M_XMENU, "工具程式", 'X', xyzlist);
+ return 0;
+ }
+
+// -----------------------------------------------------------
+// 以下用不到
+// -----------------------------------------------------------
#ifdef PLAY_ANGEL
static const commands_t angelmenu[] = {
@@ -698,7 +1091,7 @@ static int menu_angelbeats() {
#endif
/* Talk menu */
-static const commands_t talklist[] = {
+/*static const commands_t talklist[] = {
{t_users, 0, "Users 線上使用者列表"},
{t_query, 0, "Query 查詢網友"},
// PERM_PAGE - 水球都要 PERM_LOGIN 了
@@ -716,51 +1109,11 @@ static const commands_t talklist[] = {
#endif
{t_display, 0, "Display 顯示上幾次熱訊"},
{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 const commands_t namelist[] = {
- {t_override, PERM_LOGINOK,"OverRide 好友名單"},
- {t_reject, PERM_LOGINOK, "Black 壞人名單"},
- {t_aloha,PERM_LOGINOK, "ALOHA 上站通知名單"},
- {t_fix_aloha,PERM_LOGINOK,"XFixALOHA 修正上站通知"},
- {t_special,PERM_LOGINOK, "Special 其他特別名單"},
- {NULL, 0, NULL}
-};
-
-static int u_view_recentlogin()
-{
- char fn[PATHLEN];
- setuserfile(fn, FN_RECENTLOGIN);
- return more(fn, YEA);
-}
+};*/
-#ifdef USE_RECENTPAY
-static int u_view_recentpay()
-{
- char fn[PATHLEN];
- clear();
- mvouts(10, 5, "注意: 此處內容僅供參考,實際" MONEYNAME
- "異動以站方內部資料為準");
- pressanykey();
- setuserfile(fn, FN_RECENTPAY);
- return more(fn, YEA);
-}
-#endif
-
-static const commands_t myfilelist[] = {
- {u_editplan, PERM_LOGINOK, "QueryEdit 編輯名片檔"},
- {u_editsig, PERM_LOGINOK, "Signature 編輯簽名檔"},
+/*static const commands_t myfilelist[] = {
+ {u_editplan, PERM_LOGINOK, "QueryEdit 〉編輯名片檔〈"},
+ {u_editsig, PERM_LOGINOK, "Signature 〉編輯簽名檔〈"},
{NULL, 0, NULL}
};
@@ -784,111 +1137,15 @@ u_mylogs()
{
domenu(M_UMENU, "個人記錄", 'L', myuserlog);
return 0;
-}
-
-void Customize(); // user.c
-
-static int
-u_customize()
-{
- Customize();
- return 0;
-}
-
-
-/* User menu */
-static const commands_t userlist[] = {
- {u_customize, PERM_BASIC, "UCustomize 個人化設定"},
- {u_info, PERM_BASIC, "Info 設定個人資料與密碼"},
- {u_loginview, PERM_BASIC, "VLogin View 選擇進站畫面"},
- {u_myfiles, PERM_LOGINOK, "My Files 【個人檔案】 (名片,簽名檔...)"},
- {u_mylogs, PERM_LOGINOK, "LMy Logs 【個人記錄】 (最近上線...)"},
- {u_register, MENU_UNREGONLY, "Register 填寫《註冊申請單》"},
-#ifdef ASSESS
- {u_cancelbadpost,PERM_LOGINOK, "Bye BadPost 申請刪除退文"},
-#endif // ASSESS
- {deprecate_userlist, 0, "KCloak 隱身術"},
- {NULL, 0, NULL}
-};
-
-#ifdef HAVE_USERAGREEMENT
-static int
-x_agreement(void)
-{
- more(HAVE_USERAGREEMENT, YEA);
- return 0;
-}
-#endif
-
-static int
-x_admin_money(void)
-{
- char init = 'V';
- if (HasUserPerm(PERM_VIEWSYSOP))
- init = 'G';
- domenu(M_XMENU, "金錢相關管理", init, m_admin_money);
- return 0;
-}
-
-static int
-x_admin_user(void)
-{
- domenu(M_XMENU, "使用者記錄管理", 'O', m_admin_user);
- return 0;
-}
-
-#ifdef HAVE_INFO
-static int
-x_program(void)
-{
- more("etc/version", YEA);
- return 0;
-}
-#endif
-
-#ifdef HAVE_LICENSE
-static int
-x_gpl(void)
-{
- more("etc/GPL", YEA);
- return 0;
-}
-#endif
-
-#ifdef HAVE_SYSUPDATES
-static int
-x_sys_updates(void)
-{
- more("etc/sysupdates", YEA);
- return 0;
-}
-#endif
-
-#ifdef DEBUG
-int _debug_reportstruct()
-{
- clear();
- prints("boardheader_t:\t%d\n", sizeof(boardheader_t));
- prints("fileheader_t:\t%d\n", sizeof(fileheader_t));
- prints("userinfo_t:\t%d\n", sizeof(userinfo_t));
- prints("screenline_t:\t%d\n", sizeof(screenline_t));
- prints("SHM_t:\t%d\n", sizeof(SHM_t));
- prints("userec_t:\t%d\n", sizeof(userec_t));
- pressanykey();
- return 0;
-}
-
-#endif
+}*/
/* XYZ tool sub menu */
-static const commands_t m_xyz_hot[] = {
+/*static const commands_t m_xyz_hot[] = {
{x_week, 0, "Week 《本週五十大熱門話題》"},
{x_issue, 0, "Issue 《今日十大熱門話題》"},
{x_boardman,0, "Man Boards 《看板精華區排行榜》"},
{NULL, 0, NULL}
};
-
-/* XYZ tool sub menu */
static const commands_t m_xyz_user[] = {
{x_user100 ,0, "Users 《使用者百大排行榜》"},
{topsong,PERM_LOGINOK,
@@ -910,98 +1167,11 @@ x_users(void)
{
domenu(M_XMENU, "使用者統計資訊", 'U', m_xyz_user);
return 0;
-}
+}*/
-/* XYZ tool menu */
-static const commands_t xyzlist[] = {
- {x_hot, 0, "THot Topics 《熱門話題與看板》"},
- {x_users,0, "Users 《使用者相關統計》"},
-#ifndef DEBUG
- /* All these are useless in debug mode. */
-#ifdef HAVE_USERAGREEMENT
- {x_agreement,0, "Agreement 《本站使用者條款》"},
-#endif
-#ifdef HAVE_LICENSE
- {x_gpl, 0, "ILicense GNU 使用執照"},
-#endif
-#ifdef HAVE_INFO
- {x_program, 0, "Program 本程式之版本與版權宣告"},
-#endif
- {x_history, 0, "History 《我們的成長》"},
- {x_login,0, "System 《系統重要公告》"},
-#ifdef HAVE_SYSUPDATES
- {x_sys_updates,0,"LUpdates 《本站系統程式更新紀錄》"},
-#endif
-
-#else // !DEBUG
- {_debug_reportstruct, 0,
- "ReportStruct 報告各種結構的大小"},
-#endif // !DEBUG
-
- {p_sysinfo, 0, "Xinfo 《查看系統資訊》"},
- {NULL, 0, NULL}
-};
-
-/* Ptt money menu */
-static const commands_t moneylist[] = {
- {p_give, 0, "0Give 給其他人" MONEYNAME},
- {save_violatelaw, 0,"1ViolateLaw 繳罰單"},
- {p_from, 0, "2From 暫時修改故鄉"},
- {ordersong,0, "3OSong 心情點播機"},
- {NULL, 0, NULL}
-};
-
-static const commands_t cmdlist[] = {
- {admin, PERM_SYSOP|PERM_ACCOUNTS|PERM_BOARD|PERM_VIEWSYSOP|PERM_ACCTREG|PERM_POLICE_MAN,
- "0Admin 【 系統維護區 】"},
- {Announce, 0, "Announce 【 精華公佈欄 】"},
-#ifdef DEBUG
- {Favorite, 0, "Favorite 【 我的最不愛 】"},
-#else
- {Favorite, 0, "Favorite 【 我 的 最愛 】"},
-#endif
- {Class, 0, "Class 【 分組討論區 】"},
- // TODO 目前很多人被停權時會變成 -R-1-3 (PERM_LOGINOK, PERM_VIOLATELAW,
- // PERM_NOREGCODE) 沒有 PERM_READMAIL,但這樣麻煩的是他們就搞不懂發生什麼事
- {Mail, PERM_BASIC, "Mail 【 私人信件區 】"},
- // 有些 bot 喜歡整天 query online accounts, 所以聊天改為 LOGINOK
- {Talk, PERM_LOGINOK, "Talk 【 休閒聊天區 】"},
- {User, PERM_BASIC, "User 【 個人設定區 】"},
- {Xyz, 0, "Xyz 【 系統資訊區 】"},
- {Play_Play, PERM_LOGINOK, "Play 【 娛樂與休閒 】"},
- {Name_Menu, PERM_LOGINOK, "Namelist 【 編特別名單 】"},
-#ifdef DEBUG
- {Goodbye, 0, "Goodbye 再見再見再見再見"},
-#else
- {Goodbye, 0, "Goodbye 離開,再見… "},
-#endif
- {NULL, 0, NULL}
-};
-
-int main_menu(void) {
- domenu(M_MMENU, "主功\能表", (ISNEWMAIL(currutmp) ? 'M' : 'C'), cmdlist);
- return 0;
-}
-
-static int p_money() {
- domenu(M_PSALE, BBSMNAME2 "量販店", '0', moneylist);
- return 0;
-};
-
-static int chessroom();
-
-/* Ptt Play menu */
-static const commands_t playlist[] = {
- {p_money, PERM_LOGINOK, "Pay 【 " BBSMNAME2 "量販店 】"},
- {chicken_main, PERM_LOGINOK,
- "Chicken 【 " BBSMNAME2 "養雞場 】"},
- {ticket_main, PERM_LOGINOK,
- "Gamble 【 " BBSMNAME2 "彩券 】"},
- {chessroom, PERM_LOGINOK,"BChess 【 " BBSMNAME2 "棋院 】"},
- {NULL, 0, NULL}
-};
+//static int chessroom();
-static const commands_t conn6list[] = {
+/*static const commands_t conn6list[] = {
{conn6_main, PERM_LOGINOK, "1Conn6Fight 【" ANSI_COLOR(1;33) "六子棋邀局" ANSI_RESET "】"},
{conn6_personal, PERM_LOGINOK, "2Conn6Self 【" ANSI_COLOR(1;34) "六子棋打譜" ANSI_RESET "】"},
{conn6_watch, PERM_LOGINOK, "3Conn6Watch 【" ANSI_COLOR(1;35) "六子棋觀棋" ANSI_RESET "】"},
@@ -1032,65 +1202,9 @@ static int chessroom() {
return 0;
}
-// ---------------------------------------------------------------- SUB MENUS
-
-/* main menu */
-
-int
-admin(void)
-{
- char init = 'L';
-
- if (HasUserPerm(PERM_VIEWSYSOP))
- init = 'X';
- else if (HasUserPerm(PERM_ACCTREG))
- init = 'R';
- else if (HasUserPerm(PERM_POLICE_MAN))
- init = 'S';
-
- domenu(M_ADMIN, "系統維護", init, adminlist);
- return 0;
-}
-
-int
-Mail(void)
-{
- domenu(M_MAIL, "電子郵件", 'R', maillist);
- return 0;
-}
-
int
Talk(void)
{
domenu(M_TMENU, "聊天說話", 'U', talklist);
return 0;
-}
-
-int
-User(void)
-{
- domenu(M_UMENU, "個人設定", 'U', userlist);
- return 0;
-}
-
-int
-Xyz(void)
-{
- domenu(M_XMENU, "工具程式", 'T', xyzlist);
- return 0;
-}
-
-int
-Play_Play(void)
-{
- domenu(M_PMENU, "網路遊樂場", 'G', playlist);
- return 0;
-}
-
-int
-Name_Menu(void)
-{
- domenu(M_NMENU, "名單編輯", 'O', namelist);
- return 0;
-}
-
+}*/
diff --git a/mbbsd/mission.c b/mbbsd/mission.c
new file mode 100644
index 00000000..9a8c5f7b
--- /dev/null
+++ b/mbbsd/mission.c
@@ -0,0 +1,158 @@
+#include "bbs.h"
+
+#ifdef USE_MISSION
+
+/* 每日登入大兔 */
+int mission_dailylogin(){
+ FILE *fp;
+ char buf[200], buf2[200], date[11], genbuf[3];
+ int i;
+ struct tm ptime;
+ localtime4_r(&now, &ptime);
+ i = ptime.tm_wday << 1;
+ snprintf(date, sizeof(date), "%03d-%02d-%02d", ptime.tm_year - 11, ptime.tm_mon + 1, ptime.tm_mday);
+
+ clear();
+ vs_hdr2("任務中心 ", " 每日登入大兔");
+ move(2,0);
+ outs("任務說明:\n"
+ "一定要每日上大兔喔 :)\n\n");
+ outs("參加資格:不限\n");
+ outs("任務獎勵:每日 100 " MONEYNAME "\n");
+
+ setuserfile(buf, "mission.dailylogin");
+ if(isFileExist(buf) == false){
+ if (!(fp = fopen(buf, "w"))){
+ vmsg("系統錯誤,請稍後再試。(Error code: MIS-1-F01)");
+ return 0;
+ }
+ fprintf(fp,"%s", date);
+ fclose(fp);
+ pay(-100, "完成任務:每日登入大兔。");
+ mvouts(b_lines - 2, 33, ANSI_COLOR(1;32)"恭喜完成任務!"ANSI_RESET);
+ pressanykey();
+ return 0;
+ }else{
+ if (!(fp = fopen(buf, "r"))){
+ vmsg("系統錯誤,請稍後再試。(Error code: MIS-1-F02)");
+ return 0;
+ }
+ fgets(buf2, sizeof(buf2), fp);
+ fclose(fp);
+ if (!strcmp(buf2, date)){
+ mvouts(b_lines - 2, 32, ANSI_COLOR(1;33)"已經完成過任務。"ANSI_RESET);
+ pressanykey();
+ return 0;
+ }else{
+ if (!(fp = fopen(buf, "w"))){
+ vmsg("系統錯誤,請稍後再試。(Error code: MIS-1-F03)");
+ return 0;
+ }
+ fprintf(fp,"%s", date);
+ fclose(fp);
+ pay(-100, "完成任務:每日登入大兔。");
+ mvouts(b_lines - 2, 33, ANSI_COLOR(1;32)"恭喜完成任務!"ANSI_RESET);
+ pressanykey();
+ return 0;
+ }
+ }
+}
+
+/* 修改自己的信箱 */
+int mission_email(){
+ FILE *fp;
+ char buf[200], buf2[200], genbuf[3];
+
+ clear();
+ vs_hdr2("任務中心 ", " 修改自己的信箱");
+ move(2,0);
+ outs("任務說明:\n"
+ "初創站時註冊單程式有做些修改,不幸的是程式修改時沒有測試,\n"
+ "導致後來使用者註冊單雖然有填寫電子信箱但不會被系統紀錄,\n"
+ "這項錯誤後來被發現,也在1.5版更新中修正了這項錯誤。\n"
+ "為了讓使用者資料完整,我們鼓勵使用者自主修改電子信箱。\n\n");
+ outs("參加資格:在程式修正前註冊,沒有被紀錄到信箱的使用者\n");
+ outs("任務獎勵:250 " MONEYNAME "\n");
+ outs("任務指示:在(U)ser 個人設定區→(I)nfo 個人資料設定 中修改\n");
+
+ setuserfile(buf, "mission.email");
+ if(isFileExist(buf) == false){
+ if(strcmp(cuser.email, "x")){
+ mvouts(b_lines - 2, 24, ANSI_COLOR(1;33)"電子信箱紀錄正常,不具參加資格。"ANSI_RESET);
+ pressanykey();
+ return 0;
+ }else{
+ getdata(12, 0, "接下這個任務嗎? (y)是 [N]否 ",genbuf, 3, LCECHO);
+ if (genbuf[0] != 'y') {
+ return 0;
+ }
+ if (!(fp = fopen(buf, "w"))){
+ vmsg("系統錯誤,請稍後再試。(Error code: MIS-M-F01)");
+ return 0;
+ }
+ now = time(NULL);
+ fprintf(fp,"%s", Cdate(&now));
+ fclose(fp);
+ vmsg("接下任務囉~");
+ return 0;
+ }
+ }else{
+ if (!(fp = fopen(buf, "r"))){
+ vmsg("系統錯誤,請稍後再試。(Error code: MIS-M-F02)");
+ return 0;
+ }
+ fgets(buf2, sizeof(buf2), fp);
+ fclose(fp);
+ if (!strcmp(buf2, "complete")){
+ mvouts(b_lines - 2, 32, ANSI_COLOR(1;33)"已經完成過任務。"ANSI_RESET);
+ pressanykey();
+ return 0;
+ }else{
+ if(strcmp(cuser.email, "x")){
+ if (!(fp = fopen(buf, "w"))){
+ vmsg("系統錯誤,請稍後再試。(Error code: MIS-M-F03)");
+ return 0;
+ }
+ fprintf(fp,"complete");
+ fclose(fp);
+ pay(-250, "完成任務:修改自己的信箱。");
+ mvouts(b_lines - 2, 33, ANSI_COLOR(1;32)"恭喜完成任務!"ANSI_RESET);
+ pressanykey();
+ return 0;
+ }else{
+ mvouts(b_lines - 2, 35, "任務進行中");
+ pressanykey();
+ return 0;
+ }
+ }
+ }
+}
+
+/* 任務列表 */
+int mission_main()
+{
+ int i;
+ char genbuf[3];
+
+ clear();
+ vs_hdr2(" " BBSNAME " ", " 任務中心");
+ move(1,0);
+ vbarf(ANSI_REVERSE " 編號 任務標題\t獎勵 \n");
+ vbarf(" 1. 每日登入大兔\t100 " MONEYNAME "\n");
+ vbarf(" 2. 修改自己的信箱\t250 " MONEYNAME "\n");
+
+ getdata(b_lines - 1, 0, "輸入任務編號檢視詳細說明、開始任務或領取獎勵:",genbuf, 3, LCECHO);
+
+ if (genbuf[0] == '1') {
+ mission_dailylogin();
+ return 0;
+ }
+ if (genbuf[0] == '2') {
+ mission_email();
+ return 0;
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/mbbsd/ordersong.c b/mbbsd/ordersong.c
index 624dceb4..aef18574 100644
--- a/mbbsd/ordersong.c
+++ b/mbbsd/ordersong.c
@@ -12,8 +12,11 @@
#ifndef ORDERSONG_MAX_BADPOST
#define ORDERSONG_MAX_BADPOST (1)
#endif
-#ifndef ORDERSONG_MIN_NUMLOGINDAYS
-#define ORDERSONG_MIN_NUMLOGINDAYS (30)
+//#ifndef ORDERSONG_MIN_NUMLOGINDAYS
+//#define ORDERSONG_MIN_NUMLOGINDAYS (30)
+//#endif
+#ifndef ORDERSONG_PAYMONEY
+#define ORDERSONG_PAYMONEY (100)
#endif
#define MAX_SONGS (MAX_ADBANNER-100) // (400) XXX MAX_SONGS should be fewer than MAX_ADBANNER.
@@ -33,7 +36,6 @@ do_order_song(void)
char save_title[STRLEN];
const char *override_receiver = NULL;
- // 由於變免費了,改成要看退文跟登入天數
#if defined(ORDERSONG_MAX_BADPOST) && defined(ASSESS)
if (cuser.badpost > ORDERSONG_MAX_BADPOST) {
vmsgf("為避免濫用,留言前請先消除退文記錄至 %d 篇以下",
@@ -41,6 +43,7 @@ do_order_song(void)
return 0;
}
#endif
+
#ifdef ORDERSONG_MIN_NUMLOGINDAYS
if (cuser.numlogindays < ORDERSONG_MIN_NUMLOGINDAYS) {
vmsgf("為避免濫用,留言前要先有%s %d %s",
@@ -53,44 +56,33 @@ do_order_song(void)
lockreturn0(OSONG, LOCK_MULTI);
pwcuReload();
- /* Jaky 一人一天點一首 */
- if (!strcmp(buf, Cdatedate(&cuser.lastsong)) && !HasUserPerm(PERM_SYSOP)) {
- move(22, 0);
- vmsg("你今天已經留過言囉,明天再來吧....");
- unlockutmpmode();
- return 0;
- }
-
while (1) {
char ans[4];
- move(12, 0);
- clrtobot();
+ clear();
+ vs_hdr2(" " BBSMNAME2 "超市 ", " 點播動態");
prints("親愛的 %s 歡迎來到心情點播留言系統\n\n", cuser.userid);
outs(ANSI_COLOR(1) "注意心情點播內容請勿涉及謾罵 人身攻擊 猥褻"
"公然侮辱 誹謗\n"
"若有上述違規情形,站方將保留決定是否公開內容的權利\n"
- "且違規者將不受匿名保護(其 ID 可被公佈於公開看板)\n"
- "如不同意請按 (3) 離開。" ANSI_RESET "\n");
- getdata(18, 0,
- "請選擇 " ANSI_COLOR(1) "1)" ANSI_RESET " 開始留言、"
- ANSI_COLOR(1) "2)" ANSI_RESET " 看範本、"
- "或是 " ANSI_COLOR(1) "3)" ANSI_RESET " 離開: ",
- ans, sizeof(ans), DOECHO);
-
- if (ans[0] == '1')
+ "且違規者將不受匿名保護(其 ID 可被公佈於公開看板)\n"
+ "如不同意請按 Q 離開。" ANSI_RESET "\n");
+ getdata(6, 0,"開始留言(Y) 看點歌本(S) 離開[Q] ", ans, sizeof(ans), LCECHO);
+
+ if (ans[0] == 'y'){
break;
- else if (ans[0] == '2') {
+ }else if (ans[0] == 's') {
a_menu("留言範本", SONGBOOK, 0, 0, NULL, NULL);
clear();
- }
- else if (ans[0] == '3') {
- vmsg("謝謝光臨 :)");
+ }else if (ans[0] == 'q') {
unlockutmpmode();
return 0;
- }
- }
+ }else{
+ unlockutmpmode();
+ return 0;
+ }
+ }
- getdata_str(19, 0, "留言者(可匿名): ", sender, sizeof(sender), DOECHO,
+ getdata_str(7, 0, "留言者(可匿名): ", sender, sizeof(sender), DOECHO,
cuser.userid);
#ifdef USE_ANGEL_SONG
@@ -98,14 +90,14 @@ do_order_song(void)
#endif
if (!*receiver)
- getdata(20, 0, "留言給(可匿名): ", receiver, sizeof(receiver), DOECHO);
+ getdata(8, 0, "留言給(可匿名): ", receiver, sizeof(receiver), DOECHO);
do {
- getdata(21, 0, "想要要對他/她說..:", say, sizeof(say), DOECHO);
+ getdata(9, 0, "想要要對他/她說..:", say, sizeof(say), DOECHO);
reduce_blank(say, say);
if (!say[0]) {
bell();
- mvouts(22, 0, "請重新輸入想說的內容");
+ mvouts(10, 0, "請重新輸入想說的內容");
}
} while (!say[0]);
@@ -114,8 +106,7 @@ do_order_song(void)
if (override_receiver) {
*address = 0;
} else do {
- move(22, 0); clrtobot();
- getdata_str(22, 0, "寄到誰的信箱(站內真實ID)?",
+ getdata_str(11, 0, "寄到誰的信箱(站內真實ID)?",
address, sizeof(address), LCECHO, receiver);
if (!*address)
break;
@@ -130,6 +121,24 @@ do_order_song(void)
vmsg("請輸入站內 ID 或直接 ENTER");
} while (1);
+#ifdef ORDERSONG_PAYMONEY
+ move(b_lines-2, 0);
+ prints("即將支付點播費用 %d %s", ORDERSONG_PAYMONEY, MONEYNAME);
+ getdata(b_lines - 1, 0, "確定要支付了嗎? (y/N)",genbuf, 3, LCECHO);
+ if (genbuf[0] != 'y') {
+ unlockutmpmode();
+ return 0;
+ }
+
+ reload_money();
+ if (cuser.money < (int)ORDERSONG_PAYMONEY){
+ vmsg(MONEYNAME "不夠繳納點播費用...");
+ unlockutmpmode();
+ return 0;
+ }else{
+ pay((int)ORDERSONG_PAYMONEY, "繳納點播費用。");
+#endif
+
vmsg("接著要選範本囉...");
a_menu("留言範本", SONGBOOK, 0, 0, trans_buffer, NULL);
if (!trans_buffer[0] || strstr(trans_buffer, "home") ||
@@ -249,6 +258,9 @@ do_order_song(void)
unlockutmpmode();
return 1;
+#ifdef ORDERSONG_PAYMONEY
+ }
+#endif
}
int
diff --git a/mbbsd/pmore.c b/mbbsd/pmore.c
index a6503e92..66abe199 100644
--- a/mbbsd/pmore.c
+++ b/mbbsd/pmore.c
@@ -775,7 +775,7 @@ mf_gunzip(const char *fn GCC_UNUSED, int fd)
// TODO since most files were not gzipped, maybe we can
// move type checking to "after mmap attached"
if (read(fd, magic, sizeof(magic)) != sizeof(magic) ||
- memcmp(gzip_magic, magic, sizeof(magic)) != 0) {
+ memcmp(gzip_magic, magic, sizeof(magic) != 0)) {
// XXX since we only use 'mmap' in pmore, no need to rewind fd
return fd;
}
@@ -2436,13 +2436,12 @@ _pmore2(
outs(ANSI_RESET ANSI_COLOR(1;33;44));
w -= strlen(s); outs(s);
- while (w-- > 0)
- outc(' ');
-
- outs(ANSI_RESET ANSI_CLRTOEND);
+ while (w-- > 0) outc(' '); outs(ANSI_RESET ANSI_CLRTOEND);
w = tolower(vkey());
- if (w != 'n' && w != KEY_UP && w != KEY_LEFT && w != 'q')
+ if ( w != 'n' &&
+ w != KEY_UP && w != KEY_LEFT &&
+ w != 'q')
{
RESET_MOVIE();
mfmovie.mode = MFDISP_MOVIE_PLAYING;
diff --git a/mbbsd/read.c b/mbbsd/read.c
index 6d91eed1..b6e9317c 100644
--- a/mbbsd/read.c
+++ b/mbbsd/read.c
@@ -569,8 +569,15 @@ trim_blank(char *buf) {
return *buf == 0;
}
+typedef struct filter_predicate_t {
+ int mode;
+ char keyword[TTLEN + 1];
+ int recommend;
+ int money;
+} filter_predicate_t;
+
static int
-ask_filter_predicate(fileheader_predicate_t *pred, int prev_modes, int sr_mode,
+ask_filter_predicate(filter_predicate_t *pred, int prev_modes, int sr_mode,
const fileheader_t *fh, int *success)
{
memset(pred, 0, sizeof(*pred));
@@ -640,12 +647,152 @@ ask_filter_predicate(fileheader_predicate_t *pred, int prev_modes, int sr_mode,
static int
match_filter_predicate(const fileheader_t *fh, void *arg)
{
- fileheader_predicate_t *pred = (fileheader_predicate_t *) arg;
-
- if (pred->mode & RS_MONEY)
+ filter_predicate_t *pred = (filter_predicate_t *) arg;
+ const char * const keyword = pred->keyword;
+ int sr_mode = pred->mode;
+
+ // The order does not matter. Only single sr_mode at a time.
+ if (sr_mode & RS_MARK)
+ return fh->filemode & FILE_MARKED;
+ else if (sr_mode & RS_SOLVED)
+ return fh->filemode & FILE_SOLVED;
+ else if (sr_mode & RS_NEWPOST)
+ return strncmp(fh->title, "Re:", 3) != 0;
+ else if (sr_mode & RS_AUTHOR)
+ return DBCS_strcasestr(fh->owner, keyword) != NULL;
+ else if (sr_mode & RS_KEYWORD)
+ return DBCS_strcasestr(fh->title, keyword) != NULL;
+ else if (sr_mode & RS_KEYWORD_EXCLUDE)
+ return DBCS_strcasestr(fh->title, keyword) == NULL;
+ else if (sr_mode & RS_TITLE)
+ return strcasecmp(subject(fh->title), keyword) == 0;
+ else if (sr_mode & RS_RECOMMEND)
+ return pred->recommend > 0 ?
+ (fh->recommend >= pred->recommend) :
+ (fh->recommend <= pred->recommend);
+ else if (sr_mode & RS_MONEY)
return query_file_money(fh) >= pred->money;
+ return 0;
+}
+
+static int
+find_resume_point(const char *direct, time4_t timestamp)
+{
+ fileheader_t fh = {};
+ sprintf(fh.filename, "X.%d", (int) timestamp);
+ /* getindex returns 0 when error. */
+ int idx = getindex(direct, &fh, 0);
+ if (idx < 0)
+ return -idx;
+ /* return 0 when error, same as starting from the beginning. */
+ return idx;
+}
+
+static int
+select_read_build(const char *src_direct, const char *dst_direct,
+ int src_direct_has_reference, time4_t resume_from, int count,
+ int (*match)(const fileheader_t *fh, void *arg), void *arg)
+{
+ int fr, fd;
+
+ if ((fr = open(src_direct, O_RDONLY, 0)) < 0)
+ return -1;
+
+ /* find incremental selection start point */
+ int reference = resume_from ?
+ find_resume_point(src_direct, resume_from) : 0;
+
+ int filemode;
+ if (reference) {
+ filemode = O_APPEND | O_RDWR;
+ } else {
+ filemode = O_CREAT | O_RDWR;
+ count = 0;
+ reference = 0;
+ }
+
+ if ((fd = open(dst_direct, filemode, DEFAULT_FILE_CREATE_PERM)) == -1) {
+ close(fr);
+ return -1;
+ }
+
+ if (reference > 0)
+ lseek(fr, reference * sizeof(fileheader_t), SEEK_SET);
+
+#ifdef DEBUG
+ vmsgf("search: %s", src_direct);
+#endif
+ fileheader_t fhs[8192 / sizeof(fileheader_t)];
+ int i, len;
+ while ((len = read(fr, fhs, sizeof(fhs))) > 0) {
+ len /= sizeof(fileheader_t);
+ for (i = 0; i < len; ++i) {
+ reference++;
+ if (!match(&fhs[i], arg))
+ continue;
+
+ if (!src_direct_has_reference) {
+ fhs[i].multi.refer.flag = 1;
+ fhs[i].multi.refer.ref = reference;
+ }
+ ++count;
+ write(fd, &fhs[i], sizeof(fileheader_t));
+ }
+ }
+ close(fr);
+
+ // Do not create black hole.
+ off_t current_size = lseek(fd, 0, SEEK_CUR);
+ if (current_size >= 0 && count * sizeof(fileheader_t) <= current_size)
+ ftruncate(fd, count * sizeof(fileheader_t));
+ close(fd);
+
+ return count;
+}
+
+static int
+select_read_should_build(const char *dst_direct, int bid, time4_t *resume_from,
+ int *count)
+{
+ struct stat st;
+ if (stat(dst_direct, &st) < 0)
+ {
+ *resume_from = 0;
+ *count = 0;
+ return 1;
+ }
+
+ *count = st.st_size / sizeof(fileheader_t);
- return match_fileheader_predicate(fh, pred);
+ time4_t filetime = st.st_mtime;
+
+ if (bid > 0)
+ {
+ time4_t filecreate = st.st_ctime;
+ boardheader_t *bp = getbcache(bid);
+ assert(bp);
+
+ if (bp->SRexpire)
+ {
+ if (bp->SRexpire > now) // invalid expire time.
+ bp->SRexpire = now;
+
+ if (bp->SRexpire > filecreate)
+ filetime = -1;
+ }
+ }
+
+ if (filetime < 0 || now-filetime > 60*60) {
+ *resume_from = 0;
+ return 1;
+ } else if (now-filetime > 3*60) {
+ *resume_from = filetime;
+ return 1;
+ } else {
+ /* use cached data */
+ *resume_from = 0;
+ return 0;
+ }
}
static int
@@ -666,15 +813,17 @@ select_read(const keeploc_t * locmem, int sr_mode)
STATINC(STAT_SELECTREAD);
- fileheader_predicate_t predicate;
+ filter_predicate_t predicate;
int success;
int ui_ret = ask_filter_predicate(&predicate, _mode, sr_mode, fh, &success);
if (!success)
return ui_ret;
_mode |= sr_mode;
- select_read_name(genbuf, sizeof(genbuf),
- first_select ? NULL : p, &predicate);
+ snprintf(genbuf, sizeof(genbuf), "%s%X.%X.%X",
+ first_select ? "SR.":p,
+ sr_mode, (int)strlen(predicate.keyword),
+ DBCS_StringHash(predicate.keyword));
// pre-calculate board prefix
if (currstat == RMAIL)
diff --git a/mbbsd/register.c b/mbbsd/register.c
index 267fd78f..8822e754 100644
--- a/mbbsd/register.c
+++ b/mbbsd/register.c
@@ -546,18 +546,84 @@ ensure_user_agreement_version()
exit(1);
}
+#ifdef USE_REG_CAPTCHA
+static void captcha_random(char *buf, size_t len)
+{
+ // prevent ambigious characters: oOlI
+ const char * const chars = "qwertyuipasdfghjkzxcvbnmoQWERTYUPASDFGHJKLZXCVBNM";
+
+ for (int i = 0; i < len; i++)
+ buf[i] = chars[random() % strlen(chars)];
+ buf[len] = '\0';
+}
+
+static const char *
+captcha_insert_remote(const char *handle, const char *verify)
+{
+ int ret, code = 0;
+ char uri[320];
+ snprintf(uri, sizeof(uri), "%s?secret=%s&handle=%s&verify=%s",
+ CAPTCHA_INSERT_URI, CAPTCHA_INSERT_SECRET, handle, verify);
+ THTTP t;
+ thttp_init(&t);
+ ret = thttp_get(&t, CAPTCHA_INSERT_SERVER_ADDR, uri, CAPTCHA_INSERT_HOST);
+ if (!ret)
+ code = thttp_code(&t);
+ thttp_cleanup(&t);
+
+ if (ret)
+ return "伺服器連線失敗, 請稍後再試.";
+ if (code != 200)
+ return "內部伺服器錯誤, 請稍後再試.";
+ return NULL;
+}
+
static const char *
do_register_captcha()
{
-#ifdef USE_REG_CAPTCHA
-#ifndef USE_REMOTE_CAPTCHA
-#error "To use USE_REG_CAPTCHA, you must also set USE_REMOTE_CAPTCHA"
-#endif
- return remote_captcha();
+ const char *msg = NULL;
+ char handle[CAPTCHA_CODE_LENGTH + 1];
+ char verify[CAPTCHA_CODE_LENGTH + 1];
+ char verify_input[CAPTCHA_CODE_LENGTH + 1];
+
+ vs_hdr("取得驗證碼");
+
+ captcha_random(handle, CAPTCHA_CODE_LENGTH);
+ captcha_random(verify, CAPTCHA_CODE_LENGTH);
+
+ msg = captcha_insert_remote(handle, verify);
+ if (msg)
+ return msg;
+
+ move(2, 0);
+ outs("請先至以下連結取得認證碼:\n");
+ outs(CAPTCHA_URL_PREFIX "?handle=");
+ outs(handle);
+ outs("\n");
+
+ for (int i = 3; i > 0; i--) {
+ if (i < 3) {
+ char buf[80];
+ snprintf(buf, sizeof(buf), ANSI_COLOR(1;31)
+ "驗證碼錯誤, 您還有 %d 次機會." ANSI_RESET, i);
+ move(6, 0);
+ outs(buf);
+ }
+ verify_input[0] = '\0';
+ getdata(5, 0, "請輸入驗證碼: ", verify_input,
+ sizeof(verify_input), DOECHO);
+ if (!strcmp(verify, verify_input))
+ return NULL;
+ }
+ return "驗證碼輸入錯誤次數太多, 請重新操作!";
+}
#else
+static const char *
+do_register_captcha()
+{
return NULL;
-#endif
}
+#endif
/////////////////////////////////////////////////////////////////////////////
// New Registration (Phase 1: Create Account)
@@ -1023,7 +1089,7 @@ check_register(void)
}
static int
-create_regform_request()
+create_regform_request(char *email)
{
FILE *fn;
@@ -1039,7 +1105,7 @@ create_regform_request()
fprintf(fn, "name: %s\n", cuser.realname);
fprintf(fn, "career: %s\n", cuser.career);
fprintf(fn, "addr: %s\n", cuser.address);
- fprintf(fn, "email: %s\n", "x"); // email is apparently 'x' here.
+ fprintf(fn, "email: %s\n", email);
fprintf(fn, "----\n");
fclose(fn);
@@ -1047,7 +1113,7 @@ create_regform_request()
file_append_record(FN_REQLIST, cuser.userid);
// save justify information
- pwcuRegSetTemporaryJustify("<Manual>", "x");
+ pwcuRegSetTemporaryJustify("<Manual>", email);
return 1;
}
@@ -1056,25 +1122,17 @@ toregister(char *email)
{
clear();
vs_hdr("認證設定");
- if (cuser.userlevel & PERM_NOREGCODE){
+ /*if (cuser.userlevel & PERM_NOREGCODE){
strcpy(email, "x");
goto REGFORM2;
- }
+ }*/
move(1, 0);
- outs("您好, 本站註冊認證的方式有:\n"
- " 1.若您有 E-Mail (本站不接受 yahoo, kimo等免費的 E-Mail)\n"
- " 請輸入您的 E-Mail , 我們會寄發含有認證碼的信件給您\n"
- " 收到後請到 (U)ser => (R)egister 輸入認證碼, 即可通過認證\n"
- "\n"
- " 2.若您沒有 E-Mail 或是一直無法收到認證信, 請輸入 x \n"
- " 會有站長親自人工審核註冊資料," ANSI_COLOR(1;33)
- "但注意這可能會花上數天或更多時間。" ANSI_RESET "\n"
- "**********************************************************\n"
- "* 注意! 通常應該會在輸入完成後數分至數小時內收到認證信, *\n"
- "* 若過久未收到請到郵件垃圾桶檢查是否被當作垃圾信(SPAM)了,*\n"
- "* 另外若輸入後發生認證碼錯誤請先確認輸入是否為最後一封 *\n"
- "* 收到的認證信,若真的仍然不行請再重填一次 E-Mail. *\n"
- "**********************************************************\n");
+ outs("您好,請填寫您的 E-Mail。\n"
+ "本站註冊資料的審核採手動審核,\n"
+ "是以資料完整性作為審核原則,\n"
+ "所有資料缺一不可,請您詳填。\n"
+ "若您無 E-Mail,請您輸入 x 採無信箱認證。\n"
+ "但注意若無 E-Mail 很有可能被退回註冊。\n");
while (1) {
email[0] = 0;
@@ -1090,7 +1148,7 @@ toregister(char *email)
// before long waiting, alert user
move(18, 0); clrtobot();
- outs("正在確認 email, 請稍候...\n");
+ outs("正在確認 E-Mail,請稍候...\n");
doupdate();
email_count = emaildb_check_email(email);
@@ -1098,14 +1156,14 @@ toregister(char *email)
if (email_count < 0) {
move(15, 0); clrtobot();
move(17, 0);
- outs("email 認證系統發生問題, 請稍後再試,或輸入 x 採手動認證。\n");
+ outs("email 認證系統發生問題, 請稍後再試,或輸入 x 採無信箱認證。\n");
pressanykey();
return;
} else if (email_count >= EMAILDB_LIMIT) {
move(15, 0); clrtobot();
move(17, 0);
- outs("指定的 E-Mail 已註冊過多帳號, 請使用其他 E-Mail, 或輸入 x 採手動認證\n");
- outs("但注意手動認證通常會花上數天以上的時間。\n");
+ outs("指定的 E-Mail 已註冊過多帳號, 請使用其他 E-Mail,或輸入 x 採無信箱認證。\n");
+ outs("但注意若無 E-Mail 很有可能被退回註冊。\n");
pressanykey();
} else {
#endif
@@ -1126,8 +1184,8 @@ toregister(char *email)
move(17, 0);
outs("指定的 E-Mail 不正確。可能你輸入的是免費的Email,\n");
outs("或曾有使用者以本 E-Mail 認證後被取消資格。\n\n");
- outs("若您無 E-Mail 請輸入 x 由站長手動認證,\n");
- outs("但注意手動認證通常會花上數天以上的時間。\n");
+ outs("若您無 E-Mail 請輸入 x 採無信箱認證,\n");
+ outs("但注意若無 E-Mail 很有可能被退回註冊。\n");
pressanykey();
}
}
@@ -1137,20 +1195,14 @@ toregister(char *email)
emaildb_update_email(cuser.userid, email) < 0) {
move(15, 0); clrtobot();
move(17, 0);
- outs("email 認證系統發生問題, 請稍後再試,或輸入 x 採手動認證。\n");
+ outs("E-Mail 認證系統發生問題,請稍後再試,或輸入 x 採無信箱認證。\n");
pressanykey();
return;
}
#endif
REGFORM2:
- if (strcasecmp(email, "x") == 0) { /* 手動認證 */
- if (!create_regform_request())
+ if (!create_regform_request(email))
vmsg("註冊申請單建立失敗。請至 " BN_BUGREPORT " 報告。");
- } else {
- // register by mail or mobile
- pwcuRegSetTemporaryJustify("<Email>", email);
- email_justify(cuser_ref);
- }
}
int
@@ -1180,14 +1232,13 @@ u_register(void)
vs_hdr("註冊單尚在處理中");
move(3, 0);
prints(" 您的註冊申請單尚在處理中(處理順位: %d),請耐心等候\n\n", i);
- outs(" * 如果您之前曾使用 email 等認證方式通過註冊認證但又看到此訊息,\n"
+ outs(" * 如果您之前曾通過註冊認證但又看到此訊息,\n"
" 代表您的認證由於資料不完整已被取消 (由於建立新看板的流程中\n"
" 有驗證板主註冊資料的程序,若您最近有申請開新看板中則屬此項)\n\n"
" * 如果您已收到註冊碼卻看到這個畫面,代表您在使用 Email 註冊後\n"
" " ANSI_COLOR(1;31) "又另外申請了站長直接人工審核的註冊申請單。"
ANSI_RESET "\n"
- " 進入人工審核程序後 Email 註冊碼自動失效,要等到審核完成\n"
- " (會多花很多時間,數天到數週是正常的) ,所以請耐心等候。\n\n");
+ " 審核完成需要數天到數週 ,請耐心等候,謝謝。\n\n");
vmsg("您的註冊申請單尚在處理中");
return FULLUPDATE;
}
@@ -2528,8 +2579,11 @@ m_register(void)
char genbuf[200];
if (dashs(FN_REQLIST) <= 0) {
+ clear();
+ move(b_lines-3, 0);
outs("目前並無新註冊資料");
- return XEASY;
+ pressanykey();
+ return 0;
}
fn = fopen(FN_REQLIST, "r");
assert(fn);
diff --git a/mbbsd/stuff.c b/mbbsd/stuff.c
index cc43f5b1..3a1eb0b8 100644
--- a/mbbsd/stuff.c
+++ b/mbbsd/stuff.c
@@ -24,6 +24,48 @@ setbdir(char *buf, const char *boardname)
(currmode & MODE_DIGEST ? fn_mandex : str_dotdir));
}
+static int *
+_set_ptype(int *ptype, int type) {
+ if (ptype) {
+ *ptype = type;
+ }
+ return NULL;
+}
+
+/**
+ * 給定文章標題 title,傳回指到主題的部分的指標。
+ * @param title
+ */
+const char*
+subject_ex(const char *title, int *ptype)
+{
+ do {
+ if (str_case_starts_with(title, str_reply)) {
+ title += strlen(str_reply);
+ ptype = _set_ptype(ptype, SUBJECT_REPLY);
+ } else if (str_case_starts_with(title, str_forward)) {
+ title += strlen(str_forward);
+ ptype = _set_ptype(ptype, SUBJECT_FORWARD);
+#ifdef USE_LEGACY_FORWARD
+ } else if (str_starts_with(title, str_legacy_forward)) {
+ title += strlen(str_legacy_forward);
+ ptype = _set_ptype(ptype, SUBJECT_FORWARD);
+#endif
+ } else {
+ ptype = _set_ptype(ptype, SUBJECT_NORMAL);
+ break;
+ }
+ if (*title == ' ')
+ title ++;
+ } while (1);
+ return title;
+}
+
+const char *
+subject(const char *title) {
+ return subject_ex(title, NULL);
+}
+
int
is_uBM(const char *list, const char *id)
{
@@ -407,6 +449,12 @@ void FREE(void *ptr)
#endif
+unsigned
+DBCS_StringHash(const char *s)
+{
+ return fnv1a_32_dbcs_strcase(s, FNV1_32_INIT);
+}
+
static int
MonthDay(int m, int leap)
{
diff --git a/mbbsd/syspost.c b/mbbsd/syspost.c
index 701f01a0..eff2e708 100644
--- a/mbbsd/syspost.c
+++ b/mbbsd/syspost.c
@@ -119,10 +119,8 @@ post_violatelaw2(const char *crime, const char *police, const char *reason, cons
ANSI_COLOR(1;35) "%s" ANSI_RESET "行為,\n"
"違反本站站規,處以" ANSI_COLOR(1;35) "%s" ANSI_RESET
",特此公告\n\n\n%s\n",
- police, crime, reason, result, memo ? memo : "");
-
- if (!strstr(police, "警察")) {
- post_msg(BN_POLICELOG, title, msg, "[" BBSMNAME "法院]");
+ cuser.userid, crime, reason, result, memo ? memo : "");
+ post_msg(BN_SECURITY, title, msg, "[" BBSMNAME2 "法院]");
snprintf(msg, sizeof(msg),
ANSI_COLOR(1;32) "%s" ANSI_RESET "判決:\n"
@@ -131,9 +129,7 @@ post_violatelaw2(const char *crime, const char *police, const char *reason, cons
"違反本站站規,處以" ANSI_COLOR(1;35) "%s" ANSI_RESET
",特此公告\n\n\n%s\n",
"站務警察", crime, reason, result, memo ? memo : "");
- }
-
- post_msg("ViolateLaw", title, msg, "[" BBSMNAME "法院]");
+ post_msg(BN_POLICELOG, title, msg, "[" BBSMNAME2 "法院]");
}
void
diff --git a/mbbsd/talk.c b/mbbsd/talk.c
index cecdb1b2..ef430e42 100644
--- a/mbbsd/talk.c
+++ b/mbbsd/talk.c
@@ -4,10 +4,10 @@
#define QCAST int (*)(const void *, const void *)
static char * const sig_des[] = {
- "", "交談", "", "五子棋", "象棋", "暗棋", "圍棋", "黑白棋", "六子旗",
+ "", "交談", "",/* "五子棋", "象棋", "暗棋", "圍棋", "黑白棋", "六子旗",*/
};
static char * const withme_str[] = {
- "談天", "五子棋", "", "象棋", "暗棋", "圍棋", "黑白棋", "六子旗", NULL
+ "談天"/*, "五子棋", "", "象棋", "暗棋", "圍棋", "黑白棋", "六子旗"*/, NULL
};
#define MAX_SHOW_MODE 7
@@ -23,7 +23,7 @@ typedef struct pickup_t {
} pickup_t;
// If you want to change this, you have to change shm structure and shmctl.c
-#define PICKUP_WAYS 8
+#define PICKUP_WAYS 5
static char * const fcolor[11] = {
NULL, ANSI_COLOR(36), ANSI_COLOR(32), ANSI_COLOR(1;32),
@@ -110,7 +110,9 @@ modestring(const userinfo_t * uentp, int simple)
word = ModeTypeTable[mode];
fri_stat = friend_stat(currutmp, uentp);
+ /*大兔:107.05.20 BRsBBS 1.3.2 站長看不到動態*/
if (!(HasUserPerm(PERM_SYSOP) || HasUserPerm(PERM_SEECLOAK)) &&
+ (HasUserPerm(PERM_SYSOP) && !(fri_stat & HFM)) &&
((uentp->invisible || (fri_stat & HRM)) &&
!((fri_stat & HFM) && (fri_stat & HRM))))
return notonline;
@@ -128,7 +130,7 @@ modestring(const userinfo_t * uentp, int simple)
snprintf(modestr, sizeof(modestr), "回應呼叫");
}
else if (!mode && *uentp->chatid == 3)
- snprintf(modestr, sizeof(modestr), "水球準備中");
+ snprintf(modestr, sizeof(modestr), "水球正在灌水");
else if (
#ifdef NOKILLWATERBALL
uentp->msgcount > 0
@@ -141,7 +143,7 @@ modestring(const userinfo_t * uentp, int simple)
{"", "一", "兩", "三", "四", "五",
"六", "七", "八", "九"};
snprintf(modestr, sizeof(modestr),
- "中%s顆水球", cnum[(int)(uentp->msgcount)]);
+ "中了%s顆水球", cnum[(int)(uentp->msgcount)]);
} else
snprintf(modestr, sizeof(modestr), "不行了 @_@");
else if (!mode)
@@ -159,9 +161,9 @@ modestring(const userinfo_t * uentp, int simple)
else
snprintf(modestr, sizeof(modestr),
"%s %s", word, getuserid(uentp->destuid));
- } else if (mode == CHESSWATCHING) {
+ } /*else if (mode == CHESSWATCHING) {
snprintf(modestr, sizeof(modestr), "觀棋");
- } else if (mode != PAGE && mode != TQUERY)
+ }*/ else if (mode != PAGE && mode != TQUERY)
return word;
else
snprintf(modestr, sizeof(modestr),
@@ -506,10 +508,10 @@ my_query(const char *uident)
// ------------------------------------------------------------
- prints("《 五子棋 》%5d 勝 %5d 敗 %5d 和 "
+ /*prints("《 五子棋 》%5d 勝 %5d 敗 %5d 和 "
"《象棋戰績》%5d 勝 %5d 敗 %5d 和\n",
muser.five_win, muser.five_lose, muser.five_tie,
- muser.chc_win, muser.chc_lose, muser.chc_tie);
+ muser.chc_win, muser.chc_lose, muser.chc_tie);*/
showplans_userec(&muser);
@@ -1360,10 +1362,10 @@ my_talk(userinfo_t * uin, int fri_stat, char defact)
outc('\n');
}
}
- move(4, 0);
+ /*move(4, 0);
outs("要和他(她) (T)談天(F)五子棋"
- "(C)象棋(D)暗棋(G)圍棋(R)黑白棋(6)六子旗");
- getdata(5, 0, " (N)沒事找錯人了?[N] ", genbuf, 4, LCECHO);
+ "(C)象棋(D)暗棋(G)圍棋(R)黑白棋(6)六子旗");*/
+ getdata(5, 0, "要和他(她) (T)談天 (N)沒事找錯人了?[N] ", genbuf, 4, LCECHO);
}
switch (*genbuf) {
@@ -1371,7 +1373,7 @@ my_talk(userinfo_t * uin, int fri_stat, char defact)
case 't':
uin->sig = SIG_TALK;
break;
- case 'f':
+ /*case 'f':
lockreturn(M_FIVE, LOCK_THIS);
uin->sig = SIG_GOMO;
break;
@@ -1391,7 +1393,7 @@ my_talk(userinfo_t * uin, int fri_stat, char defact)
break;
case 'r':
uin->sig = SIG_REVERSI;
- break;
+ break;*/
default:
return;
}
@@ -1418,10 +1420,10 @@ my_talk(userinfo_t * uin, int fri_stat, char defact)
close(sock);
currutmp->sockactive = NA;
- if (uin->sig == SIG_CHC || uin->sig == SIG_GOMO ||
+ /*if (uin->sig == SIG_CHC || uin->sig == SIG_GOMO ||
uin->sig == SIG_GO || uin->sig == SIG_REVERSI ||
uin->sig == SIG_CONN6)
- ChessEstablishRequest(msgsock);
+ ChessEstablishRequest(msgsock);*/
vkey_attach(msgsock);
while ((ch = vkey()) != I_OTHERDATA) {
@@ -1441,7 +1443,7 @@ my_talk(userinfo_t * uin, int fri_stat, char defact)
if (c == 'y') {
switch (uin->sig) {
- case SIG_DARK:
+ /*case SIG_DARK:
main_dark(msgsock, uin);
break;
case SIG_GOMO:
@@ -1458,7 +1460,7 @@ my_talk(userinfo_t * uin, int fri_stat, char defact)
break;
case SIG_CONN6:
connect6(msgsock, CHESS_MODE_VERSUS);
- break;
+ break;*/
case SIG_TALK:
default:
ccw_talk(msgsock, currutmp->destuid);
@@ -1931,11 +1933,11 @@ draw_pickup(int drawall, pickup_t * pickup, int pickup_way,
{
char *msg_pickup_way[PICKUP_WAYS] = {
"嗨! 朋友", "網友代號", "網友動態", "發呆時間", "來自何方",
- " 五子棋 ", " 象棋 ", " 圍棋 ",
+ /*" 五子棋 ", " 象棋 ", " 圍棋 ",*/
};
char *MODE_STRING[MAX_SHOW_MODE] = {
- "故鄉", "好友描述", "五子棋戰績", "象棋戰績", "象棋等級分", "圍棋戰績",
- "暗棋戰績",
+ "故鄉", "好友描述",/* "五子棋戰績", "象棋戰績", "象棋等級分", "圍棋戰績",
+ "暗棋戰績",*/
};
char pagerchar[6] = "* -Wf";
@@ -2076,23 +2078,28 @@ draw_pickup(int drawall, pickup_t * pickup, int pickup_way,
if(fcolor[state])
snprintf(xuid, sizeof(xuid), "%s%s",
fcolor[state], uentp->userid);
-
- vs_cols(ulist_coldef, cols, ULISTCOLS,
- // Columns data (9 params)
- num,
- pager,
- fcolor[state] ? xuid : uentp->userid,
- uentp->nickname,
- descript(show_mode, uentp, uentp->pager & !(friend & HRM),
- description, sizeof(description)),
+ /*大兔:107.05.20 BRsBBS 1.3.2 新增這裡,因為找不到更源頭的地方,只好在這裡動手腳...
+ 直接做一個判斷式,隱身者沒加站長好友就不顯示。08.03微修正判斷式,多揭露了動態、違規、發呆時間。*/
+ if(uentp->invisible == true && !(friend & HFM)){
+ vs_cols(ulist_coldef, cols, ULISTCOLS,num,"!","<Hidden>","隱身了","",modestring(uentp, 0),mind,idlestr,"");
+ }else{
+ vs_cols(ulist_coldef, cols, ULISTCOLS,
+ // Columns data (9 params)
+ num,
+ pager,
+ fcolor[state] ? xuid : uentp->userid,
+ uentp->nickname,
+ descript(show_mode, uentp, uentp->pager & !(friend & HRM),
+ description, sizeof(description)),
#if defined(SHOWBOARD) && defined(DEBUG)
- show_board ? (uentp->brc_id == 0 ? "" :
- getbcache(uentp->brc_id)->brdname) :
+ show_board ? (uentp->brc_id == 0 ? "" :
+ getbcache(uentp->brc_id)->brdname) :
#endif
- modestring(uentp, 0),
- mind,
- idlestr,
- "");
+ modestring(uentp, 0),
+ mind,
+ idlestr,
+ "");
+ }
}
}
@@ -2421,10 +2428,10 @@ userlist(void)
case 'b': /* broadcast */
if (HasUserFlag(UF_FRIEND) || HasUserPerm(PERM_SYSOP)) {
- char genbuf[60]="[廣播]";
+ char genbuf[60];
char ans[4];
- if (!getdata(0, 0, "廣播訊息:", genbuf+6, 54, DOECHO))
+ if (!getdata(0, 0, "廣播訊息:", genbuf, 60, DOECHO))
break;
if (!getdata(0, 0, "確定廣播? [N]",
@@ -2443,7 +2450,7 @@ userlist(void)
msg.pid = currpid;
strlcpy(msg.userid, cuser.userid, sizeof(msg.userid));
snprintf(msg.last_call_in, sizeof(msg.last_call_in),
- "[廣播]%s", genbuf);
+ ANSI_COLOR(1;33;41) "[廣播] %s" ANSI_RESET, genbuf);
for (i = 0; i < SHM->UTMPnumber; ++i) {
// XXX why use sorted list?
// can we just scan uinfo with proper checking?
@@ -2499,12 +2506,12 @@ userlist(void)
case 'S': /* 顯示好友描述 */
#ifdef HAVE_DARK_CHESS_LOG
- show_mode = (show_mode+1) % MAX_SHOW_MODE;
+ //show_mode = (show_mode+1) % MAX_SHOW_MODE;
#else
- show_mode = (show_mode+1) % (MAX_SHOW_MODE - 1);
+ //show_mode = (show_mode+1) % (MAX_SHOW_MODE - 1);
#endif
#ifdef CHESSCOUNTRY
- if (show_mode == 2)
+ /*if (show_mode == 2)
user_query_mode = 1;
else if (show_mode == 3 || show_mode == 4)
user_query_mode = 2;
@@ -2513,13 +2520,16 @@ userlist(void)
else if (show_mode == 6)
user_query_mode = 4;
else
- user_query_mode = 0;
+ user_query_mode = 0;*/
#endif /* defined(CHESSCOUNTRY) */
- redrawall = redraw = 1;
+ //redrawall = redraw = 1;
break;
case 'u': /* 線上修改資料 */
- if (HasUserPerm(PERM_ACCOUNTS|PERM_SYSOP)) {
+ /*大兔:107.05.20 BRsBBS 1.3.2 新增這裡,hidden的禁止進一步操作*/
+ if(HasUserPerm(PERM_SYSOP) && uentp->invisible == true && !(fri_stat & HFM)){
+ break;
+ }else if (HasUserPerm(PERM_ACCOUNTS|PERM_SYSOP)) {
int id;
userec_t muser;
vs_hdr("使用者設定");
@@ -2532,8 +2542,8 @@ userlist(void)
pressanykey();
}
redrawall = redraw = 1;
+ break;
}
- break;
case Ctrl('S'):
break;
@@ -2541,36 +2551,49 @@ userlist(void)
case KEY_RIGHT:
case KEY_ENTER:
case 't':
- if (HasBasicUserPerm(PERM_LOGINOK)) {
- if (uentp->pid != currpid &&
- strcmp(uentp->userid, cuser.userid) != 0) {
+ /*大兔:107.05.20 BRsBBS 1.3.2 新增這裡,hidden的禁止進一步操作*/
+ if(HasUserPerm(PERM_SYSOP) && uentp->invisible == true && !(fri_stat & HFM)){
+ break;
+ }else if (HasBasicUserPerm(PERM_LOGINOK)) {
+ if (uentp->pid != currpid &&
+ strcmp(uentp->userid, cuser.userid) != 0) {
move(1, 0);
clrtobot();
move(3, 0);
my_talk(uentp, fri_stat, 0);
redrawall = redraw = 1;
- }
+ }
+ break;
}
- break;
+
case 'K':
if (HasUserPerm(PERM_ACCOUNTS|PERM_SYSOP)) {
my_kick(uentp);
redrawall = redraw = 1;
}
break;
+
case 'w':
- if (call_in(uentp, fri_stat))
+ /*大兔:107.05.20 BRsBBS 1.3.2 新增這裡,hidden的禁止進一步操作*/
+ if(HasUserPerm(PERM_SYSOP) && uentp->invisible == true && !(fri_stat & HFM)){
+ break;
+ }else if (call_in(uentp, fri_stat)){
redrawall = redraw = 1;
- break;
+ break;
+ }
+
case 'a':
- if (HasBasicUserPerm(PERM_LOGINOK) && !(fri_stat & IFH)) {
+ /*大兔:107.05.20 BRsBBS 1.3.2 新增這裡,hidden的禁止進一步操作*/
+ if(HasUserPerm(PERM_SYSOP) && uentp->invisible == true && !(fri_stat & HFM)){
+ break;
+ }else if (HasBasicUserPerm(PERM_LOGINOK) && !(fri_stat & IFH)) {
if (vans("確定要加入好友嗎 [N/y]") == 'y') {
friend_add(uentp->userid, FRIEND_OVERRIDE,uentp->nickname);
friend_load(FRIEND_OVERRIDE, 0);
}
redrawall = redraw = 1;
+ break;
}
- break;
case 'd':
if (HasBasicUserPerm(PERM_LOGINOK) && (fri_stat & IFH)) {
@@ -2609,14 +2632,20 @@ userlist(void)
*/
case 'g':
- if (HasBasicUserPerm(PERM_LOGINOK) && cuser.money) {
+ /*大兔:107.05.20 BRsBBS 1.3.2 新增這裡,hidden的禁止進一步操作*/
+ if(HasUserPerm(PERM_SYSOP) && uentp->invisible == true && !(fri_stat & HFM)){
+ break;
+ }else if (HasBasicUserPerm(PERM_LOGINOK) && cuser.money) {
give_money_ui(uentp->userid);
redrawall = redraw = 1;
+ break;
}
- break;
case 'm':
- if (HasBasicUserPerm(PERM_LOGINOK)) {
+ /*大兔:107.05.20 BRsBBS 1.3.2 新增這裡,hidden的禁止進一步操作*/
+ if(HasUserPerm(PERM_SYSOP) && uentp->invisible == true && !(fri_stat & HFM)){
+ break;
+ }else if (HasBasicUserPerm(PERM_LOGINOK)) {
char userid[IDLEN + 1];
strlcpy(userid, uentp->userid, sizeof(userid));
vs_hdr("寄 信");
@@ -2624,14 +2653,19 @@ userlist(void)
my_send(userid);
setutmpmode(LUSERS);
redrawall = redraw = 1;
+ break;
}
- break;
case 'q':
- my_query(uentp->userid);
- setutmpmode(LUSERS);
- redrawall = redraw = 1;
- break;
+ /*大兔:107.05.20 BRsBBS 1.3.2 新增這裡,hidden的禁止進一步操作*/
+ if(HasUserPerm(PERM_SYSOP) && uentp->invisible == true && !(fri_stat & HFM)){
+ break;
+ }else{
+ my_query(uentp->userid);
+ setutmpmode(LUSERS);
+ redrawall = redraw = 1;
+ break;
+ }
case 'Q':
t_query();
@@ -2640,18 +2674,24 @@ userlist(void)
break;
case 'c':
- if (HasBasicUserPerm(PERM_LOGINOK)) {
+ /*大兔:107.05.20 BRsBBS 1.3.2 新增這裡,hidden的禁止進一步操作*/
+ if(HasUserPerm(PERM_SYSOP) && uentp->invisible == true && !(fri_stat & HFM)){
+ break;
+ }else if (HasBasicUserPerm(PERM_LOGINOK)) {
chicken_query(uentp->userid);
redrawall = redraw = 1;
+ break;
}
- break;
case 'l':
- if (HasBasicUserPerm(PERM_LOGINOK)) {
+ /*大兔:107.05.20 BRsBBS 1.3.2 新增這裡,hidden的禁止進一步操作*/
+ if(HasUserPerm(PERM_SYSOP) && uentp->invisible == true && !(fri_stat & HFM)){
+ break;
+ }else if (HasBasicUserPerm(PERM_LOGINOK)) {
t_display();
redrawall = redraw = 1;
+ break;
}
- break;
case 'h':
t_showhelp();
@@ -2962,7 +3002,7 @@ talkreply(void)
uip->destuip = currutmp - &SHM->uinfo[0];
if (buf[0] == 'y')
switch (sig) {
- case SIG_DARK:
+ /*case SIG_DARK:
main_dark(a, uip);
break;
case SIG_GOMO:
@@ -2979,7 +3019,7 @@ talkreply(void)
break;
case SIG_CONN6:
connect6(a, CHESS_MODE_VERSUS);
- break;
+ break;*/
case SIG_TALK:
default:
ccw_talk(a, currutmp->destuid);
@@ -2992,7 +3032,7 @@ talkreply(void)
currstat = currstat0;
}
-int
+/*int
t_chat(void)
{
static time4_t lastEnter = 0;
@@ -3043,6 +3083,6 @@ t_chat(void)
syncnow();
lastEnter = now;
- return ccw_chat(fd);
-}
+ return (fd);
+}*/
diff --git a/mbbsd/twofa.c b/mbbsd/twofa.c
new file mode 100644
index 00000000..c066a3c0
--- /dev/null
+++ b/mbbsd/twofa.c
@@ -0,0 +1,266 @@
+#include "bbs.h"
+
+#ifdef USE_2FALOGIN
+
+bool isFileExist();
+
+static void twoFA_GenCode(char *buf, size_t len)
+{
+ const char * const chars = "1234567890";
+
+ for (int i = 0; i < len; i++)
+ buf[i] = chars[random() % strlen(chars)];
+ buf[len] = '\0';
+}
+
+static void twoFA_GenRevCode(char *buf, size_t len)
+{
+ const char * const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+
+ for (int i = 0; i < len; i++)
+ buf[i] = chars[random() % strlen(chars)];
+ buf[len] = '\0';
+}
+
+static const char *
+twoFA_Send(char *user, char *authcode)
+{
+ int ret, code = 0;
+ char uri[320] = "",buf[200];
+
+ snprintf(uri, sizeof(uri), "/%s?user=%s"
+#ifdef BETA
+ "&beta=true&code=%s"
+#endif
+ , IBUNNY_2FA_URI, user
+#ifdef BETA
+ , authcode
+#endif
+ );
+
+ THTTP t;
+ thttp_init(&t);
+ snprintf(buf, sizeof(buf), "Bearer %s", IBUNNY_API_KEY);
+ ret = thttp_get(&t, IBUNNY_SERVER, uri, IBUNNY_SERVER, buf);
+ if (!ret)
+ code = thttp_code(&t);
+ thttp_cleanup(&t);
+
+ if (ret)
+ return "系統錯誤,您可以使用復原碼或稍後再試。(Error code: 2FA-S-001)";
+
+ if (code != 200){
+ snprintf(buf, sizeof(buf), "系統錯誤,您可以使用復原碼或稍後再試。(Error code: 2FA-S-%3d)", code);
+ return buf;
+ }
+
+ return NULL;
+}
+
+int twoFA_main(char *user)
+{
+ FILE *fp;
+ const char *msg = NULL;
+ char code[7], rev_code[9], code_input[9], buf[200], buf2[200], genbuf[3];
+
+#if defined(DETECT_CLIENT) && defined(USE_TRUSTDEV)
+ extern Fnv32_t client_code;
+ int i, trusted = 0, count=0;
+
+ setuserfile(buf, "trust.device");
+ snprintf(buf2, sizeof(buf2), "%8.8X\n", client_code);
+ if(fp = fopen(buf, "r+")){
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (!strcmp(buf, buf2)){
+ trusted = 1;
+ }
+ count++;
+ }
+ fclose(fp);
+ if(trusted == 1)
+ return NULL; //Success
+ }
+#endif
+
+ clear();
+ vs_hdr2(" 兩步驟認證 ", " 輸入驗證碼");
+
+ twoFA_GenCode(code, 6);
+
+ setuserfile(buf, "2fa.code");
+ if (!(fp = fopen(buf, "w"))){
+ move(1,0);
+ outs("系統錯誤,您可以使用復原碼或稍後再試。(Error code: 2FA-F-001)");
+ getdata(2, 0, "使用復原碼? (y/N) ",genbuf, 3, LCECHO);
+ if (genbuf[0] != 'y') {
+ return -1;
+ }
+ }
+ fprintf(fp,"%s", code);
+ fclose(fp);
+
+#ifdef BETA
+ msg = twoFA_Send(user,code);
+#else
+ msg = twoFA_Send(user,NULL);
+#endif
+ if (msg){
+ move(1,0);
+ outs(msg);
+ getdata(2, 0, "使用復原碼? (y/N) ",genbuf, 3, LCECHO);
+ if (genbuf[0] != 'y') {
+ return -1;
+ }
+ }
+ unlink(buf);
+
+ move(2,0); clrtobot();
+ outs("驗證碼將直接被發送到iBunny\n");
+ outs("一共為六位數字\n");
+
+ for (int i = 3; i > 0; i--) {
+ if (i < 3) {
+ char buf[80];
+ snprintf(buf, sizeof(buf), ANSI_COLOR(1;31) "驗證碼錯誤,您還有 %d 次機會。" ANSI_RESET, i);
+ move(6, 0);
+ outs(buf);
+ }
+ code_input[0] = '\0';
+ getdata(5, 0, "請輸入驗證碼:", code_input,
+ sizeof(code_input), DOECHO);
+
+ size_t length = strlen(code_input);
+ if(length == 6){
+ if (!strcmp(code, code_input)){
+#if defined(DETECT_CLIENT) && defined(USE_TRUSTDEV)
+ clear();
+ vs_hdr2(" 兩步驟認證 ", " 設定為信任的裝置?");
+ move(2, 0);
+ outs("設定為信任的裝置下次登入就不需要驗證。\n"
+ "提請您,請不要在公用電腦上使用此功\能。");
+ getdata(5, 0, "是否將這個裝置設定為信任的裝置(y/n)? [N]",genbuf, 3, LCECHO);
+ if(genbuf[0] == 'y') {
+ setuserfile(buf, "trust.device");
+ log_filef(buf, LOG_CREAT,"%8.8X\n", client_code);
+ }
+#endif
+ return NULL; //Success
+ }
+ }else if(length == 8){
+ setuserfile(buf, "2fa.recov");
+ if (!(fp = fopen(buf, "r"))){
+ outs("系統錯誤,無法使用復原碼,請稍後再試。(Error code: 2FA-F-002)");
+ return -1;
+ }
+ fgets(rev_code, sizeof(rev_code), fp);
+ fclose(fp);
+
+ if (!strcmp(rev_code, code_input)){
+ unlink(buf);
+ move(6, 0);
+ outs(ANSI_COLOR(1;33) "使用了復原碼認證,故復原碼已失效。" ANSI_RESET);
+ return NULL; //Success
+ }
+ }
+
+ now = time(NULL);
+ setuserfile(buf, "2fa.bad");
+ log_filef(buf, LOG_CREAT,"%s 第%d次兩步驟驗證失敗,IP位置:%s。\n",Cdate(&now), 4 - i , fromhost);
+ log_filef("2fa.bad", LOG_CREAT,"%s %s %s (%d/3)\n",Cdate(&now), cuser.userid, fromhost, 4 - i);
+ }
+ return -1;
+}
+
+int twoFA_genRecovCode()
+{
+ FILE *fp;
+ char rev_code[9], buf[200], genbuf[3];
+ char *user = cuser.userid;
+ char passbuf[PASSLEN];
+
+ vs_hdr("兩步驟認證復原碼");
+ if(!(HasUserFlag(UF_TWOFA_LOGIN))){
+ vmsg("請先在個人設定開啟兩步驟認證。");
+ return 0;
+ }
+
+ setuserfile(buf, "2fa.recov");
+ move(1, 0);
+
+ if(isFileExist(buf) == true){
+ outs("您已經有一組復原碼,每個帳戶只能擁有一組。\n");
+ outs("當您繼續操作產生新復原碼,原有的就會失效。");
+ getdata(4, 0, "確定繼續嗎? (y)繼續 [N]取消 ",genbuf, 3, LCECHO);
+ if (genbuf[0] != 'y') {
+ vmsg("取消操作");
+ return 0;
+ }
+ }
+
+ move(1, 0); clrtobot();
+ outs("復原碼是當您無法使用兩步驟認證時,\n");
+ outs("可以在輸入驗證碼時輸入復原碼取回帳戶存取權。\n");
+ outs("另外,另外每一組復原碼只能使用一次,使用後就會失效。\n\n");
+
+ outs("以下操作需要先確認您的身份。\n");
+ getdata(6, 0, MSG_PASSWD, passbuf, PASS_INPUT_LEN + 1, PASSECHO);
+ passbuf[8] = '\0';
+ if (!(checkpasswd(cuser.passwd, passbuf))){
+ vmsg("密碼錯誤!");
+ return 0;
+ }
+
+ twoFA_GenRevCode(rev_code, 8);
+ if (!(fp = fopen(buf, "w"))){
+ vmsg("系統錯誤,請稍後再試。(Error code: 2FA-F-003)");
+ return 0;
+ }
+ fprintf(fp,"%s", rev_code);
+ fclose(fp);
+
+ move(10,0);
+ outs("您的復原碼是:" ANSI_COLOR(1));
+ outs(rev_code);
+ outs(ANSI_RESET "\n\n");
+ outs("復原碼共計8碼,會出現英文字母I、L、O,不會出現數字0、1。");
+ mvouts(b_lines - 2,12,ANSI_COLOR(1;33) "請您記下復原碼並妥善保管,離開本視窗後就不能再重新查詢。" ANSI_RESET);
+
+ pressanykey();
+ return 0;
+}
+
+#endif //USE_2FALOGIN
+
+#if defined(DETECT_CLIENT) && defined(USE_TRUSTDEV)
+
+int twoFA_RemoveTrust()
+{
+ FILE *fp;
+ char rev_code[9], buf[200], genbuf[3];
+ char *user = cuser.userid;
+ char passbuf[PASSLEN];
+
+ setuserfile(buf, "trust.device");
+ if(isFileExist(buf) == false){
+ vmsg("沒有在任何裝置上設定為信任。");
+ return 0;
+ }
+
+ clear();
+ vs_hdr("撤銷信任裝置");
+
+ move(2, 0);
+ outs("設定為信任的裝置在登入時不需要驗證。\n");
+ outs("要撤銷掉所有目前設定為信任的裝置嗎?\n");
+ getdata(5, 0, "確定繼續嗎? (y)繼續 [N]取消 ",genbuf, 3, LCECHO);
+ if (genbuf[0] != 'y') {
+ vmsg("取消操作");
+ return 0;
+ }
+
+ unlink(buf);
+ vmsg("已經撤銷所有信任的裝置");
+ return 0;
+}
+
+#endif //defined(DETECT_CLIENT) && defined(USE_TRUSTDEV)
\ No newline at end of file
diff --git a/mbbsd/user.c b/mbbsd/user.c
index 0ed458b6..a154a9cc 100644
--- a/mbbsd/user.c
+++ b/mbbsd/user.c
@@ -39,10 +39,12 @@ kill_user(int num, const char *userid)
if(!userid || num<=0 ) return -1;
sethomepath(src, userid);
- snprintf(dst, sizeof(dst), "tmp/%s", userid);
friend_delete_all(userid, FRIEND_ALOHA);
- if (dashd(src) && Rename(src, dst) == 0) {
- snprintf(src, sizeof(src), "/bin/rm -fr home/%c/%s >/dev/null 2>&1", userid[0], userid);
+ if (dashd(src)) {
+ snprintf(src, sizeof(src),
+ "/bin/tar zcvf backup/user_%s.tgz home/%c/%s >/dev/null 2>&1;"
+ "/bin/rm -fr home/%c/%s >/dev/null 2>&1"
+ , userid, userid[0], userid, userid[0], userid);
system(src);
}
@@ -160,10 +162,13 @@ int u_cancelbadpost(void)
return 0;
}
+int getBoardTax(char *userid);
+char *isBrdTaxPaid(char *userid);
+
void
user_display(const userec_t * u, int adminmode)
{
- int diff = 0;
+ int diff = 0, tax;
char genbuf[200];
// Many fields are available (and have sync issue) in user->query,
@@ -175,7 +180,10 @@ user_display(const userec_t * u, int adminmode)
" " ANSI_COLOR(1;30;45) " 使 用 者" " 資 料 "
" " ANSI_RESET " " ANSI_COLOR(30;41) "┴┬┴┬┴┬" ANSI_RESET
"\n");
- prints("\t代號暱稱: %s (%s)\n", u->userid, u->nickname);
+ prints("\t代號暱稱: %s (%s)\n\n", u->userid, u->nickname);
+
+ /* 以下資料本人及PERM_SYSOP、PERM_ACCOUNTS看得見 */
+ if(adminmode && HasUserPerm(PERM_SYSOP|PERM_ACCOUNTS) || !(adminmode) && strcmp(u->userid, cuser.userid) == 0){
prints("\t真實姓名: %s", u->realname);
#if FOREIGN_REG_DAY > 0
prints(" %s%s",
@@ -204,28 +212,16 @@ user_display(const userec_t * u, int adminmode)
genbuf[diff] = '-';
prints("\t帳號權限: %s\n", genbuf);
prints("\t認證資料: %s\n", u->justify);
- }
-
+ }
sethomedir(genbuf, u->userid);
prints("\t私人信箱: %d 封 (購買信箱: %d 封)\n",
get_num_records(genbuf, sizeof(fileheader_t)),
u->exmailbox);
- prints("\t使用記錄: " STR_LOGINDAYS " %d " STR_LOGINDAYS_QTY
- ,u->numlogindays);
- prints(" / 文章 %d 篇\n", u->numposts);
-
- if (adminmode) {
- prints("\t最後上線: %s (掛站時每日增加) / %s\n",
- Cdate(&u->lastlogin), u->lasthost);
- } else {
- diff = (now - login_start_time) / 60;
- prints("\t停留期間: %d 小時 %2d 分\n",
- diff / 60, diff % 60);
+ outc('\n');
}
-
- /* Thor: 想看看這個 user 是那些板的板主 */
- if (u->userlevel >= PERM_BM) {
+ /* 以上資料本人及PERM_SYSOP、PERM_BOARD看得見 */
+ if (u->userlevel >= PERM_BM && adminmode && HasUserPerm(PERM_SYSOP|PERM_BOARD) || u->userlevel >= PERM_BM && !(adminmode) && strcmp(u->userid, cuser.userid) == 0) {
int i;
boardheader_t *bhdr;
@@ -238,12 +234,38 @@ user_display(const userec_t * u, int adminmode)
}
}
outc('\n');
- }
- // conditional fields
+#ifdef USE_BOARDTAX
+ outs("\t納稅狀況: ");
+ tax = getBoardTax(u->userid);
+ if(tax == 0)
+ outs("不須繳納\n");
+ else{
+ char *paid = isBrdTaxPaid(u->userid);
+ if(paid == 0)
+ outs("本月尚未繳納\n");
+ else
+ prints("%s",paid);
+ }
+ outc('\n');
+#endif
+ }
+
+ prints("\t文章數量: %d 篇", u->numposts);
#ifdef ASSESS
- prints("\t退文數目: %u\n", (unsigned int)u->badpost);
+ prints(" (退文: %u篇)", (unsigned int)u->badpost);
#endif // ASSESS
+ prints("\n");
+
+ if (adminmode) {
+ prints("\t最後上線: %s (掛站時每日增加) / %s\n",
+ Cdate(&u->lastlogin), u->lasthost);
+ } else {
+ diff = (now - login_start_time) / 60;
+ prints("\t停留期間: %d 小時 %2d 分\n",
+ diff / 60, diff % 60);
+ }
+ prints("\t" STR_LOGINDAYS ": %d" STR_LOGINDAYS_QTY "\n",u->numlogindays);
#ifdef CHESSCOUNTRY
{
@@ -309,6 +331,39 @@ user_display(const userec_t * u, int adminmode)
}
}
+int
+list_user_board(void){
+ char userid[IDLEN+1];
+ int i, j=0;
+ boardheader_t *bhdr;
+
+ vs_hdr2(" 土地管理局 ", " 查詢使用者擔任的板主");
+ usercomplete("請輸入要設定的ID ", userid);
+ if (!is_validuserid(userid)){
+ vmsg("查無ID");
+ return 0;
+ }
+ move(1,0);clrtobot();
+ prints("查詢ID : %s\n",userid);
+ outs("擔任板主: ");
+ for (i = num_boards(), bhdr = bcache; i > 0; i--, bhdr++) {
+ if ( is_uBM(bhdr->BM, userid)) {
+ outs(bhdr->brdname);
+ outc(' ');
+ j=1;
+ }
+ }
+ outc('\n');
+ if(j == 0){
+ clear();
+ vmsg("所查的ID沒有擔任板主");
+ return 0;
+ }else{
+ mvouts(b_lines-1,0,"列出完成");
+ pressanykey();
+ }
+}
+
void
mail_violatelaw(const char *crime, const char *police, const char *reason, const char *result)
{
@@ -429,10 +484,16 @@ void Customize(void)
UF_ADBANNER_USONG,
UF_REJ_OUTTAMAIL,
UF_DEFBACKUP,
- UF_SECURE_LOGIN,
+ UF_SECURE_LOGIN,
+#ifdef USE_IBUNNY_NOTILOGIN
+ UF_NOTIFY_LOGIN,
+#endif
+#ifdef USE_2FALOGIN
+ UF_TWOFA_LOGIN,
+#endif
UF_FAV_ADDNEW,
UF_FAV_NOHILIGHT,
- UF_NO_MODMARK ,
+ UF_NO_MODMARK,
UF_COLORED_MODMARK,
#ifdef DBCSAWARE
UF_DBCS_AWARE,
@@ -454,7 +515,13 @@ void Customize(void)
"ADBANNER 顯示使用者心情點播(需開啟動態看板)",
"MAIL 拒收站外信",
"BACKUP 預設備份信件與其它記錄", //"與聊天記錄",
- "LOGIN 只允許\使用安全連線(ex, ssh)登入",
+ "LOGIN 只允許\使用安全連線(ex, ssh)登入",
+#ifdef USE_IBUNNY_NOTILOGIN
+ "NOTI_LOGIN 帳號被登入時發送通知 (需搭配iBunny)",
+#endif
+#ifdef USE_2FALOGIN
+ "2FA_LOGIN 使用兩步驟驗證登入 (需搭配iBunny)",
+#endif
"MYFAV 新板自動進我的最愛",
"MYFAV 單色顯示我的最愛",
"MODMARK 隱藏文章修改符號(推文/修文) (~)",
@@ -617,6 +684,111 @@ static void set_chess(const char *name, int y,
*p_tie = atoi(p);
}
+int
+userPass_change(userec_t x, int adminmode, int unum)
+{
+ int i = 0, fail = 0;
+ char buf[STRLEN], genbuf[200];
+
+ clear();
+ vs_hdr2(" " BBSNAME " ", " 修改密碼");
+
+ move(2,0);
+ prints("正在修改%s的密碼...\n\n",x.userid);
+ if (!adminmode) {
+ outs("以下操作需要先確認您的身份。\n");
+ getdata(5, 0, MSG_PASSWD, buf, PASS_INPUT_LEN + 1, PASSECHO);
+ buf[8] = '\0';
+ if (!(checkpasswd(x.passwd, buf))){
+ vmsg("密碼錯誤!");
+ return 0;
+ }
+ }
+ move(4,0);clrtobot();
+ if (!getdata(4, 0, "請設定新密碼:", buf, PASS_INPUT_LEN + 1,PASSECHO)) {
+ vmsg("密碼設定取消, 繼續使用舊密碼");
+ return 0;
+ }
+ strlcpy(genbuf, buf, PASSLEN);
+
+ move(6, 0);
+ outs("請注意設定密碼只有前八個字元有效,超過的將自動忽略。");
+
+ getdata(5, 0, "請檢查新密碼:", buf, PASS_INPUT_LEN + 1, PASSECHO);
+ if (strncmp(buf, genbuf, PASSLEN)) {
+ vmsg("新密碼確認失敗, 無法設定新密碼");
+ return 0;
+ }
+ buf[8] = '\0';
+ strlcpy(x.passwd, genpasswd(buf), sizeof(x.passwd));
+
+ // for admin mode, do verify after.
+ if (adminmode)
+ {
+ FILE *fp;
+ char witness[3][IDLEN+1], title[100];
+ int uid;
+ for (i = 0; i < 3; i++) {
+ if (!getdata(7 + i, 0, "請輸入協助證明之使用者:",
+ witness[i], sizeof(witness[i]), DOECHO)) {
+ outs("\n不輸入則無法更改\n");
+ return 0;
+ } else if (!(uid = searchuser(witness[i], NULL))) {
+ outs("\n查無此使用者\n");
+ return 0;
+ } else {
+ userec_t atuser;
+ passwd_sync_query(uid, &atuser);
+ if (!(atuser.userlevel & PERM_LOGINOK)) {
+ outs("\n使用者未通過認證,請重新輸入。\n");
+ i--;
+ } else if (atuser.numlogindays < 6*30) {
+ outs("\n" STR_LOGINDAYS "未超過 180,請重新輸入\n");
+ i--;
+ }
+ // Adjust upper or lower case
+ strlcpy(witness[i], atuser.userid, sizeof(witness[i]));
+ }
+ }
+
+ if (i < 3 || vans(msg_sure_ny) != 'y')
+ return 0;
+
+ sprintf(title, "%s 的密碼重設通知 (by %s)",x.userid, cuser.userid);
+ unlink("etc/updatepwd.log");
+ if(! (fp = fopen("etc/updatepwd.log", "w")))
+ {
+ move(b_lines-1, 0); clrtobot();
+ outs("系統錯誤: 無法建立通知檔,請至 " BN_BUGREPORT " 報告。");
+ return 0;
+ }
+
+ fprintf(fp, "%s 要求密碼重設:\n"
+ "見證人為 %s, %s, %s",
+ x.userid, witness[0], witness[1], witness[2] );
+ fclose(fp);
+
+ post_file(BN_SECURITY, title, "etc/updatepwd.log", "[系統安全局]");
+ mail_id(x.userid, title, "etc/updatepwd.log", cuser.userid);
+ for(i=0; i<3; i++)
+ {
+ mail_id(witness[i], title, "etc/updatepwd.log", cuser.userid);
+ }
+ }
+
+ passwd_sync_update(unum, &x);
+
+ if (!adminmode){
+ vmsg("已修改密碼,請重新登入。");
+ kick_all(x.userid);
+ }else{
+ kick_all(x.userid);
+ vmsg("已修改密碼。");
+ }
+
+ return 0;
+}
+
void
uinfo_query(const char *orig_uid, int adminmode, int unum)
{
@@ -663,9 +835,9 @@ uinfo_query(const char *orig_uid, int adminmode, int unum)
ans = vans(adminmode ?
"(1)改資料(2)密碼(3)權限(4)砍帳(5)改ID(6)寵物(7)審判(8)退文(M)信箱 [0]結束 " :
- "請選擇 (1)修改資料 (2)設定密碼 (C)個人化設定 [0]結束 ");
+ "請選擇 (1)修改資料 (2)設定密碼 (C)個人化設定 (M)信箱 [0]結束 ");
- if (ans > '2' && ans != 'c' && !adminmode)
+ if (ans > '2' && ans != 'c' && ans != 'm' && !adminmode)
ans = '0';
if (ans == '1' || ans == '3' || ans == 'm') {
@@ -696,10 +868,7 @@ uinfo_query(const char *orig_uid, int adminmode, int unum)
case 'm':
while (1) {
- getdata_str(y, 0,
- adminmode ? "E-Mail (站長變更不需認證): " :
- "電子信箱 [變動要重新認證]:",
- buf, sizeof(x.email), DOECHO, x.email);
+ getdata_str(y, 0,"電子信箱:", buf, sizeof(x.email), DOECHO, x.email);
strip_blank(buf, buf);
@@ -744,10 +913,6 @@ uinfo_query(const char *orig_uid, int adminmode, int unum)
#endif
strlcpy(x.email, buf, sizeof(x.email));
mail_changed = 1;
-
- // XXX delregcodefile 會看 cuser.userid...
- if (!adminmode)
- delregcodefile();
}
break;
@@ -980,97 +1145,7 @@ uinfo_query(const char *orig_uid, int adminmode, int unum)
break;
case '2':
- y = 19;
- if (!adminmode) {
- if (!getdata(y++, 0, "請輸入原密碼:", buf, PASS_INPUT_LEN + 1,
- PASSECHO) ||
- !checkpasswd(x.passwd, buf)) {
- outs("\n\n您輸入的密碼不正確\n");
- fail++;
- break;
- }
- }
- if (!getdata(y++, 0, "請設定新密碼:", buf, PASS_INPUT_LEN + 1,
- PASSECHO)) {
- outs("\n\n密碼設定取消, 繼續使用舊密碼\n");
- fail++;
- break;
- }
- strlcpy(genbuf, buf, PASSLEN);
-
- move(y+1, 0);
- outs("請注意設定密碼只有前八個字元有效,超過的將自動忽略。");
-
- getdata(y++, 0, "請檢查新密碼:", buf, PASS_INPUT_LEN + 1, PASSECHO);
- if (strncmp(buf, genbuf, PASSLEN)) {
- outs("\n\n新密碼確認失敗, 無法設定新密碼\n");
- fail++;
- break;
- }
- buf[8] = '\0';
- strlcpy(x.passwd, genpasswd(buf), sizeof(x.passwd));
-
- // for admin mode, do verify after.
- if (adminmode)
- {
- FILE *fp;
- char witness[3][IDLEN+1], title[100];
- int uid;
- for (i = 0; i < 3; i++) {
- if (!getdata(y + i, 0, "請輸入協助證明之使用者:",
- witness[i], sizeof(witness[i]), DOECHO)) {
- outs("\n不輸入則無法更改\n");
- fail++;
- break;
- } else if (!(uid = searchuser(witness[i], NULL))) {
- outs("\n查無此使用者\n");
- fail++;
- break;
- } else {
- userec_t atuser;
- passwd_sync_query(uid, &atuser);
- if (!(atuser.userlevel & PERM_LOGINOK)) {
- outs("\n使用者未通過認證,請重新輸入。\n");
- i--;
- } else if (atuser.numlogindays < 6*30) {
- outs("\n" STR_LOGINDAYS "未超過 180,請重新輸入\n");
- i--;
- }
- // Adjust upper or lower case
- strlcpy(witness[i], atuser.userid, sizeof(witness[i]));
- }
- }
- y += 3;
-
- if (i < 3 || fail > 0 || vans(msg_sure_ny) != 'y')
- {
- fail++;
- break;
- }
- pre_confirmed = 1;
-
- sprintf(title, "%s 的密碼重設通知 (by %s)",x.userid, cuser.userid);
- unlink("etc/updatepwd.log");
- if(! (fp = fopen("etc/updatepwd.log", "w")))
- {
- move(b_lines-1, 0); clrtobot();
- outs("系統錯誤: 無法建立通知檔,請至 " BN_BUGREPORT " 報告。");
- fail++; pre_confirmed = 0;
- break;
- }
-
- fprintf(fp, "%s 要求密碼重設:\n"
- "見證人為 %s, %s, %s",
- x.userid, witness[0], witness[1], witness[2] );
- fclose(fp);
-
- post_file(BN_SECURITY, title, "etc/updatepwd.log", "[系統安全局]");
- mail_id(x.userid, title, "etc/updatepwd.log", cuser.userid);
- for(i=0; i<3; i++)
- {
- mail_id(witness[i], title, "etc/updatepwd.log", cuser.userid);
- }
- }
+ userPass_change(x,adminmode,unum);
break;
case '3':
@@ -1199,10 +1274,10 @@ uinfo_query(const char *orig_uid, int adminmode, int unum)
orig_uid, x.userid, cuser.userid);
post_msg(BN_SECURITY, title, title, "[系統安全局]");
}
- if (mail_changed && !adminmode) {
+ /*if (mail_changed && !adminmode) {
// wait registration.
x.userlevel &= ~(PERM_LOGINOK | PERM_POST);
- }
+ }*/
if (tokill) {
kick_all(x.userid);
diff --git a/mbbsd/vote.c b/mbbsd/vote.c
index aa79a445..2c484044 100644
--- a/mbbsd/vote.c
+++ b/mbbsd/vote.c
@@ -144,7 +144,7 @@ b_nonzeroNum(const char *buf)
}
static void
-vote_report(const char *bname, const char *post_bname, const char *fname)
+vote_report(const char *votename, const char *post_bname, const char *fname)
{
int bid;
char buf[PATHLEN];
@@ -152,8 +152,8 @@ vote_report(const char *bname, const char *post_bname, const char *fname)
setbpath(buf, post_bname);
stampfile(buf, &header);
- strlcpy(header.owner, "[馬路探子]", sizeof(header.owner));
- snprintf(header.title, sizeof(header.title), "[%s] 看板 選情報導", bname);
+ strlcpy(header.owner, "[投票系統]", sizeof(header.owner));
+ snprintf(header.title, sizeof(header.title), "%s", votename);
Copy(fname, buf);
@@ -169,7 +169,7 @@ b_result_one(const vote_buffer_t *vbuf, boardheader_t * fh, int *total)
{
FILE *cfp, *tfp, *xfp;
int lockfd;
- char *bname;
+ char *bname, votename[200];
char inbuf[ANSILINELEN];
int *counts;
int people_num;
@@ -227,10 +227,14 @@ b_result_one(const vote_buffer_t *vbuf, boardheader_t * fh, int *total)
// Report: title part
setbfile(buf, bname, vbuf->title);
if ((xfp = fopen(buf, "r"))) {
- fgets(inbuf, sizeof(inbuf), xfp);
- fprintf(tfp, "%s\n◆ 投票名稱: %s\n\n", msg_separator, inbuf);
- fclose(xfp);
- }
+ fgets(inbuf, sizeof(inbuf), xfp);
+ snprintf(votename, sizeof(votename), "[開票] %s", inbuf);
+ fclose(xfp);
+ }else{
+ snprintf(votename, sizeof(votename), "[開票] %s看板投票開票結果", bname);
+ }
+ fprintf(tfp, "作者: [投票系統] 看板: %s\n標題: %s\n時間: %s\n", bname, votename, ctime4(&now));
+ fprintf(tfp, "%s\n◆ 投票名稱: %s\n\n", msg_separator, votename);
fprintf(tfp, "%s\n◆ 投票中止於: %s\n\n\n◆ 票選題目描述:\n\n",
msg_separator, Cdate(&closetime));
fh->vtime = now;
@@ -267,9 +271,9 @@ b_result_one(const vote_buffer_t *vbuf, boardheader_t * fh, int *total)
fclose(tfp);
// Post to boards
- vote_report(bname, bname, b_report);
+ vote_report(votename, bname, b_report);
if (!(fh->brdattr & (BRD_NOCOUNT|BRD_HIDE))) { // from ptt2 local modification
- vote_report(bname, BN_RECORD, b_report);
+ vote_report(votename, BN_RECORD, b_report);
}
// Reuse the report file, and append old results after it.
@@ -806,14 +810,6 @@ user_vote_one(const vote_buffer_t *vbuf, const char *bname)
setbfile(buf, bname, vbuf->desc);
more(buf, YEA);
-#ifdef USE_VOTE_CAPTCHA
- const char *captcha_msg = remote_captcha();
- if (captcha_msg != NULL) {
- vmsg(captcha_msg);
- return FULLUPDATE;
- }
-#endif
-
vs_hdr("投票箱");
setbfile(buf, bname, vbuf->control);
diff --git a/mbbsd/voteboard.c b/mbbsd/voteboard.c
index 4c269cb3..e454396f 100644
--- a/mbbsd/voteboard.c
+++ b/mbbsd/voteboard.c
@@ -63,11 +63,6 @@ do_voteboardreply(const fileheader_t * fhdr)
return;
}
- if (currmode & MODE_SELECT) {
- vmsg("請先退出搜尋模式後再進行連署。");
- return;
- }
-
if (CheckVoteRestrictionFile(fhdr, sizeof(genbuf), genbuf))
{
vmsgf("未達投票資格限制: %s", genbuf);
diff --git a/pttbbs.mk b/pttbbs.mk
index 3fcd85ec..2fa2270b 100644
--- a/pttbbs.mk
+++ b/pttbbs.mk
@@ -73,6 +73,11 @@ PTT_CFLAGS+= -DDEBUG
PTT_CXXFLAGS+= -DDEBUG
.endif
+# 若有定義 BETA, 則在 CFLAGS內定義 BETA
+.if defined(BETA)
+PTT_CFLAGS+= -DBETA
+.endif
+
.if defined(GDB)
CFLAGS:= -g -O0 $(PTT_CFLAGS)
CXXFLAGS:= -g -O0 $(PTT_CXXFLAGS)
diff --git a/sample/etc/editable b/sample/etc/editable
index 22acfaa2..858b0cfd 100644
--- a/sample/etc/editable
+++ b/sample/etc/editable
@@ -10,6 +10,7 @@
etc/Welcome 歡迎畫面
etc/Logout 出站畫面
etc/goodbye 錯誤登入訊息
+etc/Maintain 系統維護畫面
etc/sysop 站長名單
etc/mail_account_sysop 帳號站長信箱收信列表
etc/mail_account_sysop_desc 帳號站長信箱收信說明
@@ -28,6 +29,7 @@ etc/Welcome_login.4
# ----------------------------------------
# 一般檔案
# ----------------------------------------
+etc/maintainConfig 系統維護參數(檔案存在就開啟維護模式)
etc/crosspost.txt 過度轉錄開的罰單通知信
etc/myfav_defaults 我的最愛預設列表
etc/post.note 發文注意事項
diff --git a/sample/pttbbs.conf b/sample/pttbbs.conf
index 61dbe773..a8740f79 100644
--- a/sample/pttbbs.conf
+++ b/sample/pttbbs.conf
@@ -1,14 +1,12 @@
-/* $Id: pttbbs.conf,v 1.14 2003/07/06 03:41:08 in2 Exp $ */
-
/* 定義 BBS 站名位址 */
-#define BBSNAME "新批踢踢" /* 中文站名 */
-#define BBSENAME "PTT2" /* 英文站名 */
-#define MYHOSTNAME "ptt2.cc" /* 網路位址 */
-#define MYIP "140.112.30.143" /* IP位址 */
+#define BBSNAME "大兔的神密世界" /* 中文站名 */
+#define BBSENAME "BigBunny's World" /* 英文站名 */
+#define MYHOSTNAME "BunnyBBS.tk" /* 網路位址 */
+#define MYIP "114.33.186.187" /* IP位址 */
/* 定義是否查詢文章的 web 版 URL,及 URL 用的 hostname/prefix */
-#define QUERY_ARTICLE_URL /* 是否提供查詢文章 URL */
-#define URL_PREFIX "http://www.ptt.cc/bbs" /* URL prefix */
+#define QUERY_ARTICLE_URL /* 是否提供查詢文章 URL */
+#define URL_PREFIX "https://www.bunnybbs.tk/article" /* URL prefix */
/*
http://www.ptt.cc/bbs/SYSOP/M.1197864962.A.476.html
^^^^^^^^^^^^^^^^^^^^^
@@ -18,13 +16,13 @@
/* 下列資訊為系統效能,預設值為普通小系站規模 */
/* 最多註冊人數, 每個人會用掉 21 bytes 的 shared-memory */
-#define MAX_USERS (10000)
+#define MAX_USERS (100)
/* 最多同時上線人數, 每個人會用掉 3456 bytes 的 shared-memory */
-#define MAX_ACTIVE (512)
+#define MAX_ACTIVE (10)
/* 最大開板個數, 每個會用掉 6420 bytes 的 shared-memory */
-#define MAX_BOARD (1024)
+#define MAX_BOARD (128)
/* 最大 CPU負荷, 超過的時候將拒絕 login */
#define MAX_CPULOAD (300)
@@ -37,48 +35,69 @@
* BBSMNAME2 則是出現在部份選單裡,建議盡量照原格式 4 字元寬
* MONEYNAME 是錢幣的名字,建議五個字元內
*/
-#define BBSMNAME "Ptt"
-#define BBSMNAME2 "Ptt"
-#define MONEYNAME "Ptt幣"
+#define BBSMNAME "BBS"
+#define BBSMNAME2 "大兔"
+#define MONEYNAME "兔幣"
/* 定義系統資訊 */
-#define BBSUSER "bbs"
-#define BBSUID 9999
-#define BBSGID 99
+#define BBSUSER "bbs"
+#define BBSUID 9999
+#define BBSGID 99
+#define BBSHOME "/home/bbs"
/* *** 以下為預設板名 (見 include/config.h) *** */
/* 安全紀錄 */
-#define BN_SECURITY "Security"
+#define BN_SECURITY "BNY_Security"
+
/* 動態看板的家 */
-#define BN_NOTE "Note"
+#define BN_NOTE "ENG_EnvAdmin"
+
/* 紀錄 */
-#define BN_RECORD "Record"
+#define BN_RECORD "Record"
+
+/* 帳號審核紀錄 */
+#define BN_ID_RECORD "IDs_Record"
+
+/* 金融監管紀錄 */
+#define BN_FINANC "INT_FinanSup"
/* SYSOP 板 */
-#define BN_SYSOP "SYSOP"
+#define BN_SYSOP "BNY_SYSOP"
+
/* 測試板 */
-#define BN_TEST "Test"
+#define BN_TEST "Test"
+
/* 發生錯誤時建議的回報板名為此板 */
-#define BN_BUGREPORT BBSMNAME "Bug"
+#define BN_BUGREPORT "ENG_Bug"
+
/* 法律訴訟的板 */
-#define BN_LAW BBSMNAME "Law"
-/* 新手板(會自動進我的最愛) */
-#define BN_NEWBIE BBSMNAME "NewHand"
-/* 找看板(會自動進我的最愛) */
-#define BN_ASKBOARD "AskBoard"
+#define BN_LAW "JUD_Court"
+
+/* 罰單紀錄的板 */
+#define BN_POLICELOG "JUD_Violate"
+
+/* 新手板 */
+//#define BN_NEWBIE BBSMNAME "NewHand"
+
+/* 找看板 */
+//#define BN_ASKBOARD "AskBoard"
+
/* 外國板 */
-#define BN_FOREIGN BBSMNAME "Foreign"
+//#define BN_FOREIGN BBSMNAME "Foreign"
/* *** 以下為定義時會多出功能的板名 *** */
/* 若定義, 提供美工特別用板 */
-#define BN_ARTDSN "Artdsn"
+//#define BN_ARTDSN "Artdsn"
/* 若定義,該板發文不受行限或是可上傳 */
-#define BN_BBSMOVIE "BBSmovie"
+//#define BN_BBSMOVIE "BBSmovie"
+
+/* 若定義, 則以此為版名提供全站文摘 */
+//#define BN_DIGEST BBSMNAME "Digest"
// /* 若定義,則.... */
-// #define BN_WHOAMI "WhoAmI"
+//#define BN_WHOAMI "WhoAmI"
/* 若定義, 則全站所有五子棋/象棋棋譜都會紀錄在此板 */
//#define BN_FIVECHESS_LOG BBSMNAME "Five"
@@ -104,7 +123,7 @@
#define RELAY_SERVER_IP "127.0.0.1"
/* 抬頭色彩 */
-#define TITLE_COLOR "\033[0;1;37;46m"
+#define TITLE_COLOR "\033[0;1;37;42m"
/* 若定義, 則所有編輯文章最下方都會加入編輯來源.
否則只有 SYSOP板會加入來源 */
@@ -125,7 +144,7 @@
#define OUTJOBSPOOL
/* 若定義, 則不能舉辦賭盤 */
-#define NO_GAMBLE
+//#define NO_GAMBLE
/* 可動態透過 GLOBALVAR[9]調整使用者上限 */
#define DYMAX_ACTIVE
@@ -170,7 +189,7 @@
//#define COLORDATE
/* 若定義, 在使用者註冊之前, 會先顯示出該檔案, 經使用者確認後才能註冊 */
-//#define HAVE_USERAGREEMENT "etc/UserAgreement"
+#define HAVE_USERAGREEMENT "etc/UserAgreement"
//#define HAVE_USERAGREEMENT_VERSION "etc/UserAgreementVersion"
//#define HAVE_USERAGREEMENT_ACCEPTABLE "etc/UserAgreementAcceptable"
@@ -182,7 +201,7 @@
#define GUEST_DEFAULT_DBCS_NOINTRESC
/* 使用新式的 pmore (piaip's more) 代替舊式 bug 抓不完的 more 或是簡易的 minimore */
-//#define USE_PMORE
+#define USE_PMORE
/* 使用 rfork()取代 fork() . 目前只在 FreeBSD上有效 */
//#define USE_RFORK
@@ -194,7 +213,7 @@
如在 linux x86_64 下使用 HUGETLB 時需為 4MB aligned,
而在 linux ia64 下使用 HUGETLB時需為 256MB aligned.
單位為 bytes */
-//#define SHMALIGNEDSIZE (1048576*4) // 4MB for x86_64
+#define SHMALIGNEDSIZE (1048576*4) // 4MB for x86_64
/* 讓過於熱門或被鬧的版冷靜, SHM 會變大一些些 */
#define USE_COOLDOWN
@@ -202,7 +221,7 @@
/* 若定義, 則在刪除看板文章的時候, 僅會在 .DIR 中標明, 並不會將該資料
從 .DIR 中拿掉. 可以避免多項問題 (尤其是熱門看板一堆推薦及編輯時)
須配合使用 (尚未完成) */
-//#define SAFE_ARTICLE_DELETE
+#define SAFE_ARTICLE_DELETE
/* 若定義, 則在傳送水球的時候, 不會直接 kill 該程序. 理論上可以減少大
量的系統負和 */
@@ -216,12 +235,12 @@
在第一次啟動時, 您並不能定義 (否則就拿不到站長權了) .
而在設定完成後, 若您站長帳號並不叫做 SYSOP,
則可透過 NO_SYSOP_ACCOUNT 關閉該帳號, 以避免安全問題發生. */
-//#define NO_SYSOP_ACCOUNT
+// #define NO_SYSOP_ACCOUNT
/* 若定義, 則熱門看板列表會改用 shmctl utmpsortd 來計算, 而不是每
個使用者自己算. 在站上會同時有很多人同時跑去看熱門看板的時候用.
若站上並不會一瞬間很多人跑去看熱門看板, 會得到反效果. */
-//#define HOTBOARDCACHE 128
+#define HOTBOARDCACHE 128
/* 在轉信時附上的時區. 若在台灣, 中國大陸等地, 用預設的即可. */
//#define INNTIMEZONE "+0800 (CST)"
@@ -233,7 +252,7 @@
#define OLDRECOMMEND
/* 若定義, 則 guest 可推文,格式變為 IP+日期 */
-#define GUESTRECOMMEND
+//#define GUESTRECOMMEND
/* 定義幾秒內算快速推文 */
#define FASTRECMD_LIMIT (90)
@@ -245,7 +264,7 @@
#define DEFAULT_AUTOCPLOG
/* 如果 time_t 是 8 bytes的話 (如 X86_64) */
-//#define TIMET64
+#define TIMET64
/* 使用 utmpd, 在外部運算好友資料, 如果您確定這個在做什麼才開啟 */
//#define UTMPD
@@ -254,10 +273,10 @@
//#define NOFLOODING
/* 使用 daemon/fromd, 使用外部daemon紀錄上站故鄉名稱 */
-//#define FROMD
+#define FROMD
/* 若定義, 則不允許註冊 guest */
-//#define NO_GUEST_ACCOUNT_REG
+#define NO_GUEST_ACCOUNT_REG
/* 若定義為 1, 則每篇發文會寫到 log/post , 可以給分析或張爸魔一類的程式用 */
#define LOG_CONF_POST (1)
@@ -266,9 +285,6 @@
#define EMAILDB_LIMIT 5
//#define USE_REG_CAPTCHA
-//#define USE_POST_CAPTCHA_FOR_NOREG
-//#define USE_VOTE_CAPTCHA
-//#define USE_REMOTE_CAPTCHA
//#define CAPTCHA_INSERT_SERVER_ADDR "127.0.0.1:80"
//#define CAPTCHA_INSERT_HOST CAPTCHA_INSERT_SERVER_ADDR
//#define CAPTCHA_INSERT_URI "/captcha/insert"
@@ -278,4 +294,38 @@
/* 前進站畫面 */
#define INSCREEN \
-"前進站畫面 (請至 pttbbs.conf 修改您的前進站畫面)"
+"\r\n / |_ _/ \\ / / \r\n | | _ _ _ _ / / \r\n __|_ @ @ _|_ \\ \r\n _\\_ /\\ _/_ | \r\n -- -- | \r\n / _ | _ _ _ \\ \\ \r\n / / | | \\ | \r\n /_ / /_/ /_/ \r\n\r\nmeow~ welcome to bunnybbs's server~\r\n"
+
+/* 開啟退文 */
+#define ASSESS
+
+/* 留下交易記錄 */
+#define USE_RECENTPAY
+
+/* ALLPOST行為修正到最新版本 */
+//#define USE_LIVE_ALLPOST
+/*大兔:關掉此定義,因為ALLPOST不存在於大兔*/
+
+/* 修正游標的位置無法顯示任何文字的情況 */
+#define USE_PFTERM
+
+/* 停止新帳號被申請 */
+// #define NO_LOGINASNEW
+
+/* 除錯模式 */
+// #define DEBUG
+
+/* 安裝新版資源回收桶與編輯記錄 */
+#define USE_TIME_CAPSULE
+
+/* 文章最高價格 */
+#define MAX_POST_MONEY (1000)
+
+/* 新版水桶功能 */
+#define USE_NEW_BAN_SYSTEM
+
+/* 系統更新紀錄 */
+#define HAVE_SYSUPDATES
+
+/* 寄信給站長 */
+#define USE_MAIL_ACCOUNT_SYSOP
\ No newline at end of file
diff --git a/util/Makefile b/util/Makefile
index c392f744..62671e8a 100644
--- a/util/Makefile
+++ b/util/Makefile
@@ -15,7 +15,7 @@ MBBSD_OBJS= var
# 下面這些程式, 會被 compile 並且和 $(UTIL_OBJS) 聯結
CPROG_WITH_UTIL= \
boardlist post poststat \
- account deluserfile \
+ account deluserfile mmail boardtaxmail \
expire mandex broadcast \
openticket topusr \
toplazyBM writemoney \
@@ -84,7 +84,8 @@ install: $(PROGS)
.endif
clean:
- rm -f *.o shmctl $(CPROGS) $(CPROG_WITH_UTIL) $(CPROG_WITHOUT_UTIL) $(CPP_WITH_UTIL)
+ rm -f *.o $(CPROGS) $(CPROG_WITH_UTIL) $(CPROG_WITHOUT_UTIL) $(CPP_WITH_UTIL)
+ rm -f shmctl
installfiltermail:
diff --git a/util/account.c b/util/account.c
index 9f41eac6..ee8b4a80 100644
--- a/util/account.c
+++ b/util/account.c
@@ -149,7 +149,7 @@ parse_usies(const char *fn, int *act)
return 0;
}
-static int
+/*static int
output_today(struct tm *ptime, int *act, int peak_hour_login, int day_login)
{
char buf[256];
@@ -216,7 +216,7 @@ update_history(struct tm *ptime, int peak_hour, int peak_hour_login, int day_log
if ((fp = fopen("etc/history.data", "r+")) == NULL)
return 1;
- /* 最多同時上線 */
+ // 最多同時上線
if (fscanf(fp, "%d %d %d %d", &max_day_login, &max_hour_login, &max_reg, &max_online) != 4)
goto out;
@@ -360,7 +360,7 @@ update_holiday(struct tm *ptime)
strlcpy(SHM->today_is, buf, sizeof(SHM->today_is));
return 0;
-}
+}*/
int
main(/*int argc, char **argv*/)
@@ -400,30 +400,30 @@ main(/*int argc, char **argv*/)
}
/* -------------------------------------------------------------- */
- printf("上站人次統計\n");
- output_today(&tm_adjusted, act, peak_hour_login, day_login);
+ /*printf("上站人次統計\n");
+ output_today(&tm_adjusted, act, peak_hour_login, day_login);*/
/* -------------------------------------------------------------- */
- printf("歷史事件處理\n");
/* Ptt 歷史事件處理 */
- update_history(&tm_adjusted, peak_hour, peak_hour_login, day_login);
+ /*printf("歷史事件處理\n");
+ update_history(&tm_adjusted, peak_hour, peak_hour_login, day_login);*/
if (tm_now.tm_hour == 0) {
- Copy("etc/today", "etc/yesterday");
+ /*Copy("etc/today", "etc/yesterday");*/
/* system("rm -f note.dat"); */
- keeplog("etc/today", BN_RECORD, "上站人次統計", NULL);
+ //keeplog("etc/today", BN_RECORD, "上站人次統計", NULL);
keeplog(FN_MONEY, BN_SECURITY, "本日金錢往來記錄", NULL);
keeplog("etc/illegal_money", BN_SECURITY, "本日違法賺錢記錄", NULL);
keeplog("etc/osong.log", BN_SECURITY, "本日點歌記錄", NULL);
- keeplog("etc/chicken", BN_RECORD, "雞場報告", NULL);
+ //keeplog("etc/chicken", BN_RECORD, "雞場報告", NULL);
// Restore etc/yesterday because keeplog removes it.
- Copy("etc/yesterday", "etc/today");
+ //Copy("etc/yesterday", "etc/today");
snprintf(buf, sizeof(buf), "[安全報告] 使用者上線監控 [%02d/%02d:%02d]",
tm_now.tm_mon + 1, tm_now.tm_mday, tm_now.tm_hour);
- keeplog("usies", "Security", buf, "usies");
+ keeplog("usies", BN_SECURITY, buf, "usies");
// usies is removed - so we have to also delete .act
remove(act_file);
printf("[安全報告] 使用者上線監控\n");
@@ -436,8 +436,8 @@ main(/*int argc, char **argv*/)
gzip("etc/mailog", "mailog", buf);
/* Ptt 節日處理 */
- printf("節日處理\n");
- update_holiday_list(&tm_now);
+ /*printf("節日處理\n");
+ update_holiday_list(&tm_now);*/
/* Ptt 歡迎畫面處理 */
printf("歡迎畫面處理\n");
@@ -455,14 +455,14 @@ main(/*int argc, char **argv*/)
fclose(fp);
}
- if (tm_now.tm_wday == 0)
- keeplog("etc/week", BN_RECORD, "本週熱門話題", NULL);
+ /*if (tm_now.tm_wday == 0)
+ keeplog("etc/week", BN_RECORD, "本週熱門話題", NULL);
if (tm_now.tm_mday == 1)
- keeplog("etc/month", BN_RECORD, "本月熱門話題", NULL);
+ keeplog("etc/month", BN_RECORD, "本月熱門話題", NULL);
if (tm_now.tm_yday == 1)
- keeplog("etc/year", BN_RECORD, "年度熱門話題", NULL);
+ keeplog("etc/year", BN_RECORD, "年度熱門話題", NULL);*/
} else if (tm_now.tm_hour == 3 && tm_now.tm_wday == 6) {
const char fn1[] = "tmp";
const char fn2[] = "suicide";
@@ -479,7 +479,7 @@ main(/*int argc, char **argv*/)
/* Ptt reset Ptt's share memory */
printf("重設cache 與fcache\n");
- update_holiday(&tm_now);
+ //update_holiday(&tm_now);
SHM->Puptime = 0;
resolve_fcache();
diff --git a/util/bbsctl.c b/util/bbsctl.c
index 37577f67..62ba00e9 100644
--- a/util/bbsctl.c
+++ b/util/bbsctl.c
@@ -96,10 +96,13 @@ int parse_bindports_mode(const char *fn)
static int startbbs_defaults()
{
// default: start listening ports with mbbsd.
- printf("starting mbbsd by at 23, 443, 3000-3010\n");
+ /*printf("starting mbbsd by at 23, 443, 3000-3010\n");
execl(BBSHOME "/bin/mbbsd", "mbbsd", "-d", "-p23", "-p443",
"-p3000", "-p3001", "-p3002", "-p3003", "-p3004", "-p3005",
- "-p3006", "-p3007", "-p3008", "-p3009", "-p3010", NULL);
+ "-p3006", "-p3007", "-p3008", "-p3009", "-p3010", NULL);*/
+ printf("starting mbbsd by at 23\n");
+ execl(BBSHOME "/bin/mbbsd", "mbbsd", "-d", "-p23", NULL);
+ /*�酉嚗��私ort23隞亙��垢���皜祈岫銝哨��航���憿€�107.04.23*/
printf("starting daemons failed\n");
return 1;
diff --git a/util/boardtaxmail.c b/util/boardtaxmail.c
new file mode 100644
index 00000000..e2670678
--- /dev/null
+++ b/util/boardtaxmail.c
@@ -0,0 +1,33 @@
+#include "bbs.h"
+
+int main(void)
+{
+ FILE *fp, *fp2;
+ char *ptr, *id, *mn;
+ char buf[200] = "", cmd[200];
+ int i, money = 0, count=0;
+ int delayday=0, delaypay=0;
+ int tax=0, shouldpay=0, paid=0;
+ struct tm ptime;
+
+ localtime4_r(&now, &ptime);
+ i = ptime.tm_wday << 1;
+
+ if(!(fp = fopen(BBSHOME "/etc/boardtax.txt", "r+"))){
+ return 0;
+ }else{
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (!(ptr = strchr(buf, ':')))
+ continue;
+ *ptr = '\0';
+ id = buf;
+ mn = ptr + 1;
+ money = atoi(mn);
+ sprintf(cmd, BBSHOME "/bin/mmail %s \"本月看板稅開徵通知\" \"[金融管理署]\" \"" BBSHOME "/etc/boardtaxmail.txt\"", id);
+ system(cmd);
+ count++;
+ }
+ fclose(fp);
+ return 0;
+ }
+}
\ No newline at end of file
diff --git a/util/initbbs.c b/util/initbbs.c
index 3fb46dd3..363e86c1 100644
--- a/util/initbbs.c
+++ b/util/initbbs.c
@@ -4,13 +4,14 @@ static void initDir() {
Mkdir("adm");
Mkdir("boards");
Mkdir("etc");
- Mkdir("log");
Mkdir("man");
Mkdir("man/boards");
Mkdir("out");
Mkdir("tmp");
Mkdir("run");
Mkdir("jobspool");
+ Mkdir("log");
+ Mkdir("log/taxpaid");
}
static void initHome() {
@@ -104,8 +105,8 @@ static void initBoards() {
if(fp) {
memset(&b, 0, sizeof(b));
-
- strcpy(b.brdname, "SYSOP");
+
+ strcpy(b.brdname, BN_SYSOP);
strcpy(b.title, "嘰哩 ◎站長好!");
b.brdattr = BRD_POSTMASK;
b.level = 0;
@@ -126,7 +127,7 @@ static void initBoards() {
b.gid = 2;
newboard(fp, &b);
- strcpy(b.brdname, "Security");
+ strcpy(b.brdname, BN_SECURITY);
strcpy(b.title, "發電 ◎站內系統安全");
b.brdattr = 0;
b.level = PERM_SYSOP;
@@ -154,14 +155,14 @@ static void initBoards() {
b.gid = 5;
newboard(fp, &b);
- strcpy(b.brdname, "Note");
+ strcpy(b.brdname, BN_NOTE);
strcpy(b.title, "嘰哩 ◎動態看板及歌曲投稿");
b.brdattr = 0;
b.level = 0;
b.gid = 5;
newboard(fp, &b);
- strcpy(b.brdname, "Record");
+ strcpy(b.brdname, BN_RECORD);
strcpy(b.title, "嘰哩 ◎我們的成果");
b.brdattr = 0 | BRD_POSTMASK;
b.level = 0;
@@ -190,6 +191,15 @@ static void initBoards() {
b.gid = 5;
newboard(fp, &b);
+#ifdef BN_DIGEST
+ strcpy(b.brdname, BN_DIGEST);
+ strcpy(b.title, "文摘 ◎" BBSNAME "文摘 好文的收集地");
+ b.brdattr = BRD_POSTMASK;
+ b.level = PERM_SYSOP;
+ b.gid = 5;
+ newboard(fp, &b);
+#endif
+
#ifdef BN_FIVECHESS_LOG
strcpy(b.brdname, BN_FIVECHESS_LOG);
strcpy(b.title, "棋藝 ◎" BBSNAME "五子棋譜 站上對局全紀錄");
@@ -215,31 +225,31 @@ static void initMan() {
f.multi.money = 0;
f.filemode = 0;
- if((fp = fopen("man/boards/N/Note/.DIR", "w"))) {
+ if((fp = fopen("man/boards/" BN_NOTE_Alphabet "/" BN_NOTE "/.DIR", "w"))) {
strcpy(f.filename, "SONGBOOK");
strcpy(f.title, "◆ 【點 歌 歌 本】");
fwrite(&f, sizeof(f), 1, fp);
- Mkdir("man/boards/N/Note/SONGBOOK");
+ Mkdir("man/boards/" BN_NOTE_Alphabet "/" BN_NOTE "/SONGBOOK");
- strcpy(f.filename, "SYS");
- strcpy(f.title, "◆ <系統> 動態看板");
- fwrite(&f, sizeof(f), 1, fp);
- Mkdir("man/boards/N/Note/SYS");
-
strcpy(f.filename, "SONGO");
strcpy(f.title, "◆ <點歌> 動態看板");
fwrite(&f, sizeof(f), 1, fp);
- Mkdir("man/boards/N/Note/SONGO");
-
+ Mkdir("man/boards/" BN_NOTE_Alphabet "/" BN_NOTE "/SONGO");
+
+ strcpy(f.filename, "SYS");
+ strcpy(f.title, "◆ <系統> 動態看板");
+ fwrite(&f, sizeof(f), 1, fp);
+ Mkdir("man/boards/" BN_NOTE_Alphabet "/" BN_NOTE "/SYS");
+
strcpy(f.filename, "AD");
strcpy(f.title, "◆ <廣告> 動態看板");
fwrite(&f, sizeof(f), 1, fp);
- Mkdir("man/boards/N/Note/AD");
+ Mkdir("man/boards/" BN_NOTE_Alphabet "/" BN_NOTE "/AD");
strcpy(f.filename, "NEWS");
strcpy(f.title, "◆ <新聞> 動態看板");
fwrite(&f, sizeof(f), 1, fp);
- Mkdir("man/boards/N/Note/NEWS");
+ Mkdir("man/boards/" BN_NOTE_Alphabet "/" BN_NOTE "/NEWS");
fclose(fp);
}
@@ -247,8 +257,8 @@ static void initMan() {
}
static void initSymLink() {
- symlink(BBSHOME "/man/boards/N/Note/SONGBOOK", BBSHOME "/etc/SONGBOOK");
- symlink(BBSHOME "/man/boards/N/Note/SONGO", BBSHOME "/etc/SONGO");
+ symlink(BBSHOME "/man/boards/" BN_NOTE_Alphabet "/" BN_NOTE "/SONGBOOK", BBSHOME "/etc/SONGBOOK");
+ symlink(BBSHOME "/man/boards/" BN_NOTE_Alphabet "/" BN_NOTE "/SONGO", BBSHOME "/etc/SONGO");
symlink(BBSHOME "/man/boards/E/EditExp", BBSHOME "/etc/editexp");
}
@@ -270,8 +280,7 @@ int main(int argc, char **argv)
"將把 BBS 安裝在 " BBSHOME "\n\n"
"確定要執行, 請使用 initbbs -DoIt\n");
return 1;
- }
-
+ }else{
if(chdir(BBSHOME)) {
perror(BBSHOME);
exit(1);
@@ -288,4 +297,5 @@ int main(int argc, char **argv)
initHistory();
return 0;
+ }
}
diff --git a/util/mmail.c b/util/mmail.c
new file mode 100644
index 00000000..1fed188b
--- /dev/null
+++ b/util/mmail.c
@@ -0,0 +1,57 @@
+#include "bbs.h"
+
+void keeplog(FILE *fin, char *board, char *title, char *owner) {
+ fileheader_t fhdr;
+ char genbuf[256], buf[512];
+ FILE *fout;
+ int bid;
+
+ sprintf(genbuf, BBSHOME "/home/%c/%s", board[0], 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 "/home/%c/%s/.DIR", board[0], board);
+ append_record(genbuf, &fhdr, sizeof(fhdr));
+ /* XXX: bid of cache.c's getbnum starts from 1 */
+ if((bid = getbnum(board)) > 0)
+ touchbtotal(bid);
+
+}
+
+int main(int argc, char **argv)
+{
+ FILE *fp;
+
+ attach_SHM();
+ 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[1], argv[2], argv[3]);
+ return 0;
+}
diff --git a/util/pyutil/big5_gen.py b/util/pyutil/big5_gen.py
index 685f3189..40bb51fc 100755
--- a/util/pyutil/big5_gen.py
+++ b/util/pyutil/big5_gen.py
@@ -1,7 +1,6 @@
#!/usr/bin/env python
# Usage: ./big5_gen.py > big5_tbl.py
-from __future__ import print_function
import os
import tarfile
@@ -13,31 +12,31 @@ U2B_FILE = BIG5_DATA.extractfile('uao250-u2b.big5.txt')
# b2u
b2u = B2U_FILE.readlines()
-b2u = [line.strip().split(b' ')
+b2u = [line.strip().split(' ')
for line in b2u
- if line.strip().startswith(b'0x')]
+ if line.strip().startswith('0x')]
b2u = dict((int(b, 0), int(u, 0)) for (b, u) in b2u)
-print ("""#!/usr/bin/env python
+print """#!/usr/bin/env python
-""")
-print ("b2u_table = (")
+"""
+print "b2u_table = ("
for i in range(0x10000):
- print ('0x%04x,' % (i if i not in b2u else b2u[i]), end=' ')
+ print '0x%04x,' % (i if i not in b2u else b2u[i]),
if i % 10 == 9:
- print ('')
-print (")\n")
+ print ''
+print ")\n"
# u2b
u2b = U2B_FILE.readlines()
-u2b = [line.strip().split(b' ')
+u2b = [line.strip().split(' ')
for line in u2b
- if line.strip().startswith(b'0x')]
+ if line.strip().startswith('0x')]
u2b = dict((int(u, 0), int(b, 0)) for (b, u) in u2b)
-print ("u2b_table = (")
+print "u2b_table = ("
for i in range(0x10000):
- print ('0x%04x,' % (i if i not in u2b else u2b[i]), end=' ')
+ print '0x%04x,' % (i if i not in u2b else u2b[i]),
if i % 10 == 9:
- print ('')
-print (")\n")
+ print ''
+print ")\n"
diff --git a/util/shmctl.c b/util/shmctl.c
index f87bd925..e412b7ba 100644
--- a/util/shmctl.c
+++ b/util/shmctl.c
@@ -578,7 +578,7 @@ int utmpnum(int argc, char **argv)
{
(void)argc;
(void)argv;
- printf("%d.0\n", SHM->UTMPnumber);
+ printf("%d\n", SHM->UTMPnumber);
return 0;
}
diff --git a/util/xchatd.c b/util/xchatd.c
index 7322dc2d..dd5a8b80 100644
--- a/util/xchatd.c
+++ b/util/xchatd.c
@@ -2034,7 +2034,7 @@ static ChatAction party_data[] =
{"bless", "祝福", "祝福", "心想事成"},
{"board", "主機板", "把", "抓去跪主機板"},
{"bokan", "氣功\", "雙掌微合,蓄勢待發……突然間,電光乍現,對", "使出了Bo--Kan!"},
- {"bow", "鞠躬", "畢恭畢敬的向", "鞠躬"},
+ {"bow", "鞠躬", "畢躬畢敬的向", "鞠躬"},
{"box", "幕之內", "開始輪擺\式移位,對", "作肝臟攻擊"},
{"boy", "平底鍋", "從背後拿出了平底鍋,把", "敲昏了"},
{"bye", "掰掰", "向", "說掰掰!!"},