Merge branch 'ical'
[alpine.git] / pith / abdlc.c
blob7b10e0748d14df755c4c9cf9334130bca4c8b536
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: abdlc.c 769 2007-10-24 00:15:40Z hubert@u.washington.edu $";
3 #endif
5 /*
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"
29 * Internal prototypes
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
45 but not writeable. */
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,
56 valid_high;
57 static int index_of_low,
58 size_of_cache,
59 n_cached;
62 void
63 initialize_dlc_cache(void)
65 dprint((11, "- initialize_dlc_cache -\n"));
67 (void)dlc_mgr(NO_LINE, Initialize, (DL_CACHE_S *)NULL);
71 void
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.
89 int
90 dlc_siblings(DL_CACHE_S *dlc1, DL_CACHE_S *dlc2)
92 if(!dlc1 || !dlc2 || dlc1->adrbk_num != dlc2->adrbk_num)
93 return 0;
95 switch(dlc1->type){
97 case DlcSimple:
98 case DlcListHead:
99 case DlcListBlankTop:
100 case DlcListBlankBottom:
101 case DlcListEnt:
102 case DlcListClickHere:
103 case DlcListEmpty:
104 switch(dlc2->type){
105 case DlcSimple:
106 case DlcListHead:
107 case DlcListBlankTop:
108 case DlcListBlankBottom:
109 case DlcListEnt:
110 case DlcListClickHere:
111 case DlcListEmpty:
112 return(dlc1->dlcelnum == dlc2->dlcelnum);
114 default:
115 return 0;
118 break;
120 case DlcDirDelim1:
121 case DlcDirDelim2:
122 switch(dlc2->type){
123 case DlcDirDelim1:
124 case DlcDirDelim2:
125 return 1;
127 default:
128 return 0;
130 break;
132 case DlcGlobDelim1:
133 case DlcGlobDelim2:
134 switch(dlc2->type){
135 case DlcGlobDelim1:
136 case DlcGlobDelim2:
137 return 1;
139 default:
140 return 0;
142 break;
144 case DlcTitle:
145 case DlcTitleNoPerm:
146 case DlcSubTitle:
147 case DlcTitleBlankTop:
148 switch(dlc2->type){
149 case DlcTitle:
150 case DlcTitleNoPerm:
151 case DlcSubTitle:
152 case DlcTitleBlankTop:
153 return 1;
155 default:
156 return 0;
158 break;
160 case DlcDirAccess:
161 case DlcDirSubTitle:
162 case DlcDirBlankTop:
163 switch(dlc2->type){
164 case DlcDirAccess:
165 case DlcDirSubTitle:
166 case DlcDirBlankTop:
167 return 1;
169 default:
170 return 0;
172 break;
174 case DlcTitleDashTopCmb:
175 case DlcTitleCmb:
176 case DlcTitleDashBottomCmb:
177 case DlcTitleBlankBottomCmb:
178 case DlcClickHereCmb:
179 case DlcTitleBlankTopCmb:
180 switch(dlc2->type){
181 case DlcTitleDashTopCmb:
182 case DlcTitleCmb:
183 case DlcTitleDashBottomCmb:
184 case DlcTitleBlankBottomCmb:
185 case DlcClickHereCmb:
186 case DlcTitleBlankTopCmb:
187 return 1;
189 default:
190 return 0;
192 break;
194 default:
195 return 0;
197 /*NOTREACHED*/
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.
217 DL_CACHE_S *
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;
222 long next_row;
223 long prev_row;
226 if(op == Lookup){
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 */
236 known_index =
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;
245 dlc =
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 */
261 valid_low++;
262 index_of_low = (index_of_low + 1) % size_of_cache;
264 else
265 n_cached++;
267 valid_high++;
269 next_row++;
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;
281 dlc =
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 */
290 valid_high--;
291 else
292 n_cached++;
294 valid_low--;
295 index_of_low =
296 (index_of_low - 1 + size_of_cache) % size_of_cache;
298 prev_row--;
299 known_index = new_index;
303 else if(op == Initialize){
305 n_cached = 0;
307 if(!cache_array || size_of_cache != 3 * MAX(as.l_p_page,1)){
308 if(cache_array)
309 free_cache_array(&cache_array, size_of_cache);
311 size_of_cache = 3 * MAX(as.l_p_page,1);
312 cache_array =
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){
325 long low_entry;
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) %
330 size_of_cache;
331 if(!dlc_siblings(dlc_start, &cache_array[next_index]))
332 break;
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) %
343 size_of_cache;
344 if(cache_array[next_index].type == DlcListBlankBottom)
345 low_entry--;
348 if(low_entry > valid_low){ /* invalidate everything >= this */
349 n_cached -= (valid_high - (low_entry - 1L));
350 valid_high = low_entry - 1L;
352 else{
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;
363 for(;;){
365 new_index = (known_index - 1 + size_of_cache) % size_of_cache;
366 dlc =
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;
374 valid_low--;
375 index_of_low =
376 (index_of_low - 1 + size_of_cache) % size_of_cache;
378 if(!dlc_siblings(dlc_start, dlc))
379 break;
381 known_index = new_index;
384 n_cached = 1;
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();
394 n_cached++;
395 dlc = &cache_array[0];
396 dlc = get_global_top_dlc(dlc);
397 dlc->global_row = row;
398 index_of_low = 0;
399 valid_low = row;
400 valid_high = row;
402 /* And here's how we start from the bottom. */
403 else if(op == LastEntry){
404 initialize_dlc_cache();
405 n_cached++;
406 dlc = &cache_array[0];
407 dlc = get_global_bottom_dlc(dlc);
408 dlc->global_row = row;
409 index_of_low = 0;
410 valid_low = row;
411 valid_high = 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
418 * adrbk_num_start.
420 else if(op == ArbitraryStartingPoint){
421 AddrScrn_Disp dl;
423 initialize_dlc_cache();
424 n_cached++;
425 dlc = &cache_array[0];
427 * Save this in case fill_in_dl_field needs to free the text
428 * it points to.
430 dl = dlc->dl;
431 *dlc = *dlc_start;
432 dlc->dl = dl;
433 dlc->global_row = row;
435 index_of_low = 0;
436 valid_low = row;
437 valid_high = row;
439 else if(op == DoneWithCache){
441 n_cached = 0;
442 if(cache_array)
443 free_cache_array(&cache_array, size_of_cache);
446 return(dlc);
448 panic_abook_corrupt:
449 q_status_message(SM_ORDER | SM_DING, 5, 10,
450 _("Addrbook changed unexpectedly, re-syncing..."));
451 dprint((1,
452 _("addrbook changed while we had it open?, re-sync\n")));
453 dprint((2,
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));
456 dprint((2,
457 "n_cached=%d new_index=%d known_index=%d next_index=%d\n",
458 n_cached, new_index, known_index, next_index));
459 dprint((2,
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);
463 /*NOTREACHED*/
467 void
468 free_cache_array(DL_CACHE_S **c_array, int size)
470 DL_CACHE_S *dlc;
471 int i;
473 for(i = 0; i < size; i++){
474 dlc = &(*c_array)[i];
475 /* free any allocated space */
476 switch(dlc->dl.type){
477 case Text:
478 case Title:
479 case TitleCmb:
480 case AskServer:
481 if(dlc->dl.usst)
482 fs_give((void **)&dlc->dl.usst);
484 break;
485 default:
486 break;
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
498 * the answer.
500 DL_CACHE_S *
501 dlc_prev(DL_CACHE_S *old, DL_CACHE_S *new)
503 PerAddrBook *pab;
504 AdrBk_Entry *abe;
505 adrbk_cntr_t list_count;
507 new->adrbk_num = -2;
508 new->dlcelnum = NO_NEXT;
509 new->dlcoffset = NO_NEXT;
510 new->type = DlcNotSet;
511 pab = &as.adrbks[old->adrbk_num];
513 switch(old->type){
514 case DlcTitle:
515 case DlcTitleNoPerm:
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;
522 else
523 new->type = DlcTitleBlankTop;
525 break;
527 case DlcSubTitle:
528 if(pab->access == NoAccess)
529 new->type = DlcTitleNoPerm;
530 else
531 new->type = DlcTitle;
533 break;
535 case DlcTitleBlankTop:
536 new->adrbk_num = old->adrbk_num - 1;
537 new->type = DlcSubTitle;
538 break;
540 case DlcEmpty:
541 case DlcZoomEmpty:
542 case DlcNoPermission:
543 case DlcNoAbooks:
544 if(F_ON(F_CMBND_ABOOK_DISP,ps_global)){
545 if(as.n_addrbk == 1 && as.n_serv == 0)
546 new->type = DlcOneBeforeBeginning;
547 else
548 new->type = DlcTitleBlankBottomCmb;
550 else
551 new->type = DlcOneBeforeBeginning;
553 break;
555 case DlcSimple:
557 adrbk_cntr_t el;
558 long i;
560 i = old->dlcelnum;
561 i--;
562 el = old->dlcelnum - 1;
563 while(i >= 0L){
564 if(!as.zoomed || entry_is_selected(pab->address_book->selects,
565 (a_c_arg_t)el))
566 break;
568 el--;
569 i--;
572 if(i >= 0){
573 new->dlcelnum = el;
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;
583 else
584 new->type = DlcTitleBlankBottomCmb;
586 else
587 new->type = DlcOneBeforeBeginning;
590 break;
592 case DlcListHead:
594 adrbk_cntr_t el;
595 long i;
597 i = old->dlcelnum;
598 i--;
599 el = old->dlcelnum - 1;
600 while(i >= 0L){
601 if(!as.zoomed || entry_is_selected(pab->address_book->selects,
602 (a_c_arg_t)el))
603 break;
605 el--;
606 i--;
609 if(i >= 0){
610 new->dlcelnum = el;
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;
622 else
623 new->type = DlcTitleBlankBottomCmb;
625 else
626 new->type = DlcOneBeforeBeginning;
629 break;
631 case DlcListEnt:
632 if(old->dlcoffset > 0){
633 new->type = DlcListEnt;
634 new->dlcelnum = old->dlcelnum;
635 new->dlcoffset = old->dlcoffset - 1;
637 else{
638 new->type = DlcListHead;
639 new->dlcelnum = old->dlcelnum;
642 break;
644 case DlcListClickHere:
645 case DlcListEmpty:
646 new->type = DlcListHead;
647 new->dlcelnum = old->dlcelnum;
648 break;
650 case DlcListBlankTop: /* can only occur between a Simple and a List */
651 new->type = DlcSimple;
653 adrbk_cntr_t el;
654 long i;
656 i = old->dlcelnum;
657 i--;
658 el = old->dlcelnum - 1;
659 while(i >= 0L){
660 if(!as.zoomed || entry_is_selected(pab->address_book->selects,
661 (a_c_arg_t)el))
662 break;
664 el--;
665 i--;
668 if(i >= 0)
669 new->dlcelnum = el;
670 else{
671 dprint((1, "Bug in addrbook: case ListBlankTop with no selected entry\n"));
672 goto oops;
676 break;
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);
684 if(list_count == 0)
685 new->type = DlcListEmpty;
686 else{
687 new->type = DlcListEnt;
688 new->dlcoffset = list_count - 1;
691 else
692 new->type = DlcListClickHere;
694 break;
696 case DlcGlobDelim1:
697 if(as.how_many_personals == 0)
698 new->type = DlcPersAdd;
699 else{
700 new->adrbk_num = as.how_many_personals - 1;
701 new->type = DlcSubTitle;
703 break;
705 case DlcGlobDelim2:
706 new->type = DlcGlobDelim1;
707 break;
709 case DlcPersAdd:
710 new->type = DlcOneBeforeBeginning;
711 break;
713 case DlcGlobAdd:
714 new->type = DlcGlobDelim2;
715 break;
717 case DlcDirAccess:
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;
722 else
723 new->type = DlcDirBlankTop;
725 break;
727 case DlcDirSubTitle:
728 new->type = DlcDirAccess;
729 break;
731 case DlcDirBlankTop:
732 new->adrbk_num = old->adrbk_num -1;
733 new->type = DlcDirSubTitle;
734 break;
736 case DlcDirDelim1:
737 new->adrbk_num = as.n_addrbk - 1;
738 if(as.n_addrbk == 0)
739 new->type = DlcNoAbooks;
740 else
741 new = get_bottom_dl_of_adrbk(new->adrbk_num, new);
743 break;
745 case DlcDirDelim1a:
746 new->type = DlcDirDelim1;
747 break;
749 case DlcDirDelim1b:
750 new->type = DlcDirDelim1a;
751 break;
753 case DlcDirDelim1c:
754 new->type = DlcDirDelim1b;
755 break;
757 case DlcDirDelim2:
758 if(F_ON(F_CMBND_ABOOK_DISP,ps_global))
759 new->type = DlcDirDelim1c;
760 else
761 new->type = DlcDirDelim1;
763 break;
765 case DlcTitleDashTopCmb:
766 if(old->adrbk_num == 0)
767 new->type = DlcOneBeforeBeginning;
768 else
769 new->type = DlcTitleBlankTopCmb;
771 break;
773 case DlcTitleCmb:
774 new->type = DlcTitleDashTopCmb;
775 break;
777 case DlcTitleDashBottomCmb:
778 new->type = DlcTitleCmb;
779 break;
781 case DlcTitleBlankBottomCmb:
782 new->type = DlcTitleDashBottomCmb;
783 break;
785 case DlcClickHereCmb:
786 if(as.n_addrbk == 1 && as.n_serv == 0)
787 new->type = DlcOneBeforeBeginning;
788 else
789 new->type = DlcTitleBlankBottomCmb;
791 break;
793 case DlcTitleBlankTopCmb:
794 new->adrbk_num = old->adrbk_num - 1;
795 new = get_bottom_dl_of_adrbk(new->adrbk_num, new);
796 break;
798 case DlcBeginning:
799 case DlcTwoBeforeBeginning:
800 new->type = DlcBeginning;
801 break;
803 case DlcOneBeforeBeginning:
804 new->type = DlcTwoBeforeBeginning;
805 break;
807 oops:
808 default:
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",
812 old->type));
813 /* jump back to a safe starting point */
814 longjmp(addrbook_changed_unexpectedly, 1);
815 /*NOTREACHED*/
818 new->global_row = old->global_row - 1L;
819 if(new->adrbk_num == -2)
820 new->adrbk_num = old->adrbk_num;
822 return(new);
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
829 * calling here.
831 DL_CACHE_S *
832 dlc_next(DL_CACHE_S *old, DL_CACHE_S *new)
834 PerAddrBook *pab;
835 AdrBk_Entry *abe;
836 adrbk_cntr_t ab_count;
837 adrbk_cntr_t list_count;
839 new->adrbk_num = -2;
840 new->dlcelnum = NO_NEXT;
841 new->dlcoffset = NO_NEXT;
842 new->type = DlcNotSet;
843 pab = &as.adrbks[old->adrbk_num];
845 switch(old->type){
846 case DlcTitle:
847 case DlcTitleNoPerm:
848 new->type = DlcSubTitle;
849 break;
851 case 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)
859 new->type = DlcEnd;
860 else{
861 new->adrbk_num = old->adrbk_num + 1;
862 new->type = DlcTitleBlankTop;
865 break;
867 case DlcTitleBlankTop:
868 if(pab->access == NoAccess)
869 new->type = DlcTitleNoPerm;
870 else
871 new->type = DlcTitle;
873 break;
875 case DlcEmpty:
876 case DlcZoomEmpty:
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;
884 else if(as.n_serv)
885 new->type = DlcDirDelim1;
886 else
887 new->type = DlcEnd;
889 else
890 new->type = DlcEnd;
892 break;
894 case DlcNoAbooks:
895 case DlcGlobAdd:
896 case DlcEnd:
897 new->type = DlcEnd;
898 break;
900 case DlcSimple:
902 adrbk_cntr_t el;
903 long i;
905 ab_count = adrbk_count(pab->address_book);
906 i = old->dlcelnum;
907 i++;
908 el = old->dlcelnum + 1;
909 while(i < ab_count){
910 if(!as.zoomed || entry_is_selected(pab->address_book->selects,
911 (a_c_arg_t)el))
912 break;
914 el++;
915 i++;
918 if(i < ab_count){
919 new->dlcelnum = el;
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;
931 else if(as.n_serv)
932 new->type = DlcDirDelim1;
933 else
934 new->type = DlcEnd;
936 else
937 new->type = DlcEnd;
940 break;
942 case DlcListHead:
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);
948 if(list_count == 0)
949 new->type = DlcListEmpty;
950 else{
951 new->type = DlcListEnt;
952 new->dlcoffset = 0;
955 else
956 new->type = DlcListClickHere;
958 break;
960 case DlcListEnt:
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 */
965 adrbk_cntr_t el;
966 long i;
968 ab_count = adrbk_count(pab->address_book);
969 i = old->dlcelnum;
970 i++;
971 el = old->dlcelnum + 1;
972 while(i < ab_count){
973 if(!as.zoomed || entry_is_selected(pab->address_book->selects,
974 (a_c_arg_t)el))
975 break;
977 el++;
978 i++;
981 if(i < ab_count)
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;
988 else if(as.n_serv)
989 new->type = DlcDirDelim1;
990 else
991 new->type = DlcEnd;
993 else
994 new->type = DlcEnd;
996 else{
997 new->type = DlcListEnt;
998 new->dlcoffset = old->dlcoffset + 1;
1001 break;
1003 case DlcListClickHere:
1004 case DlcListEmpty:
1006 adrbk_cntr_t el;
1007 long i;
1009 new->dlcelnum = old->dlcelnum;
1010 ab_count = adrbk_count(pab->address_book);
1011 i = old->dlcelnum;
1012 i++;
1013 el = old->dlcelnum + 1;
1014 while(i < ab_count){
1015 if(!as.zoomed || entry_is_selected(pab->address_book->selects,
1016 (a_c_arg_t)el))
1017 break;
1019 el++;
1020 i++;
1023 if(i < ab_count)
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;
1030 else if(as.n_serv)
1031 new->type = DlcDirDelim1;
1032 else
1033 new->type = DlcEnd;
1035 else
1036 new->type = DlcEnd;
1039 break;
1041 case DlcListBlankTop:
1042 new->type = DlcListHead;
1043 new->dlcelnum = old->dlcelnum;
1044 break;
1046 case DlcListBlankBottom:
1048 adrbk_cntr_t el;
1049 long i;
1051 ab_count = adrbk_count(pab->address_book);
1052 i = old->dlcelnum;
1053 i++;
1054 el = old->dlcelnum + 1;
1055 while(i < ab_count){
1056 if(!as.zoomed || entry_is_selected(pab->address_book->selects,
1057 (a_c_arg_t)el))
1058 break;
1060 el++;
1061 i++;
1064 if(i < ab_count){
1065 new->dlcelnum = el;
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;
1072 else
1073 /* can't happen */
1074 new->type = DlcEnd;
1077 break;
1079 case DlcGlobDelim1:
1080 new->type = DlcGlobDelim2;
1081 break;
1083 case DlcGlobDelim2:
1084 if(as.config && as.how_many_personals == as.n_addrbk)
1085 new->type = DlcGlobAdd;
1086 else{
1087 new->adrbk_num = as.how_many_personals;
1088 pab = &as.adrbks[new->adrbk_num];
1089 if(pab->access == NoAccess)
1090 new->type = DlcTitleNoPerm;
1091 else
1092 new->type = DlcTitle;
1095 break;
1097 case DlcDirDelim1:
1098 if(F_ON(F_CMBND_ABOOK_DISP,ps_global))
1099 new->type = DlcDirDelim1a;
1100 else
1101 new->type = DlcDirDelim2;
1103 new->adrbk_num = 0;
1104 break;
1106 case DlcDirDelim1a:
1107 new->type = DlcDirDelim1b;
1108 break;
1110 case DlcDirDelim1b:
1111 new->type = DlcDirDelim1c;
1112 break;
1114 case DlcDirDelim1c:
1115 new->type = DlcDirDelim2;
1116 new->adrbk_num = 0;
1117 break;
1119 case DlcDirDelim2:
1120 new->type = DlcDirAccess;
1121 new->adrbk_num = 0;
1122 break;
1124 case DlcPersAdd:
1125 new->type = DlcGlobDelim1;
1126 break;
1128 case DlcDirAccess:
1129 new->type = DlcDirSubTitle;
1130 break;
1132 case DlcDirSubTitle:
1133 if(old->adrbk_num == as.n_serv - 1)
1134 new->type = DlcEnd;
1135 else{
1136 new->type = DlcDirBlankTop;
1137 new->adrbk_num = old->adrbk_num + 1;
1140 break;
1142 case DlcDirBlankTop:
1143 new->type = DlcDirAccess;
1144 break;
1146 case DlcTitleDashTopCmb:
1147 new->type = DlcTitleCmb;
1148 break;
1150 case DlcTitleCmb:
1151 new->type = DlcTitleDashBottomCmb;
1152 break;
1154 case DlcTitleDashBottomCmb:
1155 new->type = DlcTitleBlankBottomCmb;
1156 break;
1158 case DlcTitleBlankBottomCmb:
1159 pab = &as.adrbks[old->adrbk_num];
1160 if(pab->ostatus != Open && pab->access != NoAccess)
1161 new->type = DlcClickHereCmb;
1162 else
1163 new = get_top_dl_of_adrbk(old->adrbk_num, new);
1165 break;
1167 case DlcTitleBlankTopCmb:
1168 new->type = DlcTitleDashTopCmb;
1169 break;
1171 case DlcOneBeforeBeginning:
1172 new = get_global_top_dlc(new);
1173 break;
1175 case DlcTwoBeforeBeginning:
1176 new->type = DlcOneBeforeBeginning;
1177 break;
1179 default:
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",
1183 old->type));
1184 /* jump back to a safe starting point */
1185 longjmp(addrbook_changed_unexpectedly, 1);
1186 /*NOTREACHED*/
1189 new->global_row = old->global_row + 1L;
1190 if(new->adrbk_num == -2)
1191 new->adrbk_num = old->adrbk_num;
1193 return(new);
1198 * Get the display line at the very top of whole addrbook screen display.
1200 DL_CACHE_S *
1201 get_global_top_dlc(DL_CACHE_S *new)
1202 /* fill in answer here */
1204 PerAddrBook *pab;
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){
1211 new->adrbk_num = 0;
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;
1218 new->adrbk_num = 0;
1220 else
1221 new->type = DlcNoAbooks;
1223 else{
1224 new->adrbk_num = 0;
1226 if(as.config){
1227 if(as.how_many_personals == 0) /* no personals */
1228 new->type = DlcPersAdd;
1229 else{
1230 pab = &as.adrbks[new->adrbk_num]; /* 1st personal */
1231 if(pab->access == NoAccess)
1232 new->type = DlcTitleNoPerm;
1233 else
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;
1245 else
1246 new->type = DlcTitle;
1248 else if(as.n_serv > 0){ /* 1st directory */
1249 new->type = DlcDirAccess;
1250 new->adrbk_num = 0;
1252 else
1253 new->type = DlcNoAbooks;
1256 return(new);
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.
1264 DL_CACHE_S *
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){
1273 if(as.n_serv){
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);
1281 else
1282 new->type = DlcNoAbooks;
1284 else{
1285 new->adrbk_num = MAX(as.n_addrbk - 1, 0);
1287 if(as.config){
1288 if(as.how_many_personals == as.n_addrbk) /* no globals */
1289 new->type = DlcGlobAdd;
1290 else
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);
1297 else if(as.n_serv){
1298 new->type = DlcDirSubTitle;
1299 new->adrbk_num = as.n_serv - 1;
1301 else{ /* !config && !opened && !n_serv */
1302 if(as.n_addrbk)
1303 new->type = DlcSubTitle;
1304 else
1305 new->type = DlcNoAbooks;
1309 return(new);
1314 * First dl in a particular addrbook, not counting title lines.
1315 * Assumes as.opened.
1317 DL_CACHE_S *
1318 get_top_dl_of_adrbk(int adrbk_num, DL_CACHE_S *new)
1320 /* fill in answer here */
1322 PerAddrBook *pab;
1323 AdrBk_Entry *abe;
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;
1331 else{
1332 adrbk_cntr_t el;
1333 long i;
1335 ab_count = adrbk_count(pab->address_book);
1337 i = 0L;
1338 el = 0;
1339 /* find first displayed entry */
1340 while(i < ab_count){
1341 if(!as.zoomed || entry_is_selected(pab->address_book->selects,
1342 (a_c_arg_t)el))
1343 break;
1345 el++;
1346 i++;
1349 if(i < ab_count){
1350 new->dlcelnum = el;
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;
1357 else if(as.zoomed)
1358 new->type = DlcZoomEmpty;
1359 else
1360 new->type = DlcEmpty;
1363 return(new);
1368 * Find the last display line for addrbook number adrbk_num.
1369 * Assumes as.opened (unless OLD_ABOOK_DISP).
1371 DL_CACHE_S *
1372 get_bottom_dl_of_adrbk(int adrbk_num, DL_CACHE_S *new)
1374 /* fill in answer here */
1376 PerAddrBook *pab;
1377 AdrBk_Entry *abe;
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;
1387 else
1388 new->type = DlcClickHereCmb;
1390 else if(F_OFF(F_CMBND_ABOOK_DISP,ps_global) && pab->ostatus != Open){
1391 new->type = DlcSubTitle;
1393 else{
1394 if(pab->access == NoAccess)
1395 new->type = DlcNoPermission;
1396 else{
1397 adrbk_cntr_t el;
1398 long i;
1400 ab_count = adrbk_count(pab->address_book);
1401 i = ab_count - 1;
1402 el = ab_count - 1;
1403 /* find last displayed entry */
1404 while(i >= 0L){
1405 if(!as.zoomed || entry_is_selected(pab->address_book->selects,
1406 (a_c_arg_t)el))
1407 break;
1409 el--;
1410 i--;
1413 if(i >= 0){
1414 new->dlcelnum = el;
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);
1423 if(list_count == 0)
1424 new->type = DlcListEmpty;
1425 else{
1426 new->type = DlcListEnt;
1427 new->dlcoffset = list_count - 1;
1430 else
1431 new->type = DlcListClickHere;
1434 else if(as.zoomed)
1435 new->type = DlcZoomEmpty;
1436 else
1437 new->type = DlcEmpty;
1442 return(new);
1447 * This returns the actual dlc instead of the dl within the dlc.
1449 DL_CACHE_S *
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
1461 * the cache.
1463 void
1464 warp_to_dlc(DL_CACHE_S *new_dlc, long int row_number_to_assign_it)
1466 DL_CACHE_S dlc;
1468 dprint((9, "- warp_to_dlc(%ld) -\n", row_number_to_assign_it));
1470 dlc = *new_dlc;
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.
1477 switch(dlc.type){
1478 case DlcPersAdd:
1479 dlc.adrbk_num = 0;
1480 break;
1481 case DlcGlobAdd:
1482 dlc.adrbk_num = as.n_addrbk;
1483 break;
1484 default:
1485 break;
1488 (void)dlc_mgr(row_number_to_assign_it, ArbitraryStartingPoint, &dlc);
1493 * Move to first dlc and give it row number 0.
1495 void
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.
1507 void
1508 warp_to_top_of_abook(int abook_num)
1510 DL_CACHE_S dlc;
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.
1522 void
1523 warp_to_end(void)
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.
1534 void
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)
1552 return 0;
1554 switch(dlc1->type){
1556 case DlcSimple:
1557 case DlcListHead:
1558 case DlcListBlankTop:
1559 case DlcListBlankBottom:
1560 case DlcListClickHere:
1561 case DlcListEmpty:
1562 return(dlc1->dlcelnum == dlc2->dlcelnum);
1564 case DlcListEnt:
1565 return(dlc1->dlcelnum == dlc2->dlcelnum &&
1566 dlc1->dlcoffset == dlc2->dlcoffset);
1568 case DlcTitle:
1569 case DlcSubTitle:
1570 case DlcTitleNoPerm:
1571 case DlcTitleBlankTop:
1572 case DlcEmpty:
1573 case DlcZoomEmpty:
1574 case DlcNoPermission:
1575 case DlcPersAdd:
1576 case DlcGlobAdd:
1577 case DlcGlobDelim1:
1578 case DlcGlobDelim2:
1579 case DlcDirAccess:
1580 case DlcDirDelim1:
1581 case DlcDirDelim2:
1582 case DlcTitleDashTopCmb:
1583 case DlcTitleCmb:
1584 case DlcTitleDashBottomCmb:
1585 case DlcTitleBlankBottomCmb:
1586 case DlcClickHereCmb:
1587 case DlcTitleBlankTopCmb:
1588 return 1;
1590 case DlcNotSet:
1591 case DlcBeginning:
1592 case DlcOneBeforeBeginning:
1593 case DlcTwoBeforeBeginning:
1594 case DlcEnd:
1595 case DlcNoAbooks:
1596 return 0;
1598 default:
1599 break;
1601 /*NOTREACHED*/
1603 return 0;
1608 * Uses information in new to fill in new->dl.
1610 void
1611 fill_in_dl_field(DL_CACHE_S *new)
1613 AddrScrn_Disp *dl;
1614 PerAddrBook *pab;
1615 char buf[6*MAX_SCREEN_COLS + 1];
1616 char buf2[6*1024];
1617 char hostbuf[128];
1618 char *folder;
1619 char *q;
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);
1625 dl = &(new->dl);
1627 /* free any previously allocated space */
1628 switch(dl->type){
1629 case Text:
1630 case Title:
1631 case TitleCmb:
1632 case AskServer:
1633 if(dl->usst)
1634 fs_give((void **)&dl->usst);
1635 default:
1636 break;
1639 /* set up new dl */
1640 switch(new->type){
1641 case DlcListBlankTop:
1642 case DlcListBlankBottom:
1643 case DlcGlobDelim1:
1644 case DlcGlobDelim2:
1645 case DlcDirDelim1:
1646 case DlcDirDelim2:
1647 case DlcTitleBlankTop:
1648 case DlcDirBlankTop:
1649 case DlcTitleBlankBottomCmb:
1650 case DlcTitleBlankTopCmb:
1651 dl->type = Text;
1652 dl->usst = cpystr("");
1653 break;
1655 case DlcTitleDashTopCmb:
1656 case DlcTitleDashBottomCmb:
1657 case DlcDirDelim1a:
1658 case DlcDirDelim1c:
1659 /* line of dashes in txt field */
1660 dl->type = Text;
1661 memset((void *)buf, '-', screen_width * sizeof(char));
1662 buf[screen_width] = '\0';
1663 dl->usst = cpystr(buf);
1664 break;
1666 case DlcNoPermission:
1667 dl->type = Text;
1668 dl->usst = cpystr(NO_PERMISSION);
1669 break;
1671 case DlcTitle:
1672 case DlcTitleNoPerm:
1673 dl->type = Title;
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)){
1689 char *str;
1691 if(pab->access == NoAccess)
1692 str = NOACCESS;
1693 else
1694 str = READONLY;
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);
1705 break;
1707 case DlcSubTitle:
1708 dl->type = Text;
1709 pab = &as.adrbks[new->adrbk_num];
1710 /* Find a hostname to put in title */
1711 hostbuf[0] = '\0';
1712 folder = NULL;
1713 if(pab->type & REMOTE_VIA_IMAP && pab->filename){
1714 char *start, *end;
1716 start = strindex(pab->filename, '{');
1717 if(start)
1718 end = strindex(start+1, '}');
1720 if(start && end){
1721 strncpy(hostbuf, start + 1,
1722 MIN(end - start - 1, sizeof(hostbuf)-1));
1723 hostbuf[MIN(end - start - 1, sizeof(hostbuf)-1)] = '\0';
1724 if(*(end+1))
1725 folder = end+1;
1729 if(!folder)
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;
1738 int l, saveval = 0;
1740 l = strlen(ps_global->home_dir);
1742 while(!new_folder && (p = last_cmpnt(folder)) != NULL){
1743 if(savep){
1744 *savep = saveval;
1745 savep = NULL;
1748 if(folder + l == p || folder + l + 1 == p)
1749 new_folder = p;
1750 else{
1751 savep = --p;
1752 saveval = *savep;
1753 *savep = '\0';
1757 if(savep)
1758 *savep = saveval;
1760 if(new_folder)
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);
1780 break;
1782 case DlcTitleCmb:
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) ?
1788 "Personal" :
1789 "Global",
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)){
1803 char *str;
1805 if(pab->access == NoAccess)
1806 str = NOACCESS;
1807 else
1808 str = READONLY;
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);
1819 break;
1821 case DlcDirDelim1b:
1822 dl->type = Text;
1823 utf8_snprintf(buf, sizeof(buf), "%-*.*w", screen_width, screen_width, OLDSTYLE_DIR_TITLE);
1824 dl->usst = cpystr(buf);
1825 break;
1827 case DlcClickHereCmb:
1828 dl->type = ClickHereCmb;
1829 break;
1831 case DlcListClickHere:
1832 dl->type = ListClickHere;
1833 dl->elnum = new->dlcelnum;
1834 break;
1836 case DlcListEmpty:
1837 dl->type = ListEmpty;
1838 dl->elnum = new->dlcelnum;
1839 break;
1841 case DlcEmpty:
1842 dl->type = Empty;
1843 break;
1845 case DlcZoomEmpty:
1846 dl->type = ZoomEmpty;
1847 break;
1849 case DlcNoAbooks:
1850 dl->type = NoAbooks;
1851 break;
1853 case DlcPersAdd:
1854 dl->type = AddFirstPers;
1855 break;
1857 case DlcGlobAdd:
1858 dl->type = AddFirstGlob;
1859 break;
1861 case DlcDirAccess:
1862 dl->type = AskServer;
1864 #ifdef ENABLE_LDAP
1866 LDAP_SERV_S *info;
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));
1873 if(info)
1874 free_ldap_server_info(&info);
1876 #else
1877 snprintf(buf2, sizeof(buf2), " %s", comatose(new->adrbk_num + 1));
1878 #endif
1880 utf8_snprintf(buf, sizeof(buf), "%-*.*w", screen_width, screen_width, buf2);
1881 dl->usst = cpystr(buf);
1882 break;
1884 case DlcDirSubTitle:
1885 dl->type = Text;
1886 #ifdef ENABLE_LDAP
1888 LDAP_SERV_S *info;
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 : "<?>",
1894 info->port);
1895 else
1896 snprintf(buf2, sizeof(buf2), " Directory Server on %s",
1897 (info && info->serv && *info->serv) ? info->serv : "<?>");
1899 if(info)
1900 free_ldap_server_info(&info);
1902 #else
1903 snprintf(buf2, sizeof(buf2), " Directory Server %s",
1904 comatose(new->adrbk_num + 1));
1905 #endif
1907 utf8_snprintf(buf, sizeof(buf), "%-*.*w", screen_width, screen_width, buf2);
1908 dl->usst = cpystr(buf);
1909 break;
1911 case DlcSimple:
1912 dl->type = Simple;
1913 dl->elnum = new->dlcelnum;
1914 break;
1916 case DlcListHead:
1917 dl->type = ListHead;
1918 dl->elnum = new->dlcelnum;
1919 break;
1921 case DlcListEnt:
1922 dl->type = ListEnt;
1923 dl->elnum = new->dlcelnum;
1924 dl->l_offset = new->dlcoffset;
1925 break;
1927 case DlcBeginning:
1928 case DlcOneBeforeBeginning:
1929 case DlcTwoBeforeBeginning:
1930 dl->type = Beginning;
1931 break;
1933 case DlcEnd:
1934 dl->type = End;
1935 break;
1937 default:
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",
1941 new->type));
1942 /* jump back to a safe starting point */
1943 longjmp(addrbook_changed_unexpectedly, 1);
1944 /*NOTREACHED*/
1950 * Returns a pointer to the member_number'th list member of the list
1951 * associated with this display line.
1953 char *
1954 listmem(long int row)
1956 PerAddrBook *pab;
1957 AddrScrn_Disp *dl;
1959 dl = dlist(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.
1973 char *
1974 listmem_from_dl(AdrBk *address_book, AddrScrn_Disp *dl)
1976 AdrBk_Entry *abe;
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
1988 * instead.
1990 if(abe && abe->tag == List){
1991 p = abe->addr.list;
1992 p += dl->l_offset;
1995 return((p && *p) ? *p : (char *)NULL);
2000 * How many members in list?
2002 adrbk_cntr_t
2003 listmem_count_from_abe(AdrBk_Entry *abe)
2005 char **p;
2007 if(abe->tag != List)
2008 return 0;
2010 for(p = abe->addr.list; p != NULL && *p != NULL; p++)
2011 ;/* do nothing */
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.
2029 AddrScrn_Disp *
2030 dlist(long int row)
2032 DL_CACHE_S *dlc = (DL_CACHE_S *)NULL;
2034 dlc = get_dlc(row);
2036 if(dlc){
2037 fill_in_dl_field(dlc);
2038 return(&dlc->dl);
2040 else{
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);
2050 /*NOTREACHED*/
2056 * Returns the index of the current address book.
2059 adrbk_num_from_lineno(long int lineno)
2061 DL_CACHE_S *dlc;
2063 dlc = get_dlc(lineno);
2065 return(dlc->adrbk_num);