diff options
Diffstat (limited to 'pith/abdlc.c')
-rw-r--r-- | pith/abdlc.c | 2066 |
1 files changed, 2066 insertions, 0 deletions
diff --git a/pith/abdlc.c b/pith/abdlc.c new file mode 100644 index 00000000..d332a1b7 --- /dev/null +++ b/pith/abdlc.c @@ -0,0 +1,2066 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: abdlc.c 769 2007-10-24 00:15:40Z hubert@u.washington.edu $"; +#endif + +/* + * ======================================================================== + * Copyright 2006-2007 University of Washington + * Copyright 2013 Eduardo Chappa + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include "../pith/headers.h" /* for os-dep and pith defs/includes */ +#include "../pith/abdlc.h" +#include "../pith/state.h" +#include "../pith/conf.h" +#include "../pith/status.h" +#include "../pith/ldap.h" +#include "../pith/tempfile.h" + + +/* + * Internal prototypes + */ +void initialize_dlc_cache(void); +int dlc_siblings(DL_CACHE_S *, DL_CACHE_S *); +DL_CACHE_S *dlc_mgr(long, DlMgrOps, DL_CACHE_S *); +void free_cache_array(DL_CACHE_S **, int); +DL_CACHE_S *dlc_prev(DL_CACHE_S *, DL_CACHE_S *); +DL_CACHE_S *dlc_next(DL_CACHE_S *, DL_CACHE_S *); +DL_CACHE_S *get_global_top_dlc(DL_CACHE_S *); +DL_CACHE_S *get_global_bottom_dlc(DL_CACHE_S *); +DL_CACHE_S *get_top_dl_of_adrbk(int, DL_CACHE_S *); +DL_CACHE_S *get_bottom_dl_of_adrbk(int, DL_CACHE_S *); + + +#define NO_PERMISSION _("[ Permission Denied ]") +/* TRANSLATORS: This is a heading referring to something that is readable + but not writeable. */ +#define READONLY _(" (ReadOnly)") +/* TRANSLATORS: Not readable */ +#define NOACCESS _(" (Un-readable)") +/* TRANSLATORS: Directories, as in LDAP Directories. A heading. */ +#define OLDSTYLE_DIR_TITLE _("Directories") + + +/* data for the display list cache */ +static DL_CACHE_S *cache_array = (DL_CACHE_S *)NULL; +static long valid_low, + valid_high; +static int index_of_low, + size_of_cache, + n_cached; + + +void +initialize_dlc_cache(void) +{ + dprint((11, "- initialize_dlc_cache -\n")); + + (void)dlc_mgr(NO_LINE, Initialize, (DL_CACHE_S *)NULL); +} + + +void +done_with_dlc_cache(void) +{ + dprint((11, "- done_with_dlc_cache -\n")); + + (void)dlc_mgr(NO_LINE, DoneWithCache, (DL_CACHE_S *)NULL); +} + + +/* + * Returns 1 if the dlc's are related to each other, 0 otherwise. + * + * The idea is that if you are going to flush one of these dlcs from the + * cache you should also flush its partners. For example, if you flush one + * Listent from a list you should flush the entire entry including all the + * Listents and the ListHead. If you flush a DlcTitle, you should also + * flush the SubTitle and the TitleBlankTop. + */ +int +dlc_siblings(DL_CACHE_S *dlc1, DL_CACHE_S *dlc2) +{ + if(!dlc1 || !dlc2 || dlc1->adrbk_num != dlc2->adrbk_num) + return 0; + + switch(dlc1->type){ + + case DlcSimple: + case DlcListHead: + case DlcListBlankTop: + case DlcListBlankBottom: + case DlcListEnt: + case DlcListClickHere: + case DlcListEmpty: + switch(dlc2->type){ + case DlcSimple: + case DlcListHead: + case DlcListBlankTop: + case DlcListBlankBottom: + case DlcListEnt: + case DlcListClickHere: + case DlcListEmpty: + return(dlc1->dlcelnum == dlc2->dlcelnum); + + default: + return 0; + } + + break; + + case DlcDirDelim1: + case DlcDirDelim2: + switch(dlc2->type){ + case DlcDirDelim1: + case DlcDirDelim2: + return 1; + + default: + return 0; + } + break; + + case DlcGlobDelim1: + case DlcGlobDelim2: + switch(dlc2->type){ + case DlcGlobDelim1: + case DlcGlobDelim2: + return 1; + + default: + return 0; + } + break; + + case DlcTitle: + case DlcTitleNoPerm: + case DlcSubTitle: + case DlcTitleBlankTop: + switch(dlc2->type){ + case DlcTitle: + case DlcTitleNoPerm: + case DlcSubTitle: + case DlcTitleBlankTop: + return 1; + + default: + return 0; + } + break; + + case DlcDirAccess: + case DlcDirSubTitle: + case DlcDirBlankTop: + switch(dlc2->type){ + case DlcDirAccess: + case DlcDirSubTitle: + case DlcDirBlankTop: + return 1; + + default: + return 0; + } + break; + + case DlcTitleDashTopCmb: + case DlcTitleCmb: + case DlcTitleDashBottomCmb: + case DlcTitleBlankBottomCmb: + case DlcClickHereCmb: + case DlcTitleBlankTopCmb: + switch(dlc2->type){ + case DlcTitleDashTopCmb: + case DlcTitleCmb: + case DlcTitleDashBottomCmb: + case DlcTitleBlankBottomCmb: + case DlcClickHereCmb: + case DlcTitleBlankTopCmb: + return 1; + + default: + return 0; + } + break; + + default: + return 0; + } + /*NOTREACHED*/ +} + + +/* + * Manage the display list cache. + * + * The cache is a circular array of DL_CACHE_S elements. It always + * contains a contiguous set of display lines. + * The lowest numbered line in the cache is + * valid_low, and the highest is valid_high. Everything in between is + * also valid. Index_of_low is where to look + * for the valid_low element in the circular array. + * + * We make calls to dlc_prev and dlc_next to get new entries for the cache. + * We need a starting value before we can do that. + * + * This returns a pointer to a dlc for the desired row. If you want the + * actual display list line you call dlist(row) instead of dlc_mgr. + */ +DL_CACHE_S * +dlc_mgr(long int row, DlMgrOps op, DL_CACHE_S *dlc_start) +{ + int new_index, known_index, next_index; + DL_CACHE_S *dlc = (DL_CACHE_S *)NULL; + long next_row; + long prev_row; + + + if(op == Lookup){ + + if(row >= valid_low && row <= valid_high){ /* already cached */ + + new_index = ((row - valid_low) + index_of_low) % size_of_cache; + dlc = &cache_array[new_index]; + + } + else if(row > valid_high){ /* row is past where we've looked */ + + known_index = + ((valid_high - valid_low) + index_of_low) % size_of_cache; + next_row = valid_high + 1L; + + /* we'll usually be looking for row = valid_high + 1 */ + while(next_row <= row){ + + new_index = (known_index + 1) % size_of_cache; + + dlc = + dlc_next(&cache_array[known_index], &cache_array[new_index]); + + /* + * This means somebody changed the file out from underneath + * us. This would happen if dlc_next needed to ask for an + * abe to figure out what the type of the next row is, but + * adrbk_get_ae returned a NULL. I don't think that can + * happen, but if it does... + */ + if(dlc->type == DlcNotSet){ + dprint((1, "dlc_next returned DlcNotSet\n")); + goto panic_abook_corrupt; + } + + if(n_cached == size_of_cache){ /* replaced low cache entry */ + valid_low++; + index_of_low = (index_of_low + 1) % size_of_cache; + } + else + n_cached++; + + valid_high++; + + next_row++; + known_index = new_index; /* for next time through loop */ + } + } + else if(row < valid_low){ /* row is back up the screen */ + + known_index = index_of_low; + prev_row = valid_low - 1L; + + while(prev_row >= row){ + + new_index = (known_index - 1 + size_of_cache) % size_of_cache; + dlc = + dlc_prev(&cache_array[known_index], &cache_array[new_index]); + + if(dlc->type == DlcNotSet){ + dprint((1, "dlc_prev returned DlcNotSet (1)\n")); + goto panic_abook_corrupt; + } + + if(n_cached == size_of_cache) /* replaced high cache entry */ + valid_high--; + else + n_cached++; + + valid_low--; + index_of_low = + (index_of_low - 1 + size_of_cache) % size_of_cache; + + prev_row--; + known_index = new_index; + } + } + } + else if(op == Initialize){ + + n_cached = 0; + + if(!cache_array || size_of_cache != 3 * MAX(as.l_p_page,1)){ + if(cache_array) + free_cache_array(&cache_array, size_of_cache); + + size_of_cache = 3 * MAX(as.l_p_page,1); + cache_array = + (DL_CACHE_S *)fs_get(size_of_cache * sizeof(DL_CACHE_S)); + memset((void *)cache_array, 0, size_of_cache * sizeof(DL_CACHE_S)); + } + + /* this will return NULL below and the caller should ignore that */ + } + /* + * Flush all rows for a particular addrbook entry from the cache, but + * keep the cache alive and anchored in the same place. The particular + * entry is the one that dlc_start is one of the rows of. + */ + else if(op == FlushDlcFromCache){ + long low_entry; + + next_row = dlc_start->global_row - 1; + for(; next_row >= valid_low; next_row--){ + next_index = ((next_row - valid_low) + index_of_low) % + size_of_cache; + if(!dlc_siblings(dlc_start, &cache_array[next_index])) + break; + } + + low_entry = next_row + 1L; + + /* + * If low_entry now points one past a ListBlankBottom, delete that, + * too, since it may not make sense anymore. + */ + if(low_entry > valid_low){ + next_index = ((low_entry -1L - valid_low) + index_of_low) % + size_of_cache; + if(cache_array[next_index].type == DlcListBlankBottom) + low_entry--; + } + + if(low_entry > valid_low){ /* invalidate everything >= this */ + n_cached -= (valid_high - (low_entry - 1L)); + valid_high = low_entry - 1L; + } + else{ + /* + * This is the tough case. That entry was the first thing cached, + * so we need to invalidate the whole cache. However, we also + * need to keep at least one thing cached for an anchor, so + * we need to get the dlc before this one and it should be a + * dlc not related to this same addrbook entry. + */ + known_index = index_of_low; + prev_row = valid_low - 1L; + + for(;;){ + + new_index = (known_index - 1 + size_of_cache) % size_of_cache; + dlc = + dlc_prev(&cache_array[known_index], &cache_array[new_index]); + + if(dlc->type == DlcNotSet){ + dprint((1, "dlc_prev returned DlcNotSet (2)\n")); + goto panic_abook_corrupt; + } + + valid_low--; + index_of_low = + (index_of_low - 1 + size_of_cache) % size_of_cache; + + if(!dlc_siblings(dlc_start, dlc)) + break; + + known_index = new_index; + } + + n_cached = 1; + valid_high = valid_low; + } + } + /* + * We have to anchor ourselves at a first element. + * Here's how we start at the top. + */ + else if(op == FirstEntry){ + initialize_dlc_cache(); + n_cached++; + dlc = &cache_array[0]; + dlc = get_global_top_dlc(dlc); + dlc->global_row = row; + index_of_low = 0; + valid_low = row; + valid_high = row; + } + /* And here's how we start from the bottom. */ + else if(op == LastEntry){ + initialize_dlc_cache(); + n_cached++; + dlc = &cache_array[0]; + dlc = get_global_bottom_dlc(dlc); + dlc->global_row = row; + index_of_low = 0; + valid_low = row; + valid_high = row; + } + /* + * And here's how we start from an arbitrary position in the middle. + * We root the cache at display line row, so it helps if row is close + * to where we're going to be starting so that things are easy to find. + * The dl that goes with line row is dl_start from addrbook number + * adrbk_num_start. + */ + else if(op == ArbitraryStartingPoint){ + AddrScrn_Disp dl; + + initialize_dlc_cache(); + n_cached++; + dlc = &cache_array[0]; + /* + * Save this in case fill_in_dl_field needs to free the text + * it points to. + */ + dl = dlc->dl; + *dlc = *dlc_start; + dlc->dl = dl; + dlc->global_row = row; + + index_of_low = 0; + valid_low = row; + valid_high = row; + } + else if(op == DoneWithCache){ + + n_cached = 0; + if(cache_array) + free_cache_array(&cache_array, size_of_cache); + } + + return(dlc); + +panic_abook_corrupt: + q_status_message(SM_ORDER | SM_DING, 5, 10, + _("Addrbook changed unexpectedly, re-syncing...")); + dprint((1, + _("addrbook changed while we had it open?, re-sync\n"))); + dprint((2, + "valid_low=%ld valid_high=%ld index_of_low=%d size_of_cache=%d\n", + valid_low, valid_high, index_of_low, size_of_cache)); + dprint((2, + "n_cached=%d new_index=%d known_index=%d next_index=%d\n", + n_cached, new_index, known_index, next_index)); + dprint((2, + "next_row=%ld prev_row=%ld row=%ld\n", next_row, prev_row, row)); + /* jump back to a safe starting point */ + longjmp(addrbook_changed_unexpectedly, 1); + /*NOTREACHED*/ +} + + +void +free_cache_array(DL_CACHE_S **c_array, int size) +{ + DL_CACHE_S *dlc; + int i; + + for(i = 0; i < size; i++){ + dlc = &(*c_array)[i]; + /* free any allocated space */ + switch(dlc->dl.type){ + case Text: + case Title: + case TitleCmb: + case AskServer: + if(dlc->dl.usst) + fs_give((void **)&dlc->dl.usst); + + break; + default: + break; + } + } + + fs_give((void **)c_array); +} + + +/* + * Get the dlc element that comes before "old". The function that calls this + * function is the one that keeps a cache and checks in the cache before + * calling here. New is a passed in pointer to a buffer where we fill in + * the answer. + */ +DL_CACHE_S * +dlc_prev(DL_CACHE_S *old, DL_CACHE_S *new) +{ + PerAddrBook *pab; + AdrBk_Entry *abe; + adrbk_cntr_t list_count; + + new->adrbk_num = -2; + new->dlcelnum = NO_NEXT; + new->dlcoffset = NO_NEXT; + new->type = DlcNotSet; + pab = &as.adrbks[old->adrbk_num]; + + switch(old->type){ + case DlcTitle: + case DlcTitleNoPerm: + if(old->adrbk_num == 0 && as.config && as.how_many_personals == 0) + new->type = DlcGlobDelim2; + else if(old->adrbk_num == 0) + new->type = DlcOneBeforeBeginning; + else if(old->adrbk_num == as.how_many_personals) + new->type = DlcGlobDelim2; + else + new->type = DlcTitleBlankTop; + + break; + + case DlcSubTitle: + if(pab->access == NoAccess) + new->type = DlcTitleNoPerm; + else + new->type = DlcTitle; + + break; + + case DlcTitleBlankTop: + new->adrbk_num = old->adrbk_num - 1; + new->type = DlcSubTitle; + break; + + case DlcEmpty: + case DlcZoomEmpty: + case DlcNoPermission: + case DlcNoAbooks: + if(F_ON(F_CMBND_ABOOK_DISP,ps_global)){ + if(as.n_addrbk == 1 && as.n_serv == 0) + new->type = DlcOneBeforeBeginning; + else + new->type = DlcTitleBlankBottomCmb; + } + else + new->type = DlcOneBeforeBeginning; + + break; + + case DlcSimple: + { + adrbk_cntr_t el; + long i; + + i = old->dlcelnum; + i--; + el = old->dlcelnum - 1; + while(i >= 0L){ + if(!as.zoomed || entry_is_selected(pab->address_book->selects, + (a_c_arg_t)el)) + break; + + el--; + i--; + } + + if(i >= 0){ + new->dlcelnum = el; + abe = adrbk_get_ae(pab->address_book, (a_c_arg_t) new->dlcelnum); + if(abe && abe->tag == Single) + new->type = DlcSimple; + else if(abe && abe->tag == List) + new->type = DlcListBlankBottom; + } + else if(F_ON(F_CMBND_ABOOK_DISP,ps_global)){ + if(as.n_addrbk == 1 && as.n_serv == 0) + new->type = DlcOneBeforeBeginning; + else + new->type = DlcTitleBlankBottomCmb; + } + else + new->type = DlcOneBeforeBeginning; + } + + break; + + case DlcListHead: + { + adrbk_cntr_t el; + long i; + + i = old->dlcelnum; + i--; + el = old->dlcelnum - 1; + while(i >= 0L){ + if(!as.zoomed || entry_is_selected(pab->address_book->selects, + (a_c_arg_t)el)) + break; + + el--; + i--; + } + + if(i >= 0){ + new->dlcelnum = el; + abe = adrbk_get_ae(pab->address_book, (a_c_arg_t) new->dlcelnum); + if(abe && abe->tag == Single){ + new->type = DlcListBlankTop; + new->dlcelnum = old->dlcelnum; + } + else if(abe && abe->tag == List) + new->type = DlcListBlankBottom; + } + else if(F_ON(F_CMBND_ABOOK_DISP,ps_global)){ + if(as.n_addrbk == 1 && as.n_serv == 0) + new->type = DlcOneBeforeBeginning; + else + new->type = DlcTitleBlankBottomCmb; + } + else + new->type = DlcOneBeforeBeginning; + } + + break; + + case DlcListEnt: + if(old->dlcoffset > 0){ + new->type = DlcListEnt; + new->dlcelnum = old->dlcelnum; + new->dlcoffset = old->dlcoffset - 1; + } + else{ + new->type = DlcListHead; + new->dlcelnum = old->dlcelnum; + } + + break; + + case DlcListClickHere: + case DlcListEmpty: + new->type = DlcListHead; + new->dlcelnum = old->dlcelnum; + break; + + case DlcListBlankTop: /* can only occur between a Simple and a List */ + new->type = DlcSimple; + { + adrbk_cntr_t el; + long i; + + i = old->dlcelnum; + i--; + el = old->dlcelnum - 1; + while(i >= 0L){ + if(!as.zoomed || entry_is_selected(pab->address_book->selects, + (a_c_arg_t)el)) + break; + + el--; + i--; + } + + if(i >= 0) + new->dlcelnum = el; + else{ + dprint((1, "Bug in addrbook: case ListBlankTop with no selected entry\n")); + goto oops; + } + } + + break; + + case DlcListBlankBottom: + new->dlcelnum = old->dlcelnum; + abe = adrbk_get_ae(pab->address_book, (a_c_arg_t) new->dlcelnum); + if(F_ON(F_EXPANDED_DISTLISTS,ps_global) + || exp_is_expanded(pab->address_book->exp, (a_c_arg_t)new->dlcelnum)){ + list_count = listmem_count_from_abe(abe); + if(list_count == 0) + new->type = DlcListEmpty; + else{ + new->type = DlcListEnt; + new->dlcoffset = list_count - 1; + } + } + else + new->type = DlcListClickHere; + + break; + + case DlcGlobDelim1: + if(as.how_many_personals == 0) + new->type = DlcPersAdd; + else{ + new->adrbk_num = as.how_many_personals - 1; + new->type = DlcSubTitle; + } + break; + + case DlcGlobDelim2: + new->type = DlcGlobDelim1; + break; + + case DlcPersAdd: + new->type = DlcOneBeforeBeginning; + break; + + case DlcGlobAdd: + new->type = DlcGlobDelim2; + break; + + case DlcDirAccess: + if(old->adrbk_num == 0 && as.n_addrbk == 0) + new->type = DlcOneBeforeBeginning; + else if(old->adrbk_num == 0) + new->type = DlcDirDelim2; + else + new->type = DlcDirBlankTop; + + break; + + case DlcDirSubTitle: + new->type = DlcDirAccess; + break; + + case DlcDirBlankTop: + new->adrbk_num = old->adrbk_num -1; + new->type = DlcDirSubTitle; + break; + + case DlcDirDelim1: + new->adrbk_num = as.n_addrbk - 1; + if(as.n_addrbk == 0) + new->type = DlcNoAbooks; + else + new = get_bottom_dl_of_adrbk(new->adrbk_num, new); + + break; + + case DlcDirDelim1a: + new->type = DlcDirDelim1; + break; + + case DlcDirDelim1b: + new->type = DlcDirDelim1a; + break; + + case DlcDirDelim1c: + new->type = DlcDirDelim1b; + break; + + case DlcDirDelim2: + if(F_ON(F_CMBND_ABOOK_DISP,ps_global)) + new->type = DlcDirDelim1c; + else + new->type = DlcDirDelim1; + + break; + + case DlcTitleDashTopCmb: + if(old->adrbk_num == 0) + new->type = DlcOneBeforeBeginning; + else + new->type = DlcTitleBlankTopCmb; + + break; + + case DlcTitleCmb: + new->type = DlcTitleDashTopCmb; + break; + + case DlcTitleDashBottomCmb: + new->type = DlcTitleCmb; + break; + + case DlcTitleBlankBottomCmb: + new->type = DlcTitleDashBottomCmb; + break; + + case DlcClickHereCmb: + if(as.n_addrbk == 1 && as.n_serv == 0) + new->type = DlcOneBeforeBeginning; + else + new->type = DlcTitleBlankBottomCmb; + + break; + + case DlcTitleBlankTopCmb: + new->adrbk_num = old->adrbk_num - 1; + new = get_bottom_dl_of_adrbk(new->adrbk_num, new); + break; + + case DlcBeginning: + case DlcTwoBeforeBeginning: + new->type = DlcBeginning; + break; + + case DlcOneBeforeBeginning: + new->type = DlcTwoBeforeBeginning; + break; + +oops: + default: + q_status_message(SM_ORDER | SM_DING, 5, 10, + _("Bug in addrbook, not supposed to happen, re-syncing...")); + dprint((1, "Bug in addrbook, impossible case (%d) in dlc_prev, re-sync\n", + old->type)); + /* jump back to a safe starting point */ + longjmp(addrbook_changed_unexpectedly, 1); + /*NOTREACHED*/ + } + + new->global_row = old->global_row - 1L; + if(new->adrbk_num == -2) + new->adrbk_num = old->adrbk_num; + + return(new); +} + + +/* + * Get the dlc element that comes after "old". The function that calls this + * function is the one that keeps a cache and checks in the cache before + * calling here. + */ +DL_CACHE_S * +dlc_next(DL_CACHE_S *old, DL_CACHE_S *new) +{ + PerAddrBook *pab; + AdrBk_Entry *abe; + adrbk_cntr_t ab_count; + adrbk_cntr_t list_count; + + new->adrbk_num = -2; + new->dlcelnum = NO_NEXT; + new->dlcoffset = NO_NEXT; + new->type = DlcNotSet; + pab = &as.adrbks[old->adrbk_num]; + + switch(old->type){ + case DlcTitle: + case DlcTitleNoPerm: + new->type = DlcSubTitle; + break; + + case DlcSubTitle: + if((old->adrbk_num == as.how_many_personals - 1) && + (as.config || as.n_addrbk > as.how_many_personals)) + new->type = DlcGlobDelim1; + else if(as.n_serv && !as.config && + (old->adrbk_num == as.n_addrbk - 1)) + new->type = DlcDirDelim1; + else if(old->adrbk_num == as.n_addrbk - 1) + new->type = DlcEnd; + else{ + new->adrbk_num = old->adrbk_num + 1; + new->type = DlcTitleBlankTop; + } + + break; + + case DlcTitleBlankTop: + if(pab->access == NoAccess) + new->type = DlcTitleNoPerm; + else + new->type = DlcTitle; + + break; + + case DlcEmpty: + case DlcZoomEmpty: + case DlcNoPermission: + case DlcClickHereCmb: + if(F_ON(F_CMBND_ABOOK_DISP,ps_global)){ + if(old->adrbk_num < as.n_addrbk - 1){ + new->adrbk_num = old->adrbk_num + 1; + new->type = DlcTitleBlankTopCmb; + } + else if(as.n_serv) + new->type = DlcDirDelim1; + else + new->type = DlcEnd; + } + else + new->type = DlcEnd; + + break; + + case DlcNoAbooks: + case DlcGlobAdd: + case DlcEnd: + new->type = DlcEnd; + break; + + case DlcSimple: + { + adrbk_cntr_t el; + long i; + + ab_count = adrbk_count(pab->address_book); + i = old->dlcelnum; + i++; + el = old->dlcelnum + 1; + while(i < ab_count){ + if(!as.zoomed || entry_is_selected(pab->address_book->selects, + (a_c_arg_t)el)) + break; + + el++; + i++; + } + + if(i < ab_count){ + new->dlcelnum = el; + abe = adrbk_get_ae(pab->address_book, (a_c_arg_t) new->dlcelnum); + if(abe && abe->tag == Single) + new->type = DlcSimple; + else if(abe && abe->tag == List) + new->type = DlcListBlankTop; + } + else if(F_ON(F_CMBND_ABOOK_DISP,ps_global)){ + if(old->adrbk_num < as.n_addrbk - 1){ + new->adrbk_num = old->adrbk_num + 1; + new->type = DlcTitleBlankTopCmb; + } + else if(as.n_serv) + new->type = DlcDirDelim1; + else + new->type = DlcEnd; + } + else + new->type = DlcEnd; + } + + break; + + case DlcListHead: + new->dlcelnum = old->dlcelnum; + abe = adrbk_get_ae(pab->address_book, (a_c_arg_t) new->dlcelnum); + if(F_ON(F_EXPANDED_DISTLISTS,ps_global) + || exp_is_expanded(pab->address_book->exp, (a_c_arg_t)new->dlcelnum)){ + list_count = listmem_count_from_abe(abe); + if(list_count == 0) + new->type = DlcListEmpty; + else{ + new->type = DlcListEnt; + new->dlcoffset = 0; + } + } + else + new->type = DlcListClickHere; + + break; + + case DlcListEnt: + new->dlcelnum = old->dlcelnum; + abe = adrbk_get_ae(pab->address_book, (a_c_arg_t) new->dlcelnum); + list_count = listmem_count_from_abe(abe); + if(old->dlcoffset == list_count - 1){ /* last member of list */ + adrbk_cntr_t el; + long i; + + ab_count = adrbk_count(pab->address_book); + i = old->dlcelnum; + i++; + el = old->dlcelnum + 1; + while(i < ab_count){ + if(!as.zoomed || entry_is_selected(pab->address_book->selects, + (a_c_arg_t)el)) + break; + + el++; + i++; + } + + if(i < ab_count) + new->type = DlcListBlankBottom; + else if(F_ON(F_CMBND_ABOOK_DISP,ps_global)){ + if(old->adrbk_num < as.n_addrbk - 1){ + new->adrbk_num = old->adrbk_num + 1; + new->type = DlcTitleBlankTopCmb; + } + else if(as.n_serv) + new->type = DlcDirDelim1; + else + new->type = DlcEnd; + } + else + new->type = DlcEnd; + } + else{ + new->type = DlcListEnt; + new->dlcoffset = old->dlcoffset + 1; + } + + break; + + case DlcListClickHere: + case DlcListEmpty: + { + adrbk_cntr_t el; + long i; + + new->dlcelnum = old->dlcelnum; + ab_count = adrbk_count(pab->address_book); + i = old->dlcelnum; + i++; + el = old->dlcelnum + 1; + while(i < ab_count){ + if(!as.zoomed || entry_is_selected(pab->address_book->selects, + (a_c_arg_t)el)) + break; + + el++; + i++; + } + + if(i < ab_count) + new->type = DlcListBlankBottom; + else if(F_ON(F_CMBND_ABOOK_DISP,ps_global)){ + if(old->adrbk_num < as.n_addrbk - 1){ + new->adrbk_num = old->adrbk_num + 1; + new->type = DlcTitleBlankTopCmb; + } + else if(as.n_serv) + new->type = DlcDirDelim1; + else + new->type = DlcEnd; + } + else + new->type = DlcEnd; + } + + break; + + case DlcListBlankTop: + new->type = DlcListHead; + new->dlcelnum = old->dlcelnum; + break; + + case DlcListBlankBottom: + { + adrbk_cntr_t el; + long i; + + ab_count = adrbk_count(pab->address_book); + i = old->dlcelnum; + i++; + el = old->dlcelnum + 1; + while(i < ab_count){ + if(!as.zoomed || entry_is_selected(pab->address_book->selects, + (a_c_arg_t)el)) + break; + + el++; + i++; + } + + if(i < ab_count){ + new->dlcelnum = el; + abe = adrbk_get_ae(pab->address_book, (a_c_arg_t) new->dlcelnum); + if(abe && abe->tag == Single) + new->type = DlcSimple; + else if(abe && abe->tag == List) + new->type = DlcListHead; + } + else + /* can't happen */ + new->type = DlcEnd; + } + + break; + + case DlcGlobDelim1: + new->type = DlcGlobDelim2; + break; + + case DlcGlobDelim2: + if(as.config && as.how_many_personals == as.n_addrbk) + new->type = DlcGlobAdd; + else{ + new->adrbk_num = as.how_many_personals; + pab = &as.adrbks[new->adrbk_num]; + if(pab->access == NoAccess) + new->type = DlcTitleNoPerm; + else + new->type = DlcTitle; + } + + break; + + case DlcDirDelim1: + if(F_ON(F_CMBND_ABOOK_DISP,ps_global)) + new->type = DlcDirDelim1a; + else + new->type = DlcDirDelim2; + + new->adrbk_num = 0; + break; + + case DlcDirDelim1a: + new->type = DlcDirDelim1b; + break; + + case DlcDirDelim1b: + new->type = DlcDirDelim1c; + break; + + case DlcDirDelim1c: + new->type = DlcDirDelim2; + new->adrbk_num = 0; + break; + + case DlcDirDelim2: + new->type = DlcDirAccess; + new->adrbk_num = 0; + break; + + case DlcPersAdd: + new->type = DlcGlobDelim1; + break; + + case DlcDirAccess: + new->type = DlcDirSubTitle; + break; + + case DlcDirSubTitle: + if(old->adrbk_num == as.n_serv - 1) + new->type = DlcEnd; + else{ + new->type = DlcDirBlankTop; + new->adrbk_num = old->adrbk_num + 1; + } + + break; + + case DlcDirBlankTop: + new->type = DlcDirAccess; + break; + + case DlcTitleDashTopCmb: + new->type = DlcTitleCmb; + break; + + case DlcTitleCmb: + new->type = DlcTitleDashBottomCmb; + break; + + case DlcTitleDashBottomCmb: + new->type = DlcTitleBlankBottomCmb; + break; + + case DlcTitleBlankBottomCmb: + pab = &as.adrbks[old->adrbk_num]; + if(pab->ostatus != Open && pab->access != NoAccess) + new->type = DlcClickHereCmb; + else + new = get_top_dl_of_adrbk(old->adrbk_num, new); + + break; + + case DlcTitleBlankTopCmb: + new->type = DlcTitleDashTopCmb; + break; + + case DlcOneBeforeBeginning: + new = get_global_top_dlc(new); + break; + + case DlcTwoBeforeBeginning: + new->type = DlcOneBeforeBeginning; + break; + + default: + q_status_message(SM_ORDER | SM_DING, 5, 10, + _("Bug in addrbook, not supposed to happen, re-syncing...")); + dprint((1, "Bug in addrbook, impossible case (%d) in dlc_next, re-sync\n", + old->type)); + /* jump back to a safe starting point */ + longjmp(addrbook_changed_unexpectedly, 1); + /*NOTREACHED*/ + } + + new->global_row = old->global_row + 1L; + if(new->adrbk_num == -2) + new->adrbk_num = old->adrbk_num; + + return(new); +} + + +/* + * Get the display line at the very top of whole addrbook screen display. + */ +DL_CACHE_S * +get_global_top_dlc(DL_CACHE_S *new) + /* fill in answer here */ +{ + PerAddrBook *pab; + + new->dlcelnum = NO_NEXT; + new->dlcoffset = NO_NEXT; + new->type = DlcNotSet; + + if(F_ON(F_CMBND_ABOOK_DISP,ps_global) && !as.config){ + new->adrbk_num = 0; + if(as.n_addrbk > 1 || (as.n_serv && as.n_addrbk == 1)) + new->type = DlcTitleDashTopCmb; + else if(as.n_addrbk == 1) + new = get_top_dl_of_adrbk(new->adrbk_num, new); + else if(as.n_serv > 0){ /* 1st directory */ + new->type = DlcDirAccess; + new->adrbk_num = 0; + } + else + new->type = DlcNoAbooks; + } + else{ + new->adrbk_num = 0; + + if(as.config){ + if(as.how_many_personals == 0) /* no personals */ + new->type = DlcPersAdd; + else{ + pab = &as.adrbks[new->adrbk_num]; /* 1st personal */ + if(pab->access == NoAccess) + new->type = DlcTitleNoPerm; + else + new->type = DlcTitle; + } + } + else if(any_ab_open()){ + new->adrbk_num = as.cur; + new = get_top_dl_of_adrbk(new->adrbk_num, new); + } + else if(as.n_addrbk > 0){ /* 1st addrbook */ + pab = &as.adrbks[new->adrbk_num]; + if(pab->access == NoAccess) + new->type = DlcTitleNoPerm; + else + new->type = DlcTitle; + } + else if(as.n_serv > 0){ /* 1st directory */ + new->type = DlcDirAccess; + new->adrbk_num = 0; + } + else + new->type = DlcNoAbooks; + } + + return(new); +} + + +/* + * Get the last display line for the whole address book screen. + * This gives us a way to start at the end and move back up. + */ +DL_CACHE_S * +get_global_bottom_dlc(DL_CACHE_S *new) + /* fill in answer here */ +{ + new->dlcelnum = NO_NEXT; + new->dlcoffset = NO_NEXT; + new->type = DlcNotSet; + + if(F_ON(F_CMBND_ABOOK_DISP,ps_global) && !as.config){ + if(as.n_serv){ + new->type = DlcDirSubTitle; + new->adrbk_num = as.n_serv - 1; + } + else if(as.n_addrbk > 0){ + new->adrbk_num = as.n_addrbk - 1; + new = get_bottom_dl_of_adrbk(new->adrbk_num, new); + } + else + new->type = DlcNoAbooks; + } + else{ + new->adrbk_num = MAX(as.n_addrbk - 1, 0); + + if(as.config){ + if(as.how_many_personals == as.n_addrbk) /* no globals */ + new->type = DlcGlobAdd; + else + new->type = DlcSubTitle; + } + else if(any_ab_open()){ + new->adrbk_num = as.cur; + new = get_bottom_dl_of_adrbk(new->adrbk_num, new); + } + else if(as.n_serv){ + new->type = DlcDirSubTitle; + new->adrbk_num = as.n_serv - 1; + } + else{ /* !config && !opened && !n_serv */ + if(as.n_addrbk) + new->type = DlcSubTitle; + else + new->type = DlcNoAbooks; + } + } + + return(new); +} + + +/* + * First dl in a particular addrbook, not counting title lines. + * Assumes as.opened. + */ +DL_CACHE_S * +get_top_dl_of_adrbk(int adrbk_num, DL_CACHE_S *new) + + /* fill in answer here */ +{ + PerAddrBook *pab; + AdrBk_Entry *abe; + adrbk_cntr_t ab_count; + + pab = &as.adrbks[adrbk_num]; + new->adrbk_num = adrbk_num; + + if(pab->access == NoAccess) + new->type = DlcNoPermission; + else{ + adrbk_cntr_t el; + long i; + + ab_count = adrbk_count(pab->address_book); + + i = 0L; + el = 0; + /* find first displayed entry */ + while(i < ab_count){ + if(!as.zoomed || entry_is_selected(pab->address_book->selects, + (a_c_arg_t)el)) + break; + + el++; + i++; + } + + if(i < ab_count){ + new->dlcelnum = el; + abe = adrbk_get_ae(pab->address_book, (a_c_arg_t) new->dlcelnum); + if(abe && abe->tag == Single) + new->type = DlcSimple; + else if(abe && abe->tag == List) + new->type = DlcListHead; + } + else if(as.zoomed) + new->type = DlcZoomEmpty; + else + new->type = DlcEmpty; + } + + return(new); +} + + +/* + * Find the last display line for addrbook number adrbk_num. + * Assumes as.opened (unless OLD_ABOOK_DISP). + */ +DL_CACHE_S * +get_bottom_dl_of_adrbk(int adrbk_num, DL_CACHE_S *new) + + /* fill in answer here */ +{ + PerAddrBook *pab; + AdrBk_Entry *abe; + adrbk_cntr_t ab_count; + adrbk_cntr_t list_count; + + pab = &as.adrbks[adrbk_num]; + new->adrbk_num = adrbk_num; + + if(F_ON(F_CMBND_ABOOK_DISP,ps_global) && pab->ostatus != Open){ + if(pab->access == NoAccess) + new->type = DlcNoPermission; + else + new->type = DlcClickHereCmb; + } + else if(F_OFF(F_CMBND_ABOOK_DISP,ps_global) && pab->ostatus != Open){ + new->type = DlcSubTitle; + } + else{ + if(pab->access == NoAccess) + new->type = DlcNoPermission; + else{ + adrbk_cntr_t el; + long i; + + ab_count = adrbk_count(pab->address_book); + i = ab_count - 1; + el = ab_count - 1; + /* find last displayed entry */ + while(i >= 0L){ + if(!as.zoomed || entry_is_selected(pab->address_book->selects, + (a_c_arg_t)el)) + break; + + el--; + i--; + } + + if(i >= 0){ + new->dlcelnum = el; + abe = adrbk_get_ae(pab->address_book, (a_c_arg_t)new->dlcelnum); + if(abe && abe->tag == Single) + new->type = DlcSimple; + else if(abe && abe->tag == List){ + if(F_ON(F_EXPANDED_DISTLISTS,ps_global) + || exp_is_expanded(pab->address_book->exp, + (a_c_arg_t)new->dlcelnum)){ + list_count = listmem_count_from_abe(abe); + if(list_count == 0) + new->type = DlcListEmpty; + else{ + new->type = DlcListEnt; + new->dlcoffset = list_count - 1; + } + } + else + new->type = DlcListClickHere; + } + } + else if(as.zoomed) + new->type = DlcZoomEmpty; + else + new->type = DlcEmpty; + } + + } + + return(new); +} + + +/* + * This returns the actual dlc instead of the dl within the dlc. + */ +DL_CACHE_S * +get_dlc(long int row) +{ + dprint((11, "- get_dlc(%ld) -\n", row)); + + return(dlc_mgr(row, Lookup, (DL_CACHE_S *)NULL)); +} + + +/* + * Move to new_dlc and give it row number row_number_to_assign_it. + * We copy the passed in dlc in case the caller passed us a pointer into + * the cache. + */ +void +warp_to_dlc(DL_CACHE_S *new_dlc, long int row_number_to_assign_it) +{ + DL_CACHE_S dlc; + + dprint((9, "- warp_to_dlc(%ld) -\n", row_number_to_assign_it)); + + dlc = *new_dlc; + + /* + * Make sure we can move forward and backward from these + * types that we may wish to warp to. The caller may not have known + * to set adrbk_num for these types. + */ + switch(dlc.type){ + case DlcPersAdd: + dlc.adrbk_num = 0; + break; + case DlcGlobAdd: + dlc.adrbk_num = as.n_addrbk; + break; + default: + break; + } + + (void)dlc_mgr(row_number_to_assign_it, ArbitraryStartingPoint, &dlc); +} + + +/* + * Move to first dlc and give it row number 0. + */ +void +warp_to_beginning(void) +{ + dprint((9, "- warp_to_beginning -\n")); + + (void)dlc_mgr(0L, FirstEntry, (DL_CACHE_S *)NULL); +} + + +/* + * Move to first dlc in abook_num and give it row number 0. + */ +void +warp_to_top_of_abook(int abook_num) +{ + DL_CACHE_S dlc; + + dprint((9, "- warp_to_top_of_abook(%d) -\n", abook_num)); + + (void)get_top_dl_of_adrbk(abook_num, &dlc); + warp_to_dlc(&dlc, 0L); +} + + +/* + * Move to last dlc and give it row number 0. + */ +void +warp_to_end(void) +{ + dprint((9, "- warp_to_end -\n")); + + (void)dlc_mgr(0L, LastEntry, (DL_CACHE_S *)NULL); +} + + +/* + * This flushes all of the cache that is related to this dlc. + */ +void +flush_dlc_from_cache(DL_CACHE_S *dlc_to_flush) +{ + dprint((11, "- flush_dlc_from_cache -\n")); + + (void)dlc_mgr(NO_LINE, FlushDlcFromCache, dlc_to_flush); +} + + +/* + * Returns 1 if the dlc's match, 0 otherwise. + */ +int +matching_dlcs(DL_CACHE_S *dlc1, DL_CACHE_S *dlc2) +{ + if(!dlc1 || !dlc2 || + dlc1->type != dlc2->type || + dlc1->adrbk_num != dlc2->adrbk_num) + return 0; + + switch(dlc1->type){ + + case DlcSimple: + case DlcListHead: + case DlcListBlankTop: + case DlcListBlankBottom: + case DlcListClickHere: + case DlcListEmpty: + return(dlc1->dlcelnum == dlc2->dlcelnum); + + case DlcListEnt: + return(dlc1->dlcelnum == dlc2->dlcelnum && + dlc1->dlcoffset == dlc2->dlcoffset); + + case DlcTitle: + case DlcSubTitle: + case DlcTitleNoPerm: + case DlcTitleBlankTop: + case DlcEmpty: + case DlcZoomEmpty: + case DlcNoPermission: + case DlcPersAdd: + case DlcGlobAdd: + case DlcGlobDelim1: + case DlcGlobDelim2: + case DlcDirAccess: + case DlcDirDelim1: + case DlcDirDelim2: + case DlcTitleDashTopCmb: + case DlcTitleCmb: + case DlcTitleDashBottomCmb: + case DlcTitleBlankBottomCmb: + case DlcClickHereCmb: + case DlcTitleBlankTopCmb: + return 1; + + case DlcNotSet: + case DlcBeginning: + case DlcOneBeforeBeginning: + case DlcTwoBeforeBeginning: + case DlcEnd: + case DlcNoAbooks: + return 0; + + default: + break; + } + /*NOTREACHED*/ + + return 0; +} + + +/* + * Uses information in new to fill in new->dl. + */ +void +fill_in_dl_field(DL_CACHE_S *new) +{ + AddrScrn_Disp *dl; + PerAddrBook *pab; + char buf[6*MAX_SCREEN_COLS + 1]; + char buf2[6*1024]; + char hostbuf[128]; + char *folder; + char *q; + unsigned screen_width = ps_global->ttyo->screen_cols; + unsigned got_width, need_width, cellwidth; + + screen_width = MIN(MAX_SCREEN_COLS, screen_width); + + dl = &(new->dl); + + /* free any previously allocated space */ + switch(dl->type){ + case Text: + case Title: + case TitleCmb: + case AskServer: + if(dl->usst) + fs_give((void **)&dl->usst); + default: + break; + } + + /* set up new dl */ + switch(new->type){ + case DlcListBlankTop: + case DlcListBlankBottom: + case DlcGlobDelim1: + case DlcGlobDelim2: + case DlcDirDelim1: + case DlcDirDelim2: + case DlcTitleBlankTop: + case DlcDirBlankTop: + case DlcTitleBlankBottomCmb: + case DlcTitleBlankTopCmb: + dl->type = Text; + dl->usst = cpystr(""); + break; + + case DlcTitleDashTopCmb: + case DlcTitleDashBottomCmb: + case DlcDirDelim1a: + case DlcDirDelim1c: + /* line of dashes in txt field */ + dl->type = Text; + memset((void *)buf, '-', screen_width * sizeof(char)); + buf[screen_width] = '\0'; + dl->usst = cpystr(buf); + break; + + case DlcNoPermission: + dl->type = Text; + dl->usst = cpystr(NO_PERMISSION); + break; + + case DlcTitle: + case DlcTitleNoPerm: + dl->type = Title; + pab = &as.adrbks[new->adrbk_num]; + /* title for this addrbook */ + snprintf(buf, sizeof(buf), " %s", pab->abnick ? pab->abnick : pab->filename); + cellwidth = utf8_width(buf); + if(cellwidth > screen_width) + cellwidth = utf8_truncate(buf, screen_width); + + /* add space padding */ + if(cellwidth < screen_width) + snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%*.*s", + screen_width - cellwidth, screen_width - cellwidth, ""); + + buf[sizeof(buf)-1] = '\0'; + + if(as.ro_warning && (pab->access == NoAccess || pab->access == ReadOnly)){ + char *str; + + if(pab->access == NoAccess) + str = NOACCESS; + else + str = READONLY; + + need_width = utf8_width(str); + + if(screen_width > need_width && (q = utf8_count_back_width(buf, buf+strlen(buf), need_width, &got_width)) != NULL) + + (void) utf8_pad_to_width(q, str, sizeof(buf)-(q-buf), need_width, 0); + } + + buf[sizeof(buf)-1] = '\0'; + dl->usst = cpystr(buf); + break; + + case DlcSubTitle: + dl->type = Text; + pab = &as.adrbks[new->adrbk_num]; + /* Find a hostname to put in title */ + hostbuf[0] = '\0'; + folder = NULL; + if(pab->type & REMOTE_VIA_IMAP && pab->filename){ + char *start, *end; + + start = strindex(pab->filename, '{'); + if(start) + end = strindex(start+1, '}'); + + if(start && end){ + strncpy(hostbuf, start + 1, + MIN(end - start - 1, sizeof(hostbuf)-1)); + hostbuf[MIN(end - start - 1, sizeof(hostbuf)-1)] = '\0'; + if(*(end+1)) + folder = end+1; + } + } + + if(!folder) + folder = pab->filename; + + /* + * Just trying to find the name relative to the home directory + * to display in an OS-independent way. + */ + if(folder && in_dir(ps_global->home_dir, folder)){ + char *p, *new_folder = NULL, *savep = NULL; + int l, saveval = 0; + + l = strlen(ps_global->home_dir); + + while(!new_folder && (p = last_cmpnt(folder)) != NULL){ + if(savep){ + *savep = saveval; + savep = NULL; + } + + if(folder + l == p || folder + l + 1 == p) + new_folder = p; + else{ + savep = --p; + saveval = *savep; + *savep = '\0'; + } + } + + if(savep) + *savep = saveval; + + if(new_folder) + folder = new_folder; + } + + snprintf(buf, sizeof(buf), " %s AddressBook%s%s in %s", + (pab->type & GLOBAL) ? "Global" : "Personal", + (pab->type & REMOTE_VIA_IMAP && *hostbuf) ? " on " : "", + (pab->type & REMOTE_VIA_IMAP && *hostbuf) ? hostbuf : "", + (folder && *folder) ? folder : "<?>"); + cellwidth = utf8_width(buf); + if(cellwidth > screen_width) + cellwidth = utf8_truncate(buf, screen_width); + + /* add space padding */ + if(cellwidth < screen_width) + snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%*.*s", + screen_width - cellwidth, screen_width - cellwidth, ""); + + buf[sizeof(buf)-1] = '\0'; + dl->usst = cpystr(buf); + break; + + case DlcTitleCmb: + dl->type = TitleCmb; + pab = &as.adrbks[new->adrbk_num]; + /* title for this addrbook */ + snprintf(buf, sizeof(buf), "%s AddressBook <%s>", + (new->adrbk_num < as.how_many_personals) ? + "Personal" : + "Global", + pab->abnick ? pab->abnick : pab->filename); + cellwidth = utf8_width(buf); + if(cellwidth > screen_width) + cellwidth = utf8_truncate(buf, screen_width); + + /* add space padding */ + if(cellwidth < screen_width) + snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%*.*s", + screen_width - cellwidth, screen_width - cellwidth, ""); + + buf[sizeof(buf)-1] = '\0'; + + if(as.ro_warning && (pab->access == NoAccess || pab->access == ReadOnly)){ + char *str; + + if(pab->access == NoAccess) + str = NOACCESS; + else + str = READONLY; + + need_width = utf8_width(str); + + if(screen_width > need_width && (q = utf8_count_back_width(buf, buf+strlen(buf), need_width, &got_width)) != NULL) + + (void) utf8_pad_to_width(q, str, sizeof(buf)-(q-buf), need_width, 0); + } + + buf[sizeof(buf)-1] = '\0'; + dl->usst = cpystr(buf); + break; + + case DlcDirDelim1b: + dl->type = Text; + utf8_snprintf(buf, sizeof(buf), "%-*.*w", screen_width, screen_width, OLDSTYLE_DIR_TITLE); + dl->usst = cpystr(buf); + break; + + case DlcClickHereCmb: + dl->type = ClickHereCmb; + break; + + case DlcListClickHere: + dl->type = ListClickHere; + dl->elnum = new->dlcelnum; + break; + + case DlcListEmpty: + dl->type = ListEmpty; + dl->elnum = new->dlcelnum; + break; + + case DlcEmpty: + dl->type = Empty; + break; + + case DlcZoomEmpty: + dl->type = ZoomEmpty; + break; + + case DlcNoAbooks: + dl->type = NoAbooks; + break; + + case DlcPersAdd: + dl->type = AddFirstPers; + break; + + case DlcGlobAdd: + dl->type = AddFirstGlob; + break; + + case DlcDirAccess: + dl->type = AskServer; + +#ifdef ENABLE_LDAP + { + LDAP_SERV_S *info; + + info = break_up_ldap_server(ps_global->VAR_LDAP_SERVERS[new->adrbk_num]); + snprintf(buf2, sizeof(buf2), " %s", + (info && info->nick && *info->nick) ? info->nick : + (info && info->serv && *info->serv) ? info->serv : + comatose(new->adrbk_num + 1)); + if(info) + free_ldap_server_info(&info); + } +#else + snprintf(buf2, sizeof(buf2), " %s", comatose(new->adrbk_num + 1)); +#endif + + utf8_snprintf(buf, sizeof(buf), "%-*.*w", screen_width, screen_width, buf2); + dl->usst = cpystr(buf); + break; + + case DlcDirSubTitle: + dl->type = Text; +#ifdef ENABLE_LDAP + { + LDAP_SERV_S *info; + + info = break_up_ldap_server(ps_global->VAR_LDAP_SERVERS[new->adrbk_num]); + if(info && info->port >= 0) + snprintf(buf2, sizeof(buf2), " Directory Server on %s:%d", + (info && info->serv && *info->serv) ? info->serv : "<?>", + info->port); + else + snprintf(buf2, sizeof(buf2), " Directory Server on %s", + (info && info->serv && *info->serv) ? info->serv : "<?>"); + + if(info) + free_ldap_server_info(&info); + } +#else + snprintf(buf2, sizeof(buf2), " Directory Server %s", + comatose(new->adrbk_num + 1)); +#endif + + utf8_snprintf(buf, sizeof(buf), "%-*.*w", screen_width, screen_width, buf2); + dl->usst = cpystr(buf); + break; + + case DlcSimple: + dl->type = Simple; + dl->elnum = new->dlcelnum; + break; + + case DlcListHead: + dl->type = ListHead; + dl->elnum = new->dlcelnum; + break; + + case DlcListEnt: + dl->type = ListEnt; + dl->elnum = new->dlcelnum; + dl->l_offset = new->dlcoffset; + break; + + case DlcBeginning: + case DlcOneBeforeBeginning: + case DlcTwoBeforeBeginning: + dl->type = Beginning; + break; + + case DlcEnd: + dl->type = End; + break; + + default: + q_status_message(SM_ORDER | SM_DING, 5, 10, + _("Bug in addrbook, not supposed to happen, re-syncing...")); + dprint((1, "Bug in addrbook, impossible dflt in fill_in_dl (%d)\n", + new->type)); + /* jump back to a safe starting point */ + longjmp(addrbook_changed_unexpectedly, 1); + /*NOTREACHED*/ + } +} + + +/* + * Returns a pointer to the member_number'th list member of the list + * associated with this display line. + */ +char * +listmem(long int row) +{ + PerAddrBook *pab; + AddrScrn_Disp *dl; + + dl = dlist(row); + if(dl->type != ListEnt) + return((char *)NULL); + + pab = &as.adrbks[adrbk_num_from_lineno(row)]; + + return(listmem_from_dl(pab->address_book, dl)); +} + + +/* + * Returns a pointer to the list member + * associated with this display line. + */ +char * +listmem_from_dl(AdrBk *address_book, AddrScrn_Disp *dl) +{ + AdrBk_Entry *abe; + char **p = (char **)NULL; + + /* This shouldn't happen */ + if(dl->type != ListEnt) + return((char *)NULL); + + abe = adrbk_get_ae(address_book, (a_c_arg_t) dl->elnum); + + /* + * If we wanted to be more careful, We'd go through the list making sure + * we don't pass the end. We'll count on the caller being careful + * instead. + */ + if(abe && abe->tag == List){ + p = abe->addr.list; + p += dl->l_offset; + } + + return((p && *p) ? *p : (char *)NULL); +} + + +/* + * How many members in list? + */ +adrbk_cntr_t +listmem_count_from_abe(AdrBk_Entry *abe) +{ + char **p; + + if(abe->tag != List) + return 0; + + for(p = abe->addr.list; p != NULL && *p != NULL; p++) + ;/* do nothing */ + + return((adrbk_cntr_t)(p - abe->addr.list)); +} + + +/* + * Return a ptr to the row'th line of the global disp_list. + * Line numbers count up but you can't count on knowing which line number + * goes with the first or the last row. That is, row 0 is not necessarily + * special. It could be before the rows that make up the display list, after + * them, or anywhere in between. You can't tell what the last row is + * numbered, but a dl with type End is returned when you get past the end. + * You can't tell what the number of the first row is, but if you go past + * the first row a dl of type Beginning will be returned. Row numbers can + * be positive or negative. Their values have no meaning other than how + * they line up relative to other row numbers. + */ +AddrScrn_Disp * +dlist(long int row) +{ + DL_CACHE_S *dlc = (DL_CACHE_S *)NULL; + + dlc = get_dlc(row); + + if(dlc){ + fill_in_dl_field(dlc); + return(&dlc->dl); + } + else{ + q_status_message(SM_ORDER | SM_DING, 5, 10, + _("Bug in addrbook, not supposed to happen, re-syncing...")); + dprint((1, "Bug in addrbook (null dlc in dlist(%ld), not supposed to happen\n", row)); + /* jump back to a safe starting point */ + + dprint((1, "dlist: panic: initialized %d, n_addrbk %d, cur_row %d, top_ent %ld, ro_warning %d, no_op_possbl %d\n", + as.initialized, as.n_addrbk, as.cur_row, as.top_ent, as.ro_warning, as.no_op_possbl)); + + longjmp(addrbook_changed_unexpectedly, 1); + /*NOTREACHED*/ + } +} + + +/* + * Returns the index of the current address book. + */ +int +adrbk_num_from_lineno(long int lineno) +{ + DL_CACHE_S *dlc; + + dlc = get_dlc(lineno); + + return(dlc->adrbk_num); +} |