summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2014-05-21 20:56:15 +0800
committerpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2014-05-21 20:56:15 +0800
commit1b3d039d6ae0775809cbff143372ec9c5565ed39 (patch)
tree2b4fe93f122d26bb795215f4be7bcba0d2a1a479
parentae4c306acdff72da05e706829e022dc0d8c3ba39 (diff)
downloadpttbbs-1b3d039d6ae0775809cbff143372ec9c5565ed39.tar
pttbbs-1b3d039d6ae0775809cbff143372ec9c5565ed39.tar.gz
pttbbs-1b3d039d6ae0775809cbff143372ec9c5565ed39.tar.bz2
pttbbs-1b3d039d6ae0775809cbff143372ec9c5565ed39.tar.lz
pttbbs-1b3d039d6ae0775809cbff143372ec9c5565ed39.tar.xz
pttbbs-1b3d039d6ae0775809cbff143372ec9c5565ed39.tar.zst
pttbbs-1b3d039d6ae0775809cbff143372ec9c5565ed39.zip
Support deletion for comments.
git-svn-id: http://opensvn.csie.org/pttbbs/trunk@6002 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
-rw-r--r--pttbbs/include/daemons.h5
-rw-r--r--pttbbs/include/proto.h6
-rw-r--r--pttbbs/mbbsd/bbs.c25
-rw-r--r--pttbbs/mbbsd/comments.c124
-rw-r--r--pttbbs/mbbsd/psb.c48
5 files changed, 182 insertions, 26 deletions
diff --git a/pttbbs/include/daemons.h b/pttbbs/include/daemons.h
index 8e5d5b28..2ba227e3 100644
--- a/pttbbs/include/daemons.h
+++ b/pttbbs/include/daemons.h
@@ -145,14 +145,15 @@ enum BRCSTORED_OPERATIONS {
enum {
COMMENTD_REQ_ADD = 1,
COMMENTD_REQ_QUERY_COUNT,
- COMMENTD_REQ_QUERY_BODY = 3,
+ COMMENTD_REQ_QUERY_BODY,
+ COMMENTD_REQ_MARK_DELETED,
};
typedef struct CommentBodyReq {
time4_t time;
time4_t ipv4;
uint32_t userref; /* user.ctime */
- uint32_t type;
+ int32_t type;
char userid[IDLEN + 1];
char msg[COMMENTLEN + 1];
} PACKSTRUCT CommentBodyReq;
diff --git a/pttbbs/include/proto.h b/pttbbs/include/proto.h
index 0e3ec112..58003099 100644
--- a/pttbbs/include/proto.h
+++ b/pttbbs/include/proto.h
@@ -182,14 +182,18 @@ void *CommentsOpen(const char *board, const char *file);
int CommentsClose(void *ctx);
int CommentsGetCount(void *ctx);
const struct CommentBodyReq *CommentsRead(void *ctx, int i);
+int CommentsDeleteFromTextFile(void *ctx, int i);
#endif
+void FormatCommentString(char *buf, size_t szbuf, int type,
+ const char *myid, int maxlength,
+ const char *msg, const char *tail);
/* psb (panty and stocking browser) */
int psb_view_edit_history(const char *base, const char *subject,
int maxrev, int current_as_base);
int psb_recycle_bin(const char *base, const char *title);
int psb_admin_edit();
-int pvcm_comment_manager(const char *board, const char *file);
+int psb_comment_manager(const char *board, const char *file);
/* chc */
void chc(int s, ChessGameMode mode);
diff --git a/pttbbs/mbbsd/bbs.c b/pttbbs/mbbsd/bbs.c
index d5530462..c36cbf4c 100644
--- a/pttbbs/mbbsd/bbs.c
+++ b/pttbbs/mbbsd/bbs.c
@@ -3134,19 +3134,8 @@ recommend(int ent, fileheader_t * fhdr, const char *direct)
Cdate_mdHM(&now));
}
-#ifdef OLDRECOMMEND
- snprintf(buf, sizeof(buf),
- ANSI_COLOR(1;31) "→ " ANSI_COLOR(33) "%s"
- ANSI_RESET ANSI_COLOR(33) ":%-*s" ANSI_RESET
- "推%s\n",
- myid, maxlength, msg, tail);
-#else
- snprintf(buf, sizeof(buf),
- "%s%s " ANSI_COLOR(33) "%s" ANSI_RESET ANSI_COLOR(33)
- ":%-*s" ANSI_RESET "%s\n",
- ctype_attr2[type], ctype[type], myid,
- maxlength, msg, tail);
-#endif // OLDRECOMMEND
+ FormatCommentString(buf, sizeof(buf), type,
+ myid, maxlength, msg, tail);
}
if (do_add_recommend(direct, fhdr, ent, buf, type) < 0)
@@ -4499,7 +4488,15 @@ manage_post(int ent, fileheader_t * fhdr, const char *direct) {
#ifdef USE_COMMENTD
case 'v':
- pvcm_comment_manager(currboard, fhdr->filename);
+ {
+ boardheader_t *bp = bp = getbcache(currbid);
+ assert(bp);
+ if (!(bp->brdattr & BRD_BM_MASK_CONTENT)) {
+ vmsg("要先開啟刪特定文字的權限。");
+ return FULLUPDATE;
+ }
+ psb_comment_manager(currboard, fhdr->filename);
+ }
break;
#endif
}
diff --git a/pttbbs/mbbsd/comments.c b/pttbbs/mbbsd/comments.c
index 954de5f8..8546478d 100644
--- a/pttbbs/mbbsd/comments.c
+++ b/pttbbs/mbbsd/comments.c
@@ -10,6 +10,36 @@ typedef struct {
CommentBodyReq *resp;
} CommentsCtx;
+void FormatCommentString(char *buf, size_t szbuf, int type,
+ const char *myid, int maxlength,
+ const char *msg, const char *tail)
+{
+#ifdef OLDRECOMMEND
+ snprintf(buf, szbuf,
+ ANSI_COLOR(1;31) "→ " ANSI_COLOR(33) "%s" ANSI_RESET
+ ANSI_COLOR(33) ":%-*s" ANSI_RESET "推%s\n",
+ myid, maxlength, msg, tail);
+#else
+ // TODO(piaip) Make bbs.c#recomment use same structure.
+ // Now we just assume they are the same.
+ const int RECTYPE_SIZE = 3;
+ static const char *ctype[RECTYPE_SIZE] = {
+ "推", "噓", "→",
+ };
+ static const char *ctype_attr2[RECTYPE_SIZE] = {
+ ANSI_COLOR(1;37),
+ ANSI_COLOR(1;31),
+ ANSI_COLOR(1;31),
+ };
+ snprintf(buf, szbuf,
+ "%s%s " ANSI_COLOR(33) "%s" ANSI_RESET ANSI_COLOR(33)
+ ":%-*s" ANSI_RESET "%s\n",
+ ctype_attr2[type], ctype[type], myid,
+ maxlength, msg, tail);
+#endif // OLDRECOMMEND
+
+}
+
int CommentsAddRecord(const char *board, const char *file,
int type, const char *msg)
{
@@ -77,7 +107,7 @@ static int CommentsLoad(CommentsCtx *c, int i)
CommentQueryRequest req = {0};
CommentBodyReq *resp;
- if (i >= c->allocated)
+ if (i >= (int)c->allocated)
CommentsAlloc(c, i);
assert(c->resp);
@@ -105,16 +135,44 @@ const struct CommentBodyReq *CommentsRead(void *ctx, int i)
{
CommentsCtx *c = (CommentsCtx *)ctx;
- while (i >= c->loaded) {
+ while (i >= (int)c->loaded) {
if (CommentsLoad(c, c->loaded++))
break;
}
- if (i >= c->loaded)
+ if (i >= (int)c->loaded)
return NULL;
return &c->resp[i];
}
+static int CommentsDelete(void *ctx, int i)
+{
+ int s, result = 0;
+ CommentsCtx *c = (CommentsCtx *)ctx;
+ if (!CommentsRead(ctx, i))
+ return -1;
+ // TODO(piaip) Notif commentd.
+ c->resp[i].type |= 0x80000000;
+
+ CommentQueryRequest req = {0};
+ req.cb = sizeof(req);
+ req.operation = COMMENTD_REQ_MARK_DELETED;
+ strlcpy(req.key.board, c->key.board, sizeof(req.key.board));
+ strlcpy(req.key.file, c->key.file, sizeof(req.key.file));
+ req.start = i;
+ s = toconnectex(COMMENTD_ADDR, 10);
+ if (s < 0) {
+ return -1;
+ }
+ if (towrite(s, &req, sizeof(req)) < 0 ||
+ toread(s, &result, sizeof(result)) < 0) {
+ close(s);
+ return -1;
+ }
+ close(s);
+ return result;
+}
+
int CommentsGetCount(void *ctx)
{
CommentsCtx *c = (CommentsCtx *)ctx;
@@ -135,4 +193,64 @@ int CommentsGetCount(void *ctx)
}
return num;
}
+
+int CommentsDeleteFromTextFile(void *ctx, int i)
+{
+ size_t pattern_len;
+ CommentsCtx *c = (CommentsCtx *)ctx;
+ const CommentBodyReq *req;
+ char buf[ANSILINELEN], pattern[ANSILINELEN];
+ char filename[PATHLEN], tmpfile[PATHLEN];
+ FILE *in, *out;
+ int found = 0;
+
+ req = CommentsRead(ctx, i);
+ if (!req || req->type < 0)
+ return -1;
+
+ setbfile(filename, c->key.board, c->key.file);
+ snprintf(tmpfile, sizeof(tmpfile), "%s.tmp", filename);
+ FormatCommentString(pattern, sizeof(pattern), req->type,
+ req->userid, 0, req->msg, "");
+ // It's stupid but we have to remove the trailing ANSI_RESET
+ // for comparison.
+ *strrchr(pattern, ESC_CHR) = 0;
+ /* Remove the trailing \n for strncmp. */
+ pattern_len = strlen(pattern);
+ // Now, try to construct and filter the message from file.
+ in = fopen(filename, "rt");
+ out = fopen(tmpfile, "wt");
+ while (fgets(buf, sizeof(buf), in)) {
+ if (strncmp(buf, pattern, pattern_len) == 0 &&
+ (buf[pattern_len] == ' ' || buf[pattern_len] == ESC_CHR) &&
+ !found) {
+ fprintf(out, "[本行文字已被 %s 刪除。]\n", cuser.userid);
+ found = 1;
+ } else {
+ fputs(buf, out);
+ }
+ }
+ fclose(out);
+ fclose(in);
+ if (found) {
+ // For everytime we have to use time capsule system.
+#ifdef USE_TIME_CAPSULE
+ int rev = timecapsule_add_revision(filename);
+#endif
+ remove(filename);
+ rename(tmpfile, filename);
+#ifdef USE_TIME_CAPSULE
+ if (rev > 0) {
+ char revfn[PATHLEN];
+ timecapsule_get_by_revision(filename, rev, revfn, sizeof(revfn));
+ log_filef(revfn, 0, "\n※ 刪除推文: %s %s <%s:%s>", cuser.userid,
+ Cdatelite(&now), req->userid, req->msg);
+ }
+#endif
+ CommentsDelete(ctx, i);
+ } else {
+ remove(tmpfile);
+ }
+ return 0;
+}
#endif
diff --git a/pttbbs/mbbsd/psb.c b/pttbbs/mbbsd/psb.c
index 769640af..96cbc22d 100644
--- a/pttbbs/mbbsd/psb.c
+++ b/pttbbs/mbbsd/psb.c
@@ -675,7 +675,7 @@ pvcm_header(void *ctx GCC_UNUSED) {
static int
pvcm_footer(void *ctx GCC_UNUSED) {
vs_footer(" 推文 ",
- " (↑/↓/PgUp/PgDn)移動 \t(q/←)跳出");
+ " (↑/↓/PgUp/PgDn)移動 (d)刪除\t(q/←)跳出");
move(b_lines-1, 0);
return 0;
}
@@ -686,21 +686,56 @@ pvcm_renderer(int i, int curr, int total, int rows GCC_UNUSED, void *ctx) {
CommentBodyReq *resp = CommentsRead(cx->cmctx, i);
if (!resp)
return 0;
+ if (resp->type < 0) {
+ prints("%c %06d <已刪>\n", (i == curr)? '>' : ' ', i + 1);
+ } else {
+ prints("%c %06d %-12.12s %s\n",
+ (i == curr) ? '>' : ' ',
+ i + 1, resp->userid, resp->msg);
+ }
+ return 0;
+}
+
+static int
+pvcm_input_processor(int key, int curr, int total GCC_UNUSED, int rows GCC_UNUSED, void *ctx) {
+ int result;
+ pvcm_ctx *cx = (pvcm_ctx*) ctx;
+
+ switch(key) {
+ case KEY_DEL:
+ case 'd':
+ if (vans("確定要刪除嗎? (y/N) ") == 'y') {
+ CommentsDeleteFromTextFile(cx->cmctx, curr);
+ }
+ return PSB_NOP;
+ }
+ return PSB_NA;
+}
- prints("%c %06d %-12.12s %s\n",
- (i == curr) ? '>' : ' ',
- i + 1, resp->userid, resp->msg);
+static int
+pvcm_welcome() {
+ clear();
+ move(2, 0);
+ vs_hdr2("刪除推文", "實驗警告");
+ outs(ANSI_COLOR(1;31)
+" 這是實驗中的刪推文界面。\n\n" ANSI_RESET
+" 提醒您: (1) 刪推文會從檔案前面開始找看起來作者跟內文相同的第一筆。\n"
+" 目前沒辦法100%%確認找到正確的位置,但起碼內文是相同的。\n\n"
+" (2) 被編輯過造成內容有變動的推文無法刪除。\n\n"
+ "");
+ doupdate();
+ pressanykey();
return 0;
}
int
-pvcm_comment_manager(const char *board, const char *file) {
+psb_comment_manager(const char *board, const char *file) {
pvcm_ctx pvcmctx = {
NULL,
};
PSB_CTX ctx = {
.curr = 0,
- .total = 0, // maxrev + pvrbctx.base_as_current,
+ .total = 0,
.header_lines = 2,
.footer_lines = 2,
.allow_pbs_version_message = 0,
@@ -708,6 +743,7 @@ pvcm_comment_manager(const char *board, const char *file) {
.header = pvcm_header,
.footer = pvcm_footer,
.renderer = pvcm_renderer,
+ .input_processor = pvcm_input_processor,
};
pvcmctx.cmctx = CommentsOpen(board, file);
if (!pvcmctx.cmctx)