diff options
-rw-r--r-- | include/bbs.h | 1 | ||||
-rw-r--r-- | include/proto.h | 43 | ||||
-rw-r--r-- | mbbsd/Makefile | 13 | ||||
-rw-r--r-- | mbbsd/board.c | 703 | ||||
-rw-r--r-- | mbbsd/fav.c | 921 | ||||
-rw-r--r-- | util/buildir.c | 14 |
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©wn %sq¾\\ ·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©wn %sq¾\\ ·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] == '.'; |