summaryrefslogtreecommitdiff
path: root/alpine/takeaddr.c
diff options
context:
space:
mode:
authorEduardo Chappa <echappa@gmx.com>2013-02-03 00:59:38 -0700
committerEduardo Chappa <echappa@gmx.com>2013-02-03 00:59:38 -0700
commit094ca96844842928810f14844413109fc6cdd890 (patch)
treee60efbb980f38ba9308ccb4fb2b77b87bbc115f3 /alpine/takeaddr.c
downloadalpine-094ca96844842928810f14844413109fc6cdd890.tar.xz
Initial Alpine Version
Diffstat (limited to 'alpine/takeaddr.c')
-rw-r--r--alpine/takeaddr.c3520
1 files changed, 3520 insertions, 0 deletions
diff --git a/alpine/takeaddr.c b/alpine/takeaddr.c
new file mode 100644
index 00000000..ec89c017
--- /dev/null
+++ b/alpine/takeaddr.c
@@ -0,0 +1,3520 @@
+#if !defined(lint) && !defined(DOS)
+static char rcsid[] = "$Id: takeaddr.c 1012 2008-03-26 00:44:22Z hubert@u.washington.edu $";
+#endif
+
+/*
+ * ========================================================================
+ * Copyright 2006-2008 University of Washington
+ * Copyright 2013 Eduardo Chappa
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * ========================================================================
+ */
+
+/*======================================================================
+ takeaddr.c
+ Mostly support for Take Address command.
+ ====*/
+
+
+#include "headers.h"
+#include "takeaddr.h"
+#include "addrbook.h"
+#include "adrbkcmd.h"
+#include "status.h"
+#include "confscroll.h"
+#include "keymenu.h"
+#include "radio.h"
+#include "titlebar.h"
+#include "alpine.h"
+#include "help.h"
+#include "mailcmd.h"
+#include "mailpart.h"
+#include "roleconf.h"
+#include "../pith/state.h"
+#include "../pith/msgno.h"
+#include "../pith/adrbklib.h"
+#include "../pith/bldaddr.h"
+#include "../pith/bitmap.h"
+#include "../pith/util.h"
+#include "../pith/addrstring.h"
+#include "../pith/remote.h"
+#include "../pith/newmail.h"
+#include "../pith/list.h"
+#include "../pith/abdlc.h"
+#include "../pith/ablookup.h"
+#include "../pith/stream.h"
+#include "../pith/mailcmd.h"
+#include "../pith/busy.h"
+
+
+typedef struct takeaddress_screen {
+ ScreenMode mode;
+ TA_S *current,
+ *top_line;
+} TA_SCREEN_S;
+
+static TA_SCREEN_S *ta_screen;
+static char *fakedomain = "@";
+
+static ESCKEY_S save_or_export[] = {
+ {'s', 's', "S", N_("Save")},
+ {'e', 'e', "E", N_("Export")},
+ {-1, 0, NULL, NULL}};
+
+
+/* internal prototypes */
+int edit_nickname(AdrBk *, AddrScrn_Disp *, int, char *, char *, HelpType, int, int);
+void add_abook_entry(TA_S *, char *, char *, char *, char *, int, TA_STATE_S **, char *);
+void take_to_addrbooks_frontend(char **, char *, char *, char *, char *,
+ char *, int, TA_STATE_S **, char *);
+void take_to_addrbooks(char **, char *, char *, char *, char *,
+ char *, int, TA_STATE_S **, char *);
+PerAddrBook *use_this_addrbook(int, char *);
+PerAddrBook *check_for_addrbook(char *);
+int takeaddr_screen(struct pine *, TA_S *, int, ScreenMode, TA_STATE_S **, char *);
+void takeaddr_bypass(struct pine *, TA_S *, TA_STATE_S **);
+int ta_do_take(TA_S *, int, int, TA_STATE_S **, char *);
+TA_S *whereis_taline(TA_S *);
+int ta_take_marked_addrs(int, TA_S *, int, TA_STATE_S **, char *);
+int ta_take_single_addr(TA_S *, int, TA_STATE_S **, char *);
+int update_takeaddr_screen(struct pine *, TA_S *, TA_SCREEN_S *, Pos *);
+void takeaddr_screen_redrawer_list(void);
+void takeaddr_screen_redrawer_single(void);
+int attached_addr_handler(TA_S *, int);
+int take_without_edit(TA_S *, int, int, TA_STATE_S **, char *);
+void export_vcard_att(struct pine *, int, long, ATTACH_S *);
+int take_export_tool(struct pine *, int, CONF_S **, unsigned);
+
+#ifdef _WINDOWS
+int ta_scroll_up(long);
+int ta_scroll_down(long);
+int ta_scroll_to_pos(long);
+int ta_scroll_callback(int, long);
+#endif
+
+
+/*
+ * Edit a nickname field.
+ *
+ * Args: abook -- the addressbook handle
+ * dl -- display list line (NULL if new entry)
+ * command_line -- line to prompt on
+ * orig -- nickname to edit
+ * prompt -- prompt
+ * this_help -- help
+ * return_existing -- changes the behavior when a user types in a nickname
+ * which already exists in this abook. If not set, it
+ * will just keep looping until the user changes; if set,
+ * it will return -8 to the caller and orig will be set
+ * to the matching nickname.
+ *
+ * Returns: -10 to cancel
+ * -9 no change
+ * -7 only case of nickname changed (only happens if dl set)
+ * -8 existing nickname chosen (only happens if return_existing set)
+ * 0 new value copied into orig
+ */
+int
+edit_nickname(AdrBk *abook, AddrScrn_Disp *dl, int command_line, char *orig,
+ char *prompt, HelpType this_help, int return_existing, int takeaddr)
+{
+ char edit_buf[MAX_NICKNAME + 1];
+ HelpType help;
+ int i, flags, lastrc, rc;
+ AdrBk_Entry *check, *passed_in_ae;
+ ESCKEY_S ekey[3];
+ SAVE_STATE_S state; /* For saving state of addrbooks temporarily */
+ char *error = NULL;
+
+ ekey[i = 0].ch = ctrl('T');
+ ekey[i].rval = 2;
+ ekey[i].name = "^T";
+ ekey[i++].label = N_("To AddrBk");
+
+ if(F_ON(F_ENABLE_TAB_COMPLETE,ps_global)){
+ ekey[i].ch = ctrl('I');
+ ekey[i].rval = 11;
+ ekey[i].name = "TAB";
+ ekey[i++].label = N_("Complete");
+ }
+
+ ekey[i].ch = -1;
+
+ strncpy(edit_buf, orig, sizeof(edit_buf)-1);
+ edit_buf[sizeof(edit_buf)-1] = '\0';
+ if(dl)
+ passed_in_ae = adrbk_get_ae(abook, (a_c_arg_t) dl->elnum);
+ else
+ passed_in_ae = (AdrBk_Entry *)NULL;
+
+ help = NO_HELP;
+ rc = 0;
+ check = NULL;
+ do{
+ if(error){
+ q_status_message(SM_ORDER, 3, 4, error);
+ fs_give((void **)&error);
+ }
+
+ /* display a message because adrbk_lookup_by_nick returned positive */
+ if(check){
+ if(return_existing){
+ strncpy(orig, edit_buf, sizeof(edit_buf)-1);
+ orig[sizeof(edit_buf)-1] = '\0';
+ if(passed_in_ae)
+ (void)adrbk_get_ae(abook, (a_c_arg_t) dl->elnum);
+ return -8;
+ }
+
+ q_status_message1(SM_ORDER, 0, 4,
+ _("Already an entry with nickname \"%s\""), edit_buf);
+ }
+
+ lastrc = rc;
+ if(rc == 3)
+ help = (help == NO_HELP ? this_help : NO_HELP);
+
+ flags = OE_APPEND_CURRENT;
+ rc = optionally_enter(edit_buf, command_line, 0, sizeof(edit_buf),
+ prompt, ekey, help, &flags);
+
+ if(rc == 1) /* ^C */
+ break;
+
+ if(rc == 2){ /* ^T */
+ void (*redraw) (void) = ps_global->redrawer;
+ char *returned_nickname;
+
+ push_titlebar_state();
+ save_state(&state);
+ if(takeaddr)
+ returned_nickname = addr_book_takeaddr();
+ else
+ returned_nickname = addr_book_selnick();
+
+ restore_state(&state);
+ if(returned_nickname){
+ strncpy(edit_buf, returned_nickname, sizeof(edit_buf)-1);
+ edit_buf[sizeof(edit_buf)-1] = '\0';
+ fs_give((void **)&returned_nickname);
+ }
+
+ ClearScreen();
+ pop_titlebar_state();
+ redraw_titlebar();
+ if((ps_global->redrawer = redraw) != NULL) /* reset old value, and test */
+ (*ps_global->redrawer)();
+ }
+ else if(rc == 11){ /* TAB */
+ if(edit_buf[0]){
+ char *new_nickname = NULL;
+ int ambiguity;
+
+ ambiguity = abook_nickname_complete(edit_buf, &new_nickname,
+ (lastrc==rc && !(flags & OE_USER_MODIFIED)), 0);
+ if(new_nickname){
+ if(*new_nickname){
+ strncpy(edit_buf, new_nickname, sizeof(edit_buf));
+ edit_buf[sizeof(edit_buf)-1] = '\0';
+ }
+
+ fs_give((void **) &new_nickname);
+ }
+
+ if(ambiguity != 2)
+ Writechar(BELL, 0);
+ }
+ }
+
+ }while(rc == 2 ||
+ rc == 3 ||
+ rc == 4 ||
+ rc == 11||
+ nickname_check(edit_buf, &error) ||
+ ((check =
+ adrbk_lookup_by_nick(abook, edit_buf, (adrbk_cntr_t *)NULL)) &&
+ check != passed_in_ae));
+
+ if(rc != 0){
+ if(passed_in_ae)
+ (void)adrbk_get_ae(abook, (a_c_arg_t) dl->elnum);
+
+ return -10;
+ }
+
+ /* only the case of nickname changed */
+ if(passed_in_ae && check == passed_in_ae && strcmp(edit_buf, orig)){
+ (void)adrbk_get_ae(abook, (a_c_arg_t) dl->elnum);
+ strncpy(orig, edit_buf, sizeof(edit_buf)-1);
+ orig[sizeof(edit_buf)-1] = '\0';
+ return -7;
+ }
+
+ if(passed_in_ae)
+ (void)adrbk_get_ae(abook, (a_c_arg_t) dl->elnum);
+
+ if(strcmp(edit_buf, orig) == 0) /* no change */
+ return -9;
+
+ strncpy(orig, edit_buf, sizeof(edit_buf)-1);
+ orig[sizeof(edit_buf)-1] = '\0';
+ return 0;
+}
+
+
+/*
+ * Add an entry to address book.
+ * It is for capturing addresses off incoming mail.
+ * This is a front end for take_to_addrbooks.
+ * It is also used for replacing an existing entry and for adding a single
+ * new address to an existing list.
+ *
+ * The reason this is here is so that when Taking a single address, we can
+ * rearrange the fullname to be Last, First instead of First Last.
+ *
+ * Args: ta_entry -- the entry from the take screen
+ * command_line -- line to prompt on
+ *
+ * Result: item is added to one of the address books,
+ * an error message is queued if appropriate.
+ */
+void
+add_abook_entry(TA_S *ta_entry, char *nick, char *fullname, char *fcc,
+ char *comment, int command_line, TA_STATE_S **tas, char *cmd)
+{
+ ADDRESS *addr;
+ char new_fullname[6*MAX_FULLNAME + 1], new_address[6*MAX_ADDRESS + 1];
+ char **new_list;
+
+ dprint((5, "-- add_abook_entry --\n"));
+
+ /*-- rearrange full name (Last, First) ---*/
+ new_fullname[0] = '\0';
+ addr = ta_entry->addr;
+ if(!fullname && addr->personal != NULL){
+ if(F_ON(F_DISABLE_TAKE_LASTFIRST, ps_global)){
+ strncpy(new_fullname, addr->personal, sizeof(new_fullname)-1);
+ new_fullname[sizeof(new_fullname)-1] = '\0';
+ }
+ else{
+ char old_fullname[6*MAX_FULLNAME + 1];
+
+ snprintf(old_fullname, sizeof(old_fullname), "%s", addr->personal);
+ old_fullname[sizeof(old_fullname)-1] = '\0';
+ switch_to_last_comma_first(old_fullname, new_fullname, sizeof(new_fullname));
+ }
+ }
+
+ /* initial value for new address */
+ new_address[0] = '\0';
+ if(addr->mailbox && addr->mailbox[0]){
+ char *scratch, *p, *t, *u;
+ size_t es;
+ unsigned long l;
+ RFC822BUFFER rbuf;
+
+ es = est_size(addr);
+ scratch = (char *) fs_get(es);
+ scratch[0] = '\0';
+ rbuf.f = dummy_soutr;
+ rbuf.s = NULL;
+ rbuf.beg = scratch;
+ rbuf.cur = scratch;
+ rbuf.end = scratch+es-1;
+ rfc822_output_address_list(&rbuf, addr, 0L, NULL);
+ *rbuf.cur = '\0';
+ if((p = srchstr(scratch, "@" RAWFIELD)) != NULL){
+ for(t = p; ; t--)
+ if(*t == '&'){ /* find "leading" token */
+ *t++ = ' '; /* replace token */
+ *p = '\0'; /* tie off string */
+ u = (char *)rfc822_base64((unsigned char *)t,
+ (unsigned long)strlen(t), &l);
+ *p = '@'; /* restore 'p' */
+ rplstr(p, es-(p-scratch), 12, ""); /* clear special token */
+ rplstr(t, es-(t-scratch), strlen(t), u); /* Null u is handled */
+ if(u)
+ fs_give((void **)&u);
+ }
+ else if(t == scratch)
+ break;
+ }
+
+ strncpy(new_address, scratch, sizeof(new_address)-1);
+ new_address[sizeof(new_address)-1] = '\0';
+
+ if(scratch)
+ fs_give((void **)&scratch);
+ }
+
+ if(ta_entry->frwrded){
+ ADDRESS *a;
+ int i, j;
+
+ for(i = 0, a = addr; a; i++, a = a->next)
+ ;/* just counting for alloc below */
+
+ /* catch special case where empty addr was set in vcard_to_ta */
+ if(i == 1 && !addr->host && !addr->mailbox && !addr->personal)
+ i = 0;
+
+ new_list = (char **) fs_get((i+1) * sizeof(char *));
+ for(j = 0, a = addr; i && a; j++, a = a->next){
+ ADDRESS *next_addr;
+ char *bufp;
+ size_t len;
+
+ next_addr = a->next;
+ a->next = NULL;
+ len = est_size(a);
+ bufp = (char *) fs_get(len * sizeof(char));
+ new_list[j] = cpystr(addr_string(a, bufp, len));
+ a->next = next_addr;
+ fs_give((void **) &bufp);
+ }
+
+ new_list[j] = NULL;
+ }
+ else{
+ int i = 0, j;
+
+ j = (ta_entry->strvalue && ta_entry->strvalue[0]) ? 2 : 1;
+
+ new_list = (char **) fs_get(j * sizeof(char *));
+
+ if(j == 2)
+ new_list[i++] = cpystr(ta_entry->strvalue);
+
+ new_list[i] = NULL;
+ }
+
+ take_to_addrbooks_frontend(new_list, nick,
+ fullname ? fullname : new_fullname,
+ new_address, fcc, comment, command_line,
+ tas, cmd);
+ free_list_array(&new_list);
+}
+
+
+void
+take_to_addrbooks_frontend(char **new_entries, char *nick, char *fullname,
+ char *addr, char *fcc, char *comment, int cmdline,
+ TA_STATE_S **tas, char *cmd)
+{
+ jmp_buf save_jmp_buf;
+ int *save_nesting_level;
+
+ dprint((5, "-- take_to_addrbooks_frontend --\n"));
+
+ if(ps_global->remote_abook_validity > 0 &&
+ adrbk_check_and_fix_all(ab_nesting_level == 0, 0, 0))
+ ps_global->mangled_footer = 1;
+
+ save_nesting_level = cpyint(ab_nesting_level);
+ memcpy(save_jmp_buf, addrbook_changed_unexpectedly, sizeof(jmp_buf));
+ if(setjmp(addrbook_changed_unexpectedly)){
+ q_status_message(SM_ORDER, 5, 10, _("Resetting address book..."));
+ dprint((1,
+ "RESETTING address book... take_to_addrbooks_frontend!\n"));
+ addrbook_reset();
+ ab_nesting_level = *save_nesting_level;
+ }
+
+ ab_nesting_level++;
+ take_to_addrbooks(new_entries, nick, fullname, addr, fcc, comment, cmdline,
+ tas, cmd);
+ memcpy(addrbook_changed_unexpectedly, save_jmp_buf, sizeof(jmp_buf));
+ ab_nesting_level--;
+ if(save_nesting_level)
+ fs_give((void **)&save_nesting_level);
+}
+
+
+/*
+ * Add to address book, called from take screen.
+ * It is also used for adding to an existing list or replacing an existing
+ * entry.
+ *
+ * Args: new_entries -- a list of addresses to add to a list or to form
+ * a new list with
+ * nick -- if adding new entry, suggest this for nickname
+ * fullname -- if adding new entry, use this for fullname
+ * addr -- if only one new_entry, this is its addr
+ * fcc -- if adding new entry, use this for fcc
+ * comment -- if adding new entry, use this for comment
+ * command_line -- line to prompt on
+ *
+ * Result: item is added to one of the address books,
+ * an error message is queued if appropriate.
+ */
+void
+take_to_addrbooks(char **new_entries, char *nick, char *fullname, char *addr,
+ char *fcc, char *comment, int command_line, TA_STATE_S **tas, char *cmd)
+{
+ char new_nickname[6*MAX_NICKNAME + 1], exist_nick[6*MAX_NICKNAME + 1];
+ char prompt[200], **p;
+ int rc, listadd = 0, ans, i;
+ AdrBk *abook;
+ SAVE_STATE_S state;
+ PerAddrBook *pab;
+ AdrBk_Entry *abe = (AdrBk_Entry *)NULL, *abe_copy;
+ adrbk_cntr_t entry_num = NO_NEXT;
+ size_t tot_size, new_size, old_size;
+ Tag old_tag;
+ char *tmp_a_string;
+ char *simple_a = NULL;
+ ADDRESS *a = NULL;
+
+
+ dprint((5, "-- take_to_addrbooks --\n"));
+
+ if(tas && *tas)
+ pab = (*tas)->pab;
+ else
+ pab = setup_for_addrbook_add(&state, command_line, cmd);
+
+ /* check we got it opened ok */
+ if(pab == NULL || pab->address_book == NULL)
+ goto take_to_addrbooks_cancel;
+
+ adrbk_check_validity(pab->address_book, 1L);
+ if(pab->address_book->flags & FILE_OUTOFDATE ||
+ (pab->address_book->rd &&
+ pab->address_book->rd->flags & REM_OUTOFDATE)){
+ q_status_message3(SM_ORDER, 0, 4,
+ "Address book%s%s has changed: %stry again",
+ (as.n_addrbk > 1 && pab->abnick) ? " " : "",
+ (as.n_addrbk > 1 && pab->abnick) ? pab->abnick : "",
+ (ps_global->remote_abook_validity == -1) ? "resynchronize and " : "");
+ if(tas && *tas){
+ restore_state(&((*tas)->state));
+ (*tas)->pab = NULL;
+ }
+ else
+ restore_state(&state);
+
+ return;
+ }
+
+ abook = pab->address_book;
+ new_nickname[0] = '\0';
+ exist_nick[0] = '\0';
+
+ if(addr){
+ simple_a = NULL;
+ a = NULL;
+ /* rfc822_parse_adrlist feels free to destroy input so send copy */
+ tmp_a_string = cpystr(addr);
+ rfc822_parse_adrlist(&a, tmp_a_string, fakedomain);
+ if(tmp_a_string)
+ fs_give((void **)&tmp_a_string);
+
+ if(a){
+ simple_a = simple_addr_string(a, tmp_20k_buf, SIZEOF_20KBUF);
+ mail_free_address(&a);
+ }
+
+ if(simple_a && *simple_a)
+ abe = adrbk_lookup_by_addr(abook, simple_a, NULL);
+
+ if(abe){
+ snprintf(prompt, sizeof(prompt), _("Warning: address exists with %s%s, continue "),
+ (abe->nickname && abe->nickname[0]) ? "nickname "
+ : (abe->fullname && abe->fullname[0]) ? "fullname "
+ : "no nickname",
+ (abe->nickname && abe->nickname[0]) ? abe->nickname
+ : (abe->fullname && abe->fullname[0]) ? abe->fullname
+ : "");
+ prompt[sizeof(prompt)-1] = '\0';
+ switch(want_to(prompt, 'y', 'x', NO_HELP, WT_NORM)){
+ case 'y':
+ if(abe->nickname && abe->nickname[0]){
+ strncpy(new_nickname, abe->nickname, sizeof(new_nickname));
+ new_nickname[sizeof(new_nickname)-1] = '\0';
+ strncpy(exist_nick, new_nickname, sizeof(exist_nick));
+ exist_nick[sizeof(exist_nick)-1] = '\0';
+ }
+
+ break;
+
+ default:
+ goto take_to_addrbooks_cancel;
+ }
+ }
+ }
+
+get_nick:
+ abe = NULL;
+ old_tag = NotSet;
+ entry_num = NO_NEXT;
+
+ /*----- nickname ------*/
+ snprintf(prompt, sizeof(prompt),
+ _("Enter new or existing nickname (one word and easy to remember): "));
+ prompt[sizeof(prompt)-1] = '\0';
+ if(!new_nickname[0] && nick){
+ strncpy(new_nickname, nick, sizeof(new_nickname));
+ new_nickname[sizeof(new_nickname)-1] = '\0';
+ }
+
+ rc = edit_nickname(abook, (AddrScrn_Disp *)NULL, command_line,
+ new_nickname, prompt, h_oe_takenick, 1, 1);
+ if(rc == -8){ /* this means an existing nickname was entered */
+ abe = adrbk_lookup_by_nick(abook, new_nickname, &entry_num);
+ if(!abe){ /* this shouldn't happen */
+ q_status_message1(SM_ORDER, 0, 4,
+ _("Already an entry %s in address book!"), new_nickname);
+ goto take_to_addrbooks_cancel;
+ }
+
+ old_tag = abe->tag;
+
+ if(abe->tag == Single && !strcmp(new_nickname, exist_nick)){
+ static ESCKEY_S choices[] = {
+ {'r', 'r', "R", N_("Replace")},
+ {'n', 'n', "N", N_("No")},
+ {-1, 0, NULL, NULL}};
+
+ snprintf(prompt, sizeof(prompt), _("Entry %s (%s) exists, replace ? "),
+ new_nickname,
+ (abe->fullname && abe->fullname[0])
+ ? (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf,
+ SIZEOF_20KBUF, abe->fullname)
+ : "<no long name>");
+ prompt[sizeof(prompt)-1] = '\0';
+ ans = radio_buttons(prompt,
+ command_line,
+ choices,
+ 'r',
+ 'x',
+ h_oe_take_replace,
+ RB_NORM);
+ }
+ else{
+ static ESCKEY_S choices[] = {
+ {'r', 'r', "R", N_("Replace")},
+ {'a', 'a', "A", N_("Add")},
+ {'n', 'n', "N", N_("No")},
+ {-1, 0, NULL, NULL}};
+
+ snprintf(prompt, sizeof(prompt),
+ _("%s %s (%s) exists, replace or add addresses to it ? "),
+ abe->tag == List ? "List" : "Entry",
+ new_nickname,
+ (abe->fullname && abe->fullname[0])
+ ? (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf,
+ SIZEOF_20KBUF, abe->fullname)
+ : "<no long name>");
+ prompt[sizeof(prompt)-1] = '\0';
+
+ ans = radio_buttons(prompt,
+ command_line,
+ choices,
+ 'a',
+ 'x',
+ h_oe_take_replace_or_add,
+ RB_NORM);
+ }
+
+ switch(ans){
+ case 'y':
+ case 'r':
+ break;
+
+ case 'n':
+ goto get_nick;
+ break;
+
+ case 'a':
+ listadd++;
+ break;
+
+ default:
+ goto take_to_addrbooks_cancel;
+ }
+ }
+ else if(rc != 0 && rc != -9) /* -9 means a null nickname */
+ goto take_to_addrbooks_cancel;
+
+ if((long)abook->count > MAX_ADRBK_SIZE ||
+ (old_tag == NotSet && (long)abook->count >= MAX_ADRBK_SIZE)){
+ q_status_message(SM_ORDER, 3, 5,
+ _("Address book is at maximum size, cancelled."));
+ dprint((2, "Addrbook at Max size, TakeAddr cancelled\n"));
+ goto take_to_addrbooks_cancel;
+ }
+
+ if(listadd){
+ /* count up size of existing list */
+ if(abe->tag == List){
+ for(p = abe->addr.list; p != NULL && *p != NULL; p++)
+ ;/* do nothing */
+
+ old_size = p - abe->addr.list;
+ }
+ /* or size of existing single address */
+ else if(abe->addr.addr && abe->addr.addr[0])
+ old_size = 1;
+ else
+ old_size = 0;
+ }
+ else /* don't care about old size, they will be tossed in edit_entry */
+ old_size = 0;
+
+ /* make up an abe to pass to edit_entry */
+ abe_copy = adrbk_newentry();
+ abe_copy->nickname = cpystr(new_nickname);
+ abe_copy->tag = List;
+ abe_copy->addr.list = NULL;
+
+ if(listadd){
+ abe_copy->fullname = cpystr((abe->fullname && abe->fullname[0])
+ ? abe->fullname : "");
+ abe_copy->fcc = cpystr((abe->fcc && abe->fcc[0]) ? abe->fcc : "");
+ abe_copy->extra = cpystr((abe->extra&&abe->extra[0]) ? abe->extra : "");
+ }
+ else{
+ /*
+ * use passed in info if available
+ */
+ abe_copy->fullname = cpystr((fullname && fullname[0])
+ ? fullname
+ : (abe && abe->fullname)
+ ? abe->fullname
+ : "");
+ abe_copy->fcc = cpystr((fcc && fcc[0])
+ ? fcc
+ : (abe && abe->fcc)
+ ? abe->fcc
+ : "");
+ abe_copy->extra = cpystr((comment && comment[0])
+ ? comment
+ : (abe && abe->extra)
+ ? abe->extra
+ : "");
+ }
+
+ /* get rid of duplicates */
+ if(listadd){
+ if(abe->tag == List){
+ int elim_dup;
+ char **q, **r;
+ ADDRESS *newadr, *oldadr;
+
+ for(q = new_entries; q != NULL && *q != NULL;){
+
+ tmp_a_string = cpystr(*q);
+ newadr = NULL;
+ rfc822_parse_adrlist(&newadr, tmp_a_string, fakedomain);
+ fs_give((void **) &tmp_a_string);
+
+ elim_dup = (newadr == NULL);
+ for(p = abe->addr.list;
+ !elim_dup && p != NULL && *p != NULL;
+ p++){
+ tmp_a_string = cpystr(*p);
+ oldadr = NULL;
+ rfc822_parse_adrlist(&oldadr, tmp_a_string, fakedomain);
+ fs_give((void **) &tmp_a_string);
+
+ if(address_is_same(newadr, oldadr))
+ elim_dup++;
+
+ if(oldadr)
+ mail_free_address(&oldadr);
+ }
+
+ /* slide the addresses down one to eliminate newadr */
+ if(elim_dup){
+ char *f;
+
+ f = *q;
+ for(r = q; r != NULL && *r != NULL; r++)
+ *r = *(r+1);
+
+ if(f)
+ fs_give((void **) &f);
+ }
+ else
+ q++;
+
+ if(newadr)
+ mail_free_address(&newadr);
+ }
+ }
+ else{
+ char **q, **r;
+ ADDRESS *newadr, *oldadr;
+
+ tmp_a_string = cpystr(abe->addr.addr ? abe->addr.addr : "");
+ oldadr = NULL;
+ rfc822_parse_adrlist(&oldadr, tmp_a_string, fakedomain);
+ fs_give((void **) &tmp_a_string);
+
+ for(q = new_entries; q != NULL && *q != NULL;){
+
+ tmp_a_string = cpystr(*q);
+ newadr = NULL;
+ rfc822_parse_adrlist(&newadr, tmp_a_string, fakedomain);
+ fs_give((void **) &tmp_a_string);
+
+ /* slide the addresses down one to eliminate newadr */
+ if(address_is_same(newadr, oldadr)){
+ char *f;
+
+ f = *q;
+ for(r = q; r != NULL && *r != NULL; r++)
+ *r = *(r+1);
+
+ if(f)
+ fs_give((void **) &f);
+ }
+ else
+ q++;
+
+ if(newadr)
+ mail_free_address(&newadr);
+ }
+
+ if(oldadr)
+ mail_free_address(&oldadr);
+ }
+
+ if(!new_entries || !*new_entries){
+ q_status_message1(SM_ORDER, 0, 4,
+ _("All of the addresses are already included in \"%s\""),
+ new_nickname);
+ free_ae(&abe_copy);
+ if(tas && *tas){
+ restore_state(&((*tas)->state));
+ (*tas)->pab = NULL;
+ }
+ else
+ restore_state(&state);
+
+ return;
+ }
+ }
+
+ /* count up size of new list */
+ for(p = new_entries; p != NULL && *p != NULL; p++)
+ ;/* do nothing */
+
+ new_size = p - new_entries;
+ tot_size = old_size + new_size;
+ abe_copy->addr.list = (char **) fs_get((tot_size+1) * sizeof(char *));
+ memset((void *) abe_copy->addr.list, 0, (tot_size+1) * sizeof(char *));
+ if(old_size > 0){
+ if(abe->tag == List){
+ for(i = 0; i < old_size; i++)
+ abe_copy->addr.list[i] = cpystr(abe->addr.list[i]);
+ }
+ else
+ abe_copy->addr.list[0] = cpystr(abe->addr.addr);
+ }
+
+ /* add new addresses to list */
+ if(tot_size == 1 && addr)
+ abe_copy->addr.list[0] = cpystr(addr);
+ else
+ for(i = 0; i < new_size; i++)
+ abe_copy->addr.list[old_size + i] = cpystr(new_entries[i]);
+
+ abe_copy->addr.list[tot_size] = NULL;
+
+ if(F_ON(F_DISABLE_TAKE_FULLNAMES, ps_global)){
+ for(i = 0; abe_copy->addr.list[i]; i++){
+ simple_a = NULL;
+ a = NULL;
+ tmp_a_string = cpystr(abe_copy->addr.list[i]);
+ rfc822_parse_adrlist(&a, tmp_a_string, fakedomain);
+ if(tmp_a_string)
+ fs_give((void **) &tmp_a_string);
+
+ if(a){
+ simple_a = simple_addr_string(a, tmp_20k_buf, SIZEOF_20KBUF);
+ mail_free_address(&a);
+ }
+
+ /* replace the old addr string with one with no full name */
+ if(simple_a && *simple_a){
+ if(abe_copy->addr.list[i])
+ fs_give((void **) &abe_copy->addr.list[i]);
+
+ abe_copy->addr.list[i] = cpystr(simple_a);
+ }
+ }
+ }
+
+ edit_entry(abook, abe_copy, (a_c_arg_t) entry_num, old_tag, 0, NULL, cmd);
+
+ /* free copy */
+ free_ae(&abe_copy);
+ if(tas && *tas){
+ restore_state(&((*tas)->state));
+ (*tas)->pab = NULL;
+ }
+ else
+ restore_state(&state);
+
+ return;
+
+take_to_addrbooks_cancel:
+ q_status_message(SM_INFO, 0, 2, _("Address book addition cancelled"));
+ if(tas && *tas){
+ restore_state(&((*tas)->state));
+ (*tas)->pab = NULL;
+ }
+ else
+ restore_state(&state);
+}
+
+
+/*
+ * Prep addrbook for TakeAddr add operation.
+ *
+ * Arg: savep -- Address of a pointer to save addrbook state in.
+ * stp -- Address of a pointer to save addrbook state in.
+ *
+ * Returns: a PerAddrBook pointer, or NULL.
+ */
+PerAddrBook *
+setup_for_addrbook_add(SAVE_STATE_S *state, int command_line, char *cmd)
+{
+ PerAddrBook *pab;
+ int save_rem_abook_valid = 0;
+
+ init_ab_if_needed();
+ save_state(state);
+
+ if(as.n_addrbk == 0){
+ q_status_message(SM_ORDER, 3, 4, _("No address book configured!"));
+ return NULL;
+ }
+ else
+ pab = use_this_addrbook(command_line, cmd);
+
+ if(!pab)
+ return NULL;
+
+ if((pab->type & REMOTE_VIA_IMAP) && ps_global->remote_abook_validity == -1){
+ save_rem_abook_valid = -1;
+ ps_global->remote_abook_validity = 0;
+ }
+
+ /* initialize addrbook so we can add to it */
+ init_abook(pab, Open);
+
+ if(save_rem_abook_valid)
+ ps_global->remote_abook_validity = save_rem_abook_valid;
+
+ if(pab->ostatus != Open){
+ q_status_message(SM_ORDER, 3, 4, _("Can't open address book!"));
+ return NULL;
+ }
+
+ if(pab->access != ReadWrite){
+ if(pab->access == ReadOnly)
+ q_status_message(SM_ORDER, 0, 4, _("AddressBook is Read Only"));
+ else if(pab->access == NoAccess)
+ q_status_message(SM_ORDER, 3, 4,
+ _("AddressBook not accessible, permission denied"));
+
+ return NULL;
+ }
+
+ return(pab);
+}
+
+
+/*
+ * Interact with user to figure out which address book they want to add a
+ * new entry (TakeAddr) to.
+ *
+ * Args: command_line -- just the line to prompt on
+ *
+ * Results: returns a pab pointing to the selected addrbook, or NULL.
+ */
+PerAddrBook *
+use_this_addrbook(int command_line, char *cmd)
+{
+ HelpType help;
+ int rc = 0;
+ PerAddrBook *pab, *the_only_pab;
+#define MAX_ABOOK 2000
+ int i, abook_num, count_read_write;
+ char addrbook[MAX_ABOOK + 1],
+ prompt[MAX_ABOOK + 81];
+ static ESCKEY_S ekey[] = {
+ {-2, 0, NULL, NULL},
+ {ctrl('P'), 10, "^P", N_("Prev AddrBook")},
+ {ctrl('N'), 11, "^N", N_("Next AddrBook")},
+ {KEY_UP, 10, "", ""},
+ {KEY_DOWN, 11, "", ""},
+ {-1, 0, NULL, NULL}};
+
+ dprint((9, "- use_this_addrbook -\n"));
+
+ /* check for only one ReadWrite addrbook */
+ count_read_write = 0;
+ for(i = 0; i < as.n_addrbk; i++){
+ pab = &as.adrbks[i];
+ /*
+ * NoExists is counted, too, so the user can add to an empty
+ * addrbook the first time.
+ */
+ if(pab->access == ReadWrite ||
+ pab->access == NoExists ||
+ pab->access == MaybeRorW){
+ count_read_write++;
+ the_only_pab = &as.adrbks[i];
+ }
+ }
+
+ /* only one usable addrbook, use it */
+ if(count_read_write == 1)
+ return(the_only_pab);
+
+ /* no addrbook to write to */
+ if(count_read_write == 0){
+ q_status_message2(SM_ORDER | SM_DING, 3, 4,
+ "No %sAddressbook to %s to!",
+ (as.n_addrbk > 0) ? "writable " : "", cmd);
+ return NULL;
+ }
+
+ /* start with the first addrbook */
+ abook_num = 0;
+ pab = &as.adrbks[abook_num];
+ strncpy(addrbook, pab->abnick, sizeof(addrbook)-1);
+ addrbook[sizeof(addrbook)-1] = '\0';
+ snprintf(prompt, sizeof(prompt), "%c%s to which addrbook : %s",
+ islower((unsigned char)(*cmd)) ? toupper((unsigned char)*cmd) : *cmd,
+ cmd+1,
+ (pab->access == ReadOnly || pab->access == NoAccess) ?
+ "[ReadOnly] " : "");
+ prompt[sizeof(prompt)-1] = '\0';
+ help = NO_HELP;
+ ps_global->mangled_footer = 1;
+ do{
+ int flags;
+
+ if(!pab)
+ q_status_message1(SM_ORDER, 3, 4, _("No addressbook \"%s\""),
+ addrbook);
+
+ if(rc == 3)
+ help = (help == NO_HELP ? h_oe_chooseabook : NO_HELP);
+
+ flags = OE_APPEND_CURRENT;
+ rc = optionally_enter(addrbook, command_line, 0, sizeof(addrbook),
+ prompt, ekey, help, &flags);
+
+ if(rc == 1){ /* ^C */
+ char capcmd[50];
+
+ snprintf(capcmd, sizeof(capcmd),
+ "%c%s",
+ islower((unsigned char)(*cmd)) ? toupper((unsigned char)*cmd)
+ : *cmd,
+ cmd+1);
+ capcmd[sizeof(capcmd)-1] = '\0';
+ cmd_cancelled(capcmd);
+ break;
+ }
+
+ if(rc == 10){ /* Previous addrbook */
+ if(--abook_num < 0)
+ abook_num = as.n_addrbk - 1;
+
+ pab = &as.adrbks[abook_num];
+ strncpy(addrbook, pab->abnick, sizeof(addrbook)-1);
+ addrbook[sizeof(addrbook)-1] = '\0';
+ snprintf(prompt, sizeof(prompt), "%s to which addrbook : %s", cmd,
+ (pab->access == ReadOnly || pab->access == NoAccess) ?
+ "[ReadOnly] " : "");
+ prompt[sizeof(prompt)-1] = '\0';
+ }
+ else if(rc == 11){ /* Next addrbook */
+ if(++abook_num > as.n_addrbk - 1)
+ abook_num = 0;
+
+ pab = &as.adrbks[abook_num];
+ strncpy(addrbook, pab->abnick, sizeof(addrbook)-1);
+ addrbook[sizeof(addrbook)-1] = '\0';
+ snprintf(prompt, sizeof(prompt), "%s to which addrbook : %s", cmd,
+ (pab->access == ReadOnly || pab->access == NoAccess) ?
+ "[ReadOnly] " : "");
+ prompt[sizeof(prompt)-1] = '\0';
+ }
+
+ }while(rc == 2 || rc == 3 || rc == 4 || rc == 10 || rc == 11 || rc == 12 ||
+ !(pab = check_for_addrbook(addrbook)));
+
+ ps_global->mangled_footer = 1;
+
+ if(rc != 0)
+ return NULL;
+
+ return(pab);
+}
+
+
+/*
+ * Return a pab pointer to the addrbook which corresponds to the argument.
+ *
+ * Args: addrbook -- the string representing the addrbook.
+ *
+ * Results: returns a PerAddrBook pointer for the referenced addrbook, NULL
+ * if none. First the nicknames are checked and then the filenames.
+ * This must be one of the existing addrbooks.
+ */
+PerAddrBook *
+check_for_addrbook(char *addrbook)
+{
+ register int i;
+ register PerAddrBook *pab;
+
+ for(i = 0; i < as.n_addrbk; i++){
+ pab = &as.adrbks[i];
+ if(strcmp(pab->abnick, addrbook) == 0)
+ break;
+ }
+
+ if(i < as.n_addrbk)
+ return(pab);
+
+ for(i = 0; i < as.n_addrbk; i++){
+ pab = &as.adrbks[i];
+ if(strcmp(pab->filename, addrbook) == 0)
+ break;
+ }
+
+ if(i < as.n_addrbk)
+ return(pab);
+
+ return NULL;
+}
+
+
+/*
+ * Screen for selecting which addresses to Take to address book.
+ *
+ * Args: ps -- Pine state
+ * ta_list -- Screen is formed from this list of addresses
+ * how_many_selected -- how many checked initially in ListMode
+ * mode -- which mode to start in
+ *
+ * Result: an address book may be updated
+ * Returns -- 0 normally
+ * 1 if it returns before redrawing screen
+ */
+int
+takeaddr_screen(struct pine *ps, TA_S *ta_list, int how_many_selected,
+ ScreenMode mode, TA_STATE_S **tas, char *command)
+{
+ UCS ch = 'x';
+ int cmd, dline, give_warn_message, command_line;
+ int km_popped = 0,
+ directly_to_take = 0,
+ ret = 0,
+ done = 0;
+ TA_S *current = NULL,
+ *ctmp = NULL;
+ TA_SCREEN_S screen;
+ Pos cursor_pos;
+ char *utf8str;
+ struct key_menu *km;
+
+ dprint((2, "- takeaddr_screen -\n"));
+
+ command_line = -FOOTER_ROWS(ps); /* third line from the bottom */
+
+ screen.current = screen.top_line = NULL;
+ screen.mode = mode;
+
+ if(ta_list == NULL){
+ /* TRANSLATORS: something like
+ No addresses to save, cancelled */
+ q_status_message1(SM_INFO, 0, 2, "No addresses to %s, cancelled",
+ command);
+ return 1;
+ }
+
+ current = first_sel_taline(ta_list);
+ ps->mangled_screen = 1;
+ ta_screen = &screen;
+
+ if(is_talist_of_one(current)){
+ directly_to_take++;
+ screen.mode = SingleMode;
+ }
+ else if(screen.mode == ListMode)
+ q_status_message(SM_INFO, 0, 1,
+ _("List mode: Use \"X\" to mark addresses to be included in list"));
+ else
+ q_status_message(SM_INFO, 0, 1,
+ _("Single mode: Use \"P\" or \"N\" to select desired address"));
+
+ while(!done){
+ if(km_popped){
+ km_popped--;
+ if(km_popped == 0){
+ clearfooter(ps);
+ ps->mangled_body = 1;
+ }
+ }
+
+ if(screen.mode == ListMode)
+ ps->redrawer = takeaddr_screen_redrawer_list;
+ else
+ ps->redrawer = takeaddr_screen_redrawer_single;
+
+ if(ps->mangled_screen){
+ ps->mangled_header = 1;
+ ps->mangled_footer = 1;
+ ps->mangled_body = 1;
+ ps->mangled_screen = 0;
+ }
+
+ /*----------- Check for new mail -----------*/
+ if(new_mail(0, NM_TIMING(ch), NM_STATUS_MSG | NM_DEFER_SORT) >= 0)
+ ps->mangled_header = 1;
+
+#ifdef _WINDOWS
+ mswin_beginupdate();
+#endif
+ if(ps->mangled_header){
+ char tbuf[40];
+
+ snprintf(tbuf, sizeof(tbuf), "TAKE ADDRESS SCREEN (%s Mode)",
+ (screen.mode == ListMode) ? "List"
+ : "Single");
+ tbuf[sizeof(tbuf)-1] = '\0';
+ set_titlebar(tbuf, ps->mail_stream, ps->context_current,
+ ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0,
+ NULL);
+ ps->mangled_header = 0;
+ }
+
+ dline = update_takeaddr_screen(ps, current, &screen, &cursor_pos);
+ if(F_OFF(F_SHOW_CURSOR, ps)){
+ cursor_pos.row = ps->ttyo->screen_rows - FOOTER_ROWS(ps);
+ cursor_pos.col = 0;
+ }
+
+ /*---- This displays new mail notification, or errors ---*/
+ if(km_popped){
+ FOOTER_ROWS(ps_global) = 3;
+ mark_status_unknown();
+ }
+
+ display_message(ch);
+ if(km_popped){
+ FOOTER_ROWS(ps_global) = 1;
+ mark_status_unknown();
+ }
+
+ /*---- Redraw footer ----*/
+ if(ps->mangled_footer){
+ bitmap_t bitmap;
+
+ if(km_popped){
+ FOOTER_ROWS(ps) = 3;
+ clearfooter(ps);
+ }
+
+ setbitmap(bitmap);
+ ps->mangled_footer = 0;
+
+ km = (screen.mode == ListMode) ? &ta_keymenu_lm : &ta_keymenu_sm;
+
+ menu_clear_binding(km, KEY_LEFT);
+ menu_clear_binding(km, KEY_RIGHT);
+ if(F_ON(F_ARROW_NAV, ps_global)){
+ int cmd;
+
+ if((cmd = menu_clear_binding(km, '<')) != MC_UNKNOWN){
+ menu_add_binding(km, '<', cmd);
+ menu_add_binding(km, KEY_LEFT, cmd);
+ }
+
+ if((cmd = menu_clear_binding(km, '>')) != MC_UNKNOWN){
+ menu_add_binding(km, '>', cmd);
+ menu_add_binding(km, KEY_RIGHT, cmd);
+ }
+ }
+
+ draw_keymenu(km, bitmap, ps->ttyo->screen_cols,
+ 1 - FOOTER_ROWS(ps_global), 0, FirstMenu);
+
+ if(km_popped){
+ FOOTER_ROWS(ps) = 1;
+ mark_keymenu_dirty();
+ }
+ }
+
+#ifdef _WINDOWS
+ mswin_endupdate();
+#endif
+ /*------ Read the command from the keyboard ----*/
+ MoveCursor(cursor_pos.row, cursor_pos.col);
+
+ if(directly_to_take){ /* bypass this screen */
+ cmd = MC_TAKE;
+ blank_keymenu(ps_global->ttyo->screen_rows - 2, 0);
+ }
+ else {
+#ifdef MOUSE
+ mouse_in_content(KEY_MOUSE, -1, -1, 0, 0);
+ register_mfunc(mouse_in_content, HEADER_ROWS(ps_global), 0,
+ ps_global->ttyo->screen_rows - (FOOTER_ROWS(ps)+1),
+ ps_global->ttyo->screen_cols);
+#endif
+
+#ifdef _WINDOWS
+ mswin_setscrollcallback(ta_scroll_callback);
+#endif
+ ch = READ_COMMAND(&utf8str);
+#ifdef MOUSE
+ clear_mfunc(mouse_in_content);
+#endif
+
+#ifdef _WINDOWS
+ mswin_setscrollcallback(NULL);
+#endif
+ cmd = menu_command(ch, km);
+ if (ta_screen->current)
+ current = ta_screen->current;
+
+ if(km_popped)
+ switch(cmd){
+ case MC_NONE :
+ case MC_OTHER :
+ case MC_RESIZE :
+ case MC_REPAINT :
+ km_popped++;
+ break;
+
+ default:
+ clearfooter(ps);
+ break;
+ }
+ }
+
+ switch(cmd){
+ case MC_HELP : /* help! */
+ if(FOOTER_ROWS(ps_global) == 1 && km_popped == 0){
+ km_popped = 2;
+ ps_global->mangled_footer = 1;
+ break;
+ }
+
+ helper(h_takeaddr_screen, _("HELP FOR TAKE ADDRESS SCREEN"),
+ HLPD_SIMPLE);
+ ps->mangled_screen = 1;
+ break;
+
+ case MC_EXIT: /* exit takeaddr screen */
+ q_status_message(SM_INFO, 0, 2, _("Address book addition cancelled"));
+ ret = 1;
+ done++;
+ break;
+
+ case MC_TAKE:
+ if(ta_do_take(current, how_many_selected, command_line, tas,
+ command))
+ done++;
+ else
+ directly_to_take = 0;
+
+ break;
+
+ case MC_CHARDOWN : /* next list element */
+ if((ctmp = next_sel_taline(current)) != NULL)
+ current = ctmp;
+ else
+ q_status_message(SM_INFO, 0, 1, _("Already on last line."));
+
+ break;
+
+ case MC_CHARUP: /* previous list element */
+ if((ctmp = pre_sel_taline(current)) != NULL)
+ current = ctmp;
+ else
+ q_status_message(SM_INFO, 0, 1, _("Already on first line."));
+
+ break;
+
+ case MC_PAGEDN : /* page forward */
+ give_warn_message = 1;
+ while(dline++ < ps->ttyo->screen_rows - FOOTER_ROWS(ps)){
+ if((ctmp = next_sel_taline(current)) != NULL){
+ current = ctmp;
+ give_warn_message = 0;
+ }
+ else
+ break;
+ }
+
+ if(give_warn_message)
+ q_status_message(SM_INFO, 0, 1, _("Already on last page."));
+
+ break;
+
+ case MC_PAGEUP : /* page backward */
+ /* move to top of screen */
+ give_warn_message = 1;
+ while(dline-- > HEADER_ROWS(ps_global)){
+ if((ctmp = pre_sel_taline(current)) != NULL){
+ current = ctmp;
+ give_warn_message = 0;
+ }
+ else
+ break;
+ }
+
+ /* page back one screenful */
+ while(++dline < ps->ttyo->screen_rows - FOOTER_ROWS(ps)){
+ if((ctmp = pre_sel_taline(current)) != NULL){
+ current = ctmp;
+ give_warn_message = 0;
+ }
+ else
+ break;
+ }
+
+ if(give_warn_message)
+ q_status_message(SM_INFO, 0, 1, _("Already on first page."));
+
+ break;
+
+ case MC_WHEREIS : /* whereis */
+ if((ctmp = whereis_taline(current)) != NULL)
+ current = ctmp;
+
+ ps->mangled_footer = 1;
+ break;
+
+ case KEY_SCRLTO:
+ /* no op for now */
+ break;
+
+#ifdef MOUSE
+ case MC_MOUSE:
+ {
+ MOUSEPRESS mp;
+
+ mouse_get_last(NULL, &mp);
+ mp.row -= HEADER_ROWS(ps_global);
+ ctmp = screen.top_line;
+ if(mp.doubleclick){
+ if(screen.mode == SingleMode){
+ if(ta_do_take(current, how_many_selected, command_line,
+ tas, command))
+ done++;
+ else
+ directly_to_take = 0;
+ }
+ else{
+ current->checked = !current->checked; /* flip it */
+ how_many_selected += (current->checked ? 1 : -1);
+ }
+ }
+ else{
+ while(mp.row && ctmp != NULL){
+ --mp.row;
+ do ctmp = ctmp->next;
+ while(ctmp != NULL && ctmp->skip_it && !ctmp->print);
+ }
+
+ if(ctmp != NULL && !ctmp->skip_it)
+ current = ctmp;
+ }
+ }
+ break;
+#endif
+
+ case MC_REPAINT :
+ case MC_RESIZE :
+ ClearScreen();
+ ps->mangled_screen = 1;
+ break;
+
+ case MC_CHOICE : /* [UN]select this addr */
+ current->checked = !current->checked; /* flip it */
+ how_many_selected += (current->checked ? 1 : -1);
+ break;
+
+ case MC_SELALL : /* select all */
+ how_many_selected = ta_mark_all(first_sel_taline(current));
+ ps->mangled_body = 1;
+ break;
+
+ case MC_UNSELALL: /* unselect all */
+ how_many_selected = ta_unmark_all(first_sel_taline(current));
+ ps->mangled_body = 1;
+ break;
+
+ case MC_LISTMODE: /* switch to SingleMode */
+ if(screen.mode == ListMode){
+ screen.mode = SingleMode;
+ q_status_message(SM_INFO, 0, 1,
+ _("Single mode: Use \"P\" or \"N\" to select desired address"));
+ }
+ else{
+ screen.mode = ListMode;
+ q_status_message(SM_INFO, 0, 1,
+ _("List mode: Use \"X\" to mark addresses to be included in list"));
+
+ if(how_many_selected <= 1){
+ how_many_selected =
+ ta_unmark_all(first_sel_taline(current));
+ current->checked = 1;
+ how_many_selected++;
+ }
+ }
+
+ ps->mangled_screen = 1;
+ break;
+
+
+ case MC_NONE : /* simple timeout */
+ break;
+
+
+ /* Unbound (or not dealt with) keystroke */
+ case MC_CHARRIGHT :
+ case MC_CHARLEFT :
+ case MC_GOTOBOL :
+ case MC_GOTOEOL :
+ case MC_UNKNOWN :
+ default:
+ bogus_command(ch, F_ON(F_USE_FK, ps) ? "F1" : "?");
+ break;
+
+ case MC_UTF8:
+ bogus_utf8_command(utf8str, F_ON(F_USE_FK, ps) ? "F1" : "?");
+ break;
+ }
+ }
+
+ ps->mangled_screen = 1;
+
+ return(ret);
+}
+
+
+/*
+ * Do what takeaddr_screen does except bypass the takeaddr_screen and
+ * go directly to do_take.
+ */
+void
+takeaddr_bypass(struct pine *ps, TA_S *current, TA_STATE_S **tasp)
+{
+ TA_SCREEN_S screen; /* We have to fake out ta_do_take because */
+ /* we're bypassing takeaddr_screen. */
+ ta_screen = &screen;
+ ta_screen->mode = SingleMode;
+ current = first_sel_taline(current);
+ (void) ta_do_take(current, 1, -FOOTER_ROWS(ps_global), tasp, _("save"));
+ ps->mangled_screen = 1;
+}
+
+
+/*
+ *
+ */
+int
+ta_do_take(TA_S *current, int how_many_selected, int command_line,
+ TA_STATE_S **tas, char *cmd)
+{
+ return((ta_screen->mode == ListMode)
+ ? ta_take_marked_addrs(how_many_selected,
+ first_sel_taline(current),
+ command_line, tas, cmd)
+ : ta_take_single_addr(current, command_line, tas, cmd));
+}
+
+
+/*
+ * WhereIs for TakeAddr screen.
+ *
+ * Returns the line match is found in or NULL.
+ */
+TA_S *
+whereis_taline(TA_S *current)
+{
+ TA_S *p;
+ int rc, found = 0, wrapped = 0, flags;
+ char *result = NULL, buf[MAX_SEARCH+1], tmp[MAX_SEARCH+20];
+ static char last[MAX_SEARCH+1];
+ HelpType help;
+ static ESCKEY_S ekey[] = {
+ {0, 0, "", ""},
+ {ctrl('Y'), 10, "^Y", N_("Top")},
+ {ctrl('V'), 11, "^V", N_("Bottom")},
+ {-1, 0, NULL, NULL}};
+
+ if(!current)
+ return NULL;
+
+ /*--- get string ---*/
+ buf[0] = '\0';
+ snprintf(tmp, sizeof(tmp), _("Word to find %s%.*s%s: "),
+ (last[0]) ? "[" : "",
+ sizeof(tmp)-20, (last[0]) ? last : "",
+ (last[0]) ? "]" : "");
+ tmp[sizeof(tmp)-1] = '\0';
+ help = NO_HELP;
+ flags = OE_APPEND_CURRENT | OE_KEEP_TRAILING_SPACE;
+ while(1){
+ rc = optionally_enter(buf,-FOOTER_ROWS(ps_global),0,sizeof(buf),
+ tmp,ekey,help,&flags);
+ if(rc == 3)
+ help = help == NO_HELP ? h_config_whereis : NO_HELP;
+ else if(rc == 0 || rc == 1 || rc == 10 || rc == 11 || !buf[0]){
+ if(rc == 0 && !buf[0] && last[0]){
+ strncpy(buf, last, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+ }
+
+ break;
+ }
+ }
+
+ if(rc == 0 && buf[0]){
+ p = current;
+ while((p = next_taline(p)) != NULL)
+ if(srchstr((char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf,
+ SIZEOF_20KBUF, p->strvalue),
+ buf)){
+ found++;
+ break;
+ }
+
+ if(!found){
+ p = first_taline(current);
+
+ while(p != current)
+ if(srchstr((char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf,
+ SIZEOF_20KBUF, p->strvalue),
+ buf)){
+ found++;
+ wrapped++;
+ break;
+ }
+ else
+ p = next_taline(p);
+ }
+ }
+ else if(rc == 10){
+ current = first_sel_taline(current);
+ result = _("Searched to top");
+ }
+ else if(rc == 11){
+ current = last_sel_taline(current);
+ result = _("Searched to bottom");
+ }
+ else{
+ current = NULL;
+ result = _("WhereIs cancelled");
+ }
+
+ if(found){
+ current = p;
+ result = wrapped ? _("Search wrapped to beginning") : _("Word found");
+ strncpy(last, buf, sizeof(last)-1);
+ last[sizeof(last)-1] = '\0';
+ }
+
+ q_status_message(SM_ORDER,0,3,result ? result : _("Word not found"));
+ return(current);
+}
+
+
+/*
+ * Call the addrbook functions which add the checked addresses.
+ *
+ * Args: how_many_selected -- how many addresses are checked
+ * f_line -- the first ta line
+ *
+ * Returns: 1 -- we're done, caller should return
+ * 0 -- we're not done
+ */
+int
+ta_take_marked_addrs(int how_many_selected, TA_S *f_line, int command_line,
+ TA_STATE_S **tas, char *cmd)
+{
+ char **new_list;
+ TA_S *p;
+
+ if(how_many_selected == 0){
+ q_status_message(SM_ORDER, 0, 4,
+ _("No addresses marked for taking. Use ExitTake to leave TakeAddr screen"));
+ return 0;
+ }
+
+ if(how_many_selected == 1){
+ for(p = f_line; p; p = next_sel_taline(p))
+ if(p->checked && !p->skip_it)
+ break;
+
+ if(p)
+ add_abook_entry(p,
+ (p->nickname && p->nickname[0]) ? p->nickname : NULL,
+ (p->fullname && p->fullname[0]) ? p->fullname : NULL,
+ (p->fcc && p->fcc[0]) ? p->fcc : NULL,
+ (p->comment && p->comment[0]) ? p->comment : NULL,
+ command_line, tas, cmd);
+ }
+ else{
+ new_list = list_of_checked(f_line);
+ for(p = f_line; p; p = next_sel_taline(p))
+ if(p->checked && !p->skip_it)
+ break;
+
+ take_to_addrbooks_frontend(new_list, p ? p->nickname : NULL,
+ p ? p->fullname : NULL, NULL, p ? p->fcc : NULL,
+ p ? p->comment : NULL, command_line, tas, cmd);
+ free_list_array(&new_list);
+ }
+
+ return 1;
+}
+
+
+int
+ta_take_single_addr(TA_S *cur, int command_line, TA_STATE_S **tas, char *cmd)
+{
+ add_abook_entry(cur,
+ (cur->nickname && cur->nickname[0]) ? cur->nickname : NULL,
+ (cur->fullname && cur->fullname[0]) ? cur->fullname : NULL,
+ (cur->fcc && cur->fcc[0]) ? cur->fcc : NULL,
+ (cur->comment && cur->comment[0]) ? cur->comment : NULL,
+ command_line, tas, cmd);
+
+ return 1;
+}
+
+
+/*
+ * Manage display of the Take Address screen.
+ *
+ * Args: ps -- pine state
+ * current -- the current TA line
+ * screen -- the TA screen
+ * cursor_pos -- return good cursor position here
+ */
+int
+update_takeaddr_screen(struct pine *ps, TA_S *current, TA_SCREEN_S *screen, Pos *cursor_pos)
+{
+ int dline;
+ TA_S *top_line,
+ *ctmp;
+ int longest, i, j;
+ char buf1[6*MAX_SCREEN_COLS + 30];
+ char buf2[6*MAX_SCREEN_COLS + 30];
+ char *p, *q;
+ int screen_width = ps->ttyo->screen_cols;
+ Pos cpos;
+
+ cpos.row = HEADER_ROWS(ps); /* default return value */
+
+ /* calculate top line of display */
+ dline = 0;
+ top_line = 0;
+
+ if (ta_screen->top_line){
+ for(dline = 0, ctmp = ta_screen->top_line;
+ ctmp && ctmp != current; ctmp = next_taline(ctmp))
+ dline++;
+
+ if (ctmp && (dline < ps->ttyo->screen_rows - HEADER_ROWS(ps)
+ - FOOTER_ROWS(ps)))
+ top_line = ta_screen->top_line;
+ }
+
+ if (!top_line){
+ dline = 0;
+ ctmp = top_line = first_taline(current);
+ do
+ if(((dline++) % (ps->ttyo->screen_rows - HEADER_ROWS(ps)
+ - FOOTER_ROWS(ps))) == 0)
+ top_line = ctmp;
+ while(ctmp != current && (ctmp = next_taline(ctmp)));
+ }
+
+#ifdef _WINDOWS
+ /*
+ * Figure out how far down the top line is from the top and how many
+ * total lines there are. Dumb to loop every time thru, but
+ * there aren't that many lines, and it's cheaper than rewriting things
+ * to maintain a line count in each structure...
+ */
+ for(dline = 0, ctmp = pre_taline(top_line); ctmp; ctmp = pre_taline(ctmp))
+ dline++;
+
+ scroll_setpos(dline);
+
+ for(ctmp = next_taline(top_line); ctmp ; ctmp = next_taline(ctmp))
+ dline++;
+
+ scroll_setrange(ps->ttyo->screen_rows - FOOTER_ROWS(ps) - HEADER_ROWS(ps),
+ dline);
+#endif
+
+
+ /* mangled body or new page, force redraw */
+ if(ps->mangled_body || screen->top_line != top_line)
+ screen->current = NULL;
+
+ /* find width of longest line for nicer formatting */
+ longest = 0;
+ for(ctmp = first_taline(top_line); ctmp; ctmp = next_taline(ctmp)){
+ int width;
+
+ if(ctmp
+ && !ctmp->print
+ && ctmp->strvalue
+ && longest < (width = utf8_width((char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf,
+ SIZEOF_20KBUF, ctmp->strvalue))))
+ longest = width;
+ }
+
+#define LENGTH_OF_THAT_STRING 5 /* "[X] " */
+ longest = MIN(longest, ps->ttyo->screen_cols);
+
+ /* loop thru painting what's needed */
+ for(dline = 0, ctmp = top_line;
+ dline < ps->ttyo->screen_rows - FOOTER_ROWS(ps) - HEADER_ROWS(ps);
+ dline++, ctmp = next_taline(ctmp)){
+
+ /*
+ * only fall thru painting if something needs painting...
+ */
+ if(!ctmp || !screen->current || ctmp == screen->current ||
+ ctmp == top_line || ctmp == current){
+ ClearLine(dline + HEADER_ROWS(ps));
+ if(!ctmp || !ctmp->strvalue)
+ continue;
+ }
+
+ p = buf1;
+ if(ctmp == current){
+ cpos.row = dline + HEADER_ROWS(ps); /* col set below */
+ StartInverse();
+ }
+
+ if(ctmp->print)
+ j = 0;
+ else
+ j = LENGTH_OF_THAT_STRING;
+
+ /*
+ * Copy the value to a temp buffer expanding tabs, and
+ * making sure not to write beyond screen right...
+ */
+ q = (char *) rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf,
+ SIZEOF_20KBUF, ctmp->strvalue);
+
+ for(i = 0; q[i] && j < ps->ttyo->screen_cols && p-buf1 < sizeof(buf1); i++){
+ if(q[i] == ctrl('I')){
+ do
+ *p++ = SPACE;
+ while(j < ps->ttyo->screen_cols && ((++j)&0x07) && p-buf1 < sizeof(buf1));
+
+ }
+ else{
+ *p++ = q[i];
+ j++;
+ }
+ }
+
+ if(p-buf1 < sizeof(buf1))
+ *p = '\0';
+
+ if(utf8_width(buf1) < longest){
+ (void) utf8_pad_to_width(buf2, buf1, sizeof(buf2), longest, 1);
+ /* it's expected to be in buf1 below */
+ strncpy(buf1, buf2, sizeof(buf1));
+ buf1[sizeof(buf1)-1] = '\0';
+ }
+
+ /* mark lines which have check marks */
+ if(ctmp == current){
+ if(screen->mode == ListMode){
+ snprintf(buf2, sizeof(buf2), "[%c] %s", ctmp->checked ? 'X' : SPACE, buf1);
+ buf2[sizeof(buf2)-1] = '\0';
+ cpos.col = 1; /* position on the X */
+ }
+ else{
+ snprintf(buf2, sizeof(buf2), " %s", buf1);
+ buf2[sizeof(buf2)-1] = '\0';
+ cpos.col = 5; /* 5 spaces before text */
+ }
+ }
+ else{
+ if(ctmp->print){
+ int width, actual_width;
+ size_t len;
+
+ /*
+ * In buf2 make ------string--------
+ * which reaches all the way across the screen. String will
+ * already have a leading and trailing space.
+ */
+ width = utf8_width(buf1);
+
+ if(width > screen_width){
+ actual_width = utf8_truncate(buf1, screen_width);
+ /* it might be 1 less */
+ if(actual_width < screen_width && (len=strlen(buf1))+1 < sizeof(buf1)){
+ buf1[len] = SPACE;
+ buf1[len+1] = '\0';
+ }
+ }
+ else{
+ snprintf(buf2, sizeof(buf2), "%s%s",
+ repeat_char((screen_width-width)/2, '-'), buf1);
+ buf2[sizeof(buf2)-1] = '\0';
+ len = strlen(buf2);
+ width = utf8_width(buf2);
+ snprintf(buf2+len, sizeof(buf2)-len, "%s",
+ repeat_char(screen_width-width, '-'));
+ buf2[sizeof(buf2)-1] = '\0';
+ }
+ }
+ else{
+ if(screen->mode == ListMode)
+ snprintf(buf2, sizeof(buf2), "[%c] %.*s", ctmp->checked ? 'X' : SPACE,
+ sizeof(buf2)-6, buf1);
+ else
+ snprintf(buf2, sizeof(buf2), " %.*s", sizeof(buf2)-6, buf1);
+
+ buf2[sizeof(buf2)-1] = '\0';
+ }
+ }
+
+ PutLine0(dline + HEADER_ROWS(ps), 0, buf2);
+
+ if(ctmp == current)
+ EndInverse();
+ }
+
+ ps->mangled_body = 0;
+ screen->top_line = top_line;
+ screen->current = current;
+ if(cursor_pos)
+ *cursor_pos = cpos;
+
+ return(cpos.row);
+}
+
+
+void
+takeaddr_screen_redrawer_list(void)
+{
+ ps_global->mangled_body = 1;
+ (void)update_takeaddr_screen(ps_global, ta_screen->current, ta_screen,
+ (Pos *)NULL);
+}
+
+
+void
+takeaddr_screen_redrawer_single(void)
+{
+ ps_global->mangled_body = 1;
+ (void)update_takeaddr_screen(ps_global, ta_screen->current, ta_screen,
+ (Pos *)NULL);
+}
+
+
+/* jpf work in progress
+ * Execute command to take addresses out of message and put in the address book
+ *
+ * Args: ps -- pine state
+ * msgmap -- the MessageMap
+ * agg -- this is aggregate operation if set
+ *
+ * Result: The entry is added to an address book.
+ */
+int
+cmd_take_addr(struct pine *ps, MSGNO_S *msgmap, int agg)
+{
+ TA_S *ta_list = NULL;
+ int how_many_selected = 0, rtype;
+
+ /* Ask user what kind of Take they want to do */
+ if(!agg && F_ON(F_ENABLE_ROLE_TAKE, ps)){
+ rtype = rule_setup_type(ps,
+ RS_RULES |
+ ((mn_get_total(msgmap) > 0)
+ ? (F_ON(F_ENABLE_TAKE_EXPORT, ps)
+ ? (RS_INCADDR | RS_INCEXP)
+ : RS_INCADDR)
+ : RS_NONE),
+ "Take to : ");
+ }
+ else if(F_ON(F_ENABLE_TAKE_EXPORT, ps) && mn_get_total(msgmap) > 0)
+ rtype = rule_setup_type(ps, RS_INCADDR | RS_INCEXP, "Take to : ");
+ else
+ rtype = 'a';
+
+ if(rtype == 'x' || rtype == 'Z'){
+ if(rtype == 'x')
+ cmd_cancelled(NULL);
+ else if(rtype == 'Z')
+ q_status_message(SM_ORDER | SM_DING, 3, 5,
+ "Try turning on color with the Setup/Kolor command.");
+ return -1;
+ }
+
+ ps->mangled_footer = 1;
+
+ if(rtype > 0)
+ switch(rtype){
+ case 'e':
+ {
+ LINES_TO_TAKE *lines_to_take = NULL;
+
+ rtype = set_up_takeaddr('e', ps, msgmap, &ta_list, &how_many_selected,
+ agg ? TA_AGG : 0, NULL);
+
+ if(rtype >= 0){
+ if(convert_ta_to_lines(ta_list, &lines_to_take)){
+ while(lines_to_take && lines_to_take->prev)
+ lines_to_take = lines_to_take->prev;
+
+ take_to_export(ps, lines_to_take);
+
+ free_ltlines(&lines_to_take);
+ }
+ else
+ q_status_message(SM_ORDER, 3, 4, _("Can't find anything to export"));
+ }
+ }
+
+ break;
+
+ case 'r':
+ case 's':
+ case 'i':
+ case 'f':
+ case 'o':
+ case 'c':
+ case 'x':
+ role_take(ps, msgmap, rtype);
+ break;
+
+ case 'a':
+ rtype = set_up_takeaddr('a', ps, msgmap, &ta_list, &how_many_selected,
+ agg ? TA_AGG : 0, attached_addr_handler);
+ if(rtype >= 0){
+ (void) takeaddr_screen(ps, ta_list, how_many_selected,
+ agg ? ListMode : SingleMode,
+ NULL, _("take"));
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ /* clean up */
+ free_talines(&ta_list);
+ env_for_pico_callback = NULL;
+ body_for_pico_callback = NULL;
+
+ return(rtype >= 0 ? 1 : 0);
+}
+
+
+int
+attached_addr_handler(TA_S *current, int added)
+{
+ char prompt[200];
+ int command_line = -FOOTER_ROWS(ps_global);
+
+ snprintf(prompt, sizeof(prompt),
+ "Take %d entries from attachment to addrbook all at once ",
+ added);
+ switch(want_to(prompt, 'n', 'x', NO_HELP, WT_NORM)){
+ case 'y':
+ if(take_without_edit(current, added, command_line, NULL, "take") >= 0)
+ return(0); /* all taken care of */
+ else
+ return(-1); /* problem */
+
+ case 'x':
+ cmd_cancelled("Take");
+ return(-1); /* problem */
+
+ default:
+ return(1); /* proceed */
+ }
+}
+
+
+int
+take_without_edit(TA_S *ta_list, int num_in_list, int command_line, TA_STATE_S **tas, char *cmd)
+{
+ PerAddrBook *pab_dst;
+ SAVE_STATE_S state; /* For saving state of addrbooks temporarily */
+ int rc, total_to_copy;
+ int how_many_dups = 0, how_many_to_copy = 0, skip_dups = 0;
+ int ret = 0;
+ int err = 0, need_write = 0, we_cancel = 0;
+ adrbk_cntr_t new_entry_num;
+ char warn[2][MAX_NICKNAME+1];
+ char tmp[200];
+ TA_S *current;
+ SWOOP_S *swoop_list = NULL, *sw;
+
+ dprint((2, "\n - take_without_edit(%d) - \n",
+ num_in_list));
+
+ /* move to beginning of the list */
+ if(ta_list)
+ while(ta_list->prev)
+ ta_list = ta_list->prev;
+
+ pab_dst = setup_for_addrbook_add(&state, command_line, cmd);
+ if(!pab_dst)
+ goto get_out;
+
+ swoop_list = (SWOOP_S *)fs_get((num_in_list+1) * sizeof(SWOOP_S));
+ memset((void *)swoop_list, 0, (num_in_list+1) * sizeof(SWOOP_S));
+ sw = swoop_list;
+
+ /*
+ * Look through all the vcards for those with nicknames already
+ * existing in the destination abook (dups) and build a list of
+ * entries to be acted on.
+ */
+ for(current = ta_list; current; current = current->next){
+ adrbk_cntr_t dst_enum;
+
+ if(current->skip_it)
+ continue;
+
+ /* check to see if this nickname already exists in the dest abook */
+ if(current->nickname && current->nickname[0]){
+ AdrBk_Entry *abe;
+
+ current->checked = 0;
+ abe = adrbk_lookup_by_nick(pab_dst->address_book,
+ current->nickname, &dst_enum);
+ /*
+ * This nickname already exists.
+ */
+ if(abe){
+ sw->dup = 1;
+ sw->dst_enum = dst_enum;
+ if(how_many_dups < 2){
+ strncpy(warn[how_many_dups], current->nickname, MAX_NICKNAME);
+ warn[how_many_dups][MAX_NICKNAME] = '\0';
+ }
+
+ how_many_dups++;
+ }
+ }
+
+ sw->ta = current;
+ sw++;
+ how_many_to_copy++;
+ }
+
+ /*
+ * If there are some nicknames which already exist in the selected
+ * abook, ask user what to do.
+ */
+ if(how_many_dups > 0){
+ if(how_many_dups == 1){
+ if(how_many_to_copy == 1 && num_in_list == 1){
+ ret = 'T'; /* use Take */
+ if(tas && *tas){
+ (*tas)->state = state;
+ (*tas)->pab = pab_dst;
+ }
+
+ goto get_out;
+ }
+ else{
+ snprintf(tmp, sizeof(tmp),
+ "Entry with nickname \"%.*s\" already exists, replace ",
+ sizeof(tmp)-50, warn[0]);
+ }
+ }
+ else if(how_many_dups == 2)
+ snprintf(tmp, sizeof(tmp),
+ "Nicknames \"%.*s\" and \"%.*s\" already exist, replace ",
+ (sizeof(tmp)-50)/2, warn[0], (sizeof(tmp)-50)/2, warn[1]);
+ else
+ snprintf(tmp, sizeof(tmp), "%d of the nicknames already exist, replace ",
+ how_many_dups);
+
+ switch(want_to(tmp, 'n', 'x', h_ab_copy_dups, WT_NORM)){
+ case 'n':
+ skip_dups++;
+ break;
+
+ case 'y':
+ break;
+
+ case 'x':
+ err++;
+ goto get_out;
+ }
+ }
+
+ /*
+ * Because the deletes happen immediately we have to delete from high
+ * entry number towards lower entry numbers so that we are deleting
+ * the correct entries. In order to do that we'll sort the swoop_list
+ * to give us a safe order.
+ */
+ if(!skip_dups && how_many_dups > 1)
+ qsort((qsort_t *)swoop_list, (size_t)num_in_list, sizeof(*swoop_list),
+ cmp_swoop_list);
+
+ we_cancel = busy_cue("Saving addrbook entries", NULL, 0);
+ total_to_copy = how_many_to_copy - (skip_dups ? how_many_dups : 0);
+
+ /*
+ * Add the list of entries to the destination abook.
+ */
+ for(sw = swoop_list; sw && sw->ta; sw++){
+ Tag tag;
+ char abuf[MAX_ADDRESS + 1];
+ int count_of_addrs;
+
+ if(skip_dups && sw->dup)
+ continue;
+
+ /*
+ * Delete existing dups and replace them.
+ */
+ if(sw->dup){
+
+ /* delete the existing entry */
+ rc = 0;
+ if(adrbk_delete(pab_dst->address_book,
+ (a_c_arg_t)sw->dst_enum, 1, 0, 0, 0) == 0){
+ need_write++;
+ }
+ else{
+ q_status_message2(SM_ORDER | SM_DING, 3, 5,
+ "Error replacing entry in %.200s: %.200s",
+ pab_dst->abnick,
+ error_description(errno));
+ err++;
+ goto get_out;
+ }
+ }
+
+ /*
+ * We need to count the number of addresses in this entry in order
+ * to tell the adrbk routines if it is a List or a Single, and in
+ * order to pass the right stuff to be added.
+ */
+ count_of_addrs = count_addrs(sw->ta->addr);
+ tag = (count_of_addrs > 1) ? List : Single;
+ if(tag == Single){
+ if(sw->ta->addr->mailbox && sw->ta->addr->mailbox[0]){
+ char *scratch, *p, *t, *u;
+ unsigned long l;
+ RFC822BUFFER rbuf;
+ size_t es;
+
+ es = est_size(sw->ta->addr);
+ scratch = (char *) fs_get(es * sizeof(char));
+ scratch[0] = '\0';
+ rbuf.f = dummy_soutr;
+ rbuf.s = NULL;
+ rbuf.beg = scratch;
+ rbuf.cur = scratch;
+ rbuf.end = scratch+es-1;
+ rfc822_output_address_list(&rbuf, sw->ta->addr, 0L, NULL);
+ *rbuf.cur = '\0';
+ if((p = srchstr(scratch, "@" RAWFIELD)) != NULL){
+ for(t = p; ; t--)
+ if(*t == '&'){ /* find "leading" token */
+ *t++ = ' '; /* replace token */
+ *p = '\0'; /* tie off string */
+ u = (char *)rfc822_base64((unsigned char *)t,
+ (unsigned long)strlen(t), &l);
+ *p = '@'; /* restore 'p' */
+ rplstr(p, es-(p-scratch), 12, ""); /* clear special token */
+ rplstr(t, es-(t-scratch), strlen(t), u); /* Null u is handled */
+ if(u)
+ fs_give((void **)&u);
+ }
+ else if(t == scratch)
+ break;
+ }
+
+ strncpy(abuf, scratch, sizeof(abuf)-1);
+ abuf[sizeof(abuf)-1] = '\0';
+
+ if(scratch)
+ fs_give((void **)&scratch);
+ }
+ else
+ abuf[0] = '\0';
+ }
+
+
+ /*
+ * Now we have a clean slate to work with.
+ */
+ if(total_to_copy <= 1)
+ rc = adrbk_add(pab_dst->address_book,
+ NO_NEXT,
+ sw->ta->nickname,
+ sw->ta->fullname,
+ tag == Single ? abuf : NULL,
+ sw->ta->fcc,
+ sw->ta->comment,
+ tag,
+ &new_entry_num,
+ (int *)NULL,
+ 0,
+ 0,
+ 0);
+ else
+ rc = adrbk_append(pab_dst->address_book,
+ sw->ta->nickname,
+ sw->ta->fullname,
+ tag == Single ? abuf : NULL,
+ sw->ta->fcc,
+ sw->ta->comment,
+ tag,
+ &new_entry_num);
+
+ if(rc == 0)
+ need_write++;
+
+ /*
+ * If the entry we copied is a list, we also have to add
+ * the list members to the copy.
+ */
+ if(rc == 0 && tag == List){
+ int i, save_sort_rule;
+ ADDRESS *a, *save_next;
+ char **list;
+
+ list = (char **)fs_get((count_of_addrs + 1) * sizeof(char *));
+ memset((void *)list, 0, (count_of_addrs+1) * sizeof(char *));
+ i = 0;
+ for(a = sw->ta->addr; a; a = a->next){
+ save_next = a->next;
+ a->next = NULL;
+
+ if(a->mailbox && a->mailbox[0]){
+ char *scratch, *p, *t, *u;
+ unsigned long l;
+ RFC822BUFFER rbuf;
+ size_t es;
+
+ es = est_size(a);
+ scratch = (char *) fs_get(es * sizeof(char));
+ scratch[0] = '\0';
+ rbuf.f = dummy_soutr;
+ rbuf.s = NULL;
+ rbuf.beg = scratch;
+ rbuf.cur = scratch;
+ rbuf.end = scratch+es-1;
+ rfc822_output_address_list(&rbuf, a, 0L, NULL);
+ *rbuf.cur = '\0';
+ if((p = srchstr(scratch, "@" RAWFIELD)) != NULL){
+ for(t = p; ; t--)
+ if(*t == '&'){ /* find "leading" token */
+ *t++ = ' '; /* replace token */
+ *p = '\0'; /* tie off string */
+ u = (char *)rfc822_base64((unsigned char *)t,
+ (unsigned long)strlen(t), &l);
+ *p = '@'; /* restore 'p' */
+ rplstr(p, es-(p-scratch), 12, ""); /* clear special token */
+ rplstr(t, es-(t-scratch), strlen(t), u); /* Null u is handled */
+ if(u)
+ fs_give((void **)&u);
+ }
+ else if(t == scratch)
+ break;
+ }
+
+ strncpy(abuf, scratch, sizeof(abuf)-1);
+ abuf[sizeof(abuf)-1] = '\0';
+
+ if(scratch)
+ fs_give((void **)&scratch);
+ }
+ else
+ abuf[0] = '\0';
+
+ list[i++] = cpystr(abuf);
+ a->next = save_next;
+ }
+
+ /*
+ * We want it to copy the list in the exact order
+ * without sorting it.
+ */
+ save_sort_rule = pab_dst->address_book->sort_rule;
+ pab_dst->address_book->sort_rule = AB_SORT_RULE_NONE;
+
+ rc = adrbk_nlistadd(pab_dst->address_book,
+ (a_c_arg_t)new_entry_num, NULL, NULL,
+ list, 0, 0, 0);
+
+ pab_dst->address_book->sort_rule = save_sort_rule;
+ free_list_array(&list);
+ }
+
+ if(rc != 0){
+ q_status_message1(SM_ORDER | SM_DING, 3, 5,
+ "Error saving: %.200s",
+ error_description(errno));
+ err++;
+ goto get_out;
+ }
+ }
+
+ if(need_write){
+ int sort_happened = 0;
+
+ if(adrbk_write(pab_dst->address_book, 0, NULL, &sort_happened, 0, 1)){
+ err++;
+ goto get_out;
+ }
+
+ if(sort_happened)
+ ps_global->mangled_screen = 1;
+ }
+
+get_out:
+ if(we_cancel)
+ cancel_busy_cue(1);
+
+ if(!ret)
+ restore_state(&state);
+
+ if(swoop_list)
+ fs_give((void **)&swoop_list);
+
+ ps_global->mangled_footer = 1;
+
+ if(err){
+ char capcmd[50];
+
+ ret = -1;
+ snprintf(capcmd, sizeof(capcmd),
+ "%c%.*s",
+ islower((unsigned char)(*cmd)) ? toupper((unsigned char)*cmd)
+ : *cmd,
+ sizeof(capcmd)-2, cmd+1);
+ if(need_write)
+ q_status_message1(SM_ORDER | SM_DING, 3, 4,
+ "%.200s only partially completed", capcmd);
+ else
+ cmd_cancelled(capcmd);
+ }
+ else if(ret != 'T' && total_to_copy > 0){
+
+ ret = 1;
+ snprintf(tmp, sizeof(tmp), "Saved %d %s to \"%.*s\"",
+ total_to_copy,
+ (total_to_copy > 1) ? "entries" : "entry",
+ sizeof(tmp)-30, pab_dst->abnick);
+ q_status_message(SM_ORDER, 4, 4, tmp);
+ }
+
+ return(ret);
+}
+
+
+/*
+ * Special case interface to allow a more interactive Save in the case where
+ * the user seems to be wanting to save an exact copy of an existing entry.
+ * For example, they might be trying to save a copy of a list with the intention
+ * of changing it a little bit. The regular save doesn't allow this, since no
+ * editing takes place, but this version plops them into the address book
+ * editor.
+ */
+void
+take_this_one_entry(struct pine *ps, TA_STATE_S **tasp, AdrBk *abook, long int cur_line)
+{
+ AdrBk_Entry *abe;
+ AddrScrn_Disp *dl;
+ char *fcc = NULL, *comment = NULL, *fullname = NULL,
+ *nickname = NULL;
+ ADDRESS *addr;
+ int how_many_selected;
+ TA_S *current = NULL;
+
+ dl = dlist(cur_line);
+ abe = ae(cur_line);
+ if(!abe){
+ q_status_message(SM_ORDER, 0, 4, _("Nothing to save, cancelled"));
+ return;
+ }
+
+ if(dl->type == ListHead || dl->type == Simple){
+ fcc = (abe->fcc && abe->fcc[0]) ? abe->fcc : NULL;
+ comment = (abe->extra && abe->extra[0]) ? abe->extra : NULL;
+ fullname = (abe->fullname && abe->fullname[0]) ? abe->fullname : NULL;
+ nickname = (abe->nickname && abe->nickname[0]) ? abe->nickname : NULL;
+ }
+
+ addr = abe_to_address(abe, dl, abook, &how_many_selected);
+ if(!addr){
+ addr = mail_newaddr();
+ addr->host = cpystr("");
+ addr->mailbox = cpystr("");
+ }
+
+ switch(abe->tag){
+ case Single:
+#ifdef ENABLE_LDAP
+ /*
+ * Special case. When user is saving an entry with a runtime
+ * ldap lookup address, they may be doing it because the lookup
+ * has become stale. Give them a way to get the old address out
+ * of the lookup entry so they can save that, instead.
+ */
+ if(!addr->personal && !strncmp(addr->mailbox, RUN_LDAP, LEN_RL)){
+ LDAP_SERV_S *info = NULL;
+ int i = 'l';
+ static ESCKEY_S backup_or_ldap[] = {
+ {'b', 'b', "B", N_("Backup")},
+ {'l', 'l', "L", N_("LDAP")},
+ {-1, 0, NULL, NULL}};
+
+ info = break_up_ldap_server(addr->mailbox + LEN_RL);
+ if(info && info->mail && *info->mail)
+ i = radio_buttons(_("Copy backup address or retain LDAP search criteria ? "),
+ -FOOTER_ROWS(ps_global), backup_or_ldap,
+ 'b', 'x',
+ h_ab_backup_or_ldap, RB_NORM);
+
+ if(i == 'b'){
+ ADDRESS *a = NULL;
+
+ rfc822_parse_adrlist(&a, info->mail, fakedomain);
+
+ if(a){
+ if(addr->mailbox)
+ fs_give((void **)&addr->mailbox);
+ if(addr->host)
+ fs_give((void **)&addr->host);
+
+ addr->mailbox = a->mailbox;
+ a->mailbox = NULL;
+ addr->host = a->host;
+ a->host = NULL;
+ mail_free_address(&a);
+ }
+ }
+
+ if(info)
+ free_ldap_server_info(&info);
+ }
+#endif /* ENABLE_LDAP */
+ current = fill_in_ta(&current, addr, 0, (char *)NULL);
+ break;
+
+ case List:
+ /*
+ * The empty string for the last argument is significant. Fill_in_ta
+ * copies the whole adrlist into a single TA if there is a print
+ * string.
+ */
+ if(dl->type == ListHead)
+ current = fill_in_ta(&current, addr, 1, "");
+ else
+ current = fill_in_ta(&current, addr, 0, (char *)NULL);
+
+ break;
+
+ default:
+ dprint((1,
+ "default case in take_this_one_entry, shouldn't happen\n"));
+ return;
+ }
+
+ if(current->strvalue && !strcmp(current->strvalue, "@")){
+ fs_give((void **)&current->strvalue);
+ if(fullname && fullname[0])
+ current->strvalue = cpystr(fullname);
+ else if(nickname && nickname[0])
+ current->strvalue = cpystr(nickname);
+ else
+ current->strvalue = cpystr("?");
+
+ convert_possibly_encoded_str_to_utf8(&current->strvalue);
+ }
+
+ if(addr)
+ mail_free_address(&addr);
+
+ if(current){
+ current = first_sel_taline(current);
+ if(fullname && *fullname){
+ current->fullname = cpystr(fullname);
+ convert_possibly_encoded_str_to_utf8(&current->fullname);
+ }
+
+ if(fcc && *fcc){
+ current->fcc = cpystr(fcc);
+ convert_possibly_encoded_str_to_utf8(&current->fcc);
+ }
+
+ if(comment && *comment){
+ current->comment = cpystr(comment);
+ convert_possibly_encoded_str_to_utf8(&current->comment);
+ }
+
+ if(nickname && *nickname){
+ current->nickname = cpystr(nickname);
+ convert_possibly_encoded_str_to_utf8(&current->nickname);
+ }
+
+ takeaddr_bypass(ps, current, tasp);
+ }
+ else
+ q_status_message(SM_ORDER, 0, 4, _("Nothing to save, cancelled"));
+
+ free_talines(&current);
+}
+
+
+/*
+ * Execute command to save addresses out of vcard attachment.
+ */
+void
+save_vcard_att(struct pine *ps, int qline, long int msgno, ATTACH_S *a)
+{
+ int how_many_selected, j;
+ TA_S *current = NULL;
+ TA_STATE_S tas, *tasp;
+
+
+ dprint((2, "\n - saving vcard attachment - \n"));
+
+ j = radio_buttons(_("Save to address book or Export to filesystem ? "),
+ qline, save_or_export, 's', 'x',
+ h_ab_save_exp, RB_NORM|RB_SEQ_SENSITIVE);
+
+ switch(j){
+ case 'x':
+ q_status_message(SM_INFO, 0, 2, _("Address book save cancelled"));
+ return;
+
+ case 'e':
+ export_vcard_att(ps, qline, msgno, a);
+ return;
+
+ case 's':
+ break;
+
+ default:
+ q_status_message(SM_ORDER, 3, 3, "can't happen in save_vcard_att");
+ return;
+ }
+
+ dprint((2, "\n - saving attachment into address book - \n"));
+ ps->mangled_footer = 1;
+ current = NULL;
+ how_many_selected = process_vcard_atts(ps->mail_stream, msgno, NULL,
+ a->body, a->number, &current);
+ if(how_many_selected > 0){
+ tas.pab = NULL;
+ tasp = &tas;
+ if(how_many_selected == 1){
+ takeaddr_bypass(ps, current, NULL);
+ }
+ else if(take_without_edit(current, how_many_selected, qline,
+ &tasp, "save") == 'T'){
+ /*
+ * Eliminate dups.
+ */
+ how_many_selected -=
+ eliminate_dups_but_not_us(first_sel_taline(current));
+
+ (void)takeaddr_screen(ps, current, how_many_selected, SingleMode,
+ &tasp, _("save"));
+
+ /*
+ * If takeaddr_screen or its children didn't do this for us,
+ * we do it here.
+ */
+ if(tas.pab)
+ restore_state(&(tas.state));
+ }
+ }
+ else if(how_many_selected == 0)
+ q_status_message(SM_ORDER, 0, 3,
+ _("Save cancelled: no entries in attachment"));
+
+ free_talines(&current);
+}
+
+
+/*
+ * Execute command to export vcard attachment.
+ */
+void
+export_vcard_att(struct pine *ps, int qline, long int msgno, ATTACH_S *a)
+{
+ int how_many_selected, i;
+ TA_S *current;
+ STORE_S *srcstore = NULL;
+ SourceType srctype;
+ static ESCKEY_S vcard_or_addresses[] = {
+ {'a', 'a', "A", N_("Address List")},
+ {'v', 'v', "V", N_("VCard")},
+ {-1, 0, NULL, NULL}};
+
+ if(ps->restricted){
+ q_status_message(SM_ORDER, 0, 3,
+ "Alpine demo can't export addresses to files");
+ return;
+ }
+
+ dprint((2, "\n - exporting vcard attachment - \n"));
+
+ i = radio_buttons(_("Export list of addresses or vCard text ? "),
+ qline, vcard_or_addresses, 'a', 'x',
+ h_ab_export_vcard, RB_NORM|RB_SEQ_SENSITIVE);
+
+ switch(i){
+ case 'x':
+ q_status_message(SM_INFO, 0, 2, _("Address book export cancelled"));
+ return;
+
+ case 'a':
+ break;
+
+ case 'v':
+ write_attachment(qline, msgno, a, "EXPORT");
+ return;
+
+ default:
+ q_status_message(SM_ORDER, 3, 3, _("can't happen in export_vcard_att"));
+ return;
+ }
+
+ ps->mangled_footer = 1;
+ current = NULL;
+ how_many_selected = process_vcard_atts(ps->mail_stream, msgno, NULL,
+ a->body, a->number, &current);
+ /*
+ * Run through all of the list and run through
+ * the addresses in each ta->addr, writing them into a storage object.
+ * Then export to filesystem.
+ */
+ srctype = CharStar;
+ if(how_many_selected > 0 &&
+ (srcstore = so_get(srctype, NULL, EDIT_ACCESS)) != NULL){
+ ADDRESS *aa, *bb;
+ int are_some = 0;
+
+ for(current = first_taline(current);
+ current;
+ current = next_taline(current)){
+
+ for(aa = current->addr; aa; aa = aa->next){
+ bb = aa->next;
+ aa->next = NULL;
+ so_puts(srcstore, addr_list_string(aa, NULL, 0));
+ are_some++;
+ so_puts(srcstore, "\n");
+ aa->next = bb;
+ }
+ }
+
+ if(are_some)
+ simple_export(ps, so_text(srcstore), srctype, "addresses", NULL);
+ else
+ q_status_message(SM_ORDER, 0, 3, _("No addresses to export"));
+
+ so_give(&srcstore);
+ }
+ else{
+ if(how_many_selected == 0)
+ q_status_message(SM_ORDER, 0, 3, _("Nothing to export"));
+ else
+ q_status_message(SM_ORDER,0,2, _("Error allocating space"));
+ }
+}
+
+
+void
+take_to_export(struct pine *ps, LINES_TO_TAKE *lines_to_take)
+{
+ CONF_S *ctmp = NULL, *first_line = NULL;
+ OPT_SCREEN_S screen;
+ LINES_TO_TAKE *li;
+ char *help_title = _("HELP FOR TAKE EXPORT SCREEN");
+ char *p;
+ ScreenMode listmode = SingleMode;
+
+ for(li = lines_to_take; li; li = li->next){
+
+ new_confline(&ctmp);
+ ctmp->flags |= CF_STARTITEM;
+ if(li->flags & LT_NOSELECT)
+ ctmp->flags |= CF_NOSELECT;
+ else if(!first_line)
+ first_line = ctmp;
+
+ p = li->printval ? li->printval : "";
+
+ if(ctmp->flags & CF_NOSELECT)
+ ctmp->value = cpystr(p);
+ else{
+ size_t l;
+
+ /* 5 is for "[X] " */
+ l = strlen(p)+5;
+ ctmp->value = (char *)fs_get((l+1) * sizeof(char));
+ snprintf(ctmp->value, l+1, " %s", p);
+ ctmp->value[l] = '\0';
+ }
+
+ /* this points to data, it doesn't have its own copy */
+ ctmp->d.t.exportval = li->exportval ? li->exportval : NULL;
+ ctmp->d.t.selected = 0;
+ ctmp->d.t.listmode = &listmode;
+
+ ctmp->tool = take_export_tool;
+ ctmp->help_title = help_title;
+ ctmp->help = h_takeexport_screen;
+ ctmp->keymenu = &take_export_keymenu_sm;
+ }
+
+ if(!first_line)
+ q_status_message(SM_ORDER, 3, 3, _("No lines to export"));
+ else{
+ memset(&screen, 0, sizeof(screen));
+ conf_scroll_screen(ps, &screen, first_line, _("Take Export"), NULL, 0);
+ }
+}
+
+
+int
+take_export_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
+{
+ CONF_S *ctmp;
+ int retval = 0;
+ int some_selected = 0, something_to_export = 0;
+ SourceType srctype;
+ STORE_S *srcstore = NULL;
+ char *prompt_msg;
+
+ switch(cmd){
+ case MC_TAKE :
+ srctype = CharStar;
+ if((srcstore = so_get(srctype, NULL, EDIT_ACCESS)) != NULL){
+ if(*(*cl)->d.t.listmode == SingleMode){
+ some_selected++;
+ if((*cl)->d.t.exportval && (*cl)->d.t.exportval[0]){
+ so_puts(srcstore, (*cl)->d.t.exportval);
+ so_puts(srcstore, "\n");
+ something_to_export++;
+ prompt_msg = "selection";
+ }
+ }
+ else{
+ /* go to first line */
+ for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
+ ;
+
+ for(; ctmp; ctmp = next_confline(ctmp))
+ if(!(ctmp->flags & CF_NOSELECT) && ctmp->d.t.selected){
+ some_selected++;
+ if(ctmp->d.t.exportval && ctmp->d.t.exportval[0]){
+ so_puts(srcstore, ctmp->d.t.exportval);
+ so_puts(srcstore, "\n");
+ something_to_export++;
+ prompt_msg = "selections";
+ }
+ }
+ }
+ }
+
+ if(!srcstore)
+ q_status_message(SM_ORDER, 0, 3, _("Error allocating space"));
+ else if(something_to_export)
+ simple_export(ps, so_text(srcstore), srctype, prompt_msg, NULL);
+ else if(!some_selected && *(*cl)->d.t.listmode == ListMode)
+ q_status_message(SM_ORDER, 0, 3, _("Use \"X\" to mark selections"));
+ else
+ q_status_message(SM_ORDER, 0, 3, _("Nothing to export"));
+
+ if(srcstore)
+ so_give(&srcstore);
+
+ break;
+
+ case MC_LISTMODE :
+ if(*(*cl)->d.t.listmode == SingleMode){
+ /*
+ * UnHide the checkboxes
+ */
+
+ *(*cl)->d.t.listmode = ListMode;
+
+ /* go to first line */
+ for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
+ ;
+
+ for(; ctmp; ctmp = next_confline(ctmp))
+ if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
+ ctmp->value[0] = '[';
+ ctmp->value[1] = ctmp->d.t.selected ? 'X' : SPACE;
+ ctmp->value[2] = ']';
+ ctmp->keymenu = &take_export_keymenu_lm;
+ }
+ }
+ else{
+ /*
+ * Hide the checkboxes
+ */
+
+ *(*cl)->d.t.listmode = SingleMode;
+
+ /* go to first line */
+ for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
+ ;
+
+ for(; ctmp; ctmp = next_confline(ctmp))
+ if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
+ ctmp->value[0] = ctmp->value[1] = ctmp->value[2] = SPACE;
+ ctmp->keymenu = &take_export_keymenu_sm;
+ }
+ }
+
+ ps->mangled_body = ps->mangled_footer = 1;
+ break;
+
+ case MC_CHOICE :
+ if((*cl)->value[1] == 'X'){
+ (*cl)->d.t.selected = 0;
+ (*cl)->value[1] = SPACE;
+ }
+ else{
+ (*cl)->d.t.selected = 1;
+ (*cl)->value[1] = 'X';
+ }
+
+ ps->mangled_body = 1;
+ break;
+
+ case MC_SELALL :
+ /* go to first line */
+ for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
+ ;
+
+ for(; ctmp; ctmp = next_confline(ctmp)){
+ if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
+ ctmp->d.t.selected = 1;
+ if(ctmp->value)
+ ctmp->value[1] = 'X';
+ }
+ }
+
+ ps->mangled_body = 1;
+ break;
+
+ case MC_UNSELALL :
+ /* go to first line */
+ for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
+ ;
+
+ for(; ctmp; ctmp = next_confline(ctmp)){
+ if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
+ ctmp->d.t.selected = 0;
+ if(ctmp->value)
+ ctmp->value[1] = SPACE;
+ }
+ }
+
+ ps->mangled_body = 1;
+ break;
+
+ case MC_EXIT :
+ retval = simple_exit_cmd(flags);
+ break;
+
+ default:
+ retval = -1;
+ break;
+ }
+
+ return(retval);
+}
+
+#ifdef ENABLE_LDAP
+/*
+ * Save an LDAP directory entry somewhere
+ *
+ * Args: ps -- pine struct
+ * e -- the entry to save
+ * save -- If this is set, then bypass the question about whether
+ * to save or export and just do the save.
+ */
+void
+save_ldap_entry(struct pine *ps, LDAP_CHOOSE_S *e, int save)
+{
+ char *fullname = NULL,
+ *address = NULL,
+ *first = NULL,
+ *last = NULL,
+ *comment = NULL;
+ char **cn = NULL,
+ **mail = NULL,
+ **sn = NULL,
+ **givenname = NULL,
+ **title = NULL,
+ **telephone = NULL,
+ **elecmail = NULL,
+ **note = NULL,
+ **ll;
+ int j,
+ export = 0;
+
+
+ dprint((2, "\n - save_ldap_entry - \n"));
+
+ if(e){
+ char *a;
+ BerElement *ber;
+
+ for(a = ldap_first_attribute(e->ld, e->selected_entry, &ber);
+ a != NULL;
+ a = ldap_next_attribute(e->ld, e->selected_entry, ber)){
+
+ dprint((9, " %s", a ? a : "?"));
+ if(strcmp(a, e->info_used->cnattr) == 0){
+ if(!cn)
+ cn = ldap_get_values(e->ld, e->selected_entry, a);
+ }
+ else if(strcmp(a, e->info_used->mailattr) == 0){
+ if(!mail)
+ mail = ldap_get_values(e->ld, e->selected_entry, a);
+ }
+ else if(strcmp(a, "electronicmail") == 0){
+ if(!elecmail)
+ elecmail = ldap_get_values(e->ld, e->selected_entry, a);
+ }
+ else if(strcmp(a, "comment") == 0){
+ if(!note)
+ note = ldap_get_values(e->ld, e->selected_entry, a);
+ }
+ else if(strcmp(a, e->info_used->snattr) == 0){
+ if(!sn)
+ sn = ldap_get_values(e->ld, e->selected_entry, a);
+ }
+ else if(strcmp(a, e->info_used->gnattr) == 0){
+ if(!givenname)
+ givenname = ldap_get_values(e->ld, e->selected_entry, a);
+ }
+ else if(strcmp(a, "telephonenumber") == 0){
+ if(!telephone)
+ telephone = ldap_get_values(e->ld, e->selected_entry, a);
+ }
+ else if(strcmp(a, "title") == 0){
+ if(!title)
+ title = ldap_get_values(e->ld, e->selected_entry, a);
+ }
+ }
+
+ if(!save){
+ j = radio_buttons(_("Save to address book or Export to filesystem ? "),
+ -FOOTER_ROWS(ps), save_or_export, 's', 'x',
+ h_ab_save_exp, RB_NORM);
+
+ switch(j){
+ case 'x':
+ q_status_message(SM_INFO, 0, 2, _("Address book save cancelled"));
+ break;
+
+ case 'e':
+ export++;
+ break;
+
+ case 's':
+ save++;
+ break;
+
+ default:
+ q_status_message(SM_ORDER, 3, 3,
+ "can't happen in save_ldap_ent");
+ break;
+ }
+ }
+ }
+
+ if(elecmail){
+ if(elecmail[0] && elecmail[0][0] && !mail)
+ mail = elecmail;
+ else
+ ldap_value_free(elecmail);
+
+ elecmail = NULL;
+ }
+
+ if(save){ /* save into the address book */
+ ADDRESS *addr;
+ char *d,
+ *fakedomain = "@";
+ size_t len;
+ char **cm;
+ int how_many_selected = 0;
+
+
+ if(cn && cn[0] && cn[0][0])
+ fullname = cpystr(cn[0]);
+ if(sn && sn[0] && sn[0][0])
+ last = cpystr(sn[0]);
+ if(givenname && givenname[0] && givenname[0][0])
+ first = cpystr(givenname[0]);
+
+ if(note && note[0] && note[0][0])
+ cm = note;
+ else
+ cm = title;
+
+ for(ll = cm, len = 0; ll && *ll; ll++)
+ len += strlen(*ll) + 2;
+
+ if(len){
+ comment = (char *)fs_get(len * sizeof(char));
+ d = comment;
+ ll = cm;
+ while(*ll){
+ sstrncpy(&d, *ll, len-(d-comment));
+ ll++;
+ if(*ll)
+ sstrncpy(&d, "; ", len-(d-comment));
+ }
+
+ comment[len-1] = '\0';
+ }
+
+ for(ll = mail, len = 0; ll && *ll; ll++)
+ len += strlen(*ll) + 1;
+
+ /* paste the email addresses together */
+ if(len){
+ address = (char *)fs_get(len * sizeof(char));
+ d = address;
+ ll = mail;
+ while(*ll){
+ sstrncpy(&d, *ll, len-(d-address));
+ ll++;
+ if(*ll)
+ sstrncpy(&d, ", ", len-(d-address));
+ }
+
+ address[len-1] = '\0';
+ }
+
+ addr = NULL;
+ if(address)
+ rfc822_parse_adrlist(&addr, address, fakedomain);
+
+ if(addr && fullname && !(first && last)){
+ if(addr->personal)
+ fs_give((void **)&addr->personal);
+
+ addr->personal = cpystr(fullname);
+ }
+
+ if(addr && e->serv && *e->serv){ /* save by reference */
+ char *dn, *edn = NULL;
+
+ dn = ldap_get_dn(e->ld, e->selected_entry);
+ if(dn){
+ edn = add_backslash_escapes(dn);
+ our_ldap_dn_memfree(dn);
+ }
+
+ if(e->serv && *e->serv && edn && *edn){
+ char buf[MAILTMPLEN+1];
+ char *backup_mail = NULL;
+
+ how_many_selected++;
+
+ if(addr && addr->mailbox && addr->host){
+ strncpy(buf, addr->mailbox, sizeof(buf)-2),
+ buf[sizeof(buf)-2] = '\0';
+ strncat(buf, "@", sizeof(buf)-1-strlen(buf));
+ strncat(buf, addr->host, sizeof(buf)-1-strlen(buf));
+ buf[sizeof(buf)-1] = '\0';
+ backup_mail = cpystr(buf);
+ }
+
+ /*
+ * We only need one addr which we will use to hold the
+ * pointer to the query.
+ */
+ if(addr->next)
+ mail_free_address(&addr->next);
+
+ if(addr->mailbox)
+ fs_give((void **)&addr->mailbox);
+ if(addr->host)
+ fs_give((void **)&addr->host);
+ if(addr->personal)
+ fs_give((void **)&addr->personal);
+
+ snprintf(buf, sizeof(buf),
+ "%s%s /base=%s/scope=base/cust=(objectclass=*)%s%s",
+ RUN_LDAP,
+ e->serv,
+ edn,
+ backup_mail ? "/mail=" : "",
+ backup_mail ? backup_mail : "");
+ buf[sizeof(buf)-1] = '\0';
+
+ if(backup_mail)
+ fs_give((void **)&backup_mail);
+
+ /*
+ * Put the search parameters in mailbox and put @ in
+ * host so that expand_address accepts it as an unqualified
+ * address and doesn't try to add localdomain.
+ */
+ addr->mailbox = cpystr(buf);
+ addr->host = cpystr("@");
+ }
+
+ if(edn)
+ fs_give((void **)&edn);
+ }
+ else{ /* save by value */
+ how_many_selected++;
+ if(!addr)
+ addr = mail_newaddr();
+ }
+
+ if(how_many_selected > 0){
+ TA_S *current = NULL;
+
+ /*
+ * The empty string for the last argument is significant.
+ * Fill_in_ta copies the whole adrlist into a single TA if
+ * there is a print string.
+ */
+ current = fill_in_ta(&current, addr, 1, "");
+ current = first_sel_taline(current);
+
+ if(first && last && current){
+ char *p;
+ size_t l;
+
+ l = strlen(last) + 2 + strlen(first);
+ p = (char *)fs_get((l+1) * sizeof(char));
+ snprintf(p, l, "%s, %s", last, first);
+ p[l] = '\0';
+ current->fullname = p;
+ convert_possibly_encoded_str_to_utf8(&current->fullname);
+ }
+
+ if(comment && current){
+ current->comment = cpystr(comment);
+ convert_possibly_encoded_str_to_utf8(&current->comment);
+ }
+
+ /*
+ * We don't want the personal name to make it into the address
+ * field in an LDAP: query sort of address, so move it
+ * out of the addr.
+ */
+ if(e->serv && *e->serv && current && fullname){
+ if(current->fullname)
+ fs_give((void **)&current->fullname);
+
+ current->fullname = fullname;
+ fullname = NULL;
+ convert_possibly_encoded_str_to_utf8(&current->fullname);
+ }
+
+ mail_free_address(&addr);
+
+ if(current)
+ takeaddr_bypass(ps, current, NULL);
+ else
+ q_status_message(SM_ORDER, 0, 4, "Nothing to save");
+
+ free_talines(&current);
+ }
+ else
+ q_status_message(SM_ORDER, 0, 4, "Nothing to save");
+
+ }
+ else if(export){ /* export to filesystem */
+ STORE_S *srcstore = NULL;
+ SourceType srctype;
+ static ESCKEY_S text_or_vcard[] = {
+ {'t', 't', "T", N_("Text")},
+ {'a', 'a', "A", N_("Addresses")},
+ {'v', 'v', "V", N_("VCard")},
+ {-1, 0, NULL, NULL}};
+
+ j = radio_buttons(
+ _("Export text of entry, address, or VCard format ? "),
+ -FOOTER_ROWS(ps), text_or_vcard, 't', 'x',
+ h_ldap_text_or_vcard, RB_NORM);
+
+ switch(j){
+ case 'x':
+ q_status_message(SM_INFO, 0, 2, _("Address book export cancelled"));
+ break;
+
+ case 't':
+ srctype = CharStar;
+ if(!(srcstore = prep_ldap_for_viewing(ps, e, srctype, NULL)))
+ q_status_message(SM_ORDER, 0, 2, _("Error allocating space"));
+ else{
+ (void)simple_export(ps_global, so_text(srcstore), srctype,
+ "text", NULL);
+ so_give(&srcstore);
+ }
+
+ break;
+
+ case 'a':
+ if(mail && mail[0] && mail[0][0]){
+
+ srctype = CharStar;
+ if(!(srcstore = so_get(srctype, NULL, EDIT_ACCESS)))
+ q_status_message(SM_ORDER,0,2, _("Error allocating space"));
+ else{
+ for(ll = mail; ll && *ll; ll++){
+ so_puts(srcstore, *ll);
+ so_puts(srcstore, "\n");
+ }
+
+ (void)simple_export(ps_global, so_text(srcstore),
+ srctype, "addresses", NULL);
+ so_give(&srcstore);
+ }
+ }
+
+ break;
+
+ case 'v':
+ srctype = CharStar;
+ if(!(srcstore = so_get(srctype, NULL, EDIT_ACCESS)))
+ q_status_message(SM_ORDER,0,2, _("Error allocating space"));
+ else{
+ gf_io_t pc;
+ VCARD_INFO_S *vinfo;
+
+ vinfo = (VCARD_INFO_S *)fs_get(sizeof(VCARD_INFO_S));
+ memset((void *)vinfo, 0, sizeof(VCARD_INFO_S));
+
+ if(cn && cn[0] && cn[0][0])
+ vinfo->fullname = copy_list_array(cn);
+
+ if(note && note[0] && note[0][0])
+ vinfo->note = copy_list_array(note);
+
+ if(title && title[0] && title[0][0])
+ vinfo->title = copy_list_array(title);
+
+ if(telephone && telephone[0] && telephone[0][0])
+ vinfo->tel = copy_list_array(telephone);
+
+ if(mail && mail[0] && mail[0][0])
+ vinfo->email = copy_list_array(mail);
+
+ if(sn && sn[0] && sn[0][0])
+ vinfo->last = cpystr(sn[0]);
+
+ if(givenname && givenname[0] && givenname[0][0])
+ vinfo->first = cpystr(givenname[0]);
+
+ gf_set_so_writec(&pc, srcstore);
+
+ write_single_vcard_entry(ps_global, pc, vinfo);
+
+ free_vcard_info(&vinfo);
+
+ (void)simple_export(ps_global, so_text(srcstore),
+ srctype, "vcard text", NULL);
+ so_give(&srcstore);
+ }
+
+ break;
+
+ default:
+ q_status_message(SM_ORDER, 3, 3, "can't happen in text_or_vcard");
+ break;
+ }
+ }
+
+ if(cn)
+ ldap_value_free(cn);
+ if(mail)
+ ldap_value_free(mail);
+ if(elecmail)
+ ldap_value_free(elecmail);
+ if(note)
+ ldap_value_free(note);
+ if(sn)
+ ldap_value_free(sn);
+ if(givenname)
+ ldap_value_free(givenname);
+ if(telephone)
+ ldap_value_free(telephone);
+ if(title)
+ ldap_value_free(title);
+ if(fullname)
+ fs_give((void **)&fullname);
+ if(address)
+ fs_give((void **)&address);
+ if(first)
+ fs_give((void **)&first);
+ if(last)
+ fs_give((void **)&last);
+ if(comment)
+ fs_give((void **)&comment);
+}
+#endif /* ENABLE_LDAP */
+
+
+#ifdef _WINDOWS
+
+int
+ta_scroll_up(count)
+ long count;
+{
+ if(count<0)
+ return(ta_scroll_down(-count));
+ else if (count){
+ long i=count;
+ TA_S *next_sel;
+
+ while(i && ta_screen->top_line->next){
+ if(ta_screen->top_line == ta_screen->current){
+ if(next_sel = next_sel_taline(ta_screen->current)){
+ ta_screen->current = next_sel;
+ ta_screen->top_line = next_taline(ta_screen->top_line);
+ i--;
+ }
+ else i = 0;
+ }
+ else{
+ ta_screen->top_line = next_taline(ta_screen->top_line);
+ i--;
+ }
+ }
+ }
+ return(TRUE);
+}
+
+int
+ta_scroll_down(count)
+ long count;
+{
+ if(count < 0)
+ return(ta_scroll_up(-count));
+ else if (count){
+ long i,dline;
+ long page_size = ps_global->ttyo->screen_rows -
+ FOOTER_ROWS(ps_global) - HEADER_ROWS(ps_global);
+ TA_S *ctmp;
+ TA_S *first = first_taline(ta_screen->top_line);
+
+ i=count;
+ dline=0;
+ for(ctmp = ta_screen->top_line;
+ ctmp != ta_screen->current; ctmp = next_taline(ctmp))
+ dline++;
+ while(i && ta_screen->top_line != first){
+ ta_screen->top_line = pre_taline(ta_screen->top_line);
+ i--;
+ dline++;
+ if(dline >= page_size){
+ ctmp = pre_sel_taline(ta_screen->current);
+ if(ctmp == NULL){
+ i = 0;
+ ta_screen->top_line = next_taline(ta_screen->top_line);
+ }
+ else {
+ for(; ctmp != ta_screen->current;
+ ta_screen->current = pre_taline(ta_screen->current))
+ dline--;
+ }
+ }
+ }
+ }
+ return(TRUE);
+}
+
+int ta_scroll_to_pos(line)
+ long line;
+{
+ TA_S *ctmp;
+ int dline;
+
+ for(dline = 0, ctmp = first_taline(ta_screen->top_line);
+ ctmp != ta_screen->top_line; ctmp = next_taline(ctmp))
+ dline++;
+
+ if (!ctmp)
+ dline = 1;
+
+ return(ta_scroll_up(line - dline));
+}
+
+int
+ta_scroll_callback (cmd, scroll_pos)
+ int cmd;
+ long scroll_pos;
+{
+ int paint = TRUE;
+ long page_size = ps_global->ttyo->screen_rows - HEADER_ROWS(ps_global)
+ - FOOTER_ROWS(ps_global);
+
+ switch (cmd) {
+ case MSWIN_KEY_SCROLLUPLINE:
+ paint = ta_scroll_down (scroll_pos);
+ break;
+
+ case MSWIN_KEY_SCROLLDOWNLINE:
+ paint = ta_scroll_up (scroll_pos);
+ break;
+
+ case MSWIN_KEY_SCROLLUPPAGE:
+ paint = ta_scroll_down (page_size);
+ break;
+
+ case MSWIN_KEY_SCROLLDOWNPAGE:
+ paint = ta_scroll_up (page_size);
+ break;
+
+ case MSWIN_KEY_SCROLLTO:
+ paint = ta_scroll_to_pos (scroll_pos);
+ break;
+ }
+
+ if(paint)
+ update_takeaddr_screen(ps_global, ta_screen->current, ta_screen, (Pos *)NULL);
+
+ return(paint);
+}
+
+#endif /* _WINDOWS */