2007-09-02 [colin] 2.10.0cvs190
[claws.git] / src / addrcindex.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2002-2007 Match Grun and the Claws Mail team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (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, see <http://www.gnu.org/licenses/>.
17  * 
18  */
19
20 /*
21  * Functions to maintain address completion index.
22  */
23
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "mgutils.h"
28 #include "addritem.h"
29 #include "addrcindex.h"
30
31 /*
32 static gint _n_created = 0;
33 static gint _n_freed   = 0;
34 */
35
36 typedef struct {
37         gchar     *name;
38         ItemEMail *address;
39 }
40 AddrIndexEntry;
41
42 static gchar *addrcindex_function( gpointer data ) {
43         return ( ( AddrIndexEntry * ) data )->name;
44 }
45
46 /*
47 * Create new completion index.
48 */
49 AddrCacheIndex *addrcindex_create( void ) {
50         AddrCacheIndex *index;
51
52         /*
53         ++_n_created;
54         g_print( "addrcindex_create/1/%d\n", _n_created );
55         */
56         index = g_new0( AddrCacheIndex, 1 );
57         index->completion = g_completion_new( addrcindex_function );
58         index->addressList = NULL;
59         index->invalid = TRUE;
60
61         return index;
62 }
63
64 /*
65 * Clear the completion index.
66 */
67 void addrcindex_clear( AddrCacheIndex *index ) {
68         if( index ) {
69                 /* Clear completion index */
70                 g_completion_clear_items( index->completion );
71
72                 /* Clear address list */        
73                 g_list_free( index->addressList );
74                 index->addressList = NULL;
75                 index->invalid = TRUE;
76         }
77 }
78
79 /*
80 * Free completion index.
81 */
82 void addrcindex_free( AddrCacheIndex *index ) {
83         if( index ) {
84                 /*
85                 ++_n_freed;
86                 g_print( "addrcindex_free/2/%d\n", _n_freed );
87                 */
88                 /* Clear out */
89                 addrcindex_clear( index );
90
91                 /* Free up */
92                 g_completion_free( index->completion );
93                 index->completion = NULL;
94                 index->invalid = FALSE;
95
96                 g_free( index );
97         }
98 }
99
100 /**
101  * Mark index as invalid. Will need to be rebuilt.
102  * \param index Address completion index.
103  */
104 void addrcindex_invalidate( AddrCacheIndex *index ) {
105         g_return_if_fail( index != NULL );
106         index->invalid = TRUE;
107 }
108
109 /**
110  * Mark index as valid.
111  * \param index Address completion index.
112  */
113 void addrcindex_validate( AddrCacheIndex *index ) {
114         g_return_if_fail( index != NULL );
115         index->invalid = FALSE;
116 }
117
118 /*
119  * Add completion entry to index.
120  * Enter: index Index.
121  *        name  Name.
122  *        email EMail entry to add.
123  */
124 void addrcindex_add_entry(
125         AddrCacheIndex *index, gchar *name, ItemEMail *email )
126 {
127         AddrIndexEntry *entry;
128
129         entry = g_new0( AddrIndexEntry, 1 );
130         entry->name = g_strdup( name );
131         entry->address = email;
132         g_strdown( entry->name );
133         index->addressList = g_list_append( index->addressList, entry );
134 }
135
136 /*
137 * Add an email entry into index. The index will also include all name fields
138 * for the person.
139
140 * Add address into index.
141 * Enter: index Index.
142 *        email E-Mail to add.
143 */
144 void addrcindex_add_email( AddrCacheIndex *index, ItemEMail *email ) {
145         ItemPerson *person;
146         gchar *name;
147         GSList *uniqName;
148         GSList *node;
149         gboolean flag;
150
151         g_return_if_fail( index != NULL );
152         g_return_if_fail( email != NULL );
153
154         flag = FALSE;
155         uniqName = NULL;
156         name = ADDRITEM_NAME( email );
157         if( name != NULL ) {
158                 if( strlen( name ) > 0 ) {
159                         uniqName = g_slist_append( uniqName, name );
160                 }
161         }
162         name = email->address;
163         if( mgu_slist_test_unq_nc( uniqName, name ) ) {
164                 uniqName = g_slist_append( uniqName, name );
165         }
166         if( name ) {
167                 if( strlen( name ) > 0 ) flag = TRUE;
168         }
169
170         /* Bail if no email address */
171         if( ! flag ) {
172                 g_slist_free( uniqName );
173                 return;
174         }
175
176         person = ( ItemPerson * ) ADDRITEM_PARENT( email );
177         if( person != NULL ) {
178                 name = ADDRITEM_NAME( person );
179                 if( mgu_slist_test_unq_nc( uniqName, name ) ) {
180                         uniqName = g_slist_append( uniqName, name );
181                 }
182
183                 name = person->nickName;
184                 if( mgu_slist_test_unq_nc( uniqName, name ) ) {
185                         uniqName = g_slist_append( uniqName, name );
186                 }
187
188                 name = person->firstName;
189                 if( mgu_slist_test_unq_nc( uniqName, name ) ) {
190                         uniqName = g_slist_append( uniqName, name );
191                 }
192
193                 name = person->lastName;
194                 if( mgu_slist_test_unq_nc( uniqName, name ) ) {
195                         uniqName = g_slist_append( uniqName, name );
196                 }
197         }
198
199         /* Create a completion entry for each unique name */
200         node = uniqName;
201         while( node ) {
202                 addrcindex_add_entry( index, node->data, email );
203                 node = g_slist_next( node );
204         }
205         g_slist_free( uniqName );
206
207 }
208
209 /*
210  * Process email address entry, checking for unique alias and address. If the
211  * address field is empty, no entries will be generated.
212  * Enter: index Index.
213  *        uniqName List of unique names to examine.
214  *        email    EMail address item to process.
215  * Return: List of entries from email object to add to index.
216  */
217 static GSList *addrcindex_proc_mail(
218         AddrCacheIndex *index, GSList *uniqName, ItemEMail *email )
219 {
220         GSList *list;
221         gchar *name;
222
223         /* Test for address */
224         list = NULL;
225         name = email->address;
226         if( name ) {
227                 if( strlen( name ) > 0 ) {
228                         /* Address was supplied */
229                         /* Append alias if unique */
230                         name = ADDRITEM_NAME( email );
231                         if( mgu_slist_test_unq_nc( uniqName, name ) ) {
232                                 list = g_slist_append( list, name );
233                         }
234                         /* Then append the address if unique */
235                         /* Note is possible that the address has already */
236                         /* been entered into one of the name fields. */
237                         if( mgu_slist_test_unq_nc( uniqName, email->address ) ) {
238                                 list = g_slist_append( list, email->address );
239                         }
240                 }
241         }
242         return list;
243 }
244
245 /*
246 * Add person's address entries into index. Each email address is processed.
247 * If the address field has been supplied, entries will be made. The index
248 * will include the address, alias and all name fields for the person.
249
250 * Enter: index  Index.
251 *        person Person to add.
252 */
253 void addrcindex_add_person( AddrCacheIndex *index, ItemPerson *person ) {
254         gchar *name;
255         GSList *uniqName;
256         GSList *node;
257         GSList *listMail;
258         GList  *listEMail;
259         ItemEMail *email;
260
261         g_return_if_fail( index != NULL );
262         g_return_if_fail( person != NULL );
263
264         /* Build list of all unique names in person's name fields */
265         uniqName = NULL;
266         name = ADDRITEM_NAME( person );
267         if( mgu_slist_test_unq_nc( uniqName, name ) ) {
268                 uniqName = g_slist_append( uniqName, name );
269         }
270
271         name = person->nickName;
272         if( mgu_slist_test_unq_nc( uniqName, name ) ) {
273                 uniqName = g_slist_append( uniqName, name );
274         }
275
276         name = person->firstName;
277         if( mgu_slist_test_unq_nc( uniqName, name ) ) {
278                 uniqName = g_slist_append( uniqName, name );
279         }
280
281         name = person->lastName;
282         if( mgu_slist_test_unq_nc( uniqName, name ) ) {
283                 uniqName = g_slist_append( uniqName, name );
284         }
285
286         /* Process each email address entry */
287         listEMail = person->listEMail;
288         while( listEMail ) {
289                 email = listEMail->data;
290                 listMail = addrcindex_proc_mail( index, uniqName, email );
291                 if( listMail ) {
292                         /* Create a completion entry for the address item */
293                         node = listMail;
294                         while( node ) {
295                                 /* g_print( "\tname-m::%s::\n", node->data ); */
296                                 addrcindex_add_entry( index, node->data, email );
297                                 node = g_slist_next( node );
298                         }
299                         /* ... and all person's name entries */
300                         node = uniqName;
301                         while( node ) {
302                                 /* g_print( "\tname-p::%s::\n", node->data ); */
303                                 addrcindex_add_entry( index, node->data, email );
304                                 node = g_slist_next( node );
305                         }
306                         g_slist_free( listMail );
307                 }
308                 listEMail = g_list_next( listEMail );
309         }
310
311         /* Free up the list */
312         g_slist_free( uniqName );
313 }
314
315 /*
316 * Print index to stream.
317 * Enter: index  Index.
318 *        stream Output stream.
319 */
320 void addrcindex_print( AddrCacheIndex *index, FILE *stream ) {
321         GList *node;
322         AddrIndexEntry *entry;
323         ItemEMail *email;
324
325         g_return_if_fail( index != NULL );
326         fprintf( stream, "AddressSearchIndex:\n" );
327         node = index->addressList;
328         while( node ) {
329                 entry = node->data;
330                 email = entry->address;
331                 fprintf( stream, "\tname: '%s'\t'%s'\n", entry->name, email->address );
332                 node = g_list_next( node );
333         }
334 }
335
336 /*
337 * Perform search for specified search term.
338 * Enter: index  Completion index.
339 *        search Search string.
340 * Return: List of references to ItemEMail objects meeting search criteria. The
341 *         list should be g_list_free() when no longer required.
342 */
343 GList *addrcindex_search( AddrCacheIndex *index, const gchar *search ) {
344         AddrIndexEntry *entry;
345         gchar *prefix;
346         GList *list;
347         GList *node;
348         GList *listEMail;
349
350         g_return_if_fail( index != NULL );
351         g_return_if_fail( search != NULL );
352
353         listEMail = NULL;
354         if( index->addressList != NULL ) { 
355                 /* Add items to list */
356                 g_completion_add_items( index->completion, index->addressList );
357
358                 /* Perform the search */
359                 prefix = g_strdup( search );
360                 g_strdown( prefix );
361                 list = g_completion_complete( index->completion, prefix, NULL );
362                 g_free( prefix );
363
364                 /* Build list of unique EMail objects */
365                 node = list;
366                 while( node ) {
367                         entry = node->data;
368                         /* g_print( "\tname ::%s::\n", entry->name ); */
369                         if( NULL == g_list_find( listEMail, entry->address ) ) {
370                                 listEMail = g_list_append(
371                                                 listEMail, entry->address );
372                         }
373                         node = g_list_next( node );
374                 }
375         }
376
377         return listEMail;
378 }
379
380 /*
381 * End of Source.
382 */