2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001-2006 Match Grun and the Claws Mail team
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 <netinet/in.h>
40 #ifdef HAVE_LIBPISOCK_PI_ARGS_H
41 # include <libpisock/pi-args.h>
42 # include <libpisock/pi-appinfo.h>
43 # include <libpisock/pi-address.h>
44 # include <libpisock/pi-version.h>
47 # include <pi-appinfo.h>
48 # include <pi-address.h>
49 # include <pi-version.h>
54 #include "addrcache.h"
57 #include "adbookbase.h"
60 #define JPILOT_DBHOME_DIR ".jpilot"
61 #define JPILOT_DBHOME_FILE "AddressDB.pdb"
62 #define PILOT_LINK_LIB_NAME "libpisock.so"
64 #define IND_LABEL_LASTNAME 0 /* Index of last name in address data */
65 #define IND_LABEL_FIRSTNAME 1 /* Index of first name in address data */
66 #define IND_PHONE_EMAIL 4 /* Index of E-Mail address in phone labels */
67 #define OFFSET_PHONE_LABEL 3 /* Offset to phone data in address data */
68 #define IND_CUSTOM_LABEL 14 /* Offset to custom label names */
69 #define NUM_CUSTOM_LABEL 4 /* Number of custom labels */
71 /* Shamelessly copied from JPilot (libplugin.h) */
73 unsigned char db_name
[32];
74 unsigned char flags
[2];
75 unsigned char version
[2];
76 unsigned char creation_time
[4];
77 unsigned char modification_time
[4];
78 unsigned char backup_time
[4];
79 unsigned char modification_number
[4];
80 unsigned char app_info_offset
[4];
81 unsigned char sort_info_offset
[4];
82 unsigned char type
[4];/*Database ID */
83 unsigned char creator_id
[4];/*Application ID */
84 unsigned char unique_id_seed
[4];
85 unsigned char next_record_list_id
[4];
86 unsigned char number_of_records
[2];
89 /* Shamelessly copied from JPilot (libplugin.h) */
95 time_t modification_time
;
97 unsigned int modification_number
;
98 unsigned int app_info_offset
;
99 unsigned int sort_info_offset
;
100 char type
[5];/*Database ID */
101 char creator_id
[5];/*Application ID */
102 char unique_id_seed
[5];
103 unsigned int next_record_list_id
;
104 unsigned int number_of_records
;
107 /* Shamelessly copied from JPilot (libplugin.h) */
109 unsigned char Offset
[4]; /*4 bytes offset from BOF to record */
110 unsigned char attrib
;
111 unsigned char unique_ID
[3];
114 /* Shamelessly copied from JPilot (libplugin.h) */
115 typedef struct mem_rec_header_s
{
116 unsigned int rec_num
;
118 unsigned int unique_id
;
119 unsigned char attrib
;
120 struct mem_rec_header_s
*next
;
123 /* Shamelessly copied from JPilot (libplugin.h) */
124 #define SPENT_PC_RECORD_BIT 256
128 MODIFIED_PALM_REC
= 101L,
129 DELETED_PALM_REC
= 102L,
131 DELETED_PC_REC
= SPENT_PC_RECORD_BIT
+ 104L,
132 DELETED_DELETED_PALM_REC
= SPENT_PC_RECORD_BIT
+ 105L
135 /* Shamelessly copied from JPilot (libplugin.h) */
138 unsigned int unique_id
;
139 unsigned char attrib
;
144 /* Shamelessly copied from JPilot (libplugin.h) */
146 unsigned long header_len
;
147 unsigned long header_version
;
148 unsigned long rec_len
;
149 unsigned long unique_id
;
150 unsigned long rt
; /* Record Type */
151 unsigned char attrib
;
159 gboolean convert_charcode
= TRUE
;
162 * Create new pilot file object.
163 * \return Initialized JPilot file object.
165 JPilotFile
*jpilot_create() {
166 JPilotFile
*pilotFile
;
167 pilotFile
= g_new0( JPilotFile
, 1 );
168 pilotFile
->type
= ADBOOKTYPE_JPILOT
;
169 pilotFile
->addressCache
= addrcache_create();
170 pilotFile
->retVal
= MGU_SUCCESS
;
172 pilotFile
->file
= NULL
;
173 pilotFile
->path
= NULL
;
174 pilotFile
->readMetadata
= FALSE
;
175 pilotFile
->customLabels
= NULL
;
176 pilotFile
->labelInd
= NULL
;
177 pilotFile
->havePC3
= FALSE
;
178 pilotFile
->pc3ModifyTime
= 0;
183 * Create new pilot file object for specified file.
184 * \param path Path to JPilot address book.
185 * \return Initialized JPilot file object.
187 JPilotFile
*jpilot_create_path( const gchar
*path
) {
188 JPilotFile
*pilotFile
;
189 pilotFile
= jpilot_create();
190 jpilot_set_file( pilotFile
, path
);
197 void jpilot_set_name( JPilotFile
* pilotFile
, const gchar
*value
) {
198 g_return_if_fail( pilotFile
!= NULL
);
199 addrcache_set_name( pilotFile
->addressCache
, value
);
201 void jpilot_set_file( JPilotFile
* pilotFile
, const gchar
*value
) {
202 g_return_if_fail( pilotFile
!= NULL
);
203 addrcache_refresh( pilotFile
->addressCache
);
204 pilotFile
->readMetadata
= FALSE
;
205 pilotFile
->path
= mgu_replace_string( pilotFile
->path
, value
);
207 void jpilot_set_accessed( JPilotFile
*pilotFile
, const gboolean value
) {
208 g_return_if_fail( pilotFile
!= NULL
);
209 pilotFile
->addressCache
->accessFlag
= value
;
212 gint
jpilot_get_status( JPilotFile
*pilotFile
) {
213 g_return_val_if_fail( pilotFile
!= NULL
, -1 );
214 return pilotFile
->retVal
;
216 ItemFolder
*jpilot_get_root_folder( JPilotFile
*pilotFile
) {
217 g_return_val_if_fail( pilotFile
!= NULL
, NULL
);
218 return addrcache_get_root_folder( pilotFile
->addressCache
);
220 gchar
*jpilot_get_name( JPilotFile
*pilotFile
) {
221 g_return_val_if_fail( pilotFile
!= NULL
, NULL
);
222 return addrcache_get_name( pilotFile
->addressCache
);
226 * Test whether file was read.
227 * \param pilotFile JPilot control data.
228 * \return <i>TRUE</i> if file was read.
230 gboolean
jpilot_get_read_flag( JPilotFile
*pilotFile
) {
231 g_return_val_if_fail( pilotFile
!= NULL
, FALSE
);
232 return pilotFile
->addressCache
->dataRead
;
236 * Free up custom label list.
237 * \param pilotFile JPilot control data.
239 void jpilot_clear_custom_labels( JPilotFile
*pilotFile
) {
242 g_return_if_fail( pilotFile
!= NULL
);
244 /* Release custom labels */
245 mgu_free_dlist( pilotFile
->customLabels
);
246 pilotFile
->customLabels
= NULL
;
248 /* Release indexes */
249 node
= pilotFile
->labelInd
;
252 node
= g_list_next( node
);
254 g_list_free( pilotFile
->labelInd
);
255 pilotFile
->labelInd
= NULL
;
257 /* Force a fresh read */
258 addrcache_refresh( pilotFile
->addressCache
);
262 * Append a custom label, representing an E-Mail address field to the
264 * \param pilotFile JPilot control data.
266 void jpilot_add_custom_label( JPilotFile
*pilotFile
, const gchar
*labelName
) {
267 g_return_if_fail( pilotFile
!= NULL
);
270 gchar
*labelCopy
= g_strdup( labelName
);
271 g_strstrip( labelCopy
);
272 if( *labelCopy
== '\0' ) {
276 pilotFile
->customLabels
= g_list_append( pilotFile
->customLabels
, labelCopy
);
277 /* Force a fresh read */
278 addrcache_refresh( pilotFile
->addressCache
);
284 * Get list of custom labels.
285 * \param pilotFile JPilot control data.
286 * \return List of labels. Must use g_free() when done.
288 GList
*jpilot_get_custom_labels( JPilotFile
*pilotFile
) {
289 GList
*retVal
= NULL
;
292 g_return_val_if_fail( pilotFile
!= NULL
, NULL
);
294 node
= pilotFile
->customLabels
;
296 retVal
= g_list_append( retVal
, g_strdup( node
->data
) );
297 node
= g_list_next( node
);
303 * Return filespec of PC3 file corresponding to JPilot PDB file.
304 * \param pilotFile JPilot control data.
305 * \return File specification; should be g_free() when done.
307 static gchar
*jpilot_get_pc3_file( JPilotFile
*pilotFile
) {
311 if( pilotFile
== NULL
) return NULL
;
312 if( pilotFile
->path
== NULL
) return NULL
;
314 fileSpec
= g_strdup( pilotFile
->path
);
315 len
= strlen( fileSpec
);
318 for( i
= len
; i
> 0; i
-- ) {
319 if( *(fileSpec
+ i
) == '.' ) {
326 if( len
- pos
== 3 ) {
327 *r
++ = 'p'; *r
++ = 'c'; *r
= '3';
336 * Save PC3 file time to cache.
337 * \param pilotFile JPilot control data.
338 * \return <i>TRUE</i> if time marked.
340 static gboolean
jpilot_mark_files( JPilotFile
*pilotFile
) {
341 gboolean retVal
= FALSE
;
342 struct stat filestat
;
345 /* Mark PDB file cache */
346 retVal
= addrcache_mark_file( pilotFile
->addressCache
, pilotFile
->path
);
348 /* Now mark PC3 file */
349 pilotFile
->havePC3
= FALSE
;
350 pilotFile
->pc3ModifyTime
= 0;
351 pcFile
= jpilot_get_pc3_file( pilotFile
);
352 if( pcFile
== NULL
) return retVal
;
353 if( 0 == stat( pcFile
, &filestat
) ) {
354 pilotFile
->havePC3
= TRUE
;
355 pilotFile
->pc3ModifyTime
= filestat
.st_mtime
;
363 * Check whether JPilot PDB or PC3 file has changed by comparing
365 * \param pilotFile JPilot control data.
366 * \return <i>TRUE</i> if file has changed.
368 static gboolean
jpilot_check_files( JPilotFile
*pilotFile
) {
369 gboolean retVal
= TRUE
;
370 struct stat filestat
;
373 /* Check main file */
374 if( addrcache_check_file( pilotFile
->addressCache
, pilotFile
->path
) )
378 if( ! pilotFile
->havePC3
) return FALSE
;
379 pcFile
= jpilot_get_pc3_file( pilotFile
);
380 if( pcFile
== NULL
) return FALSE
;
382 if( 0 == stat( pcFile
, &filestat
) ) {
383 if( filestat
.st_mtime
== pilotFile
->pc3ModifyTime
) retVal
= FALSE
;
390 * Test whether file was modified since last access.
391 * Return: TRUE if file was modified.
393 gboolean
jpilot_get_modified( JPilotFile
*pilotFile
) {
394 g_return_val_if_fail( pilotFile
!= NULL
, FALSE
);
395 pilotFile
->addressCache
->modified
= jpilot_check_files( pilotFile
);
396 return pilotFile
->addressCache
->modified
;
398 void jpilot_set_modified( JPilotFile
*pilotFile
, const gboolean value
) {
399 g_return_if_fail( pilotFile
!= NULL
);
400 pilotFile
->addressCache
->modified
= value
;
402 gboolean
jpilot_get_accessed( JPilotFile
*pilotFile
) {
403 g_return_val_if_fail( pilotFile
!= NULL
, FALSE
);
404 return pilotFile
->addressCache
->accessFlag
;
408 * Free up pilot file object by releasing internal memory.
409 * \param pilotFile JPilot control data.
411 void jpilot_free( JPilotFile
*pilotFile
) {
412 g_return_if_fail( pilotFile
!= NULL
);
414 /* Release custom labels */
415 jpilot_clear_custom_labels( pilotFile
);
418 addrcache_clear( pilotFile
->addressCache
);
419 addrcache_free( pilotFile
->addressCache
);
421 /* Free internal stuff */
422 g_free( pilotFile
->path
);
424 pilotFile
->file
= NULL
;
425 pilotFile
->path
= NULL
;
426 pilotFile
->readMetadata
= FALSE
;
427 pilotFile
->havePC3
= FALSE
;
428 pilotFile
->pc3ModifyTime
= 0;
430 pilotFile
->type
= ADBOOKTYPE_NONE
;
431 pilotFile
->addressCache
= NULL
;
432 pilotFile
->retVal
= MGU_SUCCESS
;
434 /* Now release file object */
439 * Refresh internal variables to force a file read.
441 void jpilot_force_refresh( JPilotFile
*pilotFile
) {
442 addrcache_refresh( pilotFile
->addressCache
);
446 * Print object to specified stream.
448 void jpilot_print_file( JPilotFile
*pilotFile
, FILE *stream
) {
451 g_return_if_fail( pilotFile
!= NULL
);
453 fprintf( stream
, "JPilotFile:\n" );
454 fprintf( stream
, "file spec: '%s'\n", pilotFile
->path
);
455 fprintf( stream
, " metadata: %s\n", pilotFile
->readMetadata
? "yes" : "no" );
456 fprintf( stream
, " ret val: %d\n", pilotFile
->retVal
);
458 node
= pilotFile
->customLabels
;
460 fprintf( stream
, " c label: %s\n", (gchar
*)node
->data
);
461 node
= g_list_next( node
);
464 node
= pilotFile
->labelInd
;
466 fprintf( stream
, " labelind: %d\n", GPOINTER_TO_INT(node
->data
) );
467 node
= g_list_next( node
);
470 addrcache_print( pilotFile
->addressCache
, stream
);
471 fprintf( stream
, " ret val: %d\n", pilotFile
->retVal
);
472 fprintf( stream
, " have pc3: %s\n", pilotFile
->havePC3
? "yes" : "no" );
473 fprintf( stream
, " pc3 time: %lu\n", pilotFile
->pc3ModifyTime
);
474 addritem_print_item_folder( pilotFile
->addressCache
->rootFolder
, stream
);
478 * Print summary of object to specified stream.
480 void jpilot_print_short( JPilotFile
*pilotFile
, FILE *stream
) {
482 g_return_if_fail( pilotFile
!= NULL
);
483 fprintf( stream
, "JPilotFile:\n" );
484 fprintf( stream
, "file spec: '%s'\n", pilotFile
->path
);
485 fprintf( stream
, " metadata: %s\n", pilotFile
->readMetadata
? "yes" : "no" );
486 fprintf( stream
, " ret val: %d\n", pilotFile
->retVal
);
488 node
= pilotFile
->customLabels
;
490 fprintf( stream
, " c label: %s\n", (gchar
*)node
->data
);
491 node
= g_list_next( node
);
494 node
= pilotFile
->labelInd
;
496 fprintf( stream
, " labelind: %d\n", GPOINTER_TO_INT(node
->data
) );
497 node
= g_list_next( node
);
499 addrcache_print( pilotFile
->addressCache
, stream
);
500 fprintf( stream
, " have pc3: %s\n", pilotFile
->havePC3
? "yes" : "no" );
501 fprintf( stream
, " pc3 time: %lu\n", pilotFile
->pc3ModifyTime
);
504 /* Shamelessly copied from JPilot (libplugin.c) */
505 static unsigned int bytes_to_bin(unsigned char *bytes
, unsigned int num_bytes
) {
508 for (i
=0;i
<num_bytes
;i
++) {
514 /* Shamelessly copied from JPilot (utils.c) */
515 /* These next 2 functions were copied from pi-file.c in the pilot-link app */
516 /* Exact value of "Jan 1, 1970 0:00:00 GMT" - "Jan 1, 1904 0:00:00 GMT" */
517 #define PILOT_TIME_DELTA (unsigned)(2082844800)
519 time_t pilot_time_to_unix_time ( unsigned long raw_time
) {
520 return (time_t)(raw_time
- PILOT_TIME_DELTA
);
523 /* Shamelessly copied from JPilot (libplugin.c) */
524 static int raw_header_to_header(RawDBHeader
*rdbh
, DBHeader
*dbh
) {
527 strncpy(dbh
->db_name
, rdbh
->db_name
, 31);
528 dbh
->db_name
[31] = '\0';
529 dbh
->flags
= bytes_to_bin(rdbh
->flags
, 2);
530 dbh
->version
= bytes_to_bin(rdbh
->version
, 2);
531 temp
= bytes_to_bin(rdbh
->creation_time
, 4);
532 dbh
->creation_time
= pilot_time_to_unix_time(temp
);
533 temp
= bytes_to_bin(rdbh
->modification_time
, 4);
534 dbh
->modification_time
= pilot_time_to_unix_time(temp
);
535 temp
= bytes_to_bin(rdbh
->backup_time
, 4);
536 dbh
->backup_time
= pilot_time_to_unix_time(temp
);
537 dbh
->modification_number
= bytes_to_bin(rdbh
->modification_number
, 4);
538 dbh
->app_info_offset
= bytes_to_bin(rdbh
->app_info_offset
, 4);
539 dbh
->sort_info_offset
= bytes_to_bin(rdbh
->sort_info_offset
, 4);
540 strncpy(dbh
->type
, rdbh
->type
, 4);
542 strncpy(dbh
->creator_id
, rdbh
->creator_id
, 4);
543 dbh
->creator_id
[4] = '\0';
544 strncpy(dbh
->unique_id_seed
, rdbh
->unique_id_seed
, 4);
545 dbh
->unique_id_seed
[4] = '\0';
546 dbh
->next_record_list_id
= bytes_to_bin(rdbh
->next_record_list_id
, 4);
547 dbh
->number_of_records
= bytes_to_bin(rdbh
->number_of_records
, 2);
551 /* Shamelessly copied from JPilot (libplugin.c) */
552 /* returns 1 if found */
554 static int find_next_offset( mem_rec_header
*mem_rh
, long fpos
,
555 unsigned int *next_offset
, unsigned char *attrib
, unsigned int *unique_id
)
557 mem_rec_header
*temp_mem_rh
;
558 unsigned char found
= 0;
559 unsigned long found_at
;
562 for (temp_mem_rh
=mem_rh
; temp_mem_rh
; temp_mem_rh
= temp_mem_rh
->next
) {
563 if ((temp_mem_rh
->offset
> fpos
) && (temp_mem_rh
->offset
< found_at
)) {
564 found_at
= temp_mem_rh
->offset
;
565 /* *attrib = temp_mem_rh->attrib; */
566 /* *unique_id = temp_mem_rh->unique_id; */
568 if ((temp_mem_rh
->offset
== fpos
)) {
570 *attrib
= temp_mem_rh
->attrib
;
571 *unique_id
= temp_mem_rh
->unique_id
;
574 *next_offset
= found_at
;
578 /* Shamelessly copied from JPilot (libplugin.c) */
579 static void free_mem_rec_header(mem_rec_header
**mem_rh
) {
580 mem_rec_header
*h
, *next_h
;
581 for (h
=*mem_rh
; h
; h
=next_h
) {
588 /* Shamelessly copied from JPilot (libplugin.c) */
590 static int jpilot_get_info_size( FILE *in
, int *size
) {
596 fseek(in
, 0, SEEK_SET
);
597 fread(&rdbh
, sizeof(RawDBHeader
), 1, in
);
602 raw_header_to_header(&rdbh
, &dbh
);
603 if (dbh
.app_info_offset
==0) {
607 if (dbh
.sort_info_offset
!=0) {
608 *size
= dbh
.sort_info_offset
- dbh
.app_info_offset
;
611 if (dbh
.number_of_records
==0) {
612 fseek(in
, 0, SEEK_END
);
613 *size
=ftell(in
) - dbh
.app_info_offset
;
617 fread(&rh
, sizeof(record_header
), 1, in
);
618 offset
= ((rh
.Offset
[0]*256+rh
.Offset
[1])*256+rh
.Offset
[2])*256+rh
.Offset
[3];
619 *size
=offset
- dbh
.app_info_offset
;
625 * Read address file into address list. Based on JPilot's
626 * libplugin.c (jp_get_app_info)
628 static gint
jpilot_get_file_info( JPilotFile
*pilotFile
, unsigned char **buf
, int *buf_size
) {
631 unsigned int rec_size
;
635 if( ( !buf_size
) || ( ! buf
) ) {
642 if( pilotFile
->path
) {
643 in
= g_fopen( pilotFile
->path
, "rb" );
645 return MGU_OPEN_FILE
;
652 num
= fread( &rdbh
, sizeof( RawDBHeader
), 1, in
);
656 return MGU_ERROR_READ
;
664 /* Convert header into something recognizable */
665 raw_header_to_header(&rdbh
, &dbh
);
667 num
= jpilot_get_info_size(in
, &rec_size
);
670 return MGU_ERROR_READ
;
673 fseek(in
, dbh
.app_info_offset
, SEEK_SET
);
674 *buf
= ( char * ) malloc(rec_size
);
677 return MGU_OO_MEMORY
;
679 num
= fread(*buf
, rec_size
, 1, in
);
684 return MGU_ERROR_READ
;
689 *buf_size
= rec_size
;
694 /* Shamelessly copied from JPilot (libplugin.c) */
695 static int unpack_header(PC3RecordHeader
*header
, unsigned char *packed_header
) {
701 memcpy(&l
, p
, sizeof(l
));
702 header
->header_len
=ntohl(l
);
705 memcpy(&l
, p
, sizeof(l
));
706 header
->header_version
=ntohl(l
);
709 memcpy(&l
, p
, sizeof(l
));
710 header
->rec_len
=ntohl(l
);
713 memcpy(&l
, p
, sizeof(l
));
714 header
->unique_id
=ntohl(l
);
717 memcpy(&l
, p
, sizeof(l
));
721 memcpy(&(header
->attrib
), p
, sizeof(unsigned char));
722 p
+=sizeof(unsigned char);
727 /* Shamelessly copied from JPilot (libplugin.c) */
728 static int read_header(FILE *pc_in
, PC3RecordHeader
*header
) {
731 unsigned char packed_header
[256];
734 num
= fread(&l
, sizeof(l
), 1, pc_in
);
741 memcpy(packed_header
, &l
, sizeof(l
));
746 num
= fread(packed_header
+sizeof(l
), len
-sizeof(l
), 1, pc_in
);
753 unpack_header(header
, packed_header
);
758 * Read next record from PC3 file. Based on JPilot function
759 * <code>pc_read_next_rec()</code> (libplugin.c)
761 * \param in File handle.
762 * \param br Record buffer.
763 * \return Status/error code. <code>MGU_SUCCESS</code> if data read
766 static gint
jpilot_read_next_pc( FILE *in
, buf_rec
*br
) {
767 PC3RecordHeader header
;
774 num
= read_header( in
, &header
);
777 return MGU_ERROR_READ
;
783 rec_len
= header
.rec_len
;
784 record
= malloc( rec_len
);
786 return MGU_OO_MEMORY
;
788 num
= fread( record
, rec_len
, 1, in
);
792 return MGU_ERROR_READ
;
796 br
->unique_id
= header
.unique_id
;
797 br
->attrib
= header
.attrib
;
805 * Read address file into a linked list. Based on JPilot function
806 * <code>jp_read_DB_files()</code> (from libplugin.c)
808 * \param pilotFile JPilot control data.
809 * \param records Pointer to linked list of records read.
810 * \return Status/error code. <code>MGU_SUCCESS</code> if data read
813 static gint
jpilot_read_db_files( JPilotFile
*pilotFile
, GList
**records
) {
817 int num_records
, recs_returned
, i
, num
, r
;
818 unsigned int offset
, prev_offset
, next_offset
, rec_size
;
820 long fpos
; /*file position indicator */
821 unsigned char attrib
;
822 unsigned int unique_id
;
823 mem_rec_header
*mem_rh
, *temp_mem_rh
, *last_mem_rh
;
830 mem_rh
= last_mem_rh
= NULL
;
834 if( pilotFile
->path
== NULL
) {
838 in
= g_fopen( pilotFile
->path
, "rb" );
840 return MGU_OPEN_FILE
;
843 /* Read the database header */
844 num
= fread( &rdbh
, sizeof( RawDBHeader
), 1, in
);
848 return MGU_ERROR_READ
;
855 raw_header_to_header( &rdbh
, &dbh
);
857 /* Read each record entry header */
858 num_records
= dbh
.number_of_records
;
862 for( i
= 1; i
< num_records
+ 1; i
++ ) {
863 num
= fread( &rh
, sizeof( record_header
), 1, in
);
875 ( ( rh
.Offset
[0] * 256 + rh
.Offset
[1] ) * 256
876 + rh
.Offset
[2] ) * 256
878 if( offset
< prev_offset
) {
881 prev_offset
= offset
;
882 temp_mem_rh
= ( mem_rec_header
* ) malloc( sizeof( mem_rec_header
) );
883 if( ! temp_mem_rh
) {
886 temp_mem_rh
->next
= NULL
;
887 temp_mem_rh
->rec_num
= i
;
888 temp_mem_rh
->offset
= offset
;
889 temp_mem_rh
->attrib
= rh
.attrib
;
890 temp_mem_rh
->unique_id
=
891 ( rh
.unique_ID
[0] * 256 + rh
.unique_ID
[1] ) * 256
893 if( mem_rh
== NULL
) {
894 mem_rh
= temp_mem_rh
;
895 last_mem_rh
= temp_mem_rh
;
898 last_mem_rh
->next
= temp_mem_rh
;
899 last_mem_rh
= temp_mem_rh
;
903 temp_mem_rh
= mem_rh
;
908 mem_rh
, 0, &next_offset
, &attrib
, &unique_id
);
912 next_offset
= mem_rh
->offset
;
913 attrib
= mem_rh
->attrib
;
914 unique_id
= mem_rh
->unique_id
;
917 fseek( in
, next_offset
, SEEK_SET
);
918 while( ! feof( in
) ) {
922 mem_rh
, fpos
, &next_offset
, &attrib
,
925 next_offset
= 0xFFFFFF;
927 attrib
= temp_mem_rh
->attrib
;
928 unique_id
= temp_mem_rh
->unique_id
;
929 if ( temp_mem_rh
->next
) {
930 temp_mem_rh
= temp_mem_rh
->next
;
931 next_offset
= temp_mem_rh
->offset
;
935 rec_size
= next_offset
- fpos
;
936 buf
= malloc( rec_size
);
938 num
= fread( buf
, rec_size
, 1, in
);
946 temp_br
= malloc( sizeof( buf_rec
) );
951 temp_br
->rt
= PALM_REC
;
952 temp_br
->unique_id
= unique_id
;
953 temp_br
->attrib
= attrib
;
955 temp_br
->size
= rec_size
;
957 *records
= g_list_append( *records
, temp_br
);
963 free_mem_rec_header( &mem_rh
);
965 /* Read the PC3 file, if present */
966 pcFile
= jpilot_get_pc3_file( pilotFile
);
967 if( pcFile
== NULL
) return MGU_SUCCESS
;
968 pc_in
= g_fopen( pcFile
, "rb");
971 if( pc_in
== NULL
) {
975 while( ! feof( pc_in
) ) {
978 temp_br
= malloc( sizeof( buf_rec
) );
982 r
= jpilot_read_next_pc( pc_in
, temp_br
);
983 if( r
!= MGU_SUCCESS
) {
984 if( (r
!= MGU_EOF
) && (r
!= MGU_ERROR_READ
) ) {
985 free( temp_br
->buf
);
992 if( ( temp_br
->rt
!= DELETED_PC_REC
)
993 && ( temp_br
->rt
!= DELETED_PALM_REC
)
994 && ( temp_br
->rt
!= MODIFIED_PALM_REC
)
995 && ( temp_br
->rt
!= DELETED_DELETED_PALM_REC
) )
997 *records
= g_list_append( *records
, temp_br
);
1002 if( ( temp_br
->rt
== DELETED_PALM_REC
)
1003 || ( temp_br
->rt
== MODIFIED_PALM_REC
) )
1005 temp_list
= *records
;
1007 while( temp_list
->next
) {
1008 temp_list
=temp_list
->next
;
1011 for( ; temp_list
; temp_list
=temp_list
->prev
) {
1012 if( ( ( buf_rec
* )temp_list
->data
)->unique_id
==
1013 temp_br
->unique_id
) {
1014 ( ( buf_rec
* )temp_list
->data
)->rt
=
1021 free( temp_br
->buf
);
1031 * Parse buffer containing multiple e-mail addresses into a linked list of
1032 * addresses. Separator characters are " ,;|" and control characters. Address
1033 * is only extracted if it contains an "at" (@) character.
1035 * \param buf Buffer to process.
1036 * \return List of strings.
1038 static GList
*jpilot_parse_email( gchar
*buf
) {
1043 gboolean valid
, done
;
1045 valid
= done
= FALSE
;
1050 if( *p
== ' ' || *p
== ',' || *p
== ';' || *p
== '|' || *p
< 32 ) {
1065 em
= g_strndup( st
, len
);
1066 list
= g_list_append( list
, em
);
1074 if( *p
== '@' ) valid
= TRUE
;
1082 #define FULLNAME_BUFSIZE 256
1083 #define EMAIL_BUFSIZE 256
1086 * Process a single label entry field, parsing multiple e-mail address entries.
1088 * \param pilotFile JPilot control data.
1089 * \param labelEntry Label entry data.
1090 * \param person Person.
1092 static void jpilot_parse_label( JPilotFile
*pilotFile
, gchar
*labelEntry
, ItemPerson
*person
) {
1093 gchar buffer
[ EMAIL_BUFSIZE
];
1099 strcpy( buffer
, labelEntry
);
1100 node
= list
= jpilot_parse_email( buffer
);
1102 email
= addritem_create_item_email();
1103 addritem_email_set_address( email
, node
->data
);
1104 if (convert_charcode
) {
1106 convertBuff
= conv_codeset_strdup( labelEntry
,
1107 conv_get_locale_charset_str_no_utf8(),
1109 addritem_email_set_remarks( email
, convertBuff
);
1110 g_free( convertBuff
);
1113 addritem_email_set_remarks(email
, buffer
);
1116 addrcache_id_email( pilotFile
->addressCache
, email
);
1117 addrcache_person_add_email( pilotFile
->addressCache
, person
, email
);
1118 node
= g_list_next( node
);
1120 mgu_free_dlist( list
);
1126 * Unpack address, building new data inside cache.
1127 * \param pilotFile JPilot control data.
1128 * \param buf Record buffer.
1129 * \param folderInd Array of (category) folders to load.
1131 static void jpilot_load_address(
1132 JPilotFile
*pilotFile
, buf_rec
*buf
, ItemFolder
*folderInd
[] )
1134 struct Address addr
;
1140 gchar fullName
[ FULLNAME_BUFSIZE
];
1146 struct AddressAppInfo
*ai
;
1147 gchar
**firstName
= NULL
;
1148 gchar
**lastName
= NULL
;
1149 #if (PILOT_LINK_MAJOR > 11)
1150 pi_buffer_t
*RecordBuffer
;
1151 #endif /* PILOT_LINK_0_12 */
1153 /* Retrieve address */
1154 #if (PILOT_LINK_MAJOR < 12)
1155 num
= unpack_Address(&addr
, buf
->buf
, buf
->size
);
1159 #else /* PILOT_LINK_0_12 */
1160 RecordBuffer
= pi_buffer_new(buf
->size
);
1161 memcpy(RecordBuffer
->data
, buf
->buf
, buf
->size
);
1162 RecordBuffer
->used
= buf
->size
;
1163 if (unpack_Address(&addr
, RecordBuffer
, address_v1
) == -1) {
1164 pi_buffer_free(RecordBuffer
);
1167 pi_buffer_free(RecordBuffer
);
1169 addrEnt
= addr
.entry
;
1170 attrib
= buf
->attrib
;
1171 unique_id
= buf
->unique_id
;
1172 cat_id
= attrib
& 0x0F;
1175 if( addrEnt
[ IND_LABEL_FIRSTNAME
] ) {
1176 firstName
= g_strsplit( addrEnt
[ IND_LABEL_FIRSTNAME
], "\01", 2 );
1179 if( addrEnt
[ IND_LABEL_LASTNAME
] ) {
1180 lastName
= g_strsplit( addrEnt
[ IND_LABEL_LASTNAME
], "\01", 2 );
1183 if( name_order
== FAMILY_LAST
) {
1184 g_snprintf( fullName
, FULLNAME_BUFSIZE
, "%s %s",
1185 firstName
? firstName
[0] : "",
1186 lastName
? lastName
[0] : "" );
1189 g_snprintf( fullName
, FULLNAME_BUFSIZE
, "%s %s",
1190 lastName
? lastName
[0] : "",
1191 firstName
? firstName
[0] : "" );
1195 g_strfreev( firstName
);
1198 g_strfreev( lastName
);
1201 g_strstrip( fullName
);
1203 if( convert_charcode
) {
1205 nameConv
= conv_codeset_strdup( fullName
,
1206 conv_get_locale_charset_str_no_utf8(),
1208 strncpy2( fullName
, nameConv
, FULLNAME_BUFSIZE
);
1212 person
= addritem_create_item_person();
1213 addritem_person_set_common_name( person
, fullName
);
1214 addritem_person_set_first_name( person
, addrEnt
[ IND_LABEL_FIRSTNAME
] );
1215 addritem_person_set_last_name( person
, addrEnt
[ IND_LABEL_LASTNAME
] );
1216 addrcache_id_person( pilotFile
->addressCache
, person
);
1218 extID
= g_strdup_printf( "%d", unique_id
);
1219 addritem_person_set_external_id( person
, extID
);
1223 /* Pointer to address metadata. */
1224 ai
= & pilotFile
->addrInfo
;
1226 /* Add entry for each email address listed under phone labels. */
1227 indPhoneLbl
= addr
.phoneLabel
;
1228 for( k
= 0; k
< JPILOT_NUM_ADDR_PHONE
; k
++ ) {
1231 ind
= indPhoneLbl
[k
];
1233 * fprintf( stdout, "%d : %d : %20s : %s\n", k, ind,
1234 * ai->phoneLabels[ind], addrEnt[3+k] );
1236 if( indPhoneLbl
[k
] == IND_PHONE_EMAIL
) {
1237 labelEntry
= addrEnt
[ OFFSET_PHONE_LABEL
+ k
];
1238 jpilot_parse_label( pilotFile
, labelEntry
, person
);
1242 /* Add entry for each custom label */
1243 node
= pilotFile
->labelInd
;
1247 ind
= GPOINTER_TO_INT( node
->data
);
1250 * fprintf( stdout, "%d : %20s : %s\n", ind, ai->labels[ind],
1253 labelEntry
= addrEnt
[ind
];
1254 jpilot_parse_label( pilotFile
, labelEntry
, person
);
1257 node
= g_list_next( node
);
1260 if( person
->listEMail
) {
1261 if( cat_id
> -1 && cat_id
< JPILOT_NUM_CATEG
) {
1262 /* Add to specified category */
1263 addrcache_folder_add_person(
1264 pilotFile
->addressCache
,
1265 folderInd
[cat_id
], person
);
1268 /* Add to root folder */
1269 addrcache_add_person(
1270 pilotFile
->addressCache
, person
);
1274 addritem_free_item_person( person
);
1277 /* Free up pointer allocated inside address */
1278 free_Address( & addr
);
1282 * Free up address list.
1283 * \param records List of records to free.
1285 static void jpilot_free_addrlist( GList
*records
) {
1295 node
= g_list_next( node
);
1299 g_list_free( records
);
1303 * Read metadata from file.
1304 * \param pilotFile JPilot control data.
1305 * \return Status/error code. <code>MGU_SUCCESS</code> if data read
1308 static gint
jpilot_read_metadata( JPilotFile
*pilotFile
) {
1310 unsigned int rec_size
;
1314 g_return_val_if_fail( pilotFile
!= NULL
, -1 );
1316 pilotFile
->readMetadata
= FALSE
;
1317 addrcache_clear( pilotFile
->addressCache
);
1319 /* Read file info */
1320 retVal
= jpilot_get_file_info( pilotFile
, &buf
, &rec_size
);
1321 if( retVal
!= MGU_SUCCESS
) {
1322 pilotFile
->retVal
= retVal
;
1323 return pilotFile
->retVal
;
1326 num
= unpack_AddressAppInfo( &pilotFile
->addrInfo
, buf
, rec_size
);
1331 pilotFile
->retVal
= MGU_ERROR_READ
;
1332 return pilotFile
->retVal
;
1335 pilotFile
->readMetadata
= TRUE
;
1336 pilotFile
->retVal
= MGU_SUCCESS
;
1337 return pilotFile
->retVal
;
1341 * Setup labels and indexes from metadata.
1342 * \param pilotFile JPilot control data.
1343 * \return <i>TRUE</i> is setup successfully.
1345 static gboolean
jpilot_setup_labels( JPilotFile
*pilotFile
) {
1346 gboolean retVal
= FALSE
;
1347 struct AddressAppInfo
*ai
;
1350 g_return_val_if_fail( pilotFile
!= NULL
, -1 );
1352 /* Release indexes */
1353 node
= pilotFile
->labelInd
;
1356 node
= g_list_next( node
);
1358 pilotFile
->labelInd
= NULL
;
1360 if( pilotFile
->readMetadata
) {
1361 ai
= & pilotFile
->addrInfo
;
1362 node
= pilotFile
->customLabels
;
1364 gchar
*lbl
= node
->data
;
1367 for( i
= 0; i
< JPILOT_NUM_LABELS
; i
++ ) {
1368 gchar
*labelName
= ai
->labels
[i
];
1369 gchar convertBuff
[ JPILOT_LEN_LABEL
];
1371 if( convert_charcode
) {
1372 labelName
= conv_codeset_strdup( labelName
,
1373 conv_get_locale_charset_str_no_utf8(),
1375 strncpy2( convertBuff
, labelName
, JPILOT_LEN_LABEL
);
1376 g_free( labelName
);
1377 labelName
= convertBuff
;
1380 if( g_utf8_collate( labelName
, lbl
) == 0 ) {
1385 pilotFile
->labelInd
= g_list_append(
1386 pilotFile
->labelInd
, GINT_TO_POINTER(ind
) );
1387 node
= g_list_next( node
);
1395 * Load list with character strings of label names.
1396 * \param pilotFile JPilot control data.
1397 * \param labelList List of label names to load.
1398 * \return List of label names loaded.
1400 GList
*jpilot_load_label( JPilotFile
*pilotFile
, GList
*labelList
) {
1403 g_return_val_if_fail( pilotFile
!= NULL
, NULL
);
1405 if( pilotFile
->readMetadata
) {
1406 struct AddressAppInfo
*ai
= & pilotFile
->addrInfo
;
1407 for( i
= 0; i
< JPILOT_NUM_LABELS
; i
++ ) {
1408 gchar
*labelName
= ai
->labels
[i
];
1411 if( convert_charcode
) {
1412 labelName
= conv_codeset_strdup( labelName
,
1413 conv_get_locale_charset_str_no_utf8(),
1417 labelName
= g_strdup( labelName
);
1419 labelList
= g_list_append( labelList
, labelName
);
1422 labelList
= g_list_append(
1423 labelList
, g_strdup( "" ) );
1431 * Return category name for specified category ID.
1432 * \param pilotFile JPilot control data.
1433 * \param catID Category ID.
1434 * \return Category name, or empty string if not invalid ID. Name should be
1435 * <code>g_free()</code> when done.
1437 gchar
*jpilot_get_category_name( JPilotFile
*pilotFile
, gint catID
) {
1438 gchar
*catName
= NULL
;
1440 g_return_val_if_fail( pilotFile
!= NULL
, NULL
);
1442 if( pilotFile
->readMetadata
) {
1443 struct AddressAppInfo
*ai
= & pilotFile
->addrInfo
;
1444 struct CategoryAppInfo
*cat
= & ai
->category
;
1445 if( catID
< 0 || catID
> JPILOT_NUM_CATEG
) {
1448 catName
= g_strdup( cat
->name
[catID
] );
1451 if( ! catName
) catName
= g_strdup( "" );
1456 * Load list with character strings of phone label names.
1457 * \param pilotFile JPilot control data.
1458 * \param labelList List of label names to load.
1459 * \return List of label names loaded.
1461 GList
*jpilot_load_phone_label( JPilotFile
*pilotFile
, GList
*labelList
) {
1464 g_return_val_if_fail( pilotFile
!= NULL
, NULL
);
1466 if( pilotFile
->readMetadata
) {
1467 struct AddressAppInfo
*ai
= & pilotFile
->addrInfo
;
1468 for( i
= 0; i
< JPILOT_NUM_PHONELABELS
; i
++ ) {
1469 gchar
*labelName
= ai
->phoneLabels
[i
];
1471 labelList
= g_list_append(
1472 labelList
, g_strdup( labelName
) );
1475 labelList
= g_list_append(
1476 labelList
, g_strdup( "" ) );
1484 * Load list with character strings of custom label names. Only none blank
1486 * \param pilotFile JPilot control data.
1487 * \param labelList List of label names to load.
1488 * \return List of label names loaded. Should be freed when done.
1490 GList
*jpilot_load_custom_label( JPilotFile
*pilotFile
, GList
*labelList
) {
1493 g_return_val_if_fail( pilotFile
!= NULL
, NULL
);
1495 if( pilotFile
->readMetadata
) {
1496 struct AddressAppInfo
*ai
= & pilotFile
->addrInfo
;
1497 for( i
= 0; i
< NUM_CUSTOM_LABEL
; i
++ ) {
1498 gchar
*labelName
= ai
->labels
[i
+IND_CUSTOM_LABEL
];
1500 g_strchomp( labelName
);
1501 g_strchug( labelName
);
1502 if( *labelName
!= '\0' ) {
1503 if( convert_charcode
) {
1504 labelName
= conv_codeset_strdup( labelName
,
1505 conv_get_locale_charset_str_no_utf8(),
1509 labelName
= g_strdup( labelName
);
1511 labelList
= g_list_append( labelList
, labelName
);
1520 * Load list with character strings of category names.
1521 * \param pilotFile JPilot control data.
1522 * \return List of label names loaded. Should be freed when done.
1524 GList
*jpilot_get_category_list( JPilotFile
*pilotFile
) {
1525 GList
*catList
= NULL
;
1528 g_return_val_if_fail( pilotFile
!= NULL
, NULL
);
1530 if( pilotFile
->readMetadata
) {
1531 struct AddressAppInfo
*ai
= & pilotFile
->addrInfo
;
1532 struct CategoryAppInfo
*cat
= & ai
->category
;
1533 for( i
= 0; i
< JPILOT_NUM_CATEG
; i
++ ) {
1534 gchar
*catName
= cat
->name
[i
];
1536 catList
= g_list_append(
1537 catList
, g_strdup( catName
) );
1540 catList
= g_list_append(
1541 catList
, g_strdup( "" ) );
1549 * Build folder in address book for each category.
1550 * \param pilotFile JPilot control data.
1552 static void jpilot_build_category_list( JPilotFile
*pilotFile
) {
1553 struct AddressAppInfo
*ai
= & pilotFile
->addrInfo
;
1554 struct CategoryAppInfo
*cat
= & ai
->category
;
1557 for( i
= 0; i
< JPILOT_NUM_CATEG
; i
++ ) {
1558 ItemFolder
*folder
= addritem_create_item_folder();
1560 if( convert_charcode
) {
1562 catName
= conv_codeset_strdup( cat
->name
[i
],
1563 conv_get_locale_charset_str_no_utf8(),
1565 addritem_folder_set_name( folder
, catName
);
1569 addritem_folder_set_name( folder
, cat
->name
[i
] );
1572 addrcache_id_folder( pilotFile
->addressCache
, folder
);
1573 addrcache_add_folder( pilotFile
->addressCache
, folder
);
1578 * Remove empty (category) folders.
1579 * \param pilotFile JPilot control data.
1581 static void jpilot_remove_empty( JPilotFile
*pilotFile
) {
1587 listFolder
= addrcache_get_list_folder( pilotFile
->addressCache
);
1591 ItemFolder
*folder
= node
->data
;
1592 if( ADDRITEM_NAME(folder
) == NULL
|| *ADDRITEM_NAME(folder
) == '\0' ) {
1593 if( folder
->listPerson
) {
1594 /* Give name to folder */
1596 sprintf( name
, "? %d", i
);
1597 addritem_folder_set_name( folder
, name
);
1600 /* Mark for removal */
1601 remList
= g_list_append( remList
, folder
);
1604 node
= g_list_next( node
);
1609 ItemFolder
*folder
= node
->data
;
1610 addrcache_remove_folder( pilotFile
->addressCache
, folder
);
1611 node
= g_list_next( node
);
1613 g_list_free( remList
);
1617 * Read address file into address cache.
1618 * \param pilotFile JPilot control data.
1619 * \return Error/status code. <code>MGU_SUCCESS</code> if data read
1622 static gint
jpilot_read_file( JPilotFile
*pilotFile
) {
1624 GList
*records
= NULL
;
1627 ItemFolder
*folderInd
[ JPILOT_NUM_CATEG
];
1629 /* Read list of records from JPilot files */
1630 retVal
= jpilot_read_db_files( pilotFile
, &records
);
1631 if( retVal
!= MGU_SUCCESS
) {
1632 jpilot_free_addrlist( records
);
1636 /* Setup labels and category folders */
1637 jpilot_setup_labels( pilotFile
);
1638 jpilot_build_category_list( pilotFile
);
1640 /* Build array of pointers to categories */
1642 node
= addrcache_get_list_folder( pilotFile
->addressCache
);
1644 if( i
< JPILOT_NUM_CATEG
) {
1645 folderInd
[i
] = node
->data
;
1647 node
= g_list_next( node
);
1651 /* Load all addresses, free up old stuff as we go */
1655 if( ( br
->rt
!= DELETED_PC_REC
) &&
1656 ( br
->rt
!= DELETED_PALM_REC
) &&
1657 ( br
->rt
!= MODIFIED_PALM_REC
) &&
1658 ( br
->rt
!= DELETED_DELETED_PALM_REC
) ) {
1659 jpilot_load_address( pilotFile
, br
, folderInd
);
1664 node
= g_list_next( node
);
1668 g_list_free( records
);
1670 /* Remove empty category folders */
1671 jpilot_remove_empty( pilotFile
);
1672 jpilot_mark_files( pilotFile
);
1678 * Read file into list. Main entry point
1679 * \param pilotFile JPilot control data.
1680 * \return Error/status code. <code>MGU_SUCCESS</code> if data read
1683 gint
jpilot_read_data( JPilotFile
*pilotFile
) {
1684 const gchar
*cur_locale
;
1686 name_order
= FAMILY_LAST
;
1688 cur_locale
= conv_get_current_locale();
1690 if( g_ascii_strncasecmp( cur_locale
, "ja", 2 ) == 0 ) {
1691 name_order
= FAMILY_FIRST
;
1694 g_return_val_if_fail( pilotFile
!= NULL
, -1 );
1696 pilotFile
->retVal
= MGU_SUCCESS
;
1697 pilotFile
->addressCache
->accessFlag
= FALSE
;
1698 if( jpilot_check_files( pilotFile
) ) {
1699 addrcache_clear( pilotFile
->addressCache
);
1700 jpilot_read_metadata( pilotFile
);
1701 if( pilotFile
->retVal
== MGU_SUCCESS
) {
1702 pilotFile
->retVal
= jpilot_read_file( pilotFile
);
1703 if( pilotFile
->retVal
== MGU_SUCCESS
) {
1704 pilotFile
->addressCache
->modified
= FALSE
;
1705 pilotFile
->addressCache
->dataRead
= TRUE
;
1709 return pilotFile
->retVal
;
1713 * Return linked list of persons. This is a list of references to ItemPerson
1714 * objects. Do <b>NOT</b> attempt to use the <code>addrbook_free_xxx()</code>
1715 * functions... this will destroy the addressbook data!
1717 * \param pilotFile JPilot control data.
1718 * \return List of persons.
1720 GList
*jpilot_get_list_person( JPilotFile
*pilotFile
) {
1721 g_return_val_if_fail( pilotFile
!= NULL
, NULL
);
1722 return addrcache_get_list_person( pilotFile
->addressCache
);
1726 * Return linked list of folders. This is a list of references to non-empty
1727 * category folders. Do <b>NOT</b> attempt to use the
1728 * <code>addrbook_free_xxx()</code> functions... this will destroy the
1731 * \param pilotFile JPilot control data.
1732 * \return List of ItemFolder objects. This should not be freed.
1734 GList
*jpilot_get_list_folder( JPilotFile
*pilotFile
) {
1735 g_return_val_if_fail( pilotFile
!= NULL
, NULL
);
1736 return addrcache_get_list_folder( pilotFile
->addressCache
);
1740 * Return linked list of all persons. Note that the list contains references
1741 * to items. Do <b>NOT</b> attempt to use the <code>addrbook_free_xxx()</code>
1742 * functions... this will destroy the addressbook data!
1744 * \param pilotFile JPilot control data.
1745 * \return List of items, or NULL if none.
1747 GList
*jpilot_get_all_persons( JPilotFile
*pilotFile
) {
1748 g_return_val_if_fail( pilotFile
!= NULL
, NULL
);
1749 return addrcache_get_all_persons( pilotFile
->addressCache
);
1753 * Validate that all parameters specified.
1754 * \param pilotFile JPilot control data.
1755 * \return <i>TRUE</i> if data is good.
1757 gboolean
jpilot_validate( JPilotFile
*pilotFile
) {
1761 g_return_val_if_fail( pilotFile
!= NULL
, FALSE
);
1764 if( pilotFile
->path
) {
1765 if( strlen( pilotFile
->path
) < 1 ) retVal
= FALSE
;
1770 name
= jpilot_get_name( pilotFile
);
1772 if( strlen( name
) < 1 ) retVal
= FALSE
;
1780 #define WORK_BUFLEN 1024
1783 * Attempt to find a valid JPilot file.
1784 * \param pilotFile JPilot control data.
1785 * \return Filename, or home directory if not found, or empty string if
1786 * no home. Filename should be <code>g_free()</code> when done.
1788 gchar
*jpilot_find_pilotdb( void ) {
1789 const gchar
*homedir
;
1790 gchar str
[ WORK_BUFLEN
];
1794 homedir
= get_home_dir();
1795 if( ! homedir
) return g_strdup( "" );
1797 strcpy( str
, homedir
);
1798 len
= strlen( str
);
1800 if( str
[ len
-1 ] != G_DIR_SEPARATOR
) {
1801 str
[ len
] = G_DIR_SEPARATOR
;
1802 str
[ ++len
] = '\0';
1805 strcat( str
, JPILOT_DBHOME_DIR
);
1806 strcat( str
, G_DIR_SEPARATOR_S
);
1807 strcat( str
, JPILOT_DBHOME_FILE
);
1809 /* Attempt to open */
1810 if( ( fp
= g_fopen( str
, "rb" ) ) != NULL
) {
1814 /* Truncate filename */
1817 return g_strdup( str
);
1821 * Attempt to read file, testing for valid JPilot format.
1822 * \param fileSpec File specification to read.
1823 * \return <i>TRUE<i> if file appears to be valid format.
1825 gint
jpilot_test_read_file( const gchar
*fileSpec
) {
1826 JPilotFile
*pilotFile
;
1830 pilotFile
= jpilot_create_path( fileSpec
);
1831 retVal
= jpilot_read_metadata( pilotFile
);
1832 jpilot_free( pilotFile
);
1836 retVal
= MGU_NO_FILE
;
1842 * Check whether label is in list of custom labels.
1843 * \param pilotFile JPilot control data.
1844 * \param labelName to test.
1845 * \return <i>TRUE</i> if found.
1847 gboolean
jpilot_test_custom_label( JPilotFile
*pilotFile
, const gchar
*labelName
) {
1851 g_return_val_if_fail( pilotFile
!= NULL
, FALSE
);
1855 node
= pilotFile
->customLabels
;
1857 if( g_utf8_collate( labelName
, ( gchar
* ) node
->data
) == 0 ) {
1861 node
= g_list_next( node
);
1868 * Test whether pilot link library installed.
1869 * \return <i>TRUE</i> if library available.
1871 gboolean
jpilot_test_pilot_lib( void ) {
1875 #endif /* USE_JPILOT */