"Fossies" - the Fresh Open Source Software Archive

Member "links-1.03/bookmark.c" (16 Nov 2011, 22981 Bytes) of archive /linux/www/links-1.03.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: 2.8_vs_1.03.

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