1 /* Internal bookmarks support - default file format backend */
2 
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "elinks.h"
12 
13 #include "bfu/dialog.h"
14 #include "bookmarks/bookmarks.h"
15 #include "bookmarks/backend/common.h"
16 #include "bookmarks/backend/default.h"
17 #include "util/file.h"
18 #include "util/memory.h"
19 #include "util/string.h"
20 
21 #define BOOKMARKS_FILENAME		"bookmarks"
22 
23 
24 /* Loads the bookmarks from file */
25 static void
read_bookmarks_default(FILE * f)26 read_bookmarks_default(FILE *f)
27 {
28 	/* INBUF_SIZE = max. title length + 1 byte for separator
29 	 * + max. url length + 1 byte for separator + 5 bytes for depth
30 	 * + 1 byte for end of line + 1 byte for null char + reserve */
31 #define INBUF_SIZE ((MAX_STR_LEN - 1) + 1 + (MAX_STR_LEN - 1) + 1 + 5 + 1 + 1 \
32 		    + MAX_STR_LEN)
33 	unsigned char in_buffer[INBUF_SIZE]; /* read buffer */
34 	struct bookmark *last_bm = NULL;
35 	int last_depth = 0;
36 
37 	/* TODO: Ignore lines with bad chars in title or url (?). -- Zas */
38 	while (fgets(in_buffer, INBUF_SIZE, f)) {
39 		unsigned char *title = in_buffer;
40 		unsigned char *url;
41 		unsigned char *depth_str;
42 		int depth = 0;
43 		unsigned char *flags = NULL;
44 		unsigned char *line_end;
45 
46 		/* Load URL. */
47 
48 		url = strchr(in_buffer, '\t');
49 
50 		/* If separator is not found, or title is empty or too long,
51 		 * skip that line. */
52 		if (!url || url == in_buffer
53 		    || url - in_buffer > MAX_STR_LEN - 1)
54 			continue;
55 		*url = '\0';
56 		url++;
57 
58 		/* Load depth. */
59 
60 		depth_str = strchr(url, '\t');
61 		if (depth_str && depth_str - url > MAX_STR_LEN - 1)
62 			continue;
63 
64 		if (depth_str) {
65 			*depth_str = '\0';
66 			depth_str++;
67 			depth = atoi(depth_str);
68 			int_bounds(&depth, 0, last_bm ? last_depth + 1 : 0);
69 
70 			/* Load flags. */
71 
72 			flags = strchr(depth_str, '\t');
73 			if (flags) {
74 				*flags = '\0';
75 				flags++;
76 			}
77 		} else {
78 			depth_str = url;
79 		}
80 
81 		/* Load EOLN. */
82 
83 		line_end = strchr(flags ? flags : depth_str, '\n');
84 		if (!line_end)
85 			continue;
86 		*line_end = '\0';
87 
88 		{
89 			struct bookmark *root = NULL;
90 
91 			if (depth > 0) {
92 				if (depth == last_depth) {
93 					root = last_bm->root;
94 				} else if (depth > last_depth) {
95 					root = last_bm;
96 				} else {
97 					while (last_depth - depth) {
98 						last_bm = last_bm->root;
99 						last_depth--;
100 					}
101 					root = last_bm->root;
102 				}
103 			}
104 			last_bm = add_bookmark(root, 1, title, url);
105 			last_depth = depth;
106 
107 			if (!*url && title[0] == '-' && title[1] == '\0') {
108 			       	last_bm->box_item->type = BI_SEPARATOR;
109 
110 			} else {
111 				while (flags && *flags && last_bm) {
112 					switch (*flags) {
113 						case 'F':
114 							last_bm->box_item->type = BI_FOLDER;
115 							break;
116 						case 'E':
117 							last_bm->box_item->expanded = 1;
118 							break;
119 					}
120 					flags++;
121 				}
122 			}
123 		}
124 	}
125 #undef INBUF_SIZE
126 }
127 
128 /* Saves the bookmarks to file */
129 static void
write_bookmarks_default(struct secure_save_info * ssi,struct list_head * bookmarks_list)130 write_bookmarks_default(struct secure_save_info *ssi,
131 		        struct list_head *bookmarks_list)
132 {
133 	int folder_state = get_opt_bool("bookmarks.folder_state");
134 	struct bookmark *bm;
135 
136 	foreach (bm, *bookmarks_list) {
137 		secure_fprintf(ssi, "%s\t%s\t%d\t", bm->title, bm->url, bm->box_item->depth);
138 		if (bm->box_item->type == BI_FOLDER) {
139 			secure_fputc(ssi, 'F');
140 			if (folder_state && bm->box_item->expanded)
141 				secure_fputc(ssi, 'E');
142 		}
143 		secure_fputc(ssi, '\n');
144 		if (ssi->err) break;
145 
146 		if (!list_empty(bm->child))
147 			write_bookmarks_default(ssi, &bm->child);
148 	}
149 }
150 
151 static unsigned char *
filename_bookmarks_default(int writing)152 filename_bookmarks_default(int writing)
153 {
154 	return BOOKMARKS_FILENAME;
155 }
156 
157 
158 struct bookmarks_backend default_bookmarks_backend = {
159 	filename_bookmarks_default,
160 	read_bookmarks_default,
161 	write_bookmarks_default,
162 };
163