]> git.deb.at Git - pkg/abook.git/blob - database.c
filter updates
[pkg/abook.git] / database.c
1
2 /*
3  * $Id$
4  *
5  * by JH <jheinonen@users.sourceforge.net>
6  *
7  * Copyright (C) Jaakko Heinonen
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include "abook.h"
16 #include "database.h"
17 #include "list.h"
18 #include "misc.h"
19 #include "options.h"
20 #include "filter.h"
21 #ifdef HAVE_CONFIG_H
22 #       include "config.h"
23 #endif
24
25 static void     free_item(int i);
26
27
28 list_item *database = NULL;
29
30 int items = 0;
31
32 #define INITIAL_LIST_CAPACITY   30
33
34 int list_capacity = 0;
35
36 extern int first_list_item;
37 extern int curitem;
38 extern char *selected;
39
40 extern char *datafile;
41 extern char *rcfile;
42
43 /*
44  * field definitions
45  */
46
47 #include "edit.h"
48
49 /*
50  * notes about adding fields:
51  *      - do not change any fields in TAB_CONTACT
52  *      - do not add fields to contact tab
53  *      - 6 fields per tab is maximum
54  *      - reorganize the field numbers in database.h
55  */
56
57 struct abook_field abook_fields[ITEM_FIELDS] = {
58         {"Name",        "name",         TAB_CONTACT},/* NAME */
59         {"E-mails",     "email",        TAB_CONTACT},/* EMAIL */
60         {"Address",     "address",      TAB_ADDRESS},/* ADDRESS */
61         {"City",        "city",         TAB_ADDRESS},/* CITY */
62         {"State/Province","state",      TAB_ADDRESS},/* STATE */
63         {"ZIP/Postal Code","zip",       TAB_ADDRESS},/* ZIP */
64         {"Country",     "country",      TAB_ADDRESS},/* COUNTRY */
65         {"Home Phone",  "phone",        TAB_PHONE},/* PHONE */
66         {"Work Phone",  "workphone",    TAB_PHONE},/* WORKPHONE */
67         {"Fax",         "fax",          TAB_PHONE},/* FAX */
68         {"Mobile",      "mobile",       TAB_PHONE},/* MOBILEPHONE */
69         {"Nickname/Alias", "nick",      TAB_OTHER},/* NICK */
70         {"URL",         "url",          TAB_OTHER},/* URL */
71         {"Notes",       "notes",        TAB_OTHER},/* NOTES */
72 };
73
74
75 int
76 parse_database(FILE *in)
77 {
78         char *line = NULL;
79         char *tmp;
80         int sec=0, i;
81         list_item item;
82
83         memset(&item, 0, sizeof(item));
84         
85         for(;;) {
86                 line = getaline(in);
87                 if( feof(in) ) {
88                         if( item[NAME] && sec )
89                                 add_item2database(item);
90                         else
91                                 free_list_item(item);
92                         break;
93                 }
94
95                 if( !*line || *line == '\n' || *line == '#' ) {
96                         free(line);
97                         continue;
98                 } else if( *line == '[' ) {
99                         if( item[NAME] && sec )
100                                 add_item2database(item);
101                         else
102                                 free_list_item(item);
103                         memset(&item, 0, sizeof(item));
104                         sec = 1;
105                         if ( !(tmp = strchr(line, ']')))
106                                 sec = 0; /*incorrect section lines are skipped*/
107                 } else if((tmp = strchr(line, '=') ) && sec ) {
108                         *tmp++ = '\0';
109                         for(i=0; i<ITEM_FIELDS; i++)
110                                 if( !strcmp(abook_fields[i].key, line) ) {
111                                         item[i] = strdup(tmp);
112                                         goto next;
113                                 }
114                 }
115 next:
116                 free(line);
117         }
118
119         free(line);
120         return 0;
121 }
122
123                 
124
125 int
126 load_database(char *filename)
127 {
128         FILE *in;
129
130         if( database != NULL )
131                 close_database();
132
133         if ( (in = abook_fopen(filename, "r")) == NULL )
134                 return -1;
135         
136         parse_database(in);
137
138         if ( items == 0 )
139                 return 2;
140
141         return 0;
142 }
143
144 int
145 write_database(FILE *out, struct db_enumerator e)
146 {
147         int j;
148         int i = 0;
149
150         fprintf(out,
151                 "# abook addressbook file\n\n"
152                 "[format]\n"
153                 "program=" PACKAGE "\n"
154                 "version=" VERSION "\n"
155                 "\n\n"
156         );
157
158         db_enumerate_items(e) {
159                 fprintf(out, "[%d]\n", i);
160                 for(j = 0; j < ITEM_FIELDS; j++) {
161                         if( database[e.item][j] != NULL &&
162                                         *database[e.item][j] )
163                                 fprintf(out, "%s=%s\n",
164                                         abook_fields[j].key,
165                                         database[e.item][j]
166                                         );
167                 }
168                 fputc('\n', out);
169                 i++;
170         }
171
172         return 0;
173 }
174
175 int
176 save_database()
177 {
178         FILE *out;
179         struct db_enumerator e = init_db_enumerator(ENUM_ALL);
180
181         if( (out = abook_fopen(datafile, "w")) == NULL )
182                 return -1;
183
184         if( list_is_empty() ) {
185                 fclose(out);
186                 unlink(datafile);
187                 return 1;
188         }
189
190         
191         write_database(out, e);
192         
193         fclose(out);
194         
195         return 0;
196 }
197
198 static void
199 free_item(int item)
200 {
201         free_list_item(database[item]);
202 }
203
204 void
205 free_list_item(list_item item)
206 {
207         int i;
208
209         for(i=0; i<ITEM_FIELDS; i++)
210                 my_free(item[i]);
211 }
212
213 void
214 close_database()
215 {
216         int i;
217         
218         for(i=0; i < items; i++)
219                 free_item(i);
220
221         free(database);
222         free(selected);
223
224         database = NULL;
225         selected = NULL;
226
227         items = 0;
228         first_list_item = curitem = -1;
229         list_capacity = 0;
230 }
231
232 #define _MAX_FIELD_LEN(X)       (X == EMAIL ? MAX_EMAILSTR_LEN:MAX_FIELD_LEN)
233
234 inline static void
235 validate_item(list_item item)
236 {
237         int i;
238         char *tmp;
239         
240         if(item[EMAIL] == NULL)
241                 item[EMAIL] = strdup("");
242
243         for(i=0; i<ITEM_FIELDS; i++)
244                 if( item[i] && (strlen(item[i]) > _MAX_FIELD_LEN(i) ) ) {
245                         tmp = item[i];
246                         item[i][_MAX_FIELD_LEN(i)-1] = 0;
247                         item[i] = strdup(item[i]);
248                         free(tmp);
249                 }
250 }
251
252
253 static void
254 adjust_list_capacity()
255 {
256         if(list_capacity < 1)
257                 list_capacity = INITIAL_LIST_CAPACITY;
258         else if(items >= list_capacity)
259                 list_capacity *= 2;
260         else if(list_capacity / 2 > items)
261                 list_capacity /= 2;
262         else
263                 return;
264
265         database = abook_realloc(database,
266                         sizeof(list_item) * list_capacity);
267         selected = abook_realloc(selected, list_capacity);
268 }
269
270 int
271 add_item2database(list_item item)
272 {
273         if( item[NAME] == NULL || ! *item[NAME] ) {
274                 free_list_item(item);
275                 return 1;
276         }
277
278         if( ++items > list_capacity)
279                 adjust_list_capacity();
280
281         validate_item(item);
282
283         selected[LAST_ITEM] = 0;
284         itemcpy(database[LAST_ITEM], item);
285
286         return 0;
287 }
288
289 void
290 remove_selected_items()
291 {
292         int i, j;
293
294         if( list_is_empty() )
295                 return;
296
297         if( ! selected_items() )
298                 selected[ curitem ] = 1;
299         
300         for( j = LAST_ITEM; j >= 0; j-- ) {
301                 if( selected[j] ) {
302                         free_item(j); /* added for .4 data_s_ */
303                         for( i = j; i < LAST_ITEM; i++ ) {
304                                 itemcpy(database[ i ], database[ i + 1 ]);
305                                 selected[ i ] = selected[ i + 1 ];
306                         }
307                         items--;        
308                 }
309         }
310
311         if( curitem > LAST_ITEM && items > 0 )
312                 curitem = LAST_ITEM;
313
314
315         adjust_list_capacity();
316
317         select_none();
318 }
319
320 char *
321 get_surname(char *s)
322 {
323         int i, a;
324         int len = strlen(s);
325         char *name = strdup(s);
326
327         for( a = 0, i = len - 1; i >= 0; i--, a++ ) {
328                 name[a] = s[i];
329                 if(name[a] == ' ')
330                         break;
331         }
332
333         name[ a ] = 0;
334
335         revstr(name);
336
337         return name;
338 }
339
340 static int
341 surnamecmp(const void *i1, const void *i2)
342 {
343         int ret;
344         list_item a,b;
345         char *s1, *s2;
346
347         itemcpy(a, i1);
348         itemcpy(b, i2);
349
350         s1 = get_surname(a[NAME]);
351         s2 = get_surname(b[NAME]);
352
353         if( !(ret = safe_strcmp(s1, s2)) )
354                 ret = safe_strcmp(a[NAME], b[NAME]);
355
356         free(s1);
357         free(s2);
358
359         return ret;
360 }
361
362 static int
363 namecmp(const void *i1, const void *i2)
364 {
365         list_item a, b;
366
367         itemcpy(a, i1);
368         itemcpy(b, i2);
369         
370         return safe_strcmp( a[NAME], b[NAME] );
371 }
372
373 void
374 sort_database()
375 {
376         select_none();
377         
378         qsort((void *)database, items, sizeof(list_item), namecmp);
379
380         refresh_screen();
381 }
382
383 void
384 sort_surname()
385 {
386         select_none();
387
388         qsort((void *)database, items, sizeof(list_item), surnamecmp);
389
390         refresh_screen();
391 }
392
393 int
394 find_item(char *str, int start, int search_fields[])
395 {
396         int i;
397         char *findstr = NULL;
398         char *tmp = NULL;
399         int ret = -1; /* not found */
400         struct db_enumerator e = init_db_enumerator(ENUM_ALL);
401
402         if(list_is_empty() || !is_valid_item(start))
403                 return -2; /* error */
404
405         findstr = strdup(str);
406         findstr = strupper(findstr);
407
408         e.item = start - 1; /* must be "real start" - 1 */
409         db_enumerate_items(e) {
410                 for( i = 0; search_fields[i] >= 0; i++ ) {
411                         tmp = safe_strdup(database[e.item][search_fields[i]]);
412                         if( tmp && strstr(strupper(tmp), findstr) ) {
413                                 ret = e.item;
414                                 goto out;
415                         }
416                         my_free(tmp);
417                 }
418         }
419
420 out:
421         free(findstr);
422         free(tmp);
423         return ret;
424 }
425
426
427 int
428 is_selected(int item)
429 {
430         return selected[item];
431 }
432
433 int
434 is_valid_item(int item)
435 {
436         return item <= LAST_ITEM && item >= 0;
437 }
438
439 int
440 real_db_enumerate_items(struct db_enumerator e)
441 {
442         int item = max(0, e.item + 1);
443         int i;
444         
445         switch(e.mode) {
446 #ifdef DEBUG
447                 case ENUM_ALL:
448                         break;
449 #endif
450                 case ENUM_SELECTED:
451                         for(i = item; i < items; i++) {
452                                 if(is_selected(i)) {
453                                         item = i;
454                                         goto out;
455                                 }
456                         }
457                         return -1;
458 #ifdef DEBUG
459                 default:
460                         fprintf(stderr, "real_db_enumerate_items() "
461                                         "BUG: unknown db_enumerator mode: %d\n",
462                                         e.mode);
463                         break;
464 #endif
465         }
466 out:
467         return (item > LAST_ITEM || item < 0) ? -1 : item;
468 }
469
470 struct db_enumerator
471 init_db_enumerator(int mode)
472 {
473         struct db_enumerator new;
474
475         new.item = -1; /* important - means "start from beginning" */
476         new.mode = mode;
477
478         return new;
479 }