* The instruction to remove the double quotes from the processing of
[alpine.git] / alpine / takeaddr.c
blobdf8e2b21ba13a5cb90d3d98775a5f31cdcd8e61b
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: takeaddr.c 1012 2008-03-26 00:44:22Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2020 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 /*======================================================================
20 takeaddr.c
21 Mostly support for Take Address command.
22 ====*/
25 #include "headers.h"
26 #include "takeaddr.h"
27 #include "addrbook.h"
28 #include "adrbkcmd.h"
29 #include "status.h"
30 #include "confscroll.h"
31 #include "keymenu.h"
32 #include "radio.h"
33 #include "titlebar.h"
34 #include "alpine.h"
35 #include "help.h"
36 #include "mailcmd.h"
37 #include "mailpart.h"
38 #include "roleconf.h"
39 #include "../pith/state.h"
40 #include "../pith/msgno.h"
41 #include "../pith/adrbklib.h"
42 #include "../pith/bldaddr.h"
43 #include "../pith/bitmap.h"
44 #include "../pith/util.h"
45 #include "../pith/addrstring.h"
46 #include "../pith/remote.h"
47 #include "../pith/newmail.h"
48 #include "../pith/list.h"
49 #include "../pith/abdlc.h"
50 #include "../pith/ablookup.h"
51 #include "../pith/stream.h"
52 #include "../pith/mailcmd.h"
53 #include "../pith/busy.h"
56 typedef struct takeaddress_screen {
57 ScreenMode mode;
58 TA_S *current,
59 *top_line;
60 } TA_SCREEN_S;
62 static TA_SCREEN_S *ta_screen;
63 static char *fakedomain = "@";
65 static ESCKEY_S save_or_export[] = {
66 {'s', 's', "S", N_("Save")},
67 {'e', 'e', "E", N_("Export")},
68 {-1, 0, NULL, NULL}};
71 /* internal prototypes */
72 int edit_nickname(AdrBk *, AddrScrn_Disp *, int, char *, char *, HelpType, int, int);
73 void add_abook_entry(TA_S *, char *, char *, char *, char *, int, TA_STATE_S **, char *);
74 void take_to_addrbooks_frontend(char **, char *, char *, char *, char *,
75 char *, int, TA_STATE_S **, char *);
76 void take_to_addrbooks(char **, char *, char *, char *, char *,
77 char *, int, TA_STATE_S **, char *);
78 PerAddrBook *use_this_addrbook(int, char *);
79 PerAddrBook *check_for_addrbook(char *);
80 int takeaddr_screen(struct pine *, TA_S *, int, ScreenMode, TA_STATE_S **, char *);
81 void takeaddr_bypass(struct pine *, TA_S *, TA_STATE_S **);
82 int ta_do_take(TA_S *, int, int, TA_STATE_S **, char *);
83 TA_S *whereis_taline(TA_S *);
84 int ta_take_marked_addrs(int, TA_S *, int, TA_STATE_S **, char *);
85 int ta_take_single_addr(TA_S *, int, TA_STATE_S **, char *);
86 int update_takeaddr_screen(struct pine *, TA_S *, TA_SCREEN_S *, Pos *);
87 void takeaddr_screen_redrawer_list(void);
88 void takeaddr_screen_redrawer_single(void);
89 int attached_addr_handler(TA_S *, int);
90 int take_without_edit(TA_S *, int, int, TA_STATE_S **, char *);
91 void export_vcard_att(struct pine *, int, long, ATTACH_S *);
92 int take_export_tool(struct pine *, int, CONF_S **, unsigned);
94 #ifdef _WINDOWS
95 int ta_scroll_up(long);
96 int ta_scroll_down(long);
97 int ta_scroll_to_pos(long);
98 int ta_scroll_callback(int, long);
99 #endif
103 * Edit a nickname field.
105 * Args: abook -- the addressbook handle
106 * dl -- display list line (NULL if new entry)
107 * command_line -- line to prompt on
108 * orig -- nickname to edit
109 * prompt -- prompt
110 * this_help -- help
111 * return_existing -- changes the behavior when a user types in a nickname
112 * which already exists in this abook. If not set, it
113 * will just keep looping until the user changes; if set,
114 * it will return -8 to the caller and orig will be set
115 * to the matching nickname.
117 * Returns: -10 to cancel
118 * -9 no change
119 * -7 only case of nickname changed (only happens if dl set)
120 * -8 existing nickname chosen (only happens if return_existing set)
121 * 0 new value copied into orig
124 edit_nickname(AdrBk *abook, AddrScrn_Disp *dl, int command_line, char *orig,
125 char *prompt, HelpType this_help, int return_existing, int takeaddr)
127 char edit_buf[MAX_NICKNAME + 1];
128 HelpType help;
129 int i, flags, lastrc, rc;
130 AdrBk_Entry *check, *passed_in_ae;
131 ESCKEY_S ekey[3];
132 SAVE_STATE_S state; /* For saving state of addrbooks temporarily */
133 char *error = NULL;
135 ekey[i = 0].ch = ctrl('T');
136 ekey[i].rval = 2;
137 ekey[i].name = "^T";
138 ekey[i++].label = N_("To AddrBk");
140 if(F_ON(F_ENABLE_TAB_COMPLETE,ps_global)){
141 ekey[i].ch = ctrl('I');
142 ekey[i].rval = 11;
143 ekey[i].name = "TAB";
144 ekey[i++].label = N_("Complete");
147 ekey[i].ch = -1;
149 strncpy(edit_buf, orig, sizeof(edit_buf)-1);
150 edit_buf[sizeof(edit_buf)-1] = '\0';
151 if(dl)
152 passed_in_ae = adrbk_get_ae(abook, (a_c_arg_t) dl->elnum);
153 else
154 passed_in_ae = (AdrBk_Entry *)NULL;
156 help = NO_HELP;
157 rc = 0;
158 check = NULL;
160 if(error){
161 q_status_message(SM_ORDER, 3, 4, error);
162 fs_give((void **)&error);
165 /* display a message because adrbk_lookup_by_nick returned positive */
166 if(check){
167 if(return_existing){
168 strncpy(orig, edit_buf, sizeof(edit_buf)-1);
169 orig[sizeof(edit_buf)-1] = '\0';
170 if(passed_in_ae)
171 (void)adrbk_get_ae(abook, (a_c_arg_t) dl->elnum);
172 return -8;
175 q_status_message1(SM_ORDER, 0, 4,
176 _("Already an entry with nickname \"%s\""), edit_buf);
179 lastrc = rc;
180 if(rc == 3)
181 help = (help == NO_HELP ? this_help : NO_HELP);
183 flags = OE_APPEND_CURRENT;
184 rc = optionally_enter(edit_buf, command_line, 0, sizeof(edit_buf),
185 prompt, ekey, help, &flags);
187 if(rc == 1) /* ^C */
188 break;
190 if(rc == 2){ /* ^T */
191 void (*redraw) (void) = ps_global->redrawer;
192 char *returned_nickname;
194 push_titlebar_state();
195 save_state(&state);
196 if(takeaddr)
197 returned_nickname = addr_book_takeaddr();
198 else
199 returned_nickname = addr_book_selnick();
201 restore_state(&state);
202 if(returned_nickname){
203 strncpy(edit_buf, returned_nickname, sizeof(edit_buf)-1);
204 edit_buf[sizeof(edit_buf)-1] = '\0';
205 fs_give((void **)&returned_nickname);
208 ClearScreen();
209 pop_titlebar_state();
210 redraw_titlebar();
211 if((ps_global->redrawer = redraw) != NULL) /* reset old value, and test */
212 (*ps_global->redrawer)();
214 else if(rc == 11){ /* TAB */
215 if(edit_buf[0]){
216 char *new_nickname = NULL;
217 int ambiguity;
219 ambiguity = abook_nickname_complete(edit_buf, &new_nickname,
220 (lastrc==rc && !(flags & OE_USER_MODIFIED)), 0);
221 if(new_nickname){
222 if(*new_nickname){
223 strncpy(edit_buf, new_nickname, sizeof(edit_buf));
224 edit_buf[sizeof(edit_buf)-1] = '\0';
227 fs_give((void **) &new_nickname);
230 if(ambiguity != 2)
231 Writechar(BELL, 0);
235 }while(rc == 2 ||
236 rc == 3 ||
237 rc == 4 ||
238 rc == 11||
239 nickname_check(edit_buf, &error) ||
240 ((check =
241 adrbk_lookup_by_nick(abook, edit_buf, (adrbk_cntr_t *)NULL)) &&
242 check != passed_in_ae));
244 if(rc != 0){
245 if(passed_in_ae)
246 (void)adrbk_get_ae(abook, (a_c_arg_t) dl->elnum);
248 return -10;
251 /* only the case of nickname changed */
252 if(passed_in_ae && check == passed_in_ae && strcmp(edit_buf, orig)){
253 (void)adrbk_get_ae(abook, (a_c_arg_t) dl->elnum);
254 strncpy(orig, edit_buf, sizeof(edit_buf)-1);
255 orig[sizeof(edit_buf)-1] = '\0';
256 return -7;
259 if(passed_in_ae)
260 (void)adrbk_get_ae(abook, (a_c_arg_t) dl->elnum);
262 if(strcmp(edit_buf, orig) == 0) /* no change */
263 return -9;
265 strncpy(orig, edit_buf, sizeof(edit_buf)-1);
266 orig[sizeof(edit_buf)-1] = '\0';
267 return 0;
272 * Add an entry to address book.
273 * It is for capturing addresses off incoming mail.
274 * This is a front end for take_to_addrbooks.
275 * It is also used for replacing an existing entry and for adding a single
276 * new address to an existing list.
278 * The reason this is here is so that when Taking a single address, we can
279 * rearrange the fullname to be Last, First instead of First Last.
281 * Args: ta_entry -- the entry from the take screen
282 * command_line -- line to prompt on
284 * Result: item is added to one of the address books,
285 * an error message is queued if appropriate.
287 void
288 add_abook_entry(TA_S *ta_entry, char *nick, char *fullname, char *fcc,
289 char *comment, int command_line, TA_STATE_S **tas, char *cmd)
291 ADDRESS *addr;
292 char new_fullname[6*MAX_FULLNAME + 1], new_address[6*MAX_ADDRESS + 1];
293 char **new_list;
295 dprint((5, "-- add_abook_entry --\n"));
297 /*-- rearrange full name (Last, First) ---*/
298 new_fullname[0] = '\0';
299 addr = ta_entry->addr;
300 if(!fullname && addr->personal != NULL){
301 if(F_ON(F_DISABLE_TAKE_LASTFIRST, ps_global)){
302 strncpy(new_fullname, addr->personal, sizeof(new_fullname)-1);
303 new_fullname[sizeof(new_fullname)-1] = '\0';
305 else{
306 char old_fullname[6*MAX_FULLNAME + 1];
308 snprintf(old_fullname, sizeof(old_fullname), "%s", addr->personal);
309 old_fullname[sizeof(old_fullname)-1] = '\0';
310 switch_to_last_comma_first(old_fullname, new_fullname, sizeof(new_fullname));
314 /* initial value for new address */
315 new_address[0] = '\0';
316 if(addr->mailbox && addr->mailbox[0]){
317 char *scratch, *p, *t, *u;
318 size_t es;
319 unsigned long l;
320 RFC822BUFFER rbuf;
322 es = est_size(addr);
323 scratch = (char *) fs_get(es);
324 scratch[0] = '\0';
325 rbuf.f = dummy_soutr;
326 rbuf.s = NULL;
327 rbuf.beg = scratch;
328 rbuf.cur = scratch;
329 rbuf.end = scratch+es-1;
330 rfc822_output_address_list(&rbuf, addr, 0L, NULL);
331 *rbuf.cur = '\0';
332 if((p = srchstr(scratch, "@" RAWFIELD)) != NULL){
333 for(t = p; ; t--)
334 if(*t == '&'){ /* find "leading" token */
335 *t++ = ' '; /* replace token */
336 *p = '\0'; /* tie off string */
337 u = (char *)rfc822_base64((unsigned char *)t,
338 (unsigned long)strlen(t), &l);
339 *p = '@'; /* restore 'p' */
340 rplstr(p, es-(p-scratch), 12, ""); /* clear special token */
341 rplstr(t, es-(t-scratch), strlen(t), u); /* Null u is handled */
342 if(u)
343 fs_give((void **)&u);
345 else if(t == scratch)
346 break;
349 strncpy(new_address, scratch, sizeof(new_address)-1);
350 new_address[sizeof(new_address)-1] = '\0';
352 if(scratch)
353 fs_give((void **)&scratch);
356 if(ta_entry->frwrded){
357 ADDRESS *a;
358 int i, j;
360 for(i = 0, a = addr; a; i++, a = a->next)
361 ;/* just counting for alloc below */
363 /* catch special case where empty addr was set in vcard_to_ta */
364 if(i == 1 && !addr->host && !addr->mailbox && !addr->personal)
365 i = 0;
367 new_list = (char **) fs_get((i+1) * sizeof(char *));
368 for(j = 0, a = addr; i && a; j++, a = a->next){
369 ADDRESS *next_addr;
370 char *bufp;
371 size_t len;
373 next_addr = a->next;
374 a->next = NULL;
375 len = est_size(a);
376 bufp = (char *) fs_get(len * sizeof(char));
377 new_list[j] = cpystr(addr_string(a, bufp, len));
378 a->next = next_addr;
379 fs_give((void **) &bufp);
382 new_list[j] = NULL;
384 else{
385 int i = 0, j;
387 j = (ta_entry->strvalue && ta_entry->strvalue[0]) ? 2 : 1;
389 new_list = (char **) fs_get(j * sizeof(char *));
391 if(j == 2)
392 new_list[i++] = cpystr(ta_entry->strvalue);
394 new_list[i] = NULL;
397 take_to_addrbooks_frontend(new_list, nick,
398 fullname ? fullname : new_fullname,
399 new_address, fcc, comment, command_line,
400 tas, cmd);
401 free_list_array(&new_list);
405 void
406 take_to_addrbooks_frontend(char **new_entries, char *nick, char *fullname,
407 char *addr, char *fcc, char *comment, int cmdline,
408 TA_STATE_S **tas, char *cmd)
410 jmp_buf save_jmp_buf;
411 int *save_nesting_level;
413 dprint((5, "-- take_to_addrbooks_frontend --\n"));
415 if(ps_global->remote_abook_validity > 0 &&
416 adrbk_check_and_fix_all(ab_nesting_level == 0, 0, 0))
417 ps_global->mangled_footer = 1;
419 save_nesting_level = cpyint(ab_nesting_level);
420 memcpy(save_jmp_buf, addrbook_changed_unexpectedly, sizeof(jmp_buf));
421 if(setjmp(addrbook_changed_unexpectedly)){
422 q_status_message(SM_ORDER, 5, 10, _("Resetting address book..."));
423 dprint((1,
424 "RESETTING address book... take_to_addrbooks_frontend!\n"));
425 addrbook_reset();
426 ab_nesting_level = *save_nesting_level;
429 ab_nesting_level++;
430 take_to_addrbooks(new_entries, nick, fullname, addr, fcc, comment, cmdline,
431 tas, cmd);
432 memcpy(addrbook_changed_unexpectedly, save_jmp_buf, sizeof(jmp_buf));
433 ab_nesting_level--;
434 if(save_nesting_level)
435 fs_give((void **)&save_nesting_level);
440 * Add to address book, called from take screen.
441 * It is also used for adding to an existing list or replacing an existing
442 * entry.
444 * Args: new_entries -- a list of addresses to add to a list or to form
445 * a new list with
446 * nick -- if adding new entry, suggest this for nickname
447 * fullname -- if adding new entry, use this for fullname
448 * addr -- if only one new_entry, this is its addr
449 * fcc -- if adding new entry, use this for fcc
450 * comment -- if adding new entry, use this for comment
451 * command_line -- line to prompt on
453 * Result: item is added to one of the address books,
454 * an error message is queued if appropriate.
456 void
457 take_to_addrbooks(char **new_entries, char *nick, char *fullname, char *addr,
458 char *fcc, char *comment, int command_line, TA_STATE_S **tas, char *cmd)
460 char new_nickname[6*MAX_NICKNAME + 1], exist_nick[6*MAX_NICKNAME + 1];
461 char prompt[200], **p;
462 int rc, listadd = 0, ans, i;
463 AdrBk *abook;
464 SAVE_STATE_S state;
465 PerAddrBook *pab;
466 AdrBk_Entry *abe = (AdrBk_Entry *)NULL, *abe_copy;
467 adrbk_cntr_t entry_num = NO_NEXT;
468 size_t tot_size, new_size, old_size;
469 Tag old_tag;
470 char *tmp_a_string;
471 char *simple_a = NULL;
472 ADDRESS *a = NULL;
475 dprint((5, "-- take_to_addrbooks --\n"));
477 if(tas && *tas)
478 pab = (*tas)->pab;
479 else
480 pab = setup_for_addrbook_add(&state, command_line, cmd);
482 /* check we got it opened ok */
483 if(pab == NULL || pab->address_book == NULL)
484 goto take_to_addrbooks_cancel;
486 adrbk_check_validity(pab->address_book, 1L);
487 if(pab->address_book->flags & FILE_OUTOFDATE ||
488 (pab->address_book->rd &&
489 pab->address_book->rd->flags & REM_OUTOFDATE)){
490 q_status_message3(SM_ORDER, 0, 4,
491 "Address book%s%s has changed: %stry again",
492 (as.n_addrbk > 1 && pab->abnick) ? " " : "",
493 (as.n_addrbk > 1 && pab->abnick) ? pab->abnick : "",
494 (ps_global->remote_abook_validity == -1) ? "resynchronize and " : "");
495 if(tas && *tas){
496 restore_state(&((*tas)->state));
497 (*tas)->pab = NULL;
499 else
500 restore_state(&state);
502 return;
505 abook = pab->address_book;
506 new_nickname[0] = '\0';
507 exist_nick[0] = '\0';
509 if(addr){
510 simple_a = NULL;
511 a = NULL;
512 /* rfc822_parse_adrlist feels free to destroy input so send copy */
513 tmp_a_string = cpystr(addr);
514 rfc822_parse_adrlist(&a, tmp_a_string, fakedomain);
515 if(tmp_a_string)
516 fs_give((void **)&tmp_a_string);
518 if(a){
519 simple_a = simple_addr_string(a, tmp_20k_buf, SIZEOF_20KBUF);
520 mail_free_address(&a);
523 if(simple_a && *simple_a)
524 abe = adrbk_lookup_by_addr(abook, simple_a, NULL);
526 if(abe){
527 snprintf(prompt, sizeof(prompt), _("Warning: address exists with %s%s, continue "),
528 (abe->nickname && abe->nickname[0]) ? "nickname "
529 : (abe->fullname && abe->fullname[0]) ? "fullname "
530 : "no nickname",
531 (abe->nickname && abe->nickname[0]) ? abe->nickname
532 : (abe->fullname && abe->fullname[0]) ? abe->fullname
533 : "");
534 prompt[sizeof(prompt)-1] = '\0';
535 switch(want_to(prompt, 'y', 'x', NO_HELP, WT_NORM)){
536 case 'y':
537 if(abe->nickname && abe->nickname[0]){
538 strncpy(new_nickname, abe->nickname, sizeof(new_nickname));
539 new_nickname[sizeof(new_nickname)-1] = '\0';
540 strncpy(exist_nick, new_nickname, sizeof(exist_nick));
541 exist_nick[sizeof(exist_nick)-1] = '\0';
544 break;
546 default:
547 goto take_to_addrbooks_cancel;
552 get_nick:
553 abe = NULL;
554 old_tag = NotSet;
555 entry_num = NO_NEXT;
557 /*----- nickname ------*/
558 snprintf(prompt, sizeof(prompt),
559 _("Enter new or existing nickname (one word and easy to remember): "));
560 prompt[sizeof(prompt)-1] = '\0';
561 if(!new_nickname[0] && nick){
562 strncpy(new_nickname, nick, sizeof(new_nickname));
563 new_nickname[sizeof(new_nickname)-1] = '\0';
566 rc = edit_nickname(abook, (AddrScrn_Disp *)NULL, command_line,
567 new_nickname, prompt, h_oe_takenick, 1, 1);
568 if(rc == -8){ /* this means an existing nickname was entered */
569 abe = adrbk_lookup_by_nick(abook, new_nickname, &entry_num);
570 if(!abe){ /* this shouldn't happen */
571 q_status_message1(SM_ORDER, 0, 4,
572 _("Already an entry %s in address book!"), new_nickname);
573 goto take_to_addrbooks_cancel;
576 old_tag = abe->tag;
578 if(abe->tag == Single && !strcmp(new_nickname, exist_nick)){
579 static ESCKEY_S choices[] = {
580 {'r', 'r', "R", N_("Replace")},
581 {'n', 'n', "N", N_("No")},
582 {-1, 0, NULL, NULL}};
584 snprintf(prompt, sizeof(prompt), _("Entry %s (%s) exists, replace ? "),
585 new_nickname,
586 (abe->fullname && abe->fullname[0])
587 ? (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf,
588 SIZEOF_20KBUF, abe->fullname)
589 : "<no long name>");
590 prompt[sizeof(prompt)-1] = '\0';
591 ans = radio_buttons(prompt,
592 command_line,
593 choices,
594 'r',
595 'x',
596 h_oe_take_replace,
597 RB_NORM);
599 else{
600 static ESCKEY_S choices[] = {
601 {'r', 'r', "R", N_("Replace")},
602 {'a', 'a', "A", N_("Add")},
603 {'n', 'n', "N", N_("No")},
604 {-1, 0, NULL, NULL}};
606 snprintf(prompt, sizeof(prompt),
607 _("%s %s (%s) exists, replace or add addresses to it ? "),
608 abe->tag == List ? "List" : "Entry",
609 new_nickname,
610 (abe->fullname && abe->fullname[0])
611 ? (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf,
612 SIZEOF_20KBUF, abe->fullname)
613 : "<no long name>");
614 prompt[sizeof(prompt)-1] = '\0';
616 ans = radio_buttons(prompt,
617 command_line,
618 choices,
619 'a',
620 'x',
621 h_oe_take_replace_or_add,
622 RB_NORM);
625 switch(ans){
626 case 'y':
627 case 'r':
628 break;
630 case 'n':
631 goto get_nick;
632 break;
634 case 'a':
635 listadd++;
636 break;
638 default:
639 goto take_to_addrbooks_cancel;
642 else if(rc != 0 && rc != -9) /* -9 means a null nickname */
643 goto take_to_addrbooks_cancel;
645 if((long)abook->count > MAX_ADRBK_SIZE ||
646 (old_tag == NotSet && (long)abook->count >= MAX_ADRBK_SIZE)){
647 q_status_message(SM_ORDER, 3, 5,
648 _("Address book is at maximum size, cancelled."));
649 dprint((2, "Addrbook at Max size, TakeAddr cancelled\n"));
650 goto take_to_addrbooks_cancel;
653 if(listadd){
654 /* count up size of existing list */
655 if(abe->tag == List){
656 for(p = abe->addr.list; p != NULL && *p != NULL; p++)
657 ;/* do nothing */
659 old_size = p - abe->addr.list;
661 /* or size of existing single address */
662 else if(abe->addr.addr && abe->addr.addr[0])
663 old_size = 1;
664 else
665 old_size = 0;
667 else /* don't care about old size, they will be tossed in edit_entry */
668 old_size = 0;
670 /* make up an abe to pass to edit_entry */
671 abe_copy = adrbk_newentry();
672 abe_copy->nickname = cpystr(new_nickname);
673 abe_copy->tag = List;
674 abe_copy->addr.list = NULL;
676 if(listadd){
677 abe_copy->fullname = cpystr((abe->fullname && abe->fullname[0])
678 ? abe->fullname : "");
679 abe_copy->fcc = cpystr((abe->fcc && abe->fcc[0]) ? abe->fcc : "");
680 abe_copy->extra = cpystr((abe->extra&&abe->extra[0]) ? abe->extra : "");
682 else{
684 * use passed in info if available
686 abe_copy->fullname = cpystr((fullname && fullname[0])
687 ? fullname
688 : (abe && abe->fullname)
689 ? abe->fullname
690 : "");
691 abe_copy->fcc = cpystr((fcc && fcc[0])
692 ? fcc
693 : (abe && abe->fcc)
694 ? abe->fcc
695 : "");
696 abe_copy->extra = cpystr((comment && comment[0])
697 ? comment
698 : (abe && abe->extra)
699 ? abe->extra
700 : "");
703 /* get rid of duplicates */
704 if(listadd){
705 if(abe->tag == List){
706 int elim_dup;
707 char **q, **r;
708 ADDRESS *newadr, *oldadr;
710 for(q = new_entries; q != NULL && *q != NULL;){
712 tmp_a_string = cpystr(*q);
713 newadr = NULL;
714 rfc822_parse_adrlist(&newadr, tmp_a_string, fakedomain);
715 fs_give((void **) &tmp_a_string);
717 elim_dup = (newadr == NULL);
718 for(p = abe->addr.list;
719 !elim_dup && p != NULL && *p != NULL;
720 p++){
721 tmp_a_string = cpystr(*p);
722 oldadr = NULL;
723 rfc822_parse_adrlist(&oldadr, tmp_a_string, fakedomain);
724 fs_give((void **) &tmp_a_string);
726 if(address_is_same(newadr, oldadr))
727 elim_dup++;
729 if(oldadr)
730 mail_free_address(&oldadr);
733 /* slide the addresses down one to eliminate newadr */
734 if(elim_dup){
735 char *f;
737 f = *q;
738 for(r = q; r != NULL && *r != NULL; r++)
739 *r = *(r+1);
741 if(f)
742 fs_give((void **) &f);
744 else
745 q++;
747 if(newadr)
748 mail_free_address(&newadr);
751 else{
752 char **q, **r;
753 ADDRESS *newadr, *oldadr;
755 tmp_a_string = cpystr(abe->addr.addr ? abe->addr.addr : "");
756 oldadr = NULL;
757 rfc822_parse_adrlist(&oldadr, tmp_a_string, fakedomain);
758 fs_give((void **) &tmp_a_string);
760 for(q = new_entries; q != NULL && *q != NULL;){
762 tmp_a_string = cpystr(*q);
763 newadr = NULL;
764 rfc822_parse_adrlist(&newadr, tmp_a_string, fakedomain);
765 fs_give((void **) &tmp_a_string);
767 /* slide the addresses down one to eliminate newadr */
768 if(address_is_same(newadr, oldadr)){
769 char *f;
771 f = *q;
772 for(r = q; r != NULL && *r != NULL; r++)
773 *r = *(r+1);
775 if(f)
776 fs_give((void **) &f);
778 else
779 q++;
781 if(newadr)
782 mail_free_address(&newadr);
785 if(oldadr)
786 mail_free_address(&oldadr);
789 if(!new_entries || !*new_entries){
790 q_status_message1(SM_ORDER, 0, 4,
791 _("All of the addresses are already included in \"%s\""),
792 new_nickname);
793 free_ae(&abe_copy);
794 if(tas && *tas){
795 restore_state(&((*tas)->state));
796 (*tas)->pab = NULL;
798 else
799 restore_state(&state);
801 return;
805 /* count up size of new list */
806 for(p = new_entries; p != NULL && *p != NULL; p++)
807 ;/* do nothing */
809 new_size = p - new_entries;
810 tot_size = old_size + new_size;
811 abe_copy->addr.list = (char **) fs_get((tot_size+1) * sizeof(char *));
812 memset((void *) abe_copy->addr.list, 0, (tot_size+1) * sizeof(char *));
813 if(old_size > 0){
814 if(abe->tag == List){
815 for(i = 0; i < old_size; i++)
816 abe_copy->addr.list[i] = cpystr(abe->addr.list[i]);
818 else
819 abe_copy->addr.list[0] = cpystr(abe->addr.addr);
822 /* add new addresses to list */
823 if(tot_size == 1 && addr)
824 abe_copy->addr.list[0] = cpystr(addr);
825 else
826 for(i = 0; i < new_size; i++)
827 abe_copy->addr.list[old_size + i] = cpystr(new_entries[i]);
829 abe_copy->addr.list[tot_size] = NULL;
831 if(F_ON(F_DISABLE_TAKE_FULLNAMES, ps_global)){
832 for(i = 0; abe_copy->addr.list[i]; i++){
833 simple_a = NULL;
834 a = NULL;
835 tmp_a_string = cpystr(abe_copy->addr.list[i]);
836 rfc822_parse_adrlist(&a, tmp_a_string, fakedomain);
837 if(tmp_a_string)
838 fs_give((void **) &tmp_a_string);
840 if(a){
841 simple_a = simple_addr_string(a, tmp_20k_buf, SIZEOF_20KBUF);
842 mail_free_address(&a);
845 /* replace the old addr string with one with no full name */
846 if(simple_a && *simple_a){
847 if(abe_copy->addr.list[i])
848 fs_give((void **) &abe_copy->addr.list[i]);
850 abe_copy->addr.list[i] = cpystr(simple_a);
855 edit_entry(abook, abe_copy, (a_c_arg_t) entry_num, old_tag, 0, NULL, cmd);
857 /* free copy */
858 free_ae(&abe_copy);
859 if(tas && *tas){
860 restore_state(&((*tas)->state));
861 (*tas)->pab = NULL;
863 else
864 restore_state(&state);
866 return;
868 take_to_addrbooks_cancel:
869 q_status_message(SM_INFO, 0, 2, _("Address book addition cancelled"));
870 if(tas && *tas){
871 restore_state(&((*tas)->state));
872 (*tas)->pab = NULL;
874 else
875 restore_state(&state);
880 * Prep addrbook for TakeAddr add operation.
882 * Arg: savep -- Address of a pointer to save addrbook state in.
883 * stp -- Address of a pointer to save addrbook state in.
885 * Returns: a PerAddrBook pointer, or NULL.
887 PerAddrBook *
888 setup_for_addrbook_add(SAVE_STATE_S *state, int command_line, char *cmd)
890 PerAddrBook *pab;
891 int save_rem_abook_valid = 0;
893 init_ab_if_needed();
894 save_state(state);
896 if(as.n_addrbk == 0){
897 q_status_message(SM_ORDER, 3, 4, _("No address book configured!"));
898 return NULL;
900 else
901 pab = use_this_addrbook(command_line, cmd);
903 if(!pab)
904 return NULL;
906 if((pab->type & REMOTE_VIA_IMAP) && ps_global->remote_abook_validity == -1){
907 save_rem_abook_valid = -1;
908 ps_global->remote_abook_validity = 0;
911 /* initialize addrbook so we can add to it */
912 init_abook(pab, Open);
914 if(save_rem_abook_valid)
915 ps_global->remote_abook_validity = save_rem_abook_valid;
917 if(pab->ostatus != Open){
918 q_status_message(SM_ORDER, 3, 4, _("Can't open address book!"));
919 return NULL;
922 if(pab->access != ReadWrite){
923 if(pab->access == ReadOnly)
924 q_status_message(SM_ORDER, 0, 4, _("AddressBook is Read Only"));
925 else if(pab->access == NoAccess)
926 q_status_message(SM_ORDER, 3, 4,
927 _("AddressBook not accessible, permission denied"));
929 return NULL;
932 return(pab);
937 * Interact with user to figure out which address book they want to add a
938 * new entry (TakeAddr) to.
940 * Args: command_line -- just the line to prompt on
942 * Results: returns a pab pointing to the selected addrbook, or NULL.
944 PerAddrBook *
945 use_this_addrbook(int command_line, char *cmd)
947 HelpType help;
948 int rc = 0;
949 PerAddrBook *pab, *the_only_pab;
950 #define MAX_ABOOK 2000
951 int i, abook_num, count_read_write;
952 char addrbook[MAX_ABOOK + 1],
953 prompt[MAX_ABOOK + 81];
954 static ESCKEY_S ekey[] = {
955 {-2, 0, NULL, NULL},
956 {ctrl('P'), 10, "^P", N_("Prev AddrBook")},
957 {ctrl('N'), 11, "^N", N_("Next AddrBook")},
958 {KEY_UP, 10, "", ""},
959 {KEY_DOWN, 11, "", ""},
960 {-1, 0, NULL, NULL}};
962 dprint((9, "- use_this_addrbook -\n"));
964 /* check for only one ReadWrite addrbook */
965 count_read_write = 0;
966 for(i = 0; i < as.n_addrbk; i++){
967 pab = &as.adrbks[i];
969 * NoExists is counted, too, so the user can add to an empty
970 * addrbook the first time.
972 if(pab->access == ReadWrite ||
973 pab->access == NoExists ||
974 pab->access == MaybeRorW){
975 count_read_write++;
976 the_only_pab = &as.adrbks[i];
980 /* only one usable addrbook, use it */
981 if(count_read_write == 1)
982 return(the_only_pab);
984 /* no addrbook to write to */
985 if(count_read_write == 0){
986 q_status_message2(SM_ORDER | SM_DING, 3, 4,
987 "No %sAddressbook to %s to!",
988 (as.n_addrbk > 0) ? "writable " : "", cmd);
989 return NULL;
992 /* start with the first addrbook */
993 abook_num = 0;
994 pab = &as.adrbks[abook_num];
995 strncpy(addrbook, pab->abnick, sizeof(addrbook)-1);
996 addrbook[sizeof(addrbook)-1] = '\0';
997 snprintf(prompt, sizeof(prompt), "%c%s to which addrbook : %s",
998 islower((unsigned char)(*cmd)) ? toupper((unsigned char)*cmd) : *cmd,
999 cmd+1,
1000 (pab->access == ReadOnly || pab->access == NoAccess) ?
1001 "[ReadOnly] " : "");
1002 prompt[sizeof(prompt)-1] = '\0';
1003 help = NO_HELP;
1004 ps_global->mangled_footer = 1;
1006 int flags;
1008 if(!pab)
1009 q_status_message1(SM_ORDER, 3, 4, _("No addressbook \"%s\""),
1010 addrbook);
1012 if(rc == 3)
1013 help = (help == NO_HELP ? h_oe_chooseabook : NO_HELP);
1015 flags = OE_APPEND_CURRENT;
1016 rc = optionally_enter(addrbook, command_line, 0, sizeof(addrbook),
1017 prompt, ekey, help, &flags);
1019 if(rc == 1){ /* ^C */
1020 char capcmd[50];
1022 snprintf(capcmd, sizeof(capcmd),
1023 "%c%s",
1024 islower((unsigned char)(*cmd)) ? toupper((unsigned char)*cmd)
1025 : *cmd,
1026 cmd+1);
1027 capcmd[sizeof(capcmd)-1] = '\0';
1028 cmd_cancelled(capcmd);
1029 break;
1032 if(rc == 10){ /* Previous addrbook */
1033 if(--abook_num < 0)
1034 abook_num = as.n_addrbk - 1;
1036 pab = &as.adrbks[abook_num];
1037 strncpy(addrbook, pab->abnick, sizeof(addrbook)-1);
1038 addrbook[sizeof(addrbook)-1] = '\0';
1039 snprintf(prompt, sizeof(prompt), "%s to which addrbook : %s", cmd,
1040 (pab->access == ReadOnly || pab->access == NoAccess) ?
1041 "[ReadOnly] " : "");
1042 prompt[sizeof(prompt)-1] = '\0';
1044 else if(rc == 11){ /* Next addrbook */
1045 if(++abook_num > as.n_addrbk - 1)
1046 abook_num = 0;
1048 pab = &as.adrbks[abook_num];
1049 strncpy(addrbook, pab->abnick, sizeof(addrbook)-1);
1050 addrbook[sizeof(addrbook)-1] = '\0';
1051 snprintf(prompt, sizeof(prompt), "%s to which addrbook : %s", cmd,
1052 (pab->access == ReadOnly || pab->access == NoAccess) ?
1053 "[ReadOnly] " : "");
1054 prompt[sizeof(prompt)-1] = '\0';
1057 }while(rc == 2 || rc == 3 || rc == 4 || rc == 10 || rc == 11 || rc == 12 ||
1058 !(pab = check_for_addrbook(addrbook)));
1060 ps_global->mangled_footer = 1;
1062 if(rc != 0)
1063 return NULL;
1065 return(pab);
1070 * Return a pab pointer to the addrbook which corresponds to the argument.
1072 * Args: addrbook -- the string representing the addrbook.
1074 * Results: returns a PerAddrBook pointer for the referenced addrbook, NULL
1075 * if none. First the nicknames are checked and then the filenames.
1076 * This must be one of the existing addrbooks.
1078 PerAddrBook *
1079 check_for_addrbook(char *addrbook)
1081 register int i;
1082 register PerAddrBook *pab;
1084 for(i = 0; i < as.n_addrbk; i++){
1085 pab = &as.adrbks[i];
1086 if(strcmp(pab->abnick, addrbook) == 0)
1087 break;
1090 if(i < as.n_addrbk)
1091 return(pab);
1093 for(i = 0; i < as.n_addrbk; i++){
1094 pab = &as.adrbks[i];
1095 if(strcmp(pab->filename, addrbook) == 0)
1096 break;
1099 if(i < as.n_addrbk)
1100 return(pab);
1102 return NULL;
1107 * Screen for selecting which addresses to Take to address book.
1109 * Args: ps -- Pine state
1110 * ta_list -- Screen is formed from this list of addresses
1111 * how_many_selected -- how many checked initially in ListMode
1112 * mode -- which mode to start in
1114 * Result: an address book may be updated
1115 * Returns -- 0 normally
1116 * 1 if it returns before redrawing screen
1119 takeaddr_screen(struct pine *ps, TA_S *ta_list, int how_many_selected,
1120 ScreenMode mode, TA_STATE_S **tas, char *command)
1122 UCS ch = 'x';
1123 int cmd, dline, give_warn_message, command_line;
1124 int km_popped = 0,
1125 directly_to_take = 0,
1126 ret = 0,
1127 done = 0;
1128 TA_S *current = NULL,
1129 *ctmp = NULL;
1130 TA_SCREEN_S screen;
1131 Pos cursor_pos;
1132 char *utf8str;
1133 struct key_menu *km;
1135 dprint((2, "- takeaddr_screen -\n"));
1137 command_line = -FOOTER_ROWS(ps); /* third line from the bottom */
1139 screen.current = screen.top_line = NULL;
1140 screen.mode = mode;
1142 if(ta_list == NULL){
1143 /* TRANSLATORS: something like
1144 No addresses to save, cancelled */
1145 q_status_message1(SM_INFO, 0, 2, "No addresses to %s, cancelled",
1146 command);
1147 return 1;
1150 current = first_sel_taline(ta_list);
1151 ps->mangled_screen = 1;
1152 ta_screen = &screen;
1154 if(is_talist_of_one(current)){
1155 directly_to_take++;
1156 screen.mode = SingleMode;
1158 else if(screen.mode == ListMode)
1159 q_status_message(SM_INFO, 0, 1,
1160 _("List mode: Use \"X\" to mark addresses to be included in list"));
1161 else
1162 q_status_message(SM_INFO, 0, 1,
1163 _("Single mode: Use \"P\" or \"N\" to select desired address"));
1165 while(!done){
1166 if(km_popped){
1167 km_popped--;
1168 if(km_popped == 0){
1169 clearfooter(ps);
1170 ps->mangled_body = 1;
1174 if(screen.mode == ListMode)
1175 ps->redrawer = takeaddr_screen_redrawer_list;
1176 else
1177 ps->redrawer = takeaddr_screen_redrawer_single;
1179 if(ps->mangled_screen){
1180 ps->mangled_header = 1;
1181 ps->mangled_footer = 1;
1182 ps->mangled_body = 1;
1183 ps->mangled_screen = 0;
1186 /*----------- Check for new mail -----------*/
1187 if(new_mail(0, NM_TIMING(ch), NM_STATUS_MSG | NM_DEFER_SORT) >= 0)
1188 ps->mangled_header = 1;
1190 #ifdef _WINDOWS
1191 mswin_beginupdate();
1192 #endif
1193 if(ps->mangled_header){
1194 char tbuf[40];
1196 snprintf(tbuf, sizeof(tbuf), "TAKE ADDRESS SCREEN (%s Mode)",
1197 (screen.mode == ListMode) ? "List"
1198 : "Single");
1199 tbuf[sizeof(tbuf)-1] = '\0';
1200 set_titlebar(tbuf, ps->mail_stream, ps->context_current,
1201 ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0,
1202 NULL);
1203 ps->mangled_header = 0;
1206 dline = update_takeaddr_screen(ps, current, &screen, &cursor_pos);
1207 if(F_OFF(F_SHOW_CURSOR, ps)){
1208 cursor_pos.row = ps->ttyo->screen_rows - FOOTER_ROWS(ps);
1209 cursor_pos.col = 0;
1212 /*---- This displays new mail notification, or errors ---*/
1213 if(km_popped){
1214 FOOTER_ROWS(ps_global) = 3;
1215 mark_status_unknown();
1218 display_message(ch);
1219 if(km_popped){
1220 FOOTER_ROWS(ps_global) = 1;
1221 mark_status_unknown();
1224 /*---- Redraw footer ----*/
1225 if(ps->mangled_footer){
1226 bitmap_t bitmap;
1228 if(km_popped){
1229 FOOTER_ROWS(ps) = 3;
1230 clearfooter(ps);
1233 setbitmap(bitmap);
1234 ps->mangled_footer = 0;
1236 km = (screen.mode == ListMode) ? &ta_keymenu_lm : &ta_keymenu_sm;
1238 menu_clear_binding(km, KEY_LEFT);
1239 menu_clear_binding(km, KEY_RIGHT);
1240 if(F_ON(F_ARROW_NAV, ps_global)){
1241 int cmd;
1243 if((cmd = menu_clear_binding(km, '<')) != MC_UNKNOWN){
1244 menu_add_binding(km, '<', cmd);
1245 menu_add_binding(km, KEY_LEFT, cmd);
1248 if((cmd = menu_clear_binding(km, '>')) != MC_UNKNOWN){
1249 menu_add_binding(km, '>', cmd);
1250 menu_add_binding(km, KEY_RIGHT, cmd);
1254 draw_keymenu(km, bitmap, ps->ttyo->screen_cols,
1255 1 - FOOTER_ROWS(ps_global), 0, FirstMenu);
1257 if(km_popped){
1258 FOOTER_ROWS(ps) = 1;
1259 mark_keymenu_dirty();
1263 #ifdef _WINDOWS
1264 mswin_endupdate();
1265 #endif
1266 /*------ Read the command from the keyboard ----*/
1267 MoveCursor(cursor_pos.row, cursor_pos.col);
1269 if(directly_to_take){ /* bypass this screen */
1270 cmd = MC_TAKE;
1271 blank_keymenu(ps_global->ttyo->screen_rows - 2, 0);
1273 else {
1274 #ifdef MOUSE
1275 mouse_in_content(KEY_MOUSE, -1, -1, 0, 0);
1276 register_mfunc(mouse_in_content, HEADER_ROWS(ps_global), 0,
1277 ps_global->ttyo->screen_rows - (FOOTER_ROWS(ps)+1),
1278 ps_global->ttyo->screen_cols);
1279 #endif
1281 #ifdef _WINDOWS
1282 mswin_setscrollcallback(ta_scroll_callback);
1283 #endif
1284 ch = READ_COMMAND(&utf8str);
1285 #ifdef MOUSE
1286 clear_mfunc(mouse_in_content);
1287 #endif
1289 #ifdef _WINDOWS
1290 mswin_setscrollcallback(NULL);
1291 #endif
1292 cmd = menu_command(ch, km);
1293 if (ta_screen->current)
1294 current = ta_screen->current;
1296 if(km_popped)
1297 switch(cmd){
1298 case MC_NONE :
1299 case MC_OTHER :
1300 case MC_RESIZE :
1301 case MC_REPAINT :
1302 km_popped++;
1303 break;
1305 default:
1306 clearfooter(ps);
1307 break;
1311 switch(cmd){
1312 case MC_HELP : /* help! */
1313 if(FOOTER_ROWS(ps_global) == 1 && km_popped == 0){
1314 km_popped = 2;
1315 ps_global->mangled_footer = 1;
1316 break;
1319 helper(h_takeaddr_screen, _("HELP FOR TAKE ADDRESS SCREEN"),
1320 HLPD_SIMPLE);
1321 ps->mangled_screen = 1;
1322 break;
1324 case MC_EXIT: /* exit takeaddr screen */
1325 q_status_message(SM_INFO, 0, 2, _("Address book addition cancelled"));
1326 ret = 1;
1327 done++;
1328 break;
1330 case MC_TAKE:
1331 if(ta_do_take(current, how_many_selected, command_line, tas,
1332 command))
1333 done++;
1334 else
1335 directly_to_take = 0;
1337 break;
1339 case MC_CHARDOWN : /* next list element */
1340 if((ctmp = next_sel_taline(current)) != NULL)
1341 current = ctmp;
1342 else
1343 q_status_message(SM_INFO, 0, 1, _("Already on last line."));
1345 break;
1347 case MC_CHARUP: /* previous list element */
1348 if((ctmp = pre_sel_taline(current)) != NULL)
1349 current = ctmp;
1350 else
1351 q_status_message(SM_INFO, 0, 1, _("Already on first line."));
1353 break;
1355 case MC_PAGEDN : /* page forward */
1356 give_warn_message = 1;
1357 while(dline++ < ps->ttyo->screen_rows - FOOTER_ROWS(ps)){
1358 if((ctmp = next_sel_taline(current)) != NULL){
1359 current = ctmp;
1360 give_warn_message = 0;
1362 else
1363 break;
1366 if(give_warn_message)
1367 q_status_message(SM_INFO, 0, 1, _("Already on last page."));
1369 break;
1371 case MC_PAGEUP : /* page backward */
1372 /* move to top of screen */
1373 give_warn_message = 1;
1374 while(dline-- > HEADER_ROWS(ps_global)){
1375 if((ctmp = pre_sel_taline(current)) != NULL){
1376 current = ctmp;
1377 give_warn_message = 0;
1379 else
1380 break;
1383 /* page back one screenful */
1384 while(++dline < ps->ttyo->screen_rows - FOOTER_ROWS(ps)){
1385 if((ctmp = pre_sel_taline(current)) != NULL){
1386 current = ctmp;
1387 give_warn_message = 0;
1389 else
1390 break;
1393 if(give_warn_message)
1394 q_status_message(SM_INFO, 0, 1, _("Already on first page."));
1396 break;
1398 case MC_WHEREIS : /* whereis */
1399 if((ctmp = whereis_taline(current)) != NULL)
1400 current = ctmp;
1402 ps->mangled_footer = 1;
1403 break;
1405 case KEY_SCRLTO:
1406 /* no op for now */
1407 break;
1409 #ifdef MOUSE
1410 case MC_MOUSE:
1412 MOUSEPRESS mp;
1414 mouse_get_last(NULL, &mp);
1415 mp.row -= HEADER_ROWS(ps_global);
1416 ctmp = screen.top_line;
1417 if(mp.doubleclick){
1418 if(screen.mode == SingleMode){
1419 if(ta_do_take(current, how_many_selected, command_line,
1420 tas, command))
1421 done++;
1422 else
1423 directly_to_take = 0;
1425 else{
1426 current->checked = !current->checked; /* flip it */
1427 how_many_selected += (current->checked ? 1 : -1);
1430 else{
1431 while(mp.row && ctmp != NULL){
1432 --mp.row;
1433 do ctmp = ctmp->next;
1434 while(ctmp != NULL && ctmp->skip_it && !ctmp->print);
1437 if(ctmp != NULL && !ctmp->skip_it)
1438 current = ctmp;
1441 break;
1442 #endif
1444 case MC_REPAINT :
1445 case MC_RESIZE :
1446 ClearScreen();
1447 ps->mangled_screen = 1;
1448 break;
1450 case MC_CHOICE : /* [UN]select this addr */
1451 current->checked = !current->checked; /* flip it */
1452 how_many_selected += (current->checked ? 1 : -1);
1453 break;
1455 case MC_SELALL : /* select all */
1456 how_many_selected = ta_mark_all(first_sel_taline(current));
1457 ps->mangled_body = 1;
1458 break;
1460 case MC_UNSELALL: /* unselect all */
1461 how_many_selected = ta_unmark_all(first_sel_taline(current));
1462 ps->mangled_body = 1;
1463 break;
1465 case MC_LISTMODE: /* switch to SingleMode */
1466 if(screen.mode == ListMode){
1467 screen.mode = SingleMode;
1468 q_status_message(SM_INFO, 0, 1,
1469 _("Single mode: Use \"P\" or \"N\" to select desired address"));
1471 else{
1472 screen.mode = ListMode;
1473 q_status_message(SM_INFO, 0, 1,
1474 _("List mode: Use \"X\" to mark addresses to be included in list"));
1476 if(how_many_selected <= 1){
1477 how_many_selected =
1478 ta_unmark_all(first_sel_taline(current));
1479 current->checked = 1;
1480 how_many_selected++;
1484 ps->mangled_screen = 1;
1485 break;
1488 case MC_NONE : /* simple timeout */
1489 break;
1492 /* Unbound (or not dealt with) keystroke */
1493 case MC_CHARRIGHT :
1494 case MC_CHARLEFT :
1495 case MC_GOTOBOL :
1496 case MC_GOTOEOL :
1497 case MC_UNKNOWN :
1498 default:
1499 bogus_command(ch, F_ON(F_USE_FK, ps) ? "F1" : "?");
1500 break;
1502 case MC_UTF8:
1503 bogus_utf8_command(utf8str, F_ON(F_USE_FK, ps) ? "F1" : "?");
1504 break;
1508 ps->mangled_screen = 1;
1510 return(ret);
1515 * Do what takeaddr_screen does except bypass the takeaddr_screen and
1516 * go directly to do_take.
1518 void
1519 takeaddr_bypass(struct pine *ps, TA_S *current, TA_STATE_S **tasp)
1521 TA_SCREEN_S screen; /* We have to fake out ta_do_take because */
1522 /* we're bypassing takeaddr_screen. */
1523 ta_screen = &screen;
1524 ta_screen->mode = SingleMode;
1525 current = first_sel_taline(current);
1526 (void) ta_do_take(current, 1, -FOOTER_ROWS(ps_global), tasp, _("save"));
1527 ps->mangled_screen = 1;
1535 ta_do_take(TA_S *current, int how_many_selected, int command_line,
1536 TA_STATE_S **tas, char *cmd)
1538 return((ta_screen->mode == ListMode)
1539 ? ta_take_marked_addrs(how_many_selected,
1540 first_sel_taline(current),
1541 command_line, tas, cmd)
1542 : ta_take_single_addr(current, command_line, tas, cmd));
1547 * WhereIs for TakeAddr screen.
1549 * Returns the line match is found in or NULL.
1551 TA_S *
1552 whereis_taline(TA_S *current)
1554 TA_S *p;
1555 int rc, found = 0, wrapped = 0, flags;
1556 char *result = NULL, buf[MAX_SEARCH+1], tmp[MAX_SEARCH+20];
1557 static char last[MAX_SEARCH+1];
1558 HelpType help;
1559 static ESCKEY_S ekey[] = {
1560 {0, 0, "", ""},
1561 {ctrl('Y'), 10, "^Y", N_("Top")},
1562 {ctrl('V'), 11, "^V", N_("Bottom")},
1563 {-1, 0, NULL, NULL}};
1565 if(!current)
1566 return NULL;
1568 /*--- get string ---*/
1569 buf[0] = '\0';
1570 snprintf(tmp, sizeof(tmp), _("Word to find %s%.*s%s: "),
1571 (last[0]) ? "[" : "",
1572 MAX_SEARCH, (last[0]) ? last : "", /* MAX_SEARCH == sizeof(tmp) - 20 */
1573 (last[0]) ? "]" : "");
1574 tmp[sizeof(tmp)-1] = '\0';
1575 help = NO_HELP;
1576 flags = OE_APPEND_CURRENT | OE_KEEP_TRAILING_SPACE;
1577 while(1){
1578 rc = optionally_enter(buf,-FOOTER_ROWS(ps_global),0,sizeof(buf),
1579 tmp,ekey,help,&flags);
1580 if(rc == 3)
1581 help = help == NO_HELP ? h_config_whereis : NO_HELP;
1582 else if(rc == 0 || rc == 1 || rc == 10 || rc == 11 || !buf[0]){
1583 if(rc == 0 && !buf[0] && last[0]){
1584 strncpy(buf, last, sizeof(buf)-1);
1585 buf[sizeof(buf)-1] = '\0';
1588 break;
1592 if(rc == 0 && buf[0]){
1593 p = current;
1594 while((p = next_taline(p)) != NULL)
1595 if(srchstr((char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf,
1596 SIZEOF_20KBUF, p->strvalue),
1597 buf)){
1598 found++;
1599 break;
1602 if(!found){
1603 p = first_taline(current);
1605 while(p != current)
1606 if(srchstr((char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf,
1607 SIZEOF_20KBUF, p->strvalue),
1608 buf)){
1609 found++;
1610 wrapped++;
1611 break;
1613 else
1614 p = next_taline(p);
1617 else if(rc == 10){
1618 current = first_sel_taline(current);
1619 result = _("Searched to top");
1621 else if(rc == 11){
1622 current = last_sel_taline(current);
1623 result = _("Searched to bottom");
1625 else{
1626 current = NULL;
1627 result = _("WhereIs cancelled");
1630 if(found){
1631 current = p;
1632 result = wrapped ? _("Search wrapped to beginning") : _("Word found");
1633 strncpy(last, buf, sizeof(last)-1);
1634 last[sizeof(last)-1] = '\0';
1637 q_status_message(SM_ORDER,0,3,result ? result : _("Word not found"));
1638 return(current);
1643 * Call the addrbook functions which add the checked addresses.
1645 * Args: how_many_selected -- how many addresses are checked
1646 * f_line -- the first ta line
1648 * Returns: 1 -- we're done, caller should return
1649 * 0 -- we're not done
1652 ta_take_marked_addrs(int how_many_selected, TA_S *f_line, int command_line,
1653 TA_STATE_S **tas, char *cmd)
1655 char **new_list;
1656 TA_S *p;
1658 if(how_many_selected == 0){
1659 q_status_message(SM_ORDER, 0, 4,
1660 _("No addresses marked for taking. Use ExitTake to leave TakeAddr screen"));
1661 return 0;
1664 if(how_many_selected == 1){
1665 for(p = f_line; p; p = next_sel_taline(p))
1666 if(p->checked && !p->skip_it)
1667 break;
1669 if(p)
1670 add_abook_entry(p,
1671 (p->nickname && p->nickname[0]) ? p->nickname : NULL,
1672 (p->fullname && p->fullname[0]) ? p->fullname : NULL,
1673 (p->fcc && p->fcc[0]) ? p->fcc : NULL,
1674 (p->comment && p->comment[0]) ? p->comment : NULL,
1675 command_line, tas, cmd);
1677 else{
1678 new_list = list_of_checked(f_line);
1679 for(p = f_line; p; p = next_sel_taline(p))
1680 if(p->checked && !p->skip_it)
1681 break;
1683 take_to_addrbooks_frontend(new_list, p ? p->nickname : NULL,
1684 p ? p->fullname : NULL, NULL, p ? p->fcc : NULL,
1685 p ? p->comment : NULL, command_line, tas, cmd);
1686 free_list_array(&new_list);
1689 return 1;
1694 ta_take_single_addr(TA_S *cur, int command_line, TA_STATE_S **tas, char *cmd)
1696 add_abook_entry(cur,
1697 (cur->nickname && cur->nickname[0]) ? cur->nickname : NULL,
1698 (cur->fullname && cur->fullname[0]) ? cur->fullname : NULL,
1699 (cur->fcc && cur->fcc[0]) ? cur->fcc : NULL,
1700 (cur->comment && cur->comment[0]) ? cur->comment : NULL,
1701 command_line, tas, cmd);
1703 return 1;
1708 * Manage display of the Take Address screen.
1710 * Args: ps -- pine state
1711 * current -- the current TA line
1712 * screen -- the TA screen
1713 * cursor_pos -- return good cursor position here
1716 update_takeaddr_screen(struct pine *ps, TA_S *current, TA_SCREEN_S *screen, Pos *cursor_pos)
1718 int dline;
1719 TA_S *top_line,
1720 *ctmp;
1721 int longest, i, j;
1722 char buf1[6*MAX_SCREEN_COLS + 30];
1723 char buf2[6*MAX_SCREEN_COLS + 30];
1724 char *p, *q;
1725 int screen_width = ps->ttyo->screen_cols;
1726 Pos cpos;
1728 cpos.row = HEADER_ROWS(ps); /* default return value */
1730 /* calculate top line of display */
1731 dline = 0;
1732 top_line = 0;
1734 if (ta_screen->top_line){
1735 for(dline = 0, ctmp = ta_screen->top_line;
1736 ctmp && ctmp != current; ctmp = next_taline(ctmp))
1737 dline++;
1739 if (ctmp && (dline < ps->ttyo->screen_rows - HEADER_ROWS(ps)
1740 - FOOTER_ROWS(ps)))
1741 top_line = ta_screen->top_line;
1744 if (!top_line){
1745 dline = 0;
1746 ctmp = top_line = first_taline(current);
1748 if(((dline++) % (ps->ttyo->screen_rows - HEADER_ROWS(ps)
1749 - FOOTER_ROWS(ps))) == 0)
1750 top_line = ctmp;
1751 while(ctmp != current && (ctmp = next_taline(ctmp)));
1754 #ifdef _WINDOWS
1756 * Figure out how far down the top line is from the top and how many
1757 * total lines there are. Dumb to loop every time thru, but
1758 * there aren't that many lines, and it's cheaper than rewriting things
1759 * to maintain a line count in each structure...
1761 for(dline = 0, ctmp = pre_taline(top_line); ctmp; ctmp = pre_taline(ctmp))
1762 dline++;
1764 scroll_setpos(dline);
1766 for(ctmp = next_taline(top_line); ctmp ; ctmp = next_taline(ctmp))
1767 dline++;
1769 scroll_setrange(ps->ttyo->screen_rows - FOOTER_ROWS(ps) - HEADER_ROWS(ps),
1770 dline);
1771 #endif
1774 /* mangled body or new page, force redraw */
1775 if(ps->mangled_body || screen->top_line != top_line)
1776 screen->current = NULL;
1778 /* find width of longest line for nicer formatting */
1779 longest = 0;
1780 for(ctmp = first_taline(top_line); ctmp; ctmp = next_taline(ctmp)){
1781 int width;
1783 if(ctmp
1784 && !ctmp->print
1785 && ctmp->strvalue
1786 && longest < (width = utf8_width((char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf,
1787 SIZEOF_20KBUF, ctmp->strvalue))))
1788 longest = width;
1791 #define LENGTH_OF_THAT_STRING 5 /* "[X] " */
1792 longest = MIN(longest, ps->ttyo->screen_cols);
1794 /* loop thru painting what's needed */
1795 for(dline = 0, ctmp = top_line;
1796 dline < ps->ttyo->screen_rows - FOOTER_ROWS(ps) - HEADER_ROWS(ps);
1797 dline++, ctmp = next_taline(ctmp)){
1800 * only fall thru painting if something needs painting...
1802 if(!ctmp || !screen->current || ctmp == screen->current ||
1803 ctmp == top_line || ctmp == current){
1804 ClearLine(dline + HEADER_ROWS(ps));
1805 if(!ctmp || !ctmp->strvalue)
1806 continue;
1809 p = buf1;
1810 if(ctmp == current){
1811 cpos.row = dline + HEADER_ROWS(ps); /* col set below */
1812 StartInverse();
1815 if(ctmp->print)
1816 j = 0;
1817 else
1818 j = LENGTH_OF_THAT_STRING;
1821 * Copy the value to a temp buffer expanding tabs, and
1822 * making sure not to write beyond screen right...
1824 q = (char *) rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf,
1825 SIZEOF_20KBUF, ctmp->strvalue);
1827 for(i = 0; q[i] && j < ps->ttyo->screen_cols && p-buf1 < sizeof(buf1); i++){
1828 if(q[i] == ctrl('I')){
1830 *p++ = SPACE;
1831 while(j < ps->ttyo->screen_cols && ((++j)&0x07) && p-buf1 < sizeof(buf1));
1834 else{
1835 *p++ = q[i];
1836 j++;
1840 if(p-buf1 < sizeof(buf1))
1841 *p = '\0';
1843 if(utf8_width(buf1) < longest){
1844 (void) utf8_pad_to_width(buf2, buf1, sizeof(buf2), longest, 1);
1845 /* it's expected to be in buf1 below */
1846 strncpy(buf1, buf2, sizeof(buf1));
1847 buf1[sizeof(buf1)-1] = '\0';
1850 /* mark lines which have check marks */
1851 if(ctmp == current){
1852 if(screen->mode == ListMode){
1853 snprintf(buf2, sizeof(buf2), "[%c] %s", ctmp->checked ? 'X' : SPACE, buf1);
1854 buf2[sizeof(buf2)-1] = '\0';
1855 cpos.col = 1; /* position on the X */
1857 else{
1858 snprintf(buf2, sizeof(buf2), " %s", buf1);
1859 buf2[sizeof(buf2)-1] = '\0';
1860 cpos.col = 5; /* 5 spaces before text */
1863 else{
1864 if(ctmp->print){
1865 int width, actual_width;
1866 size_t len;
1869 * In buf2 make ------string--------
1870 * which reaches all the way across the screen. String will
1871 * already have a leading and trailing space.
1873 width = utf8_width(buf1);
1875 if(width > screen_width){
1876 actual_width = utf8_truncate(buf1, screen_width);
1877 /* it might be 1 less */
1878 if(actual_width < screen_width && (len=strlen(buf1))+1 < sizeof(buf1)){
1879 buf1[len] = SPACE;
1880 buf1[len+1] = '\0';
1883 else{
1884 snprintf(buf2, sizeof(buf2), "%s%s",
1885 repeat_char((screen_width-width)/2, '-'), buf1);
1886 buf2[sizeof(buf2)-1] = '\0';
1887 len = strlen(buf2);
1888 width = utf8_width(buf2);
1889 snprintf(buf2+len, sizeof(buf2)-len, "%s",
1890 repeat_char(screen_width-width, '-'));
1891 buf2[sizeof(buf2)-1] = '\0';
1894 else{
1895 if(screen->mode == ListMode) /* 6*MAX_SCREEN_COLS + 24 = sizeof(buf2)-6 */
1896 snprintf(buf2, sizeof(buf2), "[%c] %.*s", ctmp->checked ? 'X' : SPACE,
1897 6*MAX_SCREEN_COLS + 24, buf1);
1898 else
1899 snprintf(buf2, sizeof(buf2), " %.*s", 6*MAX_SCREEN_COLS+24, buf1);
1901 buf2[sizeof(buf2)-1] = '\0';
1905 PutLine0(dline + HEADER_ROWS(ps), 0, buf2);
1907 if(ctmp == current)
1908 EndInverse();
1911 ps->mangled_body = 0;
1912 screen->top_line = top_line;
1913 screen->current = current;
1914 if(cursor_pos)
1915 *cursor_pos = cpos;
1917 return(cpos.row);
1921 void
1922 takeaddr_screen_redrawer_list(void)
1924 ps_global->mangled_body = 1;
1925 (void)update_takeaddr_screen(ps_global, ta_screen->current, ta_screen,
1926 (Pos *)NULL);
1930 void
1931 takeaddr_screen_redrawer_single(void)
1933 ps_global->mangled_body = 1;
1934 (void)update_takeaddr_screen(ps_global, ta_screen->current, ta_screen,
1935 (Pos *)NULL);
1939 /* jpf work in progress
1940 * Execute command to take addresses out of message and put in the address book
1942 * Args: ps -- pine state
1943 * msgmap -- the MessageMap
1944 * agg -- this is aggregate operation if set
1946 * Result: The entry is added to an address book.
1949 cmd_take_addr(struct pine *ps, MSGNO_S *msgmap, int agg)
1951 TA_S *ta_list = NULL;
1952 int how_many_selected = 0, rtype;
1954 /* Ask user what kind of Take they want to do */
1955 if(!agg && F_ON(F_ENABLE_ROLE_TAKE, ps)){
1956 rtype = rule_setup_type(ps,
1957 RS_RULES |
1958 ((mn_get_total(msgmap) > 0)
1959 ? (F_ON(F_ENABLE_TAKE_EXPORT, ps)
1960 ? (RS_INCADDR | RS_INCEXP)
1961 : RS_INCADDR)
1962 : RS_NONE),
1963 "Take to : ");
1965 else if(F_ON(F_ENABLE_TAKE_EXPORT, ps) && mn_get_total(msgmap) > 0)
1966 rtype = rule_setup_type(ps, RS_INCADDR | RS_INCEXP, "Take to : ");
1967 else
1968 rtype = 'a';
1970 if(rtype == 'x' || rtype == 'Z'){
1971 if(rtype == 'x')
1972 cmd_cancelled(NULL);
1973 else if(rtype == 'Z')
1974 q_status_message(SM_ORDER | SM_DING, 3, 5,
1975 "Try turning on color with the Setup/Kolor command.");
1976 return -1;
1979 ps->mangled_footer = 1;
1981 if(rtype > 0)
1982 switch(rtype){
1983 case 'e':
1985 LINES_TO_TAKE *lines_to_take = NULL;
1987 rtype = set_up_takeaddr('e', ps, msgmap, &ta_list, &how_many_selected,
1988 agg ? TA_AGG : 0, NULL);
1990 if(rtype >= 0){
1991 if(convert_ta_to_lines(ta_list, &lines_to_take)){
1992 while(lines_to_take && lines_to_take->prev)
1993 lines_to_take = lines_to_take->prev;
1995 take_to_export(ps, lines_to_take);
1997 free_ltlines(&lines_to_take);
1999 else
2000 q_status_message(SM_ORDER, 3, 4, _("Can't find anything to export"));
2004 break;
2006 case 'r':
2007 case 's':
2008 case 'i':
2009 case 'f':
2010 case 'o':
2011 case 'c':
2012 case 'x':
2013 role_take(ps, msgmap, rtype);
2014 break;
2016 case 'a':
2017 rtype = set_up_takeaddr('a', ps, msgmap, &ta_list, &how_many_selected,
2018 agg ? TA_AGG : 0, attached_addr_handler);
2019 if(rtype >= 0){
2020 (void) takeaddr_screen(ps, ta_list, how_many_selected,
2021 agg ? ListMode : SingleMode,
2022 NULL, _("take"));
2025 break;
2027 default:
2028 break;
2031 /* clean up */
2032 free_talines(&ta_list);
2033 env_for_pico_callback = NULL;
2034 body_for_pico_callback = NULL;
2036 return(rtype >= 0 ? 1 : 0);
2041 attached_addr_handler(TA_S *current, int added)
2043 char prompt[200];
2044 int command_line = -FOOTER_ROWS(ps_global);
2046 snprintf(prompt, sizeof(prompt),
2047 "Take %d entries from attachment to addrbook all at once ",
2048 added);
2049 switch(want_to(prompt, 'n', 'x', NO_HELP, WT_NORM)){
2050 case 'y':
2051 if(take_without_edit(current, added, command_line, NULL, "take") >= 0)
2052 return(0); /* all taken care of */
2053 else
2054 return(-1); /* problem */
2056 case 'x':
2057 cmd_cancelled("Take");
2058 return(-1); /* problem */
2060 default:
2061 return(1); /* proceed */
2067 take_without_edit(TA_S *ta_list, int num_in_list, int command_line, TA_STATE_S **tas, char *cmd)
2069 #define OURTMPBUFLEN 200
2070 PerAddrBook *pab_dst;
2071 SAVE_STATE_S state; /* For saving state of addrbooks temporarily */
2072 int rc, total_to_copy;
2073 int how_many_dups = 0, how_many_to_copy = 0, skip_dups = 0;
2074 int ret = 0;
2075 int err = 0, need_write = 0, we_cancel = 0;
2076 adrbk_cntr_t new_entry_num;
2077 char warn[2][MAX_NICKNAME+1];
2078 char tmp[OURTMPBUFLEN];
2079 TA_S *current;
2080 SWOOP_S *swoop_list = NULL, *sw;
2082 dprint((2, "\n - take_without_edit(%d) - \n",
2083 num_in_list));
2085 /* move to beginning of the list */
2086 if(ta_list)
2087 while(ta_list->prev)
2088 ta_list = ta_list->prev;
2090 pab_dst = setup_for_addrbook_add(&state, command_line, cmd);
2091 if(!pab_dst)
2092 goto get_out;
2094 swoop_list = (SWOOP_S *)fs_get((num_in_list+1) * sizeof(SWOOP_S));
2095 memset((void *)swoop_list, 0, (num_in_list+1) * sizeof(SWOOP_S));
2096 sw = swoop_list;
2099 * Look through all the vcards for those with nicknames already
2100 * existing in the destination abook (dups) and build a list of
2101 * entries to be acted on.
2103 for(current = ta_list; current; current = current->next){
2104 adrbk_cntr_t dst_enum;
2106 if(current->skip_it)
2107 continue;
2109 /* check to see if this nickname already exists in the dest abook */
2110 if(current->nickname && current->nickname[0]){
2111 AdrBk_Entry *abe;
2113 current->checked = 0;
2114 abe = adrbk_lookup_by_nick(pab_dst->address_book,
2115 current->nickname, &dst_enum);
2117 * This nickname already exists.
2119 if(abe){
2120 sw->dup = 1;
2121 sw->dst_enum = dst_enum;
2122 if(how_many_dups < 2){
2123 strncpy(warn[how_many_dups], current->nickname, MAX_NICKNAME);
2124 warn[how_many_dups][MAX_NICKNAME] = '\0';
2127 how_many_dups++;
2131 sw->ta = current;
2132 sw++;
2133 how_many_to_copy++;
2137 * If there are some nicknames which already exist in the selected
2138 * abook, ask user what to do.
2140 if(how_many_dups > 0){
2141 if(how_many_dups == 1){
2142 if(how_many_to_copy == 1 && num_in_list == 1){
2143 ret = 'T'; /* use Take */
2144 if(tas && *tas){
2145 (*tas)->state = state;
2146 (*tas)->pab = pab_dst;
2149 goto get_out;
2151 else{
2152 snprintf(tmp, sizeof(tmp),
2153 "Entry with nickname \"%.*s\" already exists, replace ",
2154 OURTMPBUFLEN-50, warn[0]);
2157 else if(how_many_dups == 2)
2158 snprintf(tmp, sizeof(tmp),
2159 "Nicknames \"%.*s\" and \"%.*s\" already exist, replace ",
2160 (OURTMPBUFLEN-50)/2, warn[0], (OURTMPBUFLEN-50)/2, warn[1]);
2161 else
2162 snprintf(tmp, sizeof(tmp), "%d of the nicknames already exist, replace ",
2163 how_many_dups);
2165 switch(want_to(tmp, 'n', 'x', h_ab_copy_dups, WT_NORM)){
2166 case 'n':
2167 skip_dups++;
2168 break;
2170 case 'y':
2171 break;
2173 case 'x':
2174 err++;
2175 goto get_out;
2180 * Because the deletes happen immediately we have to delete from high
2181 * entry number towards lower entry numbers so that we are deleting
2182 * the correct entries. In order to do that we'll sort the swoop_list
2183 * to give us a safe order.
2185 if(!skip_dups && how_many_dups > 1)
2186 qsort((qsort_t *)swoop_list, (size_t)num_in_list, sizeof(*swoop_list),
2187 cmp_swoop_list);
2189 we_cancel = busy_cue("Saving addrbook entries", NULL, 0);
2190 total_to_copy = how_many_to_copy - (skip_dups ? how_many_dups : 0);
2193 * Add the list of entries to the destination abook.
2195 for(sw = swoop_list; sw && sw->ta; sw++){
2196 Tag tag;
2197 char abuf[MAX_ADDRESS + 1];
2198 int count_of_addrs;
2200 if(skip_dups && sw->dup)
2201 continue;
2204 * Delete existing dups and replace them.
2206 if(sw->dup){
2208 /* delete the existing entry */
2209 rc = 0;
2210 if(adrbk_delete(pab_dst->address_book,
2211 (a_c_arg_t)sw->dst_enum, 1, 0, 0, 0) == 0){
2212 need_write++;
2214 else{
2215 q_status_message2(SM_ORDER | SM_DING, 3, 5,
2216 "Error replacing entry in %.200s: %.200s",
2217 pab_dst->abnick,
2218 error_description(errno));
2219 err++;
2220 goto get_out;
2225 * We need to count the number of addresses in this entry in order
2226 * to tell the adrbk routines if it is a List or a Single, and in
2227 * order to pass the right stuff to be added.
2229 count_of_addrs = count_addrs(sw->ta->addr);
2230 tag = (count_of_addrs > 1) ? List : Single;
2231 if(tag == Single){
2232 if(sw->ta->addr->mailbox && sw->ta->addr->mailbox[0]){
2233 char *scratch, *p, *t, *u;
2234 unsigned long l;
2235 RFC822BUFFER rbuf;
2236 size_t es;
2238 es = est_size(sw->ta->addr);
2239 scratch = (char *) fs_get(es * sizeof(char));
2240 scratch[0] = '\0';
2241 rbuf.f = dummy_soutr;
2242 rbuf.s = NULL;
2243 rbuf.beg = scratch;
2244 rbuf.cur = scratch;
2245 rbuf.end = scratch+es-1;
2246 rfc822_output_address_list(&rbuf, sw->ta->addr, 0L, NULL);
2247 *rbuf.cur = '\0';
2248 if((p = srchstr(scratch, "@" RAWFIELD)) != NULL){
2249 for(t = p; ; t--)
2250 if(*t == '&'){ /* find "leading" token */
2251 *t++ = ' '; /* replace token */
2252 *p = '\0'; /* tie off string */
2253 u = (char *)rfc822_base64((unsigned char *)t,
2254 (unsigned long)strlen(t), &l);
2255 *p = '@'; /* restore 'p' */
2256 rplstr(p, es-(p-scratch), 12, ""); /* clear special token */
2257 rplstr(t, es-(t-scratch), strlen(t), u); /* Null u is handled */
2258 if(u)
2259 fs_give((void **)&u);
2261 else if(t == scratch)
2262 break;
2265 strncpy(abuf, scratch, sizeof(abuf)-1);
2266 abuf[sizeof(abuf)-1] = '\0';
2268 if(scratch)
2269 fs_give((void **)&scratch);
2271 else
2272 abuf[0] = '\0';
2277 * Now we have a clean slate to work with.
2279 if(total_to_copy <= 1)
2280 rc = adrbk_add(pab_dst->address_book,
2281 NO_NEXT,
2282 sw->ta->nickname,
2283 sw->ta->fullname,
2284 tag == Single ? abuf : NULL,
2285 sw->ta->fcc,
2286 sw->ta->comment,
2287 tag,
2288 &new_entry_num,
2289 (int *)NULL,
2293 else
2294 rc = adrbk_append(pab_dst->address_book,
2295 sw->ta->nickname,
2296 sw->ta->fullname,
2297 tag == Single ? abuf : NULL,
2298 sw->ta->fcc,
2299 sw->ta->comment,
2300 tag,
2301 &new_entry_num);
2303 if(rc == 0)
2304 need_write++;
2307 * If the entry we copied is a list, we also have to add
2308 * the list members to the copy.
2310 if(rc == 0 && tag == List){
2311 int i, save_sort_rule;
2312 ADDRESS *a, *save_next;
2313 char **list;
2315 list = (char **)fs_get((count_of_addrs + 1) * sizeof(char *));
2316 memset((void *)list, 0, (count_of_addrs+1) * sizeof(char *));
2317 i = 0;
2318 for(a = sw->ta->addr; a; a = a->next){
2319 save_next = a->next;
2320 a->next = NULL;
2322 if(a->mailbox && a->mailbox[0]){
2323 char *scratch, *p, *t, *u;
2324 unsigned long l;
2325 RFC822BUFFER rbuf;
2326 size_t es;
2328 es = est_size(a);
2329 scratch = (char *) fs_get(es * sizeof(char));
2330 scratch[0] = '\0';
2331 rbuf.f = dummy_soutr;
2332 rbuf.s = NULL;
2333 rbuf.beg = scratch;
2334 rbuf.cur = scratch;
2335 rbuf.end = scratch+es-1;
2336 rfc822_output_address_list(&rbuf, a, 0L, NULL);
2337 *rbuf.cur = '\0';
2338 if((p = srchstr(scratch, "@" RAWFIELD)) != NULL){
2339 for(t = p; ; t--)
2340 if(*t == '&'){ /* find "leading" token */
2341 *t++ = ' '; /* replace token */
2342 *p = '\0'; /* tie off string */
2343 u = (char *)rfc822_base64((unsigned char *)t,
2344 (unsigned long)strlen(t), &l);
2345 *p = '@'; /* restore 'p' */
2346 rplstr(p, es-(p-scratch), 12, ""); /* clear special token */
2347 rplstr(t, es-(t-scratch), strlen(t), u); /* Null u is handled */
2348 if(u)
2349 fs_give((void **)&u);
2351 else if(t == scratch)
2352 break;
2355 strncpy(abuf, scratch, sizeof(abuf)-1);
2356 abuf[sizeof(abuf)-1] = '\0';
2358 if(scratch)
2359 fs_give((void **)&scratch);
2361 else
2362 abuf[0] = '\0';
2364 list[i++] = cpystr(abuf);
2365 a->next = save_next;
2369 * We want it to copy the list in the exact order
2370 * without sorting it.
2372 save_sort_rule = pab_dst->address_book->sort_rule;
2373 pab_dst->address_book->sort_rule = AB_SORT_RULE_NONE;
2375 rc = adrbk_nlistadd(pab_dst->address_book,
2376 (a_c_arg_t)new_entry_num, NULL, NULL,
2377 list, 0, 0, 0);
2379 pab_dst->address_book->sort_rule = save_sort_rule;
2380 free_list_array(&list);
2383 if(rc != 0){
2384 q_status_message1(SM_ORDER | SM_DING, 3, 5,
2385 "Error saving: %.200s",
2386 error_description(errno));
2387 err++;
2388 goto get_out;
2392 if(need_write){
2393 int sort_happened = 0;
2395 if(adrbk_write(pab_dst->address_book, 0, NULL, &sort_happened, 0, 1)){
2396 err++;
2397 goto get_out;
2400 if(sort_happened)
2401 ps_global->mangled_screen = 1;
2404 get_out:
2405 if(we_cancel)
2406 cancel_busy_cue(1);
2408 if(!ret)
2409 restore_state(&state);
2411 if(swoop_list)
2412 fs_give((void **)&swoop_list);
2414 ps_global->mangled_footer = 1;
2416 if(err){
2417 #define CAPCMDLEN 50
2418 char capcmd[CAPCMDLEN];
2420 ret = -1;
2421 snprintf(capcmd, sizeof(capcmd),
2422 "%c%.*s",
2423 islower((unsigned char)(*cmd)) ? toupper((unsigned char)*cmd)
2424 : *cmd,
2425 CAPCMDLEN-2, cmd+1);
2426 if(need_write)
2427 q_status_message1(SM_ORDER | SM_DING, 3, 4,
2428 "%.200s only partially completed", capcmd);
2429 else
2430 cmd_cancelled(capcmd);
2432 else if(ret != 'T' && total_to_copy > 0){
2434 ret = 1;
2435 snprintf(tmp, sizeof(tmp), "Saved %d %s to \"%.*s\"",
2436 total_to_copy,
2437 (total_to_copy > 1) ? "entries" : "entry",
2438 OURTMPBUFLEN-30, pab_dst->abnick);
2439 q_status_message(SM_ORDER, 4, 4, tmp);
2442 return(ret);
2447 * Special case interface to allow a more interactive Save in the case where
2448 * the user seems to be wanting to save an exact copy of an existing entry.
2449 * For example, they might be trying to save a copy of a list with the intention
2450 * of changing it a little bit. The regular save doesn't allow this, since no
2451 * editing takes place, but this version plops them into the address book
2452 * editor.
2454 void
2455 take_this_one_entry(struct pine *ps, TA_STATE_S **tasp, AdrBk *abook, long int cur_line)
2457 AdrBk_Entry *abe;
2458 AddrScrn_Disp *dl;
2459 char *fcc = NULL, *comment = NULL, *fullname = NULL,
2460 *nickname = NULL;
2461 ADDRESS *addr;
2462 int how_many_selected;
2463 TA_S *current = NULL;
2465 dl = dlist(cur_line);
2466 abe = ae(cur_line);
2467 if(!abe){
2468 q_status_message(SM_ORDER, 0, 4, _("Nothing to save, cancelled"));
2469 return;
2472 if(dl->type == ListHead || dl->type == Simple){
2473 fcc = (abe->fcc && abe->fcc[0]) ? abe->fcc : NULL;
2474 comment = (abe->extra && abe->extra[0]) ? abe->extra : NULL;
2475 fullname = (abe->fullname && abe->fullname[0]) ? abe->fullname : NULL;
2476 nickname = (abe->nickname && abe->nickname[0]) ? abe->nickname : NULL;
2479 addr = abe_to_address(abe, dl, abook, &how_many_selected);
2480 if(!addr){
2481 addr = mail_newaddr();
2482 addr->host = cpystr("");
2483 addr->mailbox = cpystr("");
2486 switch(abe->tag){
2487 case Single:
2488 #ifdef ENABLE_LDAP
2490 * Special case. When user is saving an entry with a runtime
2491 * ldap lookup address, they may be doing it because the lookup
2492 * has become stale. Give them a way to get the old address out
2493 * of the lookup entry so they can save that, instead.
2495 if(!addr->personal && !strncmp(addr->mailbox, RUN_LDAP, LEN_RL)){
2496 LDAP_SERV_S *info = NULL;
2497 int i = 'l';
2498 static ESCKEY_S backup_or_ldap[] = {
2499 {'b', 'b', "B", N_("Backup")},
2500 {'l', 'l', "L", N_("LDAP")},
2501 {-1, 0, NULL, NULL}};
2503 info = break_up_ldap_server(addr->mailbox + LEN_RL);
2504 if(info && info->mail && *info->mail)
2505 i = radio_buttons(_("Copy backup address or retain LDAP search criteria ? "),
2506 -FOOTER_ROWS(ps_global), backup_or_ldap,
2507 'b', 'x',
2508 h_ab_backup_or_ldap, RB_NORM);
2510 if(i == 'b'){
2511 ADDRESS *a = NULL;
2513 rfc822_parse_adrlist(&a, info->mail, fakedomain);
2515 if(a){
2516 if(addr->mailbox)
2517 fs_give((void **)&addr->mailbox);
2518 if(addr->host)
2519 fs_give((void **)&addr->host);
2521 addr->mailbox = a->mailbox;
2522 a->mailbox = NULL;
2523 addr->host = a->host;
2524 a->host = NULL;
2525 mail_free_address(&a);
2529 if(info)
2530 free_ldap_server_info(&info);
2532 #endif /* ENABLE_LDAP */
2533 current = fill_in_ta(&current, addr, 0, (char *)NULL);
2534 break;
2536 case List:
2538 * The empty string for the last argument is significant. Fill_in_ta
2539 * copies the whole adrlist into a single TA if there is a print
2540 * string.
2542 if(dl->type == ListHead)
2543 current = fill_in_ta(&current, addr, 1, "");
2544 else
2545 current = fill_in_ta(&current, addr, 0, (char *)NULL);
2547 break;
2549 default:
2550 dprint((1,
2551 "default case in take_this_one_entry, shouldn't happen\n"));
2552 return;
2555 if(current->strvalue && !strcmp(current->strvalue, "@")){
2556 fs_give((void **)&current->strvalue);
2557 if(fullname && fullname[0])
2558 current->strvalue = cpystr(fullname);
2559 else if(nickname && nickname[0])
2560 current->strvalue = cpystr(nickname);
2561 else
2562 current->strvalue = cpystr("?");
2564 convert_possibly_encoded_str_to_utf8(&current->strvalue);
2567 if(addr)
2568 mail_free_address(&addr);
2570 if(current){
2571 current = first_sel_taline(current);
2572 if(fullname && *fullname){
2573 current->fullname = cpystr(fullname);
2574 convert_possibly_encoded_str_to_utf8(&current->fullname);
2577 if(fcc && *fcc){
2578 current->fcc = cpystr(fcc);
2579 convert_possibly_encoded_str_to_utf8(&current->fcc);
2582 if(comment && *comment){
2583 current->comment = cpystr(comment);
2584 convert_possibly_encoded_str_to_utf8(&current->comment);
2587 if(nickname && *nickname){
2588 current->nickname = cpystr(nickname);
2589 convert_possibly_encoded_str_to_utf8(&current->nickname);
2592 takeaddr_bypass(ps, current, tasp);
2594 else
2595 q_status_message(SM_ORDER, 0, 4, _("Nothing to save, cancelled"));
2597 free_talines(&current);
2602 * Execute command to save addresses out of vcard attachment.
2604 void
2605 save_vcard_att(struct pine *ps, int qline, long int msgno, ATTACH_S *a)
2607 int how_many_selected, j;
2608 TA_S *current = NULL;
2609 TA_STATE_S tas, *tasp;
2612 dprint((2, "\n - saving vcard attachment - \n"));
2614 j = radio_buttons(_("Save to address book or Export to filesystem ? "),
2615 qline, save_or_export, 's', 'x',
2616 h_ab_save_exp, RB_NORM|RB_SEQ_SENSITIVE);
2618 switch(j){
2619 case 'x':
2620 q_status_message(SM_INFO, 0, 2, _("Address book save cancelled"));
2621 return;
2623 case 'e':
2624 export_vcard_att(ps, qline, msgno, a);
2625 return;
2627 case 's':
2628 break;
2630 default:
2631 q_status_message(SM_ORDER, 3, 3, "can't happen in save_vcard_att");
2632 return;
2635 dprint((2, "\n - saving attachment into address book - \n"));
2636 ps->mangled_footer = 1;
2637 current = NULL;
2638 how_many_selected = process_vcard_atts(ps->mail_stream, msgno, NULL,
2639 a->body, a->number, &current);
2640 if(how_many_selected > 0){
2641 tas.pab = NULL;
2642 tasp = &tas;
2643 if(how_many_selected == 1){
2644 takeaddr_bypass(ps, current, NULL);
2646 else if(take_without_edit(current, how_many_selected, qline,
2647 &tasp, "save") == 'T'){
2649 * Eliminate dups.
2651 how_many_selected -=
2652 eliminate_dups_but_not_us(first_sel_taline(current));
2654 (void)takeaddr_screen(ps, current, how_many_selected, SingleMode,
2655 &tasp, _("save"));
2658 * If takeaddr_screen or its children didn't do this for us,
2659 * we do it here.
2661 if(tas.pab)
2662 restore_state(&(tas.state));
2665 else if(how_many_selected == 0)
2666 q_status_message(SM_ORDER, 0, 3,
2667 _("Save cancelled: no entries in attachment"));
2669 free_talines(&current);
2674 * Execute command to export vcard attachment.
2676 void
2677 export_vcard_att(struct pine *ps, int qline, long int msgno, ATTACH_S *a)
2679 int how_many_selected, i;
2680 TA_S *current;
2681 STORE_S *srcstore = NULL;
2682 SourceType srctype;
2683 static ESCKEY_S vcard_or_addresses[] = {
2684 {'a', 'a', "A", N_("Address List")},
2685 {'v', 'v', "V", N_("VCard")},
2686 {-1, 0, NULL, NULL}};
2688 if(ps->restricted){
2689 q_status_message(SM_ORDER, 0, 3,
2690 "Alpine demo can't export addresses to files");
2691 return;
2694 dprint((2, "\n - exporting vcard attachment - \n"));
2696 i = radio_buttons(_("Export list of addresses or vCard text ? "),
2697 qline, vcard_or_addresses, 'a', 'x',
2698 h_ab_export_vcard, RB_NORM|RB_SEQ_SENSITIVE);
2700 switch(i){
2701 case 'x':
2702 q_status_message(SM_INFO, 0, 2, _("Address book export cancelled"));
2703 return;
2705 case 'a':
2706 break;
2708 case 'v':
2709 write_attachment(qline, msgno, a, "EXPORT");
2710 return;
2712 default:
2713 q_status_message(SM_ORDER, 3, 3, _("can't happen in export_vcard_att"));
2714 return;
2717 ps->mangled_footer = 1;
2718 current = NULL;
2719 how_many_selected = process_vcard_atts(ps->mail_stream, msgno, NULL,
2720 a->body, a->number, &current);
2722 * Run through all of the list and run through
2723 * the addresses in each ta->addr, writing them into a storage object.
2724 * Then export to filesystem.
2726 srctype = CharStar;
2727 if(how_many_selected > 0 &&
2728 (srcstore = so_get(srctype, NULL, EDIT_ACCESS)) != NULL){
2729 ADDRESS *aa, *bb;
2730 int are_some = 0;
2732 for(current = first_taline(current);
2733 current;
2734 current = next_taline(current)){
2736 for(aa = current->addr; aa; aa = aa->next){
2737 bb = aa->next;
2738 aa->next = NULL;
2739 so_puts(srcstore, addr_list_string(aa, NULL, 0));
2740 are_some++;
2741 so_puts(srcstore, "\n");
2742 aa->next = bb;
2746 if(are_some)
2747 simple_export(ps, so_text(srcstore), srctype, "addresses", NULL);
2748 else
2749 q_status_message(SM_ORDER, 0, 3, _("No addresses to export"));
2751 so_give(&srcstore);
2753 else{
2754 if(how_many_selected == 0)
2755 q_status_message(SM_ORDER, 0, 3, _("Nothing to export"));
2756 else
2757 q_status_message(SM_ORDER,0,2, _("Error allocating space"));
2762 void
2763 take_to_export(struct pine *ps, LINES_TO_TAKE *lines_to_take)
2765 CONF_S *ctmp = NULL, *first_line = NULL;
2766 OPT_SCREEN_S screen;
2767 LINES_TO_TAKE *li;
2768 char *help_title = _("HELP FOR TAKE EXPORT SCREEN");
2769 char *p;
2770 ScreenMode listmode = SingleMode;
2772 for(li = lines_to_take; li; li = li->next){
2774 new_confline(&ctmp);
2775 ctmp->flags |= CF_STARTITEM;
2776 if(li->flags & LT_NOSELECT)
2777 ctmp->flags |= CF_NOSELECT;
2778 else if(!first_line)
2779 first_line = ctmp;
2781 p = li->printval ? li->printval : "";
2783 if(ctmp->flags & CF_NOSELECT)
2784 ctmp->value = cpystr(p);
2785 else{
2786 size_t l;
2788 /* 5 is for "[X] " */
2789 l = strlen(p)+5;
2790 ctmp->value = (char *)fs_get((l+1) * sizeof(char));
2791 snprintf(ctmp->value, l+1, " %s", p);
2792 ctmp->value[l] = '\0';
2795 /* this points to data, it doesn't have its own copy */
2796 ctmp->d.t.exportval = li->exportval ? li->exportval : NULL;
2797 ctmp->d.t.selected = 0;
2798 ctmp->d.t.listmode = &listmode;
2800 ctmp->tool = take_export_tool;
2801 ctmp->help_title = help_title;
2802 ctmp->help = h_takeexport_screen;
2803 ctmp->keymenu = &take_export_keymenu_sm;
2806 if(!first_line)
2807 q_status_message(SM_ORDER, 3, 3, _("No lines to export"));
2808 else{
2809 memset(&screen, 0, sizeof(screen));
2810 conf_scroll_screen(ps, &screen, first_line, _("Take Export"), NULL, 0, NULL);
2816 take_export_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
2818 CONF_S *ctmp;
2819 int retval = 0;
2820 int some_selected = 0, something_to_export = 0;
2821 SourceType srctype;
2822 STORE_S *srcstore = NULL;
2823 char *prompt_msg;
2825 switch(cmd){
2826 case MC_TAKE :
2827 srctype = CharStar;
2828 if((srcstore = so_get(srctype, NULL, EDIT_ACCESS)) != NULL){
2829 if(*(*cl)->d.t.listmode == SingleMode){
2830 some_selected++;
2831 if((*cl)->d.t.exportval && (*cl)->d.t.exportval[0]){
2832 so_puts(srcstore, (*cl)->d.t.exportval);
2833 so_puts(srcstore, "\n");
2834 something_to_export++;
2835 prompt_msg = "selection";
2838 else{
2839 /* go to first line */
2840 for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
2843 for(; ctmp; ctmp = next_confline(ctmp))
2844 if(!(ctmp->flags & CF_NOSELECT) && ctmp->d.t.selected){
2845 some_selected++;
2846 if(ctmp->d.t.exportval && ctmp->d.t.exportval[0]){
2847 so_puts(srcstore, ctmp->d.t.exportval);
2848 so_puts(srcstore, "\n");
2849 something_to_export++;
2850 prompt_msg = "selections";
2856 if(!srcstore)
2857 q_status_message(SM_ORDER, 0, 3, _("Error allocating space"));
2858 else if(something_to_export)
2859 simple_export(ps, so_text(srcstore), srctype, prompt_msg, NULL);
2860 else if(!some_selected && *(*cl)->d.t.listmode == ListMode)
2861 q_status_message(SM_ORDER, 0, 3, _("Use \"X\" to mark selections"));
2862 else
2863 q_status_message(SM_ORDER, 0, 3, _("Nothing to export"));
2865 if(srcstore)
2866 so_give(&srcstore);
2868 break;
2870 case MC_LISTMODE :
2871 if(*(*cl)->d.t.listmode == SingleMode){
2873 * UnHide the checkboxes
2876 *(*cl)->d.t.listmode = ListMode;
2878 /* go to first line */
2879 for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
2882 for(; ctmp; ctmp = next_confline(ctmp))
2883 if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
2884 ctmp->value[0] = '[';
2885 ctmp->value[1] = ctmp->d.t.selected ? 'X' : SPACE;
2886 ctmp->value[2] = ']';
2887 ctmp->keymenu = &take_export_keymenu_lm;
2890 else{
2892 * Hide the checkboxes
2895 *(*cl)->d.t.listmode = SingleMode;
2897 /* go to first line */
2898 for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
2901 for(; ctmp; ctmp = next_confline(ctmp))
2902 if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
2903 ctmp->value[0] = ctmp->value[1] = ctmp->value[2] = SPACE;
2904 ctmp->keymenu = &take_export_keymenu_sm;
2908 ps->mangled_body = ps->mangled_footer = 1;
2909 break;
2911 case MC_CHOICE :
2912 if((*cl)->value[1] == 'X'){
2913 (*cl)->d.t.selected = 0;
2914 (*cl)->value[1] = SPACE;
2916 else{
2917 (*cl)->d.t.selected = 1;
2918 (*cl)->value[1] = 'X';
2921 ps->mangled_body = 1;
2922 break;
2924 case MC_SELALL :
2925 /* go to first line */
2926 for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
2929 for(; ctmp; ctmp = next_confline(ctmp)){
2930 if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
2931 ctmp->d.t.selected = 1;
2932 if(ctmp->value)
2933 ctmp->value[1] = 'X';
2937 ps->mangled_body = 1;
2938 break;
2940 case MC_UNSELALL :
2941 /* go to first line */
2942 for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
2945 for(; ctmp; ctmp = next_confline(ctmp)){
2946 if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
2947 ctmp->d.t.selected = 0;
2948 if(ctmp->value)
2949 ctmp->value[1] = SPACE;
2953 ps->mangled_body = 1;
2954 break;
2956 case MC_EXIT :
2957 retval = simple_exit_cmd(flags);
2958 break;
2960 default:
2961 retval = -1;
2962 break;
2965 return(retval);
2968 #ifdef ENABLE_LDAP
2970 * Save an LDAP directory entry somewhere
2972 * Args: ps -- pine struct
2973 * e -- the entry to save
2974 * save -- If this is set, then bypass the question about whether
2975 * to save or export and just do the save.
2977 void
2978 save_ldap_entry(struct pine *ps, LDAP_CHOOSE_S *e, int save)
2980 char *fullname = NULL,
2981 *address = NULL,
2982 *first = NULL,
2983 *last = NULL,
2984 *comment = NULL;
2985 struct berval **cn = NULL,
2986 **mail = NULL,
2987 **sn = NULL,
2988 **givenname = NULL,
2989 **title = NULL,
2990 **telephone = NULL,
2991 **elecmail = NULL,
2992 **note = NULL;
2993 int j, num,
2994 export = 0;
2997 dprint((2, "\n - save_ldap_entry - \n"));
2999 if(e){
3000 char *a;
3001 BerElement *ber;
3003 for(a = ldap_first_attribute(e->ld, e->selected_entry, &ber);
3004 a != NULL;
3005 a = ldap_next_attribute(e->ld, e->selected_entry, ber)){
3007 dprint((9, " %s", a ? a : "?"));
3008 if(strcmp(a, e->info_used->cnattr) == 0){
3009 if(!cn)
3010 cn = ldap_get_values_len(e->ld, e->selected_entry, a);
3012 else if(strcmp(a, e->info_used->mailattr) == 0){
3013 if(!mail)
3014 mail = ldap_get_values_len(e->ld, e->selected_entry, a);
3016 else if(strcmp(a, "electronicmail") == 0){
3017 if(!elecmail)
3018 elecmail = ldap_get_values_len(e->ld, e->selected_entry, a);
3020 else if(strcmp(a, "comment") == 0){
3021 if(!note)
3022 note = ldap_get_values_len(e->ld, e->selected_entry, a);
3024 else if(strcmp(a, e->info_used->snattr) == 0){
3025 if(!sn)
3026 sn = ldap_get_values_len(e->ld, e->selected_entry, a);
3028 else if(strcmp(a, e->info_used->gnattr) == 0){
3029 if(!givenname)
3030 givenname = ldap_get_values_len(e->ld, e->selected_entry, a);
3032 else if(strcmp(a, "telephonenumber") == 0){
3033 if(!telephone)
3034 telephone = ldap_get_values_len(e->ld, e->selected_entry, a);
3036 else if(strcmp(a, "title") == 0){
3037 if(!title)
3038 title = ldap_get_values_len(e->ld, e->selected_entry, a);
3042 if(!save){
3043 j = radio_buttons(_("Save to address book or Export to filesystem ? "),
3044 -FOOTER_ROWS(ps), save_or_export, 's', 'x',
3045 h_ab_save_exp, RB_NORM);
3047 switch(j){
3048 case 'x':
3049 q_status_message(SM_INFO, 0, 2, _("Address book save cancelled"));
3050 break;
3052 case 'e':
3053 export++;
3054 break;
3056 case 's':
3057 save++;
3058 break;
3060 default:
3061 q_status_message(SM_ORDER, 3, 3,
3062 "can't happen in save_ldap_ent");
3063 break;
3068 if(elecmail){
3069 if(ALPINE_LDAP_can_use(elecmail) && !mail)
3070 mail = elecmail;
3071 else
3072 ldap_value_free_len(elecmail);
3074 elecmail = NULL;
3077 if(save){ /* save into the address book */
3078 ADDRESS *addr;
3079 char *d,
3080 *fakedomain = "@";
3081 size_t len;
3082 struct berval **cm;
3083 int how_many_selected = 0;
3086 if(ALPINE_LDAP_can_use(cn))
3087 fullname = cpystr(cn[0]->bv_val);
3088 if(ALPINE_LDAP_can_use(sn))
3089 last = cpystr(sn[0]->bv_val);
3090 if(ALPINE_LDAP_can_use(givenname))
3091 first = cpystr(givenname[0]->bv_val);
3093 if(ALPINE_LDAP_can_use(note))
3094 cm = note;
3095 else
3096 cm = title;
3098 for(len = 0, num = 0; ALPINE_LDAP_usable(cm, num); num++)
3099 len += strlen(cm[num]->bv_val) + 2;
3101 if(len){
3102 comment = (char *)fs_get(len * sizeof(char));
3103 d = comment;
3104 num = 0;
3105 while(ALPINE_LDAP_usable(cm, num)){
3106 sstrncpy(&d, cm[num]->bv_val, len-(d-comment));
3107 num++;
3108 if(ALPINE_LDAP_usable(cm, num))
3109 sstrncpy(&d, "; ", len-(d-comment));
3112 comment[len-1] = '\0';
3115 for(len = 0, num = 0; ALPINE_LDAP_usable(mail, num); num++)
3116 len += strlen(mail[num]->bv_val) + 2;
3118 /* paste the email addresses together */
3119 if(len){
3120 address = (char *)fs_get(len * sizeof(char));
3121 d = address;
3122 num = 0;
3123 while(ALPINE_LDAP_usable(mail, num)){
3124 sstrncpy(&d, mail[num]->bv_val, len-(d-address));
3125 num++;
3126 if(ALPINE_LDAP_usable(mail, num))
3127 sstrncpy(&d, ", ", len-(d-address));
3130 address[len-1] = '\0';
3133 addr = NULL;
3134 if(address)
3135 rfc822_parse_adrlist(&addr, address, fakedomain);
3137 if(addr && fullname && !(first && last)){
3138 if(addr->personal)
3139 fs_give((void **)&addr->personal);
3141 addr->personal = cpystr(fullname);
3144 if(addr && e->serv && *e->serv){ /* save by reference */
3145 char *dn, *edn = NULL;
3147 dn = ldap_get_dn(e->ld, e->selected_entry);
3148 if(dn){
3149 edn = add_backslash_escapes(dn);
3150 our_ldap_dn_memfree(dn);
3153 if(e->serv && *e->serv && edn && *edn){
3154 char buf[MAILTMPLEN+1];
3155 char *backup_mail = NULL;
3157 how_many_selected++;
3159 if(addr && addr->mailbox && addr->host){
3160 strncpy(buf, addr->mailbox, sizeof(buf)-2),
3161 buf[sizeof(buf)-2] = '\0';
3162 strncat(buf, "@", sizeof(buf)-1-strlen(buf));
3163 strncat(buf, addr->host, sizeof(buf)-1-strlen(buf));
3164 buf[sizeof(buf)-1] = '\0';
3165 backup_mail = cpystr(buf);
3169 * We only need one addr which we will use to hold the
3170 * pointer to the query.
3172 if(addr->next)
3173 mail_free_address(&addr->next);
3175 if(addr->mailbox)
3176 fs_give((void **)&addr->mailbox);
3177 if(addr->host)
3178 fs_give((void **)&addr->host);
3179 if(addr->personal)
3180 fs_give((void **)&addr->personal);
3182 snprintf(buf, sizeof(buf),
3183 "%s%s /base=%s/scope=base/cust=(objectclass=*)%s%s",
3184 RUN_LDAP,
3185 e->serv,
3186 edn,
3187 backup_mail ? "/mail=" : "",
3188 backup_mail ? backup_mail : "");
3189 buf[sizeof(buf)-1] = '\0';
3191 if(backup_mail)
3192 fs_give((void **)&backup_mail);
3195 * Put the search parameters in mailbox and put @ in
3196 * host so that expand_address accepts it as an unqualified
3197 * address and doesn't try to add localdomain.
3199 addr->mailbox = cpystr(buf);
3200 addr->host = cpystr("@");
3203 if(edn)
3204 fs_give((void **)&edn);
3206 else{ /* save by value */
3207 how_many_selected++;
3208 if(!addr)
3209 addr = mail_newaddr();
3212 if(how_many_selected > 0){
3213 TA_S *current = NULL;
3216 * The empty string for the last argument is significant.
3217 * Fill_in_ta copies the whole adrlist into a single TA if
3218 * there is a print string.
3220 current = fill_in_ta(&current, addr, 1, "");
3221 current = first_sel_taline(current);
3223 if(first && last && current){
3224 char *p;
3225 size_t l;
3227 l = strlen(last) + 2 + strlen(first);
3228 p = (char *)fs_get((l+1) * sizeof(char));
3229 snprintf(p, l, "%s, %s", last, first);
3230 p[l] = '\0';
3231 current->fullname = p;
3232 convert_possibly_encoded_str_to_utf8(&current->fullname);
3235 if(comment && current){
3236 current->comment = cpystr(comment);
3237 convert_possibly_encoded_str_to_utf8(&current->comment);
3241 * We don't want the personal name to make it into the address
3242 * field in an LDAP: query sort of address, so move it
3243 * out of the addr.
3245 if(e->serv && *e->serv && current && fullname){
3246 if(current->fullname)
3247 fs_give((void **)&current->fullname);
3249 current->fullname = fullname;
3250 fullname = NULL;
3251 convert_possibly_encoded_str_to_utf8(&current->fullname);
3254 mail_free_address(&addr);
3256 if(current)
3257 takeaddr_bypass(ps, current, NULL);
3258 else
3259 q_status_message(SM_ORDER, 0, 4, "Nothing to save");
3261 free_talines(&current);
3263 else
3264 q_status_message(SM_ORDER, 0, 4, "Nothing to save");
3267 else if(export){ /* export to filesystem */
3268 STORE_S *srcstore = NULL;
3269 SourceType srctype;
3270 static ESCKEY_S text_or_vcard[] = {
3271 {'t', 't', "T", N_("Text")},
3272 {'a', 'a', "A", N_("Addresses")},
3273 {'v', 'v', "V", N_("VCard")},
3274 {-1, 0, NULL, NULL}};
3276 j = radio_buttons(
3277 _("Export text of entry, address, or VCard format ? "),
3278 -FOOTER_ROWS(ps), text_or_vcard, 't', 'x',
3279 h_ldap_text_or_vcard, RB_NORM);
3281 switch(j){
3282 case 'x':
3283 q_status_message(SM_INFO, 0, 2, _("Address book export cancelled"));
3284 break;
3286 case 't':
3287 srctype = CharStar;
3288 if(!(srcstore = prep_ldap_for_viewing(ps, e, srctype, NULL)))
3289 q_status_message(SM_ORDER, 0, 2, _("Error allocating space"));
3290 else{
3291 (void)simple_export(ps_global, so_text(srcstore), srctype,
3292 "text", NULL);
3293 so_give(&srcstore);
3296 break;
3298 case 'a':
3299 if(ALPINE_LDAP_can_use(mail)){
3301 srctype = CharStar;
3302 if(!(srcstore = so_get(srctype, NULL, EDIT_ACCESS)))
3303 q_status_message(SM_ORDER,0,2, _("Error allocating space"));
3304 else{
3305 for(num = 0; ALPINE_LDAP_usable(mail, num); num++){
3306 so_puts(srcstore, mail[num]->bv_val);
3307 so_puts(srcstore, "\n");
3310 (void)simple_export(ps_global, so_text(srcstore),
3311 srctype, "addresses", NULL);
3312 so_give(&srcstore);
3316 break;
3318 case 'v':
3319 srctype = CharStar;
3320 if(!(srcstore = so_get(srctype, NULL, EDIT_ACCESS)))
3321 q_status_message(SM_ORDER,0,2, _("Error allocating space"));
3322 else{
3323 gf_io_t pc;
3324 VCARD_INFO_S *vinfo;
3326 vinfo = (VCARD_INFO_S *)fs_get(sizeof(VCARD_INFO_S));
3327 memset((void *)vinfo, 0, sizeof(VCARD_INFO_S));
3329 if(ALPINE_LDAP_can_use(cn))
3330 vinfo->fullname = berval_to_array(cn);
3332 if(ALPINE_LDAP_can_use(note))
3333 vinfo->note = berval_to_array(note);
3335 if(ALPINE_LDAP_can_use(title))
3336 vinfo->title = berval_to_array(title);
3338 if(ALPINE_LDAP_can_use(telephone))
3339 vinfo->tel = berval_to_array(telephone);
3341 if(ALPINE_LDAP_can_use(mail))
3342 vinfo->email = berval_to_array(mail);
3344 if(ALPINE_LDAP_can_use(sn))
3345 vinfo->last = cpystr(sn[0]->bv_val);
3347 if(ALPINE_LDAP_can_use(givenname))
3348 vinfo->first = cpystr(givenname[0]->bv_val);
3350 gf_set_so_writec(&pc, srcstore);
3352 write_single_vcard_entry(ps_global, pc, vinfo);
3354 free_vcard_info(&vinfo);
3356 (void)simple_export(ps_global, so_text(srcstore),
3357 srctype, "vcard text", NULL);
3358 so_give(&srcstore);
3361 break;
3363 default:
3364 q_status_message(SM_ORDER, 3, 3, "can't happen in text_or_vcard");
3365 break;
3369 if(cn)
3370 ldap_value_free_len(cn);
3371 if(mail)
3372 ldap_value_free_len(mail);
3373 if(elecmail)
3374 ldap_value_free_len(elecmail);
3375 if(note)
3376 ldap_value_free_len(note);
3377 if(sn)
3378 ldap_value_free_len(sn);
3379 if(givenname)
3380 ldap_value_free_len(givenname);
3381 if(telephone)
3382 ldap_value_free_len(telephone);
3383 if(title)
3384 ldap_value_free_len(title);
3385 if(fullname)
3386 fs_give((void **)&fullname);
3387 if(address)
3388 fs_give((void **)&address);
3389 if(first)
3390 fs_give((void **)&first);
3391 if(last)
3392 fs_give((void **)&last);
3393 if(comment)
3394 fs_give((void **)&comment);
3396 #endif /* ENABLE_LDAP */
3399 #ifdef _WINDOWS
3402 ta_scroll_up(count)
3403 long count;
3405 if(count<0)
3406 return(ta_scroll_down(-count));
3407 else if (count){
3408 long i=count;
3409 TA_S *next_sel;
3411 while(i && ta_screen->top_line->next){
3412 if(ta_screen->top_line == ta_screen->current){
3413 if(next_sel = next_sel_taline(ta_screen->current)){
3414 ta_screen->current = next_sel;
3415 ta_screen->top_line = next_taline(ta_screen->top_line);
3416 i--;
3418 else i = 0;
3420 else{
3421 ta_screen->top_line = next_taline(ta_screen->top_line);
3422 i--;
3426 return(TRUE);
3430 ta_scroll_down(count)
3431 long count;
3433 if(count < 0)
3434 return(ta_scroll_up(-count));
3435 else if (count){
3436 long i,dline;
3437 long page_size = ps_global->ttyo->screen_rows -
3438 FOOTER_ROWS(ps_global) - HEADER_ROWS(ps_global);
3439 TA_S *ctmp;
3440 TA_S *first = first_taline(ta_screen->top_line);
3442 i=count;
3443 dline=0;
3444 for(ctmp = ta_screen->top_line;
3445 ctmp != ta_screen->current; ctmp = next_taline(ctmp))
3446 dline++;
3447 while(i && ta_screen->top_line != first){
3448 ta_screen->top_line = pre_taline(ta_screen->top_line);
3449 i--;
3450 dline++;
3451 if(dline >= page_size){
3452 ctmp = pre_sel_taline(ta_screen->current);
3453 if(ctmp == NULL){
3454 i = 0;
3455 ta_screen->top_line = next_taline(ta_screen->top_line);
3457 else {
3458 for(; ctmp != ta_screen->current;
3459 ta_screen->current = pre_taline(ta_screen->current))
3460 dline--;
3465 return(TRUE);
3468 int ta_scroll_to_pos(line)
3469 long line;
3471 TA_S *ctmp;
3472 int dline;
3474 for(dline = 0, ctmp = first_taline(ta_screen->top_line);
3475 ctmp != ta_screen->top_line; ctmp = next_taline(ctmp))
3476 dline++;
3478 if (!ctmp)
3479 dline = 1;
3481 return(ta_scroll_up(line - dline));
3485 ta_scroll_callback (cmd, scroll_pos)
3486 int cmd;
3487 long scroll_pos;
3489 int paint = TRUE;
3490 long page_size = ps_global->ttyo->screen_rows - HEADER_ROWS(ps_global)
3491 - FOOTER_ROWS(ps_global);
3493 switch (cmd) {
3494 case MSWIN_KEY_SCROLLUPLINE:
3495 paint = ta_scroll_down (scroll_pos);
3496 break;
3498 case MSWIN_KEY_SCROLLDOWNLINE:
3499 paint = ta_scroll_up (scroll_pos);
3500 break;
3502 case MSWIN_KEY_SCROLLUPPAGE:
3503 paint = ta_scroll_down (page_size);
3504 break;
3506 case MSWIN_KEY_SCROLLDOWNPAGE:
3507 paint = ta_scroll_up (page_size);
3508 break;
3510 case MSWIN_KEY_SCROLLTO:
3511 paint = ta_scroll_to_pos (scroll_pos);
3512 break;
3515 if(paint)
3516 update_takeaddr_screen(ps_global, ta_screen->current, ta_screen, (Pos *)NULL);
3518 return(paint);
3521 #endif /* _WINDOWS */