2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001 Match Grun
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 2 of the License, or
8 * (at your option) any later version.
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.
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 02111-1307, USA.
21 * Functions necessary to access JPilot database files.
22 * JPilot is Copyright(c) by Judd Montgomery.
23 * Visit http://www.jpilot.org for more details.
38 #include <pi-appinfo.h>
39 #include <pi-address.h>
43 #include "addrcache.h"
46 #define JPILOT_DBHOME_DIR ".jpilot"
47 #define JPILOT_DBHOME_FILE "AddressDB.pdb"
48 #define PILOT_LINK_LIB_NAME "libpisock.so"
50 #define IND_LABEL_LASTNAME 0 // Index of last name in address data
51 #define IND_LABEL_FIRSTNAME 1 // Index of first name in address data
52 #define IND_PHONE_EMAIL 4 // Index of E-Mail address in phone labels
53 #define OFFSET_PHONE_LABEL 3 // Offset to phone data in address data
54 #define IND_CUSTOM_LABEL 14 // Offset to custom label names
55 #define NUM_CUSTOM_LABEL 4 // Number of custom labels
57 // Shamelessly copied from JPilot (libplugin.h)
59 unsigned char db_name[32];
60 unsigned char flags[2];
61 unsigned char version[2];
62 unsigned char creation_time[4];
63 unsigned char modification_time[4];
64 unsigned char backup_time[4];
65 unsigned char modification_number[4];
66 unsigned char app_info_offset[4];
67 unsigned char sort_info_offset[4];
68 unsigned char type[4];/*Database ID */
69 unsigned char creator_id[4];/*Application ID */
70 unsigned char unique_id_seed[4];
71 unsigned char next_record_list_id[4];
72 unsigned char number_of_records[2];
75 // Shamelessly copied from JPilot (libplugin.h)
81 time_t modification_time;
83 unsigned int modification_number;
84 unsigned int app_info_offset;
85 unsigned int sort_info_offset;
86 char type[5];/*Database ID */
87 char creator_id[5];/*Application ID */
88 char unique_id_seed[5];
89 unsigned int next_record_list_id;
90 unsigned int number_of_records;
93 // Shamelessly copied from JPilot (libplugin.h)
95 unsigned char Offset[4]; /*4 bytes offset from BOF to record */
97 unsigned char unique_ID[3];
100 // Shamelessly copied from JPilot (libplugin.h)
101 typedef struct mem_rec_header_s {
102 unsigned int rec_num;
104 unsigned int unique_id;
105 unsigned char attrib;
106 struct mem_rec_header_s *next;
109 // Shamelessly copied from JPilot (libplugin.h)
110 #define SPENT_PC_RECORD_BIT 256
114 MODIFIED_PALM_REC = 101L,
115 DELETED_PALM_REC = 102L,
117 DELETED_PC_REC = SPENT_PC_RECORD_BIT + 104L,
118 DELETED_DELETED_PALM_REC = SPENT_PC_RECORD_BIT + 105L
121 // Shamelessly copied from JPilot (libplugin.h)
124 unsigned int unique_id;
125 unsigned char attrib;
131 * Create new pilot file object.
133 JPilotFile *jpilot_create() {
134 JPilotFile *pilotFile;
135 pilotFile = g_new0( JPilotFile, 1 );
136 pilotFile->name = NULL;
137 pilotFile->file = NULL;
138 pilotFile->path = NULL;
139 pilotFile->addressCache = addrcache_create();
140 pilotFile->readMetadata = FALSE;
141 pilotFile->customLabels = NULL;
142 pilotFile->labelInd = NULL;
143 pilotFile->retVal = MGU_SUCCESS;
144 pilotFile->accessFlag = FALSE;
149 * Create new pilot file object for specified file.
151 JPilotFile *jpilot_create_path( const gchar *path ) {
152 JPilotFile *pilotFile;
153 pilotFile = jpilot_create();
154 jpilot_set_file( pilotFile, path );
161 void jpilot_set_name( JPilotFile* pilotFile, const gchar *value ) {
162 g_return_if_fail( pilotFile != NULL );
163 pilotFile->name = mgu_replace_string( pilotFile->name, value );
165 void jpilot_set_file( JPilotFile* pilotFile, const gchar *value ) {
166 g_return_if_fail( pilotFile != NULL );
167 addrcache_refresh( pilotFile->addressCache );
168 pilotFile->readMetadata = FALSE;
169 pilotFile->path = mgu_replace_string( pilotFile->path, value );
171 void jpilot_set_accessed( JPilotFile *pilotFile, const gboolean value ) {
172 g_return_if_fail( pilotFile != NULL );
173 pilotFile->accessFlag = value;
176 gint jpilot_get_status( JPilotFile *pilotFile ) {
177 g_return_if_fail( pilotFile != NULL );
178 return pilotFile->retVal;
180 ItemFolder *jpilot_get_root_folder( JPilotFile *pilotFile ) {
181 g_return_if_fail( pilotFile != NULL );
182 return addrcache_get_root_folder( pilotFile->addressCache );
184 gchar *jpilot_get_name( JPilotFile *pilotFile ) {
185 g_return_if_fail( pilotFile != NULL );
186 return pilotFile->name;
190 * Test whether file was modified since last access.
191 * Return: TRUE if file was modified.
193 gboolean jpilot_get_modified( JPilotFile *pilotFile ) {
194 g_return_if_fail( pilotFile != NULL );
195 return addrcache_check_file( pilotFile->addressCache, pilotFile->path );
197 gboolean jpilot_get_accessed( JPilotFile *pilotFile ) {
198 g_return_if_fail( pilotFile != NULL );
199 return pilotFile->accessFlag;
203 * Test whether file was read.
204 * Return: TRUE if file was read.
206 gboolean jpilot_get_read_flag( JPilotFile *pilotFile ) {
207 g_return_if_fail( pilotFile != NULL );
208 return pilotFile->addressCache->dataRead;
212 * Free up custom label list.
214 void jpilot_clear_custom_labels( JPilotFile *pilotFile ) {
216 g_return_if_fail( pilotFile != NULL );
218 // Release custom labels
219 mgu_free_dlist( pilotFile->customLabels );
220 pilotFile->customLabels = NULL;
223 node = pilotFile->labelInd;
226 node = g_list_next( node );
228 g_list_free( pilotFile->labelInd );
229 pilotFile->labelInd = NULL;
231 // Force a fresh read
232 addrcache_refresh( pilotFile->addressCache );
236 * Append a custom label, representing an E-Mail address field to the
239 void jpilot_add_custom_label( JPilotFile *pilotFile, const gchar *labelName ) {
240 g_return_if_fail( pilotFile != NULL );
243 gchar *labelCopy = g_strdup( labelName );
244 g_strstrip( labelCopy );
245 if( *labelCopy == '\0' ) {
249 pilotFile->customLabels = g_list_append( pilotFile->customLabels, labelCopy );
250 // Force a fresh read
251 addrcache_refresh( pilotFile->addressCache );
257 * Get list of custom labels.
258 * Return: List of labels. Must use g_free() when done.
260 GList *jpilot_get_custom_labels( JPilotFile *pilotFile ) {
261 GList *retVal = NULL;
263 g_return_if_fail( pilotFile != NULL );
264 node = pilotFile->customLabels;
266 retVal = g_list_append( retVal, g_strdup( node->data ) );
267 node = g_list_next( node );
273 * Free up pilot file object by releasing internal memory.
275 void jpilot_free( JPilotFile *pilotFile ) {
276 g_return_if_fail( pilotFile != NULL );
278 /* Free internal stuff */
279 g_free( pilotFile->path );
281 // Release custom labels
282 jpilot_clear_custom_labels( pilotFile );
285 addrcache_clear( pilotFile->addressCache );
286 addrcache_free( pilotFile->addressCache );
287 pilotFile->addressCache = NULL;
288 pilotFile->readMetadata = FALSE;
289 pilotFile->accessFlag = FALSE;
291 /* Now release file object */
296 * Refresh internal variables to force a file read.
298 void jpilot_force_refresh( JPilotFile *pilotFile ) {
299 addrcache_refresh( pilotFile->addressCache );
303 * Print object to specified stream.
305 void jpilot_print_file( JPilotFile *pilotFile, FILE *stream ) {
307 g_return_if_fail( pilotFile != NULL );
308 fprintf( stream, "JPilotFile:\n" );
309 fprintf( stream, "file spec: '%s'\n", pilotFile->path );
310 fprintf( stream, " metadata: %s\n", pilotFile->readMetadata ? "yes" : "no" );
311 fprintf( stream, " ret val: %d\n", pilotFile->retVal );
313 node = pilotFile->customLabels;
315 fprintf( stream, " c label: %s\n", node->data );
316 node = g_list_next( node );
319 node = pilotFile->labelInd;
321 fprintf( stream, " labelind: %d\n", GPOINTER_TO_INT(node->data) );
322 node = g_list_next( node );
325 addrcache_print( pilotFile->addressCache, stream );
326 addritem_print_item_folder( pilotFile->addressCache->rootFolder, stream );
330 * Print summary of object to specified stream.
332 void jpilot_print_short( JPilotFile *pilotFile, FILE *stream ) {
334 g_return_if_fail( pilotFile != NULL );
335 fprintf( stream, "JPilotFile:\n" );
336 fprintf( stream, "file spec: '%s'\n", pilotFile->path );
337 fprintf( stream, " metadata: %s\n", pilotFile->readMetadata ? "yes" : "no" );
338 fprintf( stream, " ret val: %d\n", pilotFile->retVal );
340 node = pilotFile->customLabels;
342 fprintf( stream, " c label: %s\n", node->data );
343 node = g_list_next( node );
346 node = pilotFile->labelInd;
348 fprintf( stream, " labelind: %d\n", GPOINTER_TO_INT(node->data) );
349 node = g_list_next( node );
351 addrcache_print( pilotFile->addressCache, stream );
354 // Shamelessly copied from JPilot (libplugin.c)
355 static unsigned int bytes_to_bin(unsigned char *bytes, unsigned int num_bytes) {
358 for (i=0;i<num_bytes;i++) {
364 // Shamelessly copied from JPilot (utils.c)
365 /*These next 2 functions were copied from pi-file.c in the pilot-link app */
366 /* Exact value of "Jan 1, 1970 0:00:00 GMT" - "Jan 1, 1904 0:00:00 GMT" */
367 #define PILOT_TIME_DELTA (unsigned)(2082844800)
369 time_t pilot_time_to_unix_time ( unsigned long raw_time ) {
370 return (time_t)(raw_time - PILOT_TIME_DELTA);
373 // Shamelessly copied from JPilot (libplugin.c)
374 static int raw_header_to_header(RawDBHeader *rdbh, DBHeader *dbh) {
376 strncpy(dbh->db_name, rdbh->db_name, 31);
377 dbh->db_name[31] = '\0';
378 dbh->flags = bytes_to_bin(rdbh->flags, 2);
379 dbh->version = bytes_to_bin(rdbh->version, 2);
380 temp = bytes_to_bin(rdbh->creation_time, 4);
381 dbh->creation_time = pilot_time_to_unix_time(temp);
382 temp = bytes_to_bin(rdbh->modification_time, 4);
383 dbh->modification_time = pilot_time_to_unix_time(temp);
384 temp = bytes_to_bin(rdbh->backup_time, 4);
385 dbh->backup_time = pilot_time_to_unix_time(temp);
386 dbh->modification_number = bytes_to_bin(rdbh->modification_number, 4);
387 dbh->app_info_offset = bytes_to_bin(rdbh->app_info_offset, 4);
388 dbh->sort_info_offset = bytes_to_bin(rdbh->sort_info_offset, 4);
389 strncpy(dbh->type, rdbh->type, 4);
391 strncpy(dbh->creator_id, rdbh->creator_id, 4);
392 dbh->creator_id[4] = '\0';
393 strncpy(dbh->unique_id_seed, rdbh->unique_id_seed, 4);
394 dbh->unique_id_seed[4] = '\0';
395 dbh->next_record_list_id = bytes_to_bin(rdbh->next_record_list_id, 4);
396 dbh->number_of_records = bytes_to_bin(rdbh->number_of_records, 2);
400 // Shamelessly copied from JPilot (libplugin.c)
401 /*returns 1 if found */
403 static int find_next_offset( mem_rec_header *mem_rh, long fpos,
404 unsigned int *next_offset, unsigned char *attrib, unsigned int *unique_id )
406 mem_rec_header *temp_mem_rh;
407 unsigned char found = 0;
408 unsigned long found_at;
411 for (temp_mem_rh=mem_rh; temp_mem_rh; temp_mem_rh = temp_mem_rh->next) {
412 if ((temp_mem_rh->offset > fpos) && (temp_mem_rh->offset < found_at)) {
413 found_at = temp_mem_rh->offset;
414 /* *attrib = temp_mem_rh->attrib; */
415 /* *unique_id = temp_mem_rh->unique_id; */
417 if ((temp_mem_rh->offset == fpos)) {
419 *attrib = temp_mem_rh->attrib;
420 *unique_id = temp_mem_rh->unique_id;
423 *next_offset = found_at;
427 // Shamelessly copied from JPilot (libplugin.c)
428 static void free_mem_rec_header(mem_rec_header **mem_rh) {
429 mem_rec_header *h, *next_h;
430 for (h=*mem_rh; h; h=next_h) {
437 // Shamelessly copied from JPilot (libplugin.c)
438 static int jpilot_free_db_list( GList **br_list ) {
439 GList *temp_list, *first;
442 /* Go to first entry in the list */
444 for( temp_list = *br_list; temp_list; temp_list = temp_list->prev ) {
447 for (temp_list = first; temp_list; temp_list = temp_list->next) {
448 if (temp_list->data) {
452 temp_list->data=NULL;
457 g_list_free(*br_list);
462 // Shamelessly copied from JPilot (libplugin.c)
464 static int jpilot_get_info_size( FILE *in, int *size ) {
470 fseek(in, 0, SEEK_SET);
471 fread(&rdbh, sizeof(RawDBHeader), 1, in);
473 // fprintf( stderr, "error reading file in 'jpilot_get_info_size'\n" );
477 raw_header_to_header(&rdbh, &dbh);
478 if (dbh.app_info_offset==0) {
482 if (dbh.sort_info_offset!=0) {
483 *size = dbh.sort_info_offset - dbh.app_info_offset;
486 if (dbh.number_of_records==0) {
487 fseek(in, 0, SEEK_END);
488 *size=ftell(in) - dbh.app_info_offset;
492 fread(&rh, sizeof(record_header), 1, in);
493 offset = ((rh.Offset[0]*256+rh.Offset[1])*256+rh.Offset[2])*256+rh.Offset[3];
494 *size=offset - dbh.app_info_offset;
499 // Read address file into address list. Based on JPilot's
500 // libplugin.c (jp_get_app_info)
501 static gint jpilot_get_file_info( JPilotFile *pilotFile, unsigned char **buf, int *buf_size ) {
504 unsigned int rec_size;
508 if( ( !buf_size ) || ( ! buf ) ) {
515 if( pilotFile->path ) {
516 in = fopen( pilotFile->path, "r" );
518 // fprintf( stderr, "can't open %s\n", pilotFile->path );
519 return MGU_OPEN_FILE;
523 // fprintf( stderr, "file not specified\n" );
527 num = fread( &rdbh, sizeof( RawDBHeader ), 1, in );
530 // fprintf( stderr, "error reading %s\n", pilotFile->path );
532 return MGU_ERROR_READ;
540 // Convert header into something recognizable
541 raw_header_to_header(&rdbh, &dbh);
543 num = jpilot_get_info_size(in, &rec_size);
546 return MGU_ERROR_READ;
549 fseek(in, dbh.app_info_offset, SEEK_SET);
550 *buf = ( char * ) malloc(rec_size);
552 // fprintf( stderr, "jpilot_get_file_info(): Out of memory\n" );
554 return MGU_OO_MEMORY;
556 num = fread(*buf, rec_size, 1, in);
561 // fprintf( stderr, "Error reading %s\n", pilotFile->path );
562 return MGU_ERROR_READ;
567 *buf_size = rec_size;
572 #define FULLNAME_BUFSIZE 256
573 #define EMAIL_BUFSIZE 256
574 // Read address file into address cache. Based on JPilot's
575 // jp_read_DB_files (from libplugin.c)
576 static gint jpilot_read_file( JPilotFile *pilotFile ) {
579 int num_records, recs_returned, i, num, r;
580 unsigned int offset, prev_offset, next_offset, rec_size;
582 long fpos; /*file position indicator */
583 unsigned char attrib;
584 unsigned int unique_id;
586 mem_rec_header *mem_rh, *temp_mem_rh, *last_mem_rh;
592 struct AddressAppInfo *ai;
595 gchar fullName[ FULLNAME_BUFSIZE ];
596 gchar bufEMail[ EMAIL_BUFSIZE ];
603 ItemFolder *folderInd[ JPILOT_NUM_CATEG ];
605 retVal = MGU_SUCCESS;
606 mem_rh = last_mem_rh = NULL;
609 // Pointer to address metadata.
610 ai = & pilotFile->addrInfo;
612 // Open file for read
613 if( pilotFile->path ) {
614 in = fopen( pilotFile->path, "r" );
616 // fprintf( stderr, "can't open %s\n", pilotFile->path );
617 return MGU_OPEN_FILE;
621 // fprintf( stderr, "file not specified\n" );
625 /* Read the database header */
626 num = fread(&rdbh, sizeof(RawDBHeader), 1, in);
629 // fprintf( stderr, "error reading '%s'\n", pilotFile->path );
631 return MGU_ERROR_READ;
638 raw_header_to_header(&rdbh, &dbh);
640 /*Read each record entry header */
641 num_records = dbh.number_of_records;
645 for (i=1; i<num_records+1; i++) {
646 num = fread( &rh, sizeof( record_header ), 1, in );
649 // fprintf( stderr, "error reading '%s'\n", pilotFile->path );
650 retVal = MGU_ERROR_READ;
658 offset = ((rh.Offset[0]*256+rh.Offset[1])*256+rh.Offset[2])*256+rh.Offset[3];
659 if (offset < prev_offset) {
662 prev_offset = offset;
664 temp_mem_rh = (mem_rec_header *)malloc(sizeof(mem_rec_header));
666 // fprintf( stderr, "jpilot_read_db_file(): Out of memory 1\n" );
667 retVal = MGU_OO_MEMORY;
671 temp_mem_rh->next = NULL;
672 temp_mem_rh->rec_num = i;
673 temp_mem_rh->offset = offset;
674 temp_mem_rh->attrib = rh.attrib;
675 temp_mem_rh->unique_id = (rh.unique_ID[0]*256+rh.unique_ID[1])*256+rh.unique_ID[2];
677 if (mem_rh == NULL) {
678 mem_rh = temp_mem_rh;
679 last_mem_rh = temp_mem_rh;
682 last_mem_rh->next = temp_mem_rh;
683 last_mem_rh = temp_mem_rh;
688 temp_mem_rh = mem_rh;
692 find_next_offset(mem_rh, 0, &next_offset, &attrib, &unique_id);
696 next_offset = mem_rh->offset;
697 attrib = mem_rh->attrib;
698 unique_id = mem_rh->unique_id;
701 fseek(in, next_offset, SEEK_SET);
703 // Build array of pointers to categories;
705 node = addrcache_get_list_folder( pilotFile->addressCache );
707 if( i < JPILOT_NUM_CATEG ) {
708 folderInd[i] = node->data;
710 node = g_list_next( node );
714 // Now go load all records
716 struct CategoryAppInfo *cat = & ai->category;
719 find_next_offset(mem_rh, fpos, &next_offset, &attrib, &unique_id);
722 next_offset = 0xFFFFFF;
724 attrib = temp_mem_rh->attrib;
725 unique_id = temp_mem_rh->unique_id;
726 cat_id = attrib & 0x0F;
727 if (temp_mem_rh->next) {
728 temp_mem_rh = temp_mem_rh->next;
729 next_offset = temp_mem_rh->offset;
733 rec_size = next_offset - fpos;
735 buf = ( char * ) malloc(rec_size);
737 num = fread(buf, rec_size, 1, in);
740 // fprintf( stderr, "Error reading %s 5\n", pilotFile );
742 retVal = MGU_ERROR_READ;
748 inum = unpack_Address( & addr, buf, rec_size );
750 addrEnt = addr.entry;
752 *fullName = *bufEMail = '\0';
753 if( addrEnt[ IND_LABEL_FIRSTNAME ] ) {
754 strcat( fullName, addrEnt[ IND_LABEL_FIRSTNAME ] );
757 if( addrEnt[ IND_LABEL_LASTNAME ] ) {
758 strcat( fullName, " " );
759 strcat( fullName, addrEnt[ IND_LABEL_LASTNAME ] );
761 g_strchug( fullName );
762 g_strchomp( fullName );
764 person = addritem_create_item_person();
765 addritem_person_set_common_name( person, fullName );
766 addritem_person_set_first_name( person, addrEnt[ IND_LABEL_FIRSTNAME ] );
767 addritem_person_set_last_name( person, addrEnt[ IND_LABEL_LASTNAME ] );
768 addrcache_id_person( pilotFile->addressCache, person );
770 extID = g_strdup_printf( "%d", unique_id );
771 addritem_person_set_external_id( person, extID );
775 // Add entry for each email address listed under phone labels.
776 indPhoneLbl = addr.phoneLabel;
777 for( k = 0; k < JPILOT_NUM_ADDR_PHONE; k++ ) {
779 ind = indPhoneLbl[k];
781 fprintf( stdout, "%d : %d : %20s : %s\n", k, ind,
782 ai->phoneLabels[ind], addrEnt[3+k] );
784 if( indPhoneLbl[k] == IND_PHONE_EMAIL ) {
785 labelEntry = addrEnt[ OFFSET_PHONE_LABEL + k ];
787 strcpy( bufEMail, labelEntry );
788 g_strchug( bufEMail );
789 g_strchomp( bufEMail );
791 email = addritem_create_item_email();
792 addritem_email_set_address( email, bufEMail );
793 addrcache_id_email( pilotFile->addressCache, email );
794 addrcache_person_add_email(
795 pilotFile->addressCache, person, email );
800 // Add entry for each custom label
801 node = pilotFile->labelInd;
804 ind = GPOINTER_TO_INT( node->data );
807 fprintf( stdout, "%d : %20s : %s\n", ind, ai->labels[ind],
810 labelEntry = addrEnt[ind];
812 strcpy( bufEMail, labelEntry );
813 g_strchug( bufEMail );
814 g_strchomp( bufEMail );
816 email = addritem_create_item_email();
817 addritem_email_set_address( email, bufEMail );
818 addritem_email_set_remarks( email, ai->labels[ind] );
819 addrcache_id_email( pilotFile->addressCache, email );
820 addrcache_person_add_email(
821 pilotFile->addressCache, person, email );
826 node = g_list_next( node );
829 if( person->listEMail ) {
830 if( cat_id > -1 && cat_id < JPILOT_NUM_CATEG ) {
831 // Add to specified category
832 addrcache_folder_add_person(
833 pilotFile->addressCache, folderInd[cat_id], person );
836 // Add to root folder
837 addrcache_add_person( pilotFile->addressCache, person );
841 addritem_free_item_person( person );
850 free_mem_rec_header(&mem_rh);
855 * Read metadata from file.
857 static gint jpilot_read_metadata( JPilotFile *pilotFile ) {
859 unsigned int rec_size;
863 g_return_if_fail( pilotFile != NULL );
865 pilotFile->readMetadata = FALSE;
866 addrcache_clear( pilotFile->addressCache );
869 retVal = jpilot_get_file_info( pilotFile, &buf, &rec_size);
870 if( retVal != MGU_SUCCESS ) {
871 pilotFile->retVal = retVal;
872 return pilotFile->retVal;
875 num = unpack_AddressAppInfo( &pilotFile->addrInfo, buf, rec_size );
880 // fprintf( stderr, "error reading '%s'\n", pilotFile->path );
881 pilotFile->retVal = MGU_ERROR_READ;
882 return pilotFile->retVal;
885 pilotFile->readMetadata = TRUE;
886 pilotFile->retVal = MGU_SUCCESS;
887 return pilotFile->retVal;
891 * Setup labels and indexes from metadata.
892 * Return: TRUE is setup successfully.
894 static gboolean jpilot_setup_labels( JPilotFile *pilotFile ) {
895 gboolean retVal = FALSE;
896 struct AddressAppInfo *ai;
899 g_return_if_fail( pilotFile != NULL );
902 node = pilotFile->labelInd;
905 node = g_list_next( node );
907 pilotFile->labelInd = NULL;
909 if( pilotFile->readMetadata ) {
910 ai = & pilotFile->addrInfo;
911 node = pilotFile->customLabels;
913 gchar *lbl = node->data;
916 for( i = 0; i < JPILOT_NUM_LABELS; i++ ) {
917 gchar *labelName = ai->labels[i];
918 if( g_strcasecmp( labelName, lbl ) == 0 ) {
923 pilotFile->labelInd = g_list_append( pilotFile->labelInd, GINT_TO_POINTER(ind) );
924 node = g_list_next( node );
932 * Load list with character strings of label names.
934 GList *jpilot_load_label( JPilotFile *pilotFile, GList *labelList ) {
936 g_return_if_fail( pilotFile != NULL );
937 if( pilotFile->readMetadata ) {
938 struct AddressAppInfo *ai = & pilotFile->addrInfo;
939 for( i = 0; i < JPILOT_NUM_LABELS; i++ ) {
940 gchar *labelName = ai->labels[i];
942 labelList = g_list_append( labelList, g_strdup( labelName ) );
945 labelList = g_list_append( labelList, g_strdup( "" ) );
953 * Return category name for specified category ID.
954 * Enter: Category ID.
955 * Return: Name, or empty string if not invalid ID. Name should be g_free() when done.
957 gchar *jpilot_get_category_name( JPilotFile *pilotFile, gint catID ) {
958 gchar *catName = NULL;
959 g_return_if_fail( pilotFile != NULL );
960 if( pilotFile->readMetadata ) {
961 struct AddressAppInfo *ai = & pilotFile->addrInfo;
962 struct CategoryAppInfo *cat = & ai->category;
963 if( catID < 0 || catID > JPILOT_NUM_CATEG ) {
966 catName = g_strdup( cat->name[catID] );
969 if( ! catName ) catName = g_strdup( "" );
974 * Load list with character strings of phone label names.
976 GList *jpilot_load_phone_label( JPilotFile *pilotFile, GList *labelList ) {
978 g_return_if_fail( pilotFile != NULL );
979 if( pilotFile->readMetadata ) {
980 struct AddressAppInfo *ai = & pilotFile->addrInfo;
981 for( i = 0; i < JPILOT_NUM_PHONELABELS; i++ ) {
982 gchar *labelName = ai->phoneLabels[i];
984 labelList = g_list_append( labelList, g_strdup( labelName ) );
987 labelList = g_list_append( labelList, g_strdup( "" ) );
995 * Load list with character strings of label names. Only none blank names
998 GList *jpilot_load_custom_label( JPilotFile *pilotFile, GList *labelList ) {
1000 g_return_if_fail( pilotFile != NULL );
1002 if( pilotFile->readMetadata ) {
1003 struct AddressAppInfo *ai = & pilotFile->addrInfo;
1004 for( i = 0; i < NUM_CUSTOM_LABEL; i++ ) {
1005 gchar *labelName = ai->labels[i+IND_CUSTOM_LABEL];
1007 g_strchomp( labelName );
1008 g_strchug( labelName );
1009 if( *labelName != '\0' ) {
1010 labelList = g_list_append( labelList, g_strdup( labelName ) );
1019 * Load list with character strings of category names.
1021 GList *jpilot_get_category_list( JPilotFile *pilotFile ) {
1022 GList *catList = NULL;
1024 g_return_if_fail( pilotFile != NULL );
1025 if( pilotFile->readMetadata ) {
1026 struct AddressAppInfo *ai = & pilotFile->addrInfo;
1027 struct CategoryAppInfo *cat = & ai->category;
1028 for( i = 0; i < JPILOT_NUM_CATEG; i++ ) {
1029 gchar *catName = cat->name[i];
1031 catList = g_list_append( catList, g_strdup( catName ) );
1034 catList = g_list_append( catList, g_strdup( "" ) );
1042 * Build folder for each category.
1044 static void jpilot_build_category_list( JPilotFile *pilotFile ) {
1045 struct AddressAppInfo *ai = & pilotFile->addrInfo;
1046 struct CategoryAppInfo *cat = & ai->category;
1048 for( i = 0; i < JPILOT_NUM_CATEG; i++ ) {
1049 ItemFolder *folder = addritem_create_item_folder();
1050 addritem_folder_set_name( folder, cat->name[i] );
1051 addrcache_id_folder( pilotFile->addressCache, folder );
1052 addrcache_add_folder( pilotFile->addressCache, folder );
1057 * Remove empty folders (categories).
1059 static void jpilot_remove_empty( JPilotFile *pilotFile ) {
1065 listFolder = addrcache_get_list_folder( pilotFile->addressCache );
1069 ItemFolder *folder = node->data;
1070 if( ADDRITEM_NAME(folder) == NULL || *ADDRITEM_NAME(folder) == '\0' ) {
1071 if( folder->listPerson ) {
1072 // Give name to folder
1074 sprintf( name, "? %d", i );
1075 addritem_folder_set_name( folder, name );
1079 remList = g_list_append( remList, folder );
1082 node = g_list_next( node );
1087 ItemFolder *folder = node->data;
1088 addrcache_remove_folder( pilotFile->addressCache, folder );
1089 node = g_list_next( node );
1091 g_list_free( remList );
1094 // ============================================================================================
1096 * Read file into list. Main entry point
1097 * Return: TRUE if file read successfully.
1099 // ============================================================================================
1100 gint jpilot_read_data( JPilotFile *pilotFile ) {
1101 g_return_if_fail( pilotFile != NULL );
1102 pilotFile->retVal = MGU_SUCCESS;
1103 pilotFile->accessFlag = FALSE;
1104 if( addrcache_check_file( pilotFile->addressCache, pilotFile->path ) ) {
1105 addrcache_clear( pilotFile->addressCache );
1106 jpilot_read_metadata( pilotFile );
1107 if( pilotFile->retVal == MGU_SUCCESS ) {
1108 jpilot_setup_labels( pilotFile );
1109 jpilot_build_category_list( pilotFile );
1110 pilotFile->retVal = jpilot_read_file( pilotFile );
1111 if( pilotFile->retVal == MGU_SUCCESS ) {
1112 jpilot_remove_empty( pilotFile );
1113 addrcache_mark_file( pilotFile->addressCache, pilotFile->path );
1114 pilotFile->addressCache->modified = FALSE;
1115 pilotFile->addressCache->dataRead = TRUE;
1119 return pilotFile->retVal;
1123 * Return link list of persons.
1125 GList *jpilot_get_list_person( JPilotFile *pilotFile ) {
1126 g_return_if_fail( pilotFile != NULL );
1127 return addrcache_get_list_person( pilotFile->addressCache );
1131 * Return link list of folders. This is always NULL since there are
1132 * no folders in GnomeCard.
1135 GList *jpilot_get_list_folder( JPilotFile *pilotFile ) {
1136 g_return_if_fail( pilotFile != NULL );
1137 return addrcache_get_list_folder( pilotFile->addressCache );
1141 * Return link list of all persons. Note that the list contains references
1142 * to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
1143 * this will destroy the addressbook data!
1144 * Return: List of items, or NULL if none.
1146 GList *jpilot_get_all_persons( JPilotFile *pilotFile ) {
1147 g_return_if_fail( pilotFile != NULL );
1148 return addrcache_get_all_persons( pilotFile->addressCache );
1152 * Check label list for specified label.
1154 gint jpilot_check_label( struct AddressAppInfo *ai, gchar *lblCheck ) {
1157 if( lblCheck == NULL ) return -1;
1158 if( strlen( lblCheck ) < 1 ) return -1;
1159 for( i = 0; i < JPILOT_NUM_LABELS; i++ ) {
1160 lblName = ai->labels[i];
1162 if( strlen( lblName ) ) {
1163 if( g_strcasecmp( lblName, lblCheck ) == 0 ) return i;
1171 * Validate that all parameters specified.
1172 * Return: TRUE if data is good.
1174 gboolean jpilot_validate( const JPilotFile *pilotFile ) {
1176 g_return_if_fail( pilotFile != NULL );
1179 if( pilotFile->path ) {
1180 if( strlen( pilotFile->path ) < 1 ) retVal = FALSE;
1185 if( pilotFile->name ) {
1186 if( strlen( pilotFile->name ) < 1 ) retVal = FALSE;
1194 #define WORK_BUFLEN 1024
1197 * Attempt to find a valid JPilot file.
1198 * Return: Filename, or home directory if not found, or empty string if
1199 * no home. Filename should be g_free() when done.
1201 gchar *jpilot_find_pilotdb( void ) {
1203 gchar str[ WORK_BUFLEN ];
1207 homedir = g_get_home_dir();
1208 if( ! homedir ) return g_strdup( "" );
1210 strcpy( str, homedir );
1211 len = strlen( str );
1213 if( str[ len-1 ] != G_DIR_SEPARATOR ) {
1214 str[ len ] = G_DIR_SEPARATOR;
1215 str[ ++len ] = '\0';
1218 strcat( str, JPILOT_DBHOME_DIR );
1219 strcat( str, G_DIR_SEPARATOR_S );
1220 strcat( str, JPILOT_DBHOME_FILE );
1223 if( ( fp = fopen( str, "r" ) ) != NULL ) {
1227 // Truncate filename
1230 return g_strdup( str );
1234 * Attempt to read file, testing for valid JPilot format.
1235 * Return: TRUE if file appears to be valid format.
1237 gint jpilot_test_read_file( const gchar *fileSpec ) {
1238 JPilotFile *pilotFile;
1241 pilotFile = jpilot_create_path( fileSpec );
1242 retVal = jpilot_read_metadata( pilotFile );
1243 jpilot_free( pilotFile );
1247 retVal = MGU_NO_FILE;
1253 * Check whether label is in custom labels.
1254 * Return: TRUE if found.
1256 gboolean jpilot_test_custom_label( JPilotFile *pilotFile, const gchar *labelName ) {
1259 g_return_if_fail( pilotFile != NULL );
1263 node = pilotFile->customLabels;
1265 if( g_strcasecmp( labelName, node->data ) == 0 ) {
1269 node = g_list_next( node );
1276 * Test whether pilot link library installed.
1277 * Return: TRUE if library available.
1279 gboolean jpilot_test_pilot_lib() {
1282 handle = dlopen( PILOT_LINK_LIB_NAME, RTLD_LAZY );
1287 // Test for symbols we need
1288 fun = dlsym( handle, "unpack_Address" );
1294 fun = dlsym( handle, "unpack_AddressAppInfo" );
1303 #endif /* USE_JPILOT */