summaryrefslogtreecommitdiffstats
path: root/mbbsd/fav.c
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 /mbbsd/fav.c
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
Diffstat (limited to 'mbbsd/fav.c')
-rw-r--r--mbbsd/fav.c921
1 files changed, 921 insertions, 0 deletions
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;
+}