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