]> git.deb.at Git - pkg/abook.git/blob - database.c
Replaced some items < 1 with list_is_empty()
[pkg/abook.git] / database.c
1
2 /*
3  * $Id$
4  *
5  * by JH <jheinonen@bigfoot.com>
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                 }
113                 free(line);
114         }
115
116         free(line);
117         return 0;
118 }
119
120                 
121
122 int
123 load_database(char *filename)
124 {
125         FILE *in;
126
127         if( database != NULL )
128                 close_database();
129
130         if ( (in = abook_fopen(filename, "r")) == NULL )
131                 return -1;
132         
133         parse_database(in);
134
135         if ( items == 0 )
136                 return 2;
137
138         return 0;
139 }
140
141 int
142 write_database(FILE *out)
143 {
144         int i,j;
145
146         fprintf(out, "# abook addressbook file\n\n");
147         fprintf(out, "[format]\n");
148         fprintf(out, "program=" PACKAGE "\n");
149         fprintf(out, "version=" VERSION "\n");
150         fprintf(out, "\n\n");
151
152         for( i = 0; i < items; i++ ) {
153                 fprintf(out, "[%d]\n", i);
154                 for(j=0; j<ITEM_FIELDS; j++) {
155                         if( database[i][j] != NULL && *database[i][j] )
156                                 fprintf(out, "%s=%s\n",
157                                         abook_fields[j].key, database[i][j]);
158                 }
159                 fputc('\n', out);
160         }
161
162         return 0;
163 }
164
165 int
166 save_database()
167 {
168         FILE *out;
169
170         if( (out = abook_fopen(datafile, "w")) == NULL )
171                 return -1;
172
173         if( list_is_empty() ) {
174                 fclose(out);
175                 unlink(datafile);
176                 return 1;
177         }
178
179         
180         write_database(out);
181         
182         fclose(out);
183         
184         return 0;
185 }
186
187 static void
188 free_item(int item)
189 {
190         free_list_item(database[item]);
191 }
192
193 void
194 free_list_item(list_item item)
195 {
196         int i;
197
198         for(i=0; i<ITEM_FIELDS; i++)
199                 my_free(item[i]);
200 }
201
202 void
203 close_database()
204 {
205         int i;
206         
207         for(i=0; i < items; i++)
208                 free_item(i);
209
210         free(database);
211         free(selected);
212
213         database = NULL;
214         selected = NULL;
215
216         items = 0;
217         first_list_item = curitem = -1;
218         list_capacity = 0;
219 }
220
221 #define _MAX_FIELD_LEN(X)       (X == EMAIL ? MAX_EMAILSTR_LEN:MAX_FIELD_LEN)
222
223 inline static void
224 validate_item(list_item item)
225 {
226         int i;
227         char *tmp;
228         
229         if(item[EMAIL] == NULL)
230                 item[EMAIL] = strdup("");
231
232         for(i=0; i<ITEM_FIELDS; i++)
233                 if( item[i] && (strlen(item[i]) > _MAX_FIELD_LEN(i) ) ) {
234                         tmp = item[i];
235                         item[i][_MAX_FIELD_LEN(i)-1] = 0;
236                         item[i] = strdup(item[i]);
237                         free(tmp);
238                 }
239 }
240
241
242 static void
243 adjust_list_capacity()
244 {
245         if(list_capacity < 1)
246                 list_capacity = INITIAL_LIST_CAPACITY;
247         else if(items >= list_capacity)
248                 list_capacity *= 2;
249         else if(list_capacity / 2 > items)
250                 list_capacity /= 2;
251         else
252                 return;
253
254         database = abook_realloc(database,
255                         sizeof(list_item) * list_capacity);
256         selected = abook_realloc(selected, list_capacity);
257 }
258
259 int
260 add_item2database(list_item item)
261 {
262         if( item[NAME] == NULL || ! *item[NAME] ) {
263                 free_list_item(item);
264                 return 1;
265         }
266
267         if( ++items > list_capacity)
268                 adjust_list_capacity();
269
270         validate_item(item);
271
272         selected[LAST_ITEM] = 0;
273         itemcpy(database[LAST_ITEM], item);
274
275         return 0;
276 }
277
278 void
279 remove_selected_items()
280 {
281         int i, j;
282
283         if( list_is_empty() )
284                 return;
285
286         if( ! selected_items() )
287                 selected[ curitem ] = 1;
288         
289         for( j = LAST_ITEM; j >= 0; j-- ) {
290                 if( selected[j] ) {
291                         free_item(j); /* added for .4 data_s_ */
292                         for( i = j; i < LAST_ITEM; i++ ) {
293                                 itemcpy(database[ i ], database[ i + 1 ]);
294                                 selected[ i ] = selected[ i + 1 ];
295                         }
296                         items--;        
297                 }
298         }
299
300         if( curitem > LAST_ITEM && items > 0 )
301                 curitem = LAST_ITEM;
302
303
304         adjust_list_capacity();
305
306         select_none();
307 }
308
309 char *
310 get_surname(char *s)
311 {
312         int i, a;
313         int len = strlen(s);
314         char *name = strdup(s);
315
316         for( a = 0, i = len - 1; i >= 0; i--, a++ ) {
317                 name[a] = s[i];
318                 if(name[a] == ' ')
319                         break;
320         }
321
322         name[ a ] = 0;
323
324         revstr(name);
325
326         return name;
327 }
328
329 static int
330 surnamecmp(const void *i1, const void *i2)
331 {
332         int ret;
333         list_item a,b;
334         char *s1, *s2;
335
336         itemcpy(a, i1);
337         itemcpy(b, i2);
338
339         s1 = get_surname(a[NAME]);
340         s2 = get_surname(b[NAME]);
341
342         if( !(ret = safe_strcmp(s1, s2)) )
343                 ret = safe_strcmp(a[NAME], b[NAME]);
344
345         free(s1);
346         free(s2);
347
348         return ret;
349 }
350
351 static int
352 namecmp(const void *i1, const void *i2)
353 {
354         list_item a, b;
355
356         itemcpy(a, i1);
357         itemcpy(b, i2);
358         
359         return safe_strcmp( a[NAME], b[NAME] );
360 }
361
362 void
363 sort_database()
364 {
365         select_none();
366         
367         qsort((void *)database, items, sizeof(list_item), namecmp);
368
369         refresh_screen();
370 }
371
372 void
373 sort_surname()
374 {
375         select_none();
376
377         qsort((void *)database, items, sizeof(list_item), surnamecmp);
378
379         refresh_screen();
380 }
381
382 int
383 find_item(char *str, int start)
384 {
385         int i;
386         char *findstr = NULL;
387         char *tmp = NULL;
388         int ret = -1; /* not found */
389
390         if(items < 1 || start < 0 || start >= LAST_ITEM)
391                 return -2; /* error */
392
393         findstr = strdup(str);
394         findstr = strupper(findstr);
395
396         for( i = start; i < items; i++ ) {
397                 tmp = strdup(database[i][NAME]);
398                 if( strstr(strupper(tmp), findstr) != NULL ) {
399                         ret = i;
400                         goto out;
401                 }
402                 my_free(tmp);
403         }
404
405 out:
406         free(findstr);
407         free(tmp);
408         return ret;
409 }
410
411
412 int
413 is_selected(int item)
414 {
415         return selected[item];
416 }