/* * $Id: adrbklib.h 1012 2008-03-26 00:44:22Z hubert@u.washington.edu $ * * ======================================================================== * Copyright 2006-2008 University of Washington * Copyright 2013-2021 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 * * ======================================================================== */ #ifndef PITH_ADRBKLIB_INCLUDED #define PITH_ADRBKLIB_INCLUDED #include "../pith/indxtype.h" #include "../pith/remtype.h" #include "../pith/store.h" #include "../pith/string.h" /* * Some notes: * * The order that the address book is stored in on disk is the order that * the entries will be displayed in. When an address book is opened, * if it is ReadWrite the sort order is checked and it is sorted if it is * out of order. * * Considerable complexity that previously existed in the address book * code has been removed. Cpu speeds have improved significantly and * memory has increased dramatically, as well. The cost of the complexity * of the lookup file and hashtables and all that stuff is thought to be * more than the benefits. See pre-5.00 pine adrbklib.h for the way it * used to be. * * The display code has remained the same. * There is also some allocation happening * in addrbook.c. In particular, the display is a window into an array * of rows, at least one row per addrbook entry plus more for lists. * Each row is an AddrScrn_Disp structure and those should typically take * up 6 or 8 bytes. A cached copy of addrbook entries is not kept, just * the element number to look it up (and often get it out of the EntryRef * cache). In order to avoid having to allocate all those rows, this is * also in the form of a cache. Only 3 * screen_length rows are kept in * the cache, and the cache is always a simple interval of rows. That is, * rows between valid_low and valid_high are all in the cache. Row numbers * in the display list are a little mysterious. There is no origin. That * is, you don't necessarily know where the start or end of the display * is. You only know how to go forward and backward and how to "warp" * to new locations in the display and go forward and backward from there. * This is because we don't know how many rows there are all together. It * is also a way to avoid searching through everything to get somewhere. * If you want to go to the End, you warp there and start backwards instead * of reading through all the entries to get there. If you edit an entry * so that it sorts into a new location, you warp to that new location to * save processing all of the entries in between. * * * Notes about RFC1522 encoding: * * If the fullname field contains other than US-ASCII characters, it is * encoded using the rules of RFC1522 or its successor. The value actually * stored in the file is encoded, even if it matches the character set of * the user. This is so it is easy to pass the entry around or to change * character sets without invalidating entries in the address book. When * a fullname is displayed, it is first decoded. If the fullname field is * encoded as being from a character set other than the user's character * set, that will be retained until the user edits the field. Then it will * change over to the user's character set. The comment field works in * the same way, as do the "phrase" fields of any addresses. On outgoing * mail, the correct character set will be retained if you use ComposeTo * from the address book screen. However, if you use a nickname from the * composer or ^T from the composer, the character set will be lost if it * is different from the user's character set. * * * Notes about RemoteViaImap address books: * * There are currently two types of address books, Local and Imap. Local means * it is in a local file. Imap means it is stored in a folder on a remote * IMAP server. The folder is a regular folder containing mail messages but * the messages are special. The first message is a header message. The last * message is the address book data. In between messages are old versions of * the address book data. The address book data is stored in the message as * it would be on disk, with no fancy mime encoding or anything. When it is * used the data from the last message in the folder is copied to a local file * and then it is used just like a local file. The local file is a cache for * the remote data. We can tell the remote data has been changed by looking * at the Date of the last message in the remote folder. If we see it has * changed we copy the whole file over again and replace the cache file. * A possibly quicker way to tell if it has changed is if the UID has * changed or the number of messages in the folder has changed. We use those * methods if possible since they don't require opening a new stream and * selecting the folder. There is one metadata file for address book data. * The name of that file is stored in the pinerc file. It contains the names * of the cache files for RemoveViaImap address books plus other caching * information for those address books (uid...). */ #define NFIELDS 11 /* one more than num of data fields in addrbook entry */ /* * The type a_c_arg_t is a little confusing. It's the type we use in * place of adrbk_cntr_t when we want to pass an adrbk_cntr_t in an argument. * We were running into problems with the integral promotion of adrbk_cntr_t * args. A_c_arg_t has to be large enough to hold a promoted adrbk_cntr_t. * So, if adrbk_cntr_t is unsigned short, then a_c_arg_t needs to be int if * int is larger than short, or unsigned int if short is same size as int. * Since usign16_t always fits in a short, a_c_arg_t of unsigned int should * always work for !HUGE. For HUGE, UINT32 will be either an unsigned int * or an unsigned long. If it is an unsigned long, then a_c_arg_t better be * an unsigned long, too. If it is an unsigned int, then a_c_arg_t could * be an unsigned int, too. However, if we just make it unsigned long, then * it will be the same in all cases and big enough in all cases. * For most people SUINT32 is UINT32, but users can define at configure stage * that SUINT32 could be something different, by means of defining an environment * variable SUINT32 as, say, unsigned long. */ #define adrbk_cntr_t SUINT32 /* addrbook counter type */ typedef unsigned long a_c_arg_t; /* type of arg passed for adrbk_cntr_t */ #define NO_NEXT ((adrbk_cntr_t)-1) #define MAX_ADRBK_SIZE (2000000000L) /* leave room for extra display lines */ /* * The value NO_NEXT is reserved to mean that there is no next address, or that * there is no address number to return. This is similar to getc returning * -1 when there is no char to get, but since we've defined this to be * unsigned we need to reserve one of the valid values for this purpose. * With current implementation it needs to be all 1's, so memset initialization * will work correctly. */ typedef enum {NotSet, Single, List} Tag; /* This is what is actually used by the routines that manipulate things */ typedef struct adrbk_entry { char *nickname; /* UTF-8 */ char *fullname; /* of simple addr or list (stored in UTF-8) */ union addr { char *addr; /* for simple Single entries */ char **list; /* for distribution lists */ } addr; char *fcc; /* fcc specific for when sending to this address */ char *extra; /* comments field (stored in UTF-8) */ char referenced; /* for detecting loops during lookup */ Tag tag; /* single addr (Single) or a list (List) */ } AdrBk_Entry; typedef struct abook_tree_node { struct abook_tree_node *down; /* next letter of nickname */ struct abook_tree_node *right; /* alternate letter of nickname */ char value; /* character at this node */ adrbk_cntr_t entrynum; /* use NO_NEXT as no-data indicator */ } AdrBk_Trie; /* information useful for displaying the addrbook */ typedef struct width_stuff { int max_nickname_width; int max_fullname_width; int max_addrfield_width; int max_fccfield_width; int third_biggest_fullname_width; int third_biggest_addrfield_width; int third_biggest_fccfield_width; } WIDTH_INFO_S; typedef struct expanded_list { adrbk_cntr_t ent; struct expanded_list *next; } EXPANDED_S; typedef enum {Local, Imap} AdrbkType; #ifndef IMAP_IDLE_TIMEOUT #define IMAP_IDLE_TIMEOUT (10L * 60L) /* seconds */ #endif #ifndef FILE_VALID_CHK_INTERVAL #define FILE_VALID_CHK_INTERVAL ( 15L) /* seconds */ #endif #ifndef LOW_FREQ_CHK_INTERVAL #define LOW_FREQ_CHK_INTERVAL (240) /* minutes */ #endif typedef struct adrbk { AdrbkType type; /* type of address book */ char *orig_filename; /* passed in filename */ char *filename; /* addrbook filename */ char *our_filecopy; /* session copy of filename contents */ FILE *fp; /* fp for our_filecopy */ adrbk_cntr_t count; /* how many entries in addrbook */ adrbk_cntr_t del_count; /* how many #DELETED entries in abook */ AdrBk_Entry *arr; /* array of entries */ AdrBk_Entry *del; /* array of deleted entries */ AdrBk_Trie *nick_trie; AdrBk_Trie *addr_trie; AdrBk_Trie *full_trie; AdrBk_Trie *revfull_trie; time_t last_change_we_know_about;/* to look for others changing it*/ time_t last_local_valid_chk;/* when valid check was done */ unsigned flags; /* see defines in alpine.h (DEL_FILE...)*/ WIDTH_INFO_S widths; /* helps addrbook.c format columns */ int sort_rule; EXPANDED_S *exp; /* this is for addrbook.c to use. A list of expanded list entry nums is kept here */ EXPANDED_S *checks; /* this is for addrbook.c to use. A list of checked entry nums is kept here */ EXPANDED_S *selects; /* this is for addrbook.c to use. A list of selected entry nums is kept here */ REMDATA_S *rd; } AdrBk; /* * The definitions starting here have to do with the virtual scrolling * region view into the addressbooks. That is, the display. * * We could make every use of an AdrBk_Entry go through a function call * like adrbk_get_ae(). Instead, we try to be smart and avoid the extra * function calls by knowing when the addrbook entry is still valid, either * because we haven't called any functions that could invalidate it or because * we have locked it in the cache. If we do lock it, we need to be careful * that it eventually gets unlocked. That can be done by an explicit * adrbk_get_ae(Unlock) call, or it is done implicitly when the address book * is written out. The reason it can get invalidated is that the abe that * we get returned to us is just a pointer to a cached addrbook entry, and * that entry can be flushed from the cache by other addrbook activity. * So we need to be careful to make sure the abe is certain to be valid * before using it. * * Data structures for the display of the address book. There's one * of these structures per line on the screen. * * Types: Title -- The title line for the different address books. It has * a ptr to the text of the Title line. * ClickHereCmb -- This is the line that says to click here to * expand. It changes types into the individual expanded * components once it is expanded. It doesn't have any data * other than an implicit title. This is only used with the * combined-style addrbook display. * ListClickHere --This is the line that says to click here to * expand the members of a distribution list. It changes * types into the individual expanded ListEnt's (if any) * when it is expanded. It has a ptr to an AdrBk_Entry. * ListEmpty -- Line that says this is an empty distribution list. No data. * Empty -- Line that says this is an empty addressbook. No data. * ZoomEmpty -- Line that says no addrs in zoomed view. No data. * AddFirstGLob -- Place holder for adding an abook. No data. * AddFirstPers -- Place holder for adding an abook. No data. * DirServers -- Place holder for accessing directory servers. No data. * Simple -- A single addressbook entry. It has a ptr to an AdrBk_Entry. * When it is displayed, the fields are usually: *
* ListHead -- The head of an address list. This has a ptr to an * AdrBk_Entry. * followed by * "DISTRIBUTION LIST:" * ListEnt -- The rest of an address list. It has a pointer to its * ListHead element and a ptr (other) to this specific address * (not a ptr to another AdrBk_Entry). *
* Text -- A ptr to text. For example, the ----- lines and * whitespace lines. * NoAbooks -- There are no address books at all. * Beginning -- The (imaginary) elements before the first real element * End -- The (imaginary) elements after the last real element */ typedef enum {DlNotSet, Empty, ZoomEmpty, AddFirstPers, AddFirstGlob, AskServer, Title, Simple, ListHead, ListClickHere, ListEmpty, ListEnt, Text, Beginning, End, NoAbooks, ClickHereCmb, TitleCmb} LineType; /* each line of address book display is one of these structures */ typedef struct addrscrn_disp { union { struct { adrbk_cntr_t ab_element_number; /* which addrbook entry */ adrbk_cntr_t ab_list_offset; /* which member of the list */ }addrbook_entry; char *text_ptr; /* a UTF-8 string */ }union_to_save_space; LineType type; } AddrScrn_Disp; #define usst union_to_save_space.text_ptr #define elnum union_to_save_space.addrbook_entry.ab_element_number #define l_offset union_to_save_space.addrbook_entry.ab_list_offset #define entry_is_checked exp_is_expanded #define entry_get_next exp_get_next #define entry_set_checked exp_set_expanded #define entry_unset_checked exp_unset_expanded #define any_checked exp_any_expanded #define howmany_checked exp_howmany_expanded #define entry_is_selected exp_is_expanded #define entry_set_selected exp_set_expanded #define entry_unset_selected exp_unset_expanded #define any_selected exp_any_expanded #define howmany_selected exp_howmany_expanded #define entry_is_deleted exp_is_expanded #define entry_set_deleted exp_set_expanded #define howmany_deleted exp_howmany_expanded #define entry_is_added exp_is_expanded #define entry_set_added exp_set_expanded /* * Argument to expand_address and build_address_internal is a BuildTo, * which is either a char * address or an AdrBk_Entry * (if we have already * looked it up in an addrbook). */ typedef enum {Str, Abe} Build_To_Arg_Type; typedef struct build_to { Build_To_Arg_Type type; union { char *str; /* normal looking address string */ AdrBk_Entry *abe; /* addrbook entry */ }arg; } BuildTo; /* Display lines used up by each top-level addrbook, counting blanks */ #define LINES_PER_ABOOK (3) /* How many of those lines are visible (not blank) */ #define VIS_LINES_PER_ABOOK (2) /* How many extra lines are between the personal and global sections */ #define XTRA_LINES_BETWEEN (1) /* How many lines does the PerAdd line take, counting blank line */ #define LINES_PER_ADD_LINE (2) /* Extra title lines above first entry that are shown when the combined-style display is turned on. */ #define XTRA_TITLE_LINES_IN_OLD_ABOOK_DISP (4) typedef enum {DlcNotSet, DlcPersAdd, /* config screen only */ DlcGlobAdd, /* " " " */ DlcTitle, /* top level displays */ DlcTitleNoPerm, /* " " " */ DlcSubTitle, /* " " " */ DlcTitleBlankTop, /* " " " */ DlcGlobDelim1, /* " " " */ DlcGlobDelim2, /* " " " */ DlcDirDelim1, /* " " " */ DlcDirDelim2, /* " " " */ DlcDirAccess, /* " " " */ DlcDirSubTitle, /* " " " */ DlcDirBlankTop, /* " " " */ DlcTitleDashTopCmb, /* combined-style top level display */ DlcTitleCmb, /* " " " " " */ DlcTitleDashBottomCmb, /* " " " " " */ DlcTitleBlankBottomCmb, /* " " " " " */ DlcClickHereCmb, /* " " " " " */ DlcTitleBlankTopCmb, /* " " " " " */ DlcDirDelim1a, /* " " " " " */ DlcDirDelim1b, /* " " " " " */ DlcDirDelim1c, /* " " " " " */ DlcEmpty, /* display of a single address book */ DlcZoomEmpty, /* " */ DlcNoPermission, /* " */ DlcSimple, /* " */ DlcListHead, /* " */ DlcListClickHere, /* " */ DlcListEmpty, /* " */ DlcListEnt, /* " */ DlcListBlankTop, /* " */ DlcListBlankBottom, /* " */ DlcNoAbooks, /* " */ DlcOneBeforeBeginning, /* used in both */ DlcTwoBeforeBeginning, /* " " " */ DlcBeginning, /* " " " */ DlcEnd} DlCacheType; typedef enum {Initialize, FirstEntry, LastEntry, ArbitraryStartingPoint, DoneWithCache, FlushDlcFromCache, Lookup} DlMgrOps; typedef enum {Warp, DontWarp} HyperType; /* * The DlCacheTypes are the types that a dlcache element can be labeled. * The idea is that there needs to be enough information in the single * cache element by itself so that you can figure out what the next and * previous dl rows are by just knowing this one row. * * In the top-level display, there are DlcTitle lines or DlcTitleNoPerm * lines, which are the same except we know that we can't access the * address book in the latter case. DlcSubTitle lines follow each of the * types of Title lines, and Titles within a section are separated by * DlcTitleBlankTop lines, which belong to (have the same adrbk_num as) * the Title they are above. * If there are no address books and no directory servers defined, we * have a DlcNoAbooks line. When we are displaying an individual address * book (not in the top-level display) there is another set of types. An * empty address book consists of one line of type DlcEmpty. An address * book without read permission is a DlcNoPermission. Simple address book * entries consist of a single DlcSimple line. Lists begin with a * DlcListHead. If the list is not expanded the DlcListHead is followed by * a DlcListClickHere. If it is known to be a list with no members the * DlcListHead is followed by a DlcListEmpty. If there are members and * the list is expanded, each list member is a single line of type * DlcListEnt. Two lists are separated by a DlcListBlankBottom belonging * to the first list. A list followed or preceded by a DlcSimple address * row has a DlcListBlank(Top or Bottom) separating it from the * DlcSimple. Above the top row of the display is an imaginary line of * type DlcOneBeforeBeginning. Before that is a DlcTwoBeforeBeginning. And * before that all the lines are just DlcBeginning lines. After the last * display line is a DlcEnd. * * The DlcDirAccess's are indexed by adrbk_num (re-used for this). * Adrbk_num -1 means access all of the servers. * Adrbk_num 0 ... n_serv -1 means access all a particular server. * Adrbk_num n_serv means access as if from composer using config setup. * * Here are the types of lines and where they fall in the top-level display: * * (not a visible line) DlcBeginning * (not a visible line) DlcBeginning * (not a visible line) DlcTwoBeforeBeginning * (not a visible line) DlcOneBeforeBeginning * Title DlcTitle (or TitleNoPerm) * Subtitle DlcSubTitle * ---this is blank---------------- DlcTitleBlankTop * Title DlcTitle (or TitleNoPerm) * Subtitle DlcSubTitle * ---this is blank---------------- DlcGlobDelim1 * ---this is blank---------------- DlcGlobDelim2 * Title DlcTitle (or TitleNoPerm) * Subtitle DlcSubTitle * ---this is blank---------------- DlcTitleBlankTop * Title DlcTitle (or TitleNoPerm) * Subtitle DlcSubTitle * ---this is blank---------------- DlcDirDelim1 * ---this is blank---------------- DlcDirDelim2 * Directory (query server 1) DlcDirAccess (adrbk_num 0) * Subtitle DlcDirSubTitle (adrbk_num 0) * ---this is blank---------------- DlcDirBlankTop * Directory (query server 2) DlcDirAccess (adrbk_num 1) * Subtitle DlcDirSubTitle (adrbk_num 1) * (not a visible line) DlcEnd * (not a visible line) DlcEnd * * * There is a combined-style display triggered by the F_CMBND_ABOOK_DISP * feature. It's a mixture of the top-level and open addrbook displays. When an * addrbook is opened the rest of the addrbooks don't disappear from the * screen. In this view, the ClickHere lines can be replaced with the entire * contents of the addrbook, but the other stuff remains on the screen, too. * Here are the types of lines and where they fall in the * combined-style display: * * (not a visible line) DlcBeginning * (not a visible line) DlcBeginning * (not a visible line) DlcTwoBeforeBeginning * (not a visible line) DlcOneBeforeBeginning * -------------------------------- DlcTitleDashTopOld * Title DlcTitleOld * -------------------------------- DlcTitleDashBottomOld * ---this is blank---------------- DlcTitleBlankBottom * ClickHere DlcClickHereOld * ---this is blank---------------- DlcTitleBlankTop * -------------------------------- DlcTitleDashTopOld * Title DlcTitleOld * -------------------------------- DlcTitleDashBottomOld * ---this is blank---------------- DlcTitleBlankBottom * ClickHere DlcClickHereOld * ---this is blank---------------- DlcDirDelim1 * -------------------------------- DlcDirDelim1a * Directories DlcDirDelim1b * -------------------------------- DlcDirDelim1c * ---this is blank---------------- DlcDirDelim2 * Directory (query server 1) DlcDirAccess (adrbk_num 0) * Subtitle DlcDirSubTitle (adrbk_num 0) * ---this is blank---------------- DlcDirBlankTop * Directory (query server 2) DlcDirAccess (adrbk_num 1) * Subtitle DlcDirSubTitle (adrbk_num 1) * (not a visible line) DlcEnd * (not a visible line) DlcEnd * * If there are no addrbooks in either of the two sections, or no Directory * servers, then that section is left out of the display. If there is only * one address book and no Directories, then the user goes directly into the * single addressbook view which looks like: * * if(no entries in addrbook) * * (not a visible line) DlcBeginning * (not a visible line) DlcBeginning * (not a visible line) DlcTwoBeforeBeginning * (not a visible line) DlcOneBeforeBeginning * Empty or NoPerm or NoAbooks DlcEmpty, DlcZoomEmpty, DlcNoPermission, * or DlcNoAbooks * (not a visible line) DlcEnd * (not a visible line) DlcEnd * * else * * (not a visible line) DlcBeginning * (not a visible line) DlcBeginning * (not a visible line) DlcTwoBeforeBeginning * (not a visible line) DlcOneBeforeBeginning * Simple Entry DlcSimple * Simple Entry DlcSimple * Simple Entry DlcSimple * DlcListBlankTop * List Header DlcListHead * Unexpanded List DlcListClickHere * or * Empty List DlcListEmpty * or * List Entry 1 DlcListEnt * List Entry 2 DlcListEnt * DlcListBlankBottom * List Header DlcListHead * List Entry 1 DlcListEnt * List Entry 2 DlcListEnt * List Entry 3 DlcListEnt * DlcListBlankBottom * Simple Entry DlcSimple * DlcListBlankTop * List Header DlcListHead * Unexpanded List DlcListClickHere * (not a visible line) DlcEnd * (not a visible line) DlcEnd * * The config screen view is similar to the top-level view except there * is no directory section (it has it's own config screen) and if there * are zero personal addrbooks or zero global addrbooks then a placeholder * line of type DlcPersAdd or DlcGlobAdd takes the place of the DlcTitle * line. */ typedef struct dl_cache { long global_row; /* disp_list row number */ adrbk_cntr_t dlcelnum; /* which elnum from that addrbook */ adrbk_cntr_t dlcoffset; /* offset in a list, only for ListEnt rows */ short adrbk_num; /* which address book we're related to */ DlCacheType type; /* type of this row */ AddrScrn_Disp dl; /* the actual dl that goes with this row */ } DL_CACHE_S; typedef enum {Nickname, Fullname, Addr, Filecopy, Comment, Notused, Def, WhenNoAddrDisplayed, Checkbox, Selected} ColumnType; /* * Users can customize the addrbook display, so this tells us which data * is in a particular column and how wide the column is. There is an * array of these per addrbook, of length NFIELDS (number of possible cols). */ typedef struct column_description { ColumnType type; WidthType wtype; int req_width; /* requested width (for fixed and percent types) */ int width; /* actual width to use */ int old_width; } COL_S; /* address book attributes for peraddrbook type */ #define GLOBAL 0x1 /* else it is personal */ #define REMOTE_VIA_IMAP 0x2 /* else it is a local file */ typedef enum {TotallyClosed, /* hash tables not even set up yet */ Closed, /* data not read in, no display list */ NoDisplay, /* data is accessible, no display list */ HalfOpen, /* data not accessible, initial display list is set */ ThreeQuartOpen, /* like HalfOpen without partial_close */ Open /* data is accessible and display list is set */ } OpenStatus; /* * There is one of these per addressbook. */ typedef struct peraddrbook { unsigned type; AccessType access; OpenStatus ostatus; char *abnick, /* kept internally in UTF-8 */ *filename; AdrBk *address_book; /* the address book handle */ int gave_parse_warnings; COL_S disp_form[NFIELDS]; /* display format */ int nick_is_displayed; /* these are for convenient, */ int full_is_displayed; /* fast access. Could get */ int addr_is_displayed; /* same info from disp_form. */ int fcc_is_displayed; int comment_is_displayed; STORE_S *so; /* storage obj for addrbook temporarily stored here */ } PerAddrBook; /* * This keeps track of the state of the screen and information about all * the address books. We usually only have one of these but sometimes * we save a version of this state (with save_state) and re-call the * address book functions. Then when we pop back up to where we were * (with restore_state) the screen and the state of the address books * is restored to what it was. */ typedef struct addrscreenstate { PerAddrBook *adrbks; /* array of addrbooks */ int initialized, /* have we done at least simple init? */ n_addrbk, /* how many addrbooks are there */ how_many_personals, /* how many of those are personal? */ cur, /* current addrbook */ cur_row, /* currently selected line */ old_cur_row, /* previously selected line */ l_p_page; /* lines per (screen) page */ long top_ent; /* index in disp_list of top entry on screen */ int ro_warning, /* whether or not to give warning */ checkboxes, /* whether or not to display checkboxes */ selections, /* whether or not to display selections */ do_bold, /* display selections in bold */ no_op_possbl, /* user can't do anything with current conf */ zoomed, /* zoomed into view only selected entries */ config, /* called from config screen */ n_serv, /* how many directory servers are there */ n_impl; /* how many of those have impl bit set */ #ifdef _WINDOWS long last_ent; /* index of last known entry */ #endif } AddrScrState; /* * AddrBookScreen and AddrBookConfig are the maintenance screens, all the * others are selection screens. The AddrBookConfig screen is an entry * point from the Setup/Addressbooks command in the main menu. Those that * end in Com are called from the pico HeaderEditor, either while in the * composer or while editing an address book entry. SelectManyNicks * returns a comma-separated list of nicknames. SelectAddrLccCom and * SelectNicksCom return a comma-separated list of nicknames. * SelectNickTake, SelectNickCom, and SelectNick all return a single * nickname. The ones that returns multiple nicknames or multiple * addresses all allow ListMode. They are SelectAddrLccCom, * SelectNicksCom, and SelectMultNoFull. */ typedef enum {AddrBookScreen, /* maintenance screen */ AddrBookConfig, /* config screen */ SelectAddrLccCom, /* returns list of nicknames of lists */ SelectNicksCom, /* just like SelectAddrLccCom, but allows selecting simple *and* list entries */ SelectNick, /* returns single nickname */ SelectNickTake, /* Same as SelectNick but different help */ SelectNickCom, /* Same as SelectNick but from composer */ SelectManyNicks, /* Returns list of nicks */ SelectAddr, /* Returns single address */ SelectAddrNoFull, /* Returns single address without fullname */ SelectMultNoFull /* Returns mult addresses without fullname */ } AddrBookArg; typedef struct save_state_struct { AddrScrState *savep; OpenStatus *stp; DL_CACHE_S *dlc_to_warp_to; } SAVE_STATE_S; typedef struct act_list { PerAddrBook *pab; adrbk_cntr_t num, num_in_dst; unsigned int skip:1, dup:1; } ACTION_LIST_S; typedef struct ta_abook_state { PerAddrBook *pab; SAVE_STATE_S state; } TA_STATE_S; /* * Many of these should really only have a single value but we give them * an array for uniformity. */ typedef struct _vcard_info { char **nickname; char **fullname; char *first; char *middle; char *last; char **fcc; char **note; char **title; char **tel; char **email; } VCARD_INFO_S; extern AddrScrState as; extern jmp_buf addrbook_changed_unexpectedly; extern long msgno_for_pico_callback; extern BODY *body_for_pico_callback; extern ENVELOPE *env_for_pico_callback; extern int ab_nesting_level; /* * These constants are supposed to be suitable for use as longs where the longs * are representing a line number or message number. * These constants aren't suitable for use with type adrbk_cntr_t. There is * a constant called NO_NEXT which you probably want for that. */ #define NO_LINE (2147483645L) #define CHANGED_CURRENT (NO_LINE + 1L) /* * The do-while stuff is so these are statements and can be written with * a following ; like a regular statement without worrying about braces and all. */ #define SKIP_SPACE(p) do{while(*p && *p == SPACE)p++;}while(0) #define SKIP_TO_TAB(p) do{while(*p && *p != TAB)p++;}while(0) #define RM_END_SPACE(start,end) \ do{char *_ptr = end; \ while(--_ptr >= start && *_ptr == SPACE)*_ptr = '\0';}while(0) #define REPLACE_NEWLINES_WITH_SPACE(p) \ do{register char *_qq; \ for(_qq = p; *_qq; _qq++) \ if(*_qq == '\n' || *_qq == '\r') \ *_qq = SPACE;}while(0) #define DELETED "#DELETED-" #define DELETED_LEN 9 #define ONE_HUNDRED_DAYS (60L * 60L * 24L * 100L) /* * When address book entries are deleted, they are left in the file * with the nickname prepended with a string like #DELETED-96/01/25#, * which stands for year 96, month 1, day 25 of the month. When one of * these entries is more than ABOOK_DELETED_EXPIRE_TIME seconds old, * then it will be totally removed from the address book the next time * an adrbk_write() is done. This is for emergencies where somebody * deletes something from their address book and would like to get it * back. You get it back by editing the nickname field manually to remove * the extra 18 characters off the front. */ #ifndef ABOOK_DELETED_EXPIRE_TIME #define ABOOK_DELETED_EXPIRE_TIME ONE_HUNDRED_DAYS #endif #ifdef ENABLE_LDAP typedef struct _cust_filt { char *filt; int combine; } CUSTOM_FILT_S; #define RUN_LDAP "LDAP: " #define LEN_RL 6 #define QRUN_LDAP "\"LDAP: " #define LEN_QRL 7 #define LDAP_DISP "[ LDAP Lookup ]" #endif /* * There are no restrictions on the length of any of the fields, except that * there are some restrictions in the current input routines. */ /* * The on-disk address book has entries that look like: * * Nickname TAB Fullname TAB Address_Field TAB Fcc TAB Comment * * An entry may be broken over more than one line but only at certain * spots. A continuation line starts with spaces (spaces, not white space). * One place a line break can occur is after any of the TABs. The other * place is in the middle of a list of addresses, between addresses. * The Address_Field may be either a simple address without the fullname * or brackets, or it may be an address list. An address list is * distinguished by the fact that it begins with "(" and ends with ")". * Addresses within a list are comma separated and each address in the list * may be a full rfc822 address, including Fullname and so on. * * Examples: * fred TAB Flintstone, Fred TAB fred@bedrock.net TAB fcc-flintstone TAB comment * or * fred TAB Flintstone, Fred TAB \n * fred@bedrock.net TAB fcc-flintstone TAB \n * comment * somelist TAB Some List TAB (fred, \n * Barney Rubble , wilma@bedrock.net) TAB \n * fcc-for-some-list TAB comment */ /* exported prototypes */ AdrBk *adrbk_open(PerAddrBook *, char *, char *, size_t, int); int adrbk_is_in_sort_order(AdrBk *, int); adrbk_cntr_t adrbk_count(AdrBk *); AdrBk_Entry *adrbk_get_ae(AdrBk *, a_c_arg_t); AdrBk_Entry *adrbk_lookup_by_nick(AdrBk *, char *, adrbk_cntr_t *); AdrBk_Entry *adrbk_lookup_by_addr(AdrBk *, char *, adrbk_cntr_t *); char *adrbk_formatname(char *, char **, char **); void adrbk_clearrefs(AdrBk *); AdrBk_Entry *adrbk_newentry(void); AdrBk_Entry *copy_ae(AdrBk_Entry *); int adrbk_add(AdrBk *, a_c_arg_t, char *, char *, char *, char *, char *, Tag, adrbk_cntr_t *, int *, int, int, int); int adrbk_append(AdrBk *, char *, char *, char *, char *, char *, Tag, adrbk_cntr_t *); int adrbk_delete(AdrBk *, a_c_arg_t, int, int, int, int); int adrbk_listdel(AdrBk *, a_c_arg_t, char *); int adrbk_listdel_all(AdrBk *, a_c_arg_t); int adrbk_nlistadd(AdrBk *, a_c_arg_t,adrbk_cntr_t *,int *,char **,int,int,int); void adrbk_check_validity(AdrBk *, long); MAILSTREAM *adrbk_handy_stream(char *); void adrbk_close(AdrBk *); void adrbk_partial_close(AdrBk *); void note_closed_adrbk_stream(MAILSTREAM *); int adrbk_write(AdrBk *, a_c_arg_t, adrbk_cntr_t *, int *, int, int); void free_ae(AdrBk_Entry **); void exp_free(EXPANDED_S *); int exp_is_expanded(EXPANDED_S *, a_c_arg_t); int exp_howmany_expanded(EXPANDED_S *); int exp_any_expanded(EXPANDED_S *); adrbk_cntr_t exp_get_next(EXPANDED_S **); void exp_set_expanded(EXPANDED_S *, a_c_arg_t); void exp_unset_expanded(EXPANDED_S *, a_c_arg_t); int adrbk_sort(AdrBk *, a_c_arg_t, adrbk_cntr_t *, int); int any_ab_open(void); void init_ab_if_needed(void); int init_addrbooks(OpenStatus, int, int, int); void addrbook_reset(void); void addrbook_redo_sorts(void); AccessType adrbk_access(PerAddrBook *); void trim_remote_adrbks(void); void completely_done_with_adrbks(void); void init_abook(PerAddrBook *, OpenStatus); int adrbk_check_all_validity_now(void); int adrbk_check_and_fix(PerAddrBook *, int, int, int); int adrbk_check_and_fix_all(int, int, int); void adrbk_maintenance(void); char **parse_addrlist(char *); char *skip_to_next_addr(char *); void add_forced_entries(AdrBk *); int any_addressbook_in_remote_stream(MAILSTREAM *); #endif /* PITH_ADRBKLIB_INCLUDED */