summaryrefslogtreecommitdiff
path: root/pith/addrbook.c
diff options
context:
space:
mode:
authorEduardo Chappa <echappa@gmx.com>2013-02-03 00:59:38 -0700
committerEduardo Chappa <echappa@gmx.com>2013-02-03 00:59:38 -0700
commit094ca96844842928810f14844413109fc6cdd890 (patch)
treee60efbb980f38ba9308ccb4fb2b77b87bbc115f3 /pith/addrbook.c
downloadalpine-094ca96844842928810f14844413109fc6cdd890.tar.xz
Initial Alpine Version
Diffstat (limited to 'pith/addrbook.c')
-rw-r--r--pith/addrbook.c369
1 files changed, 369 insertions, 0 deletions
diff --git a/pith/addrbook.c b/pith/addrbook.c
new file mode 100644
index 00000000..9828e4c6
--- /dev/null
+++ b/pith/addrbook.c
@@ -0,0 +1,369 @@
+#if !defined(lint) && !defined(DOS)
+static char rcsid[] = "$Id: addrbook.c 90 2006-07-19 22:30:36Z 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
+ *
+ * ========================================================================
+ */
+
+/*======================================================================
+ addrbook.c
+ display format/support routines
+ ====*/
+
+#include "../c-client/c-client.h"
+
+#include <system.h>
+#include <general.h>
+
+#include "addrbook.h"
+#include "state.h"
+#include "adrbklib.h"
+#include "abdlc.h"
+#include "conf.h"
+#include "conftype.h"
+#include "status.h"
+#include "debug.h"
+#include "osdep/collate.h"
+
+
+/* internal prototypes */
+void parse_format(char *, COL_S *);
+
+
+
+
+/*
+ * We have to call this to set up the format of the columns. There is a
+ * separate format for each addrbook, so we need to call this for each
+ * addrbook. We call it when the pab's are built. It also depends on
+ * whether or not as.checkboxes is set, so if we go into a Select mode
+ * from the address book maintenance screen we need to re-call this. Since
+ * we can't go back out of ListMode we don't have that problem. Restore_state
+ * has to call it because of the as.checkboxes possibly being different in
+ * the two states.
+ */
+void
+addrbook_new_disp_form(PerAddrBook *pab, char **list, int addrbook_num,
+ int (*prefix_f)(PerAddrBook *, int *))
+{
+ char *last_one;
+ int column = 0;
+
+ dprint((9, "- init_disp_form(%s) -\n",
+ (pab && pab->abnick) ? pab->abnick : "?"));
+
+ memset((void *)pab->disp_form, 0, NFIELDS*sizeof(COL_S));
+ pab->disp_form[1].wtype = WeCalculate; /* so we don't get false AllAuto */
+
+ if(prefix_f)
+ as.do_bold = (*prefix_f)(pab, &column);
+
+ /* if custom format is specified */
+ if(list && list[0] && list[0][0]){
+ /* find the one for addrbook_num */
+ for(last_one = *list;
+ *list != NULL && addrbook_num;
+ addrbook_num--,list++)
+ last_one = *list;
+
+ /* If not enough to go around, last one repeats */
+ if(*list == NULL)
+ parse_format(last_one, &(pab->disp_form[column]));
+ else
+ parse_format(*list, &(pab->disp_form[column]));
+ }
+ else{ /* default */
+ /* If 2nd wtype is AllAuto, the widths are calculated old way */
+ pab->disp_form[1].wtype = AllAuto;
+
+ pab->disp_form[column++].type = Nickname;
+ pab->disp_form[column++].type = Fullname;
+ pab->disp_form[column++].type = Addr;
+ /* Fill in rest */
+ while(column < NFIELDS)
+ pab->disp_form[column++].type = Notused;
+ }
+}
+
+
+struct parse_tokens {
+ char *name;
+ ColumnType ctype;
+};
+
+struct parse_tokens ptokens[] = {
+ {"NICKNAME", Nickname},
+ {"FULLNAME", Fullname},
+ {"ADDRESS", Addr},
+ {"FCC", Filecopy},
+ {"COMMENT", Comment},
+ {"DEFAULT", Def},
+ {NULL, Notused}
+};
+
+/*
+ * Parse format_str and fill in disp_form structure based on what's there.
+ *
+ * Args: format_str -- The format string from pinerc.
+ * disp_form -- This is where we fill in the answer.
+ *
+ * The format string consists of special tokens which give the order of
+ * the columns to be displayed. The possible tokens are NICKNAME,
+ * FULLNAME, ADDRESS, FCC, COMMENT. If a token is followed by
+ * parens with an integer inside (FULLNAME(16)) then that means we
+ * make that variable that many characters wide. If it is a percentage, we
+ * allocate that percentage of the columns to that variable. If no
+ * parens, that means we calculate it for the user. The tokens are
+ * delimited by white space. A token of DEFAULT means to calculate the
+ * whole thing as we would if no spec was given. This makes it possible
+ * to specify default for one addrbook and something special for another.
+ */
+void
+parse_format(char *format_str, COL_S *disp_form)
+{
+ int column = 0;
+ char *p, *q;
+ struct parse_tokens *pt;
+ int nicknames, fullnames, addresses, not_allauto;
+ int warnings = 0;
+
+ p = format_str;
+ while(p && *p && column < NFIELDS){
+ p = skip_white_space(p); /* space for next word */
+
+ /* look for the ptoken this word matches */
+ for(pt = ptokens; pt->name; pt++)
+ if(!struncmp(pt->name, p, strlen(pt->name)))
+ break;
+
+ /* ignore unrecognized word */
+ if(!pt->name){
+ char *r;
+
+ if((r=strindex(p, SPACE)) != NULL)
+ *r = '\0';
+
+ dprint((2, "parse_format: ignoring unrecognized word \"%s\" in address-book-formats\n", p ? p : "?"));
+ q_status_message1(SM_ORDER, warnings++==0 ? 1 : 0, 4,
+ /* TRANSLATORS: an informative error message */
+ _("Ignoring unrecognized word \"%s\" in Address-Book-Formats"), p);
+ /* put back space */
+ if(r)
+ *r = SPACE;
+
+ /* skip unrecognized word */
+ while(p && *p && !isspace((unsigned char)(*p)))
+ p++;
+
+ continue;
+ }
+
+ disp_form[column].type = pt->ctype;
+
+ /* skip over name and look for parens */
+ p += strlen(pt->name);
+ if(*p == '('){
+ p++;
+ q = p;
+ while(p && *p && isdigit((unsigned char)*p))
+ p++;
+
+ if(p && *p && *p == ')' && p > q){
+ disp_form[column].wtype = Fixed;
+ disp_form[column].req_width = atoi(q);
+ }
+ else if(p && *p && *p == '%' && p > q){
+ disp_form[column].wtype = Percent;
+ disp_form[column].req_width = atoi(q);
+ }
+ else{
+ disp_form[column].wtype = WeCalculate;
+ if(disp_form[column].type == Nickname)
+ disp_form[column].req_width = 8;
+ else
+ disp_form[column].req_width = 3;
+ }
+ }
+ else{
+ disp_form[column].wtype = WeCalculate;
+ if(disp_form[column].type == Nickname)
+ disp_form[column].req_width = 8;
+ else
+ disp_form[column].req_width = 3;
+ }
+
+ if(disp_form[column].type == Def){
+ /* If any type is DEFAULT, the widths are calculated old way */
+assign_default:
+ column = 0;
+
+ disp_form[column].wtype = AllAuto;
+ disp_form[column++].type = Nickname;
+ disp_form[column].wtype = AllAuto;
+ disp_form[column++].type = Fullname;
+ disp_form[column].wtype = AllAuto;
+ disp_form[column++].type = Addr;
+ /* Fill in rest */
+ while(column < NFIELDS)
+ disp_form[column++].type = Notused;
+
+ return;
+ }
+
+ column++;
+ /* skip text at end of word */
+ while(p && *p && !isspace((unsigned char)(*p)))
+ p++;
+ }
+
+ if(column == 0){
+ q_status_message(SM_ORDER, 0, 4,
+ _("Address-Book-Formats has no recognizable words, using default format"));
+ goto assign_default;
+ }
+
+ /* Fill in rest */
+ while(column < NFIELDS)
+ disp_form[column++].type = Notused;
+
+ /* check to see if user is just re-ordering default fields */
+ nicknames = 0;
+ fullnames = 0;
+ addresses = 0;
+ not_allauto = 0;
+ for(column = 0; column < NFIELDS; column++){
+ if(disp_form[column].type != Notused
+ && disp_form[column].wtype != WeCalculate)
+ not_allauto++;
+
+ switch(disp_form[column].type){
+ case Nickname:
+ nicknames++;
+ break;
+
+ case Fullname:
+ fullnames++;
+ break;
+
+ case Addr:
+ addresses++;
+ break;
+
+ case Filecopy:
+ case Comment:
+ not_allauto++;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /*
+ * Special case: if there is no address field specified, we put in
+ * a special field called WhenNoAddrDisplayed, which causes list
+ * entries to be displayable in all cases.
+ */
+ if(!addresses){
+ for(column = 0; column < NFIELDS; column++)
+ if(disp_form[column].type == Notused)
+ break;
+
+ if(column < NFIELDS){
+ disp_form[column].type = WhenNoAddrDisplayed;
+ disp_form[column].wtype = Special;
+ }
+ }
+
+ if(nicknames == 1 && fullnames == 1 && addresses == 1 && not_allauto == 0)
+ disp_form[0].wtype = AllAuto; /* set to do default widths */
+}
+
+
+/*
+ * Find the first selectable line greater than or equal to line. That is,
+ * the first line the cursor is allowed to start on.
+ * (If there are none >= line, it will find the highest one.)
+ *
+ * Returns the line number of the found line or NO_LINE if there isn't one.
+ */
+long
+first_selectable_line(long int line)
+{
+ long lineno;
+ register PerAddrBook *pab;
+ int i;
+
+ /* skip past non-selectable lines */
+ for(lineno=line;
+ !line_is_selectable(lineno) && dlist(lineno)->type != End;
+ lineno++)
+ ;/* do nothing */
+
+ if(line_is_selectable(lineno))
+ return(lineno);
+
+ /*
+ * There were no selectable lines from lineno on down. Trying looking
+ * back up the list.
+ */
+ for(lineno=line-1;
+ !line_is_selectable(lineno) && dlist(lineno)->type != Beginning;
+ lineno--)
+ ;/* do nothing */
+
+ if(line_is_selectable(lineno))
+ return(lineno);
+
+ /*
+ * No selectable lines at all.
+ * If some of the addrbooks are still not displayed, it is too
+ * early to set the no_op_possbl flag. Or, if some of the addrbooks
+ * are empty but writable, then we should not set it either.
+ */
+ for(i = 0; i < as.n_addrbk; i++){
+ pab = &as.adrbks[i];
+ if(pab->ostatus != Open &&
+ pab->ostatus != HalfOpen &&
+ pab->ostatus != ThreeQuartOpen)
+ return NO_LINE;
+
+ if(pab->access == ReadWrite && adrbk_count(pab->address_book) == 0)
+ return NO_LINE;
+ }
+
+ as.no_op_possbl++;
+ return NO_LINE;
+}
+
+
+/*
+ * Returns 1 if this line is of a type that can have a cursor on it.
+ */
+int
+line_is_selectable(long int lineno)
+{
+ register AddrScrn_Disp *dl;
+
+ if((dl = dlist(lineno)) && (dl->type == Text ||
+ dl->type == ListEmpty ||
+ dl->type == TitleCmb ||
+ dl->type == Beginning ||
+ dl->type == End)){
+
+ return 0;
+ }
+
+ return 1;
+}