2010-09-12 [pawel] 3.7.6cvs34
[claws.git] / src / addrcindex.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2002-2009 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         cm_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         cm_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->address = email;
131         entry->name = g_utf8_strdown( name, -1 );
132         index->addressList = g_list_append( index->addressList, entry );
133 }
134
135 /*
136 * Add an email entry into index. The index will also include all name fields
137 * for the person.
138
139 * Add address into index.
140 * Enter: index Index.
141 *        email E-Mail to add.
142 */
143 void addrcindex_add_email( AddrCacheIndex *index, ItemEMail *email ) {
144         ItemPerson *person;
145         gchar *name;
146         GSList *uniqName;
147         GSList *node;
148         gboolean flag;
149
150         cm_return_if_fail( index != NULL );
151         cm_return_if_fail( email != NULL );
152
153         flag = FALSE;
154         uniqName = NULL;
155         name = ADDRITEM_NAME( email );
156         if( name != NULL ) {
157                 if( strlen( name ) > 0 ) {
158                         uniqName = g_slist_append( uniqName, name );
159                 }
160         }
161         name = email->address;
162         if( mgu_slist_test_unq_nc( uniqName, name ) ) {
163                 uniqName = g_slist_append( uniqName, name );
164         }
165         if( name ) {
166                 if( strlen( name ) > 0 ) flag = TRUE;
167         }
168
169         /* Bail if no email address */
170         if( ! flag ) {
171                 g_slist_free( uniqName );
172                 return;
173         }
174
175         person = ( ItemPerson * ) ADDRITEM_PARENT( email );
176         if( person != NULL ) {
177                 name = ADDRITEM_NAME( person );
178                 if( mgu_slist_test_unq_nc( uniqName, name ) ) {
179                         uniqName = g_slist_append( uniqName, name );
180                 }
181
182                 name = person->nickName;
183                 if( mgu_slist_test_unq_nc( uniqName, name ) ) {
184                         uniqName = g_slist_append( uniqName, name );
185                 }
186
187                 name = person->firstName;
188                 if( mgu_slist_test_unq_nc( uniqName, name ) ) {
189                         uniqName = g_slist_append( uniqName, name );
190                 }
191
192                 name = person->lastName;
193                 if( mgu_slist_test_unq_nc( uniqName, name ) ) {
194                         uniqName = g_slist_append( uniqName, name );
195                 }
196         }
197
198         /* Create a completion entry for each unique name */
199         node = uniqName;
200         while( node ) {
201                 addrcindex_add_entry( index, node->data, email );
202                 node = g_slist_next( node );
203         }
204         g_slist_free( uniqName );
205
206 }
207
208 /*
209  * Process email address entry, checking for unique alias and address. If the
210  * address field is empty, no entries will be generated.
211  * Enter: index Index.
212  *        uniqName List of unique names to examine.
213  *        email    EMail address item to process.
214  * Return: List of entries from email object to add to index.
215  */
216 static GSList *addrcindex_proc_mail(
217         AddrCacheIndex *index, GSList *uniqName, ItemEMail *email )
218 {
219         GSList *list;
220         gchar *name;
221
222         /* Test for address */
223         list = NULL;
224         name = email->address;
225         if( name ) {
226                 if( strlen( name ) > 0 ) {
227                         /* Address was supplied */
228                         /* Append alias if unique */
229                         name = ADDRITEM_NAME( email );
230                         if( mgu_slist_test_unq_nc( uniqName, name ) ) {
231                                 list = g_slist_append( list, name );
232                         }
233                         /* Then append the address if unique */
234                         /* Note is possible that the address has already */
235                         /* been entered into one of the name fields. */
236                         if( mgu_slist_test_unq_nc( uniqName, email->address ) ) {
237                                 list = g_slist_append( list, email->address );
238                         }
239                 }
240         }
241         return list;
242 }
243
244 /*
245 * Add person's address entries into index. Each email address is processed.
246 * If the address field has been supplied, entries will be made. The index
247 * will include the address, alias and all name fields for the person.
248
249 * Enter: index  Index.
250 *        person Person to add.
251 */
252 void addrcindex_add_person( AddrCacheIndex *index, ItemPerson *person ) {
253         gchar *name;
254         GSList *uniqName;
255         GSList *node;
256         GSList *listMail;
257         GList  *listEMail;
258         ItemEMail *email;
259
260         cm_return_if_fail( index != NULL );
261         cm_return_if_fail( person != NULL );
262
263         /* Build list of all unique names in person's name fields */
264         uniqName = NULL;
265         name = ADDRITEM_NAME( person );
266         if( mgu_slist_test_unq_nc( uniqName, name ) ) {
267                 uniqName = g_slist_append( uniqName, name );
268         }
269
270         name = person->nickName;
271         if( mgu_slist_test_unq_nc( uniqName, name ) ) {
272                 uniqName = g_slist_append( uniqName, name );
273         }
274
275         name = person->firstName;
276         if( mgu_slist_test_unq_nc( uniqName, name ) ) {
277                 uniqName = g_slist_append( uniqName, name );
278         }
279
280         name = person->lastName;
281         if( mgu_slist_test_unq_nc( uniqName, name ) ) {
282                 uniqName = g_slist_append( uniqName, name );
283         }
284
285         /* Process each email address entry */
286         listEMail = person->listEMail;
287         while( listEMail ) {
288                 email = listEMail->data;
289                 listMail = addrcindex_proc_mail( index, uniqName, email );
290                 if( listMail ) {
291                         /* Create a completion entry for the address item */
292                         node = listMail;
293                         while( node ) {
294                                 /* g_print( "\tname-m::%s::\n", node->data ); */
295                                 addrcindex_add_entry( index, node->data, email );
296                                 node = g_slist_next( node );
297                         }
298                         /* ... and all person's name entries */
299                         node = uniqName;
300                         while( node ) {
301                                 /* g_print( "\tname-p::%s::\n", node->data ); */
302                                 addrcindex_add_entry( index, node->data, email );
303                                 node = g_slist_next( node );
304                         }
305                         g_slist_free( listMail );
306                 }
307                 listEMail = g_list_next( listEMail );
308         }
309
310         /* Free up the list */
311         g_slist_free( uniqName );
312 }
313
314 /*
315 * Print index to stream.
316 * Enter: index  Index.
317 *        stream Output stream.
318 */
319 void addrcindex_print( AddrCacheIndex *index, FILE *stream ) {
320         GList *node;
321         AddrIndexEntry *entry;
322         ItemEMail *email;
323
324         cm_return_if_fail( index != NULL );
325         fprintf( stream, "AddressSearchIndex:\n" );
326         node = index->addressList;
327         while( node ) {
328                 entry = node->data;
329                 email = entry->address;
330                 fprintf( stream, "\tname: '%s'\t'%s'\n", entry->name, email->address );
331                 node = g_list_next( node );
332         }
333 }
334
335 /*
336 * Perform search for specified search term.
337 * Enter: index  Completion index.
338 *        search Search string.
339 * Return: List of references to ItemEMail objects meeting search criteria. The
340 *         list should be g_list_free() when no longer required.
341 */
342 GList *addrcindex_search( AddrCacheIndex *index, const gchar *search ) {
343         AddrIndexEntry *entry;
344         gchar *prefix;
345         GList *list;
346         GList *node;
347         GList *listEMail;
348
349         cm_return_if_fail( index != NULL );
350         cm_return_if_fail( search != NULL );
351
352         listEMail = NULL;
353         if( index->addressList != NULL ) { 
354                 /* Add items to list */
355                 g_completion_add_items( index->completion, index->addressList );
356
357                 /* Perform the search */
358                 prefix = g_utf8_strdown( search, -1 );
359                 list = g_completion_complete( index->completion, prefix, NULL );
360                 g_free( prefix );
361
362                 /* Build list of unique EMail objects */
363                 node = list;
364                 while( node ) {
365                         entry = node->data;
366                         /* g_print( "\tname ::%s::\n", entry->name ); */
367                         if( NULL == g_list_find( listEMail, entry->address ) ) {
368                                 listEMail = g_list_append(
369                                                 listEMail, entry->address );
370                         }
371                         node = g_list_next( node );
372                 }
373         }
374
375         return listEMail;
376 }
377
378 /*
379 * End of Source.
380 */