Last active
September 19, 2018 03:59
-
-
Save holishing/1034aeec4c0a0d1ac552ab1c8cb5a721 to your computer and use it in GitHub Desktop.
test gist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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", "掰掰", "向", "說掰掰!!"}, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
diff from https://github.com/ptt/pttbbs/tree/ae32c2897c33e3a62f8fc58ced187337cd4c6fd4
to https://github.com/my1938/BRsBBS/tree/707471a27ddcb621569cccbe616267ae48d389be