Statistics
| Revision:

root / src / jpilot.c @ 3300

History | View | Annotate | Download (41.5 KB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 2001 Match Grun
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 2 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, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
 */
19

    
20
/*
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.
24
 */
25

    
26
#ifdef HAVE_CONFIG_H
27
#  include "config.h"
28
#endif
29

    
30
#ifdef USE_JPILOT
31

    
32
#include <glib.h>
33
#include <time.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
#include <sys/stat.h>
38
/* #include <dlfcn.h> */
39
#include <netinet/in.h>
40

    
41
#ifdef HAVE_LIBPISOCK_PI_ARGS_H
42
#  include <libpisock/pi-args.h>
43
#  include <libpisock/pi-appinfo.h>
44
#  include <libpisock/pi-address.h>
45
#  include <libpisock/pi-version.h>
46
#else
47
#  include <pi-args.h>
48
#  include <pi-appinfo.h>
49
#  include <pi-address.h>
50
#  include <pi-version.h>
51
#endif
52

    
53
#include "mgutils.h"
54
#include "addritem.h"
55
#include "addrcache.h"
56
#include "jpilot.h"
57
#include "codeconv.h"
58
#include "utils.h"
59

    
60
#define JPILOT_DBHOME_DIR   ".jpilot"
61
#define JPILOT_DBHOME_FILE  "AddressDB.pdb"
62
#define PILOT_LINK_LIB_NAME "libpisock.so"
63

    
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 */
70

    
71
/* Shamelessly copied from JPilot (libplugin.h) */
72
typedef struct {
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];
87
} RawDBHeader;
88

    
89
/* Shamelessly copied from JPilot (libplugin.h) */
90
typedef struct {
91
        char db_name[32];
92
        unsigned int flags;
93
        unsigned int version;
94
        time_t creation_time;
95
        time_t modification_time;
96
        time_t backup_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;
105
} DBHeader;
106

    
107
/* Shamelessly copied from JPilot (libplugin.h) */
108
typedef struct {
109
        unsigned char Offset[4];  /*4 bytes offset from BOF to record */
110
        unsigned char attrib;
111
        unsigned char unique_ID[3];
112
} record_header;
113

    
114
/* Shamelessly copied from JPilot (libplugin.h) */
115
typedef struct mem_rec_header_s {
116
        unsigned int rec_num;
117
        unsigned int offset;
118
        unsigned int unique_id;
119
        unsigned char attrib;
120
        struct mem_rec_header_s *next;
121
} mem_rec_header;
122

    
123
/* Shamelessly copied from JPilot (libplugin.h) */
124
#define SPENT_PC_RECORD_BIT        256
125

    
126
typedef enum {
127
        PALM_REC = 100L,
128
        MODIFIED_PALM_REC = 101L,
129
        DELETED_PALM_REC = 102L,
130
        NEW_PC_REC = 103L,
131
        DELETED_PC_REC = SPENT_PC_RECORD_BIT + 104L,
132
        DELETED_DELETED_PALM_REC = SPENT_PC_RECORD_BIT + 105L
133
} PCRecType;
134

    
135
/* Shamelessly copied from JPilot (libplugin.h) */
136
typedef struct {
137
        PCRecType rt;
138
        unsigned int unique_id;
139
        unsigned char attrib;
140
        void *buf;
141
        int size;
142
} buf_rec;
143

    
144
/* Shamelessly copied from JPilot (libplugin.h) */
145
typedef struct {
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;
152
} PC3RecordHeader;
153

    
154
enum {
155
        FAMILY_LAST = 0,
156
        FAMILY_FIRST = 1
157
} name_order;
158

    
159
gboolean convert_charcode;
160

    
161
static gchar *jpilot_convert_encoding(const gchar *str)
162
{
163
        if (convert_charcode)
164
                return conv_codeset_strdup(str, CS_SHIFT_JIS, CS_INTERNAL);
165

    
166
        return g_strdup(str);
167
}
168

    
169
/*
170
* Create new pilot file object.
171
*/
172
JPilotFile *jpilot_create() {
173
        JPilotFile *pilotFile;
174
        pilotFile = g_new0( JPilotFile, 1 );
175
        pilotFile->name = NULL;
176
        pilotFile->file = NULL;
177
        pilotFile->path = NULL;
178
        pilotFile->addressCache = addrcache_create();
179
        pilotFile->readMetadata = FALSE;
180
        pilotFile->customLabels = NULL;
181
        pilotFile->labelInd = NULL;
182
        pilotFile->retVal = MGU_SUCCESS;
183
        pilotFile->accessFlag = FALSE;
184
        pilotFile->havePC3 = FALSE;
185
        pilotFile->pc3ModifyTime = 0;
186
        return pilotFile;
187
}
188

    
189
/*
190
* Create new pilot file object for specified file.
191
*/
192
JPilotFile *jpilot_create_path( const gchar *path ) {
193
        JPilotFile *pilotFile;
194
        pilotFile = jpilot_create();
195
        jpilot_set_file( pilotFile, path );
196
        return pilotFile;
197
}
198

    
199
/*
200
* Properties...
201
*/
202
void jpilot_set_name( JPilotFile* pilotFile, const gchar *value ) {
203
        g_return_if_fail( pilotFile != NULL );
204
        pilotFile->name = mgu_replace_string( pilotFile->name, value );
205
}
206
void jpilot_set_file( JPilotFile* pilotFile, const gchar *value ) {
207
        g_return_if_fail( pilotFile != NULL );
208
        addrcache_refresh( pilotFile->addressCache );
209
        pilotFile->readMetadata = FALSE;
210
        pilotFile->path = mgu_replace_string( pilotFile->path, value );
211
}
212
void jpilot_set_accessed( JPilotFile *pilotFile, const gboolean value ) {
213
        g_return_if_fail( pilotFile != NULL );
214
        pilotFile->accessFlag = value;
215
}
216

    
217
gint jpilot_get_status( JPilotFile *pilotFile ) {
218
        g_return_val_if_fail( pilotFile != NULL, -1 );
219
        return pilotFile->retVal;
220
}
221
ItemFolder *jpilot_get_root_folder( JPilotFile *pilotFile ) {
222
        g_return_val_if_fail( pilotFile != NULL, NULL );
223
        return addrcache_get_root_folder( pilotFile->addressCache );
224
}
225
gchar *jpilot_get_name( JPilotFile *pilotFile ) {
226
        g_return_val_if_fail( pilotFile != NULL, NULL );
227
        return pilotFile->name;
228
}
229

    
230
/*
231
* Test whether file was read.
232
* Return: TRUE if file was read.
233
*/
234
gboolean jpilot_get_read_flag( JPilotFile *pilotFile ) {
235
        g_return_val_if_fail( pilotFile != NULL, FALSE );
236
        return pilotFile->addressCache->dataRead;
237
}
238

    
239
/*
240
* Free up custom label list.
241
*/
242
void jpilot_clear_custom_labels( JPilotFile *pilotFile ) {
243
        GList *node;
244

    
245
        g_return_if_fail( pilotFile != NULL );
246

    
247
        /* Release custom labels */
248
        mgu_free_dlist( pilotFile->customLabels );
249
        pilotFile->customLabels = NULL;
250

    
251
        /* Release indexes */
252
        node = pilotFile->labelInd;
253
        while( node ) {
254
                node->data = NULL;
255
                node = g_list_next( node );
256
        }
257
        g_list_free( pilotFile->labelInd );
258
        pilotFile->labelInd = NULL;
259

    
260
        /* Force a fresh read */
261
        addrcache_refresh( pilotFile->addressCache );
262
}
263

    
264
/*
265
* Append a custom label, representing an E-Mail address field to the
266
* custom label list.
267
*/
268
void jpilot_add_custom_label( JPilotFile *pilotFile, const gchar *labelName ) {
269
        g_return_if_fail( pilotFile != NULL );
270

    
271
        if( labelName ) {
272
                gchar *labelCopy = g_strdup( labelName );
273
                g_strstrip( labelCopy );
274
                if( *labelCopy == '\0' ) {
275
                        g_free( labelCopy );
276
                }
277
                else {
278
                        pilotFile->customLabels = g_list_append( pilotFile->customLabels, labelCopy );
279
                        /* Force a fresh read */
280
                        addrcache_refresh( pilotFile->addressCache );
281
                }
282
        }
283
}
284

    
285
/*
286
* Get list of custom labels.
287
* Return: List of labels. Must use g_free() when done.
288
*/
289
GList *jpilot_get_custom_labels( JPilotFile *pilotFile ) {
290
        GList *retVal = NULL;
291
        GList *node;
292

    
293
        g_return_val_if_fail( pilotFile != NULL, NULL );
294

    
295
        node = pilotFile->customLabels;
296
        while( node ) {
297
                retVal = g_list_append( retVal, g_strdup( node->data ) );
298
                node = g_list_next( node );
299
        }
300
        return retVal;
301
}
302

    
303
/*
304
* Return filespec of PC3 file corresponding to JPilot PDB file.
305
* Note: Filespec should be g_free() when done.
306
*/
307
static gchar *jpilot_get_pc3_file( JPilotFile *pilotFile ) {
308
        gchar *fileSpec, *r;
309
        gint i, len, pos;
310

    
311
        if( pilotFile == NULL ) return NULL;
312
        if( pilotFile->path == NULL ) return NULL;
313

    
314
        fileSpec = g_strdup( pilotFile->path );
315
        len = strlen( fileSpec );
316
        pos = -1;
317
        r = NULL;
318
        for( i = len; i > 0; i-- ) {
319
                if( *(fileSpec + i) == '.' ) {
320
                        pos = i + 1;
321
                        r = fileSpec + pos;
322
                        break;
323
                }
324
        }
325
        if( r ) {
326
                if( len - pos == 3 ) {
327
                        *r++ = 'p'; *r++ = 'c'; *r = '3';
328
                        return fileSpec;
329
                }
330
        }
331
        g_free( fileSpec );
332
        return NULL;
333
}
334

    
335
/*
336
* Save PC3 file time to cache.
337
* return: TRUE if time marked.
338
*/
339
static gboolean jpilot_mark_files( JPilotFile *pilotFile ) {
340
        gboolean retVal = FALSE;
341
        struct stat filestat;
342
        gchar *pcFile;
343

    
344
        /* Mark PDB file cache */
345
        retVal = addrcache_mark_file( pilotFile->addressCache, pilotFile->path );
346

    
347
        /* Now mark PC3 file */
348
        pilotFile->havePC3 = FALSE;
349
        pilotFile->pc3ModifyTime = 0;
350
        pcFile = jpilot_get_pc3_file( pilotFile );
351
        if( pcFile == NULL ) return retVal;
352
        if( 0 == g_lstat( pcFile, &filestat ) ) {
353
                pilotFile->havePC3 = TRUE;
354
                pilotFile->pc3ModifyTime = filestat.st_mtime;
355
                retVal = TRUE;
356
        }
357
        g_free( pcFile );
358
        return retVal;
359
}
360

    
361
/*
362
* Check whether JPilot PDB or PC3 file has changed by comparing
363
* with cached data.
364
* return: TRUE if file has changed.
365
*/
366
static gboolean jpilot_check_files( JPilotFile *pilotFile ) {
367
        gboolean retVal = TRUE;
368
        struct stat filestat;
369
        gchar *pcFile;
370

    
371
        /* Check main file */
372
        if( addrcache_check_file( pilotFile->addressCache, pilotFile->path ) )
373
                return TRUE;
374

    
375
        /* Test PC3 file */
376
        if( ! pilotFile->havePC3 ) return FALSE;
377
        pcFile = jpilot_get_pc3_file( pilotFile );
378
        if( pcFile == NULL ) return FALSE;
379

    
380
        if( 0 == g_lstat( pcFile, &filestat ) ) {
381
                if( filestat.st_mtime == pilotFile->pc3ModifyTime ) retVal = FALSE;
382
        }
383
        g_free( pcFile );
384
        return retVal;
385
}
386

    
387
/*
388
* Test whether file was modified since last access.
389
* Return: TRUE if file was modified.
390
*/
391
gboolean jpilot_get_modified( JPilotFile *pilotFile ) {
392
        g_return_val_if_fail( pilotFile != NULL, FALSE );
393
        return jpilot_check_files( pilotFile );
394
}
395
gboolean jpilot_get_accessed( JPilotFile *pilotFile ) {
396
        g_return_val_if_fail( pilotFile != NULL, FALSE );
397
        return pilotFile->accessFlag;
398
}
399

    
400
/*
401
* Free up pilot file object by releasing internal memory.
402
*/
403
void jpilot_free( JPilotFile *pilotFile ) {
404
        g_return_if_fail( pilotFile != NULL );
405

    
406
        /* Free internal stuff */
407
        g_free( pilotFile->path );
408

    
409
        /* Release custom labels */
410
        jpilot_clear_custom_labels( pilotFile );
411

    
412
        /* Clear cache */
413
        addrcache_clear( pilotFile->addressCache );
414
        addrcache_free( pilotFile->addressCache );
415
        pilotFile->addressCache = NULL;
416
        pilotFile->readMetadata = FALSE;
417
        pilotFile->accessFlag = FALSE;
418
        pilotFile->havePC3 = FALSE;
419
        pilotFile->pc3ModifyTime = 0;
420

    
421
        /* Now release file object */
422
        g_free( pilotFile );
423
}
424

    
425
/*
426
* Refresh internal variables to force a file read.
427
*/
428
void jpilot_force_refresh( JPilotFile *pilotFile ) {
429
        addrcache_refresh( pilotFile->addressCache );
430
}
431

    
432
/*
433
* Print object to specified stream.
434
*/
435
void jpilot_print_file( JPilotFile *pilotFile, FILE *stream ) {
436
        GList *node;
437

    
438
        g_return_if_fail( pilotFile != NULL );
439

    
440
        fprintf( stream, "JPilotFile:\n" );
441
        fprintf( stream, "file spec: '%s'\n", pilotFile->path );
442
        fprintf( stream, " metadata: %s\n", pilotFile->readMetadata ? "yes" : "no" );
443
        fprintf( stream, "  ret val: %d\n", pilotFile->retVal );
444

    
445
        node = pilotFile->customLabels;
446
        while( node ) {
447
                fprintf( stream, "  c label: %s\n", (gchar *)node->data );
448
                node = g_list_next( node );
449
        }
450

    
451
        node = pilotFile->labelInd;
452
        while( node ) {
453
                fprintf( stream, " labelind: %d\n", GPOINTER_TO_INT(node->data) );
454
                node = g_list_next( node );
455
        }
456

    
457
        addrcache_print( pilotFile->addressCache, stream );
458
        fprintf( stream, "  ret val: %d\n", pilotFile->retVal );
459
        fprintf( stream, " have pc3: %s\n", pilotFile->havePC3 ? "yes" : "no" );
460
        fprintf( stream, " pc3 time: %lu\n", pilotFile->pc3ModifyTime );
461
        addritem_print_item_folder( pilotFile->addressCache->rootFolder, stream );
462
}
463

    
464
/*
465
* Print summary of object to specified stream.
466
*/
467
void jpilot_print_short( JPilotFile *pilotFile, FILE *stream ) {
468
        GList *node;
469
        g_return_if_fail( pilotFile != NULL );
470
        fprintf( stream, "JPilotFile:\n" );
471
        fprintf( stream, "file spec: '%s'\n", pilotFile->path );
472
        fprintf( stream, " metadata: %s\n", pilotFile->readMetadata ? "yes" : "no" );
473
        fprintf( stream, "  ret val: %d\n", pilotFile->retVal );
474

    
475
        node = pilotFile->customLabels;
476
        while( node ) {
477
                fprintf( stream, "  c label: %s\n", (gchar *)node->data );
478
                node = g_list_next( node );
479
        }
480

    
481
        node = pilotFile->labelInd;
482
        while( node ) {
483
                fprintf( stream, " labelind: %d\n", GPOINTER_TO_INT(node->data) );
484
                node = g_list_next( node );
485
        }
486
        addrcache_print( pilotFile->addressCache, stream );
487
        fprintf( stream, " have pc3: %s\n", pilotFile->havePC3 ? "yes" : "no" );
488
        fprintf( stream, " pc3 time: %lu\n", pilotFile->pc3ModifyTime );
489
}
490

    
491
/* Shamelessly copied from JPilot (libplugin.c) */
492
static unsigned int bytes_to_bin(unsigned char *bytes, unsigned int num_bytes) {
493
unsigned int i, n;
494
        n=0;
495
        for (i=0;i<num_bytes;i++) {
496
                n = n*256+bytes[i];
497
        }
498
        return n;
499
}
500

    
501
/* Shamelessly copied from JPilot (utils.c) */
502
/* These next 2 functions were copied from pi-file.c in the pilot-link app */
503
/* Exact value of "Jan 1, 1970 0:00:00 GMT" - "Jan 1, 1904 0:00:00 GMT" */
504
#define PILOT_TIME_DELTA (unsigned)(2082844800)
505

    
506
time_t pilot_time_to_unix_time ( unsigned long raw_time ) {
507
   return (time_t)(raw_time - PILOT_TIME_DELTA);
508
}
509

    
510
/* Shamelessly copied from JPilot (libplugin.c) */
511
static int raw_header_to_header(RawDBHeader *rdbh, DBHeader *dbh) {
512
        unsigned long temp;
513

    
514
        strncpy(dbh->db_name, (gchar *)rdbh->db_name, 31);
515
        dbh->db_name[31] = '\0';
516
        dbh->flags = bytes_to_bin(rdbh->flags, 2);
517
        dbh->version = bytes_to_bin(rdbh->version, 2);
518
        temp = bytes_to_bin(rdbh->creation_time, 4);
519
        dbh->creation_time = pilot_time_to_unix_time(temp);
520
        temp = bytes_to_bin(rdbh->modification_time, 4);
521
        dbh->modification_time = pilot_time_to_unix_time(temp);
522
        temp = bytes_to_bin(rdbh->backup_time, 4);
523
        dbh->backup_time = pilot_time_to_unix_time(temp);
524
        dbh->modification_number = bytes_to_bin(rdbh->modification_number, 4);
525
        dbh->app_info_offset = bytes_to_bin(rdbh->app_info_offset, 4);
526
        dbh->sort_info_offset = bytes_to_bin(rdbh->sort_info_offset, 4);
527
        strncpy(dbh->type, (gchar *)rdbh->type, 4);
528
        dbh->type[4] = '\0';
529
        strncpy(dbh->creator_id, (gchar *)rdbh->creator_id, 4);
530
        dbh->creator_id[4] = '\0';
531
        strncpy(dbh->unique_id_seed, (gchar *)rdbh->unique_id_seed, 4);
532
        dbh->unique_id_seed[4] = '\0';
533
        dbh->next_record_list_id = bytes_to_bin(rdbh->next_record_list_id, 4);
534
        dbh->number_of_records = bytes_to_bin(rdbh->number_of_records, 2);
535
        return 0;
536
}
537

    
538
/* Shamelessly copied from JPilot (libplugin.c) */
539
/* returns 1 if found */
540
/*         0 if eof */
541
static int find_next_offset( mem_rec_header *mem_rh, long fpos,
542
        unsigned int *next_offset, unsigned char *attrib, unsigned int *unique_id )
