1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: abdlc.c 769 2007-10-24 00:15:40Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2007 University of Washington
8 * Copyright 2013-2017 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 #include "../pith/headers.h" /* for os-dep and pith defs/includes */
20 #include "../pith/abdlc.h"
21 #include "../pith/state.h"
22 #include "../pith/conf.h"
23 #include "../pith/status.h"
24 #include "../pith/ldap.h"
25 #include "../pith/tempfile.h"
31 void initialize_dlc_cache(void);
32 int dlc_siblings(DL_CACHE_S
*, DL_CACHE_S
*);
33 DL_CACHE_S
*dlc_mgr(long, DlMgrOps
, DL_CACHE_S
*);
34 void free_cache_array(DL_CACHE_S
**, int);
35 DL_CACHE_S
*dlc_prev(DL_CACHE_S
*, DL_CACHE_S
*);
36 DL_CACHE_S
*dlc_next(DL_CACHE_S
*, DL_CACHE_S
*);
37 DL_CACHE_S
*get_global_top_dlc(DL_CACHE_S
*);
38 DL_CACHE_S
*get_global_bottom_dlc(DL_CACHE_S
*);
39 DL_CACHE_S
*get_top_dl_of_adrbk(int, DL_CACHE_S
*);
40 DL_CACHE_S
*get_bottom_dl_of_adrbk(int, DL_CACHE_S
*);
43 #define NO_PERMISSION _("[ Permission Denied ]")
44 /* TRANSLATORS: This is a heading referring to something that is readable
46 #define READONLY _(" (ReadOnly)")
47 /* TRANSLATORS: Not readable */
48 #define NOACCESS _(" (Un-readable)")
49 /* TRANSLATORS: Directories, as in LDAP Directories. A heading. */
50 #define OLDSTYLE_DIR_TITLE _("Directories")
53 /* data for the display list cache */
54 static DL_CACHE_S
*cache_array
= (DL_CACHE_S
*)NULL
;
55 static long valid_low
,
57 static int index_of_low
,
63 initialize_dlc_cache(void)
65 dprint((11, "- initialize_dlc_cache -\n"));
67 (void)dlc_mgr(NO_LINE
, Initialize
, (DL_CACHE_S
*)NULL
);
72 done_with_dlc_cache(void)
74 dprint((11, "- done_with_dlc_cache -\n"));
76 (void)dlc_mgr(NO_LINE
, DoneWithCache
, (DL_CACHE_S
*)NULL
);
81 * Returns 1 if the dlc's are related to each other, 0 otherwise.
83 * The idea is that if you are going to flush one of these dlcs from the
84 * cache you should also flush its partners. For example, if you flush one
85 * Listent from a list you should flush the entire entry including all the
86 * Listents and the ListHead. If you flush a DlcTitle, you should also
87 * flush the SubTitle and the TitleBlankTop.
90 dlc_siblings(DL_CACHE_S
*dlc1
, DL_CACHE_S
*dlc2
)
92 if(!dlc1
|| !dlc2
|| dlc1
->adrbk_num
!= dlc2
->adrbk_num
)
100 case DlcListBlankBottom
:
102 case DlcListClickHere
:
107 case DlcListBlankTop
:
108 case DlcListBlankBottom
:
110 case DlcListClickHere
:
112 return(dlc1
->dlcelnum
== dlc2
->dlcelnum
);
147 case DlcTitleBlankTop
:
152 case DlcTitleBlankTop
:
174 case DlcTitleDashTopCmb
:
176 case DlcTitleDashBottomCmb
:
177 case DlcTitleBlankBottomCmb
:
178 case DlcClickHereCmb
:
179 case DlcTitleBlankTopCmb
:
181 case DlcTitleDashTopCmb
:
183 case DlcTitleDashBottomCmb
:
184 case DlcTitleBlankBottomCmb
:
185 case DlcClickHereCmb
:
186 case DlcTitleBlankTopCmb
:
202 * Manage the display list cache.
204 * The cache is a circular array of DL_CACHE_S elements. It always
205 * contains a contiguous set of display lines.
206 * The lowest numbered line in the cache is
207 * valid_low, and the highest is valid_high. Everything in between is
208 * also valid. Index_of_low is where to look
209 * for the valid_low element in the circular array.
211 * We make calls to dlc_prev and dlc_next to get new entries for the cache.
212 * We need a starting value before we can do that.
214 * This returns a pointer to a dlc for the desired row. If you want the
215 * actual display list line you call dlist(row) instead of dlc_mgr.
218 dlc_mgr(long int row
, DlMgrOps op
, DL_CACHE_S
*dlc_start
)
220 int new_index
, known_index
, next_index
;
221 DL_CACHE_S
*dlc
= (DL_CACHE_S
*)NULL
;
228 if(row
>= valid_low
&& row
<= valid_high
){ /* already cached */
230 new_index
= ((row
- valid_low
) + index_of_low
) % size_of_cache
;
231 dlc
= &cache_array
[new_index
];
234 else if(row
> valid_high
){ /* row is past where we've looked */
237 ((valid_high
- valid_low
) + index_of_low
) % size_of_cache
;
238 next_row
= valid_high
+ 1L;
240 /* we'll usually be looking for row = valid_high + 1 */
241 while(next_row
<= row
){
243 new_index
= (known_index
+ 1) % size_of_cache
;
246 dlc_next(&cache_array
[known_index
], &cache_array
[new_index
]);
249 * This means somebody changed the file out from underneath
250 * us. This would happen if dlc_next needed to ask for an
251 * abe to figure out what the type of the next row is, but
252 * adrbk_get_ae returned a NULL. I don't think that can
253 * happen, but if it does...
255 if(dlc
->type
== DlcNotSet
){
256 dprint((1, "dlc_next returned DlcNotSet\n"));
257 goto panic_abook_corrupt
;
260 if(n_cached
== size_of_cache
){ /* replaced low cache entry */
262 index_of_low
= (index_of_low
+ 1) % size_of_cache
;
270 known_index
= new_index
; /* for next time through loop */
273 else if(row
< valid_low
){ /* row is back up the screen */
275 known_index
= index_of_low
;
276 prev_row
= valid_low
- 1L;
278 while(prev_row
>= row
){
280 new_index
= (known_index
- 1 + size_of_cache
) % size_of_cache
;
282 dlc_prev(&cache_array
[known_index
], &cache_array
[new_index
]);
284 if(dlc
->type
== DlcNotSet
){
285 dprint((1, "dlc_prev returned DlcNotSet (1)\n"));
286 goto panic_abook_corrupt
;
289 if(n_cached
== size_of_cache
) /* replaced high cache entry */
296 (index_of_low
- 1 + size_of_cache
) % size_of_cache
;
299 known_index
= new_index
;
303 else if(op
== Initialize
){
307 if(!cache_array
|| size_of_cache
!= 3 * MAX(as
.l_p_page
,1)){
309 free_cache_array(&cache_array
, size_of_cache
);
311 size_of_cache
= 3 * MAX(as
.l_p_page
,1);
313 (DL_CACHE_S
*)fs_get(size_of_cache
* sizeof(DL_CACHE_S
));
314 memset((void *)cache_array
, 0, size_of_cache
* sizeof(DL_CACHE_S
));
317 /* this will return NULL below and the caller should ignore that */
320 * Flush all rows for a particular addrbook entry from the cache, but
321 * keep the cache alive and anchored in the same place. The particular
322 * entry is the one that dlc_start is one of the rows of.
324 else if(op
== FlushDlcFromCache
){
327 next_row
= dlc_start
->global_row
- 1;
328 for(; next_row
>= valid_low
; next_row
--){
329 next_index
= ((next_row
- valid_low
) + index_of_low
) %
331 if(!dlc_siblings(dlc_start
, &cache_array
[next_index
]))
335 low_entry
= next_row
+ 1L;
338 * If low_entry now points one past a ListBlankBottom, delete that,
339 * too, since it may not make sense anymore.
341 if(low_entry
> valid_low
){
342 next_index
= ((low_entry
-1L - valid_low
) + index_of_low
) %
344 if(cache_array
[next_index
].type
== DlcListBlankBottom
)
348 if(low_entry
> valid_low
){ /* invalidate everything >= this */
349 n_cached
-= (valid_high
- (low_entry
- 1L));
350 valid_high
= low_entry
- 1L;
354 * This is the tough case. That entry was the first thing cached,
355 * so we need to invalidate the whole cache. However, we also
356 * need to keep at least one thing cached for an anchor, so
357 * we need to get the dlc before this one and it should be a
358 * dlc not related to this same addrbook entry.
360 known_index
= index_of_low
;
361 prev_row
= valid_low
- 1L;
365 new_index
= (known_index
- 1 + size_of_cache
) % size_of_cache
;
367 dlc_prev(&cache_array
[known_index
], &cache_array
[new_index
]);
369 if(dlc
->type
== DlcNotSet
){
370 dprint((1, "dlc_prev returned DlcNotSet (2)\n"));
371 goto panic_abook_corrupt
;
376 (index_of_low
- 1 + size_of_cache
) % size_of_cache
;
378 if(!dlc_siblings(dlc_start
, dlc
))
381 known_index
= new_index
;
385 valid_high
= valid_low
;
389 * We have to anchor ourselves at a first element.
390 * Here's how we start at the top.
392 else if(op
== FirstEntry
){
393 initialize_dlc_cache();
395 dlc
= &cache_array
[0];
396 dlc
= get_global_top_dlc(dlc
);
397 dlc
->global_row
= row
;
402 /* And here's how we start from the bottom. */
403 else if(op
== LastEntry
){
404 initialize_dlc_cache();
406 dlc
= &cache_array
[0];
407 dlc
= get_global_bottom_dlc(dlc
);
408 dlc
->global_row
= row
;
414 * And here's how we start from an arbitrary position in the middle.
415 * We root the cache at display line row, so it helps if row is close
416 * to where we're going to be starting so that things are easy to find.
417 * The dl that goes with line row is dl_start from addrbook number
420 else if(op
== ArbitraryStartingPoint
){
423 initialize_dlc_cache();
425 dlc
= &cache_array
[0];
427 * Save this in case fill_in_dl_field needs to free the text
433 dlc
->global_row
= row
;
439 else if(op
== DoneWithCache
){
443 free_cache_array(&cache_array
, size_of_cache
);
449 q_status_message(SM_ORDER
| SM_DING
, 5, 10,
450 _("Addrbook changed unexpectedly, re-syncing..."));
452 _("addrbook changed while we had it open?, re-sync\n")));
454 "valid_low=%ld valid_high=%ld index_of_low=%d size_of_cache=%d\n",
455 valid_low
, valid_high
, index_of_low
, size_of_cache
));
457 "n_cached=%d new_index=%d known_index=%d next_index=%d\n",
458 n_cached
, new_index
, known_index
, next_index
));
460 "next_row=%ld prev_row=%ld row=%ld\n", next_row
, prev_row
, row
));
461 /* jump back to a safe starting point */
462 longjmp(addrbook_changed_unexpectedly
, 1);
468 free_cache_array(DL_CACHE_S
**c_array
, int size
)
473 for(i
= 0; i
< size
; i
++){
474 dlc
= &(*c_array
)[i
];
475 /* free any allocated space */
476 switch(dlc
->dl
.type
){
482 fs_give((void **)&dlc
->dl
.usst
);
490 fs_give((void **)c_array
);
495 * Get the dlc element that comes before "old". The function that calls this
496 * function is the one that keeps a cache and checks in the cache before
497 * calling here. New is a passed in pointer to a buffer where we fill in
501 dlc_prev(DL_CACHE_S
*old
, DL_CACHE_S
*new)
505 adrbk_cntr_t list_count
;
508 new->dlcelnum
= NO_NEXT
;
509 new->dlcoffset
= NO_NEXT
;
510 new->type
= DlcNotSet
;
511 pab
= &as
.adrbks
[old
->adrbk_num
];
516 if(old
->adrbk_num
== 0 && as
.config
&& as
.how_many_personals
== 0)
517 new->type
= DlcGlobDelim2
;
518 else if(old
->adrbk_num
== 0)
519 new->type
= DlcOneBeforeBeginning
;
520 else if(old
->adrbk_num
== as
.how_many_personals
)
521 new->type
= DlcGlobDelim2
;
523 new->type
= DlcTitleBlankTop
;
528 if(pab
->access
== NoAccess
)
529 new->type
= DlcTitleNoPerm
;
531 new->type
= DlcTitle
;
535 case DlcTitleBlankTop
:
536 new->adrbk_num
= old
->adrbk_num
- 1;
537 new->type
= DlcSubTitle
;
542 case DlcNoPermission
:
544 if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
)){
545 if(as
.n_addrbk
== 1 && as
.n_serv
== 0)
546 new->type
= DlcOneBeforeBeginning
;
548 new->type
= DlcTitleBlankBottomCmb
;
551 new->type
= DlcOneBeforeBeginning
;
562 el
= old
->dlcelnum
- 1;
564 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
574 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
575 if(abe
&& abe
->tag
== Single
)
576 new->type
= DlcSimple
;
577 else if(abe
&& abe
->tag
== List
)
578 new->type
= DlcListBlankBottom
;
580 else if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
)){
581 if(as
.n_addrbk
== 1 && as
.n_serv
== 0)
582 new->type
= DlcOneBeforeBeginning
;
584 new->type
= DlcTitleBlankBottomCmb
;
587 new->type
= DlcOneBeforeBeginning
;
599 el
= old
->dlcelnum
- 1;
601 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
611 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
612 if(abe
&& abe
->tag
== Single
){
613 new->type
= DlcListBlankTop
;
614 new->dlcelnum
= old
->dlcelnum
;
616 else if(abe
&& abe
->tag
== List
)
617 new->type
= DlcListBlankBottom
;
619 else if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
)){
620 if(as
.n_addrbk
== 1 && as
.n_serv
== 0)
621 new->type
= DlcOneBeforeBeginning
;
623 new->type
= DlcTitleBlankBottomCmb
;
626 new->type
= DlcOneBeforeBeginning
;
632 if(old
->dlcoffset
> 0){
633 new->type
= DlcListEnt
;
634 new->dlcelnum
= old
->dlcelnum
;
635 new->dlcoffset
= old
->dlcoffset
- 1;
638 new->type
= DlcListHead
;
639 new->dlcelnum
= old
->dlcelnum
;
644 case DlcListClickHere
:
646 new->type
= DlcListHead
;
647 new->dlcelnum
= old
->dlcelnum
;
650 case DlcListBlankTop
: /* can only occur between a Simple and a List */
651 new->type
= DlcSimple
;
658 el
= old
->dlcelnum
- 1;
660 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
671 dprint((1, "Bug in addrbook: case ListBlankTop with no selected entry\n"));
678 case DlcListBlankBottom
:
679 new->dlcelnum
= old
->dlcelnum
;
680 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
681 if(F_ON(F_EXPANDED_DISTLISTS
,ps_global
)
682 || exp_is_expanded(pab
->address_book
->exp
, (a_c_arg_t
)new->dlcelnum
)){
683 list_count
= listmem_count_from_abe(abe
);
685 new->type
= DlcListEmpty
;
687 new->type
= DlcListEnt
;
688 new->dlcoffset
= list_count
- 1;
692 new->type
= DlcListClickHere
;
697 if(as
.how_many_personals
== 0)
698 new->type
= DlcPersAdd
;
700 new->adrbk_num
= as
.how_many_personals
- 1;
701 new->type
= DlcSubTitle
;
706 new->type
= DlcGlobDelim1
;
710 new->type
= DlcOneBeforeBeginning
;
714 new->type
= DlcGlobDelim2
;
718 if(old
->adrbk_num
== 0 && as
.n_addrbk
== 0)
719 new->type
= DlcOneBeforeBeginning
;
720 else if(old
->adrbk_num
== 0)
721 new->type
= DlcDirDelim2
;
723 new->type
= DlcDirBlankTop
;
728 new->type
= DlcDirAccess
;
732 new->adrbk_num
= old
->adrbk_num
-1;
733 new->type
= DlcDirSubTitle
;
737 new->adrbk_num
= as
.n_addrbk
- 1;
739 new->type
= DlcNoAbooks
;
741 new = get_bottom_dl_of_adrbk(new->adrbk_num
, new);
746 new->type
= DlcDirDelim1
;
750 new->type
= DlcDirDelim1a
;
754 new->type
= DlcDirDelim1b
;
758 if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
))
759 new->type
= DlcDirDelim1c
;
761 new->type
= DlcDirDelim1
;
765 case DlcTitleDashTopCmb
:
766 if(old
->adrbk_num
== 0)
767 new->type
= DlcOneBeforeBeginning
;
769 new->type
= DlcTitleBlankTopCmb
;
774 new->type
= DlcTitleDashTopCmb
;
777 case DlcTitleDashBottomCmb
:
778 new->type
= DlcTitleCmb
;
781 case DlcTitleBlankBottomCmb
:
782 new->type
= DlcTitleDashBottomCmb
;
785 case DlcClickHereCmb
:
786 if(as
.n_addrbk
== 1 && as
.n_serv
== 0)
787 new->type
= DlcOneBeforeBeginning
;
789 new->type
= DlcTitleBlankBottomCmb
;
793 case DlcTitleBlankTopCmb
:
794 new->adrbk_num
= old
->adrbk_num
- 1;
795 new = get_bottom_dl_of_adrbk(new->adrbk_num
, new);
799 case DlcTwoBeforeBeginning
:
800 new->type
= DlcBeginning
;
803 case DlcOneBeforeBeginning
:
804 new->type
= DlcTwoBeforeBeginning
;
809 q_status_message(SM_ORDER
| SM_DING
, 5, 10,
810 _("Bug in addrbook, not supposed to happen, re-syncing..."));
811 dprint((1, "Bug in addrbook, impossible case (%d) in dlc_prev, re-sync\n",
813 /* jump back to a safe starting point */
814 longjmp(addrbook_changed_unexpectedly
, 1);
818 new->global_row
= old
->global_row
- 1L;
819 if(new->adrbk_num
== -2)
820 new->adrbk_num
= old
->adrbk_num
;
827 * Get the dlc element that comes after "old". The function that calls this
828 * function is the one that keeps a cache and checks in the cache before
832 dlc_next(DL_CACHE_S
*old
, DL_CACHE_S
*new)
836 adrbk_cntr_t ab_count
;
837 adrbk_cntr_t list_count
;
840 new->dlcelnum
= NO_NEXT
;
841 new->dlcoffset
= NO_NEXT
;
842 new->type
= DlcNotSet
;
843 pab
= &as
.adrbks
[old
->adrbk_num
];
848 new->type
= DlcSubTitle
;
852 if((old
->adrbk_num
== as
.how_many_personals
- 1) &&
853 (as
.config
|| as
.n_addrbk
> as
.how_many_personals
))
854 new->type
= DlcGlobDelim1
;
855 else if(as
.n_serv
&& !as
.config
&&
856 (old
->adrbk_num
== as
.n_addrbk
- 1))
857 new->type
= DlcDirDelim1
;
858 else if(old
->adrbk_num
== as
.n_addrbk
- 1)
861 new->adrbk_num
= old
->adrbk_num
+ 1;
862 new->type
= DlcTitleBlankTop
;
867 case DlcTitleBlankTop
:
868 if(pab
->access
== NoAccess
)
869 new->type
= DlcTitleNoPerm
;
871 new->type
= DlcTitle
;
877 case DlcNoPermission
:
878 case DlcClickHereCmb
:
879 if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
)){
880 if(old
->adrbk_num
< as
.n_addrbk
- 1){
881 new->adrbk_num
= old
->adrbk_num
+ 1;
882 new->type
= DlcTitleBlankTopCmb
;
885 new->type
= DlcDirDelim1
;
905 ab_count
= adrbk_count(pab
->address_book
);
908 el
= old
->dlcelnum
+ 1;
910 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
920 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
921 if(abe
&& abe
->tag
== Single
)
922 new->type
= DlcSimple
;
923 else if(abe
&& abe
->tag
== List
)
924 new->type
= DlcListBlankTop
;
926 else if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
)){
927 if(old
->adrbk_num
< as
.n_addrbk
- 1){
928 new->adrbk_num
= old
->adrbk_num
+ 1;
929 new->type
= DlcTitleBlankTopCmb
;
932 new->type
= DlcDirDelim1
;
943 new->dlcelnum
= old
->dlcelnum
;
944 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
945 if(F_ON(F_EXPANDED_DISTLISTS
,ps_global
)
946 || exp_is_expanded(pab
->address_book
->exp
, (a_c_arg_t
)new->dlcelnum
)){
947 list_count
= listmem_count_from_abe(abe
);
949 new->type
= DlcListEmpty
;
951 new->type
= DlcListEnt
;
956 new->type
= DlcListClickHere
;
961 new->dlcelnum
= old
->dlcelnum
;
962 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
963 list_count
= listmem_count_from_abe(abe
);
964 if(old
->dlcoffset
== list_count
- 1){ /* last member of list */
968 ab_count
= adrbk_count(pab
->address_book
);
971 el
= old
->dlcelnum
+ 1;
973 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
982 new->type
= DlcListBlankBottom
;
983 else if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
)){
984 if(old
->adrbk_num
< as
.n_addrbk
- 1){
985 new->adrbk_num
= old
->adrbk_num
+ 1;
986 new->type
= DlcTitleBlankTopCmb
;
989 new->type
= DlcDirDelim1
;
997 new->type
= DlcListEnt
;
998 new->dlcoffset
= old
->dlcoffset
+ 1;
1003 case DlcListClickHere
:
1009 new->dlcelnum
= old
->dlcelnum
;
1010 ab_count
= adrbk_count(pab
->address_book
);
1013 el
= old
->dlcelnum
+ 1;
1014 while(i
< ab_count
){
1015 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
1024 new->type
= DlcListBlankBottom
;
1025 else if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
)){
1026 if(old
->adrbk_num
< as
.n_addrbk
- 1){
1027 new->adrbk_num
= old
->adrbk_num
+ 1;
1028 new->type
= DlcTitleBlankTopCmb
;
1031 new->type
= DlcDirDelim1
;
1041 case DlcListBlankTop
:
1042 new->type
= DlcListHead
;
1043 new->dlcelnum
= old
->dlcelnum
;
1046 case DlcListBlankBottom
:
1051 ab_count
= adrbk_count(pab
->address_book
);
1054 el
= old
->dlcelnum
+ 1;
1055 while(i
< ab_count
){
1056 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
1066 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
1067 if(abe
&& abe
->tag
== Single
)
1068 new->type
= DlcSimple
;
1069 else if(abe
&& abe
->tag
== List
)
1070 new->type
= DlcListHead
;
1080 new->type
= DlcGlobDelim2
;
1084 if(as
.config
&& as
.how_many_personals
== as
.n_addrbk
)
1085 new->type
= DlcGlobAdd
;
1087 new->adrbk_num
= as
.how_many_personals
;
1088 pab
= &as
.adrbks
[new->adrbk_num
];
1089 if(pab
->access
== NoAccess
)
1090 new->type
= DlcTitleNoPerm
;
1092 new->type
= DlcTitle
;
1098 if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
))
1099 new->type
= DlcDirDelim1a
;
1101 new->type
= DlcDirDelim2
;
1107 new->type
= DlcDirDelim1b
;
1111 new->type
= DlcDirDelim1c
;
1115 new->type
= DlcDirDelim2
;
1120 new->type
= DlcDirAccess
;
1125 new->type
= DlcGlobDelim1
;
1129 new->type
= DlcDirSubTitle
;
1132 case DlcDirSubTitle
:
1133 if(old
->adrbk_num
== as
.n_serv
- 1)
1136 new->type
= DlcDirBlankTop
;
1137 new->adrbk_num
= old
->adrbk_num
+ 1;
1142 case DlcDirBlankTop
:
1143 new->type
= DlcDirAccess
;
1146 case DlcTitleDashTopCmb
:
1147 new->type
= DlcTitleCmb
;
1151 new->type
= DlcTitleDashBottomCmb
;
1154 case DlcTitleDashBottomCmb
:
1155 new->type
= DlcTitleBlankBottomCmb
;
1158 case DlcTitleBlankBottomCmb
:
1159 pab
= &as
.adrbks
[old
->adrbk_num
];
1160 if(pab
->ostatus
!= Open
&& pab
->access
!= NoAccess
)
1161 new->type
= DlcClickHereCmb
;
1163 new = get_top_dl_of_adrbk(old
->adrbk_num
, new);
1167 case DlcTitleBlankTopCmb
:
1168 new->type
= DlcTitleDashTopCmb
;
1171 case DlcOneBeforeBeginning
:
1172 new = get_global_top_dlc(new);
1175 case DlcTwoBeforeBeginning
:
1176 new->type
= DlcOneBeforeBeginning
;
1180 q_status_message(SM_ORDER
| SM_DING
, 5, 10,
1181 _("Bug in addrbook, not supposed to happen, re-syncing..."));
1182 dprint((1, "Bug in addrbook, impossible case (%d) in dlc_next, re-sync\n",
1184 /* jump back to a safe starting point */
1185 longjmp(addrbook_changed_unexpectedly
, 1);
1189 new->global_row
= old
->global_row
+ 1L;
1190 if(new->adrbk_num
== -2)
1191 new->adrbk_num
= old
->adrbk_num
;
1198 * Get the display line at the very top of whole addrbook screen display.
1201 get_global_top_dlc(DL_CACHE_S
*new)
1202 /* fill in answer here */
1206 new->dlcelnum
= NO_NEXT
;
1207 new->dlcoffset
= NO_NEXT
;
1208 new->type
= DlcNotSet
;
1210 if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
) && !as
.config
){
1212 if(as
.n_addrbk
> 1 || (as
.n_serv
&& as
.n_addrbk
== 1))
1213 new->type
= DlcTitleDashTopCmb
;
1214 else if(as
.n_addrbk
== 1)
1215 new = get_top_dl_of_adrbk(new->adrbk_num
, new);
1216 else if(as
.n_serv
> 0){ /* 1st directory */
1217 new->type
= DlcDirAccess
;
1221 new->type
= DlcNoAbooks
;
1227 if(as
.how_many_personals
== 0) /* no personals */
1228 new->type
= DlcPersAdd
;
1230 pab
= &as
.adrbks
[new->adrbk_num
]; /* 1st personal */
1231 if(pab
->access
== NoAccess
)
1232 new->type
= DlcTitleNoPerm
;
1234 new->type
= DlcTitle
;
1237 else if(any_ab_open()){
1238 new->adrbk_num
= as
.cur
;
1239 new = get_top_dl_of_adrbk(new->adrbk_num
, new);
1241 else if(as
.n_addrbk
> 0){ /* 1st addrbook */
1242 pab
= &as
.adrbks
[new->adrbk_num
];
1243 if(pab
->access
== NoAccess
)
1244 new->type
= DlcTitleNoPerm
;
1246 new->type
= DlcTitle
;
1248 else if(as
.n_serv
> 0){ /* 1st directory */
1249 new->type
= DlcDirAccess
;
1253 new->type
= DlcNoAbooks
;
1261 * Get the last display line for the whole address book screen.
1262 * This gives us a way to start at the end and move back up.
1265 get_global_bottom_dlc(DL_CACHE_S
*new)
1266 /* fill in answer here */
1268 new->dlcelnum
= NO_NEXT
;
1269 new->dlcoffset
= NO_NEXT
;
1270 new->type
= DlcNotSet
;
1272 if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
) && !as
.config
){
1274 new->type
= DlcDirSubTitle
;
1275 new->adrbk_num
= as
.n_serv
- 1;
1277 else if(as
.n_addrbk
> 0){
1278 new->adrbk_num
= as
.n_addrbk
- 1;
1279 new = get_bottom_dl_of_adrbk(new->adrbk_num
, new);
1282 new->type
= DlcNoAbooks
;
1285 new->adrbk_num
= MAX(as
.n_addrbk
- 1, 0);
1288 if(as
.how_many_personals
== as
.n_addrbk
) /* no globals */
1289 new->type
= DlcGlobAdd
;
1291 new->type
= DlcSubTitle
;
1293 else if(any_ab_open()){
1294 new->adrbk_num
= as
.cur
;
1295 new = get_bottom_dl_of_adrbk(new->adrbk_num
, new);
1298 new->type
= DlcDirSubTitle
;
1299 new->adrbk_num
= as
.n_serv
- 1;
1301 else{ /* !config && !opened && !n_serv */
1303 new->type
= DlcSubTitle
;
1305 new->type
= DlcNoAbooks
;
1314 * First dl in a particular addrbook, not counting title lines.
1315 * Assumes as.opened.
1318 get_top_dl_of_adrbk(int adrbk_num
, DL_CACHE_S
*new)
1320 /* fill in answer here */
1324 adrbk_cntr_t ab_count
;
1326 pab
= &as
.adrbks
[adrbk_num
];
1327 new->adrbk_num
= adrbk_num
;
1329 if(pab
->access
== NoAccess
)
1330 new->type
= DlcNoPermission
;
1335 ab_count
= adrbk_count(pab
->address_book
);
1339 /* find first displayed entry */
1340 while(i
< ab_count
){
1341 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
1351 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
) new->dlcelnum
);
1352 if(abe
&& abe
->tag
== Single
)
1353 new->type
= DlcSimple
;
1354 else if(abe
&& abe
->tag
== List
)
1355 new->type
= DlcListHead
;
1358 new->type
= DlcZoomEmpty
;
1360 new->type
= DlcEmpty
;
1368 * Find the last display line for addrbook number adrbk_num.
1369 * Assumes as.opened (unless OLD_ABOOK_DISP).
1372 get_bottom_dl_of_adrbk(int adrbk_num
, DL_CACHE_S
*new)
1374 /* fill in answer here */
1378 adrbk_cntr_t ab_count
;
1379 adrbk_cntr_t list_count
;
1381 pab
= &as
.adrbks
[adrbk_num
];
1382 new->adrbk_num
= adrbk_num
;
1384 if(F_ON(F_CMBND_ABOOK_DISP
,ps_global
) && pab
->ostatus
!= Open
){
1385 if(pab
->access
== NoAccess
)
1386 new->type
= DlcNoPermission
;
1388 new->type
= DlcClickHereCmb
;
1390 else if(F_OFF(F_CMBND_ABOOK_DISP
,ps_global
) && pab
->ostatus
!= Open
){
1391 new->type
= DlcSubTitle
;
1394 if(pab
->access
== NoAccess
)
1395 new->type
= DlcNoPermission
;
1400 ab_count
= adrbk_count(pab
->address_book
);
1403 /* find last displayed entry */
1405 if(!as
.zoomed
|| entry_is_selected(pab
->address_book
->selects
,
1415 abe
= adrbk_get_ae(pab
->address_book
, (a_c_arg_t
)new->dlcelnum
);
1416 if(abe
&& abe
->tag
== Single
)
1417 new->type
= DlcSimple
;
1418 else if(abe
&& abe
->tag
== List
){
1419 if(F_ON(F_EXPANDED_DISTLISTS
,ps_global
)
1420 || exp_is_expanded(pab
->address_book
->exp
,
1421 (a_c_arg_t
)new->dlcelnum
)){
1422 list_count
= listmem_count_from_abe(abe
);
1424 new->type
= DlcListEmpty
;
1426 new->type
= DlcListEnt
;
1427 new->dlcoffset
= list_count
- 1;
1431 new->type
= DlcListClickHere
;
1435 new->type
= DlcZoomEmpty
;
1437 new->type
= DlcEmpty
;
1447 * This returns the actual dlc instead of the dl within the dlc.
1450 get_dlc(long int row
)
1452 dprint((11, "- get_dlc(%ld) -\n", row
));
1454 return(dlc_mgr(row
, Lookup
, (DL_CACHE_S
*)NULL
));
1459 * Move to new_dlc and give it row number row_number_to_assign_it.
1460 * We copy the passed in dlc in case the caller passed us a pointer into
1464 warp_to_dlc(DL_CACHE_S
*new_dlc
, long int row_number_to_assign_it
)
1468 dprint((9, "- warp_to_dlc(%ld) -\n", row_number_to_assign_it
));
1473 * Make sure we can move forward and backward from these
1474 * types that we may wish to warp to. The caller may not have known
1475 * to set adrbk_num for these types.
1482 dlc
.adrbk_num
= as
.n_addrbk
;
1488 (void)dlc_mgr(row_number_to_assign_it
, ArbitraryStartingPoint
, &dlc
);
1493 * Move to first dlc and give it row number 0.
1496 warp_to_beginning(void)
1498 dprint((9, "- warp_to_beginning -\n"));
1500 (void)dlc_mgr(0L, FirstEntry
, (DL_CACHE_S
*)NULL
);
1505 * Move to first dlc in abook_num and give it row number 0.
1508 warp_to_top_of_abook(int abook_num
)
1512 dprint((9, "- warp_to_top_of_abook(%d) -\n", abook_num
));
1514 (void)get_top_dl_of_adrbk(abook_num
, &dlc
);
1515 warp_to_dlc(&dlc
, 0L);
1520 * Move to last dlc and give it row number 0.
1525 dprint((9, "- warp_to_end -\n"));
1527 (void)dlc_mgr(0L, LastEntry
, (DL_CACHE_S
*)NULL
);
1532 * This flushes all of the cache that is related to this dlc.
1535 flush_dlc_from_cache(DL_CACHE_S
*dlc_to_flush
)
1537 dprint((11, "- flush_dlc_from_cache -\n"));
1539 (void)dlc_mgr(NO_LINE
, FlushDlcFromCache
, dlc_to_flush
);
1544 * Returns 1 if the dlc's match, 0 otherwise.
1547 matching_dlcs(DL_CACHE_S
*dlc1
, DL_CACHE_S
*dlc2
)
1549 if(!dlc1
|| !dlc2
||
1550 dlc1
->type
!= dlc2
->type
||
1551 dlc1
->adrbk_num
!= dlc2
->adrbk_num
)
1558 case DlcListBlankTop
:
1559 case DlcListBlankBottom
:
1560 case DlcListClickHere
:
1562 return(dlc1
->dlcelnum
== dlc2
->dlcelnum
);
1565 return(dlc1
->dlcelnum
== dlc2
->dlcelnum
&&
1566 dlc1
->dlcoffset
== dlc2
->dlcoffset
);
1570 case DlcTitleNoPerm
:
1571 case DlcTitleBlankTop
:
1574 case DlcNoPermission
:
1582 case DlcTitleDashTopCmb
:
1584 case DlcTitleDashBottomCmb
:
1585 case DlcTitleBlankBottomCmb
:
1586 case DlcClickHereCmb
:
1587 case DlcTitleBlankTopCmb
:
1592 case DlcOneBeforeBeginning
:
1593 case DlcTwoBeforeBeginning
:
1608 * Uses information in new to fill in new->dl.
1611 fill_in_dl_field(DL_CACHE_S
*new)
1615 char buf
[6*MAX_SCREEN_COLS
+ 1];
1620 unsigned screen_width
= ps_global
->ttyo
->screen_cols
;
1621 unsigned got_width
, need_width
, cellwidth
;
1623 screen_width
= MIN(MAX_SCREEN_COLS
, screen_width
);
1627 /* free any previously allocated space */
1634 fs_give((void **)&dl
->usst
);
1641 case DlcListBlankTop
:
1642 case DlcListBlankBottom
:
1647 case DlcTitleBlankTop
:
1648 case DlcDirBlankTop
:
1649 case DlcTitleBlankBottomCmb
:
1650 case DlcTitleBlankTopCmb
:
1652 dl
->usst
= cpystr("");
1655 case DlcTitleDashTopCmb
:
1656 case DlcTitleDashBottomCmb
:
1659 /* line of dashes in txt field */
1661 memset((void *)buf
, '-', screen_width
* sizeof(char));
1662 buf
[screen_width
] = '\0';
1663 dl
->usst
= cpystr(buf
);
1666 case DlcNoPermission
:
1668 dl
->usst
= cpystr(NO_PERMISSION
);
1672 case DlcTitleNoPerm
:
1674 pab
= &as
.adrbks
[new->adrbk_num
];
1675 /* title for this addrbook */
1676 snprintf(buf
, sizeof(buf
), " %s", pab
->abnick
? pab
->abnick
: pab
->filename
);
1677 cellwidth
= utf8_width(buf
);
1678 if(cellwidth
> screen_width
)
1679 cellwidth
= utf8_truncate(buf
, screen_width
);
1681 /* add space padding */
1682 if(cellwidth
< screen_width
)
1683 snprintf(buf
+strlen(buf
), sizeof(buf
)-strlen(buf
), "%*.*s",
1684 screen_width
- cellwidth
, screen_width
- cellwidth
, "");
1686 buf
[sizeof(buf
)-1] = '\0';
1688 if(as
.ro_warning
&& (pab
->access
== NoAccess
|| pab
->access
== ReadOnly
)){
1691 if(pab
->access
== NoAccess
)
1696 need_width
= utf8_width(str
);
1698 if(screen_width
> need_width
&& (q
= utf8_count_back_width(buf
, buf
+strlen(buf
), need_width
, &got_width
)) != NULL
)
1700 (void) utf8_pad_to_width(q
, str
, sizeof(buf
)-(q
-buf
), need_width
, 0);
1703 buf
[sizeof(buf
)-1] = '\0';
1704 dl
->usst
= cpystr(buf
);
1709 pab
= &as
.adrbks
[new->adrbk_num
];
1710 /* Find a hostname to put in title */
1713 if(pab
->type
& REMOTE_VIA_IMAP
&& pab
->filename
){
1716 start
= strindex(pab
->filename
, '{');
1718 end
= strindex(start
+1, '}');
1721 strncpy(hostbuf
, start
+ 1,
1722 MIN(end
- start
- 1, sizeof(hostbuf
)-1));
1723 hostbuf
[MIN(end
- start
- 1, sizeof(hostbuf
)-1)] = '\0';
1730 folder
= pab
->filename
;
1733 * Just trying to find the name relative to the home directory
1734 * to display in an OS-independent way.
1736 if(folder
&& in_dir(ps_global
->home_dir
, folder
)){
1737 char *p
, *new_folder
= NULL
, *savep
= NULL
;
1740 l
= strlen(ps_global
->home_dir
);
1742 while(!new_folder
&& (p
= last_cmpnt(folder
)) != NULL
){
1748 if(folder
+ l
== p
|| folder
+ l
+ 1 == p
)
1761 folder
= new_folder
;
1764 snprintf(buf
, sizeof(buf
), " %s AddressBook%s%s in %s",
1765 (pab
->type
& GLOBAL
) ? "Global" : "Personal",
1766 (pab
->type
& REMOTE_VIA_IMAP
&& *hostbuf
) ? " on " : "",
1767 (pab
->type
& REMOTE_VIA_IMAP
&& *hostbuf
) ? hostbuf
: "",
1768 (folder
&& *folder
) ? folder
: "<?>");
1769 cellwidth
= utf8_width(buf
);
1770 if(cellwidth
> screen_width
)
1771 cellwidth
= utf8_truncate(buf
, screen_width
);
1773 /* add space padding */
1774 if(cellwidth
< screen_width
)
1775 snprintf(buf
+strlen(buf
), sizeof(buf
)-strlen(buf
), "%*.*s",
1776 screen_width
- cellwidth
, screen_width
- cellwidth
, "");
1778 buf
[sizeof(buf
)-1] = '\0';
1779 dl
->usst
= cpystr(buf
);
1783 dl
->type
= TitleCmb
;
1784 pab
= &as
.adrbks
[new->adrbk_num
];
1785 /* title for this addrbook */
1786 snprintf(buf
, sizeof(buf
), "%s AddressBook <%s>",
1787 (new->adrbk_num
< as
.how_many_personals
) ?
1790 pab
->abnick
? pab
->abnick
: pab
->filename
);
1791 cellwidth
= utf8_width(buf
);
1792 if(cellwidth
> screen_width
)
1793 cellwidth
= utf8_truncate(buf
, screen_width
);
1795 /* add space padding */
1796 if(cellwidth
< screen_width
)
1797 snprintf(buf
+strlen(buf
), sizeof(buf
)-strlen(buf
), "%*.*s",
1798 screen_width
- cellwidth
, screen_width
- cellwidth
, "");
1800 buf
[sizeof(buf
)-1] = '\0';
1802 if(as
.ro_warning
&& (pab
->access
== NoAccess
|| pab
->access
== ReadOnly
)){
1805 if(pab
->access
== NoAccess
)
1810 need_width
= utf8_width(str
);
1812 if(screen_width
> need_width
&& (q
= utf8_count_back_width(buf
, buf
+strlen(buf
), need_width
, &got_width
)) != NULL
)
1814 (void) utf8_pad_to_width(q
, str
, sizeof(buf
)-(q
-buf
), need_width
, 0);
1817 buf
[sizeof(buf
)-1] = '\0';
1818 dl
->usst
= cpystr(buf
);
1823 utf8_snprintf(buf
, sizeof(buf
), "%-*.*w", screen_width
, screen_width
, OLDSTYLE_DIR_TITLE
);
1824 dl
->usst
= cpystr(buf
);
1827 case DlcClickHereCmb
:
1828 dl
->type
= ClickHereCmb
;
1831 case DlcListClickHere
:
1832 dl
->type
= ListClickHere
;
1833 dl
->elnum
= new->dlcelnum
;
1837 dl
->type
= ListEmpty
;
1838 dl
->elnum
= new->dlcelnum
;
1846 dl
->type
= ZoomEmpty
;
1850 dl
->type
= NoAbooks
;
1854 dl
->type
= AddFirstPers
;
1858 dl
->type
= AddFirstGlob
;
1862 dl
->type
= AskServer
;
1868 info
= break_up_ldap_server(ps_global
->VAR_LDAP_SERVERS
[new->adrbk_num
]);
1869 snprintf(buf2
, sizeof(buf2
), " %s",
1870 (info
&& info
->nick
&& *info
->nick
) ? info
->nick
:
1871 (info
&& info
->serv
&& *info
->serv
) ? info
->serv
:
1872 comatose(new->adrbk_num
+ 1));
1874 free_ldap_server_info(&info
);
1877 snprintf(buf2
, sizeof(buf2
), " %s", comatose(new->adrbk_num
+ 1));
1880 utf8_snprintf(buf
, sizeof(buf
), "%-*.*w", screen_width
, screen_width
, buf2
);
1881 dl
->usst
= cpystr(buf
);
1884 case DlcDirSubTitle
:
1890 info
= break_up_ldap_server(ps_global
->VAR_LDAP_SERVERS
[new->adrbk_num
]);
1891 if(info
&& info
->port
>= 0)
1892 snprintf(buf2
, sizeof(buf2
), " Directory Server on %s:%d",
1893 (info
&& info
->serv
&& *info
->serv
) ? info
->serv
: "<?>",
1896 snprintf(buf2
, sizeof(buf2
), " Directory Server on %s",
1897 (info
&& info
->serv
&& *info
->serv
) ? info
->serv
: "<?>");
1900 free_ldap_server_info(&info
);
1903 snprintf(buf2
, sizeof(buf2
), " Directory Server %s",
1904 comatose(new->adrbk_num
+ 1));
1907 utf8_snprintf(buf
, sizeof(buf
), "%-*.*w", screen_width
, screen_width
, buf2
);
1908 dl
->usst
= cpystr(buf
);
1913 dl
->elnum
= new->dlcelnum
;
1917 dl
->type
= ListHead
;
1918 dl
->elnum
= new->dlcelnum
;
1923 dl
->elnum
= new->dlcelnum
;
1924 dl
->l_offset
= new->dlcoffset
;
1928 case DlcOneBeforeBeginning
:
1929 case DlcTwoBeforeBeginning
:
1930 dl
->type
= Beginning
;
1938 q_status_message(SM_ORDER
| SM_DING
, 5, 10,
1939 _("Bug in addrbook, not supposed to happen, re-syncing..."));
1940 dprint((1, "Bug in addrbook, impossible dflt in fill_in_dl (%d)\n",
1942 /* jump back to a safe starting point */
1943 longjmp(addrbook_changed_unexpectedly
, 1);
1950 * Returns a pointer to the member_number'th list member of the list
1951 * associated with this display line.
1954 listmem(long int row
)
1960 if(dl
->type
!= ListEnt
)
1961 return((char *)NULL
);
1963 pab
= &as
.adrbks
[adrbk_num_from_lineno(row
)];
1965 return(listmem_from_dl(pab
->address_book
, dl
));
1970 * Returns a pointer to the list member
1971 * associated with this display line.
1974 listmem_from_dl(AdrBk
*address_book
, AddrScrn_Disp
*dl
)
1977 char **p
= (char **)NULL
;
1979 /* This shouldn't happen */
1980 if(dl
->type
!= ListEnt
)
1981 return((char *)NULL
);
1983 abe
= adrbk_get_ae(address_book
, (a_c_arg_t
) dl
->elnum
);
1986 * If we wanted to be more careful, We'd go through the list making sure
1987 * we don't pass the end. We'll count on the caller being careful
1990 if(abe
&& abe
->tag
== List
){
1995 return((p
&& *p
) ? *p
: (char *)NULL
);
2000 * How many members in list?
2003 listmem_count_from_abe(AdrBk_Entry
*abe
)
2007 if(abe
->tag
!= List
)
2010 for(p
= abe
->addr
.list
; p
!= NULL
&& *p
!= NULL
; p
++)
2013 return((adrbk_cntr_t
)(p
- abe
->addr
.list
));
2018 * Return a ptr to the row'th line of the global disp_list.
2019 * Line numbers count up but you can't count on knowing which line number
2020 * goes with the first or the last row. That is, row 0 is not necessarily
2021 * special. It could be before the rows that make up the display list, after
2022 * them, or anywhere in between. You can't tell what the last row is
2023 * numbered, but a dl with type End is returned when you get past the end.
2024 * You can't tell what the number of the first row is, but if you go past
2025 * the first row a dl of type Beginning will be returned. Row numbers can
2026 * be positive or negative. Their values have no meaning other than how
2027 * they line up relative to other row numbers.
2032 DL_CACHE_S
*dlc
= (DL_CACHE_S
*)NULL
;
2037 fill_in_dl_field(dlc
);
2041 q_status_message(SM_ORDER
| SM_DING
, 5, 10,
2042 _("Bug in addrbook, not supposed to happen, re-syncing..."));
2043 dprint((1, "Bug in addrbook (null dlc in dlist(%ld), not supposed to happen\n", row
));
2044 /* jump back to a safe starting point */
2046 dprint((1, "dlist: panic: initialized %d, n_addrbk %d, cur_row %d, top_ent %ld, ro_warning %d, no_op_possbl %d\n",
2047 as
.initialized
, as
.n_addrbk
, as
.cur_row
, as
.top_ent
, as
.ro_warning
, as
.no_op_possbl
));
2049 longjmp(addrbook_changed_unexpectedly
, 1);
2056 * Returns the index of the current address book.
2059 adrbk_num_from_lineno(long int lineno
)
2063 dlc
= get_dlc(lineno
);
2065 return(dlc
->adrbk_num
);