"Fossies" - the Fresh Open Source Software Archive

Member "links-1.04/bookmark.c" (10 Oct 2017, 22598 Bytes) of package /linux/www/links-1.04.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "bookmark.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.03_vs_1.04.

    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 */
   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 */
   26 void finalize_bookmarks() {
   27     write_bookmarks();
   28     free_bookmarks();
   29 }
   30 
   31 
   32 /* Loads the bookmarks from file */
   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 */
   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 */
   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. */
  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  */
  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 */
  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 */
  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 */
  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 */
  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) */
  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 */
  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 */
  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 */
  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 */
  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  */
  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  */
  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 */
  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 */
  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 */
  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 */
  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 */
  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. */
  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 */
  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) */
  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 */
  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 */
  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 */
  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 
  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 */
  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 */
  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 */
  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 }