543
{
544
        mem_rec_header *temp_mem_rh;
545
        unsigned char found = 0;
546
        unsigned long found_at;
547

    
548
        found_at=0xFFFFFF;
549
        for (temp_mem_rh=mem_rh; temp_mem_rh; temp_mem_rh = temp_mem_rh->next) {
550
                if ((temp_mem_rh->offset > fpos) && (temp_mem_rh->offset < found_at)) {
551
                        found_at = temp_mem_rh->offset;
552
                        /* *attrib = temp_mem_rh->attrib; */
553
                        /* *unique_id = temp_mem_rh->unique_id; */
554
                }
555
                if ((temp_mem_rh->offset == fpos)) {
556
                        found = 1;
557
                        *attrib = temp_mem_rh->attrib;
558
                        *unique_id = temp_mem_rh->unique_id;
559
                }
560
        }
561
        *next_offset = found_at;
562
        return found;
563
}
564

    
565
/* Shamelessly copied from JPilot (libplugin.c) */
566
static void free_mem_rec_header(mem_rec_header **mem_rh) {
567
        mem_rec_header *h, *next_h;
568
        for (h=*mem_rh; h; h=next_h) {
569
                next_h=h->next;
570
                free(h);
571
        }
572
        *mem_rh = NULL;
573
}
574

    
575
#if 0
576
/* Shamelessly copied from JPilot (libplugin.c) */
577
static int jpilot_free_db_list( GList **br_list ) {
578
        GList *temp_list, *first;
579
        buf_rec *br;
580

581
        /* Go to first entry in the list */
582
        first=NULL;
583
        for( temp_list = *br_list; temp_list; temp_list = temp_list->prev ) {
584
                first = temp_list;
585
        }
586
        for (temp_list = first; temp_list; temp_list = temp_list->next) {
587
                if (temp_list->data) {
588
                        br=temp_list->data;
589
                        if (br->buf) {
590
                                free(br->buf);
591
                                temp_list->data=NULL;
592
                        }
593
                        free(br);
594
                }
595
        }
596
        g_list_free(*br_list);
597
        *br_list=NULL;
598
        return 0;
599
}
600
#endif
601

    
602
/* Shamelessly copied from JPilot (libplugin.c) */
603
/* Read file size */
604
static int jpilot_get_info_size( FILE *in, unsigned int *size ) {
605
        RawDBHeader rdbh;
606
        DBHeader dbh;
607
        unsigned int offset;
608
        record_header rh;
609

    
610
        fseek(in, 0, SEEK_SET);
611
        fread(&rdbh, sizeof(RawDBHeader), 1, in);
612
        if (feof(in)) {
613
                return MGU_EOF;
614
        }
615

    
616
        raw_header_to_header(&rdbh, &dbh);
617
        if (dbh.app_info_offset==0) {
618
                *size=0;
619
                return MGU_SUCCESS;
620
        }
621
        if (dbh.sort_info_offset!=0) {
622
                *size = dbh.sort_info_offset - dbh.app_info_offset;
623
                return MGU_SUCCESS;
624
        }
625
        if (dbh.number_of_records==0) {
626
                fseek(in, 0, SEEK_END);
627
                *size=ftell(in) - dbh.app_info_offset;
628
                return MGU_SUCCESS;
629
        }
630

    
631
        fread(&rh, sizeof(record_header), 1, in);
632
        offset = ((rh.Offset[0]*256+rh.Offset[1])*256+rh.Offset[2])*256+rh.Offset[3];
633
        *size=offset - dbh.app_info_offset;
634

    
635
        return MGU_SUCCESS;
636
}
637

    
638
/*
639
 * Read address file into address list. Based on JPilot's
640
 * libplugin.c (jp_get_app_info)
641
 */
