2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2007 University of Washington
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 #include "../pith/headers.h" /* for os-dep and pith defs/includes */
16 #include "../pith/abdlc.h"
17 #include "../pith/state.h"
18 #include "../pith/conf.h"
19 #include "../pith/status.h"
20 #include "../pith/ldap.h"
21 #include "../pith/tempfile.h"
27 void initialize_dlc_cache(void);
28 int dlc_siblings(DL_CACHE_S
*, DL_CACHE_S
*);
29 DL_CACHE_S
*dlc_mgr(long, DlMgrOps
, DL_CACHE_S
*);
30 void free_cache_array(DL_CACHE_S
**, int);
31 DL_CACHE_S
*dlc_prev(DL_CACHE_S
*, DL_CACHE_S
*);
32 DL_CACHE_S
*dlc_next(DL_CACHE_S
*, DL_CACHE_S
*);
33 DL_CACHE_S
*get_global_top_dlc(DL_CACHE_S
*);
34 DL_CACHE_S
*get_global_bottom_dlc(DL_CACHE_S
*);
35 DL_CACHE_S
*get_top_dl_of_adrbk(int, DL_CACHE_S
*);
36 DL_CACHE_S
*get_bottom_dl_of_adrbk(int, DL_CACHE_S
*);
39 #define NO_PERMISSION _("[ Permission Denied ]")
40 /* TRANSLATORS: This is a heading referring to something that is readable
42 #define READONLY _(" (ReadOnly)")
43 /* TRANSLATORS: Not readable */
44 #define NOACCESS _(" (Un-readable)")
45 /* TRANSLATORS: Directories, as in LDAP Directories. A heading. */
46 #define OLDSTYLE_DIR_TITLE _("Directories")
49 /* data for the display list cache */
50 static DL_CACHE_S
*cache_array
= (DL_CACHE_S
*)NULL
;
51 static long valid_low
,
53 static int index_of_low
,
59 initialize_dlc_cache(void)
61 dprint((11, "- initialize_dlc_cache -\n"));
63 (void)dlc_mgr(NO_LINE
, Initialize
, (DL_CACHE_S
*)NULL
);
68 done_with_dlc_cache(void)
70 dprint((11, "- done_with_dlc_cache -\n"));
72 (void)dlc_mgr(NO_LINE
, DoneWithCache
, (DL_CACHE_S
*)NULL
);
77 * Returns 1 if the dlc's are related to each other, 0 otherwise.
79 * The idea is that if you are going to flush one of these dlcs from the
80 * cache you should also flush its partners. For example, if you flush one
81 * Listent from a list you should flush the entire entry including all the
82 * Listents and the ListHead. If you flush a DlcTitle, you should also
83 * flush the SubTitle and the TitleBlankTop.
86 dlc_siblings(DL_CACHE_S
*dlc1
, DL_CACHE_S
*dlc2
)
88 if(!dlc1
|| !dlc2
|| dlc1
->adrbk_num
!= dlc2
->adrbk_num
)
96 case DlcListBlankBottom
:
98 case DlcListClickHere
:
103 case DlcListBlankTop
:
104 case DlcListBlankBottom
:
106 case DlcListClickHere
:
108 return(dlc1
->dlcelnum
== dlc2
->dlcelnum
);
143 case DlcTitleBlankTop
:
148 case DlcTitleBlankTop
:
170 case DlcTitleDashTopCmb
:
172 case DlcTitleDashBottomCmb
:
173 case DlcTitleBlankBottomCmb
:
174 case DlcClickHereCmb
:
175 case DlcTitleBlankTopCmb
:
177 case DlcTitleDashTopCmb
:
179 case DlcTitleDashBottomCmb
:
180 case DlcTitleBlankBottomCmb
:
181 case DlcClickHereCmb
:
182 case DlcTitleBlankTopCmb
:
198 * Manage the display list cache.
200 * The cache is a circular array of DL_CACHE_S elements. It always
201 * contains a contiguous set of display lines.
202 * The lowest numbered line in the cache is
203 * valid_low, and the highest is valid_high. Everything in between is
204 * also valid. Index_of_low is where to look
205 * for the valid_low element in the circular array.
207 * We make calls to dlc_prev and dlc_next to get new entries for the cache.
208 * We need a starting value before we can do that.
210 * This returns a pointer to a dlc for the desired row. If you want the
211 * actual display list line you call dlist(row) instead of dlc_mgr.
214 dlc_mgr(long int row
, DlMgrOps op
, DL_CACHE_S
*dlc_start
)
216 int new_index
, known_index
, next_index
= 0;
217 DL_CACHE_S
*dlc
= (DL_CACHE_S
*)NULL
;
224 if(row
>= valid_low
&& row
<= valid_high
){ /* already cached */
226 new_index
= ((row
- valid_low
) + index_of_low
) % size_of_cache
;
227 dlc
= &cache_array
[new_index
];
230 else if(row
> valid_high
){ /* row is past where we've looked */
233 ((valid_high
- valid_low
) + index_of_low
) % size_of_cache
;
234 next_row
= valid_high
+ 1L;
236 /* we'll usually be looking for row = valid_high + 1 */
237 while(next_row
<= row
){
239 new_index
= (known_index
+ 1) % size_of_cache
;
242 dlc_next(&cache_array
[known_index
], &cache_array
[new_index
]);
245 * This means somebody changed the file out from underneath
246 * us. This would happen if dlc_next needed to ask for an
247 * abe to figure out what the type of the next row is, but
248 * adrbk_get_ae returned a NULL. I don't think that can
249 * happen, but if it does...
251 if(dlc
->type
== DlcNotSet
){
252 dprint((1, "dlc_next returned DlcNotSet\n"));
253 goto panic_abook_corrupt
;
256 if(n_cached
== size_of_cache
){ /* replaced low cache entry */
258 index_of_low
= (index_of_low
+ 1) % size_of_cache
;
266 known_index
= new_index
; /* for next time through loop */
269 else if(row
< valid_low
){ /* row is back up the screen */
271 known_index
= index_of_low
;
272 prev_row
= valid_low
- 1L;
274 while(prev_row
>= row
){
276 new_index
= (known_index
- 1 + size_of_cache
) % size_of_cache
;
278 dlc_prev(&cache_array
[known_index
], &cache_array
[new_index
]);
280 if(dlc
->type
== DlcNotSet
){
281 dprint((1, "dlc_prev returned DlcNotSet (1)\n"));
282 goto panic_abook_corrupt
;
285 if(n_cached
== size_of_cache
) /* replaced high cache entry */
292 (index_of_low
- 1 + size_of_cache
) % size_of_cache
;
295 known_index
= new_index
;
299 else if(op
== Initialize
){
303 if(!cache_array
|| size_of_cache
!= 3 * MAX(as
.l_p_page
,1)){
305 free_cache_array(&cache_array
, size_of_cache
);
307 size_of_cache
= 3 * MAX(as
.l_p_page
,1);
309 (DL_CACHE_S
*)fs_get(size_of_cache
* sizeof(DL_CACHE_S
));
310 memset((void *)cache_array
, 0, size_of_cache
* sizeof(DL_CACHE_S
));
313 /* this will return NULL below and the caller should ignore that */
316 * Flush all rows for a particular addrbook entry from the cache, but
317 * keep the cache alive and anchored in the same place. The particular
318 * entry is the one that dlc_start is one of the rows of.
320 else if(op
== FlushDlcFromCache
){
323 next_row
= dlc_start
->global_row
- 1;
324 for(; next_row
>= valid_low
; next_row
--){
325 next_index
= ((next_row
- valid_low
) + index_of_low
) %
327 if(!dlc_siblings(dlc_start
, &cache_array
[next_index
]))
331 low_entry
= next_row
+ 1L;
334 * If low_entry now points one past a ListBlankBottom, delete that,
335 * too, since it may not make sense anymore.
337 if(low_entry
> valid_low
){
338 next_index
= ((low_entry
-1L - valid_low
) + index_of_low
) %
340 if(cache_array
[next_index
].type
== DlcListBlankBottom
)
344 if(low_entry
> valid_low
){ /* invalidate everything >= this */
345 n_cached
-= (valid_high
- (low_entry
- 1L));
346 valid_high
= low_entry
- 1L;
350 * This is the tough case. That entry was the first thing cached,
351 * so we need to invalidate the whole cache. However, we also
352 * need to keep at least one thing cached for an anchor, so
353 * we need to get the dlc before this one and it should be a
354 * dlc not related to this same addrbook entry.
356 known_index
= index_of_low
;
357 prev_row
= valid_low
- 1L;
361 new_index
= (known_index
- 1 + size_of_cache
) % size_of_cache
;
363 dlc_prev(&cache_array
[known_index
], &cache_array
[new_index
]);
365 if(dlc
->type
== DlcNotSet
){
366 dprint((1, "dlc_prev returned DlcNotSet (2)\n"));
367 goto panic_abook_corrupt
;
372 (index_of_low
- 1 + size_of_cache
) % size_of_cache
;
374 if(!dlc_siblings(dlc_start
, dlc
))
377 known_index
= new_index
;
381 valid_high
= valid_low
;
385 * We have to anchor ourselves at a first element.
386 * Here's how we start at the top.
388 else if(op
== FirstEntry
){
389 initialize_dlc_cache();
391 dlc
= &cache_array
[0];
392 dlc
= get_global_top_dlc(dlc
);
393 dlc
->global_row
= row
;
398 /* And here's how we start from the bottom. */
399 else if(op
== LastEntry
){
400 initialize_dlc_cache();
402 dlc
= &cache_array
[0];
403 dlc
= get_global_bottom_dlc(dlc
);
404 dlc
->global_row
= row
;
410 * And here's how we start from an arbitrary position in the middle.
411 * We root the cache at display line row, so it helps if row is close
412 * to where we're going to be starting so that things are easy to find.
413 * The dl that goes with line row is dl_start from addrbook number
416 else if(op
== ArbitraryStartingPoint
){
419 initialize_dlc_cache();
421 dlc
= &cache_array
[0];
423 * Save this in case fill_in_dl_field needs to free the text
429 dlc
->global_row
= row
;
435 else if(op
== DoneWithCache
){
439 free_cache_array(&cache_array
, size_of_cache
);
445 q_status_message(SM_ORDER
| SM_DING
, 5, 10,
446 _("Addrbook changed unexpectedly, re-syncing..."));
448 _("addrbook changed while we had it open?, re-sync\n")));
450 "valid_low=%ld valid_high=%ld index_of_low=%d size_of_cache=%d\n",
451 valid_low
, valid_high
, index_of_low
, size_of_cache
));
453 "n_cached=%d new_index=%d known_index=%d next_index=%d\n",
454 n_cached
, new_index
, known_index
, next_index
));
456 "next_row=%ld prev_row=%ld row=%ld\n", next_row
, prev_row
, row
));
457 /* jump back to a safe starting point */
458 longjmp(addrbook_changed_unexpectedly
, 1);
464 free_cache_array(DL_CACHE_S
**c_array
, int size
)
469 for(i
= 0; i
< size
; i
++){
470 dlc
= &(*c_array
)[i
];
471 /* free any allocated space */
472 switch(dlc
->dl
.type
){
478 fs_give((void **)&dlc
->dl
.usst
);
486 fs_give((void **)c_array
);
491 * Get the dlc element that comes before "old". The function that calls this
492 * function is the one that keeps a cache and checks in the cache before
493 * calling here. New is a passed in pointer to a buffer where we fill in
497 dlc_prev(DL_CACHE_S
*old
, DL_CACHE_S
*new)
501 adrbk_cntr_t list_count
;
504 new->dlcelnum
= NO_NEXT
;
505 new->dlcoffset
= NO_NEXT
;
506 new->type
= DlcNotSet
;
507 pab
= &as
.adrbks
[old
->adrbk_num
];
512 if(old
->adrbk_num
== 0 && as
.config
&& as
.how_many_personals
== 0)
513 new->type
= DlcGlobDelim2
;
514 else if(old
->adrbk_num
== 0)
515 new->type
= DlcOneBeforeBeginning
;
516 else if(old
->adrbk_num
== as
.how_many_personals
)
517 new->type
= DlcGlobDelim2
;
519 new->type
= DlcTitleBlankTop
;
524 if(pab
->access
== NoAccess
)
525 new->type
= DlcTitleNoPerm
;
527 new->type
= DlcTitle
;
531 case DlcTitleBlankTop
:
532 new->adrbk_num
= old
->adrbk_num
- 1;
533 new->type
= DlcSubTitle
;
538 case DlcNoPermission
:
540 if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
)){
541 if(as
.n_addrbk
== 1 && as
.n_serv
== 0)
542 new->type
= DlcOneBeforeBeginning
;
544 new->type
= DlcTitleBlankBottomCmb
;
547 new->type
= DlcOneBeforeBeginning
;
558 el
= old
->dlcelnum
- 1;
560 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
570 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
571 if(abe
&& abe
->tag
== Single
)
572 new->type
= DlcSimple
;
573 else if(abe
&& abe
->tag
== List
)
574 new->type
= DlcListBlankBottom
;
576 else if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
)){
577 if(as
.n_addrbk
== 1 && as
.n_serv
== 0)
578 new->type
= DlcOneBeforeBeginning
;
580 new->type
= DlcTitleBlankBottomCmb
;
583 new->type
= DlcOneBeforeBeginning
;
595 el
= old
->dlcelnum
- 1;
597 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
607 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
608 if(abe
&& abe
->tag
== Single
){
609 new->type
= DlcListBlankTop
;
610 new->dlcelnum
= old
->dlcelnum
;
612 else if(abe
&& abe
->tag
== List
)
613 new->type
= DlcListBlankBottom
;
615 else if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
)){
616 if(as
.n_addrbk
== 1 && as
.n_serv
== 0)
617 new->type
= DlcOneBeforeBeginning
;
619 new->type
= DlcTitleBlankBottomCmb
;
622 new->type
= DlcOneBeforeBeginning
;
628 if(old
->dlcoffset
> 0){
629 new->type
= DlcListEnt
;
630 new->dlcelnum
= old
->dlcelnum
;
631 new->dlcoffset
= old
->dlcoffset
- 1;
634 new->type
= DlcListHead
;
635 new->dlcelnum
= old
->dlcelnum
;
640 case DlcListClickHere
:
642 new->type
= DlcListHead
;
643 new->dlcelnum
= old
->dlcelnum
;
646 case DlcListBlankTop
: /* can only occur between a Simple and a List */
647 new->type
= DlcSimple
;
654 el
= old
->dlcelnum
- 1;
656 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
667 dprint((1, "Bug in addrbook: case ListBlankTop with no selected entry\n"));
674 case DlcListBlankBottom
:
675 new->dlcelnum
= old
->dlcelnum
;
676 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
677 if(F_ON(F_EXPANDED_DISTLISTS
,ps_global
)
678 || exp_is_expanded(pab
->address_book
->exp
, (a_c_arg_t
)new->dlcelnum
)){
679 list_count
= listmem_count_from_abe(abe
);
681 new->type
= DlcListEmpty
;
683 new->type
= DlcListEnt
;
684 new->dlcoffset
= list_count
- 1;
688 new->type
= DlcListClickHere
;
693 if(as
.how_many_personals
== 0)
694 new->type
= DlcPersAdd
;
696 new->adrbk_num
= as
.how_many_personals
- 1;
697 new->type
= DlcSubTitle
;
702 new->type
= DlcGlobDelim1
;
706 new->type
= DlcOneBeforeBeginning
;
710 new->type
= DlcGlobDelim2
;
714 if(old
->adrbk_num
== 0 && as
.n_addrbk
== 0)
715 new->type
= DlcOneBeforeBeginning
;
716 else if(old
->adrbk_num
== 0)
717 new->type
= DlcDirDelim2
;
719 new->type
= DlcDirBlankTop
;
724 new->type
= DlcDirAccess
;
728 new->adrbk_num
= old
->adrbk_num
-1;
729 new->type
= DlcDirSubTitle
;
733 new->adrbk_num
= as
.n_addrbk
- 1;
735 new->type
= DlcNoAbooks
;
737 new = get_bottom_dl_of_adrbk(new->adrbk_num
, new);
742 new->type
= DlcDirDelim1
;
746 new->type
= DlcDirDelim1a
;
750 new->type
= DlcDirDelim1b
;
754 if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
))
755 new->type
= DlcDirDelim1c
;
757 new->type
= DlcDirDelim1
;
761 case DlcTitleDashTopCmb
:
762 if(old
->adrbk_num
== 0)
763 new->type
= DlcOneBeforeBeginning
;
765 new->type
= DlcTitleBlankTopCmb
;
770 new->type
= DlcTitleDashTopCmb
;
773 case DlcTitleDashBottomCmb
:
774 new->type
= DlcTitleCmb
;
777 case DlcTitleBlankBottomCmb
:
778 new->type
= DlcTitleDashBottomCmb
;
781 case DlcClickHereCmb
:
782 if(as
.n_addrbk
== 1 && as
.n_serv
== 0)
783 new->type
= DlcOneBeforeBeginning
;
785 new->type
= DlcTitleBlankBottomCmb
;
789 case DlcTitleBlankTopCmb
:
790 new->adrbk_num
= old
->adrbk_num
- 1;
791 new = get_bottom_dl_of_adrbk(new->adrbk_num
, new);
795 case DlcTwoBeforeBeginning
:
796 new->type
= DlcBeginning
;
799 case DlcOneBeforeBeginning
:
800 new->type
= DlcTwoBeforeBeginning
;
805 q_status_message(SM_ORDER
| SM_DING
, 5, 10,
806 _("Bug in addrbook, not supposed to happen, re-syncing..."));
807 dprint((1, "Bug in addrbook, impossible case (%d) in dlc_prev, re-sync\n",
809 /* jump back to a safe starting point */
810 longjmp(addrbook_changed_unexpectedly
, 1);
814 new->global_row
= old
->global_row
- 1L;
815 if(new->adrbk_num
== -2)
816 new->adrbk_num
= old
->adrbk_num
;
823 * Get the dlc element that comes after "old". The function that calls this
824 * function is the one that keeps a cache and checks in the cache before
828 dlc_next(DL_CACHE_S
*old
, DL_CACHE_S
*new)
832 adrbk_cntr_t ab_count
;
833 adrbk_cntr_t list_count
;
836 new->dlcelnum
= NO_NEXT
;
837 new->dlcoffset
= NO_NEXT
;
838 new->type
= DlcNotSet
;
839 pab
= &as
.adrbks
[old
->adrbk_num
];
844 new->type
= DlcSubTitle
;
848 if((old
->adrbk_num
== as
.how_many_personals
- 1) &&
849 (as
.config
|| as
.n_addrbk
> as
.how_many_personals
))
850 new->type
= DlcGlobDelim1
;
851 else if(as
.n_serv
&& !as
.config
&&
852 (old
->adrbk_num
== as
.n_addrbk
- 1))
853 new->type
= DlcDirDelim1
;
854 else if(old
->adrbk_num
== as
.n_addrbk
- 1)
857 new->adrbk_num
= old
->adrbk_num
+ 1;
858 new->type
= DlcTitleBlankTop
;
863 case DlcTitleBlankTop
:
864 if(pab
->access
== NoAccess
)
865 new->type
= DlcTitleNoPerm
;
867 new->type
= DlcTitle
;
873 case DlcNoPermission
:
874 case DlcClickHereCmb
:
875 if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
)){
876 if(old
->adrbk_num
< as
.n_addrbk
- 1){
877 new->adrbk_num
= old
->adrbk_num
+ 1;
878 new->type
= DlcTitleBlankTopCmb
;
881 new->type
= DlcDirDelim1
;
901 ab_count
= adrbk_count(pab
->address_book
);
904 el
= old
->dlcelnum
+ 1;
906 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
916 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
917 if(abe
&& abe
->tag
== Single
)
918 new->type
= DlcSimple
;
919 else if(abe
&& abe
->tag
== List
)
920 new->type
= DlcListBlankTop
;
922 else if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
)){
923 if(old
->adrbk_num
< as
.n_addrbk
- 1){
924 new->adrbk_num
= old
->adrbk_num
+ 1;
925 new->type
= DlcTitleBlankTopCmb
;
928 new->type
= DlcDirDelim1
;
939 new->dlcelnum
= old
->dlcelnum
;
940 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
941 if(F_ON(F_EXPANDED_DISTLISTS
,ps_global
)
942 || exp_is_expanded(pab
->address_book
->exp
, (a_c_arg_t
)new->dlcelnum
)){
943 list_count
= listmem_count_from_abe(abe
);
945 new->type
= DlcListEmpty
;
947 new->type
= DlcListEnt
;
952 new->type
= DlcListClickHere
;
957 new->dlcelnum
= old
->dlcelnum
;
958 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
959 list_count
= listmem_count_from_abe(abe
);
960 if(old
->dlcoffset
== list_count
- 1){ /* last member of list */
964 ab_count
= adrbk_count(pab
->address_book
);
967 el
= old
->dlcelnum
+ 1;
969 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
978 new->type
= DlcListBlankBottom
;
979 else if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
)){
980 if(old
->adrbk_num
< as
.n_addrbk
- 1){
981 new->adrbk_num
= old
->adrbk_num
+ 1;
982 new->type
= DlcTitleBlankTopCmb
;
985 new->type
= DlcDirDelim1
;
993 new->type
= DlcListEnt
;
994 new->dlcoffset
= old
->dlcoffset
+ 1;
999 case DlcListClickHere
:
1005 new->dlcelnum
= old
->dlcelnum
;
1006 ab_count
= adrbk_count(pab
->address_book
);
1009 el
= old
->dlcelnum
+ 1;
1010 while(i
< ab_count
){
1011 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
1020 new->type
= DlcListBlankBottom
;
1021 else if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
)){
1022 if(old
->adrbk_num
< as
.n_addrbk
- 1){
1023 new->adrbk_num
= old
->adrbk_num
+ 1;
1024 new->type
= DlcTitleBlankTopCmb
;
1027 new->type
= DlcDirDelim1
;
1037 case DlcListBlankTop
:
1038 new->type
= DlcListHead
;
1039 new->dlcelnum
= old
->dlcelnum
;
1042 case DlcListBlankBottom
:
1047 ab_count
= adrbk_count(pab
->address_book
);
1050 el
= old
->dlcelnum
+ 1;
1051 while(i
< ab_count
){
1052 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
1062 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
1063 if(abe
&& abe
->tag
== Single
)
1064 new->type
= DlcSimple
;
1065 else if(abe
&& abe
->tag
== List
)
1066 new->type
= DlcListHead
;
1076 new->type
= DlcGlobDelim2
;
1080 if(as
.config
&& as
.how_many_personals
== as
.n_addrbk
)
1081 new->type
= DlcGlobAdd
;
1083 new->adrbk_num
= as
.how_many_personals
;
1084 pab
= &as
.adrbks
[new->adrbk_num
];
1085 if(pab
->access
== NoAccess
)
1086 new->type
= DlcTitleNoPerm
;
1088 new->type
= DlcTitle
;
1094 if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
))
1095 new->type
= DlcDirDelim1a
;
1097 new->type
= DlcDirDelim2
;
1103 new->type
= DlcDirDelim1b
;
1107 new->type
= DlcDirDelim1c
;
1111 new->type
= DlcDirDelim2
;
1116 new->type
= DlcDirAccess
;
1121 new->type
= DlcGlobDelim1
;
1125 new->type
= DlcDirSubTitle
;
1128 case DlcDirSubTitle
:
1129 if(old
->adrbk_num
== as
.n_serv
- 1)
1132 new->type
= DlcDirBlankTop
;
1133 new->adrbk_num
= old
->adrbk_num
+ 1;
1138 case DlcDirBlankTop
:
1139 new->type
= DlcDirAccess
;
1142 case DlcTitleDashTopCmb
:
1143 new->type
= DlcTitleCmb
;
1147 new->type
= DlcTitleDashBottomCmb
;
1150 case DlcTitleDashBottomCmb
:
1151 new->type
= DlcTitleBlankBottomCmb
;
1154 case DlcTitleBlankBottomCmb
:
1155 pab
= &as
.adrbks
[old
->adrbk_num
];
1156 if(pab
->ostatus
!= Open
&& pab
->access
!= NoAccess
)
1157 new->type
= DlcClickHereCmb
;
1159 new = get_top_dl_of_adrbk(old
->adrbk_num
, new);
1163 case DlcTitleBlankTopCmb
:
1164 new->type
= DlcTitleDashTopCmb
;
1167 case DlcOneBeforeBeginning
:
1168 new = get_global_top_dlc(new);
1171 case DlcTwoBeforeBeginning
:
1172 new->type
= DlcOneBeforeBeginning
;
1176 q_status_message(SM_ORDER
| SM_DING
, 5, 10,
1177 _("Bug in addrbook, not supposed to happen, re-syncing..."));
1178 dprint((1, "Bug in addrbook, impossible case (%d) in dlc_next, re-sync\n",
1180 /* jump back to a safe starting point */
1181 longjmp(addrbook_changed_unexpectedly
, 1);
1185 new->global_row
= old
->global_row
+ 1L;
1186 if(new->adrbk_num
== -2)
1187 new->adrbk_num
= old
->adrbk_num
;
1194 * Get the display line at the very top of whole addrbook screen display.
1197 get_global_top_dlc(DL_CACHE_S
*new)
1198 /* fill in answer here */
1202 new->dlcelnum
= NO_NEXT
;
1203 new->dlcoffset
= NO_NEXT
;
1204 new->type
= DlcNotSet
;
1206 if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
) && !as
.config
){
1208 if(as
.n_addrbk
> 1 || (as
.n_serv
&& as
.n_addrbk
== 1))
1209 new->type
= DlcTitleDashTopCmb
;
1210 else if(as
.n_addrbk
== 1)
1211 new = get_top_dl_of_adrbk(new->adrbk_num
, new);
1212 else if(as
.n_serv
> 0){ /* 1st directory */
1213 new->type
= DlcDirAccess
;
1217 new->type
= DlcNoAbooks
;
1223 if(as
.how_many_personals
== 0) /* no personals */
1224 new->type
= DlcPersAdd
;
1226 pab
= &as
.adrbks
[new->adrbk_num
]; /* 1st personal */
1227 if(pab
->access
== NoAccess
)
1228 new->type
= DlcTitleNoPerm
;
1230 new->type
= DlcTitle
;
1233 else if(any_ab_open()){
1234 new->adrbk_num
= as
.cur
;
1235 new = get_top_dl_of_adrbk(new->adrbk_num
, new);
1237 else if(as
.n_addrbk
> 0){ /* 1st addrbook */
1238 pab
= &as
.adrbks
[new->adrbk_num
];
1239 if(pab
->access
== NoAccess
)
1240 new->type
= DlcTitleNoPerm
;
1242 new->type
= DlcTitle
;
1244 else if(as
.n_serv
> 0){ /* 1st directory */
1245 new->type
= DlcDirAccess
;
1249 new->type
= DlcNoAbooks
;
1257 * Get the last display line for the whole address book screen.
1258 * This gives us a way to start at the end and move back up.
1261 get_global_bottom_dlc(DL_CACHE_S
*new)
1262 /* fill in answer here */
1264 new->dlcelnum
= NO_NEXT
;
1265 new->dlcoffset
= NO_NEXT
;
1266 new->type
= DlcNotSet
;
1268 if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
) && !as
.config
){
1270 new->type
= DlcDirSubTitle
;
1271 new->adrbk_num
= as
.n_serv
- 1;
1273 else if(as
.n_addrbk
> 0){
1274 new->adrbk_num
= as
.n_addrbk
- 1;
1275 new = get_bottom_dl_of_adrbk(new->adrbk_num
, new);
1278 new->type
= DlcNoAbooks
;
1281 new->adrbk_num
= MAX(as
.n_addrbk
- 1, 0);
1284 if(as
.how_many_personals
== as
.n_addrbk
) /* no globals */
1285 new->type
= DlcGlobAdd
;
1287 new->type
= DlcSubTitle
;
1289 else if(any_ab_open()){
1290 new->adrbk_num
= as
.cur
;
1291 new = get_bottom_dl_of_adrbk(new->adrbk_num
, new);
1294 new->type
= DlcDirSubTitle
;
1295 new->adrbk_num
= as
.n_serv
- 1;
1297 else{ /* !config && !opened && !n_serv */
1299 new->type
= DlcSubTitle
;
1301 new->type
= DlcNoAbooks
;
1310 * First dl in a particular addrbook, not counting title lines.
1311 * Assumes as.opened.
1314 get_top_dl_of_adrbk(int adrbk_num
, DL_CACHE_S
*new)
1316 /* fill in answer here */
1320 adrbk_cntr_t ab_count
;
1322 pab
= &as
.adrbks
[adrbk_num
];
1323 new->adrbk_num
= adrbk_num
;
1325 if(pab
->access
== NoAccess
)
1326 new->type
= DlcNoPermission
;
1331 ab_count
= adrbk_count(pab
->address_book
);
1335 /* find first displayed entry */
1336 while(i
< ab_count
){
1337 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
1347 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
1348 if(abe
&& abe
->tag
== Single
)
1349 new->type
= DlcSimple
;
1350 else if(abe
&& abe
->tag
== List
)
1351 new->type
= DlcListHead
;
1354 new->type
= DlcZoomEmpty
;
1356 new->type
= DlcEmpty
;
1364 * Find the last display line for addrbook number adrbk_num.
1365 * Assumes as.opened (unless OLD_ABOOK_DISP).
1368 get_bottom_dl_of_adrbk(int adrbk_num
, DL_CACHE_S
*new)
1370 /* fill in answer here */
1374 adrbk_cntr_t ab_count
;
1375 adrbk_cntr_t list_count
;
1377 pab
= &as
.adrbks
[adrbk_num
];
1378 new->adrbk_num
= adrbk_num
;
1380 if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
) && pab
->ostatus
!= Open
){
1381 if(pab
->access
== NoAccess
)
1382 new->type
= DlcNoPermission
;
1384 new->type
= DlcClickHereCmb
;
1386 else if(F_OFF(F_CMBND_ABOOK_DISP
,ps_global
) && pab
->ostatus
!= Open
){
1387 new->type
= DlcSubTitle
;
1390 if(pab
->access
== NoAccess
)
1391 new->type
= DlcNoPermission
;
1396 ab_count
= adrbk_count(pab
->address_book
);
1399 /* find last displayed entry */
1401 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
1411 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
)new->dlcelnum
);
1412 if(abe
&& abe
->tag
== Single
)
1413 new->type
= DlcSimple
;
1414 else if(abe
&& abe
->tag
== List
){
1415 if(F_ON(F_EXPANDED_DISTLISTS
,ps_global
)
1416 || exp_is_expanded(pab
->address_book
->exp
,
1417 (a_c_arg_t
)new->dlcelnum
)){
1418 list_count
= listmem_count_from_abe(abe
);
1420 new->type
= DlcListEmpty
;
1422 new->type
= DlcListEnt
;
1423 new->dlcoffset
= list_count
- 1;
1427 new->type
= DlcListClickHere
;
1431 new->type
= DlcZoomEmpty
;
1433 new->type
= DlcEmpty
;
1443 * This returns the actual dlc instead of the dl within the dlc.
1446 get_dlc(long int row
)
1448 dprint((11, "- get_dlc(%ld) -\n", row
));
1450 return(dlc_mgr(row
, Lookup
, (DL_CACHE_S
*)NULL
));
1455 * Move to new_dlc and give it row number row_number_to_assign_it.
1456 * We copy the passed in dlc in case the caller passed us a pointer into
1460 warp_to_dlc(DL_CACHE_S
*new_dlc
, long int row_number_to_assign_it
)
1464 dprint((9, "- warp_to_dlc(%ld) -\n", row_number_to_assign_it
));
1469 * Make sure we can move forward and backward from these
1470 * types that we may wish to warp to. The caller may not have known
1471 * to set adrbk_num for these types.
1478 dlc
.adrbk_num
= as
.n_addrbk
;
1484 (void)dlc_mgr(row_number_to_assign_it
, ArbitraryStartingPoint
, &dlc
);
1489 * Move to first dlc and give it row number 0.
1492 warp_to_beginning(void)
1494 dprint((9, "- warp_to_beginning -\n"));
1496 (void)dlc_mgr(0L, FirstEntry
, (DL_CACHE_S
*)NULL
);
1501 * Move to first dlc in abook_num and give it row number 0.
1504 warp_to_top_of_abook(int abook_num
)
1508 dprint((9, "- warp_to_top_of_abook(%d) -\n", abook_num
));
1510 (void)get_top_dl_of_adrbk(abook_num
, &dlc
);
1511 warp_to_dlc(&dlc
, 0L);
1516 * Move to last dlc and give it row number 0.
1521 dprint((9, "- warp_to_end -\n"));
1523 (void)dlc_mgr(0L, LastEntry
, (DL_CACHE_S
*)NULL
);
1528 * This flushes all of the cache that is related to this dlc.
1531 flush_dlc_from_cache(DL_CACHE_S
*dlc_to_flush
)
1533 dprint((11, "- flush_dlc_from_cache -\n"));
1535 (void)dlc_mgr(NO_LINE
, FlushDlcFromCache
, dlc_to_flush
);
1540 * Returns 1 if the dlc's match, 0 otherwise.
1543 matching_dlcs(DL_CACHE_S
*dlc1
, DL_CACHE_S
*dlc2
)
1545 if(!dlc1
|| !dlc2
||
1546 dlc1
->type
!= dlc2
->type
||
1547 dlc1
->adrbk_num
!= dlc2
->adrbk_num
)
1554 case DlcListBlankTop
:
1555 case DlcListBlankBottom
:
1556 case DlcListClickHere
:
1558 return(dlc1
->dlcelnum
== dlc2
->dlcelnum
);
1561 return(dlc1
->dlcelnum
== dlc2
->dlcelnum
&&
1562 dlc1
->dlcoffset
== dlc2
->dlcoffset
);
1566 case DlcTitleNoPerm
:
1567 case DlcTitleBlankTop
:
1570 case DlcNoPermission
:
1578 case DlcTitleDashTopCmb
:
1580 case DlcTitleDashBottomCmb
:
1581 case DlcTitleBlankBottomCmb
:
1582 case DlcClickHereCmb
:
1583 case DlcTitleBlankTopCmb
:
1588 case DlcOneBeforeBeginning
:
1589 case DlcTwoBeforeBeginning
:
1604 * Uses information in new to fill in new->dl.
1607 fill_in_dl_field(DL_CACHE_S
*new)
1611 char buf
[6*MAX_SCREEN_COLS
+ 1];
1616 unsigned screen_width
= ps_global
->ttyo
->screen_cols
;
1617 unsigned got_width
, need_width
, cellwidth
;
1619 screen_width
= MIN(MAX_SCREEN_COLS
, screen_width
);
1623 /* free any previously allocated space */
1630 fs_give((void **)&dl
->usst
);
1637 case DlcListBlankTop
:
1638 case DlcListBlankBottom
:
1643 case DlcTitleBlankTop
:
1644 case DlcDirBlankTop
:
1645 case DlcTitleBlankBottomCmb
:
1646 case DlcTitleBlankTopCmb
:
1648 dl
->usst
= cpystr("");
1651 case DlcTitleDashTopCmb
:
1652 case DlcTitleDashBottomCmb
:
1655 /* line of dashes in txt field */
1657 memset((void *)buf
, '-', screen_width
* sizeof(char));
1658 buf
[screen_width
] = '\0';
1659 dl
->usst
= cpystr(buf
);
1662 case DlcNoPermission
:
1664 dl
->usst
= cpystr(NO_PERMISSION
);
1668 case DlcTitleNoPerm
:
1670 pab
= &as
.adrbks
[new->adrbk_num
];
1671 /* title for this addrbook */
1672 snprintf(buf
, sizeof(buf
), " %s", pab
->abnick
? pab
->abnick
: pab
->filename
);
1673 cellwidth
= utf8_width(buf
);
1674 if(cellwidth
> screen_width
)
1675 cellwidth
= utf8_truncate(buf
, screen_width
);
1677 /* add space padding */
1678 if(cellwidth
< screen_width
)
1679 snprintf(buf
+strlen(buf
), sizeof(buf
)-strlen(buf
), "%*.*s",
1680 screen_width
- cellwidth
, screen_width
- cellwidth
, "");
1682 buf
[sizeof(buf
)-1] = '\0';
1684 if(as
.ro_warning
&& (pab
->access
== NoAccess
|| pab
->access
== ReadOnly
)){
1687 if(pab
->access
== NoAccess
)
1692 need_width
= utf8_width(str
);
1694 if(screen_width
> need_width
&& (q
= utf8_count_back_width(buf
, buf
+strlen(buf
), need_width
, &got_width
)) != NULL
)
1696 (void) utf8_pad_to_width(q
, str
, sizeof(buf
)-(q
-buf
), need_width
, 0);
1699 buf
[sizeof(buf
)-1] = '\0';
1700 dl
->usst
= cpystr(buf
);
1705 pab
= &as
.adrbks
[new->adrbk_num
];
1706 /* Find a hostname to put in title */
1709 if(pab
->type
& REMOTE_VIA_IMAP
&& pab
->filename
){
1710 char *start
, *end
= NULL
;
1712 start
= strindex(pab
->filename
, '{');
1714 end
= strindex(start
+1, '}');
1717 strncpy(hostbuf
, start
+ 1,
1718 MIN(end
- start
- 1, sizeof(hostbuf
)-1));
1719 hostbuf
[MIN(end
- start
- 1, sizeof(hostbuf
)-1)] = '\0';
1726 folder
= pab
->filename
;
1729 * Just trying to find the name relative to the home directory
1730 * to display in an OS-independent way.
1732 if(folder
&& in_dir(ps_global
->home_dir
, folder
)){
1733 char *p
, *new_folder
= NULL
, *savep
= NULL
;
1736 l
= strlen(ps_global
->home_dir
);
1738 while(!new_folder
&& (p
= last_cmpnt(folder
)) != NULL
){
1744 if(folder
+ l
== p
|| folder
+ l
+ 1 == p
)
1757 folder
= new_folder
;
1760 snprintf(buf
, sizeof(buf
), " %s AddressBook%s%s in %s",
1761 (pab
->type
& GLOBAL
) ? "Global" : "Personal",
1762 (pab
->type
& REMOTE_VIA_IMAP
&& *hostbuf
) ? " on " : "",
1763 (pab
->type
& REMOTE_VIA_IMAP
&& *hostbuf
) ? hostbuf
: "",
1764 (folder
&& *folder
) ? folder
: "<?>");
1765 cellwidth
= utf8_width(buf
);
1766 if(cellwidth
> screen_width
)
1767 cellwidth
= utf8_truncate(buf
, screen_width
);
1769 /* add space padding */
1770 if(cellwidth
< screen_width
)
1771 snprintf(buf
+strlen(buf
), sizeof(buf
)-strlen(buf
), "%*.*s",
1772 screen_width
- cellwidth
, screen_width
- cellwidth
, "");
1774 buf
[sizeof(buf
)-1] = '\0';
1775 dl
->usst
= cpystr(buf
);
1779 dl
->type
= TitleCmb
;
1780 pab
= &as
.adrbks
[new->adrbk_num
];
1781 /* title for this addrbook */
1782 snprintf(buf
, sizeof(buf
), "%s AddressBook <%s>",
1783 (new->adrbk_num
< as
.how_many_personals
) ?
1786 pab
->abnick
? pab
->abnick
: pab
->filename
);
1787 cellwidth
= utf8_width(buf
);
1788 if(cellwidth
> screen_width
)
1789 cellwidth
= utf8_truncate(buf
, screen_width
);
1791 /* add space padding */
1792 if(cellwidth
< screen_width
)
1793 snprintf(buf
+strlen(buf
), sizeof(buf
)-strlen(buf
), "%*.*s",
1794 screen_width
- cellwidth
, screen_width
- cellwidth
, "");
1796 buf
[sizeof(buf
)-1] = '\0';
1798 if(as
.ro_warning
&& (pab
->access
== NoAccess
|| pab
->access
== ReadOnly
)){
1801 if(pab
->access
== NoAccess
)
1806 need_width
= utf8_width(str
);
1808 if(screen_width
> need_width
&& (q
= utf8_count_back_width(buf
, buf
+strlen(buf
), need_width
, &got_width
)) != NULL
)
1810 (void) utf8_pad_to_width(q
, str
, sizeof(buf
)-(q
-buf
), need_width
, 0);
1813 buf
[sizeof(buf
)-1] = '\0';
1814 dl
->usst
= cpystr(buf
);
1819 utf8_snprintf(buf
, sizeof(buf
), "%-*.*w", screen_width
, screen_width
, OLDSTYLE_DIR_TITLE
);
1820 dl
->usst
= cpystr(buf
);
1823 case DlcClickHereCmb
:
1824 dl
->type
= ClickHereCmb
;
1827 case DlcListClickHere
:
1828 dl
->type
= ListClickHere
;
1829 dl
->elnum
= new->dlcelnum
;
1833 dl
->type
= ListEmpty
;
1834 dl
->elnum
= new->dlcelnum
;
1842 dl
->type
= ZoomEmpty
;
1846 dl
->type
= NoAbooks
;
1850 dl
->type
= AddFirstPers
;
1854 dl
->type
= AddFirstGlob
;
1858 dl
->type
= AskServer
;
1864 info
= break_up_ldap_server(ps_global
->VAR_LDAP_SERVERS
[new->adrbk_num
]);
1865 snprintf(buf2
, sizeof(buf2
), " %s",
1866 (info
&& info
->nick
&& *info
->nick
) ? info
->nick
:
1867 (info
&& info
->serv
&& *info
->serv
) ? info
->serv
:
1868 comatose(new->adrbk_num
+ 1));
1870 free_ldap_server_info(&info
);
1873 snprintf(buf2
, sizeof(buf2
), " %s", comatose(new->adrbk_num
+ 1));
1876 utf8_snprintf(buf
, sizeof(buf
), "%-*.*w", screen_width
, screen_width
, buf2
);
1877 dl
->usst
= cpystr(buf
);
1880 case DlcDirSubTitle
:
1886 info
= break_up_ldap_server(ps_global
->VAR_LDAP_SERVERS
[new->adrbk_num
]);
1887 if(info
&& info
->port
>= 0)
1888 snprintf(buf2
, sizeof(buf2
), " Directory Server on %s:%d",
1889 (info
&& info
->serv
&& *info
->serv
) ? info
->serv
: "<?>",
1892 snprintf(buf2
, sizeof(buf2
), " Directory Server on %s",
1893 (info
&& info
->serv
&& *info
->serv
) ? info
->serv
: "<?>");
1896 free_ldap_server_info(&info
);
1899 snprintf(buf2
, sizeof(buf2
), " Directory Server %s",
1900 comatose(new->adrbk_num
+ 1));
1903 utf8_snprintf(buf
, sizeof(buf
), "%-*.*w", screen_width
, screen_width
, buf2
);
1904 dl
->usst
= cpystr(buf
);
1909 dl
->elnum
= new->dlcelnum
;
1913 dl
->type
= ListHead
;
1914 dl
->elnum
= new->dlcelnum
;
1919 dl
->elnum
= new->dlcelnum
;
1920 dl
->l_offset
= new->dlcoffset
;
1924 case DlcOneBeforeBeginning
:
1925 case DlcTwoBeforeBeginning
:
1926 dl
->type
= Beginning
;
1934 q_status_message(SM_ORDER
| SM_DING
, 5, 10,
1935 _("Bug in addrbook, not supposed to happen, re-syncing..."));
1936 dprint((1, "Bug in addrbook, impossible dflt in fill_in_dl (%d)\n",
1938 /* jump back to a safe starting point */
1939 longjmp(addrbook_changed_unexpectedly
, 1);
1946 * Returns a pointer to the member_number'th list member of the list
1947 * associated with this display line.
1950 listmem(long int row
)
1956 if(dl
->type
!= ListEnt
)
1957 return((char *)NULL
);
1959 pab
= &as
.adrbks
[adrbk_num_from_lineno(row
)];
1961 return(listmem_from_dl(pab
->address_book
, dl
));
1966 * Returns a pointer to the list member
1967 * associated with this display line.
1970 listmem_from_dl(AdrBk
*address_book
, AddrScrn_Disp
*dl
)
1973 char **p
= (char **)NULL
;
1975 /* This shouldn't happen */
1976 if(dl
->type
!= ListEnt
)
1977 return((char *)NULL
);
1979 abe
= adrbk_get_ae(address_book
, (a_c_arg_t
) dl
->elnum
);
1982 * If we wanted to be more careful, We'd go through the list making sure
1983 * we don't pass the end. We'll count on the caller being careful
1986 if(abe
&& abe
->tag
== List
){
1991 return((p
&& *p
) ? *p
: (char *)NULL
);
1996 * How many members in list?
1999 listmem_count_from_abe(AdrBk_Entry
*abe
)
2003 if(abe
->tag
!= List
)
2006 for(p
= abe
->addr
.list
; p
!= NULL
&& *p
!= NULL
; p
++)
2009 return((adrbk_cntr_t
)(p
- abe
->addr
.list
));
2014 * Return a ptr to the row'th line of the global disp_list.
2015 * Line numbers count up but you can't count on knowing which line number
2016 * goes with the first or the last row. That is, row 0 is not necessarily
2017 * special. It could be before the rows that make up the display list, after
2018 * them, or anywhere in between. You can't tell what the last row is
2019 * numbered, but a dl with type End is returned when you get past the end.
2020 * You can't tell what the number of the first row is, but if you go past
2021 * the first row a dl of type Beginning will be returned. Row numbers can
2022 * be positive or negative. Their values have no meaning other than how
2023 * they line up relative to other row numbers.
2028 DL_CACHE_S
*dlc
= (DL_CACHE_S
*)NULL
;
2033 fill_in_dl_field(dlc
);
2037 q_status_message(SM_ORDER
| SM_DING
, 5, 10,
2038 _("Bug in addrbook, not supposed to happen, re-syncing..."));
2039 dprint((1, "Bug in addrbook (null dlc in dlist(%ld), not supposed to happen\n", row
));
2040 /* jump back to a safe starting point */
2042 dprint((1, "dlist: panic: initialized %d, n_addrbk %d, cur_row %d, top_ent %ld, ro_warning %d, no_op_possbl %d\n",
2043 as
.initialized
, as
.n_addrbk
, as
.cur_row
, as
.top_ent
, as
.ro_warning
, as
.no_op_possbl
));
2045 longjmp(addrbook_changed_unexpectedly
, 1);
2052 * Returns the index of the current address book.
2055 adrbk_num_from_lineno(long int lineno
)
2059 dlc
= get_dlc(lineno
);
2061 return(dlc
->adrbk_num
);