summaryrefslogtreecommitdiffstats
path: root/mbbsd
diff options
context:
space:
mode:
authorpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2007-12-10 13:43:02 +0800
committerpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2007-12-10 13:43:02 +0800
commitd1ed75451dc4644c7c6429d977fe836d367cc5d4 (patch)
treefd15f322474457011982211e9f56828bed9e4270 /mbbsd
parent73ccd0e5631c5143e53b8982401b0d7075abf266 (diff)
downloadpttbbs-d1ed75451dc4644c7c6429d977fe836d367cc5d4.tar
pttbbs-d1ed75451dc4644c7c6429d977fe836d367cc5d4.tar.gz
pttbbs-d1ed75451dc4644c7c6429d977fe836d367cc5d4.tar.bz2
pttbbs-d1ed75451dc4644c7c6429d977fe836d367cc5d4.tar.lz
pttbbs-d1ed75451dc4644c7c6429d977fe836d367cc5d4.tar.xz
pttbbs-d1ed75451dc4644c7c6429d977fe836d367cc5d4.tar.zst
pttbbs-d1ed75451dc4644c7c6429d977fe836d367cc5d4.zip
edit_post: add Smart Merge
git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@3661 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
Diffstat (limited to 'mbbsd')
-rw-r--r--mbbsd/bbs.c136
1 files changed, 131 insertions, 5 deletions
diff --git a/mbbsd/bbs.c b/mbbsd/bbs.c
index ff8a4350..cf8973ff 100644
--- a/mbbsd/bbs.c
+++ b/mbbsd/bbs.c
@@ -1,6 +1,16 @@
/* $Id$ */
#include "bbs.h"
+#ifdef EDITPOST_SMARTMERGE
+// To enable SmartMerge,
+// please get MD5 from XySSL or other systems:
+//
+// http://xyssl.org/code/source/md5/
+//
+#include "md5.h"
+#include "md5.c"
+#endif
+
#define WHEREAMI_LEVEL 16
static int recommend(int ent, fileheader_t * fhdr, const char *direct);
@@ -1293,7 +1303,42 @@ reply_post(int ent, /*const*/ fileheader_t * fhdr, const char *direct)
return do_reply(fhdr);
}
+#ifdef EDITPOST_SMARTMERGE
+
+#define MD5PFRET_OK (0)
+
+// return: 0 - ok; otherwise - fail.
static int
+md5_partial_file( char *path, size_t sz, unsigned char output[16] )
+{
+ int fd;
+ size_t n;
+ md5_context ctx;
+ unsigned char buf[1024];
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return 1;
+
+ md5_starts( &ctx );
+ while( sz > 0 &&
+ (n = read(fd, buf, sizeof(buf))) > 0 )
+ {
+ if (n > sz) n = sz;
+ md5_update( &ctx, buf, (int) n );
+ sz -= n;
+ }
+ close(fd);
+
+ if (sz > 0) // file is different
+ return 2;
+
+ md5_finish( &ctx, output );
+ return MD5PFRET_OK;
+}
+#endif // EDITPOST_SMARTMERGE
+
+int
edit_post(int ent, fileheader_t * fhdr, const char *direct)
{
char fpath[80];
@@ -1301,6 +1346,12 @@ edit_post(int ent, fileheader_t * fhdr, const char *direct)
fileheader_t postfile;
boardheader_t *bp = getbcache(currbid);
int recordTouched = 0;
+ time4_t oldmt, newmt;
+ off_t oldsz;
+
+#ifdef EDITPOST_SMARTMERGE
+ char canDoSmartMerge = 1;
+#endif // EDITPOST_SMARTMERGE
assert(0<=currbid-1 && currbid-1<MAX_BOARD);
if (strcmp(bp->brdname, GLOBAL_SECURITY) == 0)
@@ -1317,6 +1368,7 @@ edit_post(int ent, fileheader_t * fhdr, const char *direct)
strcmp(cuser.userid, STR_GUEST) == EQUSTR)
return DONOTHING;
+ // special modes (plus MODE_DIGEST?)
if( currmode & MODE_SELECT )
return DONOTHING;
@@ -1326,6 +1378,13 @@ edit_post(int ent, fileheader_t * fhdr, const char *direct)
#endif
setutmpmode(REEDIT);
+
+ // TODO 由於現在檔案都是直接蓋回原檔,
+ // 在原看板目錄開已沒有很大意義。 (效率稍高一點)
+ // 可以考慮改開在 user home dir
+ // 好處是看板的檔案數不會狂成長。 (when someone crashed)
+ // sethomedir(fpath, cuser.userid);
+ // XXX 如果你的系統有定期看板清孤兒檔,那就不用放 user home。
setbpath(fpath, currboard);
// XXX 以現在的模式,這是個 temp file
@@ -1333,24 +1392,83 @@ edit_post(int ent, fileheader_t * fhdr, const char *direct)
setdirpath(genbuf, direct, fhdr->filename);
local_article = fhdr->filemode & FILE_LOCAL;
+ // copying takes long time, add some visual effect
+ grayout_lines(0, b_lines-1, 0);
+ move(b_lines-1, 0); clrtoeol();
+ outs("正在載入檔案...");
+ refresh();
+
Copy(genbuf, fpath);
strlcpy(save_title, fhdr->title, sizeof(save_title));
+ // so far this is what we copied now...
+ oldmt = dasht(genbuf);
+ oldsz = dashs(fpath); // should be equal to genbuf(src).
+ // use fpath (dest) in case some
+ // modification was made.
do {
- time4_t oldmt, newmt;
- oldmt = dasht(genbuf);
+#ifdef EDITPOST_SMARTMERGE
+
+ unsigned char oldsum[16] = {0}, newsum[16] = {0};
+
+ // make checksum of file genbuf
+ if (canDoSmartMerge &&
+ md5_partial_file(fpath, oldsz, oldsum) != MD5PFRET_OK)
+ canDoSmartMerge = 0;
+
+#endif // EDITPOST_SMARTMERGE
if (vedit(fpath, 0, NULL) == -1)
break;
newmt = dasht(genbuf);
- if (oldmt != newmt)
+ if (newmt != oldmt)
{
- int c = 0;
move(b_lines-5, 0);
- clrtoeol();
+ clrtobot();
outs(ANSI_COLOR(1;31) "▲ 檔案已被別人修改過! ▲" ANSI_RESET"\n");
+ }
+
+#ifdef EDITPOST_SMARTMERGE
+
+ // only merge if file is enlarged and modified
+ if (newmt == oldmt || dashs(genbuf) < oldsz)
+ canDoSmartMerge = 0;
+
+ // make checksum of new file [by oldsz]
+ if (canDoSmartMerge &&
+ md5_partial_file(genbuf, oldsz, newsum) != MD5PFRET_OK)
+ canDoSmartMerge = 0;
+
+ // verify checksum
+ if (canDoSmartMerge &&
+ memcmp(oldsum, newsum, sizeof(newsum)) != 0)
+ canDoSmartMerge = 0;
+
+ if (canDoSmartMerge)
+ {
+ canDoSmartMerge = 0; // only try merge once
+ outs("進行自動合併 [Smart Merge]...\n");
+
+ // smart merge
+ if (AppendTail(genbuf, fpath, oldsz) == 0)
+ {
+ // merge ok
+ oldmt = newmt;
+ outs("合併成功\。 新修改(或推文)已併入您的文章中。\n");
+ vmsg("合併完成");
+ } else {
+ outs("自動合併失敗。 請改用人工手動編輯合併。");
+ vmsg("合併失敗");
+ }
+ }
+
+#endif // EDITPOST_SMARTMERGE
+
+ if (oldmt != newmt)
+ {
+ int c = 0;
outs("可能是您在編輯的過程中有人進行推文或修文。\n"
"您可以選擇直接覆蓋\檔案(y)、放棄(n),\n"
" 或是" ANSI_COLOR(1)"重新編輯" ANSI_RESET
@@ -1392,12 +1510,18 @@ edit_post(int ent, fileheader_t * fhdr, const char *direct)
while ((c = fgetc(src)) >= 0)
fputc(c, fp);
fclose(src);
+
+ // update oldsz, old mt records
+ oldmt = dasht(genbuf);
+ oldsz = dashs(genbuf);
}
fclose(fp);
continue;
}
}
+ // OK to save file.
+
// force to remove file first?
// unlink(genbuf);
Rename(fpath, genbuf);
@@ -1425,6 +1549,7 @@ edit_post(int ent, fileheader_t * fhdr, const char *direct)
}
break;
+
} while (1);
/* should we do this when editing was aborted? */
@@ -2133,6 +2258,7 @@ do_add_recommend(const char *direct, fileheader_t *fhdr,
int fd;
off_t sz = dashs(direct);
+ // TODO we can also check if fhdr->filename is same.
// prevent black holes
if (sz < sizeof(fileheader_t) * (ent))
{