1 #include "links.h"
2 
3 /* The location of the box in the bookmark manager */
4 #define	BM_BOX_IND		5
5 
6 
7 /* The list of bookmarks */
8 struct list_head bookmarks = {&bookmarks, &bookmarks};
9 
10 /* The last used id of a bookmark */
11 bookmark_id next_bookmark_id = 0;
12 
13 /* Clears the bookmark list */
free_bookmarks()14 void free_bookmarks() {
15 	struct bookmark *bm;
16 
17 	foreach(bm, bookmarks) {
18 		mem_free(bm->title);
19 		mem_free(bm->url);
20 	}
21 
22 	free_list(bookmarks);
23 }
24 
25 /* Does final cleanup and saving of bookmarks */
finalize_bookmarks()26 void finalize_bookmarks() {
27 	write_bookmarks();
28 	free_bookmarks();
29 }
30 
31 
32 /* Loads the bookmarks from file */
read_bookmarks()33 void read_bookmarks() {
34 	unsigned char *file_name;
35 	unsigned char *url;	/* Pointer to the start of url field */
36 	unsigned char *str, *ptr, *nl;
37 
38 	if (!links_home) return;
39 	file_name = stracpy(links_home);
40 	add_to_strn(&file_name, "bookmarks");
41 
42 	str = read_config_file(file_name);
43 	mem_free(file_name);
44 	if (!str) return;
45 
46 	for (ptr = str; *ptr; ptr = nl) {
47 		nl = strchr(ptr, '\n');
48 		if (nl) *nl++ = 0;
49 		else nl = strchr(ptr, 0);
50 
51 		url = strchr(ptr, '|');
52 		if (!url) continue;
53 		*url++ = 0;
54 		add_bookmark(ptr, url);
55 	}
56 
57 	mem_free(str);
58 }
59 
60 /* Saves the bookmarks to file */
write_bookmarks()61 void write_bookmarks() {
62 	struct bookmark *bm;
63 	unsigned char *file_name;
64 	unsigned char *s;
65 	int l;
66 
67 	if (!links_home) return;
68 	file_name = stracpy(links_home);
69 	add_to_strn(&file_name, "bookmarks");
70 
71 	s = init_str();
72 	l = 0;
73 
74 	foreachback(bm, bookmarks) {
75 		int i;
76 		unsigned char *p = stracpy(bm->title);
77 		for (i = strlen(p) - 1; i >= 0; i--) if (p[i] < ' '|| p[i] == '|') p[i] = ' ';
78 		add_to_str(&s, &l, p);
79 		mem_free(p);
80 		add_chr_to_str(&s, &l, '|');
81 		p = stracpy(bm->url);
82 		for (i = strlen(p) - 1; i >= 0; i--) if (p[i] < ' ') p[i] = ' ';
83 		add_to_str(&s, &l, p);
84 		mem_free(p);
85 		add_chr_to_str(&s, &l, '\n');
86 	}
87 
88 	write_to_config_file(file_name, s);
89 
90 	mem_free(s);
91 	mem_free(file_name);
92 
93 }
94 
95 /* Gets a bookmark by id */
get_bookmark_by_id(bookmark_id id)96 struct bookmark *get_bookmark_by_id(bookmark_id id) {
97 	struct bookmark *bm;
98 
99 	if (id == BAD_BOOKMARK_ID)
100 		return NULL;
101 
102 	foreach(bm, bookmarks) {
103 		if (id == bm->id)
104 			return bm;
105 	}
106 
107 	return NULL;
108 }
109 
110 
111 /* Adds a bookmark to the bookmark list. Don't play with new_bm after you're
112 	done. It would be impolite. */
add_bookmark(const unsigned char * title,const unsigned char * url)113 void add_bookmark(const unsigned char *title, const unsigned char *url) {
114 	struct bookmark *bm;
115 	int	title_size;	/* How much mem to allocate for the strings */
116 	int url_size;
117 
118 	title_size = strlen(title) + 1;
119 	url_size = strlen(url) + 1;
120 
121 	bm = mem_alloc(sizeof(struct bookmark));
122 
123 	bm->title = mem_alloc(title_size);
124 	bm->url = mem_alloc(url_size);
125 
126 	strcpy(bm->title, title);
127 	strcpy(bm->url, url);
128 
129 	bm->id = next_bookmark_id++;
130 
131 	/* Actually add it */
132 	add_to_list(bookmarks, bm);
133 }
134 
135 
136 /* Updates an existing bookmark.
137  *
138  * If the requested bookmark does not exist, return 0. Otherwise, return 1.
139  *
140  * If any of the fields are NULL, the value is left unchanged.
141  */
bookmark_update(bookmark_id id,unsigned char * title,unsigned char * url)142 int bookmark_update(bookmark_id id, unsigned char *title, unsigned char *url) {
143 	struct bookmark *bm = get_bookmark_by_id(id);
144 
145 	if (bm == NULL) {
146 		/* Does not exist. */
147 		return 0;
148 	}
149 
150 	if (title) {
151 		mem_free(bm->title);
152 		bm->title = stracpy((unsigned char *)title);
153 	}
154 
155 	if (url) {
156 		mem_free(bm->url);
157 		bm->url = stracpy((unsigned char *)url);
158 	}
159 
160 	return 1;
161 }
162 
163 /* Allocates and returns a bookmark */
create_bookmark(const unsigned char * title,const unsigned char * url)164 struct bookmark *create_bookmark(const unsigned char *title, const unsigned char *url) {
165 	struct bookmark *new_bm = NULL;
166 	size_t title_size;	/* How much mem to allocate for the strings */
167 	size_t url_size;
168 
169 	title_size = strlen(title) + 1;
170 	url_size = strlen(url) + 1;
171 	if (title_size > MAXINT) overalloc();
172 	if (url_size > MAXINT) overalloc();
173 
174 	new_bm = mem_alloc(sizeof(struct bookmark));
175 
176 	new_bm->title = mem_alloc(title_size);
177 	new_bm->url = mem_alloc(url_size);
178 
179 	strcpy(new_bm->title, title);
180 	strcpy(new_bm->url, url);
181 
182 	return new_bm;
183 }
184 
185 
186 /* Deletes a bookmark, given the id. Returns 0 on failure (no such bm), 1 on
187 	success */
delete_bookmark_by_id(bookmark_id id)188 int delete_bookmark_by_id(bookmark_id id) {
189 	struct bookmark *bm;
190 
191 	bm = get_bookmark_by_id(id);
192 
193 	if (bm == NULL)
194 		return 0;
195 
196 	del_from_list(bm);
197 
198 	/* Now wipe the bookmark */
199 	mem_free(bm->title);
200 	mem_free(bm->url);
201 
202 	mem_free(bm);
203 
204 	return 1;
205 }
206 
207 /****************************************************************************
208 *
209 * Bookmark manager stuff.
210 *
211 ****************************************************************************/
212 
213 void bookmark_edit_dialog(
214 		struct terminal *,
215 		unsigned char *,
216 		const unsigned char *,
217 		const unsigned char *,
218 		struct session *,
219 		struct dialog_data *,
220 		void when_done(struct dialog *),
221 		void *
222 );
223 
224 /* Gets the head of the bookmark list kept by the dialog (the one used for
225 	display purposes */
226 /* I really should use this somewhere...
227 static inline *list_head bookmark_dlg_list_get(struct dialog) {
228 	return dialog->items[BM_BOX_IND].data;
229 }
230 */
231 
232 /* Clears the bookmark list from the bookmark_dialog */
bookmark_dlg_list_clear(struct list_head * bm_list)233 static inline void bookmark_dlg_list_clear(struct list_head *bm_list) {
234 	free_list( *bm_list );
235 }
236 
237 /* Updates the bookmark list for a dialog. Returns the number of bookmarks.
238 	FIXME: Must be changed for hierarchical bookmarks.
239 */
bookmark_dlg_list_update(struct list_head * bm_list)240 int bookmark_dlg_list_update(struct list_head *bm_list) {
241 	struct bookmark *bm;	/* Iterator over bm list */
242 	struct box_item	*item;	/* New box item (one per displayed bookmark) */
243 	unsigned char *text;
244 	int count = 0;
245 	bookmark_id id;
246 
247 	/* Empty the list */
248 	bookmark_dlg_list_clear(bm_list);
249 
250 	/* Copy each bookmark into the display list */
251 	foreach(bm, bookmarks) {
252 		/* Deleted in bookmark_dlg_clear_list() */
253 		item = mem_alloc( sizeof(struct box_item) + strlen(bm->title) + 1);
254 		item->text = text = ((unsigned char *)item + sizeof(struct box_item));
255 		item->data = (void *)(my_uintptr_t)(id = bm->id);
256 
257 		/* Note that free_i is left at zero */
258 
259 		strcpy(text, bm->title);
260 
261 		add_to_list( *bm_list, item);
262 		count++;
263 	}
264 	return count;
265 }
266 
267 
268 /* Creates the box display (holds everything EXCEPT the actual rendering data) */
bookmark_dlg_box_build(struct dlg_data_item_data_box ** box)269 struct dlg_data_item_data_box *bookmark_dlg_box_build(struct dlg_data_item_data_box **box) {
270 	/* Deleted in abort */
271 	*box = mem_alloc( sizeof(struct dlg_data_item_data_box) );
272 	memset(*box, 0, sizeof(struct dlg_data_item_data_box));
273 
274 	init_list((*box)->items);
275 
276 	(*box)->list_len = bookmark_dlg_list_update(&((*box)->items));
277 	return *box;
278 }
279 
280 /* Get the id of the currently selected bookmark */
bookmark_dlg_box_id_get(struct dlg_data_item_data_box * box)281 bookmark_id bookmark_dlg_box_id_get(struct dlg_data_item_data_box *box) {
282 	struct box_item *citem;
283 	int sel;
284 
285 	sel = box->sel;
286 
287 	if (sel == -1)
288 		return BAD_BOOKMARK_ID;
289 
290 	/* Sel is an index into the list of bookmarks. Therefore, we spin thru
291 		until sel equals zero, and return the id at that point */
292 	foreach(citem, box->items) {
293 		if (sel == 0)
294 			return (bookmark_id)(my_uintptr_t)(citem->data);
295 		sel--;
296 	}
297 
298 	return BAD_BOOKMARK_ID;
299 }
300 
301 
302 
303 /* Cleans up after the bookmark dialog */
bookmark_dialog_abort_handler(struct dialog_data * dlg)304 void bookmark_dialog_abort_handler(struct dialog_data *dlg) {
305 	struct dlg_data_item_data_box *box;
306 
307 	box = (struct dlg_data_item_data_box *)(dlg->dlg->items[BM_BOX_IND].data);
308 
309 	/* Zap the display list */
310 	bookmark_dlg_list_clear(&(box->items));
311 
312 	/* Delete the box structure */
313 	mem_free(box);
314 }
315 
316 /* Handles events for a bookmark dialog */
bookmark_dialog_event_handler(struct dialog_data * dlg,struct event * ev)317 int bookmark_dialog_event_handler(struct dialog_data *dlg, struct event *ev) {
318 
319 	switch ((int)ev->ev) {
320 		case EV_KBD:
321 			/* Catch change focus requests */
322 			if (ev->x == KBD_RIGHT || (ev->x == KBD_TAB && !ev->y)) {
323 				/* MP: dirty crap!!! this should be done in bfu.c */
324 				/* Move right */
325 		display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
326 				if (++dlg->selected >= BM_BOX_IND)
327 					dlg->selected = 0;
328 		display_dlg_item(dlg, &dlg->items[dlg->selected], 1);
329 
330 				return EVENT_PROCESSED;
331 			}
332 
333 			if (ev->x == KBD_LEFT || (ev->x == KBD_TAB && ev->y)) {
334 				/* Move left */
335 		display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
336 				if (--dlg->selected < 0)
337 					dlg->selected = BM_BOX_IND - 1;
338 		display_dlg_item(dlg, &dlg->items[dlg->selected], 1);
339 
340 				return EVENT_PROCESSED;
341 			}
342 
343 			/* Moving the box */
344 			if (ev->x == KBD_DOWN) {
345 				box_sel_move(&dlg->items[BM_BOX_IND], 1);
346 				show_dlg_item_box(dlg, &dlg->items[BM_BOX_IND]);
347 
348 				return EVENT_PROCESSED;
349 			}
350 
351 			if (ev->x == KBD_UP) {
352 				box_sel_move(&dlg->items[BM_BOX_IND], -1);
353 				show_dlg_item_box(dlg, &dlg->items[BM_BOX_IND]);
354 
355 				return EVENT_PROCESSED;
356 			}
357 
358 			if (ev->x == KBD_PAGE_DOWN) {
359 				box_sel_move(&dlg->items[BM_BOX_IND], dlg->items[BM_BOX_IND].item->gid / 2);
360 				show_dlg_item_box(dlg, &dlg->items[BM_BOX_IND]);
361 
362 				return EVENT_PROCESSED;
363 			}
364 
365 			if (ev->x == KBD_PAGE_UP) {
366 				box_sel_move(&dlg->items[BM_BOX_IND], (-1) * dlg->items[BM_BOX_IND].item->gid / 2);
367 				show_dlg_item_box(dlg, &dlg->items[BM_BOX_IND]);
368 
369 				return EVENT_PROCESSED;
370 			}
371 
372 			/* Selecting a button */
373 		break;
374 		case EV_INIT:
375 		case EV_RESIZE:
376 		case EV_REDRAW:
377 		case EV_MOUSE:
378 		case EV_ABORT:
379 		break;
380 		default:
381 			internal("Unknown event received: %d", (int)ev->ev);
382 	}
383 
384 	return EVENT_NOT_PROCESSED;
385 }
386 
387 
388 /* The titles to appear in the bookmark add dialog */
389 unsigned char *bookmark_add_msg[] = {
390 	TEXT_(T_BOOKMARK_TITLE),
391 	TEXT_(T_URL),
392 };
393 
394 
395 /* The titles to appear in the bookmark manager */
396 unsigned char *bookmark_dialog_msg[] = {
397 	TEXT_(T_BOOKMARKS),
398 };
399 
400 
401 /* Loads the selected bookmark */
menu_goto_bookmark(struct terminal * term,void * url,struct session * ses)402 void menu_goto_bookmark(struct terminal *term, void *url, struct session *ses) {
403 	goto_url(ses, (unsigned char*)url);
404 }
405 
406 
407 /* Gets the url of the requested bookmark.
408  *
409  * This returns a pointer to the url's data. Be gentle with it.
410  *
411  * Returns a NULL if the bookmark has no url, AND if the passed bookmark id is
412  * invalid.
413  */
bookmark_get_url(bookmark_id id)414 const unsigned char *bookmark_get_url(bookmark_id id) {
415 	struct bookmark *bm = get_bookmark_by_id(id);
416 
417 	if (bm == NULL) {
418 		return NULL;
419 	}
420 
421 	return bm->url;
422 }
423 
424 /* Gets the name of the requested bookmark.
425  *
426  * See bookmark_get_url() for further comments.
427  */
bookmark_get_name(bookmark_id id)428 const unsigned char *bookmark_get_name(bookmark_id id) {
429 	struct bookmark *bm = get_bookmark_by_id(id);
430 
431 	if (bm == NULL) {
432 		return NULL;
433 	}
434 
435 	return bm->title;
436 }
437 
438 
439 
440 /* Goes to the called bookmark */
bookmark_goto(bookmark_id id,struct session * ses)441 void bookmark_goto(bookmark_id id, struct session *ses) {
442 	struct bookmark *bm;
443 	bm = get_bookmark_by_id(id);
444 
445 	if (bm)
446 		goto_url(ses, bm->url);
447 
448 }
449 
450 /* Shows the bookmark list */
bookmark_menu(struct terminal * term,void * ddd,struct session * ses)451 void bookmark_menu(struct terminal *term, void *ddd, struct session *ses)
452 {
453 	struct bookmark *bm;
454 	struct menu_item *mi;
455 
456 	if (!(mi = new_menu(3)))
457 		return;
458 
459 	foreach(bm, bookmarks) {
460 		add_to_menu(&mi, stracpy(bm->title), "", 0, MENU_FUNC menu_goto_bookmark, (void *)bm->url, 0);
461 	}
462 
463 	do_menu(term, mi, ses);
464 }
465 
466 
467 /* Called to setup the bookmark dialog */
layout_bookmark_manager(struct dialog_data * dlg)468 void layout_bookmark_manager(struct dialog_data *dlg)
469 {
470 	int max = 0, min = 0;
471 	int w, rw;
472 	int y = -1;
473 	struct terminal *term;
474 
475 	term = dlg->win->term;
476 
477 	/* Find dimensions of dialog */
478 	max_text_width(term, bookmark_dialog_msg[0], &max);
479 	min_text_width(term, bookmark_dialog_msg[0], &min);
480 	max_buttons_width(term, dlg->items + 2, 2, &max);
481 	min_buttons_width(term, dlg->items + 2, 2, &min);
482 
483 	w = term->x * 9 / 10 - 2 * DIALOG_LB;
484 	if (w > max) w = max;
485 	if (w < min) w = min;
486 
487 	if (w > term->x - 2 * DIALOG_LB)
488 		w = term->x - 2 * DIALOG_LB;
489 
490 	if (w < 1)
491 		w = 1;
492 
493 	w = rw = 50 ;
494 
495 	y += 1;	/* Blankline between top and top of box */
496 	dlg_format_box(NULL, term, &dlg->items[BM_BOX_IND], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
497 	y += 1;	/* Blankline between box and menu */
498 	dlg_format_buttons(NULL, term, dlg->items, 5, 0, &y, w, &rw, AL_CENTER);
499 	w = rw;
500 	dlg->xw = w + 2 * DIALOG_LB;
501 	dlg->yw = y + 2 * DIALOG_TB;
502 	center_dlg(dlg);
503 	draw_dlg(dlg);
504 	y = dlg->y + DIALOG_TB;
505 
506 	y++;
507 	dlg_format_box(term, term, &dlg->items[BM_BOX_IND], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
508 	y++;
509 	dlg_format_buttons(term, term, &dlg->items[0], 5, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
510 }
511 
512 
513 void launch_bm_add_doc_dialog(struct terminal *,struct dialog_data *, struct session *);
514 /* Callback for the "add" button in the bookmark manager */
push_add_button(struct dialog_data * dlg,struct dialog_item_data * di)515 int push_add_button(struct dialog_data *dlg, struct dialog_item_data *di) {
516 	launch_bm_add_doc_dialog(dlg->win->term, dlg, (struct session *)dlg->dlg->udata);
517 	return 0;
518 }
519 
520 
521 /* Called when the goto button is pushed */
push_goto_button(struct dialog_data * dlg,struct dialog_item_data * goto_btn)522 int push_goto_button(struct dialog_data *dlg, struct dialog_item_data *goto_btn) {
523 	bookmark_id id;
524 	struct dlg_data_item_data_box *box;
525 
526 	box = (struct dlg_data_item_data_box*)(dlg->dlg->items[BM_BOX_IND].data);
527 
528 	/* Follow the bookmark */
529 	id = bookmark_dlg_box_id_get(box);
530 	if (id != BAD_BOOKMARK_ID)
531 		bookmark_goto(id, (struct session*)goto_btn->item->udata);
532 	/* FIXME There really should be some feedback to the user here */
533 
534 	/* Close the bookmark dialog */
535 	delete_window(dlg->win);
536 	return 0;
537 }
538 
539 /* Called when an edit is complete. */
bookmark_edit_done(struct dialog * d)540 void bookmark_edit_done(struct dialog *d) {
541 	bookmark_id id = (bookmark_id)(my_uintptr_t)d->udata2;
542 	struct dialog_data *parent;
543 
544 	bookmark_update(id, d->items[0].data, d->items[1].data);
545 
546 	parent = d->udata;
547 
548 	/* Tell the bookmark dialog to redraw */
549 	if (parent)
550 		bookmark_dlg_list_update(&(((struct dlg_data_item_data_box*)parent->dlg->items[BM_BOX_IND].data)->items));
551 }
552 
553 /* Called when the edit button is pushed */
push_edit_button(struct dialog_data * dlg,struct dialog_item_data * edit_btn)554 int push_edit_button(struct dialog_data *dlg, struct dialog_item_data *edit_btn) {
555 	bookmark_id id;
556 	struct dlg_data_item_data_box *box;
557 
558 	box = (struct dlg_data_item_data_box*)(dlg->dlg->items[BM_BOX_IND].data);
559 
560 	/* Follow the bookmark */
561 	id = bookmark_dlg_box_id_get(box);
562 	if (id != BAD_BOOKMARK_ID) {
563 		const unsigned char *name = bookmark_get_name(id);
564 		const unsigned char *url = bookmark_get_url(id);
565 
566 		bookmark_edit_dialog(dlg->win->term, TEXT_(T_EDIT_BOOKMARK), name, url, (struct session*)edit_btn->item->udata, dlg, bookmark_edit_done, (void *)(my_uintptr_t)id);
567 	}
568 	/* FIXME There really should be some feedback to the user here */
569 	return 0;
570 }
571 
572 
573 /* Used to carry extra info between the push_delete_button() and the really_del_bookmark_ */
574 struct push_del_button_hop_struct {
575 	struct dialog *dlg;
576 	struct dlg_data_item_data_box *box;
577 	bookmark_id id;
578 };
579 
580 
581 /* Called to _really_ delete a bookmark (a confirm in the delete dialog) */
really_del_bookmark(void * vhop)582 void really_del_bookmark(void *vhop) {
583 	struct push_del_button_hop_struct *hop;
584 	int last;
585 
586 	hop = (struct push_del_button_hop_struct *)vhop;
587 
588 	if (!delete_bookmark_by_id(hop->id))
589 		return;
590 
591 	last = bookmark_dlg_list_update(&(hop->box->items));
592 	/* In case we deleted the last bookmark */
593 	if (hop->box->sel >= (last - 1))
594 		hop->box->sel = last - 1;
595 
596 	/* Made in push_delete_button() */
597 	/*mem_free(vhop);*/
598 }
599 
600 
601 /* Callback for the "delete" button in the bookmark manager */
push_delete_button(struct dialog_data * dlg,struct dialog_item_data * some_useless_delete_button)602 int push_delete_button(struct dialog_data *dlg, struct dialog_item_data *some_useless_delete_button) {
603 	struct bookmark *bm;
604 	struct push_del_button_hop_struct *hop;
605 	struct terminal *term;
606 	struct dlg_data_item_data_box *box;
607 
608 	/* FIXME There's probably a nicer way to do this */
609 	term = dlg->win->term;
610 
611 	box = (struct dlg_data_item_data_box*)(dlg->dlg->items[BM_BOX_IND].data);
612 
613 	bm = get_bookmark_by_id(bookmark_dlg_box_id_get(box));
614 
615 	if (bm == NULL)
616 		return 0;
617 
618 
619 	/* Deleted in really_del_bookmark() */
620 	hop = mem_alloc(sizeof(struct push_del_button_hop_struct));
621 
622 	hop->id = bm->id;
623 	hop->dlg = dlg->dlg;
624 	hop->box = box;
625 
626 	msg_box(term, getml(hop, NULL), TEXT_(T_DELETE_BOOKMARK), AL_CENTER | AL_EXTD_TEXT, TEXT_(T_DELETE_BOOKMARK), " \"", bm->title, "\" (", TEXT_(T_url), ": \"", bm->url, "\")?", NULL, hop, 2, TEXT_(T_YES), really_del_bookmark, B_ENTER, TEXT_(T_NO), NULL, B_ESC);
627 	return 0;
628 }
629 
630 /* Builds the "Bookmark manager" dialog */
menu_bookmark_manager(struct terminal * term,void * fcp,struct session * ses)631 void menu_bookmark_manager(struct terminal *term, void *fcp, struct session *ses)
632 {
633 	struct dialog *d;
634 
635 	/* Create the dialog */
636 	d = mem_alloc(sizeof(struct dialog) + 7 * sizeof(struct dialog_item) + sizeof(struct bookmark) + 2 * MAX_STR_LEN);
637 
638 	memset(d, 0, sizeof(struct dialog) + 7 * sizeof(struct dialog_item) + sizeof(struct bookmark) + 2 * MAX_STR_LEN);
639 
640 	d->title = TEXT_(T_BOOKMARK_MANAGER);
641 	d->fn = layout_bookmark_manager;
642 	d->handle_event = bookmark_dialog_event_handler;
643 	d->abort = bookmark_dialog_abort_handler;
644 /*	bookmark_build_dlg_list(d);*/	/* Where the currently displayed list goes */
645 	d->udata = ses;
646 
647 	d->items[0].type = D_BUTTON;
648 	d->items[0].gid = B_ENTER;
649 	d->items[0].fn = push_goto_button;
650 	d->items[0].udata = ses;
651 	d->items[0].text = TEXT_(T_GOTO);
652 
653 	d->items[1].type = D_BUTTON;
654 	d->items[1].gid = B_ENTER;
655 	d->items[1].fn = push_edit_button;
656 	d->items[1].udata = ses;
657 	d->items[1].text = TEXT_(T_EDIT);
658 
659 	d->items[2].type = D_BUTTON;
660 	d->items[2].gid = B_ENTER;
661 	d->items[2].fn = push_delete_button;
662 	d->items[2].text = TEXT_(T_DELETE);
663 
664 	d->items[3].type = D_BUTTON;
665 	d->items[3].gid = B_ENTER;
666 	d->items[3].fn = push_add_button;
667 	d->items[3].text = TEXT_(T_ADD);
668 
669 	d->items[4].type = D_BUTTON;
670 	d->items[4].gid = B_ESC;
671 	d->items[4].fn = cancel_dialog;
672 	d->items[4].text = TEXT_(T_CLOSE);
673 
674 	d->items[5].type = D_BOX;	/* MP: D_BOX is nonsence. I tried to remove it, but didn't succeed */
675 	d->items[5].gid = 12;
676 	/*d->items[5].data = (void *)bookmark_dlg_box_build();*/	/* Where the currently displayed list goes */
677 	bookmark_dlg_box_build((struct dlg_data_item_data_box**)(void *)&(d->items[5].data));	/* Where the currently displayed list goes */
678 
679 	d->items[6].type = D_END;
680 	do_dialog(term, d, getml(d, NULL));
681 }
682 
683 /****************************************************************************
684 *
685 * Bookmark add dialog
686 *
687 ****************************************************************************/
688 
689 /* Adds the bookmark */
bookmark_add_add(struct dialog * d)690 void bookmark_add_add(struct dialog *d)
691 {
692 	struct dialog_data *parent;
693 
694 	add_bookmark(d->items[0].data, d->items[1].data);
695 
696 	parent = d->udata;
697 
698 	/* Tell the bookmark dialog to redraw */
699 	if (parent)
700 		bookmark_dlg_list_update(&(((struct dlg_data_item_data_box*)parent->dlg->items[BM_BOX_IND].data)->items));
701 }
702 
703 
launch_bm_add_doc_dialog(struct terminal * term,struct dialog_data * parent,struct session * ses)704 void launch_bm_add_doc_dialog(struct terminal *term,struct dialog_data *parent,struct session *ses) {
705 
706 	bookmark_edit_dialog(term, TEXT_(T_ADD_BOOKMARK), NULL, NULL, ses, parent, bookmark_add_add, NULL);
707 }
708 
709 /* Called to launch an add dialog on the current link */
launch_bm_add_link_dialog(struct terminal * term,struct dialog_data * parent,struct session * ses)710 void launch_bm_add_link_dialog(struct terminal *term,struct dialog_data *parent,struct session *ses) {
711 	unsigned char url[MAX_STR_LEN];
712 
713 	/* FIXME: Logic error -- if there is no current link,
714 	 * get_current_link_url() will return NULL, which will cause
715 	 * bookmark_add_dialog() to try and use the current document's url.
716 	 * Instead, it should use "".
717 	 */
718 	bookmark_edit_dialog(term, TEXT_(T_ADD_BOOKMARK), NULL, get_current_link_url(ses, url, MAX_STR_LEN), ses, parent, bookmark_add_add, NULL);
719 }
720 
721 
722 
723 unsigned char *bm_add_msg[] = {
724 	TEXT_(T_NNAME),
725 	TEXT_(T_URL),
726 };
727 
728 /* Called to setup the add bookmark dialog */
layout_add_dialog(struct dialog_data * dlg)729 void layout_add_dialog(struct dialog_data *dlg)
730 {
731 	int max = 0, min = 0;
732 	int w, rw;
733 	int y = -1;
734 	struct terminal *term;
735 
736 	term = dlg->win->term;
737 
738 	max_text_width(term, bm_add_msg[0], &max);
739 	min_text_width(term, bm_add_msg[0], &min);
740 	max_text_width(term, bm_add_msg[1], &max);
741 	min_text_width(term, bm_add_msg[1], &min);
742 	max_buttons_width(term, dlg->items + 2, 2, &max);
743 	min_buttons_width(term, dlg->items + 2, 2, &min);
744 	w = term->x * 9 / 10 - 2 * DIALOG_LB;
745 
746 	if (w > max) w = max;
747 	if (w < min) w = min;
748 	if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
749 	if (w < 1) w = 1;
750 
751 	w = rw = 50;
752 
753 	dlg_format_text(NULL, term, bm_add_msg[0], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
754 	y += 2;
755 	dlg_format_text(NULL, term, bm_add_msg[1], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
756 	y += 2;
757 	dlg_format_buttons(NULL, term, dlg->items + 2, 2, 0, &y, w, &rw, AL_CENTER);
758 	w = rw;
759 	dlg->xw = w + 2 * DIALOG_LB;
760 	dlg->yw = y + 2 * DIALOG_TB;
761 	center_dlg(dlg);
762 	draw_dlg(dlg);
763 	y = dlg->y + DIALOG_TB;
764 	dlg_format_text(term, term, bm_add_msg[0], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
765 	dlg_format_field(NULL, term, &dlg->items[0], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
766 	y++;
767 	dlg_format_text(term, term, bm_add_msg[1], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
768 	dlg_format_field(term, term, &dlg->items[1], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
769 	y++;
770 	dlg_format_buttons(term, term, &dlg->items[2], 2, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
771 
772 }
773 
774 /* Edits a bookmark's fields.
775  * If parent is defined, then that points to a dialog that should be sent
776  * an update when the add is done.
777  *
778  * If either of src_name or src_url are NULL, try to obtain the name and url
779  * of the current document. If you want to create two null fields, pass in a
780  * pointer to a zero length string ("").
781 */
bookmark_edit_dialog(struct terminal * term,unsigned char * title,const unsigned char * src_name,const unsigned char * src_url,struct session * ses,struct dialog_data * parent,void when_done (struct dialog *),void * done_data)782 void bookmark_edit_dialog(
783 		struct terminal *term /* Terminal to write on. */,
784 		unsigned char *title /* Title of the dialog. */,
785 		const unsigned char *src_name /* Pointer to name to use. (can be null)*/,
786 		const unsigned char *src_url /* Url to use. (can be null) */,
787 		struct session *ses,
788 		struct dialog_data *parent /* The parent window launching this one. */,
789 		void when_done(struct dialog *) /* Function to execute on 'ok'. */,
790 		void *done_data /* Spare data to pass to when_done. Stored in udata2 */
791 ) {
792 	unsigned char *name, *url;
793 
794 	struct dialog *d;
795 
796 	/* Create the dialog */
797 	d = mem_alloc(sizeof(struct dialog) + 5 * sizeof(struct dialog_item) + sizeof(struct extension) + 2 * MAX_STR_LEN);
798 	memset(d, 0, sizeof(struct dialog) + 5 * sizeof(struct dialog_item) + sizeof(struct extension) + 2 * MAX_STR_LEN);
799 
800 	name = (unsigned char *)&d->items[5];
801 	url = name + MAX_STR_LEN;
802 
803 	/* Get the name */
804 	if (src_name == NULL) {
805 		/* Unknown name. */
806 		get_current_title(ses, name, MAX_STR_LEN);
807 	} else {
808 		/* Known name. */
809 		safe_strncpy(name, src_name, MAX_STR_LEN);
810 	}
811 
812 	/* Get the url */
813 	if (src_url == NULL) {
814 		/* Unknown . */
815 		get_current_url(ses, url, MAX_STR_LEN);
816 	} else {
817 		/* Known url. */
818 		safe_strncpy(url, src_url, MAX_STR_LEN);
819 	}
820 
821 	d->title = title;
822 	d->fn = layout_add_dialog;
823 	d->refresh = (void (*)(void *))when_done;
824 	d->refresh_data = d;
825 	d->udata = parent;
826 	d->udata2 = done_data;
827 
828 	d->items[0].type = D_FIELD;
829 	d->items[0].dlen = MAX_STR_LEN;
830 	d->items[0].data = name;
831 	d->items[0].fn = check_nonempty;
832 
833 	d->items[1].type = D_FIELD;
834 	d->items[1].dlen = MAX_STR_LEN;
835 	d->items[1].data = url;
836 	d->items[1].fn = check_nonempty;
837 
838 	d->items[2].type = D_BUTTON;
839 	d->items[2].gid = B_ENTER;
840 	d->items[2].fn = ok_dialog;
841 	d->items[2].text = TEXT_(T_OK);
842 
843 	d->items[3].type = D_BUTTON;
844 	d->items[3].gid = B_ESC;
845 	d->items[3].text = TEXT_(T_CANCEL);
846 	d->items[3].fn = cancel_dialog;
847 
848 	d->items[4].type = D_END;
849 
850 	do_dialog(term, d, getml(d, NULL));
851 }
852