1 /*
2 * rolo - contact management software
3 * Copyright (C) 2003 Andrew Hsu
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 * 02111-1307 USA
19 *
20 * $Id: entry.c,v 1.6 2003/05/20 01:08:52 ahsu Rel $
21 */
22
23 #include "entry.h"
24 #include <ncurses.h>
25 #include <string.h>
26 #include <vc.h>
27
28 #define MENU_PRINT_FORMAT_SIZE 38
29
30 static int cmp_tel (const char *desc_a, const char *desc_b);
31 static int cmp_email (const char *desc_a, const char *desc_b);
32 static int cmp_given_n (const char *desc_a, const char *desc_b);
33 static int cmp_desc_by_tel (const void *a, const void *b);
34 static int cmp_desc_by_email (const void *a, const void *b);
35 static int cmp_desc_by_given_n (const void *a, const void *b);
36 static int cmp_desc_by_family_n (const void *a, const void *b);
37 static char *construct_menu_name (const char *family_name,
38 const char *given_name, const char *email,
39 const char *tel);
40 static void set_menu_print_format (char *menu_print_format, int width);
41
42 /***************************************************************************
43 */
44
45 static int
cmp_tel(const char * desc_a,const char * desc_b)46 cmp_tel (const char *desc_a, const char *desc_b)
47 {
48 int i = 0;
49 int n = 0;
50 int ret_val = 0;
51
52 for (i = 57, n = 74; i < n; i++)
53 {
54 if (tolower (desc_a[i]) > tolower (desc_b[i]))
55 {
56 ret_val = 1;
57 break;
58 }
59 else if (tolower (desc_a[i]) < tolower (desc_b[i]))
60 {
61 ret_val = -1;
62 break;
63 }
64 }
65 return ret_val;
66 }
67
68 /***************************************************************************
69 */
70
71 static int
cmp_email(const char * desc_a,const char * desc_b)72 cmp_email (const char *desc_a, const char *desc_b)
73 {
74 int i = 0;
75 int n = 0;
76 int ret_val = 0;
77
78 for (i = 26, n = 56; i < n; i++)
79 {
80 if (tolower (desc_a[i]) > tolower (desc_b[i]))
81 {
82 ret_val = 1;
83 break;
84 }
85 else if (tolower (desc_a[i]) < tolower (desc_b[i]))
86 {
87 ret_val = -1;
88 break;
89 }
90 }
91 return ret_val;
92 }
93
94 /***************************************************************************
95 */
96
97 static int
cmp_given_n(const char * desc_a,const char * desc_b)98 cmp_given_n (const char *desc_a, const char *desc_b)
99 {
100 int i = 0;
101 int n = 0;
102 int ret_val = 0;
103
104 for (i = 13, n = 25; i < n; i++)
105 {
106 if (tolower (desc_a[i]) > tolower (desc_b[i]))
107 {
108 ret_val = 1;
109 break;
110 }
111 else if (tolower (desc_a[i]) < tolower (desc_b[i]))
112 {
113 ret_val = -1;
114 break;
115 }
116 }
117 return ret_val;
118 }
119
120 /***************************************************************************
121 */
122
123 static int
cmp_desc_by_tel(const void * a,const void * b)124 cmp_desc_by_tel (const void *a, const void *b)
125 {
126 int ret_val = 0;
127 entry_node **ena = NULL;
128 entry_node **enb = NULL;
129
130 ena = (entry_node **) a;
131 enb = (entry_node **) b;
132
133 ret_val = cmp_tel ((*ena)->description, (*enb)->description);
134
135 if (0 == ret_val)
136 {
137 ret_val = strcmp ((*ena)->description, (*enb)->description);
138 }
139
140 return ret_val;
141 }
142
143 /***************************************************************************
144 */
145
146 static int
cmp_desc_by_email(const void * a,const void * b)147 cmp_desc_by_email (const void *a, const void *b)
148 {
149 int ret_val = 0;
150 entry_node **ena = NULL;
151 entry_node **enb = NULL;
152
153 ena = (entry_node **) a;
154 enb = (entry_node **) b;
155
156 ret_val = cmp_email ((*ena)->description, (*enb)->description);
157 if (0 == ret_val)
158 {
159 ret_val = strcmp ((*ena)->description, (*enb)->description);
160 }
161
162 return ret_val;
163 }
164
165 /***************************************************************************
166 */
167
168 static int
cmp_desc_by_given_n(const void * a,const void * b)169 cmp_desc_by_given_n (const void *a, const void *b)
170 {
171 int ret_val = 0;
172 entry_node **ena = NULL;
173 entry_node **enb = NULL;
174
175 ena = (entry_node **) a;
176 enb = (entry_node **) b;
177
178 ret_val = cmp_given_n ((*ena)->description, (*enb)->description);
179 if (0 == ret_val)
180 {
181 ret_val = strcmp ((*ena)->description, (*enb)->description);
182 }
183
184 return ret_val;
185 }
186
187 /***************************************************************************
188 */
189
190 static int
cmp_desc_by_family_n(const void * a,const void * b)191 cmp_desc_by_family_n (const void *a, const void *b)
192 {
193 int ret_val = 0;
194 entry_node **ena = NULL;
195 entry_node **enb = NULL;
196
197 ena = (entry_node **) a;
198 enb = (entry_node **) b;
199
200 ret_val = strcmp ((*ena)->description, (*enb)->description);
201
202 return ret_val;
203 }
204
205 /***************************************************************************
206 Sorts the array of entries using the quick sort algorithm.
207 */
208
209 void
sort_entries(entry_node ** entries,int count,int sort_by)210 sort_entries (entry_node ** entries, int count, int sort_by)
211 {
212 switch (sort_by)
213 {
214 case SORT_ENTRIES_BY_FAMILY_N:
215 qsort (entries, count, sizeof (entry_node *), cmp_desc_by_family_n);
216 break;
217 case SORT_ENTRIES_BY_GIVEN_N:
218 qsort (entries, count, sizeof (entry_node *), cmp_desc_by_given_n);
219 break;
220 case SORT_ENTRIES_BY_EMAIL:
221 qsort (entries, count, sizeof (entry_node *), cmp_desc_by_email);
222 break;
223 case SORT_ENTRIES_BY_TEL:
224 qsort (entries, count, sizeof (entry_node *), cmp_desc_by_tel);
225 break;
226 default:
227 break;
228 }
229 }
230
231 /***************************************************************************
232 Filters the given linked list of entries by keeping only those
233 nodes that match the filter_string. Returns the number of nodes
234 that are left out.
235 */
236
237 int
filter_entries(entry_node * entries_ll,const char * filter_string)238 filter_entries (entry_node * entries_ll, const char *filter_string)
239 {
240 int count = 0;
241 entry_node *e = NULL;
242 entry_node *prev = NULL;
243
244 /* first check if there is a filter string */
245 if (NULL != filter_string)
246 {
247 /* remember: the first node is a dummy node */
248 prev = entries_ll;
249 e = entries_ll->next;
250
251 while (e != NULL)
252 {
253 if (NULL == strstr (e->description, filter_string))
254 {
255 /* must delete node */
256 prev->next = e->next;
257 free_entry_node (e);
258 e = prev->next;
259 count++;
260 }
261 else
262 {
263 /* skip node, move on */
264 prev = e;
265 e = e->next;
266 }
267 }
268 }
269
270 /* the number of deleted nodes */
271 return count;
272 }
273
274 /***************************************************************************
275 */
276
277 entry_node **
entries_lltoa(entry_node * entries_ll,int count)278 entries_lltoa (entry_node * entries_ll, int count)
279 {
280 entry_node **entries_a = NULL;
281 entry_node *e = NULL;
282 int i = 0;
283
284 entries_a = (entry_node **) malloc (sizeof (entry_node *) * count);
285
286 for (i = 0, e = entries_ll->next; i < count; i++)
287 {
288 entries_a[i] = e;
289 e = e->next;
290 }
291
292 return entries_a;
293 }
294
295 /***************************************************************************
296 */
297
298 void
free_entries_array_but_leave_data(entry_node ** entries_array,int count)299 free_entries_array_but_leave_data (entry_node ** entries_array, int count)
300 {
301 int i = 0;
302 for (i = 0; i < count; i++)
303 {
304 free (entries_array[i]);
305 }
306
307 free (entries_array);
308 }
309
310 /***************************************************************************
311 Frees an entry node. The user of this function must also
312 remember to set the pointer to NULL after calling this function
313 for cleanliness.
314 */
315
316 void
free_entry_node(entry_node * e)317 free_entry_node (entry_node * e)
318 {
319 if (NULL != e)
320 {
321 free (e->description);
322 free (e->fpos);
323 free (e);
324 }
325 }
326
327 /***************************************************************************
328 Allocates memory for an entry node and initialises the pointers
329 in the structure to NULL.
330 */
331
332 entry_node *
new_entry_node()333 new_entry_node ()
334 {
335 entry_node *e = NULL;
336
337 e = (entry_node *) malloc (sizeof (entry_node));
338
339 if (NULL == e)
340 {
341 endwin ();
342 fprintf (stderr, "unable to malloc an entry_node\n");
343 exit (1);
344 }
345 else
346 {
347 e->description = NULL;
348 e->fpos = NULL;
349 e->next = NULL;
350 }
351
352 return e;
353 }
354
355 /***************************************************************************
356 Parses the data file for entries one at a time and stuffs them
357 into a linked list.
358 */
359
360 int
get_entries(FILE * fp,entry_node * entries_ll)361 get_entries (FILE * fp, entry_node * entries_ll)
362 {
363 int i = 0;
364 vc_component *v = NULL;
365 vc_component *vc = NULL;
366 char *email = NULL;
367 char *tel = NULL;
368 char *family_name = NULL;
369 char *given_name = NULL;
370 char *desc = NULL;
371 int count = 0;
372 entry_node *entry = NULL;
373 fpos_t *fpos = NULL;
374
375 fpos = (fpos_t *) malloc (sizeof (fpos_t));
376 fgetpos (fp, fpos);
377 v = parse_vcard_file (fp);
378
379 while (NULL != v)
380 {
381 count++;
382 entry = new_entry_node ();
383
384 entry->next = entries_ll->next;
385 entries_ll->next = entry;
386
387 entry->fpos = fpos;
388 fpos = NULL;
389
390 /*
391 * retrive the name value
392 */
393
394 vc = vc_get_next_by_name (v, VC_NAME);
395 family_name = get_val_struct_part (vc_get_value (vc), N_FAMILY);
396 given_name = get_val_struct_part (vc_get_value (vc), N_GIVEN);
397
398 /*
399 * retrive the preferred email value
400 */
401
402 email = vc_get_preferred_email (v);
403
404 /*
405 * retrive the preferred telephone value
406 */
407
408 tel = vc_get_preferred_tel (v);
409
410 /*
411 * put them together
412 */
413
414 desc = construct_menu_name (family_name, given_name, email, tel);
415 entry->description = desc;
416
417 /*
418 * cleanup
419 */
420
421 free (family_name);
422 free (given_name);
423 family_name = NULL;
424 given_name = NULL;
425 vc_delete_deep (v);
426 v = NULL;
427
428 fpos = (fpos_t *) malloc (sizeof (fpos_t));
429 fgetpos (fp, fpos);
430 v = parse_vcard_file (fp);
431 }
432
433 return count;
434 }
435
436 /***************************************************************************
437 Constructs a string containing the description part of a
438 menu_item. The user of this function must remember to free the
439 returned string at some point in the future.
440 */
441
442 static char *
construct_menu_name(const char * family_name,const char * given_name,const char * email,const char * tel)443 construct_menu_name (const char *family_name, const char *given_name,
444 const char *email, const char *tel)
445 {
446 char *menu_name = NULL;
447 char menu_print_format[MENU_PRINT_FORMAT_SIZE];
448 int x = 0;
449 int y = 0;
450
451 /* FIXME: get the y and x vals from arguments passed to this function
452 so that this module will not need to rely on ncurses.h */
453 getmaxyx (stdscr, y, x);
454 menu_name = (char *) malloc (sizeof (char) * (x - 5 + 1));
455
456 set_menu_print_format (menu_print_format, x);
457 sprintf (menu_name, menu_print_format,
458 family_name ? family_name : "",
459 given_name ? given_name : "", email ? email : "", tel ? tel : "");
460
461 return menu_name;
462 }
463
464 /***************************************************************************
465 Sets the print format string given a width.
466 */
467
468 static void
set_menu_print_format(char * menu_print_format,int width)469 set_menu_print_format (char *menu_print_format, int width)
470 {
471 /* 75 characters long -- fits into 80 character wide screen */
472 strcpy (menu_print_format, "%-12.12s %-12.12s %-30.30s %-18.18s");
473 }
474