/*
* $Id$
*
- * by JH <jheinonen@bigfoot.com>
+ * by JH <jheinonen@users.sourceforge.net>
*
* Copyright (C) Jaakko Heinonen
*/
#include <unistd.h>
#include <fcntl.h>
#include "abook.h"
+#include <assert.h>
#include "database.h"
+#include "gettext.h"
#include "list.h"
#include "misc.h"
#include "options.h"
#include "filter.h"
+#include "xmalloc.h"
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
-static void free_item(int i);
-
-
list_item *database = NULL;
int items = 0;
#define INITIAL_LIST_CAPACITY 30
-int list_capacity = 0;
+static int list_capacity = 0;
extern int first_list_item;
extern int curitem;
extern char *selected;
extern char *datafile;
-extern char *rcfile;
/*
* field definitions
*/
struct abook_field abook_fields[ITEM_FIELDS] = {
- {"Name", "name", TAB_CONTACT},/* NAME */
- {"E-mails", "email", TAB_CONTACT},/* EMAIL */
- {"Address", "address", TAB_ADDRESS},/* ADDRESS */
- {"City", "city", TAB_ADDRESS},/* CITY */
- {"State/Province","state", TAB_ADDRESS},/* STATE */
- {"ZIP/Postal Code","zip", TAB_ADDRESS},/* ZIP */
- {"Country", "country", TAB_ADDRESS},/* COUNTRY */
- {"Home Phone", "phone", TAB_PHONE},/* PHONE */
- {"Work Phone", "workphone", TAB_PHONE},/* WORKPHONE */
- {"Fax", "fax", TAB_PHONE},/* FAX */
- {"Mobile", "mobile", TAB_PHONE},/* MOBILEPHONE */
- {"Nickname/Alias", "nick", TAB_OTHER},/* NICK */
- {"URL", "url", TAB_OTHER},/* URL */
- {"Notes", "notes", TAB_OTHER},/* NOTES */
+ {N_("Name"), "name", TAB_CONTACT},/* NAME */
+ {N_("E-mails"), "email", TAB_CONTACT},/* EMAIL */
+ {N_("Address"), "address", TAB_ADDRESS},/* ADDRESS */
+ {N_("Address2"), "address2", TAB_ADDRESS},/* ADDRESS2 */
+ {N_("City"), "city", TAB_ADDRESS},/* CITY */
+ {N_("State/Province"),"state", TAB_ADDRESS},/* STATE */
+ {N_("ZIP/Postal Code"),"zip", TAB_ADDRESS},/* ZIP */
+ {N_("Country"), "country", TAB_ADDRESS},/* COUNTRY */
+ {N_("Home Phone"), "phone", TAB_PHONE},/* PHONE */
+ {N_("Work Phone"), "workphone", TAB_PHONE},/* WORKPHONE */
+ {N_("Fax"), "fax", TAB_PHONE},/* FAX */
+ {N_("Mobile"), "mobile", TAB_PHONE},/* MOBILEPHONE */
+ {N_("Nickname/Alias"), "nick", TAB_OTHER},/* NICK */
+ {N_("URL"), "url", TAB_OTHER},/* URL */
+ {N_("Notes"), "notes", TAB_OTHER},/* NOTES */
+ {N_("Custom1"), "custom1", TAB_CUSTOM},/* CUSTOM1 */
+ {N_("Custom2"), "custom2", TAB_CUSTOM},/* CUSTOM2 */
+ {N_("Custom3"), "custom3", TAB_CUSTOM},/* CUSTOM3 */
+ {N_("Custom4"), "custom4", TAB_CUSTOM},/* CUSTOM4 */
+ {N_("Custom5"), "custom5", TAB_CUSTOM},/* CUSTOM5 */
};
+int
+find_field(const char *field)
+{
+ int i;
+
+ for(i = 0; i < ITEM_FIELDS; i++)
+ if( !strcmp(abook_fields[i].key, field) )
+ return i;
+
+ return -1;
+}
+
int
parse_database(FILE *in)
{
list_item item;
memset(&item, 0, sizeof(item));
-
+
for(;;) {
line = getaline(in);
- if( feof(in) ) {
- if( item[NAME] && sec )
+ if(feof(in)) {
+ if(item[NAME] && sec)
add_item2database(item);
else
free_list_item(item);
break;
}
- if( !*line || *line == '\n' || *line == '#' ) {
- free(line);
- continue;
- } else if( *line == '[' ) {
+ if(!*line || *line == '\n' || *line == '#') {
+ goto next;
+ } else if(*line == '[') {
if( item[NAME] && sec )
add_item2database(item);
else
free_list_item(item);
memset(&item, 0, sizeof(item));
sec = 1;
- if ( !(tmp = strchr(line, ']')))
+ if(!(tmp = strchr(line, ']')))
sec = 0; /*incorrect section lines are skipped*/
- } else if((tmp = strchr(line, '=') ) && sec ) {
+ } else if((tmp = strchr(line, '=') ) && sec) {
*tmp++ = '\0';
- for(i=0; i<ITEM_FIELDS; i++)
- if( !strcmp(abook_fields[i].key, line) )
- item[i] = strdup(tmp);
+ for(i = 0; i < ITEM_FIELDS; i++)
+ if(!strcmp(abook_fields[i].key, line)) {
+ item[i] = xstrdup(tmp);
+ goto next;
+ }
}
- free(line);
+next:
+ xfree(line);
}
- free(line);
+ xfree(line);
return 0;
}
-
+
int
load_database(char *filename)
{
FILE *in;
- if( database != NULL )
+ if(database != NULL)
close_database();
- if ( (in = abook_fopen(filename, "r")) == NULL )
+ if ((in = abook_fopen(filename, "r")) == NULL)
return -1;
-
- parse_database(in);
- if ( items == 0 )
- return 2;
+ parse_database(in);
- return 0;
+ return (items == 0) ? 2 : 0;
}
int
int j;
int i = 0;
- fprintf(out, "# abook addressbook file\n\n");
- fprintf(out, "[format]\n");
- fprintf(out, "program=" PACKAGE "\n");
- fprintf(out, "version=" VERSION "\n");
- fprintf(out, "\n\n");
+ fprintf(out,
+ "# abook addressbook file\n\n"
+ "[format]\n"
+ "program=" PACKAGE "\n"
+ "version=" VERSION "\n"
+ "\n\n"
+ );
db_enumerate_items(e) {
fprintf(out, "[%d]\n", i);
- for(j=0; j<ITEM_FIELDS; j++) {
+ for(j = 0; j < ITEM_FIELDS; j++) {
if( database[e.item][j] != NULL &&
*database[e.item][j] )
fprintf(out, "%s=%s\n",
if( (out = abook_fopen(datafile, "w")) == NULL )
return -1;
- if( list_is_empty() ) {
+ if(list_is_empty()) {
fclose(out);
unlink(datafile);
return 1;
}
-
+
write_database(out, e);
-
+
fclose(out);
-
+
return 0;
}
int i;
for(i=0; i<ITEM_FIELDS; i++)
- my_free(item[i]);
+ xfree(item[i]);
}
void
close_database()
{
int i;
-
+
for(i=0; i < items; i++)
free_item(i);
#define _MAX_FIELD_LEN(X) (X == EMAIL ? MAX_EMAILSTR_LEN:MAX_FIELD_LEN)
-inline static void
+static void
validate_item(list_item item)
{
int i;
char *tmp;
-
+
if(item[EMAIL] == NULL)
- item[EMAIL] = strdup("");
+ item[EMAIL] = xstrdup("");
for(i=0; i<ITEM_FIELDS; i++)
- if( item[i] && (strlen(item[i]) > _MAX_FIELD_LEN(i) ) ) {
+ if( item[i] && ((int)strlen(item[i]) > _MAX_FIELD_LEN(i) ) ) {
tmp = item[i];
item[i][_MAX_FIELD_LEN(i)-1] = 0;
- item[i] = strdup(item[i]);
+ item[i] = xstrdup(item[i]);
free(tmp);
}
}
else
return;
- database = abook_realloc(database,
- sizeof(list_item) * list_capacity);
- selected = abook_realloc(selected, list_capacity);
+ database = xrealloc(database, sizeof(list_item) * list_capacity);
+ selected = xrealloc(selected, list_capacity);
}
int
add_item2database(list_item item)
{
- if( item[NAME] == NULL || ! *item[NAME] ) {
+ if(item[NAME] == NULL || ! *item[NAME]) {
free_list_item(item);
return 1;
}
- if( ++items > list_capacity)
+ if(++items > list_capacity)
adjust_list_capacity();
validate_item(item);
{
int i, j;
- if( list_is_empty() )
+ if(list_is_empty())
return;
- if( ! selected_items() )
- selected[ curitem ] = 1;
-
- for( j = LAST_ITEM; j >= 0; j-- ) {
- if( selected[j] ) {
+ if(!selected_items())
+ selected[curitem] = 1;
+
+ for(j = LAST_ITEM; j >= 0; j--) {
+ if(selected[j]) {
free_item(j); /* added for .4 data_s_ */
- for( i = j; i < LAST_ITEM; i++ ) {
- itemcpy(database[ i ], database[ i + 1 ]);
- selected[ i ] = selected[ i + 1 ];
+ for(i = j; i < LAST_ITEM; i++) {
+ itemcpy(database[i], database[i + 1]);
+ selected[i] = selected[i + 1];
}
- items--;
+ items--;
}
}
- if( curitem > LAST_ITEM && items > 0 )
+ if(curitem > LAST_ITEM && items > 0)
curitem = LAST_ITEM;
-
adjust_list_capacity();
select_none();
char *
get_surname(char *s)
{
- int i, a;
- int len = strlen(s);
- char *name = strdup(s);
+ char *p = s + strlen(s);
- for( a = 0, i = len - 1; i >= 0; i--, a++ ) {
- name[a] = s[i];
- if(name[a] == ' ')
- break;
- }
+ assert(s != NULL);
- name[ a ] = 0;
+ while(p > s && *(p - 1) != ' ')
+ p--;
- revstr(name);
-
- return name;
+ return xstrdup(p);
}
static int
s1 = get_surname(a[NAME]);
s2 = get_surname(b[NAME]);
- if( !(ret = safe_strcmp(s1, s2)) )
- ret = safe_strcmp(a[NAME], b[NAME]);
+ if( !(ret = safe_strcoll(s1, s2)) )
+ ret = safe_strcoll(a[NAME], b[NAME]);
free(s1);
free(s2);
return ret;
}
+static int sort_field = -1;
+
static int
namecmp(const void *i1, const void *i2)
{
list_item a, b;
+ assert(sort_field >= 0 && sort_field <= LAST_FIELD);
+
itemcpy(a, i1);
itemcpy(b, i2);
-
- return safe_strcmp( a[NAME], b[NAME] );
+
+ return safe_strcoll(a[sort_field], b[sort_field]);
+}
+
+static int
+name2field(char *name)
+{
+ int i, ret = -1;
+
+ for(i = 0; i < ITEM_FIELDS; i++) {
+ if(!strcasecmp(name, abook_fields[i].key)) {
+ ret = i;
+ break;
+ }
+ }
+
+ return ret;
}
void
-sort_database()
+sort_by_field(int field)
{
select_none();
-
+
+ assert(field <= LAST_FIELD);
+
+ if(field < 0) {
+ field = name2field(opt_get_str(STR_SORT_FIELD));
+ if(field < 0) {
+ statusline_msg(_("Not valid field value defined "
+ "in configuration"));
+ return;
+ }
+ }
+
+ sort_field = field;
+
qsort((void *)database, items, sizeof(list_item), namecmp);
refresh_screen();
}
int
-find_item(char *str, int start)
+find_item(char *str, int start, int search_fields[])
{
int i;
char *findstr = NULL;
char *tmp = NULL;
int ret = -1; /* not found */
+ struct db_enumerator e = init_db_enumerator(ENUM_ALL);
- if(items < 1 || start < 0 || start >= LAST_ITEM)
+ if(list_is_empty() || !is_valid_item(start))
return -2; /* error */
- findstr = strdup(str);
- findstr = strupper(findstr);
+ findstr = xstrdup(str);
+ findstr = strlower(findstr);
- for( i = start; i < items; i++ ) {
- tmp = strdup(database[i][NAME]);
- if( strstr(strupper(tmp), findstr) != NULL ) {
- ret = i;
- goto out;
+ e.item = start - 1; /* must be "real start" - 1 */
+ db_enumerate_items(e) {
+ for(i = 0; search_fields[i] >= 0; i++) {
+ if(database[e.item][search_fields[i]] == NULL)
+ continue;
+ tmp = xstrdup(database[e.item][search_fields[i]]);
+ if( tmp && strstr(strlower(tmp), findstr) ) {
+ ret = e.item;
+ goto out;
+ }
+ xfree(tmp);
}
- my_free(tmp);
}
out:
{
int item = max(0, e.item + 1);
int i;
-
+
switch(e.mode) {
#ifdef DEBUG
case ENUM_ALL:
struct db_enumerator
init_db_enumerator(int mode)
{
- struct db_enumerator new;
+ struct db_enumerator e;
- new.item = -1; /* important - means "start from beginning" */
- new.mode = mode;
+ e.item = -1; /* important - means "start from beginning" */
+ e.mode = mode;
- return new;
+ return e;
}
+
+static int
+assign_fieldname(const char *name, int i)
+{
+ char *s;
+
+ assert(name);
+ assert(i >= 0 && i < ITEM_FIELDS);
+
+ if(strcasecmp(abook_fields[i].name, name)) { /* name differs */
+ /*
+ * check if we are overwriting statically allocated default
+ */
+ if(strcasecmp(abook_fields[i].name, abook_fields[i].key))
+ xfree(abook_fields[i].name);
+
+ s = xmalloc_inc(MAX_FIELDNAME_LEN, 1);
+ snprintf(s, MAX_FIELDNAME_LEN, "%s", name);
+ abook_fields[i].name = s;
+ }
+
+ return 0;
+}
+
+int
+change_custom_field_name(const char *name, int n)
+{
+ int i;
+ char keyname[21];
+
+ assert(name);
+
+ snprintf(keyname, sizeof(keyname), "custom%d", n);
+
+ for(i = CUSTOM_MIN; i <= CUSTOM_MAX; i++) {
+ if(!strcasecmp(abook_fields[i].key, keyname)) {
+ assign_fieldname(name, i);
+ return i;
+ }
+ }
+
+ return -1;
+}
+