642
static gint jpilot_get_file_info( JPilotFile *pilotFile, unsigned char **buf, unsigned int *buf_size ) {
643
        FILE *in;
644
         int num;
645
        unsigned int rec_size;
646
        RawDBHeader rdbh;
647
        DBHeader dbh;
648

    
649
        if( ( !buf_size ) || ( ! buf ) ) {
650
                return MGU_BAD_ARGS;
651
        }
652

    
653
        *buf = NULL;
654
        *buf_size=0;
655

    
656
        if( pilotFile->path ) {
657
                in = g_fopen( pilotFile->path, "rb" );
658
                if( !in ) {
659
                        return MGU_OPEN_FILE;
660
                }
661
        }
662
        else {
663
                return MGU_NO_FILE;
664
        }
665

    
666
        num = fread( &rdbh, sizeof( RawDBHeader ), 1, in );
667
        if( num != 1 ) {
668
                  if( ferror(in) ) {
669
                        fclose(in);
670
                        return MGU_ERROR_READ;
671
                }
672
        }
673
        if (feof(in)) {
674
                fclose(in);
675
                return MGU_EOF;
676
        }
677

    
678
        /* Convert header into something recognizable */
679
        raw_header_to_header(&rdbh, &dbh);
680

    
681
        num = jpilot_get_info_size(in, &rec_size);
682
        if (num) {
683
                fclose(in);
684
                return MGU_ERROR_READ;
685
        }
686

    
687
        fseek(in, dbh.app_info_offset, SEEK_SET);
688
        *buf = ( unsigned char * ) malloc(rec_size);
689
        if (!(*buf)) {
690
                fclose(in);
691
                return MGU_OO_MEMORY;
692
        }
693
        num = fread(*buf, rec_size, 1, in);
694
        if (num != 1) {
695
                if (ferror(in)) {
696
                        fclose(in);
697
                        free(*buf);
698
                        return MGU_ERROR_READ;
699
                }
700
        }
701
        fclose(in);
702

    
703
        *buf_size = rec_size;
704

    
705
        return MGU_SUCCESS;
706
}
707

    
708
/* Shamelessly copied from JPilot (libplugin.c) */
709
static int unpack_header(PC3RecordHeader *header, unsigned char *packed_header) {
710
        unsigned char *p;
711
        unsigned long l;
712

    
713
        p = packed_header;
714

    
715
        memcpy(&l, p, sizeof(l));
716
        header->header_len=ntohl(l);
717
        p+=sizeof(l);
718

    
719
        memcpy(&l, p, sizeof(l));
720
        header->header_version=ntohl(l);
721
        p+=sizeof(l);
722

    
723
        memcpy(&l, p, sizeof(l));
724
        header->rec_len=ntohl(l);
725
        p+=sizeof(l);
726

    
727
        memcpy(&l, p, sizeof(l));
728
        header->unique_id=ntohl(l);
729
        p+=sizeof(l);
730

    
731
        memcpy(&l, p, sizeof(l));
732
        header->rt=ntohl(l);
733
        p+=sizeof(l);
734

    
735
        memcpy(&(header->attrib), p, sizeof(unsigned char));
736
        p+=sizeof(unsigned char);
737

    
738
        return 0;
739
}
740

    
741
/* Shamelessly copied from JPilot (libplugin.c) */
742
static int read_header(FILE *pc_in, PC3RecordHeader *header) {
743
        unsigned long l, len;
744
        unsigned char packed_header[256];
745
        int num;
746

    
747
        num = fread(&l, sizeof(l), 1, pc_in);
748
        if (feof(pc_in)) {
749
                return -1;
750
        }
751
        if (num!=1) {
752
                return num;
753
        }
754
        memcpy(packed_header, &l, sizeof(l));
755
        len=ntohl(l);
756
        if (len > 255) {
757
                return -1;
758
        }
759
        num = fread(packed_header+sizeof(l), len-sizeof(l), 1, pc_in);
760
        if (feof(pc_in)) {
761
                return -1;
762
        }
763
        if (num!=1) {
764
                return num;
765
        }
766
        unpack_header(header, packed_header);
767
        return 1;
768
}
769

    
770
/* Read next record from PC3 file. Based on JPilot's
771
 * pc_read_next_rec (libplugin.c) */
