summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvictor <victor@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2003-11-22 10:16:02 +0800
committervictor <victor@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2003-11-22 10:16:02 +0800
commit781c220d8e6a5034957473aa308306cc4b7c862f (patch)
tree3a72c18876e32cfb11bf445eb56ed776841bd1b7
parent7571b2c04bf5df4c4937dea135ecc0e076af990f (diff)
downloadpttbbs-781c220d8e6a5034957473aa308306cc4b7c862f.tar
pttbbs-781c220d8e6a5034957473aa308306cc4b7c862f.tar.gz
pttbbs-781c220d8e6a5034957473aa308306cc4b7c862f.tar.bz2
pttbbs-781c220d8e6a5034957473aa308306cc4b7c862f.tar.lz
pttbbs-781c220d8e6a5034957473aa308306cc4b7c862f.tar.xz
pttbbs-781c220d8e6a5034957473aa308306cc4b7c862f.tar.zst
pttbbs-781c220d8e6a5034957473aa308306cc4b7c862f.zip
merge back from fav4 braches
git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@1356 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
-rw-r--r--include/bbs.h1
-rw-r--r--include/proto.h43
-rw-r--r--mbbsd/Makefile13
-rw-r--r--mbbsd/board.c703
-rw-r--r--mbbsd/fav.c921
-rw-r--r--util/buildir.c14
6 files changed, 1246 insertions, 449 deletions
diff --git a/include/bbs.h b/include/bbs.h
index 55291091..4e7172d1 100644
--- a/include/bbs.h
+++ b/include/bbs.h
@@ -57,6 +57,7 @@
/* our header */
#include "config.h"
#include "pttstruct.h"
+#include "fav.h"
#include "common.h"
#include "perm.h"
#include "modes.h"
diff --git a/include/proto.h b/include/proto.h
index 9bed7a96..312659dd 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -79,6 +79,7 @@ int Boards();
int root_board();
void save_brdbuf(void);
void init_brdbuf(void);
+int validboard(int bid);
#ifdef CRITICAL_MEMORY
void sigfree(int);
#endif
@@ -207,6 +208,48 @@ void editlock(char *fpath);
void editunlock(char *fpath);
int iseditlocking(char *fpath, char *action);
+/* fav */
+void fav_set_old_folder(fav_t *fp);
+int get_data_number(fav_t *fp);
+int get_current_fav_level(void);
+fav_t *get_current_fav(void);
+int get_item_type(fav_type_t *ft);
+char *get_item_title(fav_type_t *ft);
+char *get_folder_title(int fid);
+void set_attr(fav_type_t *ft, int bit, char bool);
+void fav_sort_by_name(void);
+void fav_sort_by_class(void);
+int fav_load(void);
+int fav_save(void);
+void fav_remove_item(short id, char type);
+fav_type_t *getboard(short bid);
+fav_type_t *getfolder(short fid);
+char getbrdattr(short bid);
+time_t getbrdtime(short bid);
+void setbrdtime(short bid, time_t t);
+int fav_getid(fav_type_t *ft);
+void fav_tag(short id, char type, char bool);
+void move_in_current_folder(int from, int to);
+void fav_move(int from, int to);
+fav_type_t *fav_add_line(void);
+fav_type_t *fav_add_folder(void);
+fav_type_t *fav_add_board(int bid);
+void fav_remove_all_tagged_item(void);
+void fav_remove_all_tagged_item(void);
+void fav_add_all_tagged_item(void);
+void fav_remove_all_tag(void);
+void fav_set_folder_title(fav_type_t *ft, char *title);
+int fav_max_folder_level(void);
+void fav_folder_in(short fid);
+void fav_folder_out(void);
+void fav_free(void);
+int fav_v3_to_v4(void);
+int is_visible_item(fav_type_t *ft);
+int is_set_attr(fav_type_t *ft, char bit);
+void cleanup(void);
+char current_fav_at_root(void);
+fav_t *get_fav_folder(fav_type_t *ft);
+
/* friend */
void friend_edit(int type);
void friend_load();
diff --git a/mbbsd/Makefile b/mbbsd/Makefile
index b1bb69d6..911c3273 100644
--- a/mbbsd/Makefile
+++ b/mbbsd/Makefile
@@ -8,13 +8,12 @@ LDFLAGS+= -L/usr/local/lib/mysql -lmysqlclient
.endif
PROG= mbbsd
-OBJS= admin.o announce.o args.o assess.o bbs.o board.o cache.o cal.o\
- card.o chat.o chc.o chicken.o dark.o\
- edit.o friend.o gamble.o gomo.o guess.o indict.o io.o\
- kaede.o lovepaper.o mail.o mbbsd.o menu.o more.o name.o osdep.o\
- othello.o page.o read.o record.o register.o screen.o stuff.o\
- talk.o term.o topsong.o user.o vice.o vote.o xyz.o\
- voteboard.o syspost.o var.o passwd.o calendar.o
+OBJS= admin.o announce.o args.o assess.o bbs.o board.o cache.o cal.o card.o\
+ chat.o chc.o chicken.o dark.o edit.o fav.o friend.o gamble.o gomo.o\
+ guess.o indict.o io.o kaede.o lovepaper.o mail.o mbbsd.o menu.o\
+ more.o name.o osdep.o othello.o page.o read.o record.o\
+ register.o screen.o stuff.o talk.o term.o topsong.o user.o\
+ vice.o vote.o xyz.o voteboard.o syspost.o var.o passwd.o calendar.o
.SUFFIXES: .c .o
.c.o: ../include/var.h
diff --git a/mbbsd/board.c b/mbbsd/board.c
index ffcb395b..76881ab0 100644
--- a/mbbsd/board.c
+++ b/mbbsd/board.c
@@ -230,17 +230,15 @@ brc_unread(const char *fname, int bnum, const int *blist)
return 0;
}
-#define BRD_UNREAD 1
-#define BRD_FAV 2
+#define BRD_NULL 0
+#define BRD_FAV 1
+#define BRD_BOARD 2
#define BRD_LINE 4
-#define BRD_TAG 8
-#define BRD_GRP_HEADER 16
-
-#define MAX_GRP_BRD 16
-#define MAX_GRP
+#define BRD_FOLDER 8
+#define BRD_TAG 16
+#define BRD_UNREAD 32
#define FAVNB ".favnb"
-#define FAV3 ".fav3"
#define B_TOTAL(bptr) (SHM->total[(bptr)->bid - 1])
#define B_LASTPOSTTIME(bptr) (SHM->lastposttime[(bptr)->bid - 1])
@@ -250,176 +248,11 @@ typedef struct {
unsigned char myattr;
} __attribute__ ((packed)) boardstat_t;
-typedef struct {
- short bid;
- char attr;
- time_t lastvisit;
-} fav_board_t;
-
-typedef struct {
-#ifdef MEM_CHECK
- int memcheck;
-#endif
- short nDatas;
- short nAllocs;
- char nLines;
- fav_board_t b[0];
-} fav_t;
-
static boardstat_t *nbrd = NULL;
-char favchange = 0, choose_board_depth = 0;
-fav_t *fav;
+static char choose_board_depth = 0;
static short brdnum;
static char yank_flag = 1;
-int cmpfav(const void *a, const void *b)
-{
- if( *(short *)a > ((fav_board_t *)b)->bid )
- return 1;
- else if( *(short *)a == ((fav_board_t *)b)->bid )
- return 0;
- return -1;
-}
-
-fav_board_t *getfav(short bid)
-{
- int i;
- for(i = 0; i < fav->nDatas; i++)
- if(fav->b[i].bid == bid)
- break;
- return i == fav->nDatas ? NULL : &fav->b[i];
-}
-
-char getfavattr(short bid)
-{
- fav_board_t *ptr = getfav(bid);
- if( ptr == NULL )
- return 0; // default here
- else
- return ptr->attr;
-}
-
-time_t getfavtime(short bid)
-{
- fav_board_t *ptr = getfav(bid);
- if( ptr == NULL )
- return login_start_time; // default here
- else
- return ptr->lastvisit;
-}
-
-void basemovefav(int src, int des)
-{
- int i;
- fav_board_t tmp = fav->b[src];
-
- if(src < des){
- for(i = src; i < des; i++)
- fav->b[i] = fav->b[i + 1];
- }
- else{ // des < src
- for(i = src; i > des; i--)
- fav->b[i] = fav->b[i - 1];
- }
- fav->b[des] = tmp;
-
- brdnum = -1;
-}
-
-void movefav(int old, int new)
-{
- int i, src = -1, des = -1;
- favchange = 1;
-
- for(i = 0; i < fav->nDatas; i++){
- if(nbrd[old].bid == fav->b[i].bid)
- src = i;
- if(nbrd[new].bid == fav->b[i].bid)
- des = i;
- }
-
- if(src == -1 || des == -1)
- return;
- basemovefav(src, des);
-}
-
-void delfavline(int bid, int num)
-{
- int i;
-
- movefav(num, --brdnum);
- fav->nLines++;
- fav->nDatas--;
-
- for(i = 0; i < fav->nDatas; i++)
- if(fav->b[i].bid < bid)
- fav->b[i].bid++;
- for(i = 0; i < brdnum; i++)
- if(nbrd[i].bid < bid)
- nbrd[i].bid++;
-}
-
-void setfav(short bid, char attr, char mode, time_t t)
-{
- /* mode: 0: ³]¦¨ off, 1: ³]¦¨ on, 2: ¤Ï¬Û */
- fav_board_t *ptr = getfav(bid);
-
- favchange = 1;
-
- if( ptr != NULL ){
- if( mode == 2 )
- ptr->attr ^= attr;
- else if( mode )
- ptr->attr |= attr;
- else
- ptr->attr &= ~attr;
- if( t )
- ptr->lastvisit = t;
- }
- else{
- int where;
- if( fav->nDatas == fav->nAllocs ){
-#ifdef DEBUG
- vmsg("realloc fav");
-#endif
- fav = realloc(fav,
- sizeof(fav_t) +
- sizeof(fav_board_t) *
- (16 + fav->nAllocs));
- memset(&fav->b[fav->nDatas], 0, sizeof(fav_board_t) * 16);
- fav->nAllocs += 16;
- }
-
- where = fav->nDatas;
-
- if( attr & BRD_LINE ){
- fav->b[where].bid = --(fav->nLines);
- fav->b[where].attr = mode ? (BRD_LINE | BRD_FAV) : 0;
- }
- else{
- fav->b[where].bid = bid ;
- fav->b[where].attr = mode ? attr : 0;
- }
-
- fav->b[where].lastvisit = t ? t : login_start_time;
- fav->nDatas++;
- }
-}
-
-void imovefav(int old)
-{
- char buf[5];
- int new;
-
- getdata(b_lines - 1, 0, "½Ð¿é¤J·s¦¸§Ç:", buf, sizeof(buf), DOECHO);
- new = atoi(buf) - 1;
- if (new < 0 || brdnum <= new){
- vmsg("¿é¤J½d³ò¦³»~!");
- return;
- }
- movefav(old, new);
-}
-
#define BRD_OLD 0
#define BRD_NEW 1
#define BRD_END 2
@@ -445,7 +278,7 @@ void updatenewfav(int mode)
if(brd[i] == BRD_NEW){
if(bcache[i].brdname[0] && Ben_Perm(&bcache[i])){ // check the permission if the board exsits
if(mode)
- setfav(i + 1, BRD_FAV, 1, 0);
+ fav_add_board(i + 1);
brd[i] = BRD_OLD;
}
}
@@ -458,7 +291,7 @@ void updatenewfav(int mode)
for(i-- ; i < numboards; i++){
if(bcache[i].brdname[0] && Ben_Perm(&bcache[i])){
if(mode)
- setfav(i + 1, BRD_FAV, 1, 0);
+ fav_add_board(i + 1);
brd[i] = BRD_OLD;
}
else
@@ -474,78 +307,33 @@ void updatenewfav(int mode)
}
}
-void favclean(fav_t *fav){
- int i;
- boardheader_t *bptr;
-
- for(i = 0; i < fav->nDatas; i++){
- if(fav->b[i].attr & BRD_LINE)
- continue;
- bptr = &bcache[ fav->b[i].bid - 1 ];
- if(!(fav->b[i].attr & BRD_FAV) || !Ben_Perm(bptr)){
- basemovefav(i, fav->nDatas--);
- continue;
- }
+void imovefav(int old)
+{
+ char buf[5];
+ int new;
+
+ getdata(b_lines - 1, 0, "½Ð¿é¤J·s¦¸§Ç:", buf, sizeof(buf), DOECHO);
+ new = atoi(buf) - 1;
+ if (new < 0 || brdnum <= new){
+ vmsg("¿é¤J½d³ò¦³»~!");
+ return;
}
+ move_in_current_folder(old, new);
}
-void freefav(fav_t *fav){
- free(fav->b);
- free(fav);
- fav = NULL;
+inline int validboard(int bid){
+ return bcache[bid].brdname[0];
}
void load_brdbuf(void)
{
static char firsttime = 1;
- int fd;
- char fname[80];
-
- setuserfile(fname, FAV3);
- if( (fd = open(fname, O_RDONLY)) == -1 ){
- // not found.
- int i;
- char favrec;
- fav = (fav_t *)malloc(sizeof(fav_t) +
- sizeof(fav_board_t) * 16);
- fav->nDatas = 0;
- fav->nAllocs = 16;
- fav->nLines = 0;
- favchange = 1;
-
- setuserfile(fname, ".fav2");
-
- if( (fd = open(fname, O_RDONLY)) != -1 ){
- for( i = 1; i <= numboards; i++){
- if(read(fd, &favrec, sizeof(char)) < 0)
- break;
- if( (favrec & BRD_FAV) )
- setfav(i, BRD_FAV, 1, 0);
- }
- close(fd);
- }
- }
- else{
- short nDatas, i;
- char nLines;
- read(fd, &nDatas, sizeof(nDatas));
- read(fd, &nLines, sizeof(nLines));
- fav = (fav_t *)malloc(sizeof(fav_t) +
- sizeof(fav_board_t) * (nDatas + 16));
- fav->nDatas = nDatas;
- fav->nAllocs = nDatas + 16;
- fav->nLines = nLines;
- read(fd, fav->b, sizeof(fav_board_t) * fav->nDatas);
- for(i = 0; i < fav->nDatas; i++){
- if( !(fav->b[i].attr & BRD_LINE) && !bcache[fav->b[i].bid - 1].brdname[0])
- fav->b[i].attr ^= BRD_FAV;
- }
- close(fd);
+
+ if( !dashf(FAV4) ) {
+ fav_v3_to_v4();
}
+ fav_load();
updatenewfav(1);
-#ifdef MEM_CHECK
- fav->memcheck = MEM_CHECK;
-#endif
firsttime = 0;
}
@@ -558,40 +346,8 @@ init_brdbuf()
void
save_brdbuf(void)
{
- int r, w, fd;
- char fname[80];
- if( !fav )
- return;
-
- if( !favchange )
- return;
-
-#ifdef MEM_CHECK
- if( fav->memcheck != MEM_CHECK )
- return;
-#endif
-
- fav->nLines = 0;
- for( r = w = 0 ; r < fav->nDatas ; ++r ){
- if( ( fav->b[r].attr & BRD_LINE ) ||
- (fav->b[r].attr & BRD_FAV && bcache[fav->b[r].bid - 1].brdname[0])){
- if(fav->b[r].attr & BRD_LINE)
- fav->nLines--;
- fav->b[w++] = fav->b[r];
- }
- }
- fav->nDatas = w;
- setuserfile(fname, FAV3);
- if( (fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0600)) != -1 ){
- int i;
- write(fd, &fav->nDatas, sizeof(short));
- write(fd, &fav->nLines, sizeof(char));
- for(i = 0; i < fav->nDatas; i++)
- if(fav->b[i].attr & BRD_FAV)
- write(fd, &fav->b[i], sizeof(fav_board_t));
- close(fd);
- }
- freefav(fav);
+ fav_save();
+ fav_free();
}
int
@@ -721,9 +477,11 @@ addnewbrdstat(int n, int state)
//ptr->lastposttime = &(SHM->lastposttime[n]);
ptr->bid = n + 1;
- ptr->myattr = getfavattr(ptr->bid);
- if ((B_BH(ptr)->brdattr & BRD_HIDE) && state == 1)
+ ptr->myattr = state;
+ if ((B_BH(ptr)->brdattr & BRD_HIDE) && state == BRD_BOARD)
B_BH(ptr)->brdattr |= BRD_POSTMASK;
+ if (yank_flag != 0)
+ ptr->myattr &= ~BRD_FAV;
check_newpost(ptr);
return ptr;
}
@@ -735,35 +493,6 @@ cmpboardfriends(const void *brd, const void *tmp)
(B_BH((boardstat_t*)brd)->nuser));
}
-static int
-favcmpboardname(const void *brd, const void *tmp)
-{
- int b1 = ((fav_board_t *)brd)->bid;
- int b2 = ((fav_board_t *)tmp)->bid;
-
- if( b1 <= 0 || b2 <= 0 ) // ¤À¹j½u
- return 1;
-
- return strcasecmp(bcache[b1 - 1].brdname, bcache[b2 - 1].brdname);
-}
-
-static int
-favcmpboardclass(const void *brd, const void *tmp)
-{
- int b1 = ((fav_board_t *)brd)->bid;
- int b2 = ((fav_board_t *)tmp)->bid;
- int cmp;
-
- if( b1 <= 0 || b2 <= 0 ) // ¤À¹j½u
- return 1;
-
- cmp = strncasecmp(bcache[b1 - 1].title, bcache[b2 - 1].title, 4);
- if( cmp )
- return cmp;
- else
- return strcasecmp(bcache[b1 - 1].brdname, bcache[b2 - 1].brdname);
-}
-
static void
load_boards(char *key)
{
@@ -785,22 +514,60 @@ load_boards(char *key)
}
if (class_bid <= 0) {
if( yank_flag == 0 ){ // fav mode
- nbrd = (boardstat_t *)malloc(sizeof(boardstat_t) * fav->nDatas);
- for( i = 0 ; i < fav->nDatas ; ++i ){
- if( fav->b[i].attr & BRD_FAV ){
- if( fav->b[i].attr & BRD_LINE && !key[0])
- addnewbrdstat(fav->b[i].bid - 1, BRD_FAV | BRD_LINE);
+ fav_t *fav = get_current_fav();
+
+ nbrd = (boardstat_t *)malloc(sizeof(boardstat_t) * get_data_number(fav));
+ for( i = 0 ; i < fav->DataTail; ++i ){
+ int state;
+ if (!is_visible_item(&fav->favh[i]))
+ continue;
+
+ if ( !key[0] ){
+ if (get_item_type(&fav->favh[i]) == FAVT_LINE )
+ state = BRD_LINE;
+ else if (get_item_type(&fav->favh[i]) == FAVT_FOLDER )
+ state = BRD_FOLDER;
else{
- bptr = &bcache[ fav->b[i].bid - 1 ];
- if( (state = Ben_Perm(bptr)) && (!key[0] || strcasestr(bptr->title, key)))
- addnewbrdstat(fav->b[i].bid - 1, state);
- }
+ bptr = &bcache[ fav_getid(&fav->favh[i]) - 1];
+ if( Ben_Perm(bptr) )
+ state = BRD_BOARD;
+ else
+ continue;
+ if (is_set_attr(&fav->favh[i], FAVH_UNREAD))
+ state |= BRD_UNREAD;
+ }
+ }else{
+ if (get_item_type(&fav->favh[i]) == FAVT_LINE )
+ continue;
+ else if (get_item_type(&fav->favh[i]) == FAVT_FOLDER ){
+ if( strcasestr(
+ get_folder_title(fav_getid(&fav->favh[i])),
+ key)
+ )
+ state = BRD_FOLDER;
+ else
+ continue;
+ }else{
+ bptr = &bcache[ fav_getid(&fav->favh[i]) - 1];
+ if( Ben_Perm(bptr) && strcasestr(bptr->title, key))
+ state = BRD_BOARD;
+ else
+ continue;
+ if (is_set_attr(&fav->favh[i], FAVH_UNREAD))
+ state |= BRD_UNREAD;
+ }
}
+
+ if (is_set_attr(&fav->favh[i], FAVH_TAG))
+ state |= BRD_TAG;
+ addnewbrdstat(fav_getid(&fav->favh[i]) - 1, BRD_FAV | state);
}
+ if (brdnum == 0)
+ addnewbrdstat(0, 0);
byMALLOC = 0;
- needREALLOC = (fav->nDatas != brdnum);
+ needREALLOC = (get_data_number(fav) != brdnum);
}
- else{ // general case
+ else { // general case
nbrd = (boardstat_t *) MALLOC(sizeof(boardstat_t) * numboards);
for (i = 0; i < numboards; i++) {
if ((bptr = SHM->bsorted[type][i]) == NULL)
@@ -824,14 +591,14 @@ load_boards(char *key)
if (class_bid == -1)
qsort(nbrd, brdnum, sizeof(boardstat_t), cmpboardfriends);
- } else {
+ } else { /* load boards of a subclass */
int childcount = bptr->childcount;
nbrd = (boardstat_t *) malloc(childcount * sizeof(boardstat_t));
for (bptr = bptr->firstchild[type]; bptr != NULL;
bptr = bptr->next[type]) {
n = (int)(bptr - bcache);
if (!((state = Ben_Perm(bptr)) || (currmode & MODE_MENU))
- || (yank_flag == 0 && !(getfavattr(n) & BRD_FAV)) ||
+ || (yank_flag == 0 && !(getbrdattr(n) & BRD_FAV)) ||
(key[0] && !strcasestr(bptr->title, key)))
continue;
addnewbrdstat(n, state);
@@ -863,7 +630,8 @@ search_board()
clrtoeol();
CreateNameList();
for (num = 0; num < brdnum; num++)
- AddNameList(B_BH(&nbrd[num])->brdname);
+ if (yank_flag != 0 || nbrd[num].myattr & BRD_BOARD)
+ AddNameList(B_BH(&nbrd[num])->brdname);
namecomplete(MSG_SELECT_BOARD, genbuf);
FreeNameList();
toplev = NULL;
@@ -915,6 +683,18 @@ unread_position(char *dirfile, boardstat_t * ptr)
return num;
}
+static char
+get_fav_type(boardstat_t *ptr)
+{
+ if (ptr->myattr & BRD_FOLDER)
+ return FAVT_FOLDER;
+ else if (ptr->myattr & BRD_BOARD)
+ return FAVT_BOARD;
+ else if (ptr->myattr & BRD_LINE)
+ return FAVT_LINE;
+ return 0;
+}
+
static void
brdlist_foot()
{
@@ -936,7 +716,7 @@ show_brdlist(int head, int clsflag, int newflag)
move(1, 0);
outs(
" "
- "¢© ùú¡X\033[33m¡´\n"
+ "¢© ¢~¡X\033[33m¡´\n"
" ùá¡X \033[m "
"¢¨¢i\033[47m¡ó\033[40m¢i¢i¢©ùç\n"
" \033[44m ¡s¡s¡s¡s¡s¡s¡s¡s "
@@ -964,15 +744,43 @@ show_brdlist(int head, int clsflag, int newflag)
"\033[1;32m", "\033[1;33m"};
char *unread[2] = {"\33[37m \033[m", "\033[1;31m£¾\033[m"};
+ if (yank_flag == 0 && get_fav_type(&nbrd[0]) == 0){
+ move(3, 0);
+ prints(" --- ªÅ¥Ø¿ý ---");
+ return;
+ }
+
while (++myrow < b_lines) {
move(myrow, 0);
clrtoeol();
if (head < brdnum) {
ptr = &nbrd[head++];
- if(ptr->myattr & BRD_LINE){
- prints("%5d %c ------------ ------------------------------------------", head, ptr->myattr & BRD_TAG ? 'D' : ' ');
+ if (ptr->myattr & BRD_LINE){
+ if( !newflag )
+ prints("%5d %c %s------------ ------------------------------------------\033[m",
+ head,
+ ptr->myattr & BRD_TAG ? 'D' : ' ',
+ ptr->myattr & BRD_FAV ? "" : "\033[1;30m");
+ else
+ prints(" %s------------ ------------------------------------------\033[m", ptr->myattr & BRD_FAV ? "" : "\033[1;30m");
+ continue;
+ }
+ else if (ptr->myattr & BRD_FOLDER){
+ char *title = get_folder_title(ptr->bid);
+ if( !newflag )
+ prints("%5d %c %sMyFavFolder\033[m ¥Ø¿ý ¡¼%-34s\033[m",
+ head,
+ ptr->myattr & BRD_TAG ? 'D' : ' ',
+ !(cuser.uflag2 & FAVNOHILIGHT) ? "\033[1;36m" : "",
+ title);
+ else
+ prints("%6d %sMyFavFolder\033[m ¥Ø¿ý ¡¼%-34s\033[m",
+ get_data_number(get_fav_folder(getfolder(ptr->bid))),
+ !(cuser.uflag2 & FAVNOHILIGHT) ? "\033[1;36m" : "",
+ title);
continue;
}
+
if (class_bid == 1)
prints(" ");
if (!newflag) {
@@ -981,21 +789,19 @@ show_brdlist(int head, int clsflag, int newflag)
(B_BH(ptr)->brdattr & BRD_POSTMASK) ? ')' : '-',
(ptr->myattr & BRD_TAG) ? "D " :
(B_BH(ptr)->brdattr & BRD_GROUPBOARD) ? " " :
- unread[ptr->myattr & BRD_UNREAD]);
+ unread[ptr->myattr & BRD_UNREAD ? 1 : 0]);
} else {
- if (newflag) {
- if ((B_BH(ptr)->brdattr & BRD_GROUPBOARD))
- prints(" ");
- else
- prints("%6d%s", (int)(B_TOTAL(ptr)),
- unread[ptr->myattr & BRD_UNREAD]);
- }
+ if (B_BH(ptr)->brdattr & BRD_GROUPBOARD)
+ prints(" ");
+ else
+ prints("%6d%s", (int)(B_TOTAL(ptr)),
+ unread[ptr->myattr & BRD_UNREAD]);
}
if (class_bid != 1) {
prints("%s%-13s\033[m%s%5.5s\033[0;37m%2.2s\033[m"
"%-34.34s",
- ((ptr->myattr & BRD_FAV) &&
- !(cuser.uflag2 & FAVNOHILIGHT))? "\033[1;36m" : "",
+ ((!(cuser.uflag2 & FAVNOHILIGHT) &&
+ getboard(ptr->bid) != NULL))? "\033[1;36m" : "",
B_BH(ptr)->brdname,
color[(unsigned int)
(B_BH(ptr)->title[1] + B_BH(ptr)->title[2] +
@@ -1041,10 +847,10 @@ static char *choosebrdhelp[] = {
"(¼Æ¦r) ¸õ¦Ü¸Ó¶µ¥Ø",
"\01¶i¶¥«ü¥O",
"(^W) °g¸ô¤F §Ú¦b­þ¸Ì",
- "(r)(¡÷)(Rtn) ¶i¤J¦h¥\\¯à¾\\Ū¿ï³æ",
- "(q)(¡ö) ¦^¨ì¥D¿ï³æ",
- "(y/Z) §Úªº³Ì·R,©Ò¦³¬ÝªO/­q¾\\·s¶}¬ÝªO",
- "(L/K) ¥[¤J¤À¹j½u¦Ü§Úªº³Ì·R / ³Æ¥÷,²M²z§Úªº³Ì·R",
+ "(r)(¡÷)/(q)(¡ö)¶i¤J¦h¥\\¯à¾\\Ū¿ï³æ / ¦^¨ì¥D¿ï³æ",
+ "(y/Z) §Úªº³Ì·R,­q¾\\¬ÝªO,©Ò¦³¬ÝªO / ­q¾\\·s¶}¬ÝªO",
+ "(g/L) ¥[¤J¤À¹j½u / ¥Ø¿ý¦Ü§Úªº³Ì·R",
+ "(K/T) ³Æ¥÷,²M²z§Úªº³Ì·R / ­×§ï§Úªº³Ì·R¥Ø¿ý¦WºÙ",
"(v/V) ³q³q¬Ý§¹/¥þ³¡¥¼Åª",
"(S) «ö·Ó¦r¥À/¤ÀÃþ±Æ§Ç",
"(t/^T/^A/^D) ¼Ð°O¬ÝªO/¨ú®ø©Ò¦³¼Ð°O/ ±N¤w¼Ð°OªÌ¥[¤J/²¾¥X§Úªº³Ì·R",
@@ -1069,13 +875,13 @@ set_menu_BM(char *BM)
static void
choose_board(int newflag)
{
- static int num = 0;
+ static short num = 0;
boardstat_t *ptr;
int head = -1, ch = 0, currmodetmp, tmp, tmp1, bidtmp;
char keyword[13] = "";
setutmpmode(newflag ? READNEW : READBRD);
- if( fav == NULL )
+ if( get_current_fav() == NULL )
load_brdbuf();
++choose_board_depth;
brdnum = 0;
@@ -1085,7 +891,7 @@ choose_board(int newflag)
do {
if (brdnum <= 0) {
load_boards(keyword);
- if (brdnum <= 0) {
+ if (brdnum <= 0 && yank_flag > 0) {
if (keyword[0] != 0) {
mprints(b_lines - 1, 0, "¨S¦³¥ô¦ó¬ÝªO¼ÐÃD¦³¦¹ÃöÁä¦r "
"(ªO¥DÀ³ª`·N¬ÝªO¼ÐÃD©R¦W)");
@@ -1109,6 +915,8 @@ choose_board(int newflag)
}
head = -1;
}
+
+ /* reset the cursor when out of range */
if (num < 0)
num = 0;
else if (num >= brdnum)
@@ -1193,7 +1001,9 @@ choose_board(int newflag)
break;
case 't':
ptr = &nbrd[num];
- setfav(ptr->bid, BRD_TAG, 2, 0);
+ if (yank_flag == 0 && get_fav_type(&nbrd[0]) != 0) {
+ fav_tag(nbrd[num].bid, get_fav_type(ptr), 2);
+ }
ptr->myattr ^= BRD_TAG;
head = 9999;
case KEY_DOWN:
@@ -1245,15 +1055,12 @@ choose_board(int newflag)
"±Æ§Ç¤è¦¡ (1)«ö·ÓªO¦W±Æ§Ç (2)«ö·ÓÃþ§O±Æ§Ç ==> [0]¨ú®ø ",
input, sizeof(input), DOECHO);
if( input[0] == '1' )
- qsort(&fav->b, fav->nDatas, sizeof(fav_board_t),
- favcmpboardname);
+ fav_sort_by_name();
else if( input[0] == '2' )
- qsort(&fav->b, fav->nDatas, sizeof(fav_board_t),
- favcmpboardclass);
+ fav_sort_by_class();
}
else
cuser.uflag ^= BRDSORT_FLAG;
- favchange = 1;
brdnum = -1;
break;
case 'y':
@@ -1261,45 +1068,30 @@ choose_board(int newflag)
brdnum = -1;
break;
case Ctrl('D'):
- for (tmp = 0; tmp < fav->nDatas; tmp++) {
- if (fav->b[tmp].attr & BRD_TAG) {
- favchange = 1;
- fav->b[tmp].attr &= ~BRD_FAV;
- fav->b[tmp].attr &= ~BRD_TAG;
- }
- }
+ fav_remove_all_tagged_item();
brdnum = -1;
break;
case Ctrl('A'):
- for (tmp = 0; tmp < fav->nDatas; tmp++) {
- if (fav->b[tmp].attr & BRD_TAG) {
- favchange = 1;
- fav->b[tmp].attr |= BRD_FAV;
- fav->b[tmp].attr &= ~BRD_TAG;
- }
- }
+ fav_add_all_tagged_item();
brdnum = -1;
break;
case Ctrl('T'):
- for (tmp = 0; tmp < fav->nDatas; tmp++)
- fav->b[tmp].attr &= ~BRD_TAG;
- favchange = 1;
+ fav_remove_all_tag();
brdnum = -1;
break;
case Ctrl('P'):
if (class_bid != 0 &&
(HAS_PERM(PERM_SYSOP) || (currmode & MODE_MENU))) {
- for (tmp = 0; tmp < fav->nDatas; tmp++) {
- short bid = fav->b[tmp].bid;
+ for (tmp = 0; tmp < brdnum; tmp++) {
+ short bid = nbrd[tmp].bid;
boardheader_t *bh = &bcache[ bid - 1 ];
/*
if (!(fav->b[tmp].attr & BRD_TAG) || bh->gid == class_bid)
continue;
*/
- if( !(fav->b[tmp].attr & BRD_TAG) )
+ if( !(nbrd[tmp].myattr & BRD_TAG) )
continue;
- favchange = 1;
- fav->b[tmp].attr &= ~BRD_TAG;
+ nbrd[tmp].myattr &= ~BRD_TAG;
if (bh->gid != class_bid) {
bh->gid = class_bid;
substitute_record(FN_BOARD, bh,
@@ -1313,43 +1105,88 @@ choose_board(int newflag)
break;
case 'L':
if (HAS_PERM(PERM_BASIC)) {
- if(fav->nDatas > FAVMAX || fav->nLines <= -127){
- vmsg("§Aªº³Ì·R¤Ó¦h¤F°Õ ¯uªá¤ß");
+ if (fav_add_line() == NULL) {
+ vmsg("·s¼W¥¢±Ñ¡A¤À¹j½u/Á`³Ì·R ¼Æ¶q¹F³Ì¤j­È¡C");
break;
}
- setfav(0, BRD_FAV | BRD_LINE, 1, 0);
- nbrd[brdnum].bid = fav->nLines;
- movefav(brdnum, num);
+ /* done move if it's the first item. */
+ if (get_fav_type(&nbrd[0]) != 0)
+ move_in_current_folder(brdnum, num);
brdnum = -1;
head = 9999;
}
break;
case 'm':
if (HAS_PERM(PERM_BASIC)) {
- if(nbrd[num].myattr & BRD_LINE){
- delfavline(nbrd[num].bid, num);
- brdnum = -1;
- }
- else if(!(nbrd[num].myattr & BRD_FAV) && (fav->nDatas > FAVMAX)){
- vmsg("§Aªº³Ì·R¤Ó¦h¤F°Õ ¯uªá¤ß");
- break;
+ ptr = &nbrd[num];
+ if (yank_flag == 0) {
+ if (ptr->myattr & BRD_FAV && getans("§A½T©w§R°£¶Ü? [N/y]") == 'y'){
+ fav_remove_item(ptr->bid, get_fav_type(ptr));
+ ptr->myattr &= ~BRD_FAV;
+ }
}
- else{
- setfav(nbrd[num].bid, BRD_FAV, 2, 0);
- nbrd[num].myattr ^= BRD_FAV;
+ else {
+ if (getboard(ptr->bid) != NULL) {
+ fav_remove_item(ptr->bid, FAVT_BOARD);
+ ptr->myattr &= ~BRD_FAV;
+ }
+ else {
+ if (fav_add_board(ptr->bid) == NULL)
+ vmsg("§Aªº³Ì·R¤Ó¦h¤F°Õ ¯uªá¤ß");
+ else
+ ptr->myattr |= BRD_FAV;
+ }
}
+ brdnum = -1;
head = 9999;
}
break;
case 'M':
- if (HAS_PERM(PERM_BASIC) && class_bid == 0 && yank_flag == 0){
- imovefav(num);
+ if (HAS_PERM(PERM_BASIC)){
+ if (class_bid == 0 && yank_flag == 0){
+ imovefav(num);
+ brdnum = -1;
+ head = 9999;
+ }
+ }
+ break;
+ case 'g':
+ if (HAS_PERM(PERM_BASIC) && yank_flag == 0) {
+ fav_type_t *ft;
+ if (fav_max_folder_level()){
+ vmsg("¥Ø¿ý¤w¹F³Ì¤j¼h¼Æ!!");
+ break;
+ }
+ if ((ft = fav_add_folder()) == NULL) {
+ vmsg("·s¼W¥¢±Ñ¡A¥Ø¿ý/Á`³Ì·R ¼Æ¶q¹F³Ì¤j­È¡C");
+ break;
+ }
+ fav_set_folder_title(ft, "·sªº¥Ø¿ý");
+ /* don't move if it's the first item */
+ if (get_fav_type(&nbrd[0]) != 0)
+ move_in_current_folder(brdnum, num);
+ brdnum = -1;
head = 9999;
}
break;
+ case 'T':
+ if (HAS_PERM(PERM_BASIC) && nbrd[num].myattr & BRD_FOLDER) {
+ char title[64];
+ fav_type_t *ft = getfolder(nbrd[num].bid);
+ strlcpy(title, get_item_title(ft), sizeof(title));
+ getdata_buf(b_lines - 1, 0, "½Ð¿é¤JÀɦW:", title, sizeof(title), DOECHO);
+ fav_set_folder_title(ft, title);
+ brdnum = -1;
+ }
+ break;
case 'K':
if (HAS_PERM(PERM_BASIC)) {
char c, fname[80], genbuf[256];
+ if (!current_fav_at_root()) {
+ vmsg("½Ð¨ì§Úªº³Ì·R³Ì¤W¼h°õ¦æ¥»¥\\¯à");
+ break;
+ }
+
c = getans("½Ð¿ï¾Ü 1)²M°£¤£¥i¨£¬ÝªO 2)³Æ¥÷§Úªº³Ì·R 3)¨ú¦^³Ì·R³Æ¥÷ [Q]");
if(!c)
break;
@@ -1357,24 +1194,24 @@ choose_board(int newflag)
break;
switch(c){
case '1':
- favclean(fav);
+ cleanup();
break;
case '2':
- setuserfile(fname, FAV3);
+ fav_save();
+ setuserfile(fname, FAV4);
sprintf(genbuf, "%s.bak", fname);
Copy(fname, genbuf);
break;
case '3':
- setuserfile(fname, FAV3);
+ setuserfile(fname, FAV4);
sprintf(genbuf, "%s.bak", fname);
- if(!dashf(genbuf)){
+ if (!dashf(genbuf)){
vmsg("§A¨S¦³³Æ¥÷§Aªº³Ì·R³á");
break;
}
Copy(genbuf, fname);
- freefav(fav);
+ fav_free();
load_brdbuf();
- favchange = 1;
break;
}
brdnum = -1;
@@ -1384,41 +1221,35 @@ choose_board(int newflag)
if (HAS_PERM(PERM_BASIC))
vmsg("¼K¼K ³o­Ó¥\\¯à¤w¸g³Q§Úªº³Ì·R¨ú¥N±¼¤F³á!");
break;
+#ifdef DEBUG
+ case 'A':
+ if (1) {
+ char genbuf[200];
+ sprintf(genbuf, "brdnum: %d num: %d", brdnum, num);
+ vmsg(genbuf);
+ }
+ break;
+#endif
case 'Z':
- if (HAS_PERM(PERM_BASIC)) {
- char genbuf[256];
- sprintf(genbuf, "½T©w­n %s­q¾\\ ·s¬ÝªO? [N/y] ", cuser.uflag2 & FAVNEW_FLAG ? "¨ú®ø" : "");
- if (getans(genbuf) != 'y')
- break;
+ if (!HAS_PERM(PERM_BASIC))
+ break;
+ char genbuf[256];
+ sprintf(genbuf, "½T©w­n %s­q¾\\ ·s¬ÝªO? [N/y] ", cuser.uflag2 & FAVNEW_FLAG ? "¨ú®ø" : "");
+ if (getans(genbuf) != 'y')
+ break;
- cuser.uflag2 ^= FAVNEW_FLAG;
- if(cuser.uflag2 & FAVNEW_FLAG){
- char fname[80];
+ cuser.uflag2 ^= FAVNEW_FLAG;
+ if(cuser.uflag2 & FAVNEW_FLAG){
+ char fname[80];
- setuserfile(fname, FAVNB);
+ setuserfile(fname, FAVNB);
- if( (tmp = open(fname, O_RDONLY, 0600)) != -1 ){
- close(tmp);
- updatenewfav(0);
- }
- else{
- char stat;
- if( (tmp = open(fname, O_WRONLY | O_CREAT, 0600)) != -1 ){
- for(tmp1 = 0; tmp1 < numboards; tmp1++){
- if(bcache[tmp1].brdname[0] && Ben_Perm(&bcache[tmp1]))
- stat = BRD_OLD;
- else
- stat = BRD_NEW;
- write(tmp, &stat, sizeof(char));
- }
- stat = BRD_END;
- write(tmp, &stat, sizeof(char));
- close(tmp);
- }
- }
+ if( (tmp = open(fname, O_RDONLY, 0600)) != -1 ){
+ close(tmp);
+ updatenewfav(0);
}
- vmsg((cuser.uflag2 & FAVNEW_FLAG) ? "¤Á´«¬°­q¾\\·s¬ÝªO¼Ò¦¡" : "¤Á´«¬°¥¿±`¼Ò¦¡");
}
+ vmsg((cuser.uflag2 & FAVNEW_FLAG) ? "¤Á´«¬°­q¾\\·s¬ÝªO¼Ò¦¡" : "¤Á´«¬°¥¿±`¼Ò¦¡");
break;
case 'v':
case 'V':
@@ -1429,10 +1260,10 @@ choose_board(int newflag)
if (ch == 'v') {
ptr->myattr &= ~BRD_UNREAD;
brc_list[0] = now;
- setfav(ptr->bid, 0, 0, now);
+ setbrdtime(ptr->bid, now);
} else {
brc_list[0] = 1;
- setfav(ptr->bid, 0, 0, 1);
+ setbrdtime(ptr->bid, 1);
ptr->myattr |= BRD_UNREAD;
}
brc_num = brc_changed = 1;
@@ -1477,6 +1308,7 @@ choose_board(int newflag)
brdnum = -1;
}
break;
+
case KEY_RIGHT:
case '\n':
case '\r':
@@ -1485,8 +1317,21 @@ choose_board(int newflag)
char buf[STRLEN];
ptr = &nbrd[num];
- if(ptr->myattr & BRD_LINE)
+ if (yank_flag == 0 && get_fav_type(&nbrd[0]) == 0)
+ break;
+ else if (ptr->myattr & BRD_LINE)
+ break;
+ else if (ptr->myattr & BRD_FOLDER){
+ int t = num;
+ num = 0;
+ fav_folder_in(ptr->bid);
+ choose_board(0);
+ fav_folder_out();
+ num = t;
+ brdnum = -1;
+ head = 9999;
break;
+ }
if (!(B_BH(ptr)->brdattr & BRD_GROUPBOARD)) { /* «Dsub class */
if (!(B_BH(ptr)->brdattr & BRD_HIDE) ||
@@ -1499,12 +1344,12 @@ choose_board(int newflag)
head = tmp - t_lines / 2;
getkeep(buf, head > 1 ? head : 1, tmp + 1);
}
- board_visit_time = getfavtime(ptr->bid);
+ board_visit_time = getbrdtime(ptr->bid);
Read();
check_newpost(ptr);
head = -1;
setutmpmode(newflag ? READNEW : READBRD);
- }
+ }
} else { /* sub class */
move(12, 1);
bidtmp = class_bid;
@@ -1528,13 +1373,13 @@ choose_board(int newflag)
setutmpbid(ptr->bid);
free(nbrd);
nbrd = NULL;
- if (yank_flag == 0 ) {
- yank_flag = 1;
- choose_board(0);
- yank_flag = 0;
- }
- else
- choose_board(0);
+ if (yank_flag == 0 ) {
+ yank_flag = 1;
+ choose_board(0);
+ yank_flag = 0;
+ }
+ else
+ choose_board(0);
currmode = currmodetmp; /* Â÷¶}ªOªO«á´N§âÅv­­®³±¼³á */
num = tmp1;
class_bid = bidtmp;
diff --git a/mbbsd/fav.c b/mbbsd/fav.c
new file mode 100644
index 00000000..6590e57e
--- /dev/null
+++ b/mbbsd/fav.c
@@ -0,0 +1,921 @@
+#include "bbs.h"
+
+#ifdef MEM_CHECK
+static int memcheck;
+#endif
+
+/* the total number of items, every level. */
+static int fav_number;
+
+/* definition of fav stack, the top one is in use now. */
+static int fav_stack_num = 0;
+static fav_t *fav_stack[FAV_MAXDEPTH] = {0};
+
+/* fav_tmp is for recordinge while copying, moving, etc. */
+static fav_t *fav_tmp;
+//static int fav_tmp_snum; /* the sequence number in favh in fav_t */
+
+
+/* for casting */
+inline static fav_board_t *cast_board(fav_type_t *p){
+ return (fav_board_t *)p->fp;
+}
+
+inline static fav_line_t *cast_line(fav_type_t *p){
+ return (fav_line_t *)p->fp;
+}
+
+inline static fav_folder_t *cast_folder(fav_type_t *p){
+ return (fav_folder_t *)p->fp;
+}
+/* --- */
+
+inline int get_data_number(fav_t *fp){
+ return fp->nBoards + fp->nLines + fp->nFolders;
+}
+
+inline int get_current_fav_level(void){
+ return fav_stack_num;
+}
+
+inline fav_t *get_current_fav(void){
+ if (fav_stack_num == 0)
+ return NULL;
+ return fav_stack[fav_stack_num - 1];
+}
+
+inline fav_t *get_fav_folder(fav_type_t *ft){
+ return cast_folder(ft)->this_folder;
+}
+
+inline int get_item_type(fav_type_t *ft){
+ return ft->type;
+}
+
+inline void fav_set_tmp_folder(fav_t *fp){
+ fav_tmp = fp;
+}
+
+inline static fav_t *fav_get_tmp_fav(void){
+ return fav_tmp;
+}
+/* --- */
+
+static void fav_decrease(fav_t *fp, fav_type_t *ft){
+ switch (get_item_type(ft)){
+ case FAVT_BOARD:
+ fp->nBoards--;
+ break;
+ case FAVT_LINE:
+ fp->nLines--;
+ break;
+ case FAVT_FOLDER:
+ fp->nFolders--;
+ break;
+ }
+ fav_number--;
+}
+/* --- */
+
+static void fav_increase(fav_t *fp, fav_type_t *ft)
+{
+ switch (get_item_type(ft)){
+ case FAVT_BOARD:
+ fp->nBoards++;
+ break;
+ case FAVT_LINE:
+ fp->nLines++;
+ fp->lineID++;
+ break;
+ case FAVT_FOLDER:
+ fp->nFolders++;
+ fp->folderID++;
+ break;
+ }
+ fav_number++;
+ fp->DataTail++;
+}
+/* --- */
+
+inline static int get_folder_num(fav_t *fp) {
+ return fp->nFolders;
+}
+
+inline static int get_folder_id(fav_t *fp) {
+ return fp->folderID;
+}
+
+inline static int get_line_id(fav_t *fp) {
+ return fp->lineID;
+}
+
+inline static int get_line_num(fav_t *fp) {
+ return fp->nLines;
+}
+
+/* bool:
+ * 0: unset 1: set 2: opposite */
+void set_attr(fav_type_t *ft, int bit, char bool){
+ if (bool == 2)
+ ft->attr ^= bit;
+ else if (bool == 1)
+ ft->attr |= bit;
+ else
+ ft->attr &= ~bit;
+}
+
+int is_set_attr(fav_type_t *ft, char bit){
+ return ft->attr & bit;
+}
+/* --- */
+
+char *get_item_title(fav_type_t *ft)
+{
+ switch (get_item_type(ft)){
+ case FAVT_BOARD:
+ return bcache[cast_board(ft)->bid - 1].brdname;
+ case FAVT_FOLDER:
+ return cast_folder(ft)->title;
+ case FAVT_LINE:
+ return "----";
+ }
+ return NULL;
+}
+
+static char *get_item_class(fav_type_t *ft)
+{
+ switch (get_item_type(ft)){
+ case FAVT_BOARD:
+ return bcache[cast_board(ft)->bid - 1].title;
+ case FAVT_FOLDER:
+ return "¥Ø¿ý";
+ case FAVT_LINE:
+ return "----";
+ }
+ return NULL;
+}
+
+#ifdef MEM_CHECK
+inline void fav_set_memcheck(int n) {
+ memcheck = n;
+}
+
+inline int fav_memcheck(void) {
+ return memcheck;
+}
+#endif
+/* ---*/
+
+static int get_type_size(int type)
+{
+ switch (type){
+ case FAVT_BOARD:
+ return sizeof(fav_board_t);
+ case FAVT_FOLDER:
+ return sizeof(fav_folder_t);
+ case FAVT_LINE:
+ return sizeof(fav_line_t);
+ }
+ return 0;
+}
+
+inline static void* fav_malloc(int size){
+ void *p = (void *)malloc(size);
+ memset(p, 0, size);
+ return p;
+}
+
+/* allocate the header(fav_type_t) and item it self. */
+static fav_type_t *fav_item_allocate(int type)
+{
+ int size = 0;
+ fav_type_t *ft = (fav_type_t *)fav_malloc(sizeof(fav_type_t));
+
+ size = get_type_size(type);
+ if (size) {
+ ft->fp = fav_malloc(size);
+ ft->type = type;
+ }
+ return ft;
+}
+
+/* symbolic link */
+inline static void
+fav_item_copy(fav_type_t *target, const fav_type_t *source){
+ target->type = source->type;
+ target->attr = source->attr;
+ target->fp = source->fp;
+}
+
+inline static fav_t *get_fav_root(void){
+ return fav_stack[0];
+}
+
+char current_fav_at_root(void) {
+ return get_current_fav() == get_fav_root();
+}
+
+/* is it an unvisable entry */
+inline int is_visible_item(fav_type_t *ft){
+ if (!(ft->attr & FAVH_FAV))
+ return 0;
+ if (get_item_type(ft) != FAVT_BOARD)
+ return 1;
+ return Ben_Perm(&bcache[cast_board(ft)->bid - 1]);
+}
+
+/* return: the exact number after cleaning
+ * reset the line number, board number, folder number, and total number (number)
+ */
+static void rebuild_fav(fav_t *fp)
+{
+ int i, j, nData, bid;
+ fav_type_t *ft;
+ fav_number = 0;
+ fp->lineID = fp->folderID = 0;
+ fp->nLines = fp->nFolders = fp->nBoards = 0;
+ nData = fp->DataTail;
+ for (i = 0, j = 0; i < nData; i++){
+ if (!(fp->favh[i].attr & FAVH_FAV))
+ continue;
+ ft = &fp->favh[i];
+ switch (get_item_type(ft)){
+ case FAVT_BOARD:
+ bid = cast_board(ft)->bid;
+ if (!validboard(bid - 1))
+ continue;
+ break;
+ case FAVT_LINE:
+ cast_line(ft)->lid = fp->lineID + 1;
+ break;
+ case FAVT_FOLDER:
+ cast_folder(ft)->fid = fp->folderID + 1;
+ rebuild_fav(get_fav_folder(&fp->favh[i]));
+ break;
+ default:
+ continue;
+ }
+ fav_increase(fp, &fp->favh[i]);
+ if (i != j)
+ fav_item_copy(&fp->favh[j], &fp->favh[i]);
+ j++;
+ }
+ fp->DataTail = get_data_number(fp);
+}
+
+inline void cleanup(void)
+{
+ rebuild_fav(get_fav_root());
+}
+
+/* sort the fav */
+static int favcmp_by_name(const void *a, const void *b)
+{
+ return strcasecmp(get_item_title((fav_type_t *)a), get_item_title((fav_type_t *)b));
+}
+
+void fav_sort_by_name(void)
+{
+ rebuild_fav(get_current_fav());
+ qsort(get_current_fav()->favh, get_data_number(get_current_fav()), sizeof(fav_type_t), favcmp_by_name);
+}
+
+static int favcmp_by_class(const void *a, const void *b)
+{
+ fav_type_t *f1, *f2;
+ int cmp;
+
+ f1 = (fav_type_t *)a;
+ f2 = (fav_type_t *)b;
+ if (get_item_type(f1) == FAVT_FOLDER)
+ return -1;
+ if (get_item_type(f2) == FAVT_FOLDER)
+ return 1;
+ if (get_item_type(f1) == FAVT_LINE)
+ return 1;
+ if (get_item_type(f2) == FAVT_LINE)
+ return -1;
+
+ cmp = strncasecmp(get_item_class(f1), get_item_class(f2), 4);
+ if (cmp)
+ return cmp;
+ return strcasecmp(get_item_title(f1), get_item_title(f1));
+}
+
+void fav_sort_by_class(void)
+{
+ rebuild_fav(get_current_fav());
+ qsort(get_current_fav()->favh, get_data_number(get_current_fav()), sizeof(fav_type_t), favcmp_by_class);
+}
+/* --- */
+
+/*
+ * The following is the movement operations in the user interface.
+ */
+inline static int fav_stack_full(void){
+ return fav_stack_num >= FAV_MAXDEPTH;
+}
+
+inline int fav_max_folder_level(void){
+ return fav_stack_full();
+}
+
+inline static int fav_stack_push_fav(fav_t *fp){
+ if (fav_stack_full())
+ return -1;
+ fav_stack[fav_stack_num++] = fp;
+ return 0;
+}
+
+inline static int fav_stack_push(fav_type_t *ft){
+// if (ft->type != FAVT_FOLDER)
+// return -1;
+ return fav_stack_push_fav(get_fav_folder(ft));
+}
+
+inline static void fav_stack_pop(void){
+ fav_stack[--fav_stack_num] = NULL;
+}
+
+void fav_folder_in(short fid)
+{
+ fav_type_t *tmp = getfolder(fid);
+ if (get_item_type(tmp) == FAVT_FOLDER){
+ fav_stack_push(tmp);
+ }
+}
+
+void fav_folder_out(void)
+{
+ fav_stack_pop();
+}
+
+/* --- */
+
+/* load from the rec file */
+static void read_favrec(int fd, fav_t *fp)
+{
+ int i;
+ fav_type_t *ft;
+ read(fd, &fp->nBoards, sizeof(fp->nBoards));
+ read(fd, &fp->nLines, sizeof(fp->nLines));
+ read(fd, &fp->nFolders, sizeof(fp->nFolders));
+ fp->DataTail = get_data_number(fp);
+ fp->nAllocs = fp->DataTail + FAV_PRE_ALLOC;
+ fp->lineID = fp->folderID = 0;
+ fp->favh = (fav_type_t *)fav_malloc(sizeof(fav_type_t) * fp->nAllocs);
+
+ for(i = 0; i < fp->DataTail; i++){
+ read(fd, &fp->favh[i].type, sizeof(fp->favh[i].type));
+ read(fd, &fp->favh[i].attr, sizeof(fp->favh[i].attr));
+ fp->favh[i].fp = (void *)fav_malloc(get_type_size(fp->favh[i].type));
+ read(fd, fp->favh[i].fp, get_type_size(fp->favh[i].type));
+ }
+
+ for(i = 0; i < fp->DataTail; i++){
+ ft = &fp->favh[i];
+ switch (ft->type) {
+ case FAVT_FOLDER: {
+ fav_t *p = (fav_t *)fav_malloc(sizeof(fav_t));
+ read_favrec(fd, p);
+ cast_folder(ft)->this_folder = p;
+ cast_folder(ft)->fid = ++(fp->folderID);
+ break;
+ }
+ case FAVT_LINE:
+ cast_line(ft)->lid = ++(fp->lineID);
+ break;
+ }
+ }
+}
+
+int fav_load(void)
+{
+ int fd;
+ char buf[128];
+ fav_t *fp;
+ if (fav_stack_num > 0)
+ return -1;
+ setuserfile(buf, FAV4);
+ fd = open(buf, O_RDONLY);
+ if (fd < 0){
+ return -1;
+ }
+ fp = (fav_t *)fav_malloc(sizeof(fav_t));
+ read_favrec(fd, fp);
+ fav_stack_push_fav(fp);
+ close(fd);
+ fav_set_memcheck(MEM_CHECK);
+ return 0;
+}
+/* --- */
+
+/* write to the rec file */
+static void write_favrec(int fd, fav_t *fp)
+{
+ int i;
+ if (fp == NULL)
+ return;
+ write(fd, &fp->nBoards, sizeof(fp->nBoards));
+ write(fd, &fp->nLines, sizeof(fp->nLines));
+ write(fd, &fp->nFolders, sizeof(fp->nFolders));
+ fp->DataTail = get_data_number(fp);
+
+ for(i = 0; i < fp->DataTail; i++){
+ write(fd, &fp->favh[i].type, sizeof(fp->favh[i].type));
+ write(fd, &fp->favh[i].attr, sizeof(fp->favh[i].attr));
+ write(fd, fp->favh[i].fp, get_type_size(fp->favh[i].type));
+ }
+
+ for(i = 0; i < fp->DataTail; i++){
+ if (fp->favh[i].type == FAVT_FOLDER)
+ write_favrec(fd, get_fav_folder(&fp->favh[i]));
+ }
+}
+
+int fav_save(void)
+{
+ int fd;
+ char buf[128], buf2[128];
+ fav_t *fp = get_fav_root();
+#ifdef MEM_CHECK
+ if (fav_memcheck() != MEM_CHECK)
+ return -1;
+#endif
+ if (fp == NULL)
+ return -1;
+ cleanup();
+ setuserfile(buf, FAV4".tmp");
+ setuserfile(buf2, FAV4);
+ fd = open(buf, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+ if (fd < 0)
+ return -1;
+ write_favrec(fd, fp);
+ close(fd);
+ Rename(buf, buf2);
+ return 0;
+}
+/* --- */
+
+/* It didn't need to remove it self, just remove all the attributes.
+ * It'll be remove when it save to the record file. */
+static void fav_free_item(fav_type_t *ft)
+{
+ set_attr(ft, 0xFFFF, FALSE);
+// ft = NULL;
+}
+
+static int fav_non_recursive_remove(fav_t *fp, fav_type_t *ft)
+{
+ set_attr(ft, 0xFFFF, FALSE);
+ fav_decrease(fp, ft);
+ return 0;
+}
+
+static int fav_remove(fav_t *fp, fav_type_t *ft)
+{
+ fav_free_item(ft);
+ fav_decrease(fp, ft);
+ return 0;
+}
+
+/* free the mem of whole fav tree */
+static void fav_free_branch(fav_t *fp)
+{
+ int i;
+ fav_type_t *ft;
+ if (fp == NULL)
+ return;
+ for(i = 0; i < fp->DataTail; i++){
+ ft = &fp->favh[i];
+ fav_remove(fp, ft);
+ }
+ free(fp);
+ fp = NULL;
+}
+
+void fav_free(void)
+{
+ fav_free_branch(get_fav_root());
+
+ /* reset the stack */
+ fav_stack_num = 0;
+}
+/* --- */
+
+static fav_type_t *get_fav_item(short id, int type)
+{
+ int i;
+ fav_type_t *ft;
+ fav_t *fp = get_current_fav();
+
+ for(i = 0; i < fp->DataTail; i++){
+ ft = &fp->favh[i];
+ if (!is_visible_item(ft) || get_item_type(ft) != type)
+ continue;
+ if (fav_getid(ft) == id)
+ return ft;
+ }
+ return NULL;
+}
+
+void fav_remove_item(short id, char type)
+{
+ fav_remove(get_current_fav(), get_fav_item(id, type));
+}
+
+fav_type_t *getboard(short bid)
+{
+ return get_fav_item(bid, FAVT_BOARD);
+}
+
+fav_type_t *getfolder(short fid)
+{
+ return get_fav_item(fid, FAVT_FOLDER);
+}
+
+char *get_folder_title(int fid)
+{
+ return get_item_title(get_fav_item(fid, FAVT_FOLDER));
+}
+
+
+char getbrdattr(short bid)
+{
+ fav_type_t *fb = getboard(bid);
+ if (!fb)
+ return 0;
+ return fb->attr;
+}
+
+time_t getbrdtime(short bid)
+{
+ fav_type_t *fb = getboard(bid);
+ if (!fb)
+ return 0;
+ return cast_board(fb)->lastvisit;
+}
+
+void setbrdtime(short bid, time_t t)
+{
+ fav_type_t *fb = getboard(bid);
+ if (fb)
+ cast_board(fb)->lastvisit = t;
+}
+
+int fav_getid(fav_type_t *ft)
+{
+ switch(get_item_type(ft)){
+ case FAVT_FOLDER:
+ return cast_folder(ft)->fid;
+ case FAVT_LINE:
+ return cast_line(ft)->lid;
+ case FAVT_BOARD:
+ return cast_board(ft)->bid;
+ }
+ return -1;
+}
+
+/* suppose we don't add too much fav_type_t at the same time. */
+static int enlarge_if_full(fav_t *fp)
+{
+ fav_type_t * p;
+ /* enlarge the volume if need. */
+ if (fav_number >= MAX_FAV)
+ return -1;
+ if (fp->DataTail < fp->nAllocs)
+ return 1;
+
+ /* realloc and clean the tail */
+ p = (fav_type_t *)realloc(fp->favh, sizeof(fav_type_t) * (fp->nAllocs + FAV_PRE_ALLOC));
+ if( p == NULL )
+ return -1;
+
+ fp->favh = p;
+ memset(fp->favh + fp->nAllocs, 0, sizeof(fav_type_t) * FAV_PRE_ALLOC);
+ fp->nAllocs += FAV_PRE_ALLOC;
+ return 0;
+}
+
+inline int is_maxsize(void){
+ return fav_number >= MAX_FAV;
+}
+
+static int fav_add(fav_t *fp, fav_type_t *item)
+{
+ if (enlarge_if_full(fp) < 0)
+ return -1;
+ fav_item_copy(&fp->favh[fp->DataTail], item);
+ fav_increase(fp, item);
+ return 0;
+}
+
+/* just move, in one folder */
+static void move_in_folder(fav_t *fav, int from, int to)
+{
+ int i, count;
+ fav_type_t tmp;
+
+ /* Find real locations of from and to in fav->favh[] */
+ for(count = i = 0; count <= from; i++)
+ if (is_visible_item(&fav->favh[i]))
+ count++;
+ from = i - 1;
+ for(count = i = 0; count <= to; i++)
+ if (is_visible_item(&fav->favh[i]))
+ count++;
+ to = i - 1;
+
+ fav_item_copy(&tmp, &fav->favh[from]);
+
+ if (from < to) {
+ for(i = from; i < to; i++)
+ fav_item_copy(&fav->favh[i], &fav->favh[i + 1]);
+ }
+ else { // to < from
+ for(i = from; i > to; i--)
+ fav_item_copy(&fav->favh[i], &fav->favh[i - 1]);
+ }
+ fav_item_copy(&fav->favh[to], &tmp);
+}
+
+void move_in_current_folder(int from, int to)
+{
+ move_in_folder(get_current_fav(), from, to);
+}
+
+/* the following defines the interface of add new fav_XXX */
+inline static fav_t *alloc_folder_item(void){
+ fav_t *fp = (fav_t *)fav_malloc(sizeof(fav_t));
+ fp->nAllocs = FAV_PRE_ALLOC;
+ fp->favh = (fav_type_t *)fav_malloc(sizeof(fav_type_t) * FAV_PRE_ALLOC);
+ return fp;
+}
+
+static fav_type_t *init_add(fav_t *fp, int type)
+{
+ fav_type_t *ft;
+ if (is_maxsize())
+ return NULL;
+ ft = fav_item_allocate(type);
+ set_attr(ft, FAVH_FAV, TRUE);
+ fav_add(fp, ft);
+ return ft;
+}
+
+/* if place < 0, just put the item to the tail */
+fav_type_t *fav_add_line(void)
+{
+ fav_t *fp = get_current_fav();
+ if (get_line_num(fp) >= MAX_LINE)
+ return NULL;
+ fav_type_t *ft = init_add(fp, FAVT_LINE);
+ if (ft == NULL)
+ return NULL;
+ cast_line(ft)->lid = get_line_id(fp);
+ return ft;
+}
+
+fav_type_t *fav_add_folder(void)
+{
+ fav_t *fp = get_current_fav();
+ fav_type_t *ft;
+ if (fav_stack_full())
+ return NULL;
+ if (get_folder_num(fp) >= MAX_FOLDER)
+ return NULL;
+ ft = init_add(fp, FAVT_FOLDER);
+ if (ft == NULL)
+ return NULL;
+ cast_folder(ft)->this_folder = alloc_folder_item();
+ cast_folder(ft)->fid = get_folder_id(fp); // after fav_increase
+ return ft;
+}
+
+fav_type_t *fav_add_board(int bid)
+{
+ fav_t *fp = get_current_fav();
+ fav_type_t *ft = init_add(fp, FAVT_BOARD);
+ if (ft == NULL)
+ return NULL;
+ cast_board(ft)->bid = bid;
+ return ft;
+}
+/* --- */
+
+/* everything about the tag in fav mode.
+ * I think we don't have to implement the function 'cross-folder' tag.*/
+
+void fav_tag(short id, char type, char bool) {
+ fav_type_t *ft = get_fav_item(id, type);
+ if (ft != NULL)
+ set_attr(ft, FAVH_TAG, bool);
+}
+
+static void fav_dosomething_tagged_item(fav_t *fp, int (*act)(fav_t *, fav_type_t *))
+{
+ int i;
+ for(i = 0; i < fp->DataTail; i++){
+ if (is_set_attr(&fp->favh[i], FAVH_FAV) && is_set_attr(&fp->favh[i], FAVH_TAG))
+ if ((*act)(fp, &fp->favh[i]) < 0)
+ break;
+ }
+}
+
+static int remove_tagged_item(fav_t *fp, fav_type_t *ft)
+{
+ int i;
+ for(i = 0; i < FAV_MAXDEPTH && fav_stack[i] != NULL; i++)
+ if (fav_stack[i] == get_fav_folder(ft)){
+ set_attr(ft, FAVH_TAG, FALSE);
+ return 0;
+ }
+ return fav_remove(fp, ft);
+}
+
+inline static int fav_remove_tagged_item(fav_t *fp){
+ fav_dosomething_tagged_item(fp, remove_tagged_item);
+ return 0;
+}
+
+/* add an item into a fav_t.
+ * here we must give the line and foler a new id to prevent an old one is exist.
+ */
+static int add_and_remove_tag(fav_t *fp, fav_type_t *ft)
+{
+ int i;
+ fav_type_t *tmp;
+ for(i = 0; i < FAV_MAXDEPTH && fav_stack[i] != NULL; i++)
+ if (fav_stack[i] == get_fav_folder(ft)){
+ set_attr(ft, FAVH_TAG, FALSE);
+ return 0;
+ }
+ tmp = fav_malloc(sizeof(fav_type_t));
+ fav_item_copy(tmp, ft);
+ set_attr(tmp, FAVH_TAG, FALSE);
+
+ /* give the new id */
+ switch (tmp->type) {
+ case FAVT_FOLDER:
+ cast_folder(tmp)->fid = fp->folderID + 1;
+ break;
+ case FAVT_LINE:
+ cast_line(tmp)->lid = fp->lineID + 1;
+ break;
+ }
+ if (fav_add(fav_get_tmp_fav(), tmp) < 0)
+ return -1;
+ if (get_item_type(ft) == FAVT_FOLDER)
+ fav_non_recursive_remove(fp, ft);
+ else
+ fav_remove(fp, ft);
+ return 0;
+}
+
+inline static int fav_add_tagged_item(fav_t *fp){
+ if (fp == fav_get_tmp_fav())
+ return -1;
+ fav_dosomething_tagged_item(fp, add_and_remove_tag);
+ return 0;
+}
+
+static void fav_do_recursively(fav_t *fp, int (*act)(fav_t *))
+{
+ int i;
+ fav_type_t *ft;
+ for(i = 0; i < fp->DataTail; i++){
+ ft = &fp->favh[i];
+ if (!is_visible_item(ft))
+ continue;
+ if (get_item_type(ft) == FAVT_FOLDER && get_fav_folder(ft) != NULL){
+ fav_do_recursively(get_fav_folder(ft), act);
+ }
+ }
+ (*act)(fp);
+}
+
+static void fav_dosomething_all_tagged_item(int (*act)(fav_t *))
+{
+ fav_do_recursively(get_fav_root(), act);
+}
+
+void fav_remove_all_tagged_item(void)
+{
+ fav_dosomething_all_tagged_item(fav_remove_tagged_item);
+}
+
+void fav_add_all_tagged_item(void)
+{
+ fav_set_tmp_folder(get_current_fav());
+ fav_dosomething_all_tagged_item(fav_add_tagged_item);
+}
+
+inline static int remove_tag(fav_t *fp, fav_type_t *ft)
+{
+ set_attr(ft, FAVH_TAG, FALSE);
+ return 0;
+}
+
+inline static int remove_tags(fav_t *fp)
+{
+ fav_dosomething_tagged_item(fp, remove_tag);
+ return 0;
+}
+
+void fav_remove_all_tag(void)
+{
+ fav_dosomething_all_tagged_item(remove_tags);
+}
+/* --- */
+
+void fav_set_folder_title(fav_type_t *ft, char *title)
+{
+ if (get_item_type(ft) != FAVT_FOLDER)
+ return;
+ strlcpy(cast_folder(ft)->title, title, sizeof(cast_folder(ft)->title));
+}
+
+/* old struct */
+#define BRD_UNREAD 1
+#define BRD_FAV 2
+#define BRD_LINE 4
+#define BRD_TAG 8
+#define BRD_GRP_HEADER 16
+
+typedef struct {
+ short bid;
+ char attr;
+ time_t lastvisit;
+} fav3_board_t;
+
+typedef struct {
+ short nDatas;
+ short nAllocs;
+ char nLines;
+ fav_board_t *b;
+} fav3_t;
+
+int fav_v3_to_v4(void)
+{
+ int i, fd, fdw;
+ char buf[128];
+
+ short nDatas;
+ char nLines;
+ fav_t *fav4 = (fav_t *)fav_malloc(sizeof(fav_t));
+ fav3_board_t *brd;
+
+ setuserfile(buf, FAV4);
+ fd = open(buf, O_RDONLY);
+ if (fd >= 0){
+ close(fd);
+ return 0;
+ }
+ fdw = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (fdw < 0)
+ return -1;
+ setuserfile(buf, FAV3);
+ fd = open(buf, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ read(fd, &nDatas, sizeof(nDatas));
+ read(fd, &nLines, sizeof(nLines));
+
+ fav4->DataTail = nDatas;
+ //fav4->nBoards = nDatas - (-nLines);
+ //fav4->nLines = -nLines;
+ fav4->nBoards = fav4->nFolders = fav4->nLines = 0;
+ fav4->favh = (fav_type_t *)fav_malloc(sizeof(fav_type_t) * fav4->DataTail);
+
+ brd = (fav3_board_t *)fav_malloc(sizeof(fav3_board_t) * nDatas);
+ read(fd, brd, sizeof(fav3_board_t) * nDatas);
+
+ for(i = 0; i < fav4->DataTail; i++){
+ fav4->favh[i].type = brd[i].attr & BRD_LINE ? FAVT_LINE : FAVT_BOARD;
+
+ if (brd[i].attr & BRD_UNREAD)
+ fav4->favh[i].attr |= FAVH_UNREAD;
+ if (brd[i].attr & BRD_FAV)
+ fav4->favh[i].attr |= FAVH_FAV;
+ if (brd[i].attr & BRD_TAG)
+ fav4->favh[i].attr |= FAVH_TAG;
+
+ fav4->favh[i].fp = (void *)fav_malloc(get_type_size(fav4->favh[i].type));
+ if (brd[i].attr & BRD_LINE){
+ fav4->favh[i].type = FAVT_LINE;
+ cast_line(&fav4->favh[i])->lid = ++fav4->nLines;
+ }
+ else{
+ fav4->favh[i].type = FAVT_BOARD;
+ cast_board(&fav4->favh[i])->bid = brd[i].bid;
+ cast_board(&fav4->favh[i])->lastvisit = brd[i].lastvisit;
+ fav4->nBoards++;
+ }
+ }
+
+ write_favrec(fdw, fav4);
+ fav_free_branch(fav4);
+ free(brd);
+ return 0;
+}
diff --git a/util/buildir.c b/util/buildir.c
index e6b7f9d2..573a0178 100644
--- a/util/buildir.c
+++ b/util/buildir.c
@@ -1,17 +1,5 @@
/* $Id$ */
-#include <stdio.h>
-#include <stdlib.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <time.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "config.h"
-#include "pttstruct.h"
-#include "proto.h"
+#include "bbs.h"
int dirselect(struct dirent *dir) {
return strchr("MDSGH", dir->d_name[0]) && dir->d_name[1] == '.';