+
+int
+is_valid_item(int item)
+{
+ return item <= LAST_ITEM && item >= 0;
+}
+
+int
+last_item()
+{
+ return LAST_ITEM;
+}
+
+int
+db_n_items()
+{
+ return items;
+}
+
+int
+real_db_enumerate_items(struct db_enumerator e)
+{
+ int item = max(0, e.item + 1);
+ int i;
+
+ switch(e.mode) {
+#ifdef DEBUG
+ case ENUM_ALL:
+ break;
+#endif
+ case ENUM_SELECTED:
+ for(i = item; i <= LAST_ITEM; i++) {
+ if(is_selected(i)) {
+ item = i;
+ goto out;
+ }
+ }
+ return -1;
+#ifdef DEBUG
+ default:
+ fprintf(stderr, "real_db_enumerate_items() "
+ "BUG: unknown db_enumerator mode: %d\n",
+ e.mode);
+ break;
+#endif
+ }
+out:
+ return (item > LAST_ITEM || item < 0) ? -1 : item;
+}
+
+struct db_enumerator
+init_db_enumerator(int mode)
+{
+ struct db_enumerator e;
+
+ e.item = -1; /* important - means "start from beginning" */
+ e.mode = mode;
+
+ return e;
+}
+
+
+list_item
+item_create()
+{
+ return xmalloc0(ITEM_SIZE);
+}
+
+void
+item_free(list_item *item)
+{
+ assert(item);
+
+ xfree(*item);
+}
+
+void
+item_empty(list_item item)
+{ int i;
+
+ assert(item);
+
+ for(i = 0; i < fields_count; i++)
+ if(item[i])
+ xfree(item[i]);
+
+}
+
+void
+item_copy(list_item dest, list_item src)
+{
+ memmove(dest, src, ITEM_SIZE);
+}
+
+void
+item_duplicate(list_item dest, list_item src)
+{
+ int i;
+
+ for(i = 0; i < fields_count; i++)
+ dest[i] = src[i] ? xstrdup(src[i]) : NULL;
+}
+
+/*
+ * Things like item[field_id(NICK)] should never be used, since besides NAME
+ * and EMAIL, none of the standard fields can be assumed to be existing.
+ *
+ * Prefer the functions item_fput(), item_fget(), db_fput() and db_fget()
+ * to access fields in items and database.
+ */
+
+/* quick lookup by "standard" field number */
+inline int
+field_id(int i)
+{
+ assert((i >= 0) && (i < ITEM_FIELDS));
+ return standard_fields_indexed[i];
+}
+
+int
+item_fput(list_item item, int i, char *val)
+{
+ int id = field_id(i);
+
+ if(id != -1) {
+ item[id] = val;
+ return 1;
+ }
+
+ return 0;
+}
+
+char *
+item_fget(list_item item, int i)
+{
+ int id = field_id(i);
+
+ if(id != -1)
+ return item[id];
+ else
+ return NULL;
+}
+
+int
+real_db_field_put(int item, int i, int std, char *val)
+{
+ int id;
+
+ assert(database[item]);
+
+ id = std ? field_id(i) : i;
+
+ if(id != -1) {
+ database[item][id] = val;
+ return 1;
+ }
+
+ return 0;
+}
+
+char *
+real_db_field_get(int item, int i, int std)
+{
+ int id;
+
+ assert(database[item]);
+
+ id = std ? field_id(i) : i;
+
+ if(id != -1)
+ return database[item][id];
+ else
+ return NULL;
+}
+
+list_item
+db_item_get(int i)
+{
+ return database[i];
+}
+
+/* Fetch addresses from all fields of FIELD_EMAILS type */
+/* Memory has to be freed by the caller */
+char *
+db_email_get(int item)
+{
+ int i;
+ char *res;
+ abook_field_list *cur;
+ abook_list *emails = NULL;
+
+ for(cur = fields_list, i = 0; cur; cur = cur->next, i++)
+ if(cur->field->type == FIELD_EMAILS && *database[item][i])
+ abook_list_append(&emails, database[item][i]);
+
+ res = abook_list_to_csv(emails);
+ abook_list_free(&emails);
+ return res ? res : xstrdup("");
+}
+