2 * ========================================================================
3 * Copyright 2006-2008 University of Washington
4 * Copyright 2013-2022 Eduardo Chappa
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 /*======================================================================
17 Mostly support for Take Address command.
26 #include "confscroll.h"
35 #include "../pith/state.h"
36 #include "../pith/msgno.h"
37 #include "../pith/adrbklib.h"
38 #include "../pith/bldaddr.h"
39 #include "../pith/bitmap.h"
40 #include "../pith/util.h"
41 #include "../pith/addrstring.h"
42 #include "../pith/remote.h"
43 #include "../pith/newmail.h"
44 #include "../pith/list.h"
45 #include "../pith/abdlc.h"
46 #include "../pith/ablookup.h"
47 #include "../pith/stream.h"
48 #include "../pith/mailcmd.h"
49 #include "../pith/busy.h"
52 typedef struct takeaddress_screen
{
58 static TA_SCREEN_S
*ta_screen
;
59 static char *fakedomain
= "@";
61 static ESCKEY_S save_or_export
[] = {
62 {'s', 's', "S", N_("Save")},
63 {'e', 'e', "E", N_("Export")},
67 /* internal prototypes */
68 int edit_nickname(AdrBk
*, AddrScrn_Disp
*, int, char *, char *, HelpType
, int, int);
69 void add_abook_entry(TA_S
*, char *, char *, char *, char *, int, TA_STATE_S
**, char *);
70 void take_to_addrbooks_frontend(char **, char *, char *, char *, char *,
71 char *, int, TA_STATE_S
**, char *);
72 void take_to_addrbooks(char **, char *, char *, char *, char *,
73 char *, int, TA_STATE_S
**, char *);
74 PerAddrBook
*use_this_addrbook(int, char *);
75 PerAddrBook
*check_for_addrbook(char *);
76 int takeaddr_screen(struct pine
*, TA_S
*, int, ScreenMode
, TA_STATE_S
**, char *);
77 void takeaddr_bypass(struct pine
*, TA_S
*, TA_STATE_S
**);
78 int ta_do_take(TA_S
*, int, int, TA_STATE_S
**, char *);
79 TA_S
*whereis_taline(TA_S
*);
80 int ta_take_marked_addrs(int, TA_S
*, int, TA_STATE_S
**, char *);
81 int ta_take_single_addr(TA_S
*, int, TA_STATE_S
**, char *);
82 int update_takeaddr_screen(struct pine
*, TA_S
*, TA_SCREEN_S
*, Pos
*);
83 void takeaddr_screen_redrawer_list(void);
84 void takeaddr_screen_redrawer_single(void);
85 int attached_addr_handler(TA_S
*, int);
86 int take_without_edit(TA_S
*, int, int, TA_STATE_S
**, char *);
87 void export_vcard_att(struct pine
*, int, long, ATTACH_S
*);
88 int take_export_tool(struct pine
*, int, CONF_S
**, unsigned);
91 int ta_scroll_up(long);
92 int ta_scroll_down(long);
93 int ta_scroll_to_pos(long);
94 int ta_scroll_callback(int, long);
99 * Edit a nickname field.
101 * Args: abook -- the addressbook handle
102 * dl -- display list line (NULL if new entry)
103 * command_line -- line to prompt on
104 * orig -- nickname to edit
107 * return_existing -- changes the behavior when a user types in a nickname
108 * which already exists in this abook. If not set, it
109 * will just keep looping until the user changes; if set,
110 * it will return -8 to the caller and orig will be set
111 * to the matching nickname.
113 * Returns: -10 to cancel
115 * -7 only case of nickname changed (only happens if dl set)
116 * -8 existing nickname chosen (only happens if return_existing set)
117 * 0 new value copied into orig
120 edit_nickname(AdrBk
*abook
, AddrScrn_Disp
*dl
, int command_line
, char *orig
,
121 char *prompt
, HelpType this_help
, int return_existing
, int takeaddr
)
123 char edit_buf
[MAX_NICKNAME
+ 1];
125 int i
, flags
, lastrc
, rc
;
126 AdrBk_Entry
*check
, *passed_in_ae
;
128 SAVE_STATE_S state
; /* For saving state of addrbooks temporarily */
131 ekey
[i
= 0].ch
= ctrl('T');
134 ekey
[i
++].label
= N_("To AddrBk");
136 if(F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
)){
137 ekey
[i
].ch
= ctrl('I');
139 ekey
[i
].name
= "TAB";
140 ekey
[i
++].label
= N_("Complete");
145 strncpy(edit_buf
, orig
, sizeof(edit_buf
)-1);
146 edit_buf
[sizeof(edit_buf
)-1] = '\0';
148 passed_in_ae
= adrbk_get_ae(abook
, (a_c_arg_t
) dl
->elnum
);
150 passed_in_ae
= (AdrBk_Entry
*)NULL
;
157 q_status_message(SM_ORDER
, 3, 4, error
);
158 fs_give((void **)&error
);
161 /* display a message because adrbk_lookup_by_nick returned positive */
164 strncpy(orig
, edit_buf
, sizeof(edit_buf
)-1);
165 orig
[sizeof(edit_buf
)-1] = '\0';
167 (void)adrbk_get_ae(abook
, (a_c_arg_t
) dl
->elnum
);
171 q_status_message1(SM_ORDER
, 0, 4,
172 _("Already an entry with nickname \"%s\""), edit_buf
);
177 help
= (help
== NO_HELP
? this_help
: NO_HELP
);
179 flags
= OE_APPEND_CURRENT
;
180 rc
= optionally_enter(edit_buf
, command_line
, 0, sizeof(edit_buf
),
181 prompt
, ekey
, help
, &flags
);
186 if(rc
== 2){ /* ^T */
187 void (*redraw
) (void) = ps_global
->redrawer
;
188 char *returned_nickname
;
190 push_titlebar_state();
193 returned_nickname
= addr_book_takeaddr();
195 returned_nickname
= addr_book_selnick();
197 restore_state(&state
);
198 if(returned_nickname
){
199 strncpy(edit_buf
, returned_nickname
, sizeof(edit_buf
)-1);
200 edit_buf
[sizeof(edit_buf
)-1] = '\0';
201 fs_give((void **)&returned_nickname
);
205 pop_titlebar_state();
207 if((ps_global
->redrawer
= redraw
) != NULL
) /* reset old value, and test */
208 (*ps_global
->redrawer
)();
210 else if(rc
== 11){ /* TAB */
212 char *new_nickname
= NULL
;
215 ambiguity
= abook_nickname_complete(edit_buf
, &new_nickname
,
216 (lastrc
==rc
&& !(flags
& OE_USER_MODIFIED
)), 0);
219 strncpy(edit_buf
, new_nickname
, sizeof(edit_buf
));
220 edit_buf
[sizeof(edit_buf
)-1] = '\0';
223 fs_give((void **) &new_nickname
);
235 nickname_check(edit_buf
, &error
) ||
237 adrbk_lookup_by_nick(abook
, edit_buf
, (adrbk_cntr_t
*)NULL
)) &&
238 check
!= passed_in_ae
));
242 (void)adrbk_get_ae(abook
, (a_c_arg_t
) dl
->elnum
);
247 /* only the case of nickname changed */
248 if(passed_in_ae
&& check
== passed_in_ae
&& strcmp(edit_buf
, orig
)){
249 (void)adrbk_get_ae(abook
, (a_c_arg_t
) dl
->elnum
);
250 strncpy(orig
, edit_buf
, sizeof(edit_buf
)-1);
251 orig
[sizeof(edit_buf
)-1] = '\0';
256 (void)adrbk_get_ae(abook
, (a_c_arg_t
) dl
->elnum
);
258 if(strcmp(edit_buf
, orig
) == 0) /* no change */
261 strncpy(orig
, edit_buf
, sizeof(edit_buf
)-1);
262 orig
[sizeof(edit_buf
)-1] = '\0';
268 * Add an entry to address book.
269 * It is for capturing addresses off incoming mail.
270 * This is a front end for take_to_addrbooks.
271 * It is also used for replacing an existing entry and for adding a single
272 * new address to an existing list.
274 * The reason this is here is so that when Taking a single address, we can
275 * rearrange the fullname to be Last, First instead of First Last.
277 * Args: ta_entry -- the entry from the take screen
278 * command_line -- line to prompt on
280 * Result: item is added to one of the address books,
281 * an error message is queued if appropriate.
284 add_abook_entry(TA_S
*ta_entry
, char *nick
, char *fullname
, char *fcc
,
285 char *comment
, int command_line
, TA_STATE_S
**tas
, char *cmd
)
288 char new_fullname
[6*MAX_FULLNAME
+ 1], new_address
[6*MAX_ADDRESS
+ 1];
291 dprint((5, "-- add_abook_entry --\n"));
293 /*-- rearrange full name (Last, First) ---*/
294 new_fullname
[0] = '\0';
295 addr
= ta_entry
->addr
;
296 if(!fullname
&& addr
->personal
!= NULL
){
297 if(F_ON(F_DISABLE_TAKE_LASTFIRST
, ps_global
)){
298 strncpy(new_fullname
, addr
->personal
, sizeof(new_fullname
)-1);
299 new_fullname
[sizeof(new_fullname
)-1] = '\0';
302 char old_fullname
[6*MAX_FULLNAME
+ 1];
304 snprintf(old_fullname
, sizeof(old_fullname
), "%s", addr
->personal
);
305 old_fullname
[sizeof(old_fullname
)-1] = '\0';
306 switch_to_last_comma_first(old_fullname
, new_fullname
, sizeof(new_fullname
));
310 /* initial value for new address */
311 new_address
[0] = '\0';
312 if(addr
->mailbox
&& addr
->mailbox
[0]){
313 char *scratch
, *p
, *t
, *u
;
319 scratch
= (char *) fs_get(es
);
321 rbuf
.f
= dummy_soutr
;
325 rbuf
.end
= scratch
+es
-1;
326 rfc822_output_address_list(&rbuf
, addr
, 0L, NULL
);
328 if((p
= srchstr(scratch
, "@" RAWFIELD
)) != NULL
){
330 if(*t
== '&'){ /* find "leading" token */
331 *t
++ = ' '; /* replace token */
332 *p
= '\0'; /* tie off string */
333 u
= (char *)rfc822_base64((unsigned char *)t
,
334 (unsigned long)strlen(t
), &l
);
335 *p
= '@'; /* restore 'p' */
336 rplstr(p
, es
-(p
-scratch
), 12, ""); /* clear special token */
337 rplstr(t
, es
-(t
-scratch
), strlen(t
), u
); /* Null u is handled */
339 fs_give((void **)&u
);
341 else if(t
== scratch
)
345 strncpy(new_address
, scratch
, sizeof(new_address
)-1);
346 new_address
[sizeof(new_address
)-1] = '\0';
349 fs_give((void **)&scratch
);
352 if(ta_entry
->frwrded
){
356 for(i
= 0, a
= addr
; a
; i
++, a
= a
->next
)
357 ;/* just counting for alloc below */
359 /* catch special case where empty addr was set in vcard_to_ta */
360 if(i
== 1 && !addr
->host
&& !addr
->mailbox
&& !addr
->personal
)
363 new_list
= (char **) fs_get((i
+1) * sizeof(char *));
364 for(j
= 0, a
= addr
; i
&& a
; j
++, a
= a
->next
){
372 bufp
= (char *) fs_get(len
* sizeof(char));
373 new_list
[j
] = cpystr(addr_string(a
, bufp
, len
));
375 fs_give((void **) &bufp
);
383 j
= (ta_entry
->strvalue
&& ta_entry
->strvalue
[0]) ? 2 : 1;
385 new_list
= (char **) fs_get(j
* sizeof(char *));
388 new_list
[i
++] = cpystr(ta_entry
->strvalue
);
393 take_to_addrbooks_frontend(new_list
, nick
,
394 fullname
? fullname
: new_fullname
,
395 new_address
, fcc
, comment
, command_line
,
397 free_list_array(&new_list
);
402 take_to_addrbooks_frontend(char **new_entries
, char *nick
, char *fullname
,
403 char *addr
, char *fcc
, char *comment
, int cmdline
,
404 TA_STATE_S
**tas
, char *cmd
)
406 jmp_buf save_jmp_buf
;
407 int *save_nesting_level
;
409 dprint((5, "-- take_to_addrbooks_frontend --\n"));
411 if(ps_global
->remote_abook_validity
> 0 &&
412 adrbk_check_and_fix_all(ab_nesting_level
== 0, 0, 0))
413 ps_global
->mangled_footer
= 1;
415 save_nesting_level
= cpyint(ab_nesting_level
);
416 memcpy(save_jmp_buf
, addrbook_changed_unexpectedly
, sizeof(jmp_buf));
417 if(setjmp(addrbook_changed_unexpectedly
)){
418 q_status_message(SM_ORDER
, 5, 10, _("Resetting address book..."));
420 "RESETTING address book... take_to_addrbooks_frontend!\n"));
422 ab_nesting_level
= *save_nesting_level
;
426 take_to_addrbooks(new_entries
, nick
, fullname
, addr
, fcc
, comment
, cmdline
,
428 memcpy(addrbook_changed_unexpectedly
, save_jmp_buf
, sizeof(jmp_buf));
430 if(save_nesting_level
)
431 fs_give((void **)&save_nesting_level
);
436 * Add to address book, called from take screen.
437 * It is also used for adding to an existing list or replacing an existing
440 * Args: new_entries -- a list of addresses to add to a list or to form
442 * nick -- if adding new entry, suggest this for nickname
443 * fullname -- if adding new entry, use this for fullname
444 * addr -- if only one new_entry, this is its addr
445 * fcc -- if adding new entry, use this for fcc
446 * comment -- if adding new entry, use this for comment
447 * command_line -- line to prompt on
449 * Result: item is added to one of the address books,
450 * an error message is queued if appropriate.
453 take_to_addrbooks(char **new_entries
, char *nick
, char *fullname
, char *addr
,
454 char *fcc
, char *comment
, int command_line
, TA_STATE_S
**tas
, char *cmd
)
456 char new_nickname
[6*MAX_NICKNAME
+ 1], exist_nick
[6*MAX_NICKNAME
+ 1];
457 char prompt
[200], **p
;
458 int rc
, listadd
= 0, ans
, i
;
462 AdrBk_Entry
*abe
= (AdrBk_Entry
*)NULL
, *abe_copy
;
463 adrbk_cntr_t entry_num
= NO_NEXT
;
464 size_t tot_size
, new_size
, old_size
;
467 char *simple_a
= NULL
;
471 dprint((5, "-- take_to_addrbooks --\n"));
476 pab
= setup_for_addrbook_add(&state
, command_line
, cmd
);
478 /* check we got it opened ok */
479 if(pab
== NULL
|| pab
->address_book
== NULL
)
480 goto take_to_addrbooks_cancel
;
482 adrbk_check_validity(pab
->address_book
, 1L);
483 if(pab
->address_book
->flags
& FILE_OUTOFDATE
||
484 (pab
->address_book
->rd
&&
485 pab
->address_book
->rd
->flags
& REM_OUTOFDATE
)){
486 q_status_message3(SM_ORDER
, 0, 4,
487 "Address book%s%s has changed: %stry again",
488 (as
.n_addrbk
> 1 && pab
->abnick
) ? " " : "",
489 (as
.n_addrbk
> 1 && pab
->abnick
) ? pab
->abnick
: "",
490 (ps_global
->remote_abook_validity
== -1) ? "resynchronize and " : "");
492 restore_state(&((*tas
)->state
));
496 restore_state(&state
);
501 abook
= pab
->address_book
;
502 new_nickname
[0] = '\0';
503 exist_nick
[0] = '\0';
508 /* rfc822_parse_adrlist feels free to destroy input so send copy */
509 tmp_a_string
= cpystr(addr
);
510 rfc822_parse_adrlist(&a
, tmp_a_string
, fakedomain
);
512 fs_give((void **)&tmp_a_string
);
515 simple_a
= simple_addr_string(a
, tmp_20k_buf
, SIZEOF_20KBUF
);
516 mail_free_address(&a
);
519 if(simple_a
&& *simple_a
)
520 abe
= adrbk_lookup_by_addr(abook
, simple_a
, NULL
);
523 snprintf(prompt
, sizeof(prompt
), _("Warning: address exists with %s%s, continue "),
524 (abe
->nickname
&& abe
->nickname
[0]) ? "nickname "
525 : (abe
->fullname
&& abe
->fullname
[0]) ? "fullname "
527 (abe
->nickname
&& abe
->nickname
[0]) ? abe
->nickname
528 : (abe
->fullname
&& abe
->fullname
[0]) ? abe
->fullname
530 prompt
[sizeof(prompt
)-1] = '\0';
531 switch(want_to(prompt
, 'y', 'x', NO_HELP
, WT_NORM
)){
533 if(abe
->nickname
&& abe
->nickname
[0]){
534 strncpy(new_nickname
, abe
->nickname
, sizeof(new_nickname
));
535 new_nickname
[sizeof(new_nickname
)-1] = '\0';
536 strncpy(exist_nick
, new_nickname
, sizeof(exist_nick
));
537 exist_nick
[sizeof(exist_nick
)-1] = '\0';
543 goto take_to_addrbooks_cancel
;
553 /*----- nickname ------*/
554 snprintf(prompt
, sizeof(prompt
),
555 _("Enter new or existing nickname (one word and easy to remember): "));
556 prompt
[sizeof(prompt
)-1] = '\0';
557 if(!new_nickname
[0] && nick
){
558 strncpy(new_nickname
, nick
, sizeof(new_nickname
));
559 new_nickname
[sizeof(new_nickname
)-1] = '\0';
562 rc
= edit_nickname(abook
, (AddrScrn_Disp
*)NULL
, command_line
,
563 new_nickname
, prompt
, h_oe_takenick
, 1, 1);
564 if(rc
== -8){ /* this means an existing nickname was entered */
565 abe
= adrbk_lookup_by_nick(abook
, new_nickname
, &entry_num
);
566 if(!abe
){ /* this shouldn't happen */
567 q_status_message1(SM_ORDER
, 0, 4,
568 _("Already an entry %s in address book!"), new_nickname
);
569 goto take_to_addrbooks_cancel
;
574 if(abe
->tag
== Single
&& !strcmp(new_nickname
, exist_nick
)){
575 static ESCKEY_S choices
[] = {
576 {'r', 'r', "R", N_("Replace")},
577 {'n', 'n', "N", N_("No")},
578 {-1, 0, NULL
, NULL
}};
580 snprintf(prompt
, sizeof(prompt
), _("Entry %s (%s) exists, replace ? "),
582 (abe
->fullname
&& abe
->fullname
[0])
583 ? (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
,
584 SIZEOF_20KBUF
, abe
->fullname
)
586 prompt
[sizeof(prompt
)-1] = '\0';
587 ans
= radio_buttons(prompt
,
596 static ESCKEY_S choices
[] = {
597 {'r', 'r', "R", N_("Replace")},
598 {'a', 'a', "A", N_("Add")},
599 {'n', 'n', "N", N_("No")},
600 {-1, 0, NULL
, NULL
}};
602 snprintf(prompt
, sizeof(prompt
),
603 _("%s %s (%s) exists, replace or add addresses to it ? "),
604 abe
->tag
== List
? "List" : "Entry",
606 (abe
->fullname
&& abe
->fullname
[0])
607 ? (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
,
608 SIZEOF_20KBUF
, abe
->fullname
)
610 prompt
[sizeof(prompt
)-1] = '\0';
612 ans
= radio_buttons(prompt
,
617 h_oe_take_replace_or_add
,
635 goto take_to_addrbooks_cancel
;
638 else if(rc
!= 0 && rc
!= -9) /* -9 means a null nickname */
639 goto take_to_addrbooks_cancel
;
641 if((long)abook
->count
> MAX_ADRBK_SIZE
||
642 (old_tag
== NotSet
&& (long)abook
->count
>= MAX_ADRBK_SIZE
)){
643 q_status_message(SM_ORDER
, 3, 5,
644 _("Address book is at maximum size, cancelled."));
645 dprint((2, "Addrbook at Max size, TakeAddr cancelled\n"));
646 goto take_to_addrbooks_cancel
;
650 /* count up size of existing list */
651 if(abe
->tag
== List
){
652 for(p
= abe
->addr
.list
; p
!= NULL
&& *p
!= NULL
; p
++)
655 old_size
= p
- abe
->addr
.list
;
657 /* or size of existing single address */
658 else if(abe
->addr
.addr
&& abe
->addr
.addr
[0])
663 else /* don't care about old size, they will be tossed in edit_entry */
666 /* make up an abe to pass to edit_entry */
667 abe_copy
= adrbk_newentry();
668 abe_copy
->nickname
= cpystr(new_nickname
);
669 abe_copy
->tag
= List
;
670 abe_copy
->addr
.list
= NULL
;
673 abe_copy
->fullname
= cpystr((abe
->fullname
&& abe
->fullname
[0])
674 ? abe
->fullname
: "");
675 abe_copy
->fcc
= cpystr((abe
->fcc
&& abe
->fcc
[0]) ? abe
->fcc
: "");
676 abe_copy
->extra
= cpystr((abe
->extra
&&abe
->extra
[0]) ? abe
->extra
: "");
680 * use passed in info if available
682 abe_copy
->fullname
= cpystr((fullname
&& fullname
[0])
684 : (abe
&& abe
->fullname
)
687 abe_copy
->fcc
= cpystr((fcc
&& fcc
[0])
692 abe_copy
->extra
= cpystr((comment
&& comment
[0])
694 : (abe
&& abe
->extra
)
699 /* get rid of duplicates */
701 if(abe
->tag
== List
){
704 ADDRESS
*newadr
, *oldadr
;
706 for(q
= new_entries
; q
!= NULL
&& *q
!= NULL
;){
708 tmp_a_string
= cpystr(*q
);
710 rfc822_parse_adrlist(&newadr
, tmp_a_string
, fakedomain
);
711 fs_give((void **) &tmp_a_string
);
713 elim_dup
= (newadr
== NULL
);
714 for(p
= abe
->addr
.list
;
715 !elim_dup
&& p
!= NULL
&& *p
!= NULL
;
717 tmp_a_string
= cpystr(*p
);
719 rfc822_parse_adrlist(&oldadr
, tmp_a_string
, fakedomain
);
720 fs_give((void **) &tmp_a_string
);
722 if(address_is_same(newadr
, oldadr
))
726 mail_free_address(&oldadr
);
729 /* slide the addresses down one to eliminate newadr */
734 for(r
= q
; r
!= NULL
&& *r
!= NULL
; r
++)
738 fs_give((void **) &f
);
744 mail_free_address(&newadr
);
749 ADDRESS
*newadr
, *oldadr
;
751 tmp_a_string
= cpystr(abe
->addr
.addr
? abe
->addr
.addr
: "");
753 rfc822_parse_adrlist(&oldadr
, tmp_a_string
, fakedomain
);
754 fs_give((void **) &tmp_a_string
);
756 for(q
= new_entries
; q
!= NULL
&& *q
!= NULL
;){
758 tmp_a_string
= cpystr(*q
);
760 rfc822_parse_adrlist(&newadr
, tmp_a_string
, fakedomain
);
761 fs_give((void **) &tmp_a_string
);
763 /* slide the addresses down one to eliminate newadr */
764 if(address_is_same(newadr
, oldadr
)){
768 for(r
= q
; r
!= NULL
&& *r
!= NULL
; r
++)
772 fs_give((void **) &f
);
778 mail_free_address(&newadr
);
782 mail_free_address(&oldadr
);
785 if(!new_entries
|| !*new_entries
){
786 q_status_message1(SM_ORDER
, 0, 4,
787 _("All of the addresses are already included in \"%s\""),
791 restore_state(&((*tas
)->state
));
795 restore_state(&state
);
801 /* count up size of new list */
802 for(p
= new_entries
; p
!= NULL
&& *p
!= NULL
; p
++)
805 new_size
= p
- new_entries
;
806 tot_size
= old_size
+ new_size
;
807 abe_copy
->addr
.list
= (char **) fs_get((tot_size
+1) * sizeof(char *));
808 memset((void *) abe_copy
->addr
.list
, 0, (tot_size
+1) * sizeof(char *));
810 if(abe
->tag
== List
){
811 for(i
= 0; i
< old_size
; i
++)
812 abe_copy
->addr
.list
[i
] = cpystr(abe
->addr
.list
[i
]);
815 abe_copy
->addr
.list
[0] = cpystr(abe
->addr
.addr
);
818 /* add new addresses to list */
819 if(tot_size
== 1 && addr
)
820 abe_copy
->addr
.list
[0] = cpystr(addr
);
822 for(i
= 0; i
< new_size
; i
++)
823 abe_copy
->addr
.list
[old_size
+ i
] = cpystr(new_entries
[i
]);
825 abe_copy
->addr
.list
[tot_size
] = NULL
;
827 if(F_ON(F_DISABLE_TAKE_FULLNAMES
, ps_global
)){
828 for(i
= 0; abe_copy
->addr
.list
[i
]; i
++){
831 tmp_a_string
= cpystr(abe_copy
->addr
.list
[i
]);
832 rfc822_parse_adrlist(&a
, tmp_a_string
, fakedomain
);
834 fs_give((void **) &tmp_a_string
);
837 simple_a
= simple_addr_string(a
, tmp_20k_buf
, SIZEOF_20KBUF
);
838 mail_free_address(&a
);
841 /* replace the old addr string with one with no full name */
842 if(simple_a
&& *simple_a
){
843 if(abe_copy
->addr
.list
[i
])
844 fs_give((void **) &abe_copy
->addr
.list
[i
]);
846 abe_copy
->addr
.list
[i
] = cpystr(simple_a
);
851 edit_entry(abook
, abe_copy
, (a_c_arg_t
) entry_num
, old_tag
, 0, NULL
, cmd
);
856 restore_state(&((*tas
)->state
));
860 restore_state(&state
);
864 take_to_addrbooks_cancel
:
865 q_status_message(SM_INFO
, 0, 2, _("Address book addition cancelled"));
867 restore_state(&((*tas
)->state
));
871 restore_state(&state
);
876 * Prep addrbook for TakeAddr add operation.
878 * Arg: savep -- Address of a pointer to save addrbook state in.
879 * stp -- Address of a pointer to save addrbook state in.
881 * Returns: a PerAddrBook pointer, or NULL.
884 setup_for_addrbook_add(SAVE_STATE_S
*state
, int command_line
, char *cmd
)
887 int save_rem_abook_valid
= 0;
892 if(as
.n_addrbk
== 0){
893 q_status_message(SM_ORDER
, 3, 4, _("No address book configured!"));
897 pab
= use_this_addrbook(command_line
, cmd
);
902 if((pab
->type
& REMOTE_VIA_IMAP
) && ps_global
->remote_abook_validity
== -1){
903 save_rem_abook_valid
= -1;
904 ps_global
->remote_abook_validity
= 0;
907 /* initialize addrbook so we can add to it */
908 init_abook(pab
, Open
);
910 if(save_rem_abook_valid
)
911 ps_global
->remote_abook_validity
= save_rem_abook_valid
;
913 if(pab
->ostatus
!= Open
){
914 q_status_message(SM_ORDER
, 3, 4, _("Can't open address book!"));
918 if(pab
->access
!= ReadWrite
){
919 if(pab
->access
== ReadOnly
)
920 q_status_message(SM_ORDER
, 0, 4, _("AddressBook is Read Only"));
921 else if(pab
->access
== NoAccess
)
922 q_status_message(SM_ORDER
, 3, 4,
923 _("AddressBook not accessible, permission denied"));
933 * Interact with user to figure out which address book they want to add a
934 * new entry (TakeAddr) to.
936 * Args: command_line -- just the line to prompt on
938 * Results: returns a pab pointing to the selected addrbook, or NULL.
941 use_this_addrbook(int command_line
, char *cmd
)
945 PerAddrBook
*pab
, *the_only_pab
;
946 #define MAX_ABOOK 2000
947 int i
, abook_num
, count_read_write
;
948 char addrbook
[MAX_ABOOK
+ 1],
949 prompt
[MAX_ABOOK
+ 81];
950 static ESCKEY_S ekey
[] = {
952 {ctrl('P'), 10, "^P", N_("Prev AddrBook")},
953 {ctrl('N'), 11, "^N", N_("Next AddrBook")},
954 {KEY_UP
, 10, "", ""},
955 {KEY_DOWN
, 11, "", ""},
956 {-1, 0, NULL
, NULL
}};
958 dprint((9, "- use_this_addrbook -\n"));
960 /* check for only one ReadWrite addrbook */
961 count_read_write
= 0;
962 for(i
= 0; i
< as
.n_addrbk
; i
++){
965 * NoExists is counted, too, so the user can add to an empty
966 * addrbook the first time.
968 if(pab
->access
== ReadWrite
||
969 pab
->access
== NoExists
||
970 pab
->access
== MaybeRorW
){
972 the_only_pab
= &as
.adrbks
[i
];
976 /* only one usable addrbook, use it */
977 if(count_read_write
== 1)
978 return(the_only_pab
);
980 /* no addrbook to write to */
981 if(count_read_write
== 0){
982 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
983 "No %sAddressbook to %s to!",
984 (as
.n_addrbk
> 0) ? "writable " : "", cmd
);
988 /* start with the first addrbook */
990 pab
= &as
.adrbks
[abook_num
];
991 strncpy(addrbook
, pab
->abnick
, sizeof(addrbook
)-1);
992 addrbook
[sizeof(addrbook
)-1] = '\0';
993 snprintf(prompt
, sizeof(prompt
), "%c%s to which addrbook : %s",
994 islower((unsigned char)(*cmd
)) ? toupper((unsigned char)*cmd
) : *cmd
,
996 (pab
->access
== ReadOnly
|| pab
->access
== NoAccess
) ?
998 prompt
[sizeof(prompt
)-1] = '\0';
1000 ps_global
->mangled_footer
= 1;
1005 q_status_message1(SM_ORDER
, 3, 4, _("No addressbook \"%s\""),
1009 help
= (help
== NO_HELP
? h_oe_chooseabook
: NO_HELP
);
1011 flags
= OE_APPEND_CURRENT
;
1012 rc
= optionally_enter(addrbook
, command_line
, 0, sizeof(addrbook
),
1013 prompt
, ekey
, help
, &flags
);
1015 if(rc
== 1){ /* ^C */
1018 snprintf(capcmd
, sizeof(capcmd
),
1020 islower((unsigned char)(*cmd
)) ? toupper((unsigned char)*cmd
)
1023 capcmd
[sizeof(capcmd
)-1] = '\0';
1024 cmd_cancelled(capcmd
);
1028 if(rc
== 10){ /* Previous addrbook */
1030 abook_num
= as
.n_addrbk
- 1;
1032 pab
= &as
.adrbks
[abook_num
];
1033 strncpy(addrbook
, pab
->abnick
, sizeof(addrbook
)-1);
1034 addrbook
[sizeof(addrbook
)-1] = '\0';
1035 snprintf(prompt
, sizeof(prompt
), "%s to which addrbook : %s", cmd
,
1036 (pab
->access
== ReadOnly
|| pab
->access
== NoAccess
) ?
1037 "[ReadOnly] " : "");
1038 prompt
[sizeof(prompt
)-1] = '\0';
1040 else if(rc
== 11){ /* Next addrbook */
1041 if(++abook_num
> as
.n_addrbk
- 1)
1044 pab
= &as
.adrbks
[abook_num
];
1045 strncpy(addrbook
, pab
->abnick
, sizeof(addrbook
)-1);
1046 addrbook
[sizeof(addrbook
)-1] = '\0';
1047 snprintf(prompt
, sizeof(prompt
), "%s to which addrbook : %s", cmd
,
1048 (pab
->access
== ReadOnly
|| pab
->access
== NoAccess
) ?
1049 "[ReadOnly] " : "");
1050 prompt
[sizeof(prompt
)-1] = '\0';
1053 }while(rc
== 2 || rc
== 3 || rc
== 4 || rc
== 10 || rc
== 11 || rc
== 12 ||
1054 !(pab
= check_for_addrbook(addrbook
)));
1056 ps_global
->mangled_footer
= 1;
1066 * Return a pab pointer to the addrbook which corresponds to the argument.
1068 * Args: addrbook -- the string representing the addrbook.
1070 * Results: returns a PerAddrBook pointer for the referenced addrbook, NULL
1071 * if none. First the nicknames are checked and then the filenames.
1072 * This must be one of the existing addrbooks.
1075 check_for_addrbook(char *addrbook
)
1078 register PerAddrBook
*pab
;
1080 for(i
= 0; i
< as
.n_addrbk
; i
++){
1081 pab
= &as
.adrbks
[i
];
1082 if(strcmp(pab
->abnick
, addrbook
) == 0)
1089 for(i
= 0; i
< as
.n_addrbk
; i
++){
1090 pab
= &as
.adrbks
[i
];
1091 if(strcmp(pab
->filename
, addrbook
) == 0)
1103 * Screen for selecting which addresses to Take to address book.
1105 * Args: ps -- Pine state
1106 * ta_list -- Screen is formed from this list of addresses
1107 * how_many_selected -- how many checked initially in ListMode
1108 * mode -- which mode to start in
1110 * Result: an address book may be updated
1111 * Returns -- 0 normally
1112 * 1 if it returns before redrawing screen
1115 takeaddr_screen(struct pine
*ps
, TA_S
*ta_list
, int how_many_selected
,
1116 ScreenMode mode
, TA_STATE_S
**tas
, char *command
)
1119 int cmd
, dline
, give_warn_message
, command_line
;
1121 directly_to_take
= 0,
1124 TA_S
*current
= NULL
,
1129 struct key_menu
*km
= NULL
;
1131 dprint((2, "- takeaddr_screen -\n"));
1133 command_line
= -FOOTER_ROWS(ps
); /* third line from the bottom */
1135 screen
.current
= screen
.top_line
= NULL
;
1138 if(ta_list
== NULL
){
1139 /* TRANSLATORS: something like
1140 No addresses to save, cancelled */
1141 q_status_message1(SM_INFO
, 0, 2, "No addresses to %s, cancelled",
1146 current
= first_sel_taline(ta_list
);
1147 ps
->mangled_screen
= 1;
1148 ta_screen
= &screen
;
1150 if(is_talist_of_one(current
)){
1152 screen
.mode
= SingleMode
;
1154 else if(screen
.mode
== ListMode
)
1155 q_status_message(SM_INFO
, 0, 1,
1156 _("List mode: Use \"X\" to mark addresses to be included in list"));
1158 q_status_message(SM_INFO
, 0, 1,
1159 _("Single mode: Use \"P\" or \"N\" to select desired address"));
1166 ps
->mangled_body
= 1;
1170 if(screen
.mode
== ListMode
)
1171 ps
->redrawer
= takeaddr_screen_redrawer_list
;
1173 ps
->redrawer
= takeaddr_screen_redrawer_single
;
1175 if(ps
->mangled_screen
){
1176 ps
->mangled_header
= 1;
1177 ps
->mangled_footer
= 1;
1178 ps
->mangled_body
= 1;
1179 ps
->mangled_screen
= 0;
1182 /*----------- Check for new mail -----------*/
1183 if(new_mail(0, NM_TIMING(ch
), NM_STATUS_MSG
| NM_DEFER_SORT
) >= 0)
1184 ps
->mangled_header
= 1;
1187 mswin_beginupdate();
1189 if(ps
->mangled_header
){
1192 snprintf(tbuf
, sizeof(tbuf
), "TAKE ADDRESS SCREEN (%s Mode)",
1193 (screen
.mode
== ListMode
) ? "List"
1195 tbuf
[sizeof(tbuf
)-1] = '\0';
1196 set_titlebar(tbuf
, ps
->mail_stream
, ps
->context_current
,
1197 ps
->cur_folder
, ps
->msgmap
, 1, FolderName
, 0, 0,
1199 ps
->mangled_header
= 0;
1202 dline
= update_takeaddr_screen(ps
, current
, &screen
, &cursor_pos
);
1203 if(F_OFF(F_SHOW_CURSOR
, ps
)){
1204 cursor_pos
.row
= ps
->ttyo
->screen_rows
- FOOTER_ROWS(ps
);
1208 /*---- This displays new mail notification, or errors ---*/
1210 FOOTER_ROWS(ps_global
) = 3;
1211 mark_status_unknown();
1214 display_message(ch
);
1216 FOOTER_ROWS(ps_global
) = 1;
1217 mark_status_unknown();
1220 /*---- Redraw footer ----*/
1221 if(ps
->mangled_footer
){
1225 FOOTER_ROWS(ps
) = 3;
1230 ps
->mangled_footer
= 0;
1232 km
= (screen
.mode
== ListMode
) ? &ta_keymenu_lm
: &ta_keymenu_sm
;
1234 menu_clear_binding(km
, KEY_LEFT
);
1235 menu_clear_binding(km
, KEY_RIGHT
);
1236 if(F_ON(F_ARROW_NAV
, ps_global
)){
1239 if((cmd
= menu_clear_binding(km
, '<')) != MC_UNKNOWN
){
1240 menu_add_binding(km
, '<', cmd
);
1241 menu_add_binding(km
, KEY_LEFT
, cmd
);
1244 if((cmd
= menu_clear_binding(km
, '>')) != MC_UNKNOWN
){
1245 menu_add_binding(km
, '>', cmd
);
1246 menu_add_binding(km
, KEY_RIGHT
, cmd
);
1250 draw_keymenu(km
, bitmap
, ps
->ttyo
->screen_cols
,
1251 1 - FOOTER_ROWS(ps_global
), 0, FirstMenu
);
1254 FOOTER_ROWS(ps
) = 1;
1255 mark_keymenu_dirty();
1262 /*------ Read the command from the keyboard ----*/
1263 MoveCursor(cursor_pos
.row
, cursor_pos
.col
);
1265 if(directly_to_take
){ /* bypass this screen */
1267 blank_keymenu(ps_global
->ttyo
->screen_rows
- 2, 0);
1271 mouse_in_content(KEY_MOUSE
, -1, -1, 0, 0);
1272 register_mfunc(mouse_in_content
, HEADER_ROWS(ps_global
), 0,
1273 ps_global
->ttyo
->screen_rows
- (FOOTER_ROWS(ps
)+1),
1274 ps_global
->ttyo
->screen_cols
);
1278 mswin_setscrollcallback(ta_scroll_callback
);
1280 ch
= READ_COMMAND(&utf8str
);
1282 clear_mfunc(mouse_in_content
);
1286 mswin_setscrollcallback(NULL
);
1288 cmd
= menu_command(ch
, km
);
1289 if (ta_screen
->current
)
1290 current
= ta_screen
->current
;
1308 case MC_HELP
: /* help! */
1309 if(FOOTER_ROWS(ps_global
) == 1 && km_popped
== 0){
1311 ps_global
->mangled_footer
= 1;
1315 helper(h_takeaddr_screen
, _("HELP FOR TAKE ADDRESS SCREEN"),
1317 ps
->mangled_screen
= 1;
1320 case MC_EXIT
: /* exit takeaddr screen */
1321 q_status_message(SM_INFO
, 0, 2, _("Address book addition cancelled"));
1327 if(ta_do_take(current
, how_many_selected
, command_line
, tas
,
1331 directly_to_take
= 0;
1335 case MC_CHARDOWN
: /* next list element */
1336 if((ctmp
= next_sel_taline(current
)) != NULL
)
1339 q_status_message(SM_INFO
, 0, 1, _("Already on last line."));
1343 case MC_CHARUP
: /* previous list element */
1344 if((ctmp
= pre_sel_taline(current
)) != NULL
)
1347 q_status_message(SM_INFO
, 0, 1, _("Already on first line."));
1351 case MC_PAGEDN
: /* page forward */
1352 give_warn_message
= 1;
1353 while(dline
++ < ps
->ttyo
->screen_rows
- FOOTER_ROWS(ps
)){
1354 if((ctmp
= next_sel_taline(current
)) != NULL
){
1356 give_warn_message
= 0;
1362 if(give_warn_message
)
1363 q_status_message(SM_INFO
, 0, 1, _("Already on last page."));
1367 case MC_PAGEUP
: /* page backward */
1368 /* move to top of screen */
1369 give_warn_message
= 1;
1370 while(dline
-- > HEADER_ROWS(ps_global
)){
1371 if((ctmp
= pre_sel_taline(current
)) != NULL
){
1373 give_warn_message
= 0;
1379 /* page back one screenful */
1380 while(++dline
< ps
->ttyo
->screen_rows
- FOOTER_ROWS(ps
)){
1381 if((ctmp
= pre_sel_taline(current
)) != NULL
){
1383 give_warn_message
= 0;
1389 if(give_warn_message
)
1390 q_status_message(SM_INFO
, 0, 1, _("Already on first page."));
1394 case MC_WHEREIS
: /* whereis */
1395 if((ctmp
= whereis_taline(current
)) != NULL
)
1398 ps
->mangled_footer
= 1;
1410 mouse_get_last(NULL
, &mp
);
1411 mp
.row
-= HEADER_ROWS(ps_global
);
1412 ctmp
= screen
.top_line
;
1414 if(screen
.mode
== SingleMode
){
1415 if(ta_do_take(current
, how_many_selected
, command_line
,
1419 directly_to_take
= 0;
1422 current
->checked
= !current
->checked
; /* flip it */
1423 how_many_selected
+= (current
->checked
? 1 : -1);
1427 while(mp
.row
&& ctmp
!= NULL
){
1429 do ctmp
= ctmp
->next
;
1430 while(ctmp
!= NULL
&& ctmp
->skip_it
&& !ctmp
->print
);
1433 if(ctmp
!= NULL
&& !ctmp
->skip_it
)
1443 ps
->mangled_screen
= 1;
1446 case MC_CHOICE
: /* [UN]select this addr */
1447 current
->checked
= !current
->checked
; /* flip it */
1448 how_many_selected
+= (current
->checked
? 1 : -1);
1451 case MC_SELALL
: /* select all */
1452 how_many_selected
= ta_mark_all(first_sel_taline(current
));
1453 ps
->mangled_body
= 1;
1456 case MC_UNSELALL
: /* unselect all */
1457 how_many_selected
= ta_unmark_all(first_sel_taline(current
));
1458 ps
->mangled_body
= 1;
1461 case MC_LISTMODE
: /* switch to SingleMode */
1462 if(screen
.mode
== ListMode
){
1463 screen
.mode
= SingleMode
;
1464 q_status_message(SM_INFO
, 0, 1,
1465 _("Single mode: Use \"P\" or \"N\" to select desired address"));
1468 screen
.mode
= ListMode
;
1469 q_status_message(SM_INFO
, 0, 1,
1470 _("List mode: Use \"X\" to mark addresses to be included in list"));
1472 if(how_many_selected
<= 1){
1474 ta_unmark_all(first_sel_taline(current
));
1475 current
->checked
= 1;
1476 how_many_selected
++;
1480 ps
->mangled_screen
= 1;
1484 case MC_NONE
: /* simple timeout */
1488 /* Unbound (or not dealt with) keystroke */
1495 bogus_command(ch
, F_ON(F_USE_FK
, ps
) ? "F1" : "?");
1499 bogus_utf8_command(utf8str
, F_ON(F_USE_FK
, ps
) ? "F1" : "?");
1504 ps
->mangled_screen
= 1;
1511 * Do what takeaddr_screen does except bypass the takeaddr_screen and
1512 * go directly to do_take.
1515 takeaddr_bypass(struct pine
*ps
, TA_S
*current
, TA_STATE_S
**tasp
)
1517 TA_SCREEN_S screen
; /* We have to fake out ta_do_take because */
1518 /* we're bypassing takeaddr_screen. */
1519 ta_screen
= &screen
;
1520 ta_screen
->mode
= SingleMode
;
1521 current
= first_sel_taline(current
);
1522 (void) ta_do_take(current
, 1, -FOOTER_ROWS(ps_global
), tasp
, _("save"));
1523 ps
->mangled_screen
= 1;
1531 ta_do_take(TA_S
*current
, int how_many_selected
, int command_line
,
1532 TA_STATE_S
**tas
, char *cmd
)
1534 return((ta_screen
->mode
== ListMode
)
1535 ? ta_take_marked_addrs(how_many_selected
,
1536 first_sel_taline(current
),
1537 command_line
, tas
, cmd
)
1538 : ta_take_single_addr(current
, command_line
, tas
, cmd
));
1543 * WhereIs for TakeAddr screen.
1545 * Returns the line match is found in or NULL.
1548 whereis_taline(TA_S
*current
)
1551 int rc
, found
= 0, wrapped
= 0, flags
;
1552 char *result
= NULL
, buf
[MAX_SEARCH
+1], tmp
[MAX_SEARCH
+20];
1553 static char last
[MAX_SEARCH
+1];
1555 static ESCKEY_S ekey
[] = {
1557 {ctrl('Y'), 10, "^Y", N_("Top")},
1558 {ctrl('V'), 11, "^V", N_("Bottom")},
1559 {-1, 0, NULL
, NULL
}};
1564 /*--- get string ---*/
1566 snprintf(tmp
, sizeof(tmp
), _("Word to find %s%.*s%s: "),
1567 (last
[0]) ? "[" : "",
1568 MAX_SEARCH
, (last
[0]) ? last
: "", /* MAX_SEARCH == sizeof(tmp) - 20 */
1569 (last
[0]) ? "]" : "");
1570 tmp
[sizeof(tmp
)-1] = '\0';
1572 flags
= OE_APPEND_CURRENT
| OE_KEEP_TRAILING_SPACE
;
1574 rc
= optionally_enter(buf
,-FOOTER_ROWS(ps_global
),0,sizeof(buf
),
1575 tmp
,ekey
,help
,&flags
);
1577 help
= help
== NO_HELP
? h_config_whereis
: NO_HELP
;
1578 else if(rc
== 0 || rc
== 1 || rc
== 10 || rc
== 11 || !buf
[0]){
1579 if(rc
== 0 && !buf
[0] && last
[0]){
1580 strncpy(buf
, last
, sizeof(buf
)-1);
1581 buf
[sizeof(buf
)-1] = '\0';
1588 if(rc
== 0 && buf
[0]){
1590 while((p
= next_taline(p
)) != NULL
)
1591 if(srchstr((char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
,
1592 SIZEOF_20KBUF
, p
->strvalue
),
1599 p
= first_taline(current
);
1602 if(srchstr((char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
,
1603 SIZEOF_20KBUF
, p
->strvalue
),
1614 current
= first_sel_taline(current
);
1615 result
= _("Searched to top");
1618 current
= last_sel_taline(current
);
1619 result
= _("Searched to bottom");
1623 result
= _("WhereIs cancelled");
1628 result
= wrapped
? _("Search wrapped to beginning") : _("Word found");
1629 strncpy(last
, buf
, sizeof(last
)-1);
1630 last
[sizeof(last
)-1] = '\0';
1633 q_status_message(SM_ORDER
,0,3,result
? result
: _("Word not found"));
1639 * Call the addrbook functions which add the checked addresses.
1641 * Args: how_many_selected -- how many addresses are checked
1642 * f_line -- the first ta line
1644 * Returns: 1 -- we're done, caller should return
1645 * 0 -- we're not done
1648 ta_take_marked_addrs(int how_many_selected
, TA_S
*f_line
, int command_line
,
1649 TA_STATE_S
**tas
, char *cmd
)
1654 if(how_many_selected
== 0){
1655 q_status_message(SM_ORDER
, 0, 4,
1656 _("No addresses marked for taking. Use ExitTake to leave TakeAddr screen"));
1660 if(how_many_selected
== 1){
1661 for(p
= f_line
; p
; p
= next_sel_taline(p
))
1662 if(p
->checked
&& !p
->skip_it
)
1667 (p
->nickname
&& p
->nickname
[0]) ? p
->nickname
: NULL
,
1668 (p
->fullname
&& p
->fullname
[0]) ? p
->fullname
: NULL
,
1669 (p
->fcc
&& p
->fcc
[0]) ? p
->fcc
: NULL
,
1670 (p
->comment
&& p
->comment
[0]) ? p
->comment
: NULL
,
1671 command_line
, tas
, cmd
);
1674 new_list
= list_of_checked(f_line
);
1675 for(p
= f_line
; p
; p
= next_sel_taline(p
))
1676 if(p
->checked
&& !p
->skip_it
)
1679 take_to_addrbooks_frontend(new_list
, p
? p
->nickname
: NULL
,
1680 p
? p
->fullname
: NULL
, NULL
, p
? p
->fcc
: NULL
,
1681 p
? p
->comment
: NULL
, command_line
, tas
, cmd
);
1682 free_list_array(&new_list
);
1690 ta_take_single_addr(TA_S
*cur
, int command_line
, TA_STATE_S
**tas
, char *cmd
)
1692 add_abook_entry(cur
,
1693 (cur
->nickname
&& cur
->nickname
[0]) ? cur
->nickname
: NULL
,
1694 (cur
->fullname
&& cur
->fullname
[0]) ? cur
->fullname
: NULL
,
1695 (cur
->fcc
&& cur
->fcc
[0]) ? cur
->fcc
: NULL
,
1696 (cur
->comment
&& cur
->comment
[0]) ? cur
->comment
: NULL
,
1697 command_line
, tas
, cmd
);
1704 * Manage display of the Take Address screen.
1706 * Args: ps -- pine state
1707 * current -- the current TA line
1708 * screen -- the TA screen
1709 * cursor_pos -- return good cursor position here
1712 update_takeaddr_screen(struct pine
*ps
, TA_S
*current
, TA_SCREEN_S
*screen
, Pos
*cursor_pos
)
1718 char buf1
[6*MAX_SCREEN_COLS
+ 30];
1719 char buf2
[6*MAX_SCREEN_COLS
+ 30 + 10];
1721 int screen_width
= ps
->ttyo
->screen_cols
;
1724 cpos
.row
= HEADER_ROWS(ps
); /* default return value */
1726 /* calculate top line of display */
1730 if (ta_screen
->top_line
){
1731 for(dline
= 0, ctmp
= ta_screen
->top_line
;
1732 ctmp
&& ctmp
!= current
; ctmp
= next_taline(ctmp
))
1735 if (ctmp
&& (dline
< ps
->ttyo
->screen_rows
- HEADER_ROWS(ps
)
1737 top_line
= ta_screen
->top_line
;
1742 ctmp
= top_line
= first_taline(current
);
1744 if(((dline
++) % (ps
->ttyo
->screen_rows
- HEADER_ROWS(ps
)
1745 - FOOTER_ROWS(ps
))) == 0)
1747 while(ctmp
!= current
&& (ctmp
= next_taline(ctmp
)));
1752 * Figure out how far down the top line is from the top and how many
1753 * total lines there are. Dumb to loop every time thru, but
1754 * there aren't that many lines, and it's cheaper than rewriting things
1755 * to maintain a line count in each structure...
1757 for(dline
= 0, ctmp
= pre_taline(top_line
); ctmp
; ctmp
= pre_taline(ctmp
))
1760 scroll_setpos(dline
);
1762 for(ctmp
= next_taline(top_line
); ctmp
; ctmp
= next_taline(ctmp
))
1765 scroll_setrange(ps
->ttyo
->screen_rows
- FOOTER_ROWS(ps
) - HEADER_ROWS(ps
),
1770 /* mangled body or new page, force redraw */
1771 if(ps
->mangled_body
|| screen
->top_line
!= top_line
)
1772 screen
->current
= NULL
;
1774 /* find width of longest line for nicer formatting */
1776 for(ctmp
= first_taline(top_line
); ctmp
; ctmp
= next_taline(ctmp
)){
1782 && longest
< (width
= utf8_width((char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
,
1783 SIZEOF_20KBUF
, ctmp
->strvalue
))))
1787 #define LENGTH_OF_THAT_STRING 5 /* "[X] " */
1788 longest
= MIN(longest
, ps
->ttyo
->screen_cols
);
1790 /* loop thru painting what's needed */
1791 for(dline
= 0, ctmp
= top_line
;
1792 dline
< ps
->ttyo
->screen_rows
- FOOTER_ROWS(ps
) - HEADER_ROWS(ps
);
1793 dline
++, ctmp
= next_taline(ctmp
)){
1796 * only fall thru painting if something needs painting...
1798 if(!ctmp
|| !screen
->current
|| ctmp
== screen
->current
||
1799 ctmp
== top_line
|| ctmp
== current
){
1800 ClearLine(dline
+ HEADER_ROWS(ps
));
1801 if(!ctmp
|| !ctmp
->strvalue
)
1806 if(ctmp
== current
){
1807 cpos
.row
= dline
+ HEADER_ROWS(ps
); /* col set below */
1814 j
= LENGTH_OF_THAT_STRING
;
1817 * Copy the value to a temp buffer expanding tabs, and
1818 * making sure not to write beyond screen right...
1820 q
= (char *) rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
,
1821 SIZEOF_20KBUF
, ctmp
->strvalue
);
1823 for(i
= 0; q
[i
] && j
< ps
->ttyo
->screen_cols
&& p
-buf1
< sizeof(buf1
); i
++){
1824 if(q
[i
] == ctrl('I')){
1827 while(j
< ps
->ttyo
->screen_cols
&& ((++j
)&0x07) && p
-buf1
< sizeof(buf1
));
1836 if(p
-buf1
< sizeof(buf1
))
1839 if(utf8_width(buf1
) < longest
){
1840 (void) utf8_pad_to_width(buf2
, buf1
, sizeof(buf2
), longest
, 1);
1841 /* it's expected to be in buf1 below */
1842 strncpy(buf1
, buf2
, sizeof(buf1
));
1843 buf1
[sizeof(buf1
)-1] = '\0';
1846 /* mark lines which have check marks */
1847 if(ctmp
== current
){
1848 if(screen
->mode
== ListMode
){
1849 snprintf(buf2
, sizeof(buf2
), "[%c] %s", ctmp
->checked
? 'X' : SPACE
, buf1
);
1850 buf2
[sizeof(buf2
)-1] = '\0';
1851 cpos
.col
= 1; /* position on the X */
1854 snprintf(buf2
, sizeof(buf2
), " %s", buf1
);
1855 buf2
[sizeof(buf2
)-1] = '\0';
1856 cpos
.col
= 5; /* 5 spaces before text */
1861 int width
, actual_width
;
1865 * In buf2 make ------string--------
1866 * which reaches all the way across the screen. String will
1867 * already have a leading and trailing space.
1869 width
= utf8_width(buf1
);
1871 if(width
> screen_width
){
1872 actual_width
= utf8_truncate(buf1
, screen_width
);
1873 /* it might be 1 less */
1874 if(actual_width
< screen_width
&& (len
=strlen(buf1
))+1 < sizeof(buf1
)){
1880 snprintf(buf2
, sizeof(buf2
), "%s%s",
1881 repeat_char((screen_width
-width
)/2, '-'), buf1
);
1882 buf2
[sizeof(buf2
)-1] = '\0';
1884 width
= utf8_width(buf2
);
1885 snprintf(buf2
+len
, sizeof(buf2
)-len
, "%s",
1886 repeat_char(screen_width
-width
, '-'));
1887 buf2
[sizeof(buf2
)-1] = '\0';
1891 if(screen
->mode
== ListMode
) /* 6*MAX_SCREEN_COLS + 24 = sizeof(buf2)-6 */
1892 snprintf(buf2
, sizeof(buf2
), "[%c] %.*s", ctmp
->checked
? 'X' : SPACE
,
1893 6*MAX_SCREEN_COLS
+ 24, buf1
);
1895 snprintf(buf2
, sizeof(buf2
), " %.*s", 6*MAX_SCREEN_COLS
+24, buf1
);
1897 buf2
[sizeof(buf2
)-1] = '\0';
1901 PutLine0(dline
+ HEADER_ROWS(ps
), 0, buf2
);
1907 ps
->mangled_body
= 0;
1908 screen
->top_line
= top_line
;
1909 screen
->current
= current
;
1918 takeaddr_screen_redrawer_list(void)
1920 ps_global
->mangled_body
= 1;
1921 (void)update_takeaddr_screen(ps_global
, ta_screen
->current
, ta_screen
,
1927 takeaddr_screen_redrawer_single(void)
1929 ps_global
->mangled_body
= 1;
1930 (void)update_takeaddr_screen(ps_global
, ta_screen
->current
, ta_screen
,
1935 /* jpf work in progress
1936 * Execute command to take addresses out of message and put in the address book
1938 * Args: ps -- pine state
1939 * msgmap -- the MessageMap
1940 * agg -- this is aggregate operation if set
1942 * Result: The entry is added to an address book.
1945 cmd_take_addr(struct pine
*ps
, MSGNO_S
*msgmap
, int agg
)
1947 TA_S
*ta_list
= NULL
;
1948 int how_many_selected
= 0, rtype
;
1950 /* Ask user what kind of Take they want to do */
1951 if(!agg
&& F_ON(F_ENABLE_ROLE_TAKE
, ps
)){
1952 rtype
= rule_setup_type(ps
,
1954 ((mn_get_total(msgmap
) > 0)
1955 ? (F_ON(F_ENABLE_TAKE_EXPORT
, ps
)
1956 ? (RS_INCADDR
| RS_INCEXP
)
1961 else if(F_ON(F_ENABLE_TAKE_EXPORT
, ps
) && mn_get_total(msgmap
) > 0)
1962 rtype
= rule_setup_type(ps
, RS_INCADDR
| RS_INCEXP
, "Take to : ");
1966 if(rtype
== 'x' || rtype
== 'Z'){
1968 cmd_cancelled(NULL
);
1969 else if(rtype
== 'Z')
1970 q_status_message(SM_ORDER
| SM_DING
, 3, 5,
1971 "Try turning on color with the Setup/Kolor command.");
1975 ps
->mangled_footer
= 1;
1981 LINES_TO_TAKE
*lines_to_take
= NULL
;
1983 rtype
= set_up_takeaddr('e', ps
, msgmap
, &ta_list
, &how_many_selected
,
1984 agg
? TA_AGG
: 0, NULL
);
1987 if(convert_ta_to_lines(ta_list
, &lines_to_take
)){
1988 while(lines_to_take
&& lines_to_take
->prev
)
1989 lines_to_take
= lines_to_take
->prev
;
1991 take_to_export(ps
, lines_to_take
);
1993 free_ltlines(&lines_to_take
);
1996 q_status_message(SM_ORDER
, 3, 4, _("Can't find anything to export"));
2009 role_take(ps
, msgmap
, rtype
);
2013 rtype
= set_up_takeaddr('a', ps
, msgmap
, &ta_list
, &how_many_selected
,
2014 agg
? TA_AGG
: 0, attached_addr_handler
);
2016 (void) takeaddr_screen(ps
, ta_list
, how_many_selected
,
2017 agg
? ListMode
: SingleMode
,
2028 free_talines(&ta_list
);
2029 env_for_pico_callback
= NULL
;
2030 body_for_pico_callback
= NULL
;
2032 return(rtype
>= 0 ? 1 : 0);
2037 attached_addr_handler(TA_S
*current
, int added
)
2040 int command_line
= -FOOTER_ROWS(ps_global
);
2042 snprintf(prompt
, sizeof(prompt
),
2043 "Take %d entries from attachment to addrbook all at once ",
2045 switch(want_to(prompt
, 'n', 'x', NO_HELP
, WT_NORM
)){
2047 if(take_without_edit(current
, added
, command_line
, NULL
, "take") >= 0)
2048 return(0); /* all taken care of */
2050 return(-1); /* problem */
2053 cmd_cancelled("Take");
2054 return(-1); /* problem */
2057 return(1); /* proceed */
2063 take_without_edit(TA_S
*ta_list
, int num_in_list
, int command_line
, TA_STATE_S
**tas
, char *cmd
)
2065 #define OURTMPBUFLEN 200
2066 PerAddrBook
*pab_dst
;
2067 SAVE_STATE_S state
; /* For saving state of addrbooks temporarily */
2068 int rc
, total_to_copy
= 0;
2069 int how_many_dups
= 0, how_many_to_copy
= 0, skip_dups
= 0;
2071 int err
= 0, need_write
= 0, we_cancel
= 0;
2072 adrbk_cntr_t new_entry_num
;
2073 char warn
[2][MAX_NICKNAME
+1];
2074 char tmp
[OURTMPBUFLEN
];
2076 SWOOP_S
*swoop_list
= NULL
, *sw
;
2078 dprint((2, "\n - take_without_edit(%d) - \n",
2081 /* move to beginning of the list */
2083 while(ta_list
->prev
)
2084 ta_list
= ta_list
->prev
;
2086 pab_dst
= setup_for_addrbook_add(&state
, command_line
, cmd
);
2090 swoop_list
= (SWOOP_S
*)fs_get((num_in_list
+1) * sizeof(SWOOP_S
));
2091 memset((void *)swoop_list
, 0, (num_in_list
+1) * sizeof(SWOOP_S
));
2095 * Look through all the vcards for those with nicknames already
2096 * existing in the destination abook (dups) and build a list of
2097 * entries to be acted on.
2099 for(current
= ta_list
; current
; current
= current
->next
){
2100 adrbk_cntr_t dst_enum
;
2102 if(current
->skip_it
)
2105 /* check to see if this nickname already exists in the dest abook */
2106 if(current
->nickname
&& current
->nickname
[0]){
2109 current
->checked
= 0;
2110 abe
= adrbk_lookup_by_nick(pab_dst
->address_book
,
2111 current
->nickname
, &dst_enum
);
2113 * This nickname already exists.
2117 sw
->dst_enum
= dst_enum
;
2118 if(how_many_dups
< 2){
2119 strncpy(warn
[how_many_dups
], current
->nickname
, MAX_NICKNAME
);
2120 warn
[how_many_dups
][MAX_NICKNAME
] = '\0';
2133 * If there are some nicknames which already exist in the selected
2134 * abook, ask user what to do.
2136 if(how_many_dups
> 0){
2137 if(how_many_dups
== 1){
2138 if(how_many_to_copy
== 1 && num_in_list
== 1){
2139 ret
= 'T'; /* use Take */
2141 (*tas
)->state
= state
;
2142 (*tas
)->pab
= pab_dst
;
2148 snprintf(tmp
, sizeof(tmp
),
2149 "Entry with nickname \"%.*s\" already exists, replace ",
2150 OURTMPBUFLEN
-50, warn
[0]);
2153 else if(how_many_dups
== 2)
2154 snprintf(tmp
, sizeof(tmp
),
2155 "Nicknames \"%.*s\" and \"%.*s\" already exist, replace ",
2156 (OURTMPBUFLEN
-50)/2, warn
[0], (OURTMPBUFLEN
-50)/2, warn
[1]);
2158 snprintf(tmp
, sizeof(tmp
), "%d of the nicknames already exist, replace ",
2161 switch(want_to(tmp
, 'n', 'x', h_ab_copy_dups
, WT_NORM
)){
2176 * Because the deletes happen immediately we have to delete from high
2177 * entry number towards lower entry numbers so that we are deleting
2178 * the correct entries. In order to do that we'll sort the swoop_list
2179 * to give us a safe order.
2181 if(!skip_dups
&& how_many_dups
> 1)
2182 qsort((qsort_t
*)swoop_list
, (size_t)num_in_list
, sizeof(*swoop_list
),
2185 we_cancel
= busy_cue("Saving addrbook entries", NULL
, 0);
2186 total_to_copy
= how_many_to_copy
- (skip_dups
? how_many_dups
: 0);
2189 * Add the list of entries to the destination abook.
2191 for(sw
= swoop_list
; sw
&& sw
->ta
; sw
++){
2193 char abuf
[MAX_ADDRESS
+ 1];
2196 if(skip_dups
&& sw
->dup
)
2200 * Delete existing dups and replace them.
2204 /* delete the existing entry */
2206 if(adrbk_delete(pab_dst
->address_book
,
2207 (a_c_arg_t
)sw
->dst_enum
, 1, 0, 0, 0) == 0){
2211 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
2212 "Error replacing entry in %.200s: %.200s",
2214 error_description(errno
));
2221 * We need to count the number of addresses in this entry in order
2222 * to tell the adrbk routines if it is a List or a Single, and in
2223 * order to pass the right stuff to be added.
2225 count_of_addrs
= count_addrs(sw
->ta
->addr
);
2226 tag
= (count_of_addrs
> 1) ? List
: Single
;
2228 if(sw
->ta
->addr
->mailbox
&& sw
->ta
->addr
->mailbox
[0]){
2229 char *scratch
, *p
, *t
, *u
;
2234 es
= est_size(sw
->ta
->addr
);
2235 scratch
= (char *) fs_get(es
* sizeof(char));
2237 rbuf
.f
= dummy_soutr
;
2241 rbuf
.end
= scratch
+es
-1;
2242 rfc822_output_address_list(&rbuf
, sw
->ta
->addr
, 0L, NULL
);
2244 if((p
= srchstr(scratch
, "@" RAWFIELD
)) != NULL
){
2246 if(*t
== '&'){ /* find "leading" token */
2247 *t
++ = ' '; /* replace token */
2248 *p
= '\0'; /* tie off string */
2249 u
= (char *)rfc822_base64((unsigned char *)t
,
2250 (unsigned long)strlen(t
), &l
);
2251 *p
= '@'; /* restore 'p' */
2252 rplstr(p
, es
-(p
-scratch
), 12, ""); /* clear special token */
2253 rplstr(t
, es
-(t
-scratch
), strlen(t
), u
); /* Null u is handled */
2255 fs_give((void **)&u
);
2257 else if(t
== scratch
)
2261 strncpy(abuf
, scratch
, sizeof(abuf
)-1);
2262 abuf
[sizeof(abuf
)-1] = '\0';
2265 fs_give((void **)&scratch
);
2273 * Now we have a clean slate to work with.
2275 if(total_to_copy
<= 1)
2276 rc
= adrbk_add(pab_dst
->address_book
,
2280 tag
== Single
? abuf
: NULL
,
2290 rc
= adrbk_append(pab_dst
->address_book
,
2293 tag
== Single
? abuf
: NULL
,
2303 * If the entry we copied is a list, we also have to add
2304 * the list members to the copy.
2306 if(rc
== 0 && tag
== List
){
2307 int i
, save_sort_rule
;
2308 ADDRESS
*a
, *save_next
;
2311 list
= (char **)fs_get((count_of_addrs
+ 1) * sizeof(char *));
2312 memset((void *)list
, 0, (count_of_addrs
+1) * sizeof(char *));
2314 for(a
= sw
->ta
->addr
; a
; a
= a
->next
){
2315 save_next
= a
->next
;
2318 if(a
->mailbox
&& a
->mailbox
[0]){
2319 char *scratch
, *p
, *t
, *u
;
2325 scratch
= (char *) fs_get(es
* sizeof(char));
2327 rbuf
.f
= dummy_soutr
;
2331 rbuf
.end
= scratch
+es
-1;
2332 rfc822_output_address_list(&rbuf
, a
, 0L, NULL
);
2334 if((p
= srchstr(scratch
, "@" RAWFIELD
)) != NULL
){
2336 if(*t
== '&'){ /* find "leading" token */
2337 *t
++ = ' '; /* replace token */
2338 *p
= '\0'; /* tie off string */
2339 u
= (char *)rfc822_base64((unsigned char *)t
,
2340 (unsigned long)strlen(t
), &l
);
2341 *p
= '@'; /* restore 'p' */
2342 rplstr(p
, es
-(p
-scratch
), 12, ""); /* clear special token */
2343 rplstr(t
, es
-(t
-scratch
), strlen(t
), u
); /* Null u is handled */
2345 fs_give((void **)&u
);
2347 else if(t
== scratch
)
2351 strncpy(abuf
, scratch
, sizeof(abuf
)-1);
2352 abuf
[sizeof(abuf
)-1] = '\0';
2355 fs_give((void **)&scratch
);
2360 list
[i
++] = cpystr(abuf
);
2361 a
->next
= save_next
;
2365 * We want it to copy the list in the exact order
2366 * without sorting it.
2368 save_sort_rule
= pab_dst
->address_book
->sort_rule
;
2369 pab_dst
->address_book
->sort_rule
= AB_SORT_RULE_NONE
;
2371 rc
= adrbk_nlistadd(pab_dst
->address_book
,
2372 (a_c_arg_t
)new_entry_num
, NULL
, NULL
,
2375 pab_dst
->address_book
->sort_rule
= save_sort_rule
;
2376 free_list_array(&list
);
2380 q_status_message1(SM_ORDER
| SM_DING
, 3, 5,
2381 "Error saving: %.200s",
2382 error_description(errno
));
2389 int sort_happened
= 0;
2391 if(adrbk_write(pab_dst
->address_book
, 0, NULL
, &sort_happened
, 0, 1)){
2397 ps_global
->mangled_screen
= 1;
2405 restore_state(&state
);
2408 fs_give((void **)&swoop_list
);
2410 ps_global
->mangled_footer
= 1;
2413 #define CAPCMDLEN 50
2414 char capcmd
[CAPCMDLEN
];
2417 snprintf(capcmd
, sizeof(capcmd
),
2419 islower((unsigned char)(*cmd
)) ? toupper((unsigned char)*cmd
)
2421 CAPCMDLEN
-2, cmd
+1);
2423 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
2424 "%.200s only partially completed", capcmd
);
2426 cmd_cancelled(capcmd
);
2428 else if(ret
!= 'T' && total_to_copy
> 0){
2431 snprintf(tmp
, sizeof(tmp
), "Saved %d %s to \"%.*s\"",
2433 (total_to_copy
> 1) ? "entries" : "entry",
2434 OURTMPBUFLEN
-30, pab_dst
->abnick
);
2435 q_status_message(SM_ORDER
, 4, 4, tmp
);
2443 * Special case interface to allow a more interactive Save in the case where
2444 * the user seems to be wanting to save an exact copy of an existing entry.
2445 * For example, they might be trying to save a copy of a list with the intention
2446 * of changing it a little bit. The regular save doesn't allow this, since no
2447 * editing takes place, but this version plops them into the address book
2451 take_this_one_entry(struct pine
*ps
, TA_STATE_S
**tasp
, AdrBk
*abook
, long int cur_line
)
2455 char *fcc
= NULL
, *comment
= NULL
, *fullname
= NULL
,
2458 int how_many_selected
;
2459 TA_S
*current
= NULL
;
2461 dl
= dlist(cur_line
);
2464 q_status_message(SM_ORDER
, 0, 4, _("Nothing to save, cancelled"));
2468 if(dl
->type
== ListHead
|| dl
->type
== Simple
){
2469 fcc
= (abe
->fcc
&& abe
->fcc
[0]) ? abe
->fcc
: NULL
;
2470 comment
= (abe
->extra
&& abe
->extra
[0]) ? abe
->extra
: NULL
;
2471 fullname
= (abe
->fullname
&& abe
->fullname
[0]) ? abe
->fullname
: NULL
;
2472 nickname
= (abe
->nickname
&& abe
->nickname
[0]) ? abe
->nickname
: NULL
;
2475 addr
= abe_to_address(abe
, dl
, abook
, &how_many_selected
);
2477 addr
= mail_newaddr();
2478 addr
->host
= cpystr("");
2479 addr
->mailbox
= cpystr("");
2486 * Special case. When user is saving an entry with a runtime
2487 * ldap lookup address, they may be doing it because the lookup
2488 * has become stale. Give them a way to get the old address out
2489 * of the lookup entry so they can save that, instead.
2491 if(!addr
->personal
&& !strncmp(addr
->mailbox
, RUN_LDAP
, LEN_RL
)){
2492 LDAP_SERV_S
*info
= NULL
;
2494 static ESCKEY_S backup_or_ldap
[] = {
2495 {'b', 'b', "B", N_("Backup")},
2496 {'l', 'l', "L", N_("LDAP")},
2497 {-1, 0, NULL
, NULL
}};
2499 info
= break_up_ldap_server(addr
->mailbox
+ LEN_RL
);
2500 if(info
&& info
->mail
&& *info
->mail
)
2501 i
= radio_buttons(_("Copy backup address or retain LDAP search criteria ? "),
2502 -FOOTER_ROWS(ps_global
), backup_or_ldap
,
2504 h_ab_backup_or_ldap
, RB_NORM
);
2509 rfc822_parse_adrlist(&a
, info
->mail
, fakedomain
);
2513 fs_give((void **)&addr
->mailbox
);
2515 fs_give((void **)&addr
->host
);
2517 addr
->mailbox
= a
->mailbox
;
2519 addr
->host
= a
->host
;
2521 mail_free_address(&a
);
2526 free_ldap_server_info(&info
);
2528 #endif /* ENABLE_LDAP */
2529 current
= fill_in_ta(¤t
, addr
, 0, (char *)NULL
);
2534 * The empty string for the last argument is significant. Fill_in_ta
2535 * copies the whole adrlist into a single TA if there is a print
2538 if(dl
->type
== ListHead
)
2539 current
= fill_in_ta(¤t
, addr
, 1, "");
2541 current
= fill_in_ta(¤t
, addr
, 0, (char *)NULL
);
2547 "default case in take_this_one_entry, shouldn't happen\n"));
2551 if(current
->strvalue
&& !strcmp(current
->strvalue
, "@")){
2552 fs_give((void **)¤t
->strvalue
);
2553 if(fullname
&& fullname
[0])
2554 current
->strvalue
= cpystr(fullname
);
2555 else if(nickname
&& nickname
[0])
2556 current
->strvalue
= cpystr(nickname
);
2558 current
->strvalue
= cpystr("?");
2560 convert_possibly_encoded_str_to_utf8(¤t
->strvalue
);
2564 mail_free_address(&addr
);
2567 current
= first_sel_taline(current
);
2568 if(fullname
&& *fullname
){
2569 current
->fullname
= cpystr(fullname
);
2570 convert_possibly_encoded_str_to_utf8(¤t
->fullname
);
2574 current
->fcc
= cpystr(fcc
);
2575 convert_possibly_encoded_str_to_utf8(¤t
->fcc
);
2578 if(comment
&& *comment
){
2579 current
->comment
= cpystr(comment
);
2580 convert_possibly_encoded_str_to_utf8(¤t
->comment
);
2583 if(nickname
&& *nickname
){
2584 current
->nickname
= cpystr(nickname
);
2585 convert_possibly_encoded_str_to_utf8(¤t
->nickname
);
2588 takeaddr_bypass(ps
, current
, tasp
);
2591 q_status_message(SM_ORDER
, 0, 4, _("Nothing to save, cancelled"));
2593 free_talines(¤t
);
2598 * Execute command to save addresses out of vcard attachment.
2601 save_vcard_att(struct pine
*ps
, int qline
, long int msgno
, ATTACH_S
*a
)
2603 int how_many_selected
, j
;
2604 TA_S
*current
= NULL
;
2605 TA_STATE_S tas
, *tasp
;
2608 dprint((2, "\n - saving vcard attachment - \n"));
2610 j
= radio_buttons(_("Save to address book or Export to filesystem ? "),
2611 qline
, save_or_export
, 's', 'x',
2612 h_ab_save_exp
, RB_NORM
|RB_SEQ_SENSITIVE
);
2616 q_status_message(SM_INFO
, 0, 2, _("Address book save cancelled"));
2620 export_vcard_att(ps
, qline
, msgno
, a
);
2627 q_status_message(SM_ORDER
, 3, 3, "can't happen in save_vcard_att");
2631 dprint((2, "\n - saving attachment into address book - \n"));
2632 ps
->mangled_footer
= 1;
2634 how_many_selected
= process_vcard_atts(ps
->mail_stream
, msgno
, NULL
,
2635 a
->body
, a
->number
, ¤t
);
2636 if(how_many_selected
> 0){
2639 if(how_many_selected
== 1){
2640 takeaddr_bypass(ps
, current
, NULL
);
2642 else if(take_without_edit(current
, how_many_selected
, qline
,
2643 &tasp
, "save") == 'T'){
2647 how_many_selected
-=
2648 eliminate_dups_but_not_us(first_sel_taline(current
));
2650 (void)takeaddr_screen(ps
, current
, how_many_selected
, SingleMode
,
2654 * If takeaddr_screen or its children didn't do this for us,
2658 restore_state(&(tas
.state
));
2661 else if(how_many_selected
== 0)
2662 q_status_message(SM_ORDER
, 0, 3,
2663 _("Save cancelled: no entries in attachment"));
2665 free_talines(¤t
);
2670 * Execute command to export vcard attachment.
2673 export_vcard_att(struct pine
*ps
, int qline
, long int msgno
, ATTACH_S
*a
)
2675 int how_many_selected
, i
;
2677 STORE_S
*srcstore
= NULL
;
2679 static ESCKEY_S vcard_or_addresses
[] = {
2680 {'a', 'a', "A", N_("Address List")},
2681 {'v', 'v', "V", N_("VCard")},
2682 {-1, 0, NULL
, NULL
}};
2685 q_status_message(SM_ORDER
, 0, 3,
2686 "Alpine demo can't export addresses to files");
2690 dprint((2, "\n - exporting vcard attachment - \n"));
2692 i
= radio_buttons(_("Export list of addresses or vCard text ? "),
2693 qline
, vcard_or_addresses
, 'a', 'x',
2694 h_ab_export_vcard
, RB_NORM
|RB_SEQ_SENSITIVE
);
2698 q_status_message(SM_INFO
, 0, 2, _("Address book export cancelled"));
2705 write_attachment(qline
, msgno
, a
, "EXPORT");
2709 q_status_message(SM_ORDER
, 3, 3, _("can't happen in export_vcard_att"));
2713 ps
->mangled_footer
= 1;
2715 how_many_selected
= process_vcard_atts(ps
->mail_stream
, msgno
, NULL
,
2716 a
->body
, a
->number
, ¤t
);
2718 * Run through all of the list and run through
2719 * the addresses in each ta->addr, writing them into a storage object.
2720 * Then export to filesystem.
2723 if(how_many_selected
> 0 &&
2724 (srcstore
= so_get(srctype
, NULL
, EDIT_ACCESS
)) != NULL
){
2728 for(current
= first_taline(current
);
2730 current
= next_taline(current
)){
2732 for(aa
= current
->addr
; aa
; aa
= aa
->next
){
2735 so_puts(srcstore
, addr_list_string(aa
, NULL
, 0));
2737 so_puts(srcstore
, "\n");
2743 simple_export(ps
, so_text(srcstore
), srctype
, "addresses", NULL
);
2745 q_status_message(SM_ORDER
, 0, 3, _("No addresses to export"));
2750 if(how_many_selected
== 0)
2751 q_status_message(SM_ORDER
, 0, 3, _("Nothing to export"));
2753 q_status_message(SM_ORDER
,0,2, _("Error allocating space"));
2759 take_to_export(struct pine
*ps
, LINES_TO_TAKE
*lines_to_take
)
2761 CONF_S
*ctmp
= NULL
, *first_line
= NULL
;
2762 OPT_SCREEN_S screen
;
2764 char *help_title
= _("HELP FOR TAKE EXPORT SCREEN");
2766 ScreenMode listmode
= SingleMode
;
2768 for(li
= lines_to_take
; li
; li
= li
->next
){
2770 new_confline(&ctmp
);
2771 ctmp
->flags
|= CF_STARTITEM
;
2772 if(li
->flags
& LT_NOSELECT
)
2773 ctmp
->flags
|= CF_NOSELECT
;
2774 else if(!first_line
)
2777 p
= li
->printval
? li
->printval
: "";
2779 if(ctmp
->flags
& CF_NOSELECT
)
2780 ctmp
->value
= cpystr(p
);
2784 /* 5 is for "[X] " */
2786 ctmp
->value
= (char *)fs_get((l
+1) * sizeof(char));
2787 snprintf(ctmp
->value
, l
+1, " %s", p
);
2788 ctmp
->value
[l
] = '\0';
2791 /* this points to data, it doesn't have its own copy */
2792 ctmp
->d
.t
.exportval
= li
->exportval
? li
->exportval
: NULL
;
2793 ctmp
->d
.t
.selected
= 0;
2794 ctmp
->d
.t
.listmode
= &listmode
;
2796 ctmp
->tool
= take_export_tool
;
2797 ctmp
->help_title
= help_title
;
2798 ctmp
->help
= h_takeexport_screen
;
2799 ctmp
->keymenu
= &take_export_keymenu_sm
;
2803 q_status_message(SM_ORDER
, 3, 3, _("No lines to export"));
2805 memset(&screen
, 0, sizeof(screen
));
2806 conf_scroll_screen(ps
, &screen
, first_line
, _("Take Export"), NULL
, 0, NULL
);
2812 take_export_tool(struct pine
*ps
, int cmd
, CONF_S
**cl
, unsigned int flags
)
2816 int some_selected
= 0, something_to_export
= 0;
2818 STORE_S
*srcstore
= NULL
;
2824 if((srcstore
= so_get(srctype
, NULL
, EDIT_ACCESS
)) != NULL
){
2825 if(*(*cl
)->d
.t
.listmode
== SingleMode
){
2827 if((*cl
)->d
.t
.exportval
&& (*cl
)->d
.t
.exportval
[0]){
2828 so_puts(srcstore
, (*cl
)->d
.t
.exportval
);
2829 so_puts(srcstore
, "\n");
2830 something_to_export
++;
2831 prompt_msg
= "selection";
2835 /* go to first line */
2836 for(ctmp
= *cl
; prev_confline(ctmp
); ctmp
= prev_confline(ctmp
))
2839 for(; ctmp
; ctmp
= next_confline(ctmp
))
2840 if(!(ctmp
->flags
& CF_NOSELECT
) && ctmp
->d
.t
.selected
){
2842 if(ctmp
->d
.t
.exportval
&& ctmp
->d
.t
.exportval
[0]){
2843 so_puts(srcstore
, ctmp
->d
.t
.exportval
);
2844 so_puts(srcstore
, "\n");
2845 something_to_export
++;
2846 prompt_msg
= "selections";
2853 q_status_message(SM_ORDER
, 0, 3, _("Error allocating space"));
2854 else if(something_to_export
)
2855 simple_export(ps
, so_text(srcstore
), srctype
, prompt_msg
, NULL
);
2856 else if(!some_selected
&& *(*cl
)->d
.t
.listmode
== ListMode
)
2857 q_status_message(SM_ORDER
, 0, 3, _("Use \"X\" to mark selections"));
2859 q_status_message(SM_ORDER
, 0, 3, _("Nothing to export"));
2867 if(*(*cl
)->d
.t
.listmode
== SingleMode
){
2869 * UnHide the checkboxes
2872 *(*cl
)->d
.t
.listmode
= ListMode
;
2874 /* go to first line */
2875 for(ctmp
= *cl
; prev_confline(ctmp
); ctmp
= prev_confline(ctmp
))
2878 for(; ctmp
; ctmp
= next_confline(ctmp
))
2879 if(!(ctmp
->flags
& CF_NOSELECT
) && ctmp
->value
){
2880 ctmp
->value
[0] = '[';
2881 ctmp
->value
[1] = ctmp
->d
.t
.selected
? 'X' : SPACE
;
2882 ctmp
->value
[2] = ']';
2883 ctmp
->keymenu
= &take_export_keymenu_lm
;
2888 * Hide the checkboxes
2891 *(*cl
)->d
.t
.listmode
= SingleMode
;
2893 /* go to first line */
2894 for(ctmp
= *cl
; prev_confline(ctmp
); ctmp
= prev_confline(ctmp
))
2897 for(; ctmp
; ctmp
= next_confline(ctmp
))
2898 if(!(ctmp
->flags
& CF_NOSELECT
) && ctmp
->value
){
2899 ctmp
->value
[0] = ctmp
->value
[1] = ctmp
->value
[2] = SPACE
;
2900 ctmp
->keymenu
= &take_export_keymenu_sm
;
2904 ps
->mangled_body
= ps
->mangled_footer
= 1;
2908 if((*cl
)->value
[1] == 'X'){
2909 (*cl
)->d
.t
.selected
= 0;
2910 (*cl
)->value
[1] = SPACE
;
2913 (*cl
)->d
.t
.selected
= 1;
2914 (*cl
)->value
[1] = 'X';
2917 ps
->mangled_body
= 1;
2921 /* go to first line */
2922 for(ctmp
= *cl
; prev_confline(ctmp
); ctmp
= prev_confline(ctmp
))
2925 for(; ctmp
; ctmp
= next_confline(ctmp
)){
2926 if(!(ctmp
->flags
& CF_NOSELECT
) && ctmp
->value
){
2927 ctmp
->d
.t
.selected
= 1;
2929 ctmp
->value
[1] = 'X';
2933 ps
->mangled_body
= 1;
2937 /* go to first line */
2938 for(ctmp
= *cl
; prev_confline(ctmp
); ctmp
= prev_confline(ctmp
))
2941 for(; ctmp
; ctmp
= next_confline(ctmp
)){
2942 if(!(ctmp
->flags
& CF_NOSELECT
) && ctmp
->value
){
2943 ctmp
->d
.t
.selected
= 0;
2945 ctmp
->value
[1] = SPACE
;
2949 ps
->mangled_body
= 1;
2953 retval
= simple_exit_cmd(flags
);
2966 * Save an LDAP directory entry somewhere
2968 * Args: ps -- pine struct
2969 * e -- the entry to save
2970 * save -- If this is set, then bypass the question about whether
2971 * to save or export and just do the save.
2974 save_ldap_entry(struct pine
*ps
, LDAP_CHOOSE_S
*e
, int save
)
2976 char *fullname
= NULL
,
2981 struct berval
**cn
= NULL
,
2993 dprint((2, "\n - save_ldap_entry - \n"));
2999 for(a
= ldap_first_attribute(e
->ld
, e
->selected_entry
, &ber
);
3001 a
= ldap_next_attribute(e
->ld
, e
->selected_entry
, ber
)){
3003 dprint((9, " %s", a
? a
: "?"));
3004 if(strcmp(a
, e
->info_used
->cnattr
) == 0){
3006 cn
= ldap_get_values_len(e
->ld
, e
->selected_entry
, a
);
3008 else if(strcmp(a
, e
->info_used
->mailattr
) == 0){
3010 mail
= ldap_get_values_len(e
->ld
, e
->selected_entry
, a
);
3012 else if(strcmp(a
, "electronicmail") == 0){
3014 elecmail
= ldap_get_values_len(e
->ld
, e
->selected_entry
, a
);
3016 else if(strcmp(a
, "comment") == 0){
3018 note
= ldap_get_values_len(e
->ld
, e
->selected_entry
, a
);
3020 else if(strcmp(a
, e
->info_used
->snattr
) == 0){
3022 sn
= ldap_get_values_len(e
->ld
, e
->selected_entry
, a
);
3024 else if(strcmp(a
, e
->info_used
->gnattr
) == 0){
3026 givenname
= ldap_get_values_len(e
->ld
, e
->selected_entry
, a
);
3028 else if(strcmp(a
, "telephonenumber") == 0){
3030 telephone
= ldap_get_values_len(e
->ld
, e
->selected_entry
, a
);
3032 else if(strcmp(a
, "title") == 0){
3034 title
= ldap_get_values_len(e
->ld
, e
->selected_entry
, a
);
3039 j
= radio_buttons(_("Save to address book or Export to filesystem ? "),
3040 -FOOTER_ROWS(ps
), save_or_export
, 's', 'x',
3041 h_ab_save_exp
, RB_NORM
);
3045 q_status_message(SM_INFO
, 0, 2, _("Address book save cancelled"));
3057 q_status_message(SM_ORDER
, 3, 3,
3058 "can't happen in save_ldap_ent");
3065 if(ALPINE_LDAP_can_use(elecmail
) && !mail
)
3068 ldap_value_free_len(elecmail
);
3073 if(save
){ /* save into the address book */
3079 int how_many_selected
= 0;
3082 if(ALPINE_LDAP_can_use(cn
))
3083 fullname
= cpystr(cn
[0]->bv_val
);
3084 if(ALPINE_LDAP_can_use(sn
))
3085 last
= cpystr(sn
[0]->bv_val
);
3086 if(ALPINE_LDAP_can_use(givenname
))
3087 first
= cpystr(givenname
[0]->bv_val
);
3089 if(ALPINE_LDAP_can_use(note
))
3094 for(len
= 0, num
= 0; ALPINE_LDAP_usable(cm
, num
); num
++)
3095 len
+= strlen(cm
[num
]->bv_val
) + 2;
3098 comment
= (char *)fs_get(len
* sizeof(char));
3101 while(ALPINE_LDAP_usable(cm
, num
)){
3102 sstrncpy(&d
, cm
[num
]->bv_val
, len
-(d
-comment
));
3104 if(ALPINE_LDAP_usable(cm
, num
))
3105 sstrncpy(&d
, "; ", len
-(d
-comment
));
3108 comment
[len
-1] = '\0';
3111 for(len
= 0, num
= 0; ALPINE_LDAP_usable(mail
, num
); num
++)
3112 len
+= strlen(mail
[num
]->bv_val
) + 2;
3114 /* paste the email addresses together */
3116 address
= (char *)fs_get(len
* sizeof(char));
3119 while(ALPINE_LDAP_usable(mail
, num
)){
3120 sstrncpy(&d
, mail
[num
]->bv_val
, len
-(d
-address
));
3122 if(ALPINE_LDAP_usable(mail
, num
))
3123 sstrncpy(&d
, ", ", len
-(d
-address
));
3126 address
[len
-1] = '\0';
3131 rfc822_parse_adrlist(&addr
, address
, fakedomain
);
3133 if(addr
&& fullname
&& !(first
&& last
)){
3135 fs_give((void **)&addr
->personal
);
3137 addr
->personal
= cpystr(fullname
);
3140 if(addr
&& e
->serv
&& *e
->serv
){ /* save by reference */
3141 char *dn
, *edn
= NULL
;
3143 dn
= ldap_get_dn(e
->ld
, e
->selected_entry
);
3145 edn
= add_backslash_escapes(dn
);
3146 our_ldap_dn_memfree(dn
);
3149 if(e
->serv
&& *e
->serv
&& edn
&& *edn
){
3150 char buf
[MAILTMPLEN
+1];
3151 char *backup_mail
= NULL
;
3153 how_many_selected
++;
3155 if(addr
&& addr
->mailbox
&& addr
->host
){
3156 strncpy(buf
, addr
->mailbox
, sizeof(buf
)-2),
3157 buf
[sizeof(buf
)-2] = '\0';
3158 strncat(buf
, "@", sizeof(buf
)-1-strlen(buf
));
3159 strncat(buf
, addr
->host
, sizeof(buf
)-1-strlen(buf
));
3160 buf
[sizeof(buf
)-1] = '\0';
3161 backup_mail
= cpystr(buf
);
3165 * We only need one addr which we will use to hold the
3166 * pointer to the query.
3169 mail_free_address(&addr
->next
);
3172 fs_give((void **)&addr
->mailbox
);
3174 fs_give((void **)&addr
->host
);
3176 fs_give((void **)&addr
->personal
);
3178 snprintf(buf
, sizeof(buf
),
3179 "%s%s /base=%s/scope=base/cust=(objectclass=*)%s%s",
3183 backup_mail
? "/mail=" : "",
3184 backup_mail
? backup_mail
: "");
3185 buf
[sizeof(buf
)-1] = '\0';
3188 fs_give((void **)&backup_mail
);
3191 * Put the search parameters in mailbox and put @ in
3192 * host so that expand_address accepts it as an unqualified
3193 * address and doesn't try to add localdomain.
3195 addr
->mailbox
= cpystr(buf
);
3196 addr
->host
= cpystr("@");
3200 fs_give((void **)&edn
);
3202 else{ /* save by value */
3203 how_many_selected
++;
3205 addr
= mail_newaddr();
3208 if(how_many_selected
> 0){
3209 TA_S
*current
= NULL
;
3212 * The empty string for the last argument is significant.
3213 * Fill_in_ta copies the whole adrlist into a single TA if
3214 * there is a print string.
3216 current
= fill_in_ta(¤t
, addr
, 1, "");
3217 current
= first_sel_taline(current
);
3219 if(first
&& last
&& current
){
3223 l
= strlen(last
) + 2 + strlen(first
);
3224 p
= (char *)fs_get((l
+1) * sizeof(char));
3225 snprintf(p
, l
, "%s, %s", last
, first
);
3227 current
->fullname
= p
;
3228 convert_possibly_encoded_str_to_utf8(¤t
->fullname
);
3231 if(comment
&& current
){
3232 current
->comment
= cpystr(comment
);
3233 convert_possibly_encoded_str_to_utf8(¤t
->comment
);
3237 * We don't want the personal name to make it into the address
3238 * field in an LDAP: query sort of address, so move it
3241 if(e
->serv
&& *e
->serv
&& current
&& fullname
){
3242 if(current
->fullname
)
3243 fs_give((void **)¤t
->fullname
);
3245 current
->fullname
= fullname
;
3247 convert_possibly_encoded_str_to_utf8(¤t
->fullname
);
3250 mail_free_address(&addr
);
3253 takeaddr_bypass(ps
, current
, NULL
);
3255 q_status_message(SM_ORDER
, 0, 4, "Nothing to save");
3257 free_talines(¤t
);
3260 q_status_message(SM_ORDER
, 0, 4, "Nothing to save");
3263 else if(export
){ /* export to filesystem */
3264 STORE_S
*srcstore
= NULL
;
3266 static ESCKEY_S text_or_vcard
[] = {
3267 {'t', 't', "T", N_("Text")},
3268 {'a', 'a', "A", N_("Addresses")},
3269 {'v', 'v', "V", N_("VCard")},
3270 {-1, 0, NULL
, NULL
}};
3273 _("Export text of entry, address, or VCard format ? "),
3274 -FOOTER_ROWS(ps
), text_or_vcard
, 't', 'x',
3275 h_ldap_text_or_vcard
, RB_NORM
);
3279 q_status_message(SM_INFO
, 0, 2, _("Address book export cancelled"));
3284 if(!(srcstore
= prep_ldap_for_viewing(ps
, e
, srctype
, NULL
)))
3285 q_status_message(SM_ORDER
, 0, 2, _("Error allocating space"));
3287 (void)simple_export(ps_global
, so_text(srcstore
), srctype
,
3295 if(ALPINE_LDAP_can_use(mail
)){
3298 if(!(srcstore
= so_get(srctype
, NULL
, EDIT_ACCESS
)))
3299 q_status_message(SM_ORDER
,0,2, _("Error allocating space"));
3301 for(num
= 0; ALPINE_LDAP_usable(mail
, num
); num
++){
3302 so_puts(srcstore
, mail
[num
]->bv_val
);
3303 so_puts(srcstore
, "\n");
3306 (void)simple_export(ps_global
, so_text(srcstore
),
3307 srctype
, "addresses", NULL
);
3316 if(!(srcstore
= so_get(srctype
, NULL
, EDIT_ACCESS
)))
3317 q_status_message(SM_ORDER
,0,2, _("Error allocating space"));
3320 VCARD_INFO_S
*vinfo
;
3322 vinfo
= (VCARD_INFO_S
*)fs_get(sizeof(VCARD_INFO_S
));
3323 memset((void *)vinfo
, 0, sizeof(VCARD_INFO_S
));
3325 if(ALPINE_LDAP_can_use(cn
))
3326 vinfo
->fullname
= berval_to_array(cn
);
3328 if(ALPINE_LDAP_can_use(note
))
3329 vinfo
->note
= berval_to_array(note
);
3331 if(ALPINE_LDAP_can_use(title
))
3332 vinfo
->title
= berval_to_array(title
);
3334 if(ALPINE_LDAP_can_use(telephone
))
3335 vinfo
->tel
= berval_to_array(telephone
);
3337 if(ALPINE_LDAP_can_use(mail
))
3338 vinfo
->email
= berval_to_array(mail
);
3340 if(ALPINE_LDAP_can_use(sn
))
3341 vinfo
->last
= cpystr(sn
[0]->bv_val
);
3343 if(ALPINE_LDAP_can_use(givenname
))
3344 vinfo
->first
= cpystr(givenname
[0]->bv_val
);
3346 gf_set_so_writec(&pc
, srcstore
);
3348 write_single_vcard_entry(ps_global
, pc
, vinfo
);
3350 free_vcard_info(&vinfo
);
3352 (void)simple_export(ps_global
, so_text(srcstore
),
3353 srctype
, "vcard text", NULL
);
3360 q_status_message(SM_ORDER
, 3, 3, "can't happen in text_or_vcard");
3366 ldap_value_free_len(cn
);
3368 ldap_value_free_len(mail
);
3370 ldap_value_free_len(elecmail
);
3372 ldap_value_free_len(note
);
3374 ldap_value_free_len(sn
);
3376 ldap_value_free_len(givenname
);
3378 ldap_value_free_len(telephone
);
3380 ldap_value_free_len(title
);
3382 fs_give((void **)&fullname
);
3384 fs_give((void **)&address
);
3386 fs_give((void **)&first
);
3388 fs_give((void **)&last
);
3390 fs_give((void **)&comment
);
3392 #endif /* ENABLE_LDAP */
3402 return(ta_scroll_down(-count
));
3407 while(i
&& ta_screen
->top_line
->next
){
3408 if(ta_screen
->top_line
== ta_screen
->current
){
3409 if(next_sel
= next_sel_taline(ta_screen
->current
)){
3410 ta_screen
->current
= next_sel
;
3411 ta_screen
->top_line
= next_taline(ta_screen
->top_line
);
3417 ta_screen
->top_line
= next_taline(ta_screen
->top_line
);
3426 ta_scroll_down(count
)
3430 return(ta_scroll_up(-count
));
3433 long page_size
= ps_global
->ttyo
->screen_rows
-
3434 FOOTER_ROWS(ps_global
) - HEADER_ROWS(ps_global
);
3436 TA_S
*first
= first_taline(ta_screen
->top_line
);
3440 for(ctmp
= ta_screen
->top_line
;
3441 ctmp
!= ta_screen
->current
; ctmp
= next_taline(ctmp
))
3443 while(i
&& ta_screen
->top_line
!= first
){
3444 ta_screen
->top_line
= pre_taline(ta_screen
->top_line
);
3447 if(dline
>= page_size
){
3448 ctmp
= pre_sel_taline(ta_screen
->current
);
3451 ta_screen
->top_line
= next_taline(ta_screen
->top_line
);
3454 for(; ctmp
!= ta_screen
->current
;
3455 ta_screen
->current
= pre_taline(ta_screen
->current
))
3464 int ta_scroll_to_pos(line
)
3470 for(dline
= 0, ctmp
= first_taline(ta_screen
->top_line
);
3471 ctmp
!= ta_screen
->top_line
; ctmp
= next_taline(ctmp
))
3477 return(ta_scroll_up(line
- dline
));
3481 ta_scroll_callback (cmd
, scroll_pos
)
3486 long page_size
= ps_global
->ttyo
->screen_rows
- HEADER_ROWS(ps_global
)
3487 - FOOTER_ROWS(ps_global
);
3490 case MSWIN_KEY_SCROLLUPLINE
:
3491 paint
= ta_scroll_down (scroll_pos
);
3494 case MSWIN_KEY_SCROLLDOWNLINE
:
3495 paint
= ta_scroll_up (scroll_pos
);
3498 case MSWIN_KEY_SCROLLUPPAGE
:
3499 paint
= ta_scroll_down (page_size
);
3502 case MSWIN_KEY_SCROLLDOWNPAGE
:
3503 paint
= ta_scroll_up (page_size
);
3506 case MSWIN_KEY_SCROLLTO
:
3507 paint
= ta_scroll_to_pos (scroll_pos
);
3512 update_takeaddr_screen(ps_global
, ta_screen
->current
, ta_screen
, (Pos
*)NULL
);
3517 #endif /* _WINDOWS */