772
static gint jpilot_read_next_pc( FILE *in, buf_rec *br ) {
773
        PC3RecordHeader header;
774
        int rec_len, num;
775
        char *record;
776

    
777
        if(feof(in)) {
778
                return MGU_EOF;
779
        }
780
        num = read_header(in, &header);
781
        if (num < 1) {
782
                if (ferror(in)) {
783
                        return MGU_ERROR_READ;
784
                }
785
                if (feof(in)) {
786
                        return MGU_EOF;
787
                }
788
        }
789
        rec_len = header.rec_len;
790
        record = malloc(rec_len);
791
        if (!record) {
792
                return MGU_OO_MEMORY;
793
        }
794
        num = fread(record, rec_len, 1, in);
795
        if (num != 1) {
796
                if (ferror(in)) {
797
                        free(record);
798
                        return MGU_ERROR_READ;
799
                }
800
        }
801
        br->rt = header.rt;
802
        br->unique_id = header.unique_id;
803
        br->attrib = header.attrib;
804
        br->buf = record;
805
        br->size = rec_len;
806

    
807
        return MGU_SUCCESS;
808
}
809

    
810
/*
811
 * Read address file into a linked list. Based on JPilot's
812
 * jp_read_DB_files (from libplugin.c)
813
 */
814
static gint jpilot_read_db_files( JPilotFile *pilotFile, GList **records ) {
815
        FILE *in, *pc_in;
816
        char *buf;
817
        GList *temp_list;
818
        int num_records, recs_returned, i, num, r;
819
        unsigned int offset, prev_offset, next_offset, rec_size;
820
        int out_of_order;
821
        long fpos;  /*file position indicator */
822
        unsigned char attrib;
823
        unsigned int unique_id;
824
        mem_rec_header *mem_rh, *temp_mem_rh, *last_mem_rh;
825
        record_header rh;
826
        RawDBHeader rdbh;
827
        DBHeader dbh;
828
        buf_rec *temp_br;
829
        gchar *pcFile;
830

    
831
        mem_rh = last_mem_rh = NULL;
832
        *records = NULL;
833
        recs_returned = 0;
834

    
835
        if( pilotFile->path == NULL ) {
836
                return MGU_BAD_ARGS;
837
        }
838

    
839
        in = g_fopen( pilotFile->path, "rb" );
840
        if (!in) {
841
                return MGU_OPEN_FILE;
842
        }
843

    
844
        /* Read the database header */
845
        num = fread(&rdbh, sizeof(RawDBHeader), 1, in);
846
        if (num != 1) {
847
                if (ferror(in)) {
848
                        fclose(in);
849
                        return MGU_ERROR_READ;
850
                }
851
                if (feof(in)) {
852
                        fclose(in);
853
                        return MGU_EOF;
854
                }
855
        }
856
        raw_header_to_header(&rdbh, &dbh);
857

    
858
        /* Read each record entry header */
859
        num_records = dbh.number_of_records;
860
        out_of_order = 0;
861
        prev_offset = 0;
862

    
863
        for (i = 1; i < num_records + 1; i++) {
864
                num = fread(&rh, sizeof(record_header), 1, in);
865
                if (num != 1) {
866
                        if (ferror(in)) {
867
                                break;
868
                        }
869
                        if (feof(in)) {
870
                                free_mem_rec_header(&mem_rh);
871
                                fclose(in);
872
                                return MGU_EOF;
873
                        }
874
                }
875

    
876
                offset = ((rh.Offset[0]*256+rh.Offset[1])*256+rh.Offset[2])*256+rh.Offset[3];
877
                if (offset < prev_offset) {
878
                        out_of_order = 1;
879
                }
880
                prev_offset = offset;
881
                temp_mem_rh = (mem_rec_header *)malloc(sizeof(mem_rec_header));
882
                if (!temp_mem_rh) {
883
                        break;
884
                }
885
                temp_mem_rh->next = NULL;
886
                temp_mem_rh->rec_num = i;
887
                temp_mem_rh->offset = offset;
888
                temp_mem_rh->attrib = rh.attrib;
889
                temp_mem_rh->unique_id = (rh.unique_ID[0]*256+rh.unique_ID[1])*256+rh.unique_ID[2];
890
                if (mem_rh == NULL) {
891
                        mem_rh = temp_mem_rh;
892
                        last_mem_rh = temp_mem_rh;
893
                } else {
894
                        last_mem_rh->next = temp_mem_rh;
895
                        last_mem_rh = temp_mem_rh;
896
                }
897
        }
898

    
899
        temp_mem_rh = mem_rh;
900

    
901
        if (num_records) {
902
                if (out_of_order) {
903
                        find_next_offset(mem_rh, 0, &next_offset, &attrib, &unique_id);
904
                } else {
905
                        if (mem_rh) {
906
                                next_offset = mem_rh->offset;
907
                                attrib = mem_rh->attrib;
908
                                unique_id = mem_rh->unique_id;
909
                        }
910
                }
911
                fseek(in, next_offset, SEEK_SET);
912
                while(!feof(in)) {
913
                        fpos = ftell(in);
914
                        if (out_of_order) {
915
                                find_next_offset(mem_rh, fpos, &next_offset, &attrib, &unique_id);
916
                        } else {
917
                                next_offset = 0xFFFFFF;
918
                                if (temp_mem_rh) {
919
                                        attrib = temp_mem_rh->attrib;
920
                                        unique_id = temp_mem_rh->unique_id;
921
                                        if (temp_mem_rh->next) {
922
                                                temp_mem_rh = temp_mem_rh->next;
923
                                                next_offset = temp_mem_rh->offset;
924
                                        }
925
                                }
926
                        }
927
                        rec_size = next_offset - fpos;
928
                        buf = malloc(rec_size);
929
                        if (!buf) break;
930
                        num = fread(buf, rec_size, 1, in);
931
                        if ((num != 1)) {
932
                                if (ferror(in)) {
933
                                        free(buf);
934
                                        break;
935
                                }
936
                        }
937

    
938
                        temp_br = malloc(sizeof(buf_rec));
939
                        if (!temp_br) {
940
                                free(buf);
941
                                break;
942
                        }
943
                        temp_br->rt = PALM_REC;
944
                        temp_br->unique_id = unique_id;
945
                        temp_br->attrib = attrib;
946
                        temp_br->buf = buf;
947
                        temp_br->size = rec_size;
948

    
949
                        *records = g_list_append(*records, temp_br);
950

    
951
                        recs_returned++;
952
                }
953
        }
954
        fclose(in);
955
        free_mem_rec_header(&mem_rh);
956

    
957
        /* Read the PC3 file, if present */
958
        pcFile = jpilot_get_pc3_file( pilotFile );
959
        if( pcFile == NULL ) return MGU_SUCCESS;
960
        pc_in = g_fopen( pcFile, "rb");
961
        g_free( pcFile );
962

    
963
        if( pc_in == NULL ) {
964
                return MGU_SUCCESS;
965
        }
966

    
967
        while( ! feof( pc_in ) ) {
968
                temp_br = malloc(sizeof(buf_rec));
969
                if (!temp_br) {
970
                        break;
971
                }
972
                r = jpilot_read_next_pc( pc_in, temp_br );
973
                if ( r != MGU_SUCCESS ) {
974
                        free(temp_br);
975
                        break;
976
                }
977
                if ((temp_br->rt!=DELETED_PC_REC)
978
                        &&(temp_br->rt!=DELETED_PALM_REC)
979
                        &&(temp_br->rt!=MODIFIED_PALM_REC)
980
                        &&(temp_br->rt!=DELETED_DELETED_PALM_REC)) {
981
                                *records = g_list_append(*records, temp_br);
982
                                recs_returned++;
983
                }
984
                if ((temp_br->rt==DELETED_PALM_REC) || (temp_br->rt==MODIFIED_PALM_REC)) {
985
                        temp_list=*records;
986
                        if (*records) {
987
                                while(temp_list->next) {
988
                                        temp_list=temp_list->next;
989
                                }
990
                        }
991
                        for (; temp_list; temp_list=temp_list->prev) {
992
                                if (((buf_rec *)temp_list->data)->unique_id == temp_br->unique_id) {
993
                                        ((buf_rec *)temp_list->data)->rt = temp_br->rt;
994
                                }
995
                        }
996
                }
997
                free(temp_br);
998
        }
999
        fclose(pc_in);
1000

    
1001
        return MGU_SUCCESS;
1002
}
1003

    
1004
#define FULLNAME_BUFSIZE        256
1005
#define EMAIL_BUFSIZE                256
1006
/*
1007
 * Unpack address, building new data inside cache.
1008
 */
1009
static void jpilot_load_address( JPilotFile *pilotFile, buf_rec *buf, ItemFolder *folderInd[] ) {
1010
        struct Address addr;
1011
        gchar **addrEnt;
1012
        gint num, k;
1013
        gint cat_id = 0;
1014
        guint unique_id;
1015
        guchar attrib;
1016
        gchar fullName[ FULLNAME_BUFSIZE ];
1017
        gchar bufEMail[ EMAIL_BUFSIZE ];
1018
        ItemPerson *person;
1019
        ItemEMail *email;
1020
        gint *indPhoneLbl;
1021
        gchar *labelEntry;
1022
        GList *node;
1023
        gchar* extID;
1024
        struct AddressAppInfo *ai;
1025
        gchar **firstName = NULL;
1026
        gchar **lastName = NULL;
1027
#if (PILOT_LINK_MAJOR > 11)
1028
        pi_buffer_t *RecordBuffer;
1029
#endif /* PILOT_LINK_0_12 */
1030

    
1031
        /* Retrieve address */
1032
#if (PILOT_LINK_MAJOR < 12)
1033
        num = unpack_Address( & addr, buf->buf, buf->size );
1034
        if( num > 0 ) {
1035
#else /* PILOT_LINK_0_12 */
1036
        RecordBuffer = pi_buffer_new(buf->size);
1037
        memcpy(RecordBuffer->data, buf->buf, buf->size);
1038
        RecordBuffer->used = buf->size;
1039
        num = unpack_Address( & addr, RecordBuffer, address_v1 );
1040
        pi_buffer_free(RecordBuffer);
1041
        if (num != -1) {
1042
#endif
1043
                gchar *nameConv;
1044

    
1045
                addrEnt = addr.entry;
1046
                attrib = buf->attrib;
1047
                unique_id = buf->unique_id;
1048
                cat_id = attrib & 0x0F;
1049

    
1050
                *fullName = *bufEMail = '\0';
1051

    
1052
                if( addrEnt[ IND_LABEL_FIRSTNAME ] ) {
1053
                        firstName = g_strsplit( addrEnt[ IND_LABEL_FIRSTNAME ], "\01", 2 );
1054
                }
1055
                if( addrEnt[ IND_LABEL_LASTNAME ] ) {
1056
                        lastName = g_strsplit( addrEnt[ IND_LABEL_LASTNAME ], "\01", 2 );
1057
                }
1058

    
1059
                if( name_order == FAMILY_LAST ) {
1060
                        g_snprintf( fullName, FULLNAME_BUFSIZE, "%s %s",
1061
                                    firstName ? firstName[0] : "",
1062
                                    lastName ? lastName[0] : "" );
1063
                }
1064
                else {
1065
                        g_snprintf( fullName, FULLNAME_BUFSIZE, "%s %s",
1066
                                    lastName ? lastName[0] : "",
1067
                                    firstName ? firstName[0] : "" );
1068
                }
1069

    
1070
                if( firstName ) {
1071
                        g_strfreev( firstName );
1072
                }
1073
                if( lastName ) {
1074
                        g_strfreev( lastName );
1075
                }
1076

    
1077
                g_strstrip( fullName );
1078

    
1079
                nameConv = jpilot_convert_encoding( fullName );
1080
                strncpy2( fullName, nameConv, FULLNAME_BUFSIZE );
1081
                g_free( nameConv );
1082

    
1083
                person = addritem_create_item_person();
1084
                addritem_person_set_common_name( person, fullName );
1085
                addritem_person_set_first_name( person, addrEnt[ IND_LABEL_FIRSTNAME ] );
1086
                addritem_person_set_last_name( person, addrEnt[ IND_LABEL_LASTNAME ] );
1087
                addrcache_id_person( pilotFile->addressCache, person );
1088

    
1089
                extID = g_strdup_printf( "%d", unique_id );
1090
                addritem_person_set_external_id( person, extID );
1091
                g_free( extID );
1092
                extID = NULL;
1093

    
1094
                /* Pointer to address metadata. */
1095
                ai = & pilotFile->addrInfo;
1096

    
1097
                /* Add entry for each email address listed under phone labels. */
1098
                indPhoneLbl = addr.phoneLabel;
1099
                for( k = 0; k < JPILOT_NUM_ADDR_PHONE; k++ ) {
1100
                        gint ind;
1101

    
1102
                        ind = indPhoneLbl[k];
1103
                        /*
1104
                        * fprintf( stdout, "%d : %d : %20s : %s\n", k, ind,
1105
                        * ai->phoneLabels[ind], addrEnt[3+k] );
1106
                        */
1107
                        if( indPhoneLbl[k] == IND_PHONE_EMAIL ) {
1108
                                labelEntry = addrEnt[ OFFSET_PHONE_LABEL + k ];
1109
                                if( labelEntry ) {
1110
                                        strcpy( bufEMail, labelEntry );
1111
                                        g_strchug( bufEMail );
1112
                                        g_strchomp( bufEMail );
1113

    
1114
                                        email = addritem_create_item_email();
1115
                                        addritem_email_set_address( email, bufEMail );
1116
                                        addrcache_id_email( pilotFile->addressCache, email );
1117
                                        addrcache_person_add_email
1118
                                                ( pilotFile->addressCache, person, email );
1119
                                }
1120
                        }
1121
                }
1122

    
1123
                /* Add entry for each custom label */
1124
                node = pilotFile->labelInd;
1125
                while( node ) {
1126
                        gint ind;
1127

    
1128
                        ind = GPOINTER_TO_INT( node->data );
1129
                        if( ind > -1 ) {
1130
                                /*
1131
                                * fprintf( stdout, "%d : %20s : %s\n", ind, ai->labels[ind],
1132
                                * addrEnt[ind] );
1133
                                */
1134
                                labelEntry = addrEnt[ind];
1135
                                if( labelEntry ) {
1136
                                        gchar *convertBuff;
1137

    
1138
                                        strcpy( bufEMail, labelEntry );
1139
                                        g_strchug( bufEMail );
1140
                                        g_strchomp( bufEMail );
1141

    
1142
                                        email = addritem_create_item_email();
1143
                                        addritem_email_set_address( email, bufEMail );
1144

    
1145
                                        convertBuff = jpilot_convert_encoding( ai->labels[ind] );
1146
                                        addritem_email_set_remarks( email, convertBuff );
1147
                                        g_free( convertBuff );
1148

    
1149
                                        addrcache_id_email( pilotFile->addressCache, email );
1150
                                        addrcache_person_add_email
1151
                                                ( pilotFile->addressCache, person, email );
1152
                                }
1153
                        }
1154

    
1155
                        node = g_list_next( node );
1156
                }
1157

    
1158
                if( person->listEMail ) {
1159
                        if( cat_id > -1 && cat_id < JPILOT_NUM_CATEG ) {
1160
                                /* Add to specified category */
1161
                                addrcache_folder_add_person
1162
                                        ( pilotFile->addressCache, folderInd[cat_id], person );
1163
                        }
1164
                        else {
1165
                                /* Add to root folder */
1166
                                addrcache_add_person( pilotFile->addressCache, person );
1167
                        }
1168
                }
1169
                else {
1170
                        addritem_free_item_person( person );
1171
                        person = NULL;
1172
                }
1173
        }
1174
}
1175

    
1176
/*
1177
 * Free up address list.
1178
 */
1179
static void jpilot_free_addrlist( GList *records ) {
1180
        GList *node;
1181
        buf_rec *br;
1182

    
1183
        node = records;
1184
        while( node ) {
1185
                br = node->data;
1186
                free( br );
1187
                node->data = NULL;
1188
                node = g_list_next( node );
1189
        }
1190

    
1191
        /* Free up list */
1192
        g_list_free( records );
1193
}
1194

    
1195
/*
1196
 * Read address file into address cache.
1197
 */
1198
static gint jpilot_read_file( JPilotFile *pilotFile ) {
1199
        gint retVal, i;
1200
        GList *records = NULL;
1201
        GList *node;
1202
        buf_rec *br;
1203
        ItemFolder *folderInd[ JPILOT_NUM_CATEG ];
1204

    
1205
        retVal = jpilot_read_db_files( pilotFile, &records );
1206
        if( retVal != MGU_SUCCESS ) {
1207
                jpilot_free_addrlist( records );
1208
                return retVal;
1209
        }
1210

    
1211
        /* Build array of pointers to categories */
1212
        i = 0;
1213
        node = addrcache_get_list_folder( pilotFile->addressCache );
1214
        while( node ) {
1215
                if( i < JPILOT_NUM_CATEG ) {
1216
                        folderInd[i] = node->data;
1217
                }
1218
                node = g_list_next( node );
1219
                i++;
1220
        }
1221

    
1222
        /* Load all addresses, free up old stuff as we go */
1223
        node = records;
1224
        while( node ) {
1225
                br = node->data;
1226
                if( ( br->rt != DELETED_PC_REC ) &&
1227
                    ( br->rt != DELETED_PALM_REC ) &&
1228
                    ( br->rt != MODIFIED_PALM_REC ) &&
1229
                    ( br->rt != DELETED_DELETED_PALM_REC ) ) {
1230
                        jpilot_load_address( pilotFile, br, folderInd );
1231
                }
1232
                free( br );
1233
                node->data = NULL;
1234
                node = g_list_next( node );
1235
        }
1236

    
1237
        /* Free up list */
1238
        g_list_free( records );
1239

    
1240
        return retVal;
1241
}
1242

    
1243

    
1244
/*
1245
* Read metadata from file.
1246
*/
1247
static gint jpilot_read_metadata( JPilotFile *pilotFile ) {
1248
        gint retVal;
1249
        unsigned int rec_size;
1250
        unsigned char *buf;
1251
        int num;
1252

    
1253
        g_return_val_if_fail( pilotFile != NULL, -1 );
1254

    
1255
        pilotFile->readMetadata = FALSE;
1256
        addrcache_clear( pilotFile->addressCache );
1257

    
1258
        /* Read file info */
1259
        retVal = jpilot_get_file_info( pilotFile, &buf, &rec_size);
1260
        if( retVal != MGU_SUCCESS ) {
1261
                pilotFile->retVal = retVal;
1262
                return pilotFile->retVal;
1263
        }
1264

    
1265
        num = unpack_AddressAppInfo( &pilotFile->addrInfo, buf, rec_size );
1266
        if( buf ) {
1267
                free(buf);
1268
        }
1269
        if( num <= 0 ) {
1270
                pilotFile->retVal = MGU_ERROR_READ;
1271
                return pilotFile->retVal;
1272
        }
1273

    
1274
        pilotFile->readMetadata = TRUE;
1275
        pilotFile->retVal = MGU_SUCCESS;
1276
        return pilotFile->retVal;
1277
}
1278

    
1279
/*
1280
* Setup labels and indexes from metadata.
1281
* Return: TRUE is setup successfully.
1282
*/
1283
static gboolean jpilot_setup_labels( JPilotFile *pilotFile ) {
1284
        gboolean retVal = FALSE;
1285
        struct AddressAppInfo *ai;
1286
        GList *node;
1287

    
1288
        g_return_val_if_fail( pilotFile != NULL, -1 );
1289

    
1290
        /* Release indexes */
1291
        node = pilotFile->labelInd;
1292
        while( node ) {
1293
                node->data = NULL;
1294
                node = g_list_next( node );
1295
        }
1296
        pilotFile->labelInd = NULL;
1297

    
1298
        if( pilotFile->readMetadata ) {
1299
                ai = & pilotFile->addrInfo;
1300
                node = pilotFile->customLabels;
1301
                while( node ) {
1302
                        gchar *lbl = node->data;
1303
                        gint ind = -1;
1304
                        gint i;
1305
                        for( i = 0; i < JPILOT_NUM_LABELS; i++ ) {
1306
                                gchar *labelName;
1307
                                gchar convertBuff[ JPILOT_LEN_LABEL ];
1308

    
1309
                                labelName = jpilot_convert_encoding( ai->labels[i] );
1310
                                strncpy2( convertBuff, labelName, JPILOT_LEN_LABEL );
1311
                                g_free( labelName );
1312
                                labelName = convertBuff;
1313

    
1314
                                if( g_ascii_strcasecmp( labelName, lbl ) == 0 ) {
1315
                                        ind = i;
1316
                                        break;
1317
                                }
1318
                        }
1319
                        pilotFile->labelInd = g_list_append( pilotFile->labelInd, GINT_TO_POINTER(ind) );
1320
                        node = g_list_next( node );
1321
                }
1322
                retVal = TRUE;
1323
        }
1324
        return retVal;
1325
}
1326

    
1327
/*
1328
* Load list with character strings of label names.
1329
*/
1330
GList *jpilot_load_label( JPilotFile *pilotFile, GList *labelList ) {
1331
        int i;
1332

    
1333
        g_return_val_if_fail( pilotFile != NULL, NULL );
1334

    
1335
        if( pilotFile->readMetadata ) {
1336
                struct AddressAppInfo *ai = & pilotFile->addrInfo;
1337
                for( i = 0; i < JPILOT_NUM_LABELS; i++ ) {
1338
                        gchar *labelName = ai->labels[i];
1339

    
1340
                        if( labelName ) {
1341
                                labelName = jpilot_convert_encoding( labelName );
1342
                                labelList = g_list_append( labelList, labelName );
1343
                        }
1344
                        else {
1345
                                labelList = g_list_append( labelList, g_strdup( "" ) );
1346
                        }
1347
                }
1348
        }
1349
        return labelList;
1350
}
1351

    
1352
/*
1353
* Return category name for specified category ID.
1354
* Enter:  Category ID.
1355
* Return: Name, or empty string if not invalid ID. Name should be g_free() when done.
1356
*/
1357
gchar *jpilot_get_category_name( JPilotFile *pilotFile, gint catID ) {
1358
        gchar *catName = NULL;
1359

    
1360
        g_return_val_if_fail( pilotFile != NULL, NULL );
1361

    
1362
        if( pilotFile->readMetadata ) {
1363
                struct AddressAppInfo *ai = & pilotFile->addrInfo;
1364
                struct CategoryAppInfo *cat = &        ai->category;
1365
                if( catID < 0 || catID > JPILOT_NUM_CATEG ) {
1366
                }
1367
                else {
1368
                        catName = g_strdup( cat->name[catID] );
1369
                }
1370
        }
1371
        if( ! catName ) catName = g_strdup( "" );
1372
        return catName;
1373
}
1374

    
1375
/*
1376
* Load list with character strings of phone label names.
1377
*/
1378
GList *jpilot_load_phone_label( JPilotFile *pilotFile, GList *labelList ) {
1379
        gint i;
1380

    
1381
        g_return_val_if_fail( pilotFile != NULL, NULL );
1382

    
1383
        if( pilotFile->readMetadata ) {
1384
                struct AddressAppInfo *ai = & pilotFile->addrInfo;
1385
                for( i = 0; i < JPILOT_NUM_PHONELABELS; i++ ) {
1386
                        gchar        *labelName = ai->phoneLabels[i];
1387
                        if( labelName ) {
1388
                                labelList = g_list_append( labelList, g_strdup( labelName ) );
1389
                        }
1390
                        else {
1391
                                labelList = g_list_append( labelList, g_strdup( "" ) );
1392
                        }
1393
                }
1394
        }
1395
        return labelList;
1396
}
1397

    
1398
/*
1399
* Load list with character strings of label names. Only none blank names
1400
* are loaded.
1401
*/
1402
GList *jpilot_load_custom_label( JPilotFile *pilotFile, GList *labelList ) {
1403
        gint i;
1404

    
1405
        g_return_val_if_fail( pilotFile != NULL, NULL );
1406

    
1407
        if( pilotFile->readMetadata ) {
1408
                struct AddressAppInfo *ai = & pilotFile->addrInfo;
1409
                for( i = 0; i < NUM_CUSTOM_LABEL; i++ ) {
1410
                        gchar *labelName = ai->labels[i+IND_CUSTOM_LABEL];
1411
                        if( labelName ) {
1412
                                g_strchomp( labelName );
1413
                                g_strchug( labelName );
1414
                                if( *labelName != '\0' ) {
1415
                                        labelName = jpilot_convert_encoding( labelName );
1416
                                        labelList = g_list_append( labelList, labelName );
1417
                                }
1418
                        }
1419
                }
1420
        }
1421
        return labelList;
1422
}
1423

    
1424
/*
1425
* Load list with character strings of category names.
1426
*/
1427
GList *jpilot_get_category_list( JPilotFile *pilotFile ) {
1428
        GList *catList = NULL;
1429
        gint i;
1430

    
1431
        g_return_val_if_fail( pilotFile != NULL, NULL );
1432

    
1433
        if( pilotFile->readMetadata ) {
1434
                struct AddressAppInfo *ai = & pilotFile->addrInfo;
1435
                struct CategoryAppInfo *cat = &        ai->category;
1436
                for( i = 0; i < JPILOT_NUM_CATEG; i++ ) {
1437
                        gchar *catName = cat->name[i];
1438
                        if( catName ) {
1439
                                catList = g_list_append( catList, g_strdup( catName ) );
1440
                        }
1441
                        else {
1442
                                catList = g_list_append( catList, g_strdup( "" ) );
1443
                        }
1444
                }
1445
        }
1446
        return catList;
1447
}
1448

    
1449
/*
1450
* Build folder for each category.
1451
*/
1452
static void jpilot_build_category_list( JPilotFile *pilotFile ) {
1453
        struct AddressAppInfo *ai = & pilotFile->addrInfo;
1454
        struct CategoryAppInfo *cat = &        ai->category;
1455
        gint i;
1456

    
1457
        for( i = 0; i < JPILOT_NUM_CATEG; i++ ) {
1458
                ItemFolder *folder = addritem_create_item_folder();
1459
                gchar *catName;
1460

    
1461
                catName = jpilot_convert_encoding( cat->name[i] );
1462
                addritem_folder_set_name( folder, catName );
1463
                g_free( catName );
1464

    
1465
                addrcache_id_folder( pilotFile->addressCache, folder );
1466
                addrcache_add_folder( pilotFile->addressCache, folder );
1467
        }
1468
}
1469

    
1470
/*
1471
* Remove empty folders (categories).
1472
*/
1473
static void jpilot_remove_empty( JPilotFile *pilotFile ) {
1474
        GList *listFolder;
1475
        GList *remList;
1476
        GList *node;
1477
        gint i = 0;
1478

    
1479
        listFolder = addrcache_get_list_folder( pilotFile->addressCache );
1480
        node = listFolder;
1481
        remList = NULL;
1482
        while( node ) {
1483
                ItemFolder *folder = node->data;
1484
                if( ADDRITEM_NAME(folder) == NULL || *ADDRITEM_NAME(folder) == '\0' ) {
1485
                        if( folder->listPerson ) {
1486
                                /* Give name to folder */
1487
                                gchar name[20];
1488
                                sprintf( name, "? %d", i );
1489
                                addritem_folder_set_name( folder, name );
1490
                        }
1491
                        else {
1492
                                /* Mark for removal */
1493
                                remList = g_list_append( remList, folder );
1494
                        }
1495
                }
1496
                node = g_list_next( node );
1497
                i++;
1498
        }
1499
        node = remList;
1500
        while( node ) {
1501
                ItemFolder *folder = node->data;
1502
                addrcache_remove_folder( pilotFile->addressCache, folder );
1503
                node = g_list_next( node );
1504
        }
1505
        g_list_free( remList );
1506
}
1507

    
1508
/*
1509
* ============================================================================================
1510
* Read file into list. Main entry point
1511
* Return: TRUE if file read successfully.
1512
* ============================================================================================
1513
*/
1514
gint jpilot_read_data( JPilotFile *pilotFile ) {
1515
        name_order = FAMILY_LAST;
1516
        convert_charcode = FALSE;
1517

    
1518
        if( conv_is_ja_locale() ) {
1519
                name_order = FAMILY_FIRST;
1520
                convert_charcode = TRUE;
1521
        }
1522

    
1523
        g_return_val_if_fail( pilotFile != NULL, -1 );
1524

    
1525
        pilotFile->retVal = MGU_SUCCESS;
1526
        pilotFile->accessFlag = FALSE;
1527

    
1528
        if( jpilot_check_files( pilotFile ) ) {
1529
                addrcache_clear( pilotFile->addressCache );
1530
                jpilot_read_metadata( pilotFile );
1531
                if( pilotFile->retVal == MGU_SUCCESS ) {
1532
                        jpilot_setup_labels( pilotFile );
1533
                        jpilot_build_category_list( pilotFile );
1534
                        pilotFile->retVal = jpilot_read_file( pilotFile );
1535
                        if( pilotFile->retVal == MGU_SUCCESS ) {
1536
                                jpilot_remove_empty( pilotFile );
1537
                                jpilot_mark_files( pilotFile );
1538
                                pilotFile->addressCache->modified = FALSE;
1539
                                pilotFile->addressCache->dataRead = TRUE;
1540
                        }
1541
                }
1542
        }
1543
        return pilotFile->retVal;
1544
}
1545

    
1546
/*
1547
* Return link list of persons.
1548
*/
1549
GList *jpilot_get_list_person( JPilotFile *pilotFile ) {
1550
        g_return_val_if_fail( pilotFile != NULL, NULL );
1551
        return addrcache_get_list_person( pilotFile->addressCache );
1552
}
1553

    
1554
/*
1555
* Return link list of folders. This is always NULL since there are
1556
* no folders in GnomeCard.
1557
* Return: NULL.
1558
*/
1559
GList *jpilot_get_list_folder( JPilotFile *pilotFile ) {
1560
        g_return_val_if_fail( pilotFile != NULL, NULL );
1561
        return addrcache_get_list_folder( pilotFile->addressCache );
1562
}
1563

    
1564
/*
1565
* Return link list of all persons. Note that the list contains references
1566
* to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
1567
* this will destroy the addressbook data!
1568
* Return: List of items, or NULL if none.
1569
*/
1570
GList *jpilot_get_all_persons( JPilotFile *pilotFile ) {
1571
        g_return_val_if_fail( pilotFile != NULL, NULL );
1572
        return addrcache_get_all_persons( pilotFile->addressCache );
1573
}
1574

    
1575
/*
1576
* Check label list for specified label.
1577
*/
1578
gint jpilot_check_label( struct AddressAppInfo *ai, gchar *lblCheck ) {
1579
        gint i;
1580
        gchar *lblName;
1581

    
1582
        if( lblCheck == NULL ) return -1;
1583
        if( strlen( lblCheck ) < 1 ) return -1;
1584
        for( i = 0; i < JPILOT_NUM_LABELS; i++ ) {
1585
                lblName = ai->labels[i];
1586
                if( lblName ) {
1587
                        if( strlen( lblName ) ) {
1588
                                if( g_ascii_strcasecmp( lblName, lblCheck ) == 0 ) return i;
1589
                        }
1590
                }
1591
        }
1592
        return -2;
1593
}
1594

    
1595
/*
1596
* Validate that all parameters specified.
1597
* Return: TRUE if data is good.
1598
*/
1599
gboolean jpilot_validate( const JPilotFile *pilotFile ) {
1600
        gboolean retVal;
1601

    
1602
        g_return_val_if_fail( pilotFile != NULL, FALSE );
1603

    
1604
        retVal = TRUE;
1605
        if( pilotFile->path ) {
1606
                if( strlen( pilotFile->path ) < 1 ) retVal = FALSE;
1607
        }
1608
        else {
1609
                retVal = FALSE;
1610
        }
1611
        if( pilotFile->name ) {
1612
                if( strlen( pilotFile->name ) < 1 ) retVal = FALSE;
1613
        }
1614
        else {
1615
                retVal = FALSE;
1616
        }
1617
        return retVal;
1618
}
1619

    
1620
#define WORK_BUFLEN 1024
1621

    
1622
/*
1623
* Attempt to find a valid JPilot file.
1624
* Return: Filename, or home directory if not found, or empty string if
1625
* no home. Filename should be g_free() when done.
1626
*/
1627
gchar *jpilot_find_pilotdb( void ) {
1628
        const gchar *homedir;
1629
        gchar str[ WORK_BUFLEN ];
1630
        gint len;
1631
        FILE *fp;
1632

    
1633
        homedir = get_home_dir();
1634
        if( ! homedir ) return g_strdup( "" );
1635

    
1636
        strcpy( str, homedir );
1637
        len = strlen( str );
1638
        if( len > 0 ) {
1639
                if( str[ len-1 ] != G_DIR_SEPARATOR ) {
1640
                        str[ len ] = G_DIR_SEPARATOR;
1641
                        str[ ++len ] = '\0';
1642
                }
1643
        }
1644
        strcat( str, JPILOT_DBHOME_DIR );
1645
        strcat( str, G_DIR_SEPARATOR_S );
1646
        strcat( str, JPILOT_DBHOME_FILE );
1647

    
1648
        /* Attempt to open */
1649
        if( ( fp = g_fopen( str, "rb" ) ) != NULL ) {
1650
                fclose( fp );
1651
        }
1652
        else {
1653
                /* Truncate filename */
1654
                str[ len ] = '\0';
1655
        }
1656
        return g_strdup( str );
1657
}
1658

    
1659
/*
1660
* Attempt to read file, testing for valid JPilot format.
1661
* Return: TRUE if file appears to be valid format.
1662
*/
1663
gint jpilot_test_read_file( const gchar *fileSpec ) {
1664
        JPilotFile *pilotFile;
1665
        gint retVal;
1666

    
1667
        if( fileSpec ) {
1668
                pilotFile = jpilot_create_path( fileSpec );
1669
                retVal = jpilot_read_metadata( pilotFile );
1670
                jpilot_free( pilotFile );
1671
                pilotFile = NULL;
1672
        }
1673
        else {
1674
                retVal = MGU_NO_FILE;
1675
        }
1676
        return retVal;
1677
}
1678

    
1679
/*
1680
* Check whether label is in custom labels.
1681
* Return: TRUE if found.
1682
*/
1683
gboolean jpilot_test_custom_label( JPilotFile *pilotFile, const gchar *labelName ) {
1684
        gboolean retVal;
1685
        GList *node;
1686

    
1687
        g_return_val_if_fail( pilotFile != NULL, FALSE );
1688

    
1689
        retVal = FALSE;
1690
        if( labelName ) {
1691
                node = pilotFile->customLabels;
1692
                while( node ) {
1693
                        if( g_ascii_strcasecmp( labelName, node->data ) == 0 ) {
1694
                                retVal = TRUE;
1695
                                break;
1696
                        }
1697
                        node = g_list_next( node );
1698
                }
1699
        }
1700
        return retVal;
1701
}
1702

    
1703
/*
1704
* Test whether pilot link library installed.
1705
* Return: TRUE if library available.
1706
*/
1707
#if 0
1708
gboolean jpilot_test_pilot_lib( void ) {
1709
        void *handle, *fun;
1710

1711
        handle = dlopen( PILOT_LINK_LIB_NAME, RTLD_LAZY );
1712
        if( ! handle ) {
1713
                return FALSE;
1714
        }
1715

1716
        /* Test for symbols we need */
1717
        fun = dlsym( handle, "unpack_Address" );
1718
        if( ! fun ) {
1719
                dlclose( handle );
1720
                return FALSE;
1721
        }
1722

1723
        fun = dlsym( handle, "unpack_AddressAppInfo" );
1724
        if( ! fun ) {
1725
                dlclose( handle );
1726
                return FALSE;
1727
        }
1728
        dlclose( handle );
1729
        return TRUE;
1730
}
1731
#endif /* 0 */
1732

    
1733
#endif        /* USE_JPILOT */
1734

    
1735
/*
1736
* End of Source.
1737